@rangojs/router 0.0.0-experimental.0f44aca1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +899 -0
  3. package/dist/bin/rango.js +1601 -0
  4. package/dist/vite/index.js +5214 -0
  5. package/package.json +176 -0
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +262 -0
  8. package/skills/caching/SKILL.md +220 -0
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +112 -0
  11. package/skills/document-cache/SKILL.md +182 -0
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/hooks/SKILL.md +704 -0
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +313 -0
  16. package/skills/layout/SKILL.md +310 -0
  17. package/skills/links/SKILL.md +239 -0
  18. package/skills/loader/SKILL.md +596 -0
  19. package/skills/middleware/SKILL.md +339 -0
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +305 -0
  22. package/skills/prerender/SKILL.md +643 -0
  23. package/skills/rango/SKILL.md +118 -0
  24. package/skills/response-routes/SKILL.md +411 -0
  25. package/skills/route/SKILL.md +385 -0
  26. package/skills/router-setup/SKILL.md +439 -0
  27. package/skills/tailwind/SKILL.md +129 -0
  28. package/skills/theme/SKILL.md +79 -0
  29. package/skills/typesafety/SKILL.md +623 -0
  30. package/skills/use-cache/SKILL.md +324 -0
  31. package/src/__internal.ts +273 -0
  32. package/src/bin/rango.ts +321 -0
  33. package/src/browser/action-coordinator.ts +97 -0
  34. package/src/browser/action-response-classifier.ts +99 -0
  35. package/src/browser/event-controller.ts +899 -0
  36. package/src/browser/history-state.ts +80 -0
  37. package/src/browser/index.ts +18 -0
  38. package/src/browser/intercept-utils.ts +52 -0
  39. package/src/browser/link-interceptor.ts +141 -0
  40. package/src/browser/logging.ts +55 -0
  41. package/src/browser/merge-segment-loaders.ts +134 -0
  42. package/src/browser/navigation-bridge.ts +645 -0
  43. package/src/browser/navigation-client.ts +215 -0
  44. package/src/browser/navigation-store.ts +806 -0
  45. package/src/browser/navigation-transaction.ts +295 -0
  46. package/src/browser/network-error-handler.ts +61 -0
  47. package/src/browser/partial-update.ts +550 -0
  48. package/src/browser/prefetch/cache.ts +146 -0
  49. package/src/browser/prefetch/fetch.ts +135 -0
  50. package/src/browser/prefetch/observer.ts +65 -0
  51. package/src/browser/prefetch/policy.ts +42 -0
  52. package/src/browser/prefetch/queue.ts +88 -0
  53. package/src/browser/rango-state.ts +112 -0
  54. package/src/browser/react/Link.tsx +360 -0
  55. package/src/browser/react/NavigationProvider.tsx +386 -0
  56. package/src/browser/react/ScrollRestoration.tsx +94 -0
  57. package/src/browser/react/context.ts +59 -0
  58. package/src/browser/react/filter-segment-order.ts +11 -0
  59. package/src/browser/react/index.ts +52 -0
  60. package/src/browser/react/location-state-shared.ts +162 -0
  61. package/src/browser/react/location-state.ts +107 -0
  62. package/src/browser/react/mount-context.ts +37 -0
  63. package/src/browser/react/nonce-context.ts +23 -0
  64. package/src/browser/react/shallow-equal.ts +27 -0
  65. package/src/browser/react/use-action.ts +218 -0
  66. package/src/browser/react/use-client-cache.ts +58 -0
  67. package/src/browser/react/use-handle.ts +162 -0
  68. package/src/browser/react/use-href.tsx +40 -0
  69. package/src/browser/react/use-link-status.ts +135 -0
  70. package/src/browser/react/use-mount.ts +31 -0
  71. package/src/browser/react/use-navigation.ts +99 -0
  72. package/src/browser/react/use-params.ts +65 -0
  73. package/src/browser/react/use-pathname.ts +47 -0
  74. package/src/browser/react/use-router.ts +63 -0
  75. package/src/browser/react/use-search-params.ts +56 -0
  76. package/src/browser/react/use-segments.ts +171 -0
  77. package/src/browser/response-adapter.ts +73 -0
  78. package/src/browser/rsc-router.tsx +431 -0
  79. package/src/browser/scroll-restoration.ts +400 -0
  80. package/src/browser/segment-reconciler.ts +216 -0
  81. package/src/browser/segment-structure-assert.ts +83 -0
  82. package/src/browser/server-action-bridge.ts +667 -0
  83. package/src/browser/shallow.ts +40 -0
  84. package/src/browser/types.ts +538 -0
  85. package/src/browser/validate-redirect-origin.ts +29 -0
  86. package/src/build/generate-manifest.ts +438 -0
  87. package/src/build/generate-route-types.ts +36 -0
  88. package/src/build/index.ts +35 -0
  89. package/src/build/route-trie.ts +265 -0
  90. package/src/build/route-types/ast-helpers.ts +25 -0
  91. package/src/build/route-types/ast-route-extraction.ts +98 -0
  92. package/src/build/route-types/codegen.ts +102 -0
  93. package/src/build/route-types/include-resolution.ts +411 -0
  94. package/src/build/route-types/param-extraction.ts +48 -0
  95. package/src/build/route-types/per-module-writer.ts +128 -0
  96. package/src/build/route-types/router-processing.ts +469 -0
  97. package/src/build/route-types/scan-filter.ts +78 -0
  98. package/src/build/runtime-discovery.ts +231 -0
  99. package/src/cache/background-task.ts +34 -0
  100. package/src/cache/cache-key-utils.ts +44 -0
  101. package/src/cache/cache-policy.ts +125 -0
  102. package/src/cache/cache-runtime.ts +338 -0
  103. package/src/cache/cache-scope.ts +382 -0
  104. package/src/cache/cf/cf-cache-store.ts +540 -0
  105. package/src/cache/cf/index.ts +25 -0
  106. package/src/cache/document-cache.ts +369 -0
  107. package/src/cache/handle-capture.ts +81 -0
  108. package/src/cache/handle-snapshot.ts +41 -0
  109. package/src/cache/index.ts +43 -0
  110. package/src/cache/memory-segment-store.ts +328 -0
  111. package/src/cache/profile-registry.ts +73 -0
  112. package/src/cache/read-through-swr.ts +134 -0
  113. package/src/cache/segment-codec.ts +256 -0
  114. package/src/cache/taint.ts +98 -0
  115. package/src/cache/types.ts +342 -0
  116. package/src/client.rsc.tsx +85 -0
  117. package/src/client.tsx +601 -0
  118. package/src/component-utils.ts +76 -0
  119. package/src/components/DefaultDocument.tsx +27 -0
  120. package/src/context-var.ts +86 -0
  121. package/src/debug.ts +243 -0
  122. package/src/default-error-boundary.tsx +88 -0
  123. package/src/deps/browser.ts +8 -0
  124. package/src/deps/html-stream-client.ts +2 -0
  125. package/src/deps/html-stream-server.ts +2 -0
  126. package/src/deps/rsc.ts +10 -0
  127. package/src/deps/ssr.ts +2 -0
  128. package/src/errors.ts +365 -0
  129. package/src/handle.ts +135 -0
  130. package/src/handles/MetaTags.tsx +246 -0
  131. package/src/handles/breadcrumbs.ts +66 -0
  132. package/src/handles/index.ts +7 -0
  133. package/src/handles/meta.ts +264 -0
  134. package/src/host/cookie-handler.ts +165 -0
  135. package/src/host/errors.ts +97 -0
  136. package/src/host/index.ts +53 -0
  137. package/src/host/pattern-matcher.ts +214 -0
  138. package/src/host/router.ts +352 -0
  139. package/src/host/testing.ts +79 -0
  140. package/src/host/types.ts +146 -0
  141. package/src/host/utils.ts +25 -0
  142. package/src/href-client.ts +222 -0
  143. package/src/index.rsc.ts +233 -0
  144. package/src/index.ts +277 -0
  145. package/src/internal-debug.ts +11 -0
  146. package/src/loader.rsc.ts +89 -0
  147. package/src/loader.ts +64 -0
  148. package/src/network-error-thrower.tsx +23 -0
  149. package/src/outlet-context.ts +15 -0
  150. package/src/outlet-provider.tsx +45 -0
  151. package/src/prerender/param-hash.ts +37 -0
  152. package/src/prerender/store.ts +185 -0
  153. package/src/prerender.ts +463 -0
  154. package/src/reverse.ts +330 -0
  155. package/src/root-error-boundary.tsx +289 -0
  156. package/src/route-content-wrapper.tsx +196 -0
  157. package/src/route-definition/dsl-helpers.ts +934 -0
  158. package/src/route-definition/helper-factories.ts +200 -0
  159. package/src/route-definition/helpers-types.ts +430 -0
  160. package/src/route-definition/index.ts +52 -0
  161. package/src/route-definition/redirect.ts +93 -0
  162. package/src/route-definition.ts +1 -0
  163. package/src/route-map-builder.ts +275 -0
  164. package/src/route-name.ts +53 -0
  165. package/src/route-types.ts +259 -0
  166. package/src/router/content-negotiation.ts +116 -0
  167. package/src/router/debug-manifest.ts +72 -0
  168. package/src/router/error-handling.ts +287 -0
  169. package/src/router/find-match.ts +158 -0
  170. package/src/router/handler-context.ts +451 -0
  171. package/src/router/intercept-resolution.ts +395 -0
  172. package/src/router/lazy-includes.ts +234 -0
  173. package/src/router/loader-resolution.ts +420 -0
  174. package/src/router/logging.ts +248 -0
  175. package/src/router/manifest.ts +267 -0
  176. package/src/router/match-api.ts +620 -0
  177. package/src/router/match-context.ts +266 -0
  178. package/src/router/match-handlers.ts +440 -0
  179. package/src/router/match-middleware/background-revalidation.ts +223 -0
  180. package/src/router/match-middleware/cache-lookup.ts +634 -0
  181. package/src/router/match-middleware/cache-store.ts +295 -0
  182. package/src/router/match-middleware/index.ts +81 -0
  183. package/src/router/match-middleware/intercept-resolution.ts +306 -0
  184. package/src/router/match-middleware/segment-resolution.ts +192 -0
  185. package/src/router/match-pipelines.ts +179 -0
  186. package/src/router/match-result.ts +219 -0
  187. package/src/router/metrics.ts +282 -0
  188. package/src/router/middleware-cookies.ts +55 -0
  189. package/src/router/middleware-types.ts +222 -0
  190. package/src/router/middleware.ts +748 -0
  191. package/src/router/pattern-matching.ts +563 -0
  192. package/src/router/prerender-match.ts +402 -0
  193. package/src/router/preview-match.ts +170 -0
  194. package/src/router/revalidation.ts +289 -0
  195. package/src/router/router-context.ts +316 -0
  196. package/src/router/router-interfaces.ts +452 -0
  197. package/src/router/router-options.ts +592 -0
  198. package/src/router/router-registry.ts +24 -0
  199. package/src/router/segment-resolution/fresh.ts +570 -0
  200. package/src/router/segment-resolution/helpers.ts +263 -0
  201. package/src/router/segment-resolution/loader-cache.ts +198 -0
  202. package/src/router/segment-resolution/revalidation.ts +1239 -0
  203. package/src/router/segment-resolution/static-store.ts +67 -0
  204. package/src/router/segment-resolution.ts +21 -0
  205. package/src/router/segment-wrappers.ts +289 -0
  206. package/src/router/telemetry-otel.ts +299 -0
  207. package/src/router/telemetry.ts +300 -0
  208. package/src/router/timeout.ts +148 -0
  209. package/src/router/trie-matching.ts +239 -0
  210. package/src/router/types.ts +170 -0
  211. package/src/router.ts +1002 -0
  212. package/src/rsc/handler-context.ts +45 -0
  213. package/src/rsc/handler.ts +1089 -0
  214. package/src/rsc/helpers.ts +198 -0
  215. package/src/rsc/index.ts +36 -0
  216. package/src/rsc/loader-fetch.ts +209 -0
  217. package/src/rsc/manifest-init.ts +86 -0
  218. package/src/rsc/nonce.ts +32 -0
  219. package/src/rsc/origin-guard.ts +141 -0
  220. package/src/rsc/progressive-enhancement.ts +379 -0
  221. package/src/rsc/response-error.ts +37 -0
  222. package/src/rsc/response-route-handler.ts +347 -0
  223. package/src/rsc/rsc-rendering.ts +235 -0
  224. package/src/rsc/runtime-warnings.ts +42 -0
  225. package/src/rsc/server-action.ts +348 -0
  226. package/src/rsc/ssr-setup.ts +128 -0
  227. package/src/rsc/types.ts +263 -0
  228. package/src/search-params.ts +230 -0
  229. package/src/segment-system.tsx +454 -0
  230. package/src/server/context.ts +591 -0
  231. package/src/server/cookie-store.ts +190 -0
  232. package/src/server/fetchable-loader-store.ts +37 -0
  233. package/src/server/handle-store.ts +308 -0
  234. package/src/server/loader-registry.ts +133 -0
  235. package/src/server/request-context.ts +914 -0
  236. package/src/server/root-layout.tsx +10 -0
  237. package/src/server/tsconfig.json +14 -0
  238. package/src/server.ts +51 -0
  239. package/src/ssr/index.tsx +365 -0
  240. package/src/static-handler.ts +114 -0
  241. package/src/theme/ThemeProvider.tsx +297 -0
  242. package/src/theme/ThemeScript.tsx +61 -0
  243. package/src/theme/constants.ts +62 -0
  244. package/src/theme/index.ts +48 -0
  245. package/src/theme/theme-context.ts +44 -0
  246. package/src/theme/theme-script.ts +155 -0
  247. package/src/theme/types.ts +182 -0
  248. package/src/theme/use-theme.ts +44 -0
  249. package/src/types/boundaries.ts +158 -0
  250. package/src/types/cache-types.ts +198 -0
  251. package/src/types/error-types.ts +192 -0
  252. package/src/types/global-namespace.ts +100 -0
  253. package/src/types/handler-context.ts +687 -0
  254. package/src/types/index.ts +88 -0
  255. package/src/types/loader-types.ts +183 -0
  256. package/src/types/route-config.ts +170 -0
  257. package/src/types/route-entry.ts +102 -0
  258. package/src/types/segments.ts +148 -0
  259. package/src/types.ts +1 -0
  260. package/src/urls/include-helper.ts +197 -0
  261. package/src/urls/index.ts +53 -0
  262. package/src/urls/path-helper-types.ts +339 -0
  263. package/src/urls/path-helper.ts +329 -0
  264. package/src/urls/pattern-types.ts +95 -0
  265. package/src/urls/response-types.ts +106 -0
  266. package/src/urls/type-extraction.ts +372 -0
  267. package/src/urls/urls-function.ts +98 -0
  268. package/src/urls.ts +1 -0
  269. package/src/use-loader.tsx +354 -0
  270. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  271. package/src/vite/discovery/discover-routers.ts +344 -0
  272. package/src/vite/discovery/prerender-collection.ts +385 -0
  273. package/src/vite/discovery/route-types-writer.ts +258 -0
  274. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  275. package/src/vite/discovery/state.ts +110 -0
  276. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  277. package/src/vite/index.ts +16 -0
  278. package/src/vite/plugin-types.ts +131 -0
  279. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  280. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  281. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  282. package/src/vite/plugins/expose-action-id.ts +365 -0
  283. package/src/vite/plugins/expose-id-utils.ts +287 -0
  284. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  285. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  286. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  287. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  288. package/src/vite/plugins/expose-ids/types.ts +45 -0
  289. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  290. package/src/vite/plugins/refresh-cmd.ts +65 -0
  291. package/src/vite/plugins/use-cache-transform.ts +323 -0
  292. package/src/vite/plugins/version-injector.ts +83 -0
  293. package/src/vite/plugins/version-plugin.ts +254 -0
  294. package/src/vite/plugins/version.d.ts +12 -0
  295. package/src/vite/plugins/virtual-entries.ts +123 -0
  296. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  297. package/src/vite/rango.ts +510 -0
  298. package/src/vite/router-discovery.ts +785 -0
  299. package/src/vite/utils/ast-handler-extract.ts +517 -0
  300. package/src/vite/utils/banner.ts +36 -0
  301. package/src/vite/utils/bundle-analysis.ts +137 -0
  302. package/src/vite/utils/manifest-utils.ts +70 -0
  303. package/src/vite/utils/package-resolution.ts +121 -0
  304. package/src/vite/utils/prerender-utils.ts +189 -0
  305. package/src/vite/utils/shared-utils.ts +169 -0
@@ -0,0 +1,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,430 @@
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
+ * // Access loader data in handlers via ctx.use()
232
+ * route("products.detail", async (ctx) => {
233
+ * const product = await ctx.use(ProductLoader);
234
+ * return <ProductPage product={product} />;
235
+ * })
236
+ * ```
237
+ * @param loaderDef - Loader created with createLoader()
238
+ * @param use - Optional callback for loader-specific revalidation rules
239
+ */
240
+ loader: <TData>(
241
+ loaderDef: LoaderDefinition<TData>,
242
+ use?: () => UseItems<LoaderUseItem>,
243
+ ) => LoaderItem;
244
+ /**
245
+ * Attach a loading component to the current route/layout
246
+ * ```typescript
247
+ * // Show loading on all requests (including SSR)
248
+ * loading(<Skeleton />)
249
+ *
250
+ * // Skip loading on SSR, only show on client navigation
251
+ * loading(<Skeleton />, { ssr: false })
252
+ * ```
253
+ * @param component - The loading UI to show during navigation
254
+ * @param options - Configuration options
255
+ * @param options.ssr - If false, skip showing loading on document requests (SSR)
256
+ */
257
+ loading: (component: ReactNode, options?: { ssr?: boolean }) => LoadingItem;
258
+ /**
259
+ * Attach an error boundary to catch errors in this segment and children
260
+ * ```typescript
261
+ * errorBoundary(<ErrorFallback />)
262
+ *
263
+ * // With dynamic error handler
264
+ * errorBoundary(({ error, reset }) => (
265
+ * <div>
266
+ * <h2>Something went wrong</h2>
267
+ * <p>{error.message}</p>
268
+ * <button onClick={reset}>Try again</button>
269
+ * </div>
270
+ * ))
271
+ * ```
272
+ * @param fallback - Static JSX or handler receiving error info and reset function
273
+ */
274
+ errorBoundary: (
275
+ fallback: ReactNode | ErrorBoundaryHandler,
276
+ ) => ErrorBoundaryItem;
277
+ /**
278
+ * Attach a not-found boundary to handle notFound() calls in this segment
279
+ * ```typescript
280
+ * notFoundBoundary(<ProductNotFound />)
281
+ *
282
+ * // With dynamic handler
283
+ * notFoundBoundary(({ notFound }) => (
284
+ * <div>
285
+ * <h2>{notFound.message}</h2>
286
+ * <a href="/products">Browse all products</a>
287
+ * </div>
288
+ * ))
289
+ * ```
290
+ * @param fallback - Static JSX or handler receiving not-found info
291
+ */
292
+ notFoundBoundary: (
293
+ fallback: ReactNode | NotFoundBoundaryHandler,
294
+ ) => NotFoundBoundaryItem;
295
+ /**
296
+ * Define a condition for when an intercept should activate
297
+ *
298
+ * Only valid inside intercept() use() callback. When multiple when() calls
299
+ * are present, ALL must return true for the intercept to activate.
300
+ * If no when() is defined, the intercept always activates on soft navigation.
301
+ *
302
+ * Context properties:
303
+ * - `from` - Source URL (where user is navigating from)
304
+ * - `to` - Destination URL (where user is navigating to)
305
+ * - `params` - Matched route params
306
+ * - `segments` - Client's current segments with `path` and `ids`
307
+ *
308
+ * ```typescript
309
+ * // Only intercept when coming from the board page
310
+ * intercept("@modal", "card", <CardModal />, () => [
311
+ * when(({ from }) => from.pathname.startsWith("/board")),
312
+ * loader(CardDetailLoader),
313
+ * ])
314
+ *
315
+ * // Use segments to check current route context
316
+ * intercept("@modal", "card", <CardModal />, () => [
317
+ * when(({ segments }) => segments.path[0] === "kanban"),
318
+ * ])
319
+ *
320
+ * // Multiple conditions (AND logic)
321
+ * intercept("@modal", "card", <CardModal />, () => [
322
+ * when(({ from }) => from.pathname.startsWith("/board")),
323
+ * when(({ segments }) => segments.ids.includes("kanban-layout")),
324
+ * ])
325
+ * ```
326
+ * @param fn - Selector function receiving navigation context, returns boolean
327
+ */
328
+ when: (fn: InterceptWhenFn) => WhenItem;
329
+ /**
330
+ * Define cache configuration for segments
331
+ *
332
+ * Creates a cache boundary that applies to all children unless overridden.
333
+ * Cache config inherits down the route tree like middleware wrapping.
334
+ *
335
+ * When ttl is not specified, uses store defaults (explicit store first,
336
+ * then app-level store). When store is not specified, uses app-level store.
337
+ *
338
+ * Note: Loaders are NOT cached by default. Use cache() inside loader()
339
+ * to explicitly opt-in to loader caching.
340
+ *
341
+ * ```typescript
342
+ * // Using app-level defaults (ttl inherited from store.defaults)
343
+ * cache(() => [
344
+ * layout(<BlogLayout />), // cached with default TTL
345
+ * route("post/:slug"), // cached with default TTL
346
+ * ])
347
+ *
348
+ * // Cache all segments with explicit 60s TTL
349
+ * cache({ ttl: 60 }, () => [
350
+ * layout(<BlogLayout />), // cached
351
+ * route("post/:slug"), // cached
352
+ * ])
353
+ *
354
+ * // With stale-while-revalidate
355
+ * cache({ ttl: 60, swr: 300 }, () => [
356
+ * route("product/:id"),
357
+ * ])
358
+ *
359
+ * // Override for specific section
360
+ * cache({ ttl: 60 }, () => [
361
+ * layout(<RootLayout />),
362
+ * cache({ ttl: 300 }, () => [
363
+ * route("static-page"), // longer TTL
364
+ * ]),
365
+ * cache(false, () => [
366
+ * route("admin"), // not cached
367
+ * ]),
368
+ * ])
369
+ *
370
+ * // Use different store for specific routes
371
+ * cache({ store: kvStore, ttl: 3600 }, () => [
372
+ * route("archive/:year"), // uses KV store
373
+ * ])
374
+ *
375
+ * // Opt-in loader caching
376
+ * route("product/:id", ProductHandler, () => [
377
+ * loader(ProductLoader), // NOT cached (default)
378
+ * loader(StaticMetadata, () => [
379
+ * cache({ ttl: 3600 }), // cached for 1 hour
380
+ * ]),
381
+ * ])
382
+ * ```
383
+ * @param optionsOrChildren - Cache options, false to disable, or children callback
384
+ * @param children - Optional callback returning child segments (when first arg is options)
385
+ */
386
+ cache: {
387
+ (): CacheItem;
388
+ (children: () => UseItems<AllUseItems>): CacheItem;
389
+ (profileName: string): CacheItem;
390
+ (profileName: string, use: () => UseItems<AllUseItems>): CacheItem;
391
+ (
392
+ options: PartialCacheOptions | false,
393
+ use?: () => UseItems<AllUseItems>,
394
+ ): CacheItem;
395
+ };
396
+ /**
397
+ * Attach a ViewTransition boundary to the current segment or a group of routes
398
+ *
399
+ * Wraps segment content with React's `<ViewTransition>` component.
400
+ * Only takes effect when React experimental is used (no-op on stable React).
401
+ *
402
+ * ```typescript
403
+ * // Attach to a single route
404
+ * path("/about", AboutPage, { name: "about" }, () => [
405
+ * transition({ enter: "fade-in", exit: "fade-out" }),
406
+ * ])
407
+ *
408
+ * // Wrap a group of routes
409
+ * transition({ enter: "fade-in", exit: "fade-out" }, () => [
410
+ * path("/", HomePage),
411
+ * path("/about", AboutPage),
412
+ * ])
413
+ *
414
+ * // Direction-aware transitions
415
+ * transition({
416
+ * enter: { "navigation": "slide-right", "navigation-back": "slide-left" },
417
+ * exit: { "navigation": "slide-left", "navigation-back": "slide-right" },
418
+ * })
419
+ * ```
420
+ * @param config - ViewTransition configuration (enter, exit, update, share, default, name)
421
+ * @param children - Optional callback returning child routes to wrap
422
+ */
423
+ transition: {
424
+ (config: TransitionConfig): TransitionItem;
425
+ (
426
+ config: TransitionConfig,
427
+ children: () => UseItems<AllUseItems>,
428
+ ): TransitionItem;
429
+ };
430
+ };
@@ -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";