@rangojs/router 0.0.0-experimental.5 → 0.0.0-experimental.51

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 (302) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +884 -4
  3. package/dist/bin/rango.js +1606 -0
  4. package/dist/vite/index.js +4567 -769
  5. package/package.json +77 -58
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +294 -0
  8. package/skills/caching/SKILL.md +93 -23
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +12 -8
  11. package/skills/document-cache/SKILL.md +18 -16
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/hooks/SKILL.md +334 -72
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +131 -8
  16. package/skills/layout/SKILL.md +100 -3
  17. package/skills/links/SKILL.md +89 -30
  18. package/skills/loader/SKILL.md +403 -43
  19. package/skills/middleware/SKILL.md +171 -34
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +204 -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 +257 -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 +328 -89
  30. package/skills/use-cache/SKILL.md +324 -0
  31. package/src/__internal.ts +102 -4
  32. package/src/bin/rango.ts +321 -0
  33. package/src/browser/action-coordinator.ts +97 -0
  34. package/src/browser/action-response-classifier.ts +99 -0
  35. package/src/browser/event-controller.ts +92 -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 +282 -557
  42. package/src/browser/navigation-client.ts +157 -71
  43. package/src/browser/navigation-store.ts +33 -50
  44. package/src/browser/navigation-transaction.ts +297 -0
  45. package/src/browser/network-error-handler.ts +61 -0
  46. package/src/browser/partial-update.ts +303 -310
  47. package/src/browser/prefetch/cache.ts +206 -0
  48. package/src/browser/prefetch/fetch.ts +144 -0
  49. package/src/browser/prefetch/observer.ts +65 -0
  50. package/src/browser/prefetch/policy.ts +48 -0
  51. package/src/browser/prefetch/queue.ts +144 -0
  52. package/src/browser/prefetch/resource-ready.ts +77 -0
  53. package/src/browser/rango-state.ts +112 -0
  54. package/src/browser/react/Link.tsx +193 -73
  55. package/src/browser/react/NavigationProvider.tsx +160 -13
  56. package/src/browser/react/context.ts +6 -0
  57. package/src/browser/react/filter-segment-order.ts +11 -0
  58. package/src/browser/react/index.ts +12 -12
  59. package/src/browser/react/location-state-shared.ts +95 -53
  60. package/src/browser/react/location-state.ts +60 -15
  61. package/src/browser/react/mount-context.ts +24 -1
  62. package/src/browser/react/nonce-context.ts +23 -0
  63. package/src/browser/react/shallow-equal.ts +27 -0
  64. package/src/browser/react/use-action.ts +29 -51
  65. package/src/browser/react/use-client-cache.ts +5 -3
  66. package/src/browser/react/use-handle.ts +32 -79
  67. package/src/browser/react/use-href.tsx +2 -2
  68. package/src/browser/react/use-link-status.ts +6 -5
  69. package/src/browser/react/use-navigation.ts +22 -63
  70. package/src/browser/react/use-params.ts +65 -0
  71. package/src/browser/react/use-pathname.ts +47 -0
  72. package/src/browser/react/use-router.ts +63 -0
  73. package/src/browser/react/use-search-params.ts +56 -0
  74. package/src/browser/react/use-segments.ts +80 -97
  75. package/src/browser/response-adapter.ts +73 -0
  76. package/src/browser/rsc-router.tsx +188 -55
  77. package/src/browser/scroll-restoration.ts +117 -44
  78. package/src/browser/segment-reconciler.ts +221 -0
  79. package/src/browser/segment-structure-assert.ts +16 -0
  80. package/src/browser/server-action-bridge.ts +504 -599
  81. package/src/browser/shallow.ts +6 -1
  82. package/src/browser/types.ts +118 -47
  83. package/src/browser/validate-redirect-origin.ts +29 -0
  84. package/src/build/generate-manifest.ts +235 -24
  85. package/src/build/generate-route-types.ts +36 -0
  86. package/src/build/index.ts +13 -0
  87. package/src/build/route-trie.ts +265 -0
  88. package/src/build/route-types/ast-helpers.ts +25 -0
  89. package/src/build/route-types/ast-route-extraction.ts +98 -0
  90. package/src/build/route-types/codegen.ts +102 -0
  91. package/src/build/route-types/include-resolution.ts +411 -0
  92. package/src/build/route-types/param-extraction.ts +48 -0
  93. package/src/build/route-types/per-module-writer.ts +128 -0
  94. package/src/build/route-types/router-processing.ts +479 -0
  95. package/src/build/route-types/scan-filter.ts +78 -0
  96. package/src/build/runtime-discovery.ts +231 -0
  97. package/src/cache/background-task.ts +34 -0
  98. package/src/cache/cache-key-utils.ts +44 -0
  99. package/src/cache/cache-policy.ts +125 -0
  100. package/src/cache/cache-runtime.ts +342 -0
  101. package/src/cache/cache-scope.ts +167 -309
  102. package/src/cache/cf/cf-cache-store.ts +571 -17
  103. package/src/cache/cf/index.ts +13 -3
  104. package/src/cache/document-cache.ts +116 -77
  105. package/src/cache/handle-capture.ts +81 -0
  106. package/src/cache/handle-snapshot.ts +41 -0
  107. package/src/cache/index.ts +1 -15
  108. package/src/cache/memory-segment-store.ts +191 -13
  109. package/src/cache/profile-registry.ts +73 -0
  110. package/src/cache/read-through-swr.ts +134 -0
  111. package/src/cache/segment-codec.ts +256 -0
  112. package/src/cache/taint.ts +153 -0
  113. package/src/cache/types.ts +72 -122
  114. package/src/client.rsc.tsx +3 -1
  115. package/src/client.tsx +106 -126
  116. package/src/component-utils.ts +4 -4
  117. package/src/components/DefaultDocument.tsx +5 -1
  118. package/src/context-var.ts +86 -0
  119. package/src/debug.ts +19 -9
  120. package/src/errors.ts +108 -2
  121. package/src/handle.ts +15 -29
  122. package/src/handles/MetaTags.tsx +73 -20
  123. package/src/handles/breadcrumbs.ts +66 -0
  124. package/src/handles/index.ts +1 -0
  125. package/src/handles/meta.ts +30 -13
  126. package/src/host/cookie-handler.ts +165 -0
  127. package/src/host/errors.ts +97 -0
  128. package/src/host/index.ts +53 -0
  129. package/src/host/pattern-matcher.ts +214 -0
  130. package/src/host/router.ts +352 -0
  131. package/src/host/testing.ts +79 -0
  132. package/src/host/types.ts +146 -0
  133. package/src/host/utils.ts +25 -0
  134. package/src/href-client.ts +119 -29
  135. package/src/index.rsc.ts +153 -19
  136. package/src/index.ts +211 -30
  137. package/src/internal-debug.ts +11 -0
  138. package/src/loader.rsc.ts +26 -147
  139. package/src/loader.ts +27 -10
  140. package/src/network-error-thrower.tsx +3 -1
  141. package/src/outlet-provider.tsx +45 -0
  142. package/src/prerender/param-hash.ts +37 -0
  143. package/src/prerender/store.ts +185 -0
  144. package/src/prerender.ts +463 -0
  145. package/src/reverse.ts +330 -0
  146. package/src/root-error-boundary.tsx +41 -29
  147. package/src/route-content-wrapper.tsx +7 -4
  148. package/src/route-definition/dsl-helpers.ts +959 -0
  149. package/src/route-definition/helper-factories.ts +200 -0
  150. package/src/route-definition/helpers-types.ts +431 -0
  151. package/src/route-definition/index.ts +52 -0
  152. package/src/route-definition/redirect.ts +93 -0
  153. package/src/route-definition.ts +1 -1428
  154. package/src/route-map-builder.ts +217 -123
  155. package/src/route-name.ts +53 -0
  156. package/src/route-types.ts +59 -8
  157. package/src/router/content-negotiation.ts +116 -0
  158. package/src/router/debug-manifest.ts +72 -0
  159. package/src/router/error-handling.ts +9 -9
  160. package/src/router/find-match.ts +160 -0
  161. package/src/router/handler-context.ts +400 -84
  162. package/src/router/intercept-resolution.ts +397 -0
  163. package/src/router/lazy-includes.ts +237 -0
  164. package/src/router/loader-resolution.ts +222 -123
  165. package/src/router/logging.ts +251 -0
  166. package/src/router/manifest.ts +154 -35
  167. package/src/router/match-api.ts +620 -0
  168. package/src/router/match-context.ts +5 -3
  169. package/src/router/match-handlers.ts +440 -0
  170. package/src/router/match-middleware/background-revalidation.ts +108 -93
  171. package/src/router/match-middleware/cache-lookup.ts +440 -10
  172. package/src/router/match-middleware/cache-store.ts +98 -26
  173. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  174. package/src/router/match-middleware/segment-resolution.ts +27 -6
  175. package/src/router/match-pipelines.ts +10 -45
  176. package/src/router/match-result.ts +55 -33
  177. package/src/router/metrics.ts +240 -15
  178. package/src/router/middleware-cookies.ts +55 -0
  179. package/src/router/middleware-types.ts +226 -0
  180. package/src/router/middleware.ts +327 -369
  181. package/src/router/pattern-matching.ts +211 -43
  182. package/src/router/prerender-match.ts +402 -0
  183. package/src/router/preview-match.ts +170 -0
  184. package/src/router/revalidation.ts +137 -38
  185. package/src/router/router-context.ts +41 -21
  186. package/src/router/router-interfaces.ts +452 -0
  187. package/src/router/router-options.ts +592 -0
  188. package/src/router/router-registry.ts +24 -0
  189. package/src/router/segment-resolution/fresh.ts +683 -0
  190. package/src/router/segment-resolution/helpers.ts +263 -0
  191. package/src/router/segment-resolution/loader-cache.ts +199 -0
  192. package/src/router/segment-resolution/revalidation.ts +1301 -0
  193. package/src/router/segment-resolution/static-store.ts +67 -0
  194. package/src/router/segment-resolution.ts +21 -0
  195. package/src/router/segment-wrappers.ts +291 -0
  196. package/src/router/telemetry-otel.ts +299 -0
  197. package/src/router/telemetry.ts +300 -0
  198. package/src/router/timeout.ts +148 -0
  199. package/src/router/trie-matching.ts +239 -0
  200. package/src/router/types.ts +77 -3
  201. package/src/router.ts +665 -4182
  202. package/src/rsc/handler-context.ts +45 -0
  203. package/src/rsc/handler.ts +764 -754
  204. package/src/rsc/helpers.ts +140 -6
  205. package/src/rsc/index.ts +0 -20
  206. package/src/rsc/loader-fetch.ts +209 -0
  207. package/src/rsc/manifest-init.ts +86 -0
  208. package/src/rsc/nonce.ts +14 -0
  209. package/src/rsc/origin-guard.ts +141 -0
  210. package/src/rsc/progressive-enhancement.ts +379 -0
  211. package/src/rsc/response-error.ts +37 -0
  212. package/src/rsc/response-route-handler.ts +347 -0
  213. package/src/rsc/rsc-rendering.ts +237 -0
  214. package/src/rsc/runtime-warnings.ts +42 -0
  215. package/src/rsc/server-action.ts +348 -0
  216. package/src/rsc/ssr-setup.ts +128 -0
  217. package/src/rsc/types.ts +38 -11
  218. package/src/search-params.ts +230 -0
  219. package/src/segment-system.tsx +172 -21
  220. package/src/server/context.ts +278 -58
  221. package/src/server/cookie-store.ts +190 -0
  222. package/src/server/fetchable-loader-store.ts +37 -0
  223. package/src/server/handle-store.ts +94 -15
  224. package/src/server/loader-registry.ts +15 -56
  225. package/src/server/request-context.ts +474 -74
  226. package/src/server.ts +35 -128
  227. package/src/ssr/index.tsx +101 -31
  228. package/src/static-handler.ts +114 -0
  229. package/src/theme/ThemeProvider.tsx +21 -15
  230. package/src/theme/ThemeScript.tsx +5 -5
  231. package/src/theme/constants.ts +5 -2
  232. package/src/theme/index.ts +4 -14
  233. package/src/theme/theme-context.ts +4 -30
  234. package/src/theme/theme-script.ts +21 -18
  235. package/src/types/boundaries.ts +158 -0
  236. package/src/types/cache-types.ts +198 -0
  237. package/src/types/error-types.ts +192 -0
  238. package/src/types/global-namespace.ts +100 -0
  239. package/src/types/handler-context.ts +777 -0
  240. package/src/types/index.ts +88 -0
  241. package/src/types/loader-types.ts +183 -0
  242. package/src/types/route-config.ts +170 -0
  243. package/src/types/route-entry.ts +109 -0
  244. package/src/types/segments.ts +150 -0
  245. package/src/types.ts +1 -1623
  246. package/src/urls/include-helper.ts +197 -0
  247. package/src/urls/index.ts +53 -0
  248. package/src/urls/path-helper-types.ts +339 -0
  249. package/src/urls/path-helper.ts +329 -0
  250. package/src/urls/pattern-types.ts +95 -0
  251. package/src/urls/response-types.ts +106 -0
  252. package/src/urls/type-extraction.ts +372 -0
  253. package/src/urls/urls-function.ts +98 -0
  254. package/src/urls.ts +1 -802
  255. package/src/use-loader.tsx +85 -77
  256. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  257. package/src/vite/discovery/discover-routers.ts +344 -0
  258. package/src/vite/discovery/prerender-collection.ts +385 -0
  259. package/src/vite/discovery/route-types-writer.ts +258 -0
  260. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  261. package/src/vite/discovery/state.ts +108 -0
  262. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  263. package/src/vite/index.ts +11 -782
  264. package/src/vite/plugin-types.ts +48 -0
  265. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  266. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  267. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  268. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  269. package/src/vite/plugins/expose-id-utils.ts +287 -0
  270. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  271. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  272. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  273. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  274. package/src/vite/plugins/expose-ids/types.ts +45 -0
  275. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  276. package/src/vite/plugins/refresh-cmd.ts +65 -0
  277. package/src/vite/plugins/use-cache-transform.ts +323 -0
  278. package/src/vite/plugins/version-injector.ts +83 -0
  279. package/src/vite/plugins/version-plugin.ts +266 -0
  280. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +27 -16
  281. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  282. package/src/vite/rango.ts +445 -0
  283. package/src/vite/router-discovery.ts +777 -0
  284. package/src/vite/utils/ast-handler-extract.ts +517 -0
  285. package/src/vite/utils/banner.ts +36 -0
  286. package/src/vite/utils/bundle-analysis.ts +137 -0
  287. package/src/vite/utils/manifest-utils.ts +70 -0
  288. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  289. package/src/vite/utils/prerender-utils.ts +189 -0
  290. package/src/vite/utils/shared-utils.ts +169 -0
  291. package/CLAUDE.md +0 -43
  292. package/src/browser/lru-cache.ts +0 -69
  293. package/src/browser/request-controller.ts +0 -164
  294. package/src/cache/memory-store.ts +0 -253
  295. package/src/href-context.ts +0 -33
  296. package/src/href.ts +0 -255
  297. package/src/server/route-manifest-cache.ts +0 -173
  298. package/src/vite/expose-handle-id.ts +0 -209
  299. package/src/vite/expose-loader-id.ts +0 -426
  300. package/src/vite/expose-location-state-id.ts +0 -177
  301. package/src/warmup/connection-warmup.tsx +0 -94
  302. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -0,0 +1,200 @@
1
+ import type { RouteDefinition, DefaultEnv } from "../types.js";
2
+ import type { AllUseItems } from "../route-types.js";
3
+ import type { RouteHelpers } from "./helpers-types.js";
4
+ import {
5
+ layout,
6
+ cache,
7
+ middleware,
8
+ revalidate,
9
+ parallel,
10
+ intercept,
11
+ when,
12
+ errorBoundary,
13
+ notFoundBoundary,
14
+ loaderFn,
15
+ loadingFn,
16
+ transitionFn,
17
+ routeFn,
18
+ } from "./dsl-helpers.js";
19
+ import RootLayout from "../server/root-layout";
20
+ import { invariant } from "../errors";
21
+
22
+ /*
23
+ * Create revalidate helper
24
+ */
25
+ const createRevalidateHelper = <TEnv>(): RouteHelpers<
26
+ any,
27
+ TEnv
28
+ >["revalidate"] => {
29
+ return revalidate as RouteHelpers<any, TEnv>["revalidate"];
30
+ };
31
+
32
+ /**
33
+ * Create errorBoundary helper
34
+ */
35
+ const createErrorBoundaryHelper = <TEnv>(): RouteHelpers<
36
+ any,
37
+ TEnv
38
+ >["errorBoundary"] => {
39
+ return errorBoundary as RouteHelpers<any, TEnv>["errorBoundary"];
40
+ };
41
+
42
+ /**
43
+ * Create notFoundBoundary helper
44
+ */
45
+ const createNotFoundBoundaryHelper = <TEnv>(): RouteHelpers<
46
+ any,
47
+ TEnv
48
+ >["notFoundBoundary"] => {
49
+ return notFoundBoundary as RouteHelpers<any, TEnv>["notFoundBoundary"];
50
+ };
51
+
52
+ /**
53
+ * Create middleware helper
54
+ */
55
+ const createMiddlewareHelper = <TEnv>(): RouteHelpers<
56
+ any,
57
+ TEnv
58
+ >["middleware"] => {
59
+ return middleware as RouteHelpers<any, TEnv>["middleware"];
60
+ };
61
+
62
+ /**
63
+ * Create parallel helper
64
+ */
65
+ const createParallelHelper = <TEnv>(): RouteHelpers<any, TEnv>["parallel"] => {
66
+ return parallel as RouteHelpers<any, TEnv>["parallel"];
67
+ };
68
+
69
+ /**
70
+ * Create intercept helper
71
+ */
72
+ const createInterceptHelper = <
73
+ const T extends RouteDefinition,
74
+ TEnv,
75
+ >(): RouteHelpers<T, TEnv>["intercept"] => {
76
+ return intercept as RouteHelpers<T, TEnv>["intercept"];
77
+ };
78
+
79
+ /**
80
+ * Create loader helper
81
+ */
82
+ const createLoaderHelper = <TEnv>(): RouteHelpers<any, TEnv>["loader"] => {
83
+ return loaderFn as RouteHelpers<any, TEnv>["loader"];
84
+ };
85
+
86
+ /**
87
+ * Create loading helper
88
+ */
89
+ const createLoadingHelper = (): RouteHelpers<any, any>["loading"] => {
90
+ return loadingFn;
91
+ };
92
+
93
+ /**
94
+ * Create route helper
95
+ */
96
+ const createRouteHelper = <
97
+ const T extends RouteDefinition,
98
+ TEnv,
99
+ >(): RouteHelpers<T, TEnv>["route"] => {
100
+ return routeFn as unknown as RouteHelpers<T, TEnv>["route"];
101
+ };
102
+
103
+ /**
104
+ * Create layout helper
105
+ */
106
+ const createLayoutHelper = <TEnv>(): RouteHelpers<any, TEnv>["layout"] => {
107
+ return layout as RouteHelpers<any, TEnv>["layout"];
108
+ };
109
+
110
+ /**
111
+ * Create when helper for intercept conditions
112
+ */
113
+ const createWhenHelper = (): RouteHelpers<any, any>["when"] => {
114
+ return when;
115
+ };
116
+
117
+ /**
118
+ * Create cache helper for cache configuration
119
+ */
120
+ const createCacheHelper = (): RouteHelpers<any, any>["cache"] => {
121
+ return cache;
122
+ };
123
+
124
+ /**
125
+ * Create transition helper
126
+ */
127
+ const createTransitionHelper = (): RouteHelpers<any, any>["transition"] => {
128
+ return transitionFn as RouteHelpers<any, any>["transition"];
129
+ };
130
+
131
+ /**
132
+ * Branded type for route handlers that carries the route type info.
133
+ * This enables type-safe verification that imported handlers match route definitions.
134
+ */
135
+ export interface RouteHandlers<T extends RouteDefinition> {
136
+ (): Array<AllUseItems>;
137
+ /** Brand to carry route type info for type checking */
138
+ readonly __routes: T;
139
+ }
140
+
141
+ /**
142
+ * Type-safe handler definition helper
143
+ *
144
+ */
145
+ export function map<const T extends RouteDefinition, TEnv = DefaultEnv>(
146
+ builder: (helpers: RouteHelpers<T, TEnv>) => Array<AllUseItems>,
147
+ ): RouteHandlers<T> {
148
+ const handler = () => {
149
+ // Check if it's a builder function (array-based API)
150
+ invariant(
151
+ typeof builder === "function",
152
+ "map() expects a builder function as its argument",
153
+ );
154
+ // Create helpers
155
+ const helpers: RouteHelpers<T, TEnv> = {
156
+ route: createRouteHelper<T, TEnv>(),
157
+ layout: createLayoutHelper<TEnv>(),
158
+ parallel: createParallelHelper<TEnv>(),
159
+ intercept: createInterceptHelper<T, TEnv>(),
160
+ middleware: createMiddlewareHelper<TEnv>(),
161
+ revalidate: createRevalidateHelper<TEnv>(),
162
+ loader: createLoaderHelper<TEnv>(),
163
+ loading: createLoadingHelper(),
164
+ errorBoundary: createErrorBoundaryHelper<TEnv>(),
165
+ notFoundBoundary: createNotFoundBoundaryHelper<TEnv>(),
166
+ when: createWhenHelper(),
167
+ cache: createCacheHelper(),
168
+ transition: createTransitionHelper(),
169
+ };
170
+
171
+ return [layout(RootLayout, () => builder(helpers))].flat(3);
172
+ };
173
+ // Cast to RouteHandlers to carry the route type brand
174
+ return handler as RouteHandlers<T>;
175
+ }
176
+
177
+ /**
178
+ * Create RouteHelpers for inline route definitions
179
+ * Used internally by router.map() for inline handler syntax
180
+ */
181
+ export function createRouteHelpers<
182
+ T extends RouteDefinition,
183
+ TEnv,
184
+ >(): RouteHelpers<T, TEnv> {
185
+ return {
186
+ route: createRouteHelper<T, TEnv>(),
187
+ layout: createLayoutHelper<TEnv>(),
188
+ parallel: createParallelHelper<TEnv>(),
189
+ intercept: createInterceptHelper<T, TEnv>(),
190
+ middleware: createMiddlewareHelper<TEnv>(),
191
+ revalidate: createRevalidateHelper<TEnv>(),
192
+ loader: createLoaderHelper<TEnv>(),
193
+ loading: createLoadingHelper(),
194
+ errorBoundary: createErrorBoundaryHelper<TEnv>(),
195
+ notFoundBoundary: createNotFoundBoundaryHelper<TEnv>(),
196
+ when: createWhenHelper(),
197
+ cache: createCacheHelper(),
198
+ transition: createTransitionHelper(),
199
+ };
200
+ }
@@ -0,0 +1,431 @@
1
+ import type { ReactNode } from "react";
2
+ import type {
3
+ ExtractRouteParams,
4
+ Handler,
5
+ PartialCacheOptions,
6
+ ErrorBoundaryHandler,
7
+ LoaderDefinition,
8
+ MiddlewareFn,
9
+ NotFoundBoundaryHandler,
10
+ ResolvedRouteMap,
11
+ RouteDefinition,
12
+ ShouldRevalidateFn,
13
+ TransitionConfig,
14
+ } from "../types.js";
15
+ import type {
16
+ AllUseItems,
17
+ LayoutItem,
18
+ RouteItem,
19
+ ParallelItem,
20
+ InterceptItem,
21
+ MiddlewareItem,
22
+ RevalidateItem,
23
+ LoaderItem,
24
+ LoadingItem,
25
+ ErrorBoundaryItem,
26
+ NotFoundBoundaryItem,
27
+ LayoutUseItem,
28
+ RouteUseItem,
29
+ ParallelUseItem,
30
+ InterceptUseItem,
31
+ LoaderUseItem,
32
+ WhenItem,
33
+ CacheItem,
34
+ TransitionItem,
35
+ UseItems,
36
+ } from "../route-types.js";
37
+ import type { InterceptWhenFn } from "../server/context";
38
+
39
+ // Re-export route item types for backward compatibility
40
+ export type {
41
+ AllUseItems,
42
+ LayoutItem,
43
+ RouteItem,
44
+ ParallelItem,
45
+ InterceptItem,
46
+ MiddlewareItem,
47
+ RevalidateItem,
48
+ LoaderItem,
49
+ ErrorBoundaryItem,
50
+ NotFoundBoundaryItem,
51
+ LayoutUseItem,
52
+ RouteUseItem,
53
+ ParallelUseItem,
54
+ InterceptUseItem,
55
+ WhenItem,
56
+ CacheItem,
57
+ } from "../route-types.js";
58
+
59
+ // Re-export intercept selector types for use in handlers
60
+ export type {
61
+ InterceptSelectorContext,
62
+ InterceptSegmentsState,
63
+ InterceptWhenFn,
64
+ } from "../server/context";
65
+
66
+ /**
67
+ * Route helpers provided by map()
68
+ * These are the only typed helpers users interact with
69
+ */
70
+ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
71
+ /**
72
+ * Define a route handler for a specific route pattern
73
+ * ```typescript
74
+ * route("products.detail", async (ctx) => {
75
+ * const product = await getProduct(ctx.params.slug);
76
+ * return <ProductPage product={product} />;
77
+ * })
78
+ *
79
+ * // With nested use() for middleware, loaders, etc.
80
+ * route("products.detail", ProductHandler, () => [
81
+ * loader(ProductLoader),
82
+ * loading(<ProductSkeleton />),
83
+ * ])
84
+ * ```
85
+ * @param name - Route name matching a key from route definitions
86
+ * @param handler - Async function that returns JSX for the route
87
+ * @param use - Optional callback returning middleware, loaders, loading, etc.
88
+ */
89
+ route: <K extends keyof ResolvedRouteMap<T> & string>(
90
+ name: K,
91
+ handler: Handler<ExtractRouteParams<T, K & string>, {}, TEnv>,
92
+ use?: () => UseItems<RouteUseItem>,
93
+ ) => RouteItem;
94
+ /**
95
+ * Define a layout that wraps child routes
96
+ * ```typescript
97
+ * layout(<RootLayout />, () => [
98
+ * route("home", HomePage),
99
+ * route("about", AboutPage),
100
+ * ])
101
+ *
102
+ * // With dynamic layout handler
103
+ * layout(async (ctx) => {
104
+ * const user = ctx.get("user");
105
+ * return <DashboardShell user={user} />;
106
+ * }, () => [
107
+ * middleware(authMiddleware),
108
+ * route("dashboard", DashboardPage),
109
+ * ])
110
+ * ```
111
+ * @param component - Static JSX or async handler for the layout
112
+ * @param use - Callback returning child routes, middleware, loaders, etc.
113
+ */
114
+ layout: (
115
+ component: ReactNode | Handler<any, any, TEnv>,
116
+ use?: () => UseItems<LayoutUseItem>,
117
+ ) => LayoutItem;
118
+ /**
119
+ * Define parallel routes that render simultaneously in named slots
120
+ * ```typescript
121
+ * parallel({
122
+ * "@sidebar": <Sidebar />,
123
+ * "@main": async (ctx) => <MainContent data={ctx.use(DataLoader)} />,
124
+ * })
125
+ *
126
+ * // With loaders and loading states
127
+ * parallel({
128
+ * "@analytics": AnalyticsPanel,
129
+ * "@metrics": MetricsPanel,
130
+ * }, () => [
131
+ * loader(DashboardLoader),
132
+ * loading(<DashboardSkeleton />),
133
+ * ])
134
+ * ```
135
+ * @param slots - Object with slot names (prefixed with @) mapped to handlers
136
+ * @param use - Optional callback for loaders, loading, revalidate, etc.
137
+ */
138
+ parallel: <
139
+ TSlots extends Record<`@${string}`, Handler<any, any, TEnv> | ReactNode>,
140
+ >(
141
+ slots: TSlots,
142
+ use?: () => UseItems<ParallelUseItem>,
143
+ ) => ParallelItem;
144
+ /**
145
+ * Define an intercepting route for soft navigation
146
+ *
147
+ * When soft-navigating to the target route from within the current layout,
148
+ * the intercept handler renders in the named slot instead of the route's
149
+ * default handler. Direct navigation uses the route's handler.
150
+ *
151
+ * ```typescript
152
+ * // In a layout - intercept "card" route as modal
153
+ * layout(<KanbanLayout />, () => [
154
+ * intercept("@modal", "card", () => <CardModal />),
155
+ * ])
156
+ *
157
+ * // With loaders and revalidation
158
+ * intercept("@modal", "card", () => <CardModal />, () => [
159
+ * loader(CardModalLoader),
160
+ * revalidate(() => false),
161
+ * ])
162
+ * ```
163
+ * @param slotName - Named slot (prefixed with @) where intercept renders
164
+ * @param routeName - Route name to intercept
165
+ * @param handler - Component or handler for intercepted render
166
+ * @param use - Optional callback for loaders, middleware, revalidate, etc.
167
+ */
168
+ intercept: {
169
+ // Local: dot-prefixed, params inferred from local route definition
170
+ <K extends keyof ResolvedRouteMap<T> & string>(
171
+ slotName: `@${string}`,
172
+ routeName: `.${K}`,
173
+ handler: ReactNode | Handler<ExtractRouteParams<T, K>, {}, TEnv>,
174
+ use?: () => UseItems<InterceptUseItem>,
175
+ ): InterceptItem;
176
+ // Global: unprefixed, params inferred from global route map
177
+ <K extends keyof RSCRouter.GeneratedRouteMap & string>(
178
+ slotName: `@${string}`,
179
+ routeName: K,
180
+ handler: ReactNode | Handler<K, RSCRouter.GeneratedRouteMap, TEnv>,
181
+ use?: () => UseItems<InterceptUseItem>,
182
+ ): InterceptItem;
183
+ };
184
+ /**
185
+ * Attach middleware to the current route/layout
186
+ * ```typescript
187
+ * middleware(async (ctx, next) => {
188
+ * const session = await getSession(ctx.request);
189
+ * if (!session) return redirect("/login");
190
+ * ctx.set("user", session.user);
191
+ * next();
192
+ * })
193
+ *
194
+ * // Chain multiple middleware
195
+ * middleware(authMiddleware, loggingMiddleware, rateLimitMiddleware)
196
+ * ```
197
+ * @param fns - One or more middleware functions to execute in order
198
+ */
199
+ middleware: (...fns: MiddlewareFn<TEnv>[]) => MiddlewareItem;
200
+ /**
201
+ * Control when a segment should revalidate during navigation
202
+ * ```typescript
203
+ * // Revalidate when params change
204
+ * revalidate(({ currentParams, nextParams }) =>
205
+ * currentParams.slug !== nextParams.slug
206
+ * )
207
+ *
208
+ * // Revalidate after specific actions (actionId format: "path/to/file.ts#exportName")
209
+ * revalidate(({ actionId }) =>
210
+ * actionId?.includes("Cart") ?? false
211
+ * )
212
+ *
213
+ * // Soft decision (suggest but allow override)
214
+ * revalidate(({ defaultShouldRevalidate }) =>
215
+ * ({ defaultShouldRevalidate: true })
216
+ * )
217
+ * ```
218
+ * @param fn - Function that returns boolean (hard) or { defaultShouldRevalidate } (soft)
219
+ */
220
+ revalidate: (fn: ShouldRevalidateFn<any, TEnv>) => RevalidateItem;
221
+ /**
222
+ * Attach a data loader to the current route/layout
223
+ * ```typescript
224
+ * loader(ProductLoader)
225
+ *
226
+ * // With loader-specific revalidation (match by file or export name)
227
+ * loader(CartLoader, () => [
228
+ * revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
229
+ * ])
230
+ *
231
+ * // Consume in client components with useLoader()
232
+ * // (preferred — cache-safe, always fresh)
233
+ * function ProductDetails() {
234
+ * const { data } = useLoader(ProductLoader);
235
+ * return <div>{data.name}</div>;
236
+ * }
237
+ * ```
238
+ * @param loaderDef - Loader created with createLoader()
239
+ * @param use - Optional callback for loader-specific revalidation rules
240
+ */
241
+ loader: <TData>(
242
+ loaderDef: LoaderDefinition<TData>,
243
+ use?: () => UseItems<LoaderUseItem>,
244
+ ) => LoaderItem;
245
+ /**
246
+ * Attach a loading component to the current route/layout
247
+ * ```typescript
248
+ * // Show loading on all requests (including SSR)
249
+ * loading(<Skeleton />)
250
+ *
251
+ * // Skip loading on SSR, only show on client navigation
252
+ * loading(<Skeleton />, { ssr: false })
253
+ * ```
254
+ * @param component - The loading UI to show during navigation
255
+ * @param options - Configuration options
256
+ * @param options.ssr - If false, skip showing loading on document requests (SSR)
257
+ */
258
+ loading: (component: ReactNode, options?: { ssr?: boolean }) => LoadingItem;
259
+ /**
260
+ * Attach an error boundary to catch errors in this segment and children
261
+ * ```typescript
262
+ * errorBoundary(<ErrorFallback />)
263
+ *
264
+ * // With dynamic error handler
265
+ * errorBoundary(({ error, reset }) => (
266
+ * <div>
267
+ * <h2>Something went wrong</h2>
268
+ * <p>{error.message}</p>
269
+ * <button onClick={reset}>Try again</button>
270
+ * </div>
271
+ * ))
272
+ * ```
273
+ * @param fallback - Static JSX or handler receiving error info and reset function
274
+ */
275
+ errorBoundary: (
276
+ fallback: ReactNode | ErrorBoundaryHandler,
277
+ ) => ErrorBoundaryItem;
278
+ /**
279
+ * Attach a not-found boundary to handle notFound() calls in this segment
280
+ * ```typescript
281
+ * notFoundBoundary(<ProductNotFound />)
282
+ *
283
+ * // With dynamic handler
284
+ * notFoundBoundary(({ notFound }) => (
285
+ * <div>
286
+ * <h2>{notFound.message}</h2>
287
+ * <a href="/products">Browse all products</a>
288
+ * </div>
289
+ * ))
290
+ * ```
291
+ * @param fallback - Static JSX or handler receiving not-found info
292
+ */
293
+ notFoundBoundary: (
294
+ fallback: ReactNode | NotFoundBoundaryHandler,
295
+ ) => NotFoundBoundaryItem;
296
+ /**
297
+ * Define a condition for when an intercept should activate
298
+ *
299
+ * Only valid inside intercept() use() callback. When multiple when() calls
300
+ * are present, ALL must return true for the intercept to activate.
301
+ * If no when() is defined, the intercept always activates on soft navigation.
302
+ *
303
+ * Context properties:
304
+ * - `from` - Source URL (where user is navigating from)
305
+ * - `to` - Destination URL (where user is navigating to)
306
+ * - `params` - Matched route params
307
+ * - `segments` - Client's current segments with `path` and `ids`
308
+ *
309
+ * ```typescript
310
+ * // Only intercept when coming from the board page
311
+ * intercept("@modal", "card", <CardModal />, () => [
312
+ * when(({ from }) => from.pathname.startsWith("/board")),
313
+ * loader(CardDetailLoader),
314
+ * ])
315
+ *
316
+ * // Use segments to check current route context
317
+ * intercept("@modal", "card", <CardModal />, () => [
318
+ * when(({ segments }) => segments.path[0] === "kanban"),
319
+ * ])
320
+ *
321
+ * // Multiple conditions (AND logic)
322
+ * intercept("@modal", "card", <CardModal />, () => [
323
+ * when(({ from }) => from.pathname.startsWith("/board")),
324
+ * when(({ segments }) => segments.ids.includes("kanban-layout")),
325
+ * ])
326
+ * ```
327
+ * @param fn - Selector function receiving navigation context, returns boolean
328
+ */
329
+ when: (fn: InterceptWhenFn) => WhenItem;
330
+ /**
331
+ * Define cache configuration for segments
332
+ *
333
+ * Creates a cache boundary that applies to all children unless overridden.
334
+ * Cache config inherits down the route tree like middleware wrapping.
335
+ *
336
+ * When ttl is not specified, uses store defaults (explicit store first,
337
+ * then app-level store). When store is not specified, uses app-level store.
338
+ *
339
+ * Note: Loaders are NOT cached by default. Use cache() inside loader()
340
+ * to explicitly opt-in to loader caching.
341
+ *
342
+ * ```typescript
343
+ * // Using app-level defaults (ttl inherited from store.defaults)
344
+ * cache(() => [
345
+ * layout(<BlogLayout />), // cached with default TTL
346
+ * route("post/:slug"), // cached with default TTL
347
+ * ])
348
+ *
349
+ * // Cache all segments with explicit 60s TTL
350
+ * cache({ ttl: 60 }, () => [
351
+ * layout(<BlogLayout />), // cached
352
+ * route("post/:slug"), // cached
353
+ * ])
354
+ *
355
+ * // With stale-while-revalidate
356
+ * cache({ ttl: 60, swr: 300 }, () => [
357
+ * route("product/:id"),
358
+ * ])
359
+ *
360
+ * // Override for specific section
361
+ * cache({ ttl: 60 }, () => [
362
+ * layout(<RootLayout />),
363
+ * cache({ ttl: 300 }, () => [
364
+ * route("static-page"), // longer TTL
365
+ * ]),
366
+ * cache(false, () => [
367
+ * route("admin"), // not cached
368
+ * ]),
369
+ * ])
370
+ *
371
+ * // Use different store for specific routes
372
+ * cache({ store: kvStore, ttl: 3600 }, () => [
373
+ * route("archive/:year"), // uses KV store
374
+ * ])
375
+ *
376
+ * // Opt-in loader caching
377
+ * route("product/:id", ProductHandler, () => [
378
+ * loader(ProductLoader), // NOT cached (default)
379
+ * loader(StaticMetadata, () => [
380
+ * cache({ ttl: 3600 }), // cached for 1 hour
381
+ * ]),
382
+ * ])
383
+ * ```
384
+ * @param optionsOrChildren - Cache options, false to disable, or children callback
385
+ * @param children - Optional callback returning child segments (when first arg is options)
386
+ */
387
+ cache: {
388
+ (): CacheItem;
389
+ (children: () => UseItems<AllUseItems>): CacheItem;
390
+ (profileName: string): CacheItem;
391
+ (profileName: string, use: () => UseItems<AllUseItems>): CacheItem;
392
+ (
393
+ options: PartialCacheOptions | false,
394
+ use?: () => UseItems<AllUseItems>,
395
+ ): CacheItem;
396
+ };
397
+ /**
398
+ * Attach a ViewTransition boundary to the current segment or a group of routes
399
+ *
400
+ * Wraps segment content with React's `<ViewTransition>` component.
401
+ * Only takes effect when React experimental is used (no-op on stable React).
402
+ *
403
+ * ```typescript
404
+ * // Attach to a single route
405
+ * path("/about", AboutPage, { name: "about" }, () => [
406
+ * transition({ enter: "fade-in", exit: "fade-out" }),
407
+ * ])
408
+ *
409
+ * // Wrap a group of routes
410
+ * transition({ enter: "fade-in", exit: "fade-out" }, () => [
411
+ * path("/", HomePage),
412
+ * path("/about", AboutPage),
413
+ * ])
414
+ *
415
+ * // Direction-aware transitions
416
+ * transition({
417
+ * enter: { "navigation": "slide-right", "navigation-back": "slide-left" },
418
+ * exit: { "navigation": "slide-left", "navigation-back": "slide-right" },
419
+ * })
420
+ * ```
421
+ * @param config - ViewTransition configuration (enter, exit, update, share, default, name)
422
+ * @param children - Optional callback returning child routes to wrap
423
+ */
424
+ transition: {
425
+ (config: TransitionConfig): TransitionItem;
426
+ (
427
+ config: TransitionConfig,
428
+ children: () => UseItems<AllUseItems>,
429
+ ): TransitionItem;
430
+ };
431
+ };
@@ -0,0 +1,52 @@
1
+ // Type definitions
2
+ export type { RouteHelpers } from "./helpers-types.js";
3
+ export type {
4
+ AllUseItems,
5
+ LayoutItem,
6
+ RouteItem,
7
+ ParallelItem,
8
+ InterceptItem,
9
+ MiddlewareItem,
10
+ RevalidateItem,
11
+ LoaderItem,
12
+ ErrorBoundaryItem,
13
+ NotFoundBoundaryItem,
14
+ LayoutUseItem,
15
+ RouteUseItem,
16
+ ParallelUseItem,
17
+ InterceptUseItem,
18
+ WhenItem,
19
+ CacheItem,
20
+ InterceptSelectorContext,
21
+ InterceptSegmentsState,
22
+ InterceptWhenFn,
23
+ } from "./helpers-types.js";
24
+
25
+ // DSL helpers
26
+ export {
27
+ layout,
28
+ cache,
29
+ middleware,
30
+ revalidate,
31
+ parallel,
32
+ intercept,
33
+ when,
34
+ errorBoundary,
35
+ notFoundBoundary,
36
+ loader,
37
+ loading,
38
+ transition,
39
+ } from "./dsl-helpers.js";
40
+
41
+ // Helper factories and map
42
+ export {
43
+ map,
44
+ createRouteHelpers,
45
+ type RouteHandlers,
46
+ } from "./helper-factories.js";
47
+
48
+ // Redirect
49
+ export { redirect } from "./redirect.js";
50
+
51
+ // Re-export createLoader from loader.rsc.ts for RSC/server context
52
+ export { createLoader } from "../loader.rsc.js";