@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.8a4d0430

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 (300) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +884 -4
  3. package/dist/bin/rango.js +1601 -0
  4. package/dist/vite/index.js +4474 -867
  5. package/package.json +60 -51
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +262 -0
  8. package/skills/caching/SKILL.md +50 -21
  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 +89 -30
  18. package/skills/loader/SKILL.md +388 -38
  19. package/skills/middleware/SKILL.md +171 -34
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +78 -1
  22. package/skills/prerender/SKILL.md +643 -0
  23. package/skills/rango/SKILL.md +85 -16
  24. package/skills/response-routes/SKILL.md +411 -0
  25. package/skills/route/SKILL.md +226 -14
  26. package/skills/router-setup/SKILL.md +123 -30
  27. package/skills/tailwind/SKILL.md +129 -0
  28. package/skills/theme/SKILL.md +9 -8
  29. package/skills/typesafety/SKILL.md +318 -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/event-controller.ts +87 -64
  36. package/src/browser/history-state.ts +80 -0
  37. package/src/browser/intercept-utils.ts +52 -0
  38. package/src/browser/link-interceptor.ts +24 -4
  39. package/src/browser/logging.ts +55 -0
  40. package/src/browser/merge-segment-loaders.ts +20 -12
  41. package/src/browser/navigation-bridge.ts +285 -553
  42. package/src/browser/navigation-client.ts +124 -71
  43. package/src/browser/navigation-store.ts +33 -50
  44. package/src/browser/navigation-transaction.ts +295 -0
  45. package/src/browser/network-error-handler.ts +61 -0
  46. package/src/browser/partial-update.ts +258 -308
  47. package/src/browser/prefetch/cache.ts +146 -0
  48. package/src/browser/prefetch/fetch.ts +135 -0
  49. package/src/browser/prefetch/observer.ts +65 -0
  50. package/src/browser/prefetch/policy.ts +42 -0
  51. package/src/browser/prefetch/queue.ts +88 -0
  52. package/src/browser/rango-state.ts +112 -0
  53. package/src/browser/react/Link.tsx +185 -73
  54. package/src/browser/react/NavigationProvider.tsx +51 -11
  55. package/src/browser/react/context.ts +6 -0
  56. package/src/browser/react/filter-segment-order.ts +11 -0
  57. package/src/browser/react/index.ts +12 -12
  58. package/src/browser/react/location-state-shared.ts +95 -53
  59. package/src/browser/react/location-state.ts +60 -15
  60. package/src/browser/react/mount-context.ts +6 -1
  61. package/src/browser/react/nonce-context.ts +23 -0
  62. package/src/browser/react/shallow-equal.ts +27 -0
  63. package/src/browser/react/use-action.ts +29 -51
  64. package/src/browser/react/use-client-cache.ts +5 -3
  65. package/src/browser/react/use-handle.ts +32 -79
  66. package/src/browser/react/use-href.tsx +2 -2
  67. package/src/browser/react/use-link-status.ts +6 -5
  68. package/src/browser/react/use-navigation.ts +22 -63
  69. package/src/browser/react/use-params.ts +65 -0
  70. package/src/browser/react/use-pathname.ts +47 -0
  71. package/src/browser/react/use-router.ts +63 -0
  72. package/src/browser/react/use-search-params.ts +56 -0
  73. package/src/browser/react/use-segments.ts +80 -97
  74. package/src/browser/response-adapter.ts +73 -0
  75. package/src/browser/rsc-router.tsx +107 -26
  76. package/src/browser/scroll-restoration.ts +92 -16
  77. package/src/browser/segment-reconciler.ts +216 -0
  78. package/src/browser/segment-structure-assert.ts +16 -0
  79. package/src/browser/server-action-bridge.ts +504 -599
  80. package/src/browser/shallow.ts +6 -1
  81. package/src/browser/types.ts +109 -47
  82. package/src/browser/validate-redirect-origin.ts +29 -0
  83. package/src/build/generate-manifest.ts +235 -24
  84. package/src/build/generate-route-types.ts +36 -0
  85. package/src/build/index.ts +13 -0
  86. package/src/build/route-trie.ts +265 -0
  87. package/src/build/route-types/ast-helpers.ts +25 -0
  88. package/src/build/route-types/ast-route-extraction.ts +98 -0
  89. package/src/build/route-types/codegen.ts +102 -0
  90. package/src/build/route-types/include-resolution.ts +411 -0
  91. package/src/build/route-types/param-extraction.ts +48 -0
  92. package/src/build/route-types/per-module-writer.ts +128 -0
  93. package/src/build/route-types/router-processing.ts +469 -0
  94. package/src/build/route-types/scan-filter.ts +78 -0
  95. package/src/build/runtime-discovery.ts +231 -0
  96. package/src/cache/background-task.ts +34 -0
  97. package/src/cache/cache-key-utils.ts +44 -0
  98. package/src/cache/cache-policy.ts +125 -0
  99. package/src/cache/cache-runtime.ts +338 -0
  100. package/src/cache/cache-scope.ts +120 -303
  101. package/src/cache/cf/cf-cache-store.ts +119 -7
  102. package/src/cache/cf/index.ts +8 -2
  103. package/src/cache/document-cache.ts +101 -72
  104. package/src/cache/handle-capture.ts +81 -0
  105. package/src/cache/handle-snapshot.ts +41 -0
  106. package/src/cache/index.ts +0 -15
  107. package/src/cache/memory-segment-store.ts +191 -13
  108. package/src/cache/profile-registry.ts +73 -0
  109. package/src/cache/read-through-swr.ts +134 -0
  110. package/src/cache/segment-codec.ts +256 -0
  111. package/src/cache/taint.ts +98 -0
  112. package/src/cache/types.ts +72 -122
  113. package/src/client.rsc.tsx +3 -1
  114. package/src/client.tsx +106 -126
  115. package/src/component-utils.ts +4 -4
  116. package/src/components/DefaultDocument.tsx +5 -1
  117. package/src/context-var.ts +86 -0
  118. package/src/debug.ts +17 -7
  119. package/src/errors.ts +108 -2
  120. package/src/handle.ts +15 -29
  121. package/src/handles/MetaTags.tsx +73 -20
  122. package/src/handles/breadcrumbs.ts +66 -0
  123. package/src/handles/index.ts +1 -0
  124. package/src/handles/meta.ts +30 -13
  125. package/src/host/cookie-handler.ts +21 -15
  126. package/src/host/errors.ts +8 -8
  127. package/src/host/index.ts +4 -7
  128. package/src/host/pattern-matcher.ts +27 -27
  129. package/src/host/router.ts +61 -39
  130. package/src/host/testing.ts +8 -8
  131. package/src/host/types.ts +15 -7
  132. package/src/host/utils.ts +1 -1
  133. package/src/href-client.ts +119 -29
  134. package/src/index.rsc.ts +153 -19
  135. package/src/index.ts +211 -30
  136. package/src/internal-debug.ts +11 -0
  137. package/src/loader.rsc.ts +26 -157
  138. package/src/loader.ts +27 -10
  139. package/src/network-error-thrower.tsx +3 -1
  140. package/src/outlet-provider.tsx +45 -0
  141. package/src/prerender/param-hash.ts +37 -0
  142. package/src/prerender/store.ts +185 -0
  143. package/src/prerender.ts +463 -0
  144. package/src/reverse.ts +330 -0
  145. package/src/root-error-boundary.tsx +41 -29
  146. package/src/route-content-wrapper.tsx +7 -4
  147. package/src/route-definition/dsl-helpers.ts +934 -0
  148. package/src/route-definition/helper-factories.ts +200 -0
  149. package/src/route-definition/helpers-types.ts +430 -0
  150. package/src/route-definition/index.ts +52 -0
  151. package/src/route-definition/redirect.ts +93 -0
  152. package/src/route-definition.ts +1 -1428
  153. package/src/route-map-builder.ts +211 -123
  154. package/src/route-name.ts +53 -0
  155. package/src/route-types.ts +59 -8
  156. package/src/router/content-negotiation.ts +116 -0
  157. package/src/router/debug-manifest.ts +72 -0
  158. package/src/router/error-handling.ts +9 -9
  159. package/src/router/find-match.ts +158 -0
  160. package/src/router/handler-context.ts +374 -81
  161. package/src/router/intercept-resolution.ts +395 -0
  162. package/src/router/lazy-includes.ts +234 -0
  163. package/src/router/loader-resolution.ts +215 -122
  164. package/src/router/logging.ts +248 -0
  165. package/src/router/manifest.ts +148 -35
  166. package/src/router/match-api.ts +620 -0
  167. package/src/router/match-context.ts +5 -3
  168. package/src/router/match-handlers.ts +440 -0
  169. package/src/router/match-middleware/background-revalidation.ts +80 -93
  170. package/src/router/match-middleware/cache-lookup.ts +382 -9
  171. package/src/router/match-middleware/cache-store.ts +51 -22
  172. package/src/router/match-middleware/intercept-resolution.ts +55 -17
  173. package/src/router/match-middleware/segment-resolution.ts +24 -6
  174. package/src/router/match-pipelines.ts +10 -45
  175. package/src/router/match-result.ts +34 -28
  176. package/src/router/metrics.ts +235 -15
  177. package/src/router/middleware-cookies.ts +55 -0
  178. package/src/router/middleware-types.ts +222 -0
  179. package/src/router/middleware.ts +324 -367
  180. package/src/router/pattern-matching.ts +211 -43
  181. package/src/router/prerender-match.ts +402 -0
  182. package/src/router/preview-match.ts +170 -0
  183. package/src/router/revalidation.ts +137 -38
  184. package/src/router/router-context.ts +36 -21
  185. package/src/router/router-interfaces.ts +452 -0
  186. package/src/router/router-options.ts +592 -0
  187. package/src/router/router-registry.ts +24 -0
  188. package/src/router/segment-resolution/fresh.ts +570 -0
  189. package/src/router/segment-resolution/helpers.ts +263 -0
  190. package/src/router/segment-resolution/loader-cache.ts +198 -0
  191. package/src/router/segment-resolution/revalidation.ts +1241 -0
  192. package/src/router/segment-resolution/static-store.ts +67 -0
  193. package/src/router/segment-resolution.ts +21 -0
  194. package/src/router/segment-wrappers.ts +289 -0
  195. package/src/router/telemetry-otel.ts +299 -0
  196. package/src/router/telemetry.ts +300 -0
  197. package/src/router/timeout.ts +148 -0
  198. package/src/router/trie-matching.ts +239 -0
  199. package/src/router/types.ts +77 -3
  200. package/src/router.ts +692 -4257
  201. package/src/rsc/handler-context.ts +45 -0
  202. package/src/rsc/handler.ts +764 -754
  203. package/src/rsc/helpers.ts +140 -6
  204. package/src/rsc/index.ts +0 -20
  205. package/src/rsc/loader-fetch.ts +209 -0
  206. package/src/rsc/manifest-init.ts +86 -0
  207. package/src/rsc/nonce.ts +14 -0
  208. package/src/rsc/origin-guard.ts +141 -0
  209. package/src/rsc/progressive-enhancement.ts +379 -0
  210. package/src/rsc/response-error.ts +37 -0
  211. package/src/rsc/response-route-handler.ts +347 -0
  212. package/src/rsc/rsc-rendering.ts +235 -0
  213. package/src/rsc/runtime-warnings.ts +42 -0
  214. package/src/rsc/server-action.ts +348 -0
  215. package/src/rsc/ssr-setup.ts +128 -0
  216. package/src/rsc/types.ts +38 -11
  217. package/src/search-params.ts +230 -0
  218. package/src/segment-system.tsx +25 -13
  219. package/src/server/context.ts +182 -51
  220. package/src/server/cookie-store.ts +190 -0
  221. package/src/server/fetchable-loader-store.ts +37 -0
  222. package/src/server/handle-store.ts +94 -15
  223. package/src/server/loader-registry.ts +15 -56
  224. package/src/server/request-context.ts +430 -70
  225. package/src/server.ts +35 -130
  226. package/src/ssr/index.tsx +100 -31
  227. package/src/static-handler.ts +114 -0
  228. package/src/theme/ThemeProvider.tsx +21 -15
  229. package/src/theme/ThemeScript.tsx +5 -5
  230. package/src/theme/constants.ts +5 -2
  231. package/src/theme/index.ts +4 -14
  232. package/src/theme/theme-context.ts +4 -30
  233. package/src/theme/theme-script.ts +21 -18
  234. package/src/types/boundaries.ts +158 -0
  235. package/src/types/cache-types.ts +198 -0
  236. package/src/types/error-types.ts +192 -0
  237. package/src/types/global-namespace.ts +100 -0
  238. package/src/types/handler-context.ts +687 -0
  239. package/src/types/index.ts +88 -0
  240. package/src/types/loader-types.ts +183 -0
  241. package/src/types/route-config.ts +170 -0
  242. package/src/types/route-entry.ts +102 -0
  243. package/src/types/segments.ts +148 -0
  244. package/src/types.ts +1 -1623
  245. package/src/urls/include-helper.ts +197 -0
  246. package/src/urls/index.ts +53 -0
  247. package/src/urls/path-helper-types.ts +339 -0
  248. package/src/urls/path-helper.ts +329 -0
  249. package/src/urls/pattern-types.ts +95 -0
  250. package/src/urls/response-types.ts +106 -0
  251. package/src/urls/type-extraction.ts +372 -0
  252. package/src/urls/urls-function.ts +98 -0
  253. package/src/urls.ts +1 -802
  254. package/src/use-loader.tsx +85 -77
  255. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  256. package/src/vite/discovery/discover-routers.ts +344 -0
  257. package/src/vite/discovery/prerender-collection.ts +385 -0
  258. package/src/vite/discovery/route-types-writer.ts +258 -0
  259. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  260. package/src/vite/discovery/state.ts +110 -0
  261. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  262. package/src/vite/index.ts +11 -1133
  263. package/src/vite/plugin-types.ts +131 -0
  264. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  265. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  266. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  267. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -51
  268. package/src/vite/plugins/expose-id-utils.ts +287 -0
  269. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  270. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  271. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  272. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  273. package/src/vite/plugins/expose-ids/types.ts +45 -0
  274. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  275. package/src/vite/plugins/refresh-cmd.ts +65 -0
  276. package/src/vite/plugins/use-cache-transform.ts +323 -0
  277. package/src/vite/plugins/version-injector.ts +83 -0
  278. package/src/vite/plugins/version-plugin.ts +254 -0
  279. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  280. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  281. package/src/vite/rango.ts +510 -0
  282. package/src/vite/router-discovery.ts +785 -0
  283. package/src/vite/utils/ast-handler-extract.ts +517 -0
  284. package/src/vite/utils/banner.ts +36 -0
  285. package/src/vite/utils/bundle-analysis.ts +137 -0
  286. package/src/vite/utils/manifest-utils.ts +70 -0
  287. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  288. package/src/vite/utils/prerender-utils.ts +189 -0
  289. package/src/vite/utils/shared-utils.ts +169 -0
  290. package/CLAUDE.md +0 -43
  291. package/src/browser/lru-cache.ts +0 -69
  292. package/src/browser/request-controller.ts +0 -164
  293. package/src/cache/memory-store.ts +0 -253
  294. package/src/href-context.ts +0 -33
  295. package/src/href.ts +0 -255
  296. package/src/server/route-manifest-cache.ts +0 -173
  297. package/src/vite/expose-handle-id.ts +0 -209
  298. package/src/vite/expose-loader-id.ts +0 -426
  299. package/src/vite/expose-location-state-id.ts +0 -177
  300. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Theme module exports for @rangojs/router/theme
3
3
  *
4
- * This module provides theme management for rsc-router:
4
+ * This module provides the public theme API:
5
5
  * - useTheme: Hook for accessing theme state in client components
6
6
  * - ThemeProvider: Component for manual theme provider setup (typically not needed)
7
+ * - ThemeScript: FOUC-prevention script component for document/head usage
7
8
  * - Types for theme configuration
8
9
  *
9
10
  * @example
@@ -43,16 +44,5 @@ export type {
43
44
  ThemeContextValue,
44
45
  } from "./types.js";
45
46
 
46
- // Constants (for advanced use cases)
47
- export { THEME_DEFAULTS, THEME_COOKIE, resolveThemeConfig } from "./constants.js";
48
-
49
- // Script generation (for advanced SSR use cases)
50
- export { generateThemeScript, getNonceAttribute } from "./theme-script.js";
51
-
52
- // Context (for advanced use cases)
53
- export {
54
- ThemeContext,
55
- useThemeContext,
56
- initThemeConfigSync,
57
- getSSRThemeConfig,
58
- } from "./theme-context.js";
47
+ // Constants
48
+ export { THEME_DEFAULTS, THEME_COOKIE } from "./constants.js";
@@ -10,40 +10,14 @@
10
10
  */
11
11
 
12
12
  import { createContext, useContext, type Context } from "react";
13
- import type { ResolvedThemeConfig, ThemeContextValue } from "./types.js";
13
+ import type { ThemeContextValue } from "./types.js";
14
14
 
15
15
  /**
16
16
  * React context for theme state
17
17
  * null when theme is not enabled in router config
18
18
  */
19
- export const ThemeContext: Context<ThemeContextValue | null> = createContext<ThemeContextValue | null>(null);
20
-
21
- /**
22
- * SSR module-level state for theme config.
23
- * Populated by initThemeConfigSync before React renders.
24
- * Used by MetaTags during SSR to render the theme script.
25
- */
26
- let ssrThemeConfig: ResolvedThemeConfig | null = null;
27
-
28
- /**
29
- * Initialize theme config synchronously for SSR.
30
- * Called before rendering to populate state for MetaTags.
31
- *
32
- * @param config - Theme config from router, or null if theme is disabled
33
- */
34
- export function initThemeConfigSync(config: ResolvedThemeConfig | null): void {
35
- ssrThemeConfig = config;
36
- }
37
-
38
- /**
39
- * Get theme config for SSR/hydration.
40
- * Used by MetaTags to render the theme script.
41
- *
42
- * @returns Theme config if available, null otherwise
43
- */
44
- export function getSSRThemeConfig(): ResolvedThemeConfig | null {
45
- return ssrThemeConfig;
46
- }
19
+ export const ThemeContext: Context<ThemeContextValue | null> =
20
+ createContext<ThemeContextValue | null>(null);
47
21
 
48
22
  /**
49
23
  * Get theme context (internal use)
@@ -63,7 +37,7 @@ export function requireThemeContext(): ThemeContextValue {
63
37
  throw new Error(
64
38
  "useTheme must be used within a ThemeProvider. " +
65
39
  "Make sure theme is enabled in your router config: " +
66
- "createRouter({ theme: { ... } })"
40
+ "createRouter({ theme: { ... } })",
67
41
  );
68
42
  }
69
43
  return ctx;
@@ -40,7 +40,8 @@ export function generateThemeScript(config: ResolvedThemeConfig): string {
40
40
  for (var i = 0; i < cookies.length; i++) {
41
41
  var cookie = cookies[i].trim();
42
42
  if (cookie.indexOf(storageKey + '=') === 0) {
43
- return decodeURIComponent(cookie.substring(storageKey.length + 1));
43
+ try { return decodeURIComponent(cookie.substring(storageKey.length + 1)); }
44
+ catch (e) { return cookie.substring(storageKey.length + 1); }
44
45
  }
45
46
  }
46
47
  // Fall back to localStorage
@@ -125,23 +126,25 @@ export function generateThemeScript(config: ResolvedThemeConfig): string {
125
126
  * Removes comments, extra whitespace, and unnecessary newlines
126
127
  */
127
128
  function minifyScript(script: string): string {
128
- return script
129
- // Remove single-line comments
130
- .replace(/\/\/.*$/gm, "")
131
- // Remove multi-line comments
132
- .replace(/\/\*[\s\S]*?\*\//g, "")
133
- // Remove leading/trailing whitespace from lines
134
- .split("\n")
135
- .map((line) => line.trim())
136
- .filter((line) => line.length > 0)
137
- .join("")
138
- // Collapse multiple spaces to single space
139
- .replace(/\s+/g, " ")
140
- // Remove spaces around operators and punctuation
141
- .replace(/\s*([{};,=!<>()[\]+\-*/&|?:])\s*/g, "$1")
142
- // Add back necessary spaces (e.g., "var x")
143
- .replace(/(var|function|return|if|for|try|catch|typeof|else)\(/g, "$1 (")
144
- .replace(/\)([a-zA-Z])/g, ") $1");
129
+ return (
130
+ script
131
+ // Remove single-line comments
132
+ .replace(/\/\/.*$/gm, "")
133
+ // Remove multi-line comments
134
+ .replace(/\/\*[\s\S]*?\*\//g, "")
135
+ // Remove leading/trailing whitespace from lines
136
+ .split("\n")
137
+ .map((line) => line.trim())
138
+ .filter((line) => line.length > 0)
139
+ .join("")
140
+ // Collapse multiple spaces to single space
141
+ .replace(/\s+/g, " ")
142
+ // Remove spaces around operators and punctuation
143
+ .replace(/\s*([{};,=!<>()[\]+\-*/&|?:])\s*/g, "$1")
144
+ // Add back necessary spaces (e.g., "var x")
145
+ .replace(/(var|function|return|if|for|try|catch|typeof|else)\(/g, "$1 (")
146
+ .replace(/\)([a-zA-Z])/g, ") $1")
147
+ );
145
148
  }
146
149
 
147
150
  /**
@@ -0,0 +1,158 @@
1
+ import type { ReactNode } from "react";
2
+
3
+ /**
4
+ * Error information passed to error boundary fallback components
5
+ */
6
+ export interface ErrorInfo {
7
+ /** Error message (always available) */
8
+ message: string;
9
+ /** Error name/type (e.g., "RouteNotFoundError", "MiddlewareError") */
10
+ name: string;
11
+ /** Optional error code for programmatic handling */
12
+ code?: string;
13
+ /** Stack trace (only in development) */
14
+ stack?: string;
15
+ /** Original error cause if available */
16
+ cause?: unknown;
17
+ /** Segment ID where the error occurred */
18
+ segmentId: string;
19
+ /** Segment type where the error occurred */
20
+ segmentType:
21
+ | "layout"
22
+ | "route"
23
+ | "parallel"
24
+ | "loader"
25
+ | "middleware"
26
+ | "cache";
27
+ }
28
+
29
+ /**
30
+ * Props passed to server-side error boundary fallback components
31
+ *
32
+ * Server error boundaries don't have a reset function since the error
33
+ * occurred during server rendering. Users can navigate away or refresh.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * function ProductErrorFallback({ error }: ErrorBoundaryFallbackProps) {
38
+ * return (
39
+ * <div>
40
+ * <h2>Something went wrong loading the product</h2>
41
+ * <p>{error.message}</p>
42
+ * <a href="/">Go home</a>
43
+ * </div>
44
+ * );
45
+ * }
46
+ * ```
47
+ */
48
+ export interface ErrorBoundaryFallbackProps {
49
+ /** Error information */
50
+ error: ErrorInfo;
51
+ }
52
+
53
+ /**
54
+ * Error boundary handler - receives error info and returns fallback UI
55
+ */
56
+ export type ErrorBoundaryHandler = (
57
+ props: ErrorBoundaryFallbackProps,
58
+ ) => ReactNode;
59
+
60
+ /**
61
+ * Props passed to client-side error boundary fallback components
62
+ *
63
+ * Client error boundaries have a reset function that clears the error state
64
+ * and re-renders the children.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * function ClientErrorFallback({ error, reset }: ClientErrorBoundaryFallbackProps) {
69
+ * return (
70
+ * <div>
71
+ * <h2>Something went wrong</h2>
72
+ * <p>{error.message}</p>
73
+ * <button onClick={reset}>Try again</button>
74
+ * </div>
75
+ * );
76
+ * }
77
+ * ```
78
+ */
79
+ export interface ClientErrorBoundaryFallbackProps {
80
+ /** Error information */
81
+ error: ErrorInfo;
82
+ /** Function to reset error state and retry rendering */
83
+ reset: () => void;
84
+ }
85
+
86
+ /**
87
+ * Wrapped loader data result for deferred resolution with error handling.
88
+ * When loaders are deferred to client-side resolution, errors need to be
89
+ * wrapped so the client can handle them appropriately.
90
+ */
91
+ export type LoaderDataResult<T = unknown> =
92
+ | { __loaderResult: true; ok: true; data: T }
93
+ | {
94
+ __loaderResult: true;
95
+ ok: false;
96
+ error: ErrorInfo;
97
+ fallback: ReactNode | null;
98
+ };
99
+
100
+ /**
101
+ * Type guard to check if a value is a wrapped loader result
102
+ */
103
+ export function isLoaderDataResult(value: unknown): value is LoaderDataResult {
104
+ return (
105
+ typeof value === "object" &&
106
+ value !== null &&
107
+ "__loaderResult" in value &&
108
+ (value as any).__loaderResult === true
109
+ );
110
+ }
111
+
112
+ /**
113
+ * Not found information passed to notFound boundary fallback components
114
+ */
115
+ export interface NotFoundInfo {
116
+ /** Not found message */
117
+ message: string;
118
+ /** Segment ID where notFound was thrown */
119
+ segmentId: string;
120
+ /** Segment type where notFound was thrown */
121
+ segmentType:
122
+ | "layout"
123
+ | "route"
124
+ | "parallel"
125
+ | "loader"
126
+ | "middleware"
127
+ | "cache";
128
+ /** The pathname that triggered the not found */
129
+ pathname?: string;
130
+ }
131
+
132
+ /**
133
+ * Props passed to notFound boundary fallback components
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * function ProductNotFound({ notFound }: NotFoundBoundaryFallbackProps) {
138
+ * return (
139
+ * <div>
140
+ * <h2>Product Not Found</h2>
141
+ * <p>{notFound.message}</p>
142
+ * <a href="/products">Browse all products</a>
143
+ * </div>
144
+ * );
145
+ * }
146
+ * ```
147
+ */
148
+ export interface NotFoundBoundaryFallbackProps {
149
+ /** Not found information */
150
+ notFound: NotFoundInfo;
151
+ }
152
+
153
+ /**
154
+ * NotFound boundary handler - receives not found info and returns fallback UI
155
+ */
156
+ export type NotFoundBoundaryHandler = (
157
+ props: NotFoundBoundaryFallbackProps,
158
+ ) => ReactNode;
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Context passed to cache condition/key/tags functions.
3
+ *
4
+ * This is a subset of RequestContext that's guaranteed to be available
5
+ * during cache key generation (before middleware runs).
6
+ *
7
+ * Note: While the full RequestContext is passed, middleware-set variables
8
+ * (ctx.var, ctx.get()) may not be populated yet since cache lookup
9
+ * happens before middleware execution.
10
+ */
11
+ export type { RequestContext as CacheContext } from "../server/request-context.js";
12
+
13
+ /**
14
+ * Cache configuration options for cache() DSL
15
+ *
16
+ * Controls how segments, layouts, and loaders are cached.
17
+ * Cache configuration inherits down the route tree unless overridden.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Basic caching with TTL
22
+ * cache({ ttl: 60 }, () => [
23
+ * layout(<BlogLayout />),
24
+ * route("post/:slug"),
25
+ * ])
26
+ *
27
+ * // With stale-while-revalidate
28
+ * cache({ ttl: 60, swr: 300 }, () => [
29
+ * route("product/:id"),
30
+ * ])
31
+ *
32
+ * // Conditional caching
33
+ * cache({
34
+ * ttl: 300,
35
+ * condition: (ctx) => !ctx.request.headers.get('x-preview'),
36
+ * }, () => [...])
37
+ *
38
+ * // Custom cache key
39
+ * cache({
40
+ * ttl: 300,
41
+ * key: (ctx) => `product-${ctx.params.id}-${ctx.searchParams.get('variant')}`,
42
+ * }, () => [...])
43
+ *
44
+ * // With tags for invalidation
45
+ * cache({
46
+ * ttl: 300,
47
+ * tags: (ctx) => [`product:${ctx.params.id}`, 'products'],
48
+ * }, () => [...])
49
+ * ```
50
+ */
51
+ export interface CacheOptions<TEnv = unknown> {
52
+ /**
53
+ * Time-to-live in seconds.
54
+ * After this period, cached content is considered stale.
55
+ */
56
+ ttl: number;
57
+
58
+ /**
59
+ * Stale-while-revalidate window in seconds (after TTL).
60
+ * During this window, stale content is served immediately while
61
+ * fresh content is fetched in the background via waitUntil.
62
+ *
63
+ * @example
64
+ * // TTL: 60s, SWR: 300s
65
+ * // 0-60s: FRESH (serve from cache)
66
+ * // 60-360s: STALE (serve from cache, revalidate in background)
67
+ * // 360s+: EXPIRED (cache miss, fetch fresh)
68
+ */
69
+ swr?: number;
70
+
71
+ /**
72
+ * Override the cache store for this boundary.
73
+ * When specified, this boundary and its children use this store
74
+ * instead of the app-level store from handler config.
75
+ *
76
+ * Useful for:
77
+ * - Different backends per route section (memory vs KV vs Redis)
78
+ * - Loader-specific caching strategies
79
+ * - Hot data in fast cache, cold data in larger/slower cache
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const kvStore = new CloudflareKVStore(env.CACHE_KV);
84
+ * const memoryStore = new MemorySegmentCacheStore({ defaults: { ttl: 10 } });
85
+ *
86
+ * // Fast memory cache for hot data
87
+ * cache({ store: memoryStore }, () => [
88
+ * route("dashboard"),
89
+ * ])
90
+ *
91
+ * // KV for larger, less frequently accessed data
92
+ * cache({ store: kvStore, ttl: 3600 }, () => [
93
+ * route("archive/:year"),
94
+ * ])
95
+ * ```
96
+ */
97
+ store?: import("../cache/types.js").SegmentCacheStore;
98
+
99
+ /**
100
+ * Conditional cache read function.
101
+ * Return false to skip cache for this request (always fetch fresh).
102
+ *
103
+ * Has access to full RequestContext including env, request, params, cookies, etc.
104
+ * Note: Middleware-set variables (ctx.var) may not be populated yet.
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * condition: (ctx) => {
109
+ * // Skip cache for preview mode
110
+ * if (ctx.request.headers.get('x-preview')) return false;
111
+ * // Skip cache for authenticated users
112
+ * if (ctx.request.headers.has('authorization')) return false;
113
+ * return true;
114
+ * }
115
+ * ```
116
+ */
117
+ condition?: (
118
+ ctx: import("../server/request-context.js").RequestContext<TEnv>,
119
+ ) => boolean;
120
+
121
+ /**
122
+ * Custom cache key function - FULL OVERRIDE.
123
+ * Bypasses default key generation AND store's keyGenerator.
124
+ *
125
+ * Has access to full RequestContext including env, request, params, cookies, etc.
126
+ * Note: Middleware-set variables (ctx.var) may not be populated yet.
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * // Include query params in cache key
131
+ * key: (ctx) => `product-${ctx.params.id}-${ctx.searchParams.get('variant')}`
132
+ *
133
+ * // Include env bindings
134
+ * key: (ctx) => `${ctx.env.REGION}:product:${ctx.params.id}`
135
+ *
136
+ * // Include cookies
137
+ * key: (ctx) => `${cookies().get('locale')?.value ?? 'en'}:${ctx.pathname}`
138
+ * ```
139
+ */
140
+ key?: (
141
+ ctx: import("../server/request-context.js").RequestContext<TEnv>,
142
+ ) => string | Promise<string>;
143
+
144
+ /**
145
+ * Tags for cache invalidation.
146
+ * Can be a static array or a function that returns tags.
147
+ *
148
+ * Note: Tags are passed through to the store but built-in stores
149
+ * (MemorySegmentCacheStore, CFCacheStore) do not yet index or
150
+ * invalidate by tag. Effective tag-based invalidation requires a
151
+ * custom store implementation with secondary indices.
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * // Static tags
156
+ * tags: ['products', 'catalog']
157
+ *
158
+ * // Dynamic tags
159
+ * tags: (ctx) => [`product:${ctx.params.id}`, 'products']
160
+ * ```
161
+ */
162
+ tags?:
163
+ | string[]
164
+ | ((
165
+ ctx: import("../server/request-context.js").RequestContext<TEnv>,
166
+ ) => string[]);
167
+ }
168
+
169
+ /**
170
+ * Partial cache options for cache() DSL.
171
+ *
172
+ * When `ttl` is not specified, it will use the default from cache config.
173
+ * This allows cache() calls to inherit app-level defaults:
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * // App-level default (in handler config)
178
+ * cache: { store: myStore, defaults: { ttl: 60 } }
179
+ *
180
+ * // Route-level (inherits ttl from defaults)
181
+ * cache(() => [
182
+ * route("products"),
183
+ * ])
184
+ *
185
+ * // Override with explicit ttl
186
+ * cache({ ttl: 300 }, () => [...])
187
+ * ```
188
+ */
189
+ export type PartialCacheOptions<TEnv = unknown> = Partial<CacheOptions<TEnv>>;
190
+
191
+ /**
192
+ * Cache entry configuration stored in EntryData.
193
+ * Represents the resolved cache config for a segment.
194
+ */
195
+ export interface EntryCacheConfig {
196
+ /** Cache options (false means caching disabled for this entry) - ttl is optional, uses defaults */
197
+ options: PartialCacheOptions | false;
198
+ }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Phase where the error occurred during request handling.
3
+ *
4
+ * Coverage notes:
5
+ * - "routing": Invoked when route matching fails (router.ts, rsc/handler.ts)
6
+ * - "manifest": Reserved for manifest loading errors (not currently invoked)
7
+ * - "middleware": Reserved for middleware execution errors (errors propagate to handler phase)
8
+ * - "loader": Invoked when loader execution fails (router.ts via wrapLoaderWithErrorHandling, rsc/handler.ts)
9
+ * - "handler": Invoked when route/layout handler execution fails (router.ts)
10
+ * - "rendering": Invoked during SSR rendering errors (ssr/index.tsx, separate callback)
11
+ * - "action": Invoked when server action execution fails (rsc/handler.ts, router.ts)
12
+ * - "revalidation": Invoked when revalidation fails (router.ts, conditional with action)
13
+ * - "origin": Invoked when cross-origin request validation rejects a request (rsc/handler.ts)
14
+ * - "unknown": Fallback for unclassified errors (not currently invoked)
15
+ */
16
+ export type ErrorPhase =
17
+ | "routing" // During route matching
18
+ | "manifest" // During manifest loading (reserved, not currently invoked)
19
+ | "middleware" // During middleware execution (errors propagate to handler phase)
20
+ | "loader" // During loader execution
21
+ | "handler" // During route/layout handler execution
22
+ | "rendering" // During RSC/SSR rendering (SSR handler uses separate callback)
23
+ | "action" // During server action execution
24
+ | "revalidation" // During revalidation evaluation
25
+ | "cache" // During "use cache" background operations (stale revalidation, async cache writes)
26
+ | "prerender" // During build-time pre-rendering (Vite closeBundle)
27
+ | "static" // During build-time static handler rendering (Vite closeBundle)
28
+ | "origin" // During cross-origin request validation (CSRF protection)
29
+ | "unknown"; // Fallback for unclassified errors
30
+
31
+ /**
32
+ * Comprehensive context passed to onError callback
33
+ *
34
+ * Provides all available information about where and when an error occurred
35
+ * during request handling. The callback can use this for logging, monitoring,
36
+ * error tracking services, or custom error responses.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const router = createRouter<AppEnv>({
41
+ * onError: (context) => {
42
+ * // Log to error tracking service
43
+ * errorTracker.capture({
44
+ * error: context.error,
45
+ * phase: context.phase,
46
+ * url: context.request.url,
47
+ * route: context.routeKey,
48
+ * userId: context.env?.user?.id,
49
+ * });
50
+ *
51
+ * // Log to console with context
52
+ * console.error(`[${context.phase}] Error in ${context.routeKey}:`, {
53
+ * message: context.error.message,
54
+ * segment: context.segmentId,
55
+ * duration: context.duration,
56
+ * });
57
+ * },
58
+ * });
59
+ * ```
60
+ */
61
+ export interface OnErrorContext<TEnv = any> {
62
+ /**
63
+ * The error that occurred
64
+ */
65
+ error: Error;
66
+
67
+ /**
68
+ * Phase where the error occurred
69
+ */
70
+ phase: ErrorPhase;
71
+
72
+ /**
73
+ * The original request
74
+ */
75
+ request: Request;
76
+
77
+ /**
78
+ * Parsed URL from the request
79
+ */
80
+ url: URL;
81
+
82
+ /**
83
+ * Request pathname
84
+ */
85
+ pathname: string;
86
+
87
+ /**
88
+ * HTTP method
89
+ */
90
+ method: string;
91
+
92
+ /**
93
+ * Matched route key (if available)
94
+ * e.g., "shop.products.detail"
95
+ */
96
+ routeKey?: string;
97
+
98
+ /**
99
+ * Route params (if available)
100
+ * e.g., { slug: "headphones" }
101
+ */
102
+ params?: Record<string, string>;
103
+
104
+ /**
105
+ * Segment ID where error occurred (if available)
106
+ * e.g., "M1L0" for a layout, "M1R0" for a route
107
+ */
108
+ segmentId?: string;
109
+
110
+ /**
111
+ * Segment type where error occurred (if available)
112
+ */
113
+ segmentType?: "layout" | "route" | "parallel" | "loader" | "middleware";
114
+
115
+ /**
116
+ * Loader name (if error occurred in a loader)
117
+ */
118
+ loaderName?: string;
119
+
120
+ /**
121
+ * Middleware name/id (if error occurred in middleware)
122
+ */
123
+ middlewareId?: string;
124
+
125
+ /**
126
+ * Action ID (if error occurred during server action)
127
+ * e.g., "src/actions.ts#addToCart"
128
+ */
129
+ actionId?: string;
130
+
131
+ /**
132
+ * Environment/bindings (platform context)
133
+ */
134
+ env?: TEnv;
135
+
136
+ /**
137
+ * Duration from request start to error (milliseconds)
138
+ */
139
+ duration?: number;
140
+
141
+ /**
142
+ * Whether this is a partial/navigation request
143
+ */
144
+ isPartial?: boolean;
145
+
146
+ /**
147
+ * Whether an error boundary caught the error
148
+ * If true, the error was handled and a fallback UI was rendered
149
+ */
150
+ handledByBoundary?: boolean;
151
+
152
+ /**
153
+ * Stack trace (if available)
154
+ */
155
+ stack?: string;
156
+
157
+ /**
158
+ * Additional metadata specific to the error phase
159
+ */
160
+ metadata?: Record<string, unknown>;
161
+ }
162
+
163
+ /**
164
+ * Callback function for error handling
165
+ *
166
+ * Called whenever an error occurs during request handling.
167
+ * The callback is for notification/logging purposes - it cannot
168
+ * modify the error handling flow (use errorBoundary for that).
169
+ *
170
+ * @param context - Comprehensive error context
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const onError: OnErrorCallback = (context) => {
175
+ * // Send to error tracking service
176
+ * Sentry.captureException(context.error, {
177
+ * tags: {
178
+ * phase: context.phase,
179
+ * route: context.routeKey,
180
+ * },
181
+ * extra: {
182
+ * url: context.url.toString(),
183
+ * params: context.params,
184
+ * duration: context.duration,
185
+ * },
186
+ * });
187
+ * };
188
+ * ```
189
+ */
190
+ export type OnErrorCallback<TEnv = any> = (
191
+ context: OnErrorContext<TEnv>,
192
+ ) => void | Promise<void>;