@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.141

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 (460) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +432 -7
  3. package/dist/bin/rango.js +2073 -213
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +7258 -2714
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +140 -67
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +329 -0
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +487 -0
  12. package/skills/caching/SKILL.md +357 -25
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +246 -0
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +16 -10
  19. package/skills/document-cache/SKILL.md +87 -62
  20. package/skills/fonts/SKILL.md +6 -4
  21. package/skills/handler-use/SKILL.md +364 -0
  22. package/skills/hooks/SKILL.md +557 -79
  23. package/skills/host-router/SKILL.md +320 -0
  24. package/skills/i18n/SKILL.md +276 -0
  25. package/skills/intercept/SKILL.md +207 -15
  26. package/skills/layout/SKILL.md +146 -6
  27. package/skills/links/SKILL.md +304 -25
  28. package/skills/loader/SKILL.md +616 -54
  29. package/skills/middleware/SKILL.md +217 -37
  30. package/skills/migrate-nextjs/SKILL.md +611 -0
  31. package/skills/migrate-react-router/SKILL.md +927 -0
  32. package/skills/mime-routes/SKILL.md +42 -11
  33. package/skills/observability/SKILL.md +194 -0
  34. package/skills/parallel/SKILL.md +284 -3
  35. package/skills/ppr/SKILL.md +293 -0
  36. package/skills/prerender/SKILL.md +437 -52
  37. package/skills/rango/SKILL.md +369 -22
  38. package/skills/react-compiler/SKILL.md +168 -0
  39. package/skills/response-routes/SKILL.md +263 -121
  40. package/skills/route/SKILL.md +350 -21
  41. package/skills/router-setup/SKILL.md +246 -33
  42. package/skills/scripts/SKILL.md +179 -0
  43. package/skills/server-actions/SKILL.md +775 -0
  44. package/skills/shell-manifest/SKILL.md +185 -0
  45. package/skills/streams-and-websockets/SKILL.md +283 -0
  46. package/skills/tailwind/SKILL.md +27 -3
  47. package/skills/testing/SKILL.md +126 -222
  48. package/skills/testing/bindings.md +103 -0
  49. package/skills/testing/cache-prerender.md +127 -0
  50. package/skills/testing/client-components.md +124 -0
  51. package/skills/testing/e2e-parity.md +125 -0
  52. package/skills/testing/flight.md +91 -0
  53. package/skills/testing/handles.md +131 -0
  54. package/skills/testing/loader.md +128 -0
  55. package/skills/testing/middleware.md +99 -0
  56. package/skills/testing/render-handler.md +122 -0
  57. package/skills/testing/response-routes.md +95 -0
  58. package/skills/testing/reverse-and-types.md +85 -0
  59. package/skills/testing/server-actions.md +107 -0
  60. package/skills/testing/server-tree.md +128 -0
  61. package/skills/testing/setup.md +123 -0
  62. package/skills/theme/SKILL.md +9 -8
  63. package/skills/typesafety/SKILL.md +532 -103
  64. package/skills/use-cache/SKILL.md +367 -0
  65. package/skills/vercel/SKILL.md +128 -0
  66. package/skills/view-transitions/SKILL.md +337 -0
  67. package/src/__augment-tests__/augment.ts +81 -0
  68. package/src/__augment-tests__/augmented.check.ts +116 -0
  69. package/src/__internal.ts +77 -44
  70. package/src/bin/rango.ts +312 -15
  71. package/src/browser/action-coordinator.ts +114 -0
  72. package/src/browser/action-fence.ts +47 -0
  73. package/src/browser/app-shell.ts +39 -0
  74. package/src/browser/app-version.ts +14 -0
  75. package/src/browser/connection-warmup.ts +134 -0
  76. package/src/browser/cookie-name.ts +140 -0
  77. package/src/browser/event-controller.ts +293 -202
  78. package/src/browser/history-state.ts +101 -0
  79. package/src/browser/index.ts +3 -3
  80. package/src/browser/intercept-utils.ts +52 -0
  81. package/src/browser/invalidate-client-cache.ts +52 -0
  82. package/src/browser/link-interceptor.ts +24 -4
  83. package/src/browser/logging.ts +11 -0
  84. package/src/browser/merge-segment-loaders.ts +20 -12
  85. package/src/browser/navigation-bridge.ts +385 -576
  86. package/src/browser/navigation-client.ts +245 -75
  87. package/src/browser/navigation-store-handle.ts +38 -0
  88. package/src/browser/navigation-store.ts +184 -118
  89. package/src/browser/navigation-transaction.ts +247 -0
  90. package/src/browser/network-error-handler.ts +88 -0
  91. package/src/browser/partial-update.ts +412 -364
  92. package/src/browser/prefetch/cache.ts +359 -0
  93. package/src/browser/prefetch/fetch.ts +452 -0
  94. package/src/browser/prefetch/observer.ts +65 -0
  95. package/src/browser/prefetch/policy.ts +48 -0
  96. package/src/browser/prefetch/queue.ts +209 -0
  97. package/src/browser/prefetch/resource-ready.ts +77 -0
  98. package/src/browser/rango-state.ts +194 -0
  99. package/src/browser/react/Link.tsx +275 -68
  100. package/src/browser/react/NavigationProvider.tsx +265 -109
  101. package/src/browser/react/ScrollRestoration.tsx +10 -6
  102. package/src/browser/react/context.ts +11 -0
  103. package/src/browser/react/filter-segment-order.ts +70 -0
  104. package/src/browser/react/index.ts +0 -48
  105. package/src/browser/react/location-state-shared.ts +272 -60
  106. package/src/browser/react/location-state.ts +90 -20
  107. package/src/browser/react/mount-context.ts +6 -1
  108. package/src/browser/react/nonce-context.ts +23 -0
  109. package/src/browser/react/shallow-equal.ts +27 -0
  110. package/src/browser/react/use-action.ts +35 -66
  111. package/src/browser/react/use-handle.ts +39 -126
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +39 -13
  114. package/src/browser/react/use-navigation.ts +53 -69
  115. package/src/browser/react/use-params.ts +75 -0
  116. package/src/browser/react/use-pathname.ts +47 -0
  117. package/src/browser/react/use-reverse.ts +106 -0
  118. package/src/browser/react/use-router.ts +98 -0
  119. package/src/browser/react/use-search-params.ts +51 -0
  120. package/src/browser/react/use-segments.ts +72 -99
  121. package/src/browser/response-adapter.ts +164 -0
  122. package/src/browser/rsc-router.tsx +300 -72
  123. package/src/browser/scroll-restoration.ts +138 -50
  124. package/src/browser/segment-reconciler.ts +243 -0
  125. package/src/browser/segment-structure-assert.ts +17 -1
  126. package/src/browser/server-action-bridge.ts +668 -613
  127. package/src/browser/types.ts +223 -51
  128. package/src/browser/validate-redirect-origin.ts +56 -0
  129. package/src/build/collect-fallback-refs.ts +107 -0
  130. package/src/build/generate-manifest.ts +252 -161
  131. package/src/build/generate-route-types.ts +41 -1038
  132. package/src/build/index.ts +12 -7
  133. package/src/build/prefix-tree-utils.ts +123 -0
  134. package/src/build/route-trie.ts +225 -42
  135. package/src/build/route-types/ast-helpers.ts +25 -0
  136. package/src/build/route-types/ast-route-extraction.ts +105 -0
  137. package/src/build/route-types/codegen.ts +113 -0
  138. package/src/build/route-types/include-resolution.ts +812 -0
  139. package/src/build/route-types/param-extraction.ts +51 -0
  140. package/src/build/route-types/per-module-writer.ts +144 -0
  141. package/src/build/route-types/router-processing.ts +695 -0
  142. package/src/build/route-types/scan-filter.ts +85 -0
  143. package/src/build/route-types/source-scan.ts +216 -0
  144. package/src/build/runtime-discovery.ts +223 -0
  145. package/src/cache/background-task.ts +34 -0
  146. package/src/cache/cache-error.ts +104 -0
  147. package/src/cache/cache-key-utils.ts +60 -0
  148. package/src/cache/cache-policy.ts +199 -0
  149. package/src/cache/cache-runtime.ts +525 -0
  150. package/src/cache/cache-scope.ts +298 -332
  151. package/src/cache/cache-tag.ts +103 -0
  152. package/src/cache/cf/cf-base64.ts +33 -0
  153. package/src/cache/cf/cf-cache-constants.ts +127 -0
  154. package/src/cache/cf/cf-cache-store.ts +2508 -158
  155. package/src/cache/cf/cf-cache-types.ts +349 -0
  156. package/src/cache/cf/cf-kv-utils.ts +46 -0
  157. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  158. package/src/cache/cf/index.ts +17 -17
  159. package/src/cache/document-cache.ts +199 -92
  160. package/src/cache/handle-capture.ts +81 -0
  161. package/src/cache/handle-snapshot.ts +111 -0
  162. package/src/cache/index.ts +24 -35
  163. package/src/cache/memory-segment-store.ts +363 -30
  164. package/src/cache/profile-registry.ts +88 -0
  165. package/src/cache/read-through-swr.ts +178 -0
  166. package/src/cache/segment-codec.ts +248 -0
  167. package/src/cache/shell-snapshot.ts +368 -0
  168. package/src/cache/tag-invalidation.ts +230 -0
  169. package/src/cache/taint.ts +153 -0
  170. package/src/cache/types.ts +222 -211
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1113 -0
  173. package/src/client.rsc.tsx +43 -21
  174. package/src/client.tsx +131 -347
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +109 -0
  177. package/src/component-utils.ts +23 -4
  178. package/src/components/DefaultDocument.tsx +13 -3
  179. package/src/context-var.ts +168 -0
  180. package/src/debug.ts +19 -9
  181. package/src/decode-loader-results.ts +52 -0
  182. package/src/defer.ts +185 -0
  183. package/src/deps/ssr.ts +0 -1
  184. package/src/encode-kv.ts +49 -0
  185. package/src/errors.ts +106 -10
  186. package/src/escape-script.ts +52 -0
  187. package/src/handle.ts +110 -35
  188. package/src/handles/MetaTags.tsx +83 -59
  189. package/src/handles/Scripts.tsx +183 -0
  190. package/src/handles/breadcrumbs.ts +93 -0
  191. package/src/handles/deferred-resolution.ts +127 -0
  192. package/src/handles/is-thenable.ts +18 -0
  193. package/src/handles/meta.ts +44 -53
  194. package/src/handles/script.ts +244 -0
  195. package/src/host/cookie-handler.ts +20 -65
  196. package/src/host/errors.ts +21 -30
  197. package/src/host/index.ts +13 -9
  198. package/src/host/pattern-matcher.ts +50 -79
  199. package/src/host/router.ts +151 -121
  200. package/src/host/testing.ts +45 -32
  201. package/src/host/types.ts +52 -11
  202. package/src/host/utils.ts +2 -2
  203. package/src/href-client.ts +192 -57
  204. package/src/index.rsc.ts +173 -35
  205. package/src/index.ts +241 -73
  206. package/src/internal-debug.ts +9 -2
  207. package/src/loader-store.ts +500 -0
  208. package/src/loader.rsc.ts +31 -99
  209. package/src/loader.ts +30 -12
  210. package/src/missing-id-error.ts +68 -0
  211. package/src/outlet-context.ts +1 -1
  212. package/src/outlet-provider.tsx +41 -0
  213. package/src/prerender/param-hash.ts +16 -14
  214. package/src/prerender/store.ts +121 -21
  215. package/src/prerender.ts +460 -26
  216. package/src/redirect-origin.ts +100 -0
  217. package/src/regex-escape.ts +8 -0
  218. package/src/render-error-thrower.tsx +20 -0
  219. package/src/response-utils.ts +62 -0
  220. package/src/reverse.ts +198 -128
  221. package/src/root-error-boundary.tsx +42 -48
  222. package/src/route-content-wrapper.tsx +22 -77
  223. package/src/route-definition/dsl-helpers.ts +1116 -0
  224. package/src/route-definition/helper-factories.ts +88 -0
  225. package/src/route-definition/helpers-types.ts +505 -0
  226. package/src/route-definition/index.ts +54 -0
  227. package/src/route-definition/redirect.ts +134 -0
  228. package/src/route-definition/resolve-handler-use.ts +160 -0
  229. package/src/route-definition/use-item-types.ts +29 -0
  230. package/src/route-definition.ts +1 -1481
  231. package/src/route-map-builder.ts +82 -144
  232. package/src/route-name.ts +53 -0
  233. package/src/route-types.ts +71 -45
  234. package/src/router/basename.ts +14 -0
  235. package/src/router/content-negotiation.ts +263 -0
  236. package/src/router/debug-manifest.ts +72 -0
  237. package/src/router/error-handling.ts +54 -27
  238. package/src/router/find-match.ts +245 -0
  239. package/src/router/handler-context.ts +377 -125
  240. package/src/router/instrument.ts +350 -0
  241. package/src/router/intercept-resolution.ts +59 -28
  242. package/src/router/lazy-includes.ts +254 -0
  243. package/src/router/loader-resolution.ts +421 -157
  244. package/src/router/logging.ts +106 -6
  245. package/src/router/manifest.ts +131 -57
  246. package/src/router/match-api.ts +167 -246
  247. package/src/router/match-context.ts +4 -24
  248. package/src/router/match-handlers.ts +440 -0
  249. package/src/router/match-middleware/background-revalidation.ts +117 -93
  250. package/src/router/match-middleware/cache-lookup.ts +297 -150
  251. package/src/router/match-middleware/cache-store.ts +123 -51
  252. package/src/router/match-middleware/intercept-resolution.ts +44 -43
  253. package/src/router/match-middleware/segment-resolution.ts +64 -22
  254. package/src/router/match-pipelines.ts +11 -87
  255. package/src/router/match-result.ts +121 -50
  256. package/src/router/metrics.ts +219 -28
  257. package/src/router/middleware-types.ts +93 -0
  258. package/src/router/middleware.ts +505 -441
  259. package/src/router/navigation-snapshot.ts +133 -0
  260. package/src/router/params-util.ts +23 -0
  261. package/src/router/parse-pattern.ts +115 -0
  262. package/src/router/pattern-matching.ts +311 -142
  263. package/src/router/prefetch-cache-ttl.ts +51 -0
  264. package/src/router/prefetch-limits.ts +37 -0
  265. package/src/router/prerender-match.ts +547 -0
  266. package/src/router/preview-match.ts +102 -0
  267. package/src/router/request-classification.ts +278 -0
  268. package/src/router/revalidation.ts +203 -62
  269. package/src/router/route-snapshot.ts +246 -0
  270. package/src/router/router-context.ts +45 -48
  271. package/src/router/router-interfaces.ts +554 -0
  272. package/src/router/router-options.ts +779 -0
  273. package/src/router/router-registry.ts +21 -0
  274. package/src/router/segment-resolution/fresh.ts +772 -0
  275. package/src/router/segment-resolution/helpers.ts +348 -0
  276. package/src/router/segment-resolution/loader-cache.ts +250 -0
  277. package/src/router/segment-resolution/loader-mask.ts +44 -0
  278. package/src/router/segment-resolution/revalidation.ts +1331 -0
  279. package/src/router/segment-resolution/static-store.ts +81 -0
  280. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  281. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  282. package/src/router/segment-resolution.ts +25 -1354
  283. package/src/router/segment-wrappers.ts +292 -0
  284. package/src/router/state-cookie-name.ts +33 -0
  285. package/src/router/substitute-pattern-params.ts +75 -0
  286. package/src/router/telemetry-otel.ts +261 -0
  287. package/src/router/telemetry.ts +377 -0
  288. package/src/router/timeout.ts +128 -0
  289. package/src/router/tracing.ts +206 -0
  290. package/src/router/trie-matching.ts +240 -61
  291. package/src/router/types.ts +23 -70
  292. package/src/router/url-params.ts +57 -0
  293. package/src/router.ts +781 -2378
  294. package/src/rsc/full-payload.ts +70 -0
  295. package/src/rsc/handler-context.ts +46 -0
  296. package/src/rsc/handler.ts +905 -1142
  297. package/src/rsc/helpers.ts +275 -19
  298. package/src/rsc/index.ts +2 -25
  299. package/src/rsc/json-route-result.ts +38 -0
  300. package/src/rsc/loader-fetch.ts +305 -0
  301. package/src/rsc/manifest-init.ts +77 -0
  302. package/src/rsc/nonce.ts +14 -0
  303. package/src/rsc/origin-guard.ts +155 -0
  304. package/src/rsc/progressive-enhancement.ts +502 -0
  305. package/src/rsc/redirect-guard.ts +99 -0
  306. package/src/rsc/response-cache-serve.ts +238 -0
  307. package/src/rsc/response-error.ts +104 -0
  308. package/src/rsc/response-route-handler.ts +257 -0
  309. package/src/rsc/rsc-rendering.ts +527 -0
  310. package/src/rsc/runtime-warnings.ts +55 -0
  311. package/src/rsc/server-action.ts +522 -0
  312. package/src/rsc/shell-capture.ts +897 -0
  313. package/src/rsc/shell-serve.ts +124 -0
  314. package/src/rsc/ssr-setup.ts +144 -0
  315. package/src/rsc/transition-gate.ts +89 -0
  316. package/src/rsc/types.ts +95 -12
  317. package/src/runtime-env.ts +18 -0
  318. package/src/search-params.ts +99 -82
  319. package/src/segment-content-promise.ts +67 -0
  320. package/src/segment-loader-promise.ts +149 -0
  321. package/src/segment-system.tsx +349 -134
  322. package/src/serialize.ts +243 -0
  323. package/src/server/context.ts +459 -85
  324. package/src/server/cookie-parse.ts +32 -0
  325. package/src/server/cookie-store.ts +310 -0
  326. package/src/server/fetchable-loader-store.ts +11 -6
  327. package/src/server/handle-store.ts +123 -42
  328. package/src/server/loader-registry.ts +51 -100
  329. package/src/server/request-context.ts +848 -157
  330. package/src/server.ts +15 -8
  331. package/src/ssr/index.tsx +443 -135
  332. package/src/ssr/ssr-root.tsx +228 -0
  333. package/src/static-handler.ts +45 -18
  334. package/src/testing/cache-status.ts +162 -0
  335. package/src/testing/collect-handle.ts +46 -0
  336. package/src/testing/dispatch.ts +701 -0
  337. package/src/testing/dom.entry.ts +22 -0
  338. package/src/testing/e2e/fixture.ts +188 -0
  339. package/src/testing/e2e/index.ts +128 -0
  340. package/src/testing/e2e/matchers.ts +35 -0
  341. package/src/testing/e2e/page-helpers.ts +272 -0
  342. package/src/testing/e2e/parity.ts +387 -0
  343. package/src/testing/e2e/server.ts +195 -0
  344. package/src/testing/flight-matchers.ts +97 -0
  345. package/src/testing/flight-normalize.ts +11 -0
  346. package/src/testing/flight-runtime.d.ts +57 -0
  347. package/src/testing/flight-tree.ts +682 -0
  348. package/src/testing/flight.entry.ts +52 -0
  349. package/src/testing/flight.ts +257 -0
  350. package/src/testing/generated-routes.ts +199 -0
  351. package/src/testing/index.ts +105 -0
  352. package/src/testing/internal/context.ts +371 -0
  353. package/src/testing/internal/flight-client-globals.ts +30 -0
  354. package/src/testing/internal/seed-vars.ts +54 -0
  355. package/src/testing/render-handler.ts +357 -0
  356. package/src/testing/render-route.tsx +584 -0
  357. package/src/testing/run-loader.ts +385 -0
  358. package/src/testing/run-middleware.ts +205 -0
  359. package/src/testing/run-transition-when.ts +164 -0
  360. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  361. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  362. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  363. package/src/testing/vitest-stubs/version.ts +5 -0
  364. package/src/testing/vitest.ts +305 -0
  365. package/src/theme/ThemeProvider.tsx +76 -98
  366. package/src/theme/ThemeScript.tsx +12 -14
  367. package/src/theme/constants.ts +57 -15
  368. package/src/theme/index.ts +3 -20
  369. package/src/theme/theme-context.ts +5 -35
  370. package/src/theme/theme-script.ts +43 -39
  371. package/src/theme/use-theme.ts +0 -3
  372. package/src/types/boundaries.ts +123 -0
  373. package/src/types/cache-types.ts +207 -0
  374. package/src/types/error-types.ts +132 -0
  375. package/src/types/global-namespace.ts +113 -0
  376. package/src/types/handler-context.ts +839 -0
  377. package/src/types/index.ts +81 -0
  378. package/src/types/loader-types.ts +212 -0
  379. package/src/types/request-scope.ts +112 -0
  380. package/src/types/route-config.ts +138 -0
  381. package/src/types/route-entry.ts +114 -0
  382. package/src/types/segments.ts +271 -0
  383. package/src/types.ts +1 -1795
  384. package/src/urls/include-helper.ts +162 -0
  385. package/src/urls/include-provider.ts +71 -0
  386. package/src/urls/index.ts +44 -0
  387. package/src/urls/path-helper-types.ts +413 -0
  388. package/src/urls/path-helper.ts +280 -0
  389. package/src/urls/pattern-types.ts +160 -0
  390. package/src/urls/response-types.ts +109 -0
  391. package/src/urls/type-extraction.ts +316 -0
  392. package/src/urls/urls-function.ts +80 -0
  393. package/src/urls.ts +1 -1341
  394. package/src/use-loader.tsx +406 -141
  395. package/src/vercel/index.ts +11 -0
  396. package/src/vercel/tracing.ts +88 -0
  397. package/src/vite/debug.ts +185 -0
  398. package/src/vite/discovery/bundle-postprocess.ts +182 -0
  399. package/src/vite/discovery/discover-routers.ts +389 -0
  400. package/src/vite/discovery/discovery-errors.ts +255 -0
  401. package/src/vite/discovery/gate-state.ts +171 -0
  402. package/src/vite/discovery/prerender-collection.ts +467 -0
  403. package/src/vite/discovery/route-types-writer.ts +214 -0
  404. package/src/vite/discovery/self-gen-tracking.ts +73 -0
  405. package/src/vite/discovery/state.ts +161 -0
  406. package/src/vite/discovery/virtual-module-codegen.ts +183 -0
  407. package/src/vite/index.ts +23 -2255
  408. package/src/vite/inject-client-debug.ts +36 -0
  409. package/src/vite/plugin-types.ts +303 -0
  410. package/src/vite/plugins/cjs-to-esm.ts +90 -0
  411. package/src/vite/plugins/client-ref-dedup.ts +120 -0
  412. package/src/vite/plugins/client-ref-hashing.ts +118 -0
  413. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  414. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  415. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  416. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
  417. package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
  418. package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
  419. package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
  420. package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
  421. package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
  422. package/src/vite/plugins/expose-ids/types.ts +45 -0
  423. package/src/vite/plugins/expose-internal-ids.ts +805 -0
  424. package/src/vite/plugins/performance-tracks.ts +89 -0
  425. package/src/vite/plugins/refresh-cmd.ts +127 -0
  426. package/src/vite/plugins/use-cache-transform.ts +313 -0
  427. package/src/vite/plugins/vercel-output.ts +384 -0
  428. package/src/vite/plugins/version-injector.ts +94 -0
  429. package/src/vite/plugins/version-plugin.ts +263 -0
  430. package/src/vite/plugins/virtual-entries.ts +234 -0
  431. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  432. package/src/vite/rango.ts +560 -0
  433. package/src/vite/router-discovery.ts +1638 -0
  434. package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
  435. package/src/vite/utils/banner.ts +36 -0
  436. package/src/vite/utils/bundle-analysis.ts +132 -0
  437. package/src/vite/utils/client-chunks.ts +184 -0
  438. package/src/vite/utils/directive-prologue.ts +40 -0
  439. package/src/vite/utils/forward-user-plugins.ts +171 -0
  440. package/src/vite/utils/manifest-utils.ts +15 -0
  441. package/src/vite/utils/package-resolution.ts +89 -0
  442. package/src/vite/utils/prerender-utils.ts +249 -0
  443. package/src/vite/utils/shared-utils.ts +269 -0
  444. package/CLAUDE.md +0 -43
  445. package/dist/vite/index.named-routes.gen.ts +0 -103
  446. package/src/browser/lru-cache.ts +0 -69
  447. package/src/browser/react/use-client-cache.ts +0 -56
  448. package/src/browser/request-controller.ts +0 -164
  449. package/src/browser/shallow.ts +0 -35
  450. package/src/cache/memory-store.ts +0 -253
  451. package/src/handles/index.ts +0 -6
  452. package/src/href-context.ts +0 -33
  453. package/src/network-error-thrower.tsx +0 -21
  454. package/src/router.gen.ts +0 -6
  455. package/src/static-handler.gen.ts +0 -5
  456. package/src/urls.gen.ts +0 -8
  457. package/src/vite/expose-internal-ids.ts +0 -1167
  458. package/src/vite/package-resolution.ts +0 -125
  459. package/src/vite/virtual-entries.ts +0 -114
  460. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -0,0 +1,779 @@
1
+ import type { ComponentType, ReactNode } from "react";
2
+ import type { SegmentCacheStore } from "../cache/types.js";
3
+ import type {
4
+ ErrorBoundaryHandler,
5
+ NotFoundBoundaryHandler,
6
+ OnErrorCallback,
7
+ } from "../types";
8
+ import type { NonceProvider } from "../rsc/types.js";
9
+ import type { ExecutionContext } from "../server/request-context.js";
10
+ import type { UrlPatterns } from "../urls.js";
11
+ import type { UrlBuilder } from "../urls/pattern-types.js";
12
+ import type { NamedRouteEntry } from "./content-negotiation.js";
13
+ import type { TelemetrySink } from "./telemetry.js";
14
+ import type { RouterTracingConfig } from "./tracing.js";
15
+ import type { RouterTimeouts, OnTimeoutCallback } from "./timeout.js";
16
+
17
+ /**
18
+ * SSR stream mode returned by resolveStreaming.
19
+ *
20
+ * - `"stream"` — start flushing HTML as soon as the shell is ready
21
+ * (default React SSR behavior via `renderToReadableStream`).
22
+ * - `"allReady"` — wait for every Suspense boundary to resolve before
23
+ * sending any bytes (equivalent to awaiting `stream.allReady`).
24
+ */
25
+ export type SSRStreamMode = "stream" | "allReady";
26
+
27
+ /**
28
+ * Context passed to the resolveStreaming callback.
29
+ */
30
+ export interface ResolveStreamingContext<TEnv = unknown> {
31
+ request: Request;
32
+ env: TEnv;
33
+ url: URL;
34
+ }
35
+
36
+ /**
37
+ * SSR configuration options.
38
+ */
39
+ export interface SSROptions<TEnv = unknown> {
40
+ /**
41
+ * Determine whether an HTML response should stream progressively or
42
+ * wait for full readiness before flushing.
43
+ *
44
+ * Called once per HTML request, before the HTML response is produced.
45
+ * Does NOT apply to RSC responses (`__rsc`, partial navigation, prefetch).
46
+ *
47
+ * Return `"stream"` (default) for progressive streaming or `"allReady"`
48
+ * to buffer the complete HTML before sending.
49
+ *
50
+ * @example Bot detection
51
+ * ```ts
52
+ * createRouter({
53
+ * ssr: {
54
+ * resolveStreaming: async ({ request, env }) => {
55
+ * const bot = await detectBot(request, env);
56
+ * return bot.isBot && !bot.supportsStreaming ? "allReady" : "stream";
57
+ * },
58
+ * },
59
+ * });
60
+ * ```
61
+ */
62
+ resolveStreaming?: (
63
+ context: ResolveStreamingContext<TEnv>,
64
+ ) => SSRStreamMode | Promise<SSRStreamMode>;
65
+ }
66
+
67
+ /**
68
+ * Props passed to the root layout component
69
+ */
70
+ export interface RootLayoutProps {
71
+ children: ReactNode;
72
+ }
73
+
74
+ /**
75
+ * Router configuration options
76
+ */
77
+ export interface RangoOptions<TEnv = any> {
78
+ /**
79
+ * Unique identifier for this router instance.
80
+ * Used to namespace static output files and route maps.
81
+ * Auto-generated if not provided.
82
+ */
83
+ id?: string;
84
+
85
+ /**
86
+ * Injected by the Vite transform at compile time.
87
+ * Hash of filename + line number for stable cross-environment ID.
88
+ * @internal
89
+ */
90
+ $$id?: string;
91
+
92
+ /**
93
+ * Injected by the Vite transform at compile time.
94
+ * Absolute path of the source file that defines this router,
95
+ * relative to project root. Eliminates runtime stack trace parsing.
96
+ * @internal
97
+ */
98
+ $$sourceFile?: string;
99
+
100
+ /**
101
+ * URL prefix applied to all routes registered with this router.
102
+ *
103
+ * Useful when the app is served under a sub-path (e.g. `/admin` or `/v2`).
104
+ * All `path()` patterns are automatically prefixed and `reverse()` returns
105
+ * full paths including the basename. Route names are NOT prefixed.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const router = createRouter({
110
+ * basename: "/admin",
111
+ * }).routes(({ path }) => [
112
+ * path("/", Dashboard, { name: "home" }), // matches /admin
113
+ * path("/users", Users, { name: "users" }), // matches /admin/users
114
+ * ]);
115
+ *
116
+ * router.reverse("home"); // "/admin"
117
+ * router.reverse("users"); // "/admin/users"
118
+ * ```
119
+ */
120
+ basename?: string;
121
+
122
+ /**
123
+ * Enable performance metrics collection
124
+ * When enabled, metrics are output to console and available via Server-Timing header
125
+ */
126
+ debugPerformance?: boolean;
127
+
128
+ /**
129
+ * Allow the `?__debug_manifest` query parameter to return route manifest data as JSON.
130
+ * In development mode this is always enabled regardless of this setting.
131
+ * Defaults to false. Set to true to enable in production.
132
+ * @internal
133
+ */
134
+ allowDebugManifest?: boolean;
135
+
136
+ /**
137
+ * DEVELOPMENT/TEST ONLY. Emit an `X-Rango-Cache` response header describing
138
+ * the cache status of the matched route, for use by testing primitives such
139
+ * as `assertCacheStatus`.
140
+ *
141
+ * Defaults to `false`. When neither this option nor the
142
+ * `RANGO_TEST_SIGNALS=1` environment flag is set, NO header is emitted and
143
+ * router output is byte-identical to the default.
144
+ *
145
+ * The header encodes per-segment (v1: coarse route-level) status keyed by the
146
+ * route NAME, e.g. `X-Rango-Cache: product.detail=hit`. Do NOT enable in
147
+ * production — it exposes internal cache decisions.
148
+ */
149
+ debugCacheSignal?: boolean;
150
+
151
+ /**
152
+ * Document component that wraps the entire application.
153
+ *
154
+ * This component provides the HTML structure for your app and wraps
155
+ * both normal route content AND error states, preventing the app shell
156
+ * from unmounting during errors (avoids FOUC).
157
+ *
158
+ * Must be a client component ("use client") that accepts { children }.
159
+ *
160
+ * If not provided, a default document with basic HTML structure is used:
161
+ * `<html><head><meta charset/viewport></head><body>{children}</body></html>`
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * // components/Document.tsx
166
+ * "use client";
167
+ * export function Document({ children }: { children: ReactNode }) {
168
+ * return (
169
+ * <html lang="en">
170
+ * <head>
171
+ * <link rel="stylesheet" href="/styles.css" />
172
+ * </head>
173
+ * <body>
174
+ * <nav>...</nav>
175
+ * {children}
176
+ * </body>
177
+ * </html>
178
+ * );
179
+ * }
180
+ *
181
+ * // router.tsx
182
+ * const router = createRouter<AppEnv>({
183
+ * document: Document,
184
+ * });
185
+ * ```
186
+ */
187
+ document?: ComponentType<RootLayoutProps>;
188
+
189
+ /**
190
+ * Default error boundary fallback used when no error boundary is defined in the route tree
191
+ * If not provided, errors will propagate and crash the request
192
+ */
193
+ defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler;
194
+
195
+ /**
196
+ * Default not-found boundary fallback used when no notFoundBoundary is defined in the route tree
197
+ * If not provided, DataNotFoundError will be treated as a regular error
198
+ */
199
+ defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler;
200
+
201
+ /**
202
+ * Component to render when no route matches the requested URL.
203
+ *
204
+ * This is rendered within your document/app shell with a 404 status code.
205
+ * Use this for a custom 404 page that maintains your app's look and feel.
206
+ *
207
+ * If not provided, a default "Page not found" component is rendered.
208
+ *
209
+ * Can be a static ReactNode or a function receiving the pathname.
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * // Simple static component
214
+ * const router = createRouter<AppEnv>({
215
+ * document: Document,
216
+ * notFound: <NotFound404 />,
217
+ * });
218
+ *
219
+ * // Dynamic component with pathname
220
+ * const router = createRouter<AppEnv>({
221
+ * document: Document,
222
+ * notFound: ({ pathname }) => (
223
+ * <div>
224
+ * <h1>404 - Not Found</h1>
225
+ * <p>No page exists at {pathname}</p>
226
+ * <a href="/">Go home</a>
227
+ * </div>
228
+ * ),
229
+ * });
230
+ * ```
231
+ */
232
+ notFound?: ReactNode | ((props: { pathname: string }) => ReactNode);
233
+
234
+ /**
235
+ * Callback invoked when an error occurs during request handling.
236
+ *
237
+ * This callback is for notification/logging purposes - it cannot modify
238
+ * the error handling flow. Use errorBoundary() in route definitions to
239
+ * customize error UI.
240
+ *
241
+ * The callback receives comprehensive context about the error including:
242
+ * - The error itself
243
+ * - Phase where it occurred (routing, middleware, loader, handler, etc.)
244
+ * - Request info (URL, method, params)
245
+ * - Route info (routeKey, segmentId)
246
+ * - Environment/bindings
247
+ * - Duration from request start
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * const router = createRouter<AppEnv>({
252
+ * onError: (context) => {
253
+ * // Send to error tracking service
254
+ * Sentry.captureException(context.error, {
255
+ * tags: {
256
+ * phase: context.phase,
257
+ * route: context.routeKey,
258
+ * },
259
+ * extra: {
260
+ * url: context.url.toString(),
261
+ * params: context.params,
262
+ * duration: context.duration,
263
+ * },
264
+ * });
265
+ * },
266
+ * });
267
+ * ```
268
+ */
269
+ onError?: OnErrorCallback<TEnv>;
270
+
271
+ /**
272
+ * Cache store for segment caching.
273
+ *
274
+ * When provided, enables route-level caching via cache() boundaries.
275
+ * The store handles persistence (memory, KV, Redis, etc.).
276
+ *
277
+ * Can be a static config or a function receiving env for runtime bindings.
278
+ *
279
+ * @example Static config
280
+ * ```typescript
281
+ * import { MemorySegmentCacheStore } from "@rangojs/router/cache";
282
+ *
283
+ * const router = createRouter({
284
+ * cache: {
285
+ * store: new MemorySegmentCacheStore({ defaults: { ttl: 60 } }),
286
+ * },
287
+ * });
288
+ * ```
289
+ *
290
+ * @example Dynamic config with env (e.g., Cloudflare Workers with ExecutionContext)
291
+ * ```typescript
292
+ * const router = createRouter<AppBindings>({
293
+ * cache: (_env, ctx) => ({
294
+ * store: new CFCacheStore({
295
+ * defaults: { ttl: 60 },
296
+ * ctx: ctx!, // ExecutionContext for non-blocking writes
297
+ * }),
298
+ * }),
299
+ * });
300
+ * ```
301
+ */
302
+ cache?:
303
+ | { store: SegmentCacheStore; enabled?: boolean }
304
+ | ((
305
+ env: TEnv,
306
+ ctx?: ExecutionContext,
307
+ ) => {
308
+ store: SegmentCacheStore;
309
+ enabled?: boolean;
310
+ });
311
+
312
+ /**
313
+ * Named cache profiles for "use cache" directive.
314
+ * Profile names map to TTL/SWR configuration.
315
+ *
316
+ * - `"use cache"` (no name) resolves to the `default` profile.
317
+ * - `"use cache: short"` resolves to the `short` profile.
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * createRouter({
322
+ * cacheProfiles: {
323
+ * default: { ttl: 900, swr: 1800 },
324
+ * short: { ttl: 60, swr: 120 },
325
+ * long: { ttl: 3600, swr: 7200 },
326
+ * products: { ttl: 300, swr: 600, tags: ['products'] },
327
+ * },
328
+ * });
329
+ * ```
330
+ */
331
+ cacheProfiles?: Record<
332
+ string,
333
+ import("../cache/profile-registry.js").CacheProfile
334
+ >;
335
+
336
+ /**
337
+ * Theme configuration for automatic theme management.
338
+ *
339
+ * When provided, enables:
340
+ * - ctx.theme and ctx.setTheme() in route handlers
341
+ * - useTheme() hook for client components
342
+ * - FOUC prevention via inline script in MetaTags
343
+ * - Automatic ThemeProvider wrapping in NavigationProvider
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * const router = createRouter<AppEnv>({
348
+ * theme: {
349
+ * defaultTheme: "system",
350
+ * themes: ["light", "dark"],
351
+ * }
352
+ * });
353
+ *
354
+ * // In route handler:
355
+ * route("settings", (ctx) => {
356
+ * const theme = ctx.theme; // "light" | "dark" | "system"
357
+ * ctx.setTheme("dark"); // Sets cookie
358
+ * return <SettingsPage />;
359
+ * });
360
+ *
361
+ * // In client component:
362
+ * import { useTheme } from "@rangojs/router/theme";
363
+ *
364
+ * function ThemeToggle() {
365
+ * const { theme, setTheme, themes } = useTheme();
366
+ * return <select value={theme} onChange={e => setTheme(e.target.value)}>
367
+ * {themes.map(t => <option key={t}>{t}</option>)}
368
+ * </select>;
369
+ * }
370
+ * ```
371
+ *
372
+ * Use `theme: true` to enable with all defaults.
373
+ */
374
+ theme?: import("../theme/types.js").ThemeConfig | true;
375
+
376
+ /**
377
+ * Default for whether the router wraps `transition()` segments in its own
378
+ * React `<ViewTransition>` boundary (experimental React only).
379
+ *
380
+ * - "auto" (default): every route/layout that opts in via `transition()`
381
+ * gets a router-owned cross-fade.
382
+ * - false: the router never places its own boundary. Routes that use
383
+ * `transition()` still drive navigation through startTransition (so loaders
384
+ * hold instead of flashing a skeleton) and still let consumer-placed
385
+ * `<ViewTransition>` elements animate — the router just contributes no
386
+ * cross-fade of its own. This is the "router triggers, you place the
387
+ * transitions" model.
388
+ *
389
+ * A per-segment `transition({ viewTransition })` overrides this default.
390
+ *
391
+ * @example
392
+ * ```typescript
393
+ * // App-wide: drive + hold, but never auto-wrap. Place <ViewTransition>
394
+ * // yourself in components where you want a morph.
395
+ * const router = createRouter<AppEnv>({ viewTransition: false });
396
+ * ```
397
+ */
398
+ viewTransition?: "auto" | false;
399
+
400
+ /**
401
+ * URL patterns to register with the router.
402
+ *
403
+ * Accepts either a `UrlPatterns` object from `urls()` or a builder function
404
+ * directly (urls() is called implicitly).
405
+ *
406
+ * @example
407
+ * ```typescript
408
+ * // With urls()
409
+ * createRouter<AppEnv>({
410
+ * document: Document,
411
+ * urls: urlpatterns,
412
+ * });
413
+ *
414
+ * // With builder function
415
+ * createRouter<AppEnv>({
416
+ * document: Document,
417
+ * urls: ({ path }) => [
418
+ * path("/", HomePage, { name: "home" }),
419
+ * path("/about", AboutPage, { name: "about" }),
420
+ * ],
421
+ * });
422
+ * ```
423
+ */
424
+ urls?: UrlPatterns<TEnv, any> | UrlBuilder<TEnv>;
425
+
426
+ /**
427
+ * Injected by the Vite transform at compile time.
428
+ * Static import of NamedRoutes from the generated named-routes file.
429
+ * Used to seed reverse() with the full named route map.
430
+ * @internal
431
+ */
432
+ $$routeNames?: Record<string, NamedRouteEntry>;
433
+
434
+ /**
435
+ * Nonce provider for Content Security Policy (CSP).
436
+ *
437
+ * Can be:
438
+ * - A function that returns a nonce string
439
+ * - A function that returns `true` to auto-generate a nonce
440
+ * - Undefined to disable nonce (default)
441
+ *
442
+ * The nonce will be applied to inline scripts injected by the RSC payload.
443
+ * It's also available to middleware via the typed `nonce` token:
444
+ * `import { nonce } from "@rangojs/router"; ctx.get(nonce)`
445
+ *
446
+ * @example Auto-generate nonce
447
+ * ```tsx
448
+ * createRouter({
449
+ * nonce: () => true,
450
+ * });
451
+ * ```
452
+ *
453
+ * @example Custom nonce from request context
454
+ * ```tsx
455
+ * createRouter({
456
+ * nonce: (request, env) => env.nonce,
457
+ * });
458
+ * ```
459
+ *
460
+ * @example Access nonce in middleware
461
+ * ```tsx
462
+ * import { nonce } from "@rangojs/router";
463
+ *
464
+ * const cspMiddleware: Middleware = async (ctx, next) => {
465
+ * const value = ctx.get(nonce); // string | undefined
466
+ * await next();
467
+ * };
468
+ * ```
469
+ */
470
+ nonce?: NonceProvider<TEnv>;
471
+
472
+ /**
473
+ * RSC version string included in metadata.
474
+ * The browser sends this back on partial requests to detect version mismatches.
475
+ *
476
+ * Defaults to the auto-generated VERSION from `@rangojs/router:version` virtual module.
477
+ * Only set this if you need a custom versioning strategy.
478
+ *
479
+ * @default VERSION from @rangojs/router:version
480
+ */
481
+ version?: string;
482
+
483
+ /**
484
+ * TTL (in seconds) for the in-memory prefetch cache and the
485
+ * Cache-Control header on prefetch responses.
486
+ *
487
+ * Controls how long prefetch responses are kept in the client-side
488
+ * in-memory cache and sets `Cache-Control: private, max-age=<ttl>`
489
+ * on server responses for CDN/edge caching.
490
+ *
491
+ * The cache is automatically invalidated on server actions regardless
492
+ * of TTL, so this is primarily a staleness safety net.
493
+ *
494
+ * Set to `false` to disable prefetch caching entirely.
495
+ *
496
+ * @default 300 (5 minutes)
497
+ */
498
+ prefetchCacheTTL?: number | false;
499
+
500
+ /**
501
+ * Maximum number of decoded prefetch payloads the client keeps in its
502
+ * in-memory prefetch cache. When the cache is full the oldest entry is
503
+ * evicted (FIFO) to make room for a new prefetch.
504
+ *
505
+ * Each entry retains a fully decoded RSC payload (and the route's client
506
+ * chunks pulled in while decoding), so this is the lever on client-side
507
+ * prefetch memory: a higher value warms more routes at the cost of more
508
+ * retained payloads. Staleness is bounded separately by `prefetchCacheTTL`;
509
+ * this bounds the entry COUNT.
510
+ *
511
+ * Values below 1 (or non-finite) fall back to the default. To turn
512
+ * prefetching off entirely, set `prefetchCacheTTL: false` instead.
513
+ *
514
+ * @default 100
515
+ */
516
+ prefetchCacheSize?: number;
517
+
518
+ /**
519
+ * Maximum number of speculative prefetch requests (viewport/render strategy)
520
+ * the client runs concurrently. Hover prefetches bypass this queue and fire
521
+ * immediately; this caps only the background, idle-gated queue so prefetches
522
+ * never saturate the browser's connection pool.
523
+ *
524
+ * Values below 1 (or non-finite) fall back to the default.
525
+ *
526
+ * @default 2
527
+ */
528
+ prefetchConcurrency?: number;
529
+
530
+ /**
531
+ * Prefix for the rango state cookie name. The resolved name is
532
+ * `{prefix}_{routerId}`; the prefix is sanitized to cookie-name-safe
533
+ * characters (`[A-Za-z0-9-]`) and an empty result falls back to the default.
534
+ *
535
+ * The rango state cookie keys the client's prefetch / HTTP caches. Overriding
536
+ * the prefix lets you align it with cookie-naming policies or consent-manager
537
+ * classification lists, or avoid colliding with an existing `rango-state`
538
+ * cookie. It is not a full-name override: the `_{routerId}` suffix is what
539
+ * keeps sibling apps on one origin from clobbering each other's state.
540
+ *
541
+ * @default "rango-state"
542
+ */
543
+ stateCookiePrefix?: string;
544
+
545
+ /**
546
+ * Enable connection warmup to keep TCP+TLS alive after idle periods.
547
+ *
548
+ * When enabled, the client sends a HEAD request after the user returns
549
+ * from an idle period (60s+), prewarming the TLS connection before
550
+ * the next navigation.
551
+ *
552
+ * @default true
553
+ */
554
+ warmup?: boolean;
555
+
556
+ /**
557
+ * Wrap the hydrated client tree in `React.StrictMode`.
558
+ *
559
+ * The Rango browser entry hydrates the app inside `<React.StrictMode>` by
560
+ * default. StrictMode double-invokes render and (in development) mounts,
561
+ * unmounts, then remounts every effect to surface impure renders and missing
562
+ * effect cleanup. Production builds treat StrictMode as a no-op, so this flag
563
+ * only changes development behavior in a normal app.
564
+ *
565
+ * Set to `false` to hydrate without the StrictMode wrapper. The main reason to
566
+ * opt out is to isolate StrictMode's intentional double-render/double-effect
567
+ * from genuine re-renders when measuring client-hook stability — with
568
+ * StrictMode off, render counts are exact in development too.
569
+ *
570
+ * The value is resolved server-side at router creation and shipped to the
571
+ * client in the initial payload metadata; the browser entry reads it once at
572
+ * hydration. Changing it does not affect the SSR HTML (StrictMode emits no
573
+ * DOM), so toggling it never causes a hydration mismatch.
574
+ *
575
+ * @default true
576
+ */
577
+ strictMode?: boolean;
578
+
579
+ /**
580
+ * Shorthand timeout (ms) applied to both action execution and render start.
581
+ * Does NOT apply to streamIdleMs.
582
+ * Overridden by individual values in `timeouts`.
583
+ *
584
+ * @example
585
+ * ```typescript
586
+ * createRouter({ timeout: 10_000 });
587
+ * ```
588
+ */
589
+ timeout?: number;
590
+
591
+ /**
592
+ * Structured timeout configuration per phase.
593
+ * Values here override the `timeout` shorthand.
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * createRouter({
598
+ * timeouts: {
599
+ * actionMs: 10_000,
600
+ * renderStartMs: 8_000,
601
+ * },
602
+ * });
603
+ * ```
604
+ */
605
+ timeouts?: RouterTimeouts;
606
+
607
+ /**
608
+ * Custom handler invoked when a timeout occurs.
609
+ * Receives context about which phase timed out and must return a Response.
610
+ * If not provided, returns a plain 504 with "Request timed out" body
611
+ * and X-Rango-Timeout-Phase header.
612
+ *
613
+ * If the callback throws, the default 504 response is used as fallback.
614
+ *
615
+ * @example
616
+ * ```typescript
617
+ * createRouter({
618
+ * timeout: 10_000,
619
+ * onTimeout: (ctx) => {
620
+ * return new Response(
621
+ * JSON.stringify({ error: "timeout", phase: ctx.phase }),
622
+ * { status: 504, headers: { "Content-Type": "application/json" } },
623
+ * );
624
+ * },
625
+ * });
626
+ * ```
627
+ */
628
+ onTimeout?: OnTimeoutCallback<TEnv>;
629
+
630
+ /**
631
+ * Telemetry sink for structured, discrete lifecycle EVENTS: request
632
+ * start/end/error, loader start/end/error, handler errors, cache decisions,
633
+ * revalidation decisions, timeouts, origin rejections.
634
+ *
635
+ * This is the EVENT surface. Phase-duration SPANS (request/middleware/action/
636
+ * handler/loader/render/ssr timing wired into a tracing backend) come from the
637
+ * separate `tracing` option below — a sink does not emit them, because async-context nesting
638
+ * cannot be faithfully reconstructed from after-the-fact start/end events.
639
+ *
640
+ * No-op when not configured (zero overhead).
641
+ *
642
+ * @example Console logging
643
+ * ```typescript
644
+ * import { createConsoleSink } from "@rangojs/router";
645
+ *
646
+ * const router = createRouter({
647
+ * telemetry: createConsoleSink(),
648
+ * });
649
+ * ```
650
+ *
651
+ * @example OpenTelemetry — pair the event sink with the tracing slot
652
+ * ```typescript
653
+ * import { createOTelTracing, createOTelSink } from "@rangojs/router";
654
+ * import { trace } from "@opentelemetry/api";
655
+ *
656
+ * const tracer = trace.getTracer("my-app");
657
+ * const router = createRouter({
658
+ * tracing: createOTelTracing(tracer), // phase spans
659
+ * telemetry: createOTelSink(tracer), // discrete-fact events
660
+ * });
661
+ * ```
662
+ *
663
+ * @example Custom sink
664
+ * ```typescript
665
+ * const router = createRouter({
666
+ * telemetry: {
667
+ * emit(event) {
668
+ * myTracer.record(event);
669
+ * },
670
+ * },
671
+ * });
672
+ * ```
673
+ */
674
+ telemetry?: TelemetrySink;
675
+
676
+ /**
677
+ * Span tracing for the router's performance phases (request, middleware, action,
678
+ * loaders, render, ssr). Connects the same phases shown in the
679
+ * `debugPerformance` timeline to the host platform's tracing system. This is
680
+ * the SPAN surface (the `telemetry` option above is the event surface).
681
+ *
682
+ * Two factories produce a config, both for this slot:
683
+ * - `createOTelTracing(tracer)` from `@rangojs/router` — any platform with an
684
+ * OpenTelemetry SDK (including Node). Bridges the phases onto
685
+ * `tracer.startActiveSpan`.
686
+ * - `createCloudflareTracing()` from `@rangojs/router/cloudflare` — Cloudflare
687
+ * Workers native custom spans, alongside the automatic KV/D1/fetch spans.
688
+ *
689
+ * When tracing is unset — or off-platform (no OTel SDK / no Cloudflare tracing
690
+ * destination) — every span call falls through to the work directly, so the
691
+ * request behaves exactly as if tracing were off.
692
+ *
693
+ * @example OpenTelemetry
694
+ * ```typescript
695
+ * import { createOTelTracing } from "@rangojs/router";
696
+ * import { trace } from "@opentelemetry/api";
697
+ *
698
+ * const router = createRouter({
699
+ * tracing: createOTelTracing(trace.getTracer("my-app")),
700
+ * });
701
+ * ```
702
+ *
703
+ * @example Cloudflare
704
+ * ```typescript
705
+ * import { createCloudflareTracing } from "@rangojs/router/cloudflare";
706
+ *
707
+ * const router = createRouter({
708
+ * tracing: createCloudflareTracing({ spans: { ssr: false } }),
709
+ * });
710
+ * ```
711
+ */
712
+ tracing?: RouterTracingConfig;
713
+
714
+ /**
715
+ * SSR configuration options.
716
+ *
717
+ * @example
718
+ * ```typescript
719
+ * createRouter({
720
+ * ssr: {
721
+ * resolveStreaming: async ({ request, env }) => {
722
+ * const bot = await detectBot(request, env);
723
+ * return bot.isBot ? "allReady" : "stream";
724
+ * },
725
+ * },
726
+ * });
727
+ * ```
728
+ */
729
+ ssr?: SSROptions<TEnv>;
730
+
731
+ /**
732
+ * Cross-origin request protection for server actions, loader fetches,
733
+ * and progressive enhancement form submissions.
734
+ *
735
+ * When enabled, the router validates that the request's Origin header
736
+ * (or Referer fallback) matches the Host before executing actions,
737
+ * loaders, or PE submissions. Requests without Origin/Referer are
738
+ * allowed (same-origin navigations, non-browser clients).
739
+ *
740
+ * The built-in check compares Origin against the Host header and
741
+ * url.protocol. It does NOT trust X-Forwarded-Host/Proto headers
742
+ * (they are client-controllable without a trusted proxy). On standard
743
+ * deployments (Cloudflare Workers, Node behind nginx/caddy) the Host
744
+ * header is already set to the public-facing host by the platform or
745
+ * proxy. For non-standard proxy setups where Host differs from the
746
+ * public origin, use a custom function that reads the appropriate
747
+ * forwarded headers from your trusted proxy.
748
+ *
749
+ * - `true` (default) -- enable built-in origin validation
750
+ * - `false` -- disable
751
+ * - function -- full custom control with access to env, phase,
752
+ * and the built-in check via `ctx.defaultCheck()`
753
+ *
754
+ * The callback receives `OriginCheckContext` with `request`, `url`,
755
+ * `env`, `routerId`, `phase` ("action" | "loader" | "pe-form"),
756
+ * and `defaultCheck()`. Return `true` to allow, `false` for default
757
+ * 403 rejection, or a `Response` for custom rejection.
758
+ *
759
+ * @default true
760
+ *
761
+ * @example Trusted proxy with X-Forwarded-Host
762
+ * ```ts
763
+ * createRouter({
764
+ * originCheck({ request, url, env, defaultCheck }) {
765
+ * if (env.TRUST_PROXY) {
766
+ * const origin = request.headers.get("origin");
767
+ * if (!origin) return true;
768
+ * if (origin === "null") return false;
769
+ * const host = request.headers.get("x-forwarded-host")
770
+ * ?? request.headers.get("host") ?? url.host;
771
+ * return origin.toLowerCase() === `${url.protocol}//${host}`.toLowerCase();
772
+ * }
773
+ * return defaultCheck();
774
+ * },
775
+ * });
776
+ * ```
777
+ */
778
+ originCheck?: import("../rsc/origin-guard.js").OriginCheckConfig<TEnv>;
779
+ }