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

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 (312) 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 +4960 -935
  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/handler-use/SKILL.md +362 -0
  14. package/skills/hooks/SKILL.md +334 -72
  15. package/skills/host-router/SKILL.md +218 -0
  16. package/skills/intercept/SKILL.md +151 -8
  17. package/skills/layout/SKILL.md +122 -3
  18. package/skills/links/SKILL.md +92 -31
  19. package/skills/loader/SKILL.md +404 -44
  20. package/skills/middleware/SKILL.md +205 -37
  21. package/skills/migrate-nextjs/SKILL.md +560 -0
  22. package/skills/migrate-react-router/SKILL.md +764 -0
  23. package/skills/mime-routes/SKILL.md +128 -0
  24. package/skills/parallel/SKILL.md +263 -1
  25. package/skills/prerender/SKILL.md +685 -0
  26. package/skills/rango/SKILL.md +87 -16
  27. package/skills/response-routes/SKILL.md +411 -0
  28. package/skills/route/SKILL.md +281 -14
  29. package/skills/router-setup/SKILL.md +210 -32
  30. package/skills/tailwind/SKILL.md +129 -0
  31. package/skills/theme/SKILL.md +9 -8
  32. package/skills/typesafety/SKILL.md +328 -89
  33. package/skills/use-cache/SKILL.md +324 -0
  34. package/src/__internal.ts +102 -4
  35. package/src/bin/rango.ts +321 -0
  36. package/src/browser/action-coordinator.ts +97 -0
  37. package/src/browser/action-response-classifier.ts +99 -0
  38. package/src/browser/app-version.ts +14 -0
  39. package/src/browser/event-controller.ts +92 -64
  40. package/src/browser/history-state.ts +80 -0
  41. package/src/browser/intercept-utils.ts +52 -0
  42. package/src/browser/link-interceptor.ts +24 -4
  43. package/src/browser/logging.ts +55 -0
  44. package/src/browser/merge-segment-loaders.ts +20 -12
  45. package/src/browser/navigation-bridge.ts +317 -560
  46. package/src/browser/navigation-client.ts +206 -68
  47. package/src/browser/navigation-store.ts +73 -55
  48. package/src/browser/navigation-transaction.ts +297 -0
  49. package/src/browser/network-error-handler.ts +61 -0
  50. package/src/browser/partial-update.ts +343 -316
  51. package/src/browser/prefetch/cache.ts +216 -0
  52. package/src/browser/prefetch/fetch.ts +206 -0
  53. package/src/browser/prefetch/observer.ts +65 -0
  54. package/src/browser/prefetch/policy.ts +48 -0
  55. package/src/browser/prefetch/queue.ts +160 -0
  56. package/src/browser/prefetch/resource-ready.ts +77 -0
  57. package/src/browser/rango-state.ts +112 -0
  58. package/src/browser/react/Link.tsx +253 -74
  59. package/src/browser/react/NavigationProvider.tsx +87 -11
  60. package/src/browser/react/context.ts +11 -0
  61. package/src/browser/react/filter-segment-order.ts +11 -0
  62. package/src/browser/react/index.ts +12 -12
  63. package/src/browser/react/location-state-shared.ts +95 -53
  64. package/src/browser/react/location-state.ts +60 -15
  65. package/src/browser/react/mount-context.ts +6 -1
  66. package/src/browser/react/nonce-context.ts +23 -0
  67. package/src/browser/react/shallow-equal.ts +27 -0
  68. package/src/browser/react/use-action.ts +29 -51
  69. package/src/browser/react/use-client-cache.ts +5 -3
  70. package/src/browser/react/use-handle.ts +30 -126
  71. package/src/browser/react/use-href.tsx +2 -2
  72. package/src/browser/react/use-link-status.ts +6 -5
  73. package/src/browser/react/use-navigation.ts +44 -65
  74. package/src/browser/react/use-params.ts +65 -0
  75. package/src/browser/react/use-pathname.ts +47 -0
  76. package/src/browser/react/use-router.ts +76 -0
  77. package/src/browser/react/use-search-params.ts +56 -0
  78. package/src/browser/react/use-segments.ts +80 -97
  79. package/src/browser/response-adapter.ts +73 -0
  80. package/src/browser/rsc-router.tsx +214 -58
  81. package/src/browser/scroll-restoration.ts +127 -52
  82. package/src/browser/segment-reconciler.ts +243 -0
  83. package/src/browser/segment-structure-assert.ts +16 -0
  84. package/src/browser/server-action-bridge.ts +510 -603
  85. package/src/browser/shallow.ts +6 -1
  86. package/src/browser/types.ts +141 -48
  87. package/src/browser/validate-redirect-origin.ts +29 -0
  88. package/src/build/generate-manifest.ts +235 -24
  89. package/src/build/generate-route-types.ts +39 -0
  90. package/src/build/index.ts +13 -0
  91. package/src/build/route-trie.ts +291 -0
  92. package/src/build/route-types/ast-helpers.ts +25 -0
  93. package/src/build/route-types/ast-route-extraction.ts +98 -0
  94. package/src/build/route-types/codegen.ts +102 -0
  95. package/src/build/route-types/include-resolution.ts +418 -0
  96. package/src/build/route-types/param-extraction.ts +48 -0
  97. package/src/build/route-types/per-module-writer.ts +128 -0
  98. package/src/build/route-types/router-processing.ts +618 -0
  99. package/src/build/route-types/scan-filter.ts +85 -0
  100. package/src/build/runtime-discovery.ts +231 -0
  101. package/src/cache/background-task.ts +34 -0
  102. package/src/cache/cache-key-utils.ts +44 -0
  103. package/src/cache/cache-policy.ts +125 -0
  104. package/src/cache/cache-runtime.ts +342 -0
  105. package/src/cache/cache-scope.ts +167 -309
  106. package/src/cache/cf/cf-cache-store.ts +571 -17
  107. package/src/cache/cf/index.ts +13 -3
  108. package/src/cache/document-cache.ts +116 -77
  109. package/src/cache/handle-capture.ts +81 -0
  110. package/src/cache/handle-snapshot.ts +41 -0
  111. package/src/cache/index.ts +1 -15
  112. package/src/cache/memory-segment-store.ts +191 -13
  113. package/src/cache/profile-registry.ts +73 -0
  114. package/src/cache/read-through-swr.ts +134 -0
  115. package/src/cache/segment-codec.ts +256 -0
  116. package/src/cache/taint.ts +153 -0
  117. package/src/cache/types.ts +72 -122
  118. package/src/client.rsc.tsx +3 -1
  119. package/src/client.tsx +135 -301
  120. package/src/component-utils.ts +4 -4
  121. package/src/components/DefaultDocument.tsx +5 -1
  122. package/src/context-var.ts +156 -0
  123. package/src/debug.ts +19 -9
  124. package/src/errors.ts +108 -2
  125. package/src/handle.ts +55 -29
  126. package/src/handles/MetaTags.tsx +73 -20
  127. package/src/handles/breadcrumbs.ts +66 -0
  128. package/src/handles/index.ts +1 -0
  129. package/src/handles/meta.ts +30 -13
  130. package/src/host/cookie-handler.ts +21 -15
  131. package/src/host/errors.ts +8 -8
  132. package/src/host/index.ts +4 -7
  133. package/src/host/pattern-matcher.ts +27 -27
  134. package/src/host/router.ts +61 -39
  135. package/src/host/testing.ts +8 -8
  136. package/src/host/types.ts +15 -7
  137. package/src/host/utils.ts +1 -1
  138. package/src/href-client.ts +119 -29
  139. package/src/index.rsc.ts +155 -19
  140. package/src/index.ts +251 -30
  141. package/src/internal-debug.ts +11 -0
  142. package/src/loader.rsc.ts +26 -157
  143. package/src/loader.ts +27 -10
  144. package/src/network-error-thrower.tsx +3 -1
  145. package/src/outlet-provider.tsx +45 -0
  146. package/src/prerender/param-hash.ts +37 -0
  147. package/src/prerender/store.ts +186 -0
  148. package/src/prerender.ts +524 -0
  149. package/src/reverse.ts +354 -0
  150. package/src/root-error-boundary.tsx +41 -29
  151. package/src/route-content-wrapper.tsx +7 -4
  152. package/src/route-definition/dsl-helpers.ts +1121 -0
  153. package/src/route-definition/helper-factories.ts +200 -0
  154. package/src/route-definition/helpers-types.ts +478 -0
  155. package/src/route-definition/index.ts +55 -0
  156. package/src/route-definition/redirect.ts +101 -0
  157. package/src/route-definition/resolve-handler-use.ts +149 -0
  158. package/src/route-definition.ts +1 -1428
  159. package/src/route-map-builder.ts +217 -123
  160. package/src/route-name.ts +53 -0
  161. package/src/route-types.ts +77 -8
  162. package/src/router/content-negotiation.ts +215 -0
  163. package/src/router/debug-manifest.ts +72 -0
  164. package/src/router/error-handling.ts +9 -9
  165. package/src/router/find-match.ts +160 -0
  166. package/src/router/handler-context.ts +438 -86
  167. package/src/router/intercept-resolution.ts +402 -0
  168. package/src/router/lazy-includes.ts +237 -0
  169. package/src/router/loader-resolution.ts +356 -128
  170. package/src/router/logging.ts +251 -0
  171. package/src/router/manifest.ts +163 -35
  172. package/src/router/match-api.ts +555 -0
  173. package/src/router/match-context.ts +5 -3
  174. package/src/router/match-handlers.ts +440 -0
  175. package/src/router/match-middleware/background-revalidation.ts +108 -93
  176. package/src/router/match-middleware/cache-lookup.ts +460 -10
  177. package/src/router/match-middleware/cache-store.ts +98 -26
  178. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  179. package/src/router/match-middleware/segment-resolution.ts +80 -6
  180. package/src/router/match-pipelines.ts +10 -45
  181. package/src/router/match-result.ts +135 -35
  182. package/src/router/metrics.ts +240 -15
  183. package/src/router/middleware-cookies.ts +55 -0
  184. package/src/router/middleware-types.ts +220 -0
  185. package/src/router/middleware.ts +324 -369
  186. package/src/router/navigation-snapshot.ts +182 -0
  187. package/src/router/pattern-matching.ts +211 -43
  188. package/src/router/prerender-match.ts +502 -0
  189. package/src/router/preview-match.ts +98 -0
  190. package/src/router/request-classification.ts +310 -0
  191. package/src/router/revalidation.ts +137 -38
  192. package/src/router/route-snapshot.ts +245 -0
  193. package/src/router/router-context.ts +41 -21
  194. package/src/router/router-interfaces.ts +484 -0
  195. package/src/router/router-options.ts +618 -0
  196. package/src/router/router-registry.ts +24 -0
  197. package/src/router/segment-resolution/fresh.ts +748 -0
  198. package/src/router/segment-resolution/helpers.ts +268 -0
  199. package/src/router/segment-resolution/loader-cache.ts +199 -0
  200. package/src/router/segment-resolution/revalidation.ts +1379 -0
  201. package/src/router/segment-resolution/static-store.ts +67 -0
  202. package/src/router/segment-resolution.ts +21 -0
  203. package/src/router/segment-wrappers.ts +291 -0
  204. package/src/router/telemetry-otel.ts +299 -0
  205. package/src/router/telemetry.ts +300 -0
  206. package/src/router/timeout.ts +148 -0
  207. package/src/router/trie-matching.ts +239 -0
  208. package/src/router/types.ts +78 -3
  209. package/src/router.ts +740 -4252
  210. package/src/rsc/handler-context.ts +45 -0
  211. package/src/rsc/handler.ts +907 -797
  212. package/src/rsc/helpers.ts +140 -6
  213. package/src/rsc/index.ts +0 -20
  214. package/src/rsc/loader-fetch.ts +229 -0
  215. package/src/rsc/manifest-init.ts +90 -0
  216. package/src/rsc/nonce.ts +14 -0
  217. package/src/rsc/origin-guard.ts +141 -0
  218. package/src/rsc/progressive-enhancement.ts +391 -0
  219. package/src/rsc/response-error.ts +37 -0
  220. package/src/rsc/response-route-handler.ts +347 -0
  221. package/src/rsc/rsc-rendering.ts +246 -0
  222. package/src/rsc/runtime-warnings.ts +42 -0
  223. package/src/rsc/server-action.ts +356 -0
  224. package/src/rsc/ssr-setup.ts +128 -0
  225. package/src/rsc/types.ts +46 -11
  226. package/src/search-params.ts +230 -0
  227. package/src/segment-content-promise.ts +67 -0
  228. package/src/segment-loader-promise.ts +122 -0
  229. package/src/segment-system.tsx +134 -36
  230. package/src/server/context.ts +341 -61
  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 +113 -15
  234. package/src/server/loader-registry.ts +24 -64
  235. package/src/server/request-context.ts +607 -81
  236. package/src/server.ts +35 -130
  237. package/src/ssr/index.tsx +103 -30
  238. package/src/static-handler.ts +126 -0
  239. package/src/theme/ThemeProvider.tsx +21 -15
  240. package/src/theme/ThemeScript.tsx +5 -5
  241. package/src/theme/constants.ts +5 -2
  242. package/src/theme/index.ts +4 -14
  243. package/src/theme/theme-context.ts +4 -30
  244. package/src/theme/theme-script.ts +21 -18
  245. package/src/types/boundaries.ts +158 -0
  246. package/src/types/cache-types.ts +198 -0
  247. package/src/types/error-types.ts +192 -0
  248. package/src/types/global-namespace.ts +100 -0
  249. package/src/types/handler-context.ts +791 -0
  250. package/src/types/index.ts +88 -0
  251. package/src/types/loader-types.ts +210 -0
  252. package/src/types/route-config.ts +170 -0
  253. package/src/types/route-entry.ts +120 -0
  254. package/src/types/segments.ts +150 -0
  255. package/src/types.ts +1 -1623
  256. package/src/urls/include-helper.ts +207 -0
  257. package/src/urls/index.ts +53 -0
  258. package/src/urls/path-helper-types.ts +372 -0
  259. package/src/urls/path-helper.ts +364 -0
  260. package/src/urls/pattern-types.ts +107 -0
  261. package/src/urls/response-types.ts +116 -0
  262. package/src/urls/type-extraction.ts +372 -0
  263. package/src/urls/urls-function.ts +98 -0
  264. package/src/urls.ts +1 -802
  265. package/src/use-loader.tsx +161 -81
  266. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  267. package/src/vite/discovery/discover-routers.ts +348 -0
  268. package/src/vite/discovery/prerender-collection.ts +439 -0
  269. package/src/vite/discovery/route-types-writer.ts +258 -0
  270. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  271. package/src/vite/discovery/state.ts +117 -0
  272. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  273. package/src/vite/index.ts +15 -1133
  274. package/src/vite/plugin-types.ts +103 -0
  275. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  276. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  277. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  278. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  279. package/src/vite/plugins/expose-id-utils.ts +299 -0
  280. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  281. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  282. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  283. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  284. package/src/vite/plugins/expose-ids/types.ts +45 -0
  285. package/src/vite/plugins/expose-internal-ids.ts +786 -0
  286. package/src/vite/plugins/performance-tracks.ts +88 -0
  287. package/src/vite/plugins/refresh-cmd.ts +127 -0
  288. package/src/vite/plugins/use-cache-transform.ts +323 -0
  289. package/src/vite/plugins/version-injector.ts +83 -0
  290. package/src/vite/plugins/version-plugin.ts +266 -0
  291. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  292. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  293. package/src/vite/rango.ts +462 -0
  294. package/src/vite/router-discovery.ts +918 -0
  295. package/src/vite/utils/ast-handler-extract.ts +517 -0
  296. package/src/vite/utils/banner.ts +36 -0
  297. package/src/vite/utils/bundle-analysis.ts +137 -0
  298. package/src/vite/utils/manifest-utils.ts +70 -0
  299. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  300. package/src/vite/utils/prerender-utils.ts +221 -0
  301. package/src/vite/utils/shared-utils.ts +170 -0
  302. package/CLAUDE.md +0 -43
  303. package/src/browser/lru-cache.ts +0 -69
  304. package/src/browser/request-controller.ts +0 -164
  305. package/src/cache/memory-store.ts +0 -253
  306. package/src/href-context.ts +0 -33
  307. package/src/href.ts +0 -255
  308. package/src/server/route-manifest-cache.ts +0 -173
  309. package/src/vite/expose-handle-id.ts +0 -209
  310. package/src/vite/expose-loader-id.ts +0 -426
  311. package/src/vite/expose-location-state-id.ts +0 -177
  312. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -0,0 +1,207 @@
1
+ import type { AllUseItems, IncludeItem } from "../route-types.js";
2
+ import {
3
+ getContext,
4
+ runWithPrefixes,
5
+ getUrlPrefix,
6
+ getNamePrefix,
7
+ } from "../server/context";
8
+ import {
9
+ INTERNAL_INCLUDE_SCOPE_PREFIX,
10
+ validateUserRouteName,
11
+ } from "../route-name.js";
12
+ import type { UrlPatterns, IncludeOptions } from "./pattern-types.js";
13
+ import type { IncludeFn } from "./path-helper-types.js";
14
+
15
+ function hasExplicitNameOption(options: IncludeOptions | undefined): boolean {
16
+ return !!options && Object.prototype.hasOwnProperty.call(options, "name");
17
+ }
18
+
19
+ function allocateInternalIncludeScopeId(
20
+ counters: Record<string, number>,
21
+ ): string {
22
+ const key = "__include_scope__";
23
+ const index = counters[key] ?? 0;
24
+ counters[key] = index + 1;
25
+ return `${INTERNAL_INCLUDE_SCOPE_PREFIX}${index}`;
26
+ }
27
+
28
+ /**
29
+ * Process an IncludeItem by executing its nested patterns with prefixes
30
+ * This expands the include into actual route registrations
31
+ */
32
+ function processIncludeItem(item: IncludeItem): AllUseItems[] {
33
+ const { prefix, patterns } = item;
34
+ const namePrefix =
35
+ (item as IncludeItem & { _lazyContext?: { namePrefix?: string } })
36
+ ._lazyContext?.namePrefix ?? item.options?.name;
37
+
38
+ // Execute the nested patterns' handler with URL and name prefixes
39
+ // The urlPrefix being set tells nested urls() to skip RootLayout wrapping
40
+ return runWithPrefixes(prefix, namePrefix, () => {
41
+ // Call the nested patterns' handler - this registers routes with prefixed patterns/names
42
+ return (patterns as UrlPatterns).handler();
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Recursively process items, expanding any IncludeItems
48
+ * Returns items with IncludeItems expanded into actual route items
49
+ *
50
+ * Lazy includes are kept as-is (not expanded) for the router to handle later.
51
+ */
52
+ export function processItems(items: readonly AllUseItems[]): AllUseItems[] {
53
+ const result: AllUseItems[] = [];
54
+
55
+ for (const item of items) {
56
+ if (!item) continue;
57
+
58
+ if (item.type === "include") {
59
+ const includeItem = item as IncludeItem & {
60
+ _expanded?: AllUseItems[];
61
+ lazy?: boolean;
62
+ };
63
+
64
+ // Lazy includes are NOT expanded here - kept for router to handle
65
+ if (includeItem.lazy) {
66
+ result.push(item);
67
+ continue;
68
+ }
69
+
70
+ // Eager includes are already expanded during include() call
71
+ if (includeItem._expanded) {
72
+ // Items were expanded immediately - just process them recursively
73
+ result.push(...processItems(includeItem._expanded));
74
+ } else {
75
+ // Fallback for legacy include items without _expanded
76
+ const expanded = processIncludeItem(item as IncludeItem);
77
+ result.push(...processItems(expanded));
78
+ }
79
+ } else if (item.type === "layout" && (item as any).uses) {
80
+ // Process nested items in layout
81
+ const layoutItem = item as any;
82
+ layoutItem.uses = processItems(layoutItem.uses);
83
+ result.push(layoutItem);
84
+ } else {
85
+ result.push(item);
86
+ }
87
+ }
88
+
89
+ return result;
90
+ }
91
+
92
+ /**
93
+ * Create include() helper for composing URL patterns
94
+ *
95
+ * By default, include() IMMEDIATELY expands the nested patterns. This ensures
96
+ * that routes from included patterns inherit the correct parent context
97
+ * (the layout they're included in).
98
+ *
99
+ * With `lazy: true`, patterns are NOT expanded at definition time. Instead,
100
+ * they're evaluated on first request that matches the prefix. This improves
101
+ * cold start time for apps with many routes.
102
+ */
103
+ export function createIncludeHelper<TEnv>(): IncludeFn<TEnv> {
104
+ return (
105
+ prefix: string,
106
+ patterns: UrlPatterns<TEnv>,
107
+ options?: IncludeOptions,
108
+ ): IncludeItem => {
109
+ const store = getContext();
110
+ const ctx = store.getStore();
111
+ if (!ctx) throw new Error("include() must be called inside urls()");
112
+
113
+ const explicitName = options?.name;
114
+ const hasExplicitName = hasExplicitNameOption(options);
115
+ if (hasExplicitName && explicitName) {
116
+ validateUserRouteName(explicitName);
117
+ }
118
+ const name = `$include_${prefix.replace(/[/:*?]/g, "_")}`;
119
+
120
+ // Capture context for deferred evaluation
121
+ const capturedUrlPrefix = getUrlPrefix();
122
+ const capturedNamePrefix = getNamePrefix();
123
+ const capturedParent = ctx.parent;
124
+ const fullPrefix = capturedUrlPrefix
125
+ ? capturedUrlPrefix.endsWith("/") && prefix.startsWith("/")
126
+ ? capturedUrlPrefix + prefix.slice(1)
127
+ : capturedUrlPrefix + prefix
128
+ : prefix;
129
+ const internalScope = !hasExplicitName
130
+ ? allocateInternalIncludeScopeId(ctx.counters)
131
+ : undefined;
132
+ const nextSegment = hasExplicitName ? explicitName : internalScope;
133
+ const fullNamePrefix =
134
+ nextSegment !== undefined && nextSegment !== ""
135
+ ? capturedNamePrefix
136
+ ? `${capturedNamePrefix}.${nextSegment}`
137
+ : nextSegment
138
+ : capturedNamePrefix;
139
+
140
+ // Track this include for build-time manifest generation
141
+ if (ctx.trackedIncludes) {
142
+ ctx.trackedIncludes.push({
143
+ prefix,
144
+ fullPrefix,
145
+ namePrefix: fullNamePrefix,
146
+ patterns,
147
+ lazy: true,
148
+ });
149
+ }
150
+
151
+ // Allocate an include-scope token for this include() call. The token is
152
+ // appended to the parent's shortCode prefix whenever the include's
153
+ // direct-descendant shortCodes are generated (see getShortCode in
154
+ // context.ts), partitioning the parent's counter namespace so routes
155
+ // inside an include cannot collide with siblings declared outside it.
156
+ //
157
+ // Scopes compose: a nested include inside an outer include with scope
158
+ // "I0" allocates against the `${parent.shortCode}I0_include` counter
159
+ // and produces scope "I0I0", "I0I1", etc.
160
+ const parentScope = ctx.includeScope ?? "";
161
+ let includeScope = parentScope;
162
+ if (capturedParent?.shortCode) {
163
+ const includeCounterKey = `${capturedParent.shortCode}${parentScope}_include`;
164
+ ctx.counters[includeCounterKey] ??= 0;
165
+ const includeIdx = ctx.counters[includeCounterKey];
166
+ ctx.counters[includeCounterKey] = includeIdx + 1;
167
+ includeScope = `${parentScope}I${includeIdx}`;
168
+ }
169
+
170
+ // Snapshot parent's counters AFTER allocating the include scope so lazy
171
+ // manifest generation starts with the same counter state this include
172
+ // observed — its descendants still get fresh per-scope counters because
173
+ // they key off `${parent.shortCode}${includeScope}_*` (not shared with
174
+ // siblings outside the include).
175
+ const capturedCounters = { ...ctx.counters };
176
+
177
+ // Compute rootScoped at capture time, mirroring the logic in runWithPrefixes.
178
+ // This ensures lazy evaluation restores the correct scope state.
179
+ const parentRootScoped = ctx.rootScoped;
180
+ const capturedRootScoped =
181
+ nextSegment === ""
182
+ ? (parentRootScoped ?? true)
183
+ : nextSegment !== undefined
184
+ ? (parentRootScoped ?? false)
185
+ : parentRootScoped;
186
+
187
+ // All includes are lazy - patterns are evaluated on first matching request
188
+ // This improves cold start time significantly for large route sets
189
+ return {
190
+ type: "include",
191
+ name,
192
+ prefix,
193
+ patterns,
194
+ options,
195
+ lazy: true,
196
+ _lazyContext: {
197
+ urlPrefix: capturedUrlPrefix,
198
+ namePrefix: fullNamePrefix,
199
+ parent: capturedParent,
200
+ counters: capturedCounters,
201
+ cacheProfiles: ctx.cacheProfiles,
202
+ rootScoped: capturedRootScoped,
203
+ includeScope,
204
+ },
205
+ } as IncludeItem;
206
+ };
207
+ }
@@ -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,372 @@
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
+ * A slot value can be a Handler / ReactNode / StaticHandlerDefinition
239
+ * (legacy form, broadcast use applies to every slot) or a slot descriptor
240
+ * `{ handler, use? }` whose `use` is scoped to that slot only. Per-slot
241
+ * merge order is `handler.use` → shared `use` → slot-local `use`, with
242
+ * narrowest scope winning for last-write-wins items like `loading()`.
243
+ */
244
+ parallel: <
245
+ TSlots extends Record<
246
+ `@${string}`,
247
+ | Handler<any, any, TEnv>
248
+ | ReactNode
249
+ | StaticHandlerDefinition
250
+ | {
251
+ handler:
252
+ | Handler<any, any, TEnv>
253
+ | ReactNode
254
+ | StaticHandlerDefinition;
255
+ use?: () => ParallelUseItem[];
256
+ }
257
+ >,
258
+ >(
259
+ slots: TSlots,
260
+ use?: () => ParallelUseItem[],
261
+ ) => ParallelItem;
262
+
263
+ /**
264
+ * Define an intercepting route for soft navigation
265
+ * Note: routeName must match a named path() in this urlpatterns
266
+ */
267
+ intercept: keyof RSCRouter.GeneratedRouteMap extends never
268
+ ? (
269
+ slotName: `@${string}`,
270
+ routeName: string,
271
+ handler: ReactNode | Handler<any, any, TEnv>,
272
+ use?: () => InterceptUseItem[],
273
+ ) => InterceptItem
274
+ : (
275
+ slotName: `@${string}`,
276
+ routeName: (keyof RSCRouter.GeneratedRouteMap & string) | `.${string}`,
277
+ handler: ReactNode | Handler<any, any, TEnv>,
278
+ use?: () => InterceptUseItem[],
279
+ ) => InterceptItem;
280
+
281
+ /**
282
+ * Attach middleware to the current route/layout, or wrap child segments
283
+ */
284
+ middleware: {
285
+ (fn: MiddlewareFn<TEnv>): MiddlewareItem;
286
+ (
287
+ fn: MiddlewareFn<TEnv>,
288
+ children: () => UseItems<LayoutUseItem>,
289
+ ): MiddlewareItem;
290
+ (fns: MiddlewareFn<TEnv>[]): MiddlewareItem;
291
+ (
292
+ fns: MiddlewareFn<TEnv>[],
293
+ children: () => UseItems<LayoutUseItem>,
294
+ ): MiddlewareItem;
295
+ };
296
+
297
+ /**
298
+ * Control when a segment should revalidate during navigation
299
+ */
300
+ revalidate: (fn: ShouldRevalidateFn<any, TEnv>) => RevalidateItem;
301
+
302
+ /**
303
+ * Attach a data loader to the current route/layout
304
+ */
305
+ loader: <TData>(
306
+ loaderDef: LoaderDefinition<TData>,
307
+ use?: () => LoaderUseItem[],
308
+ ) => LoaderItem;
309
+
310
+ /**
311
+ * Attach a loading component to the current route/layout
312
+ */
313
+ loading: (
314
+ component: ReactNode | (() => ReactNode),
315
+ options?: { ssr?: boolean },
316
+ ) => LoadingItem;
317
+
318
+ /**
319
+ * Attach an error boundary to catch errors in this segment
320
+ */
321
+ errorBoundary: (
322
+ fallback: ReactNode | ErrorBoundaryHandler,
323
+ ) => ErrorBoundaryItem;
324
+
325
+ /**
326
+ * Attach a not-found boundary to handle notFound() calls
327
+ */
328
+ notFoundBoundary: (
329
+ fallback: ReactNode | NotFoundBoundaryHandler,
330
+ ) => NotFoundBoundaryItem;
331
+
332
+ /**
333
+ * Define a condition for when an intercept should activate
334
+ */
335
+ when: (fn: InterceptWhenFn) => WhenItem;
336
+
337
+ /**
338
+ * Define cache configuration for segments
339
+ */
340
+ cache: {
341
+ (): TypedCacheItem<{}, {}>;
342
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
343
+ children: () => TChildren,
344
+ ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
345
+ (options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
346
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
347
+ options: PartialCacheOptions | false,
348
+ use: () => TChildren,
349
+ ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
350
+ };
351
+
352
+ /**
353
+ * Attach a ViewTransition boundary to the current segment or a group of routes
354
+ */
355
+ transition: {
356
+ (): TransitionItem;
357
+ (config: TransitionConfig): TransitionItem;
358
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
359
+ children: () => TChildren,
360
+ ): TypedTransitionItem<
361
+ ExtractRoutes<TChildren>,
362
+ ExtractResponses<TChildren>
363
+ >;
364
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
365
+ config: TransitionConfig,
366
+ children: () => TChildren,
367
+ ): TypedTransitionItem<
368
+ ExtractRoutes<TChildren>,
369
+ ExtractResponses<TChildren>
370
+ >;
371
+ };
372
+ };