@rangojs/router 0.0.0-experimental.7 → 0.0.0-experimental.70

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 (307) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +942 -4
  3. package/dist/bin/rango.js +1689 -0
  4. package/dist/vite/index.js +4951 -930
  5. package/package.json +70 -60
  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 +92 -31
  18. package/skills/loader/SKILL.md +404 -44
  19. package/skills/middleware/SKILL.md +173 -34
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +204 -1
  22. package/skills/prerender/SKILL.md +685 -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 +210 -32
  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/app-version.ts +14 -0
  36. package/src/browser/event-controller.ts +92 -64
  37. package/src/browser/history-state.ts +80 -0
  38. package/src/browser/intercept-utils.ts +52 -0
  39. package/src/browser/link-interceptor.ts +24 -4
  40. package/src/browser/logging.ts +55 -0
  41. package/src/browser/merge-segment-loaders.ts +20 -12
  42. package/src/browser/navigation-bridge.ts +296 -558
  43. package/src/browser/navigation-client.ts +179 -69
  44. package/src/browser/navigation-store.ts +73 -55
  45. package/src/browser/navigation-transaction.ts +297 -0
  46. package/src/browser/network-error-handler.ts +61 -0
  47. package/src/browser/partial-update.ts +328 -313
  48. package/src/browser/prefetch/cache.ts +206 -0
  49. package/src/browser/prefetch/fetch.ts +150 -0
  50. package/src/browser/prefetch/observer.ts +65 -0
  51. package/src/browser/prefetch/policy.ts +48 -0
  52. package/src/browser/prefetch/queue.ts +160 -0
  53. package/src/browser/prefetch/resource-ready.ts +77 -0
  54. package/src/browser/rango-state.ts +112 -0
  55. package/src/browser/react/Link.tsx +230 -74
  56. package/src/browser/react/NavigationProvider.tsx +87 -11
  57. package/src/browser/react/context.ts +11 -0
  58. package/src/browser/react/filter-segment-order.ts +11 -0
  59. package/src/browser/react/index.ts +12 -12
  60. package/src/browser/react/location-state-shared.ts +95 -53
  61. package/src/browser/react/location-state.ts +60 -15
  62. package/src/browser/react/mount-context.ts +6 -1
  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 +29 -51
  66. package/src/browser/react/use-client-cache.ts +5 -3
  67. package/src/browser/react/use-handle.ts +30 -126
  68. package/src/browser/react/use-href.tsx +2 -2
  69. package/src/browser/react/use-link-status.ts +6 -5
  70. package/src/browser/react/use-navigation.ts +22 -63
  71. package/src/browser/react/use-params.ts +65 -0
  72. package/src/browser/react/use-pathname.ts +47 -0
  73. package/src/browser/react/use-router.ts +76 -0
  74. package/src/browser/react/use-search-params.ts +56 -0
  75. package/src/browser/react/use-segments.ts +80 -97
  76. package/src/browser/response-adapter.ts +73 -0
  77. package/src/browser/rsc-router.tsx +214 -58
  78. package/src/browser/scroll-restoration.ts +127 -52
  79. package/src/browser/segment-reconciler.ts +221 -0
  80. package/src/browser/segment-structure-assert.ts +16 -0
  81. package/src/browser/server-action-bridge.ts +510 -603
  82. package/src/browser/shallow.ts +6 -1
  83. package/src/browser/types.ts +141 -48
  84. package/src/browser/validate-redirect-origin.ts +29 -0
  85. package/src/build/generate-manifest.ts +235 -24
  86. package/src/build/generate-route-types.ts +39 -0
  87. package/src/build/index.ts +13 -0
  88. package/src/build/route-trie.ts +265 -0
  89. package/src/build/route-types/ast-helpers.ts +25 -0
  90. package/src/build/route-types/ast-route-extraction.ts +98 -0
  91. package/src/build/route-types/codegen.ts +102 -0
  92. package/src/build/route-types/include-resolution.ts +418 -0
  93. package/src/build/route-types/param-extraction.ts +48 -0
  94. package/src/build/route-types/per-module-writer.ts +128 -0
  95. package/src/build/route-types/router-processing.ts +618 -0
  96. package/src/build/route-types/scan-filter.ts +85 -0
  97. package/src/build/runtime-discovery.ts +231 -0
  98. package/src/cache/background-task.ts +34 -0
  99. package/src/cache/cache-key-utils.ts +44 -0
  100. package/src/cache/cache-policy.ts +125 -0
  101. package/src/cache/cache-runtime.ts +342 -0
  102. package/src/cache/cache-scope.ts +167 -309
  103. package/src/cache/cf/cf-cache-store.ts +571 -17
  104. package/src/cache/cf/index.ts +13 -3
  105. package/src/cache/document-cache.ts +116 -77
  106. package/src/cache/handle-capture.ts +81 -0
  107. package/src/cache/handle-snapshot.ts +41 -0
  108. package/src/cache/index.ts +1 -15
  109. package/src/cache/memory-segment-store.ts +191 -13
  110. package/src/cache/profile-registry.ts +73 -0
  111. package/src/cache/read-through-swr.ts +134 -0
  112. package/src/cache/segment-codec.ts +256 -0
  113. package/src/cache/taint.ts +153 -0
  114. package/src/cache/types.ts +72 -122
  115. package/src/client.rsc.tsx +3 -1
  116. package/src/client.tsx +105 -179
  117. package/src/component-utils.ts +4 -4
  118. package/src/components/DefaultDocument.tsx +5 -1
  119. package/src/context-var.ts +156 -0
  120. package/src/debug.ts +19 -9
  121. package/src/errors.ts +108 -2
  122. package/src/handle.ts +55 -29
  123. package/src/handles/MetaTags.tsx +73 -20
  124. package/src/handles/breadcrumbs.ts +66 -0
  125. package/src/handles/index.ts +1 -0
  126. package/src/handles/meta.ts +30 -13
  127. package/src/host/cookie-handler.ts +21 -15
  128. package/src/host/errors.ts +8 -8
  129. package/src/host/index.ts +4 -7
  130. package/src/host/pattern-matcher.ts +27 -27
  131. package/src/host/router.ts +61 -39
  132. package/src/host/testing.ts +8 -8
  133. package/src/host/types.ts +15 -7
  134. package/src/host/utils.ts +1 -1
  135. package/src/href-client.ts +119 -29
  136. package/src/index.rsc.ts +155 -19
  137. package/src/index.ts +223 -30
  138. package/src/internal-debug.ts +11 -0
  139. package/src/loader.rsc.ts +26 -157
  140. package/src/loader.ts +27 -10
  141. package/src/network-error-thrower.tsx +3 -1
  142. package/src/outlet-provider.tsx +45 -0
  143. package/src/prerender/param-hash.ts +37 -0
  144. package/src/prerender/store.ts +186 -0
  145. package/src/prerender.ts +524 -0
  146. package/src/reverse.ts +351 -0
  147. package/src/root-error-boundary.tsx +41 -29
  148. package/src/route-content-wrapper.tsx +7 -4
  149. package/src/route-definition/dsl-helpers.ts +982 -0
  150. package/src/route-definition/helper-factories.ts +200 -0
  151. package/src/route-definition/helpers-types.ts +434 -0
  152. package/src/route-definition/index.ts +55 -0
  153. package/src/route-definition/redirect.ts +101 -0
  154. package/src/route-definition/resolve-handler-use.ts +149 -0
  155. package/src/route-definition.ts +1 -1428
  156. package/src/route-map-builder.ts +217 -123
  157. package/src/route-name.ts +53 -0
  158. package/src/route-types.ts +70 -8
  159. package/src/router/content-negotiation.ts +215 -0
  160. package/src/router/debug-manifest.ts +72 -0
  161. package/src/router/error-handling.ts +9 -9
  162. package/src/router/find-match.ts +160 -0
  163. package/src/router/handler-context.ts +435 -86
  164. package/src/router/intercept-resolution.ts +402 -0
  165. package/src/router/lazy-includes.ts +237 -0
  166. package/src/router/loader-resolution.ts +356 -128
  167. package/src/router/logging.ts +251 -0
  168. package/src/router/manifest.ts +154 -35
  169. package/src/router/match-api.ts +555 -0
  170. package/src/router/match-context.ts +5 -3
  171. package/src/router/match-handlers.ts +440 -0
  172. package/src/router/match-middleware/background-revalidation.ts +108 -93
  173. package/src/router/match-middleware/cache-lookup.ts +459 -10
  174. package/src/router/match-middleware/cache-store.ts +98 -26
  175. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  176. package/src/router/match-middleware/segment-resolution.ts +80 -6
  177. package/src/router/match-pipelines.ts +10 -45
  178. package/src/router/match-result.ts +55 -33
  179. package/src/router/metrics.ts +240 -15
  180. package/src/router/middleware-cookies.ts +55 -0
  181. package/src/router/middleware-types.ts +220 -0
  182. package/src/router/middleware.ts +324 -369
  183. package/src/router/navigation-snapshot.ts +182 -0
  184. package/src/router/pattern-matching.ts +211 -43
  185. package/src/router/prerender-match.ts +502 -0
  186. package/src/router/preview-match.ts +98 -0
  187. package/src/router/request-classification.ts +310 -0
  188. package/src/router/revalidation.ts +137 -38
  189. package/src/router/route-snapshot.ts +245 -0
  190. package/src/router/router-context.ts +41 -21
  191. package/src/router/router-interfaces.ts +484 -0
  192. package/src/router/router-options.ts +618 -0
  193. package/src/router/router-registry.ts +24 -0
  194. package/src/router/segment-resolution/fresh.ts +743 -0
  195. package/src/router/segment-resolution/helpers.ts +268 -0
  196. package/src/router/segment-resolution/loader-cache.ts +199 -0
  197. package/src/router/segment-resolution/revalidation.ts +1373 -0
  198. package/src/router/segment-resolution/static-store.ts +67 -0
  199. package/src/router/segment-resolution.ts +21 -0
  200. package/src/router/segment-wrappers.ts +291 -0
  201. package/src/router/telemetry-otel.ts +299 -0
  202. package/src/router/telemetry.ts +300 -0
  203. package/src/router/timeout.ts +148 -0
  204. package/src/router/trie-matching.ts +239 -0
  205. package/src/router/types.ts +78 -3
  206. package/src/router.ts +740 -4252
  207. package/src/rsc/handler-context.ts +45 -0
  208. package/src/rsc/handler.ts +907 -797
  209. package/src/rsc/helpers.ts +140 -6
  210. package/src/rsc/index.ts +0 -20
  211. package/src/rsc/loader-fetch.ts +229 -0
  212. package/src/rsc/manifest-init.ts +90 -0
  213. package/src/rsc/nonce.ts +14 -0
  214. package/src/rsc/origin-guard.ts +141 -0
  215. package/src/rsc/progressive-enhancement.ts +391 -0
  216. package/src/rsc/response-error.ts +37 -0
  217. package/src/rsc/response-route-handler.ts +347 -0
  218. package/src/rsc/rsc-rendering.ts +246 -0
  219. package/src/rsc/runtime-warnings.ts +42 -0
  220. package/src/rsc/server-action.ts +356 -0
  221. package/src/rsc/ssr-setup.ts +128 -0
  222. package/src/rsc/types.ts +46 -11
  223. package/src/search-params.ts +230 -0
  224. package/src/segment-system.tsx +165 -17
  225. package/src/server/context.ts +315 -58
  226. package/src/server/cookie-store.ts +190 -0
  227. package/src/server/fetchable-loader-store.ts +37 -0
  228. package/src/server/handle-store.ts +113 -15
  229. package/src/server/loader-registry.ts +24 -64
  230. package/src/server/request-context.ts +607 -81
  231. package/src/server.ts +35 -130
  232. package/src/ssr/index.tsx +103 -30
  233. package/src/static-handler.ts +126 -0
  234. package/src/theme/ThemeProvider.tsx +21 -15
  235. package/src/theme/ThemeScript.tsx +5 -5
  236. package/src/theme/constants.ts +5 -2
  237. package/src/theme/index.ts +4 -14
  238. package/src/theme/theme-context.ts +4 -30
  239. package/src/theme/theme-script.ts +21 -18
  240. package/src/types/boundaries.ts +158 -0
  241. package/src/types/cache-types.ts +198 -0
  242. package/src/types/error-types.ts +192 -0
  243. package/src/types/global-namespace.ts +100 -0
  244. package/src/types/handler-context.ts +791 -0
  245. package/src/types/index.ts +88 -0
  246. package/src/types/loader-types.ts +210 -0
  247. package/src/types/route-config.ts +170 -0
  248. package/src/types/route-entry.ts +109 -0
  249. package/src/types/segments.ts +150 -0
  250. package/src/types.ts +1 -1623
  251. package/src/urls/include-helper.ts +197 -0
  252. package/src/urls/index.ts +53 -0
  253. package/src/urls/path-helper-types.ts +346 -0
  254. package/src/urls/path-helper.ts +364 -0
  255. package/src/urls/pattern-types.ts +107 -0
  256. package/src/urls/response-types.ts +116 -0
  257. package/src/urls/type-extraction.ts +372 -0
  258. package/src/urls/urls-function.ts +98 -0
  259. package/src/urls.ts +1 -802
  260. package/src/use-loader.tsx +161 -81
  261. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  262. package/src/vite/discovery/discover-routers.ts +348 -0
  263. package/src/vite/discovery/prerender-collection.ts +439 -0
  264. package/src/vite/discovery/route-types-writer.ts +258 -0
  265. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  266. package/src/vite/discovery/state.ts +117 -0
  267. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  268. package/src/vite/index.ts +15 -1129
  269. package/src/vite/plugin-types.ts +103 -0
  270. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  271. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  272. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  273. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  274. package/src/vite/plugins/expose-id-utils.ts +299 -0
  275. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  276. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  277. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  278. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  279. package/src/vite/plugins/expose-ids/types.ts +45 -0
  280. package/src/vite/plugins/expose-internal-ids.ts +786 -0
  281. package/src/vite/plugins/performance-tracks.ts +88 -0
  282. package/src/vite/plugins/refresh-cmd.ts +127 -0
  283. package/src/vite/plugins/use-cache-transform.ts +323 -0
  284. package/src/vite/plugins/version-injector.ts +83 -0
  285. package/src/vite/plugins/version-plugin.ts +266 -0
  286. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  287. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  288. package/src/vite/rango.ts +462 -0
  289. package/src/vite/router-discovery.ts +918 -0
  290. package/src/vite/utils/ast-handler-extract.ts +517 -0
  291. package/src/vite/utils/banner.ts +36 -0
  292. package/src/vite/utils/bundle-analysis.ts +137 -0
  293. package/src/vite/utils/manifest-utils.ts +70 -0
  294. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  295. package/src/vite/utils/prerender-utils.ts +207 -0
  296. package/src/vite/utils/shared-utils.ts +170 -0
  297. package/CLAUDE.md +0 -43
  298. package/src/browser/lru-cache.ts +0 -69
  299. package/src/browser/request-controller.ts +0 -164
  300. package/src/cache/memory-store.ts +0 -253
  301. package/src/href-context.ts +0 -33
  302. package/src/href.ts +0 -255
  303. package/src/server/route-manifest-cache.ts +0 -173
  304. package/src/vite/expose-handle-id.ts +0 -209
  305. package/src/vite/expose-loader-id.ts +0 -426
  306. package/src/vite/expose-location-state-id.ts +0 -177
  307. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -0,0 +1,197 @@
1
+ import type { AllUseItems, IncludeItem } from "../route-types.js";
2
+ import {
3
+ getContext,
4
+ runWithPrefixes,
5
+ getUrlPrefix,
6
+ getNamePrefix,
7
+ getRootScoped,
8
+ } from "../server/context";
9
+ import {
10
+ INTERNAL_INCLUDE_SCOPE_PREFIX,
11
+ validateUserRouteName,
12
+ } from "../route-name.js";
13
+ import type { UrlPatterns, IncludeOptions } from "./pattern-types.js";
14
+ import type { IncludeFn } from "./path-helper-types.js";
15
+
16
+ function hasExplicitNameOption(options: IncludeOptions | undefined): boolean {
17
+ return !!options && Object.prototype.hasOwnProperty.call(options, "name");
18
+ }
19
+
20
+ function allocateInternalIncludeScopeId(
21
+ counters: Record<string, number>,
22
+ ): string {
23
+ const key = "__include_scope__";
24
+ const index = counters[key] ?? 0;
25
+ counters[key] = index + 1;
26
+ return `${INTERNAL_INCLUDE_SCOPE_PREFIX}${index}`;
27
+ }
28
+
29
+ /**
30
+ * Process an IncludeItem by executing its nested patterns with prefixes
31
+ * This expands the include into actual route registrations
32
+ */
33
+ function processIncludeItem(item: IncludeItem): AllUseItems[] {
34
+ const { prefix, patterns } = item;
35
+ const namePrefix =
36
+ (item as IncludeItem & { _lazyContext?: { namePrefix?: string } })
37
+ ._lazyContext?.namePrefix ?? item.options?.name;
38
+
39
+ // Execute the nested patterns' handler with URL and name prefixes
40
+ // The urlPrefix being set tells nested urls() to skip RootLayout wrapping
41
+ return runWithPrefixes(prefix, namePrefix, () => {
42
+ // Call the nested patterns' handler - this registers routes with prefixed patterns/names
43
+ return (patterns as UrlPatterns).handler();
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Recursively process items, expanding any IncludeItems
49
+ * Returns items with IncludeItems expanded into actual route items
50
+ *
51
+ * Lazy includes are kept as-is (not expanded) for the router to handle later.
52
+ */
53
+ export function processItems(items: readonly AllUseItems[]): AllUseItems[] {
54
+ const result: AllUseItems[] = [];
55
+
56
+ for (const item of items) {
57
+ if (!item) continue;
58
+
59
+ if (item.type === "include") {
60
+ const includeItem = item as IncludeItem & {
61
+ _expanded?: AllUseItems[];
62
+ lazy?: boolean;
63
+ };
64
+
65
+ // Lazy includes are NOT expanded here - kept for router to handle
66
+ if (includeItem.lazy) {
67
+ result.push(item);
68
+ continue;
69
+ }
70
+
71
+ // Eager includes are already expanded during include() call
72
+ if (includeItem._expanded) {
73
+ // Items were expanded immediately - just process them recursively
74
+ result.push(...processItems(includeItem._expanded));
75
+ } else {
76
+ // Fallback for legacy include items without _expanded
77
+ const expanded = processIncludeItem(item as IncludeItem);
78
+ result.push(...processItems(expanded));
79
+ }
80
+ } else if (item.type === "layout" && (item as any).uses) {
81
+ // Process nested items in layout
82
+ const layoutItem = item as any;
83
+ layoutItem.uses = processItems(layoutItem.uses);
84
+ result.push(layoutItem);
85
+ } else {
86
+ result.push(item);
87
+ }
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+ /**
94
+ * Create include() helper for composing URL patterns
95
+ *
96
+ * By default, include() IMMEDIATELY expands the nested patterns. This ensures
97
+ * that routes from included patterns inherit the correct parent context
98
+ * (the layout they're included in).
99
+ *
100
+ * With `lazy: true`, patterns are NOT expanded at definition time. Instead,
101
+ * they're evaluated on first request that matches the prefix. This improves
102
+ * cold start time for apps with many routes.
103
+ */
104
+ export function createIncludeHelper<TEnv>(): IncludeFn<TEnv> {
105
+ return (
106
+ prefix: string,
107
+ patterns: UrlPatterns<TEnv>,
108
+ options?: IncludeOptions,
109
+ ): IncludeItem => {
110
+ const store = getContext();
111
+ const ctx = store.getStore();
112
+ if (!ctx) throw new Error("include() must be called inside urls()");
113
+
114
+ const explicitName = options?.name;
115
+ const hasExplicitName = hasExplicitNameOption(options);
116
+ if (hasExplicitName && explicitName) {
117
+ validateUserRouteName(explicitName);
118
+ }
119
+ const name = `$include_${prefix.replace(/[/:*?]/g, "_")}`;
120
+
121
+ // Capture context for deferred evaluation
122
+ const capturedUrlPrefix = getUrlPrefix();
123
+ const capturedNamePrefix = getNamePrefix();
124
+ const capturedParent = ctx.parent;
125
+ const fullPrefix = capturedUrlPrefix
126
+ ? capturedUrlPrefix.endsWith("/") && prefix.startsWith("/")
127
+ ? capturedUrlPrefix + prefix.slice(1)
128
+ : capturedUrlPrefix + prefix
129
+ : prefix;
130
+ const internalScope = !hasExplicitName
131
+ ? allocateInternalIncludeScopeId(ctx.counters)
132
+ : undefined;
133
+ const nextSegment = hasExplicitName ? explicitName : internalScope;
134
+ const fullNamePrefix =
135
+ nextSegment !== undefined && nextSegment !== ""
136
+ ? capturedNamePrefix
137
+ ? `${capturedNamePrefix}.${nextSegment}`
138
+ : nextSegment
139
+ : capturedNamePrefix;
140
+
141
+ // Track this include for build-time manifest generation
142
+ if (ctx.trackedIncludes) {
143
+ ctx.trackedIncludes.push({
144
+ prefix,
145
+ fullPrefix,
146
+ namePrefix: fullNamePrefix,
147
+ patterns,
148
+ lazy: true,
149
+ });
150
+ }
151
+
152
+ // Snapshot parent's counters so lazy manifest generation starts
153
+ // at the correct index, preventing shortCode collisions with
154
+ // sibling entries (e.g., BlogLayout and ArticlesLayout under NavLayout).
155
+ const capturedCounters = { ...ctx.counters };
156
+
157
+ // Reserve a layout slot in the parent's counter so sibling lazy includes
158
+ // produce different shortCode indices for their root layout.
159
+ // Without this, consecutive include() calls capture identical counters
160
+ // and their first child layouts get the same shortCode (e.g., both M0L0L0),
161
+ // causing the client partial-update diff to see no changes on navigation.
162
+ if (capturedParent?.shortCode) {
163
+ const layoutCounterKey = `${capturedParent.shortCode}_layout`;
164
+ ctx.counters[layoutCounterKey] ??= 0;
165
+ ctx.counters[layoutCounterKey]++;
166
+ }
167
+
168
+ // Compute rootScoped at capture time, mirroring the logic in runWithPrefixes.
169
+ // This ensures lazy evaluation restores the correct scope state.
170
+ const parentRootScoped = ctx.rootScoped;
171
+ const capturedRootScoped =
172
+ nextSegment === ""
173
+ ? (parentRootScoped ?? true)
174
+ : nextSegment !== undefined
175
+ ? (parentRootScoped ?? false)
176
+ : parentRootScoped;
177
+
178
+ // All includes are lazy - patterns are evaluated on first matching request
179
+ // This improves cold start time significantly for large route sets
180
+ return {
181
+ type: "include",
182
+ name,
183
+ prefix,
184
+ patterns,
185
+ options,
186
+ lazy: true,
187
+ _lazyContext: {
188
+ urlPrefix: capturedUrlPrefix,
189
+ namePrefix: fullNamePrefix,
190
+ parent: capturedParent,
191
+ counters: capturedCounters,
192
+ cacheProfiles: ctx.cacheProfiles,
193
+ rootScoped: capturedRootScoped,
194
+ },
195
+ } as IncludeItem;
196
+ };
197
+ }
@@ -0,0 +1,53 @@
1
+ // Response types and symbols
2
+ export {
3
+ RESPONSE_TYPE,
4
+ type ResponseHandler,
5
+ type JsonValue,
6
+ type JsonResponseHandler,
7
+ type TextResponseHandler,
8
+ type ResponseHandlerContext,
9
+ } from "./response-types.js";
10
+
11
+ // Pattern types
12
+ export type {
13
+ UnnamedRoute,
14
+ LocalOnlyInclude,
15
+ PathOptions,
16
+ PathDefinition,
17
+ UrlPatterns,
18
+ IncludeOptions,
19
+ } from "./pattern-types.js";
20
+
21
+ // Type extraction utilities
22
+ export type {
23
+ ExtractRoutes,
24
+ ExtractResponses,
25
+ ExtractRouteNames,
26
+ ExtractPathParams,
27
+ ResponseError,
28
+ ResponseEnvelope,
29
+ RouteResponse,
30
+ } from "./type-extraction.js";
31
+
32
+ // Path helper types
33
+ export type {
34
+ PathFn,
35
+ ResponsePathFn,
36
+ JsonResponsePathFn,
37
+ TextResponsePathFn,
38
+ IncludeFn,
39
+ PathHelpers,
40
+ } from "./path-helper-types.js";
41
+
42
+ // Main entry point
43
+ export { urls } from "./urls-function.js";
44
+
45
+ // Re-exports from route-types
46
+ export type {
47
+ AllUseItems,
48
+ IncludeItem,
49
+ TypedRouteItem,
50
+ TypedIncludeItem,
51
+ TypedLayoutItem,
52
+ TypedCacheItem,
53
+ } from "../route-types.js";
@@ -0,0 +1,346 @@
1
+ import type { ReactNode } from "react";
2
+ import type {
3
+ ErrorBoundaryHandler,
4
+ ExtractParams,
5
+ Handler,
6
+ HandlerContext,
7
+ LoaderDefinition,
8
+ MiddlewareFn,
9
+ NotFoundBoundaryHandler,
10
+ PartialCacheOptions,
11
+ ShouldRevalidateFn,
12
+ TransitionConfig,
13
+ } from "../types.js";
14
+ import type {
15
+ AllUseItems,
16
+ TypedLayoutItem,
17
+ ParallelItem,
18
+ InterceptItem,
19
+ MiddlewareItem,
20
+ RevalidateItem,
21
+ LoaderItem,
22
+ LoadingItem,
23
+ ErrorBoundaryItem,
24
+ NotFoundBoundaryItem,
25
+ LayoutUseItem,
26
+ RouteUseItem,
27
+ ResponseRouteUseItem,
28
+ ParallelUseItem,
29
+ InterceptUseItem,
30
+ LoaderUseItem,
31
+ WhenItem,
32
+ TypedCacheItem,
33
+ TransitionItem,
34
+ TypedTransitionItem,
35
+ TypedRouteItem,
36
+ TypedIncludeItem,
37
+ UseItems,
38
+ } from "../route-types.js";
39
+ import type { SearchSchema } from "../search-params.js";
40
+ import type {
41
+ PrerenderHandlerDefinition,
42
+ PassthroughHandlerDefinition,
43
+ } from "../prerender.js";
44
+ import type { StaticHandlerDefinition } from "../static-handler.js";
45
+ import type { InterceptWhenFn } from "../server/context";
46
+ import type {
47
+ ResponseHandler,
48
+ ResponseHandlerContext,
49
+ TextResponseHandler,
50
+ } from "./response-types.js";
51
+ import type {
52
+ UnnamedRoute,
53
+ LocalOnlyInclude,
54
+ PathOptions,
55
+ UrlPatterns,
56
+ IncludeOptions,
57
+ } from "./pattern-types.js";
58
+ import type { ExtractRoutes, ExtractResponses } from "./type-extraction.js";
59
+
60
+ /**
61
+ * Base path function signature for defining routes with URL patterns.
62
+ */
63
+ export type PathFn<TEnv> = <
64
+ const TPattern extends string,
65
+ const TName extends string = UnnamedRoute,
66
+ const TSearch extends SearchSchema = {},
67
+ TParams extends Record<string, any> = ExtractParams<TPattern>,
68
+ >(
69
+ pattern: TPattern,
70
+ handler:
71
+ | ReactNode
72
+ | ((
73
+ ctx: HandlerContext<TParams, TEnv, TSearch>,
74
+ ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>)
75
+ | PrerenderHandlerDefinition<TParams>
76
+ | PassthroughHandlerDefinition<TParams, TEnv>
77
+ | StaticHandlerDefinition<TParams>,
78
+ optionsOrUse?: PathOptions<TName, TSearch> | (() => UseItems<RouteUseItem>),
79
+ use?: () => UseItems<RouteUseItem>,
80
+ // Generic handler bypass: when handler uses index-signature params
81
+ // (e.g. Handler<Record<string, any>>), skip the biconditional.
82
+ // `string extends keyof TParams` is true for index signatures,
83
+ // false for concrete params ({id: string}) and empty ({}).
84
+ //
85
+ // Subset check: pattern params must be assignable to handler params,
86
+ // but handler can have MORE params (e.g. from parent include() prefix).
87
+ // This allows Prerender<"locale.detail"> with {locale, slug} to mount
88
+ // on path("/blog/:slug") where the pattern only declares {slug}.
89
+ ) => string extends keyof TParams
90
+ ? TypedRouteItem<TName, TPattern, unknown, TSearch>
91
+ : TParams extends ExtractParams<TPattern>
92
+ ? TypedRouteItem<TName, TPattern, unknown, TSearch>
93
+ : { __error: `Handler params do not match pattern "${TPattern}"` };
94
+
95
+ /**
96
+ * Path function for response routes that must return Response (image, stream, any).
97
+ * Handler must return Response, not ReactNode. Uses lighter ResponseHandlerContext.
98
+ * Use items restricted to middleware() and cache() only.
99
+ */
100
+ export type ResponsePathFn<TEnv> = <
101
+ const TPattern extends string,
102
+ const TName extends string = UnnamedRoute,
103
+ const TSearch extends SearchSchema = {},
104
+ >(
105
+ pattern: TPattern,
106
+ handler: ResponseHandler<ExtractParams<TPattern>, TEnv>,
107
+ optionsOrUse?:
108
+ | PathOptions<TName, TSearch>
109
+ | (() => UseItems<ResponseRouteUseItem>),
110
+ use?: () => UseItems<ResponseRouteUseItem>,
111
+ ) => TypedRouteItem<TName, TPattern, unknown, TSearch>;
112
+
113
+ /**
114
+ * Path function for JSON response routes (path.json()).
115
+ * Handler can return plain JSON-serializable values or Response.
116
+ * TData is inferred from the handler's return type (excluding Response/Promise wrappers).
117
+ */
118
+ export type JsonResponsePathFn<TEnv> = <
119
+ const TPattern extends string,
120
+ const TName extends string = UnnamedRoute,
121
+ const TSearch extends SearchSchema = {},
122
+ TData = unknown,
123
+ >(
124
+ pattern: TPattern,
125
+ handler: (
126
+ ctx: ResponseHandlerContext<ExtractParams<TPattern>, TEnv>,
127
+ ) => TData | Response | Promise<TData | Response>,
128
+ optionsOrUse?:
129
+ | PathOptions<TName, TSearch>
130
+ | (() => UseItems<ResponseRouteUseItem>),
131
+ use?: () => UseItems<ResponseRouteUseItem>,
132
+ ) => TypedRouteItem<TName, TPattern, TData, TSearch>;
133
+
134
+ /**
135
+ * Path function for text-based response routes (path.text(), path.html(), path.xml()).
136
+ * Handler can return a string or Response. TData is always `string`.
137
+ */
138
+ export type TextResponsePathFn<TEnv> = <
139
+ const TPattern extends string,
140
+ const TName extends string = UnnamedRoute,
141
+ const TSearch extends SearchSchema = {},
142
+ >(
143
+ pattern: TPattern,
144
+ handler: TextResponseHandler<ExtractParams<TPattern>, TEnv>,
145
+ optionsOrUse?:
146
+ | PathOptions<TName, TSearch>
147
+ | (() => UseItems<ResponseRouteUseItem>),
148
+ use?: () => UseItems<ResponseRouteUseItem>,
149
+ ) => TypedRouteItem<TName, TPattern, string, TSearch>;
150
+
151
+ /**
152
+ * Base include function signature.
153
+ */
154
+ export type IncludeFn<TEnv> = <
155
+ TRoutes extends Record<string, any>,
156
+ const TUrlPrefix extends string,
157
+ const TNamePrefix extends string = LocalOnlyInclude,
158
+ TResponses extends Record<string, unknown> = Record<string, unknown>,
159
+ >(
160
+ prefix: TUrlPrefix,
161
+ patterns: UrlPatterns<TEnv, TRoutes, TResponses>,
162
+ options?: IncludeOptions<TNamePrefix>,
163
+ ) => TypedIncludeItem<TRoutes, TNamePrefix, TUrlPrefix, TResponses>;
164
+
165
+ export type PathHelpers<TEnv> = {
166
+ /**
167
+ * Define a route with URL pattern at definition site
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * // Pattern and component only
172
+ * path("/about", AboutPage)
173
+ *
174
+ * // With options
175
+ * path("/:slug", PostPage, { name: "post" })
176
+ *
177
+ * // With children (loaders, middleware, etc.)
178
+ * path("/:slug", PostPage, { name: "post" }, () => [
179
+ * loader(PostLoader),
180
+ * ])
181
+ * ```
182
+ */
183
+ path: PathFn<TEnv> & {
184
+ json: JsonResponsePathFn<TEnv>;
185
+ text: TextResponsePathFn<TEnv>;
186
+ html: TextResponsePathFn<TEnv>;
187
+ xml: TextResponsePathFn<TEnv>;
188
+ md: TextResponsePathFn<TEnv>;
189
+ image: ResponsePathFn<TEnv>;
190
+ stream: ResponsePathFn<TEnv>;
191
+ any: ResponsePathFn<TEnv>;
192
+ };
193
+
194
+ /**
195
+ * Define a layout that wraps child routes
196
+ */
197
+ layout: {
198
+ (
199
+ component: ReactNode | Handler<any, any, TEnv> | StaticHandlerDefinition,
200
+ ): TypedLayoutItem<{}, {}>;
201
+ <
202
+ const TChildren extends readonly (
203
+ | LayoutUseItem
204
+ | readonly LayoutUseItem[]
205
+ )[],
206
+ >(
207
+ component: ReactNode | Handler<any, any, TEnv> | StaticHandlerDefinition,
208
+ use: () => TChildren,
209
+ ): TypedLayoutItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
210
+ };
211
+
212
+ /**
213
+ * Include nested URL patterns under a URL prefix.
214
+ *
215
+ * The `name` option controls how child route names appear in the
216
+ * global route map and generated types:
217
+ *
218
+ * ```typescript
219
+ * // Named — children become "blog.index", "blog.post", etc.
220
+ * // Visible in generated types and globally reversible.
221
+ * include("/blog", blogPatterns, { name: "blog" })
222
+ *
223
+ * // Flattened — children merge into the parent namespace as-is.
224
+ * // Equivalent to defining those routes inline at the include site.
225
+ * include("/blog", blogPatterns, { name: "" })
226
+ *
227
+ * // Local-only (default) — children are scoped privately.
228
+ * // Hidden from generated types and global reverse resolution.
229
+ * // Only dot-local reverse (reverse(".child")) works inside.
230
+ * include("/blog", blogPatterns)
231
+ * ```
232
+ */
233
+ include: IncludeFn<TEnv>;
234
+
235
+ /**
236
+ * Define parallel routes that render simultaneously in named slots
237
+ */
238
+ parallel: <
239
+ TSlots extends Record<
240
+ `@${string}`,
241
+ Handler<any, any, TEnv> | ReactNode | StaticHandlerDefinition
242
+ >,
243
+ >(
244
+ slots: TSlots,
245
+ use?: () => ParallelUseItem[],
246
+ ) => ParallelItem;
247
+
248
+ /**
249
+ * Define an intercepting route for soft navigation
250
+ * Note: routeName must match a named path() in this urlpatterns
251
+ */
252
+ intercept: keyof RSCRouter.GeneratedRouteMap extends never
253
+ ? (
254
+ slotName: `@${string}`,
255
+ routeName: string,
256
+ handler: ReactNode | Handler<any, any, TEnv>,
257
+ use?: () => InterceptUseItem[],
258
+ ) => InterceptItem
259
+ : (
260
+ slotName: `@${string}`,
261
+ routeName: (keyof RSCRouter.GeneratedRouteMap & string) | `.${string}`,
262
+ handler: ReactNode | Handler<any, any, TEnv>,
263
+ use?: () => InterceptUseItem[],
264
+ ) => InterceptItem;
265
+
266
+ /**
267
+ * Attach middleware to the current route/layout
268
+ */
269
+ middleware: (...fns: MiddlewareFn<TEnv>[]) => MiddlewareItem;
270
+
271
+ /**
272
+ * Control when a segment should revalidate during navigation
273
+ */
274
+ revalidate: (fn: ShouldRevalidateFn<any, TEnv>) => RevalidateItem;
275
+
276
+ /**
277
+ * Attach a data loader to the current route/layout
278
+ */
279
+ loader: <TData>(
280
+ loaderDef: LoaderDefinition<TData>,
281
+ use?: () => LoaderUseItem[],
282
+ ) => LoaderItem;
283
+
284
+ /**
285
+ * Attach a loading component to the current route/layout
286
+ */
287
+ loading: (
288
+ component: ReactNode | (() => ReactNode),
289
+ options?: { ssr?: boolean },
290
+ ) => LoadingItem;
291
+
292
+ /**
293
+ * Attach an error boundary to catch errors in this segment
294
+ */
295
+ errorBoundary: (
296
+ fallback: ReactNode | ErrorBoundaryHandler,
297
+ ) => ErrorBoundaryItem;
298
+
299
+ /**
300
+ * Attach a not-found boundary to handle notFound() calls
301
+ */
302
+ notFoundBoundary: (
303
+ fallback: ReactNode | NotFoundBoundaryHandler,
304
+ ) => NotFoundBoundaryItem;
305
+
306
+ /**
307
+ * Define a condition for when an intercept should activate
308
+ */
309
+ when: (fn: InterceptWhenFn) => WhenItem;
310
+
311
+ /**
312
+ * Define cache configuration for segments
313
+ */
314
+ cache: {
315
+ (): TypedCacheItem<{}, {}>;
316
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
317
+ children: () => TChildren,
318
+ ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
319
+ (options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
320
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
321
+ options: PartialCacheOptions | false,
322
+ use: () => TChildren,
323
+ ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
324
+ };
325
+
326
+ /**
327
+ * Attach a ViewTransition boundary to the current segment or a group of routes
328
+ */
329
+ transition: {
330
+ (): TransitionItem;
331
+ (config: TransitionConfig): TransitionItem;
332
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
333
+ children: () => TChildren,
334
+ ): TypedTransitionItem<
335
+ ExtractRoutes<TChildren>,
336
+ ExtractResponses<TChildren>
337
+ >;
338
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
339
+ config: TransitionConfig,
340
+ children: () => TChildren,
341
+ ): TypedTransitionItem<
342
+ ExtractRoutes<TChildren>,
343
+ ExtractResponses<TChildren>
344
+ >;
345
+ };
346
+ };