@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,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,339 @@
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 { PrerenderHandlerDefinition } from "../prerender.js";
41
+ import type { StaticHandlerDefinition } from "../static-handler.js";
42
+ import type { InterceptWhenFn } from "../server/context";
43
+ import type {
44
+ ResponseHandler,
45
+ ResponseHandlerContext,
46
+ TextResponseHandler,
47
+ } from "./response-types.js";
48
+ import type {
49
+ UnnamedRoute,
50
+ LocalOnlyInclude,
51
+ PathOptions,
52
+ UrlPatterns,
53
+ IncludeOptions,
54
+ } from "./pattern-types.js";
55
+ import type { ExtractRoutes, ExtractResponses } from "./type-extraction.js";
56
+
57
+ /**
58
+ * Base path function signature for defining routes with URL patterns.
59
+ */
60
+ export type PathFn<TEnv> = <
61
+ const TPattern extends string,
62
+ const TName extends string = UnnamedRoute,
63
+ const TSearch extends SearchSchema = {},
64
+ TParams extends Record<string, any> = ExtractParams<TPattern>,
65
+ >(
66
+ pattern: TPattern,
67
+ handler:
68
+ | ReactNode
69
+ | ((
70
+ ctx: HandlerContext<TParams, TEnv, TSearch>,
71
+ ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>)
72
+ | PrerenderHandlerDefinition<TParams>
73
+ | StaticHandlerDefinition<TParams>,
74
+ optionsOrUse?: PathOptions<TName, TSearch> | (() => UseItems<RouteUseItem>),
75
+ use?: () => UseItems<RouteUseItem>,
76
+ // Generic handler bypass: when handler uses index-signature params
77
+ // (e.g. Handler<Record<string, any>>), skip the biconditional.
78
+ // `string extends keyof TParams` is true for index signatures,
79
+ // false for concrete params ({id: string}) and empty ({}).
80
+ //
81
+ // Subset check: pattern params must be assignable to handler params,
82
+ // but handler can have MORE params (e.g. from parent include() prefix).
83
+ // This allows Prerender<"locale.detail"> with {locale, slug} to mount
84
+ // on path("/blog/:slug") where the pattern only declares {slug}.
85
+ ) => string extends keyof TParams
86
+ ? TypedRouteItem<TName, TPattern, unknown, TSearch>
87
+ : TParams extends ExtractParams<TPattern>
88
+ ? TypedRouteItem<TName, TPattern, unknown, TSearch>
89
+ : { __error: `Handler params do not match pattern "${TPattern}"` };
90
+
91
+ /**
92
+ * Path function for response routes that must return Response (image, stream, any).
93
+ * Handler must return Response, not ReactNode. Uses lighter ResponseHandlerContext.
94
+ * Use items restricted to middleware() and cache() only.
95
+ */
96
+ export type ResponsePathFn<TEnv> = <
97
+ const TPattern extends string,
98
+ const TName extends string = UnnamedRoute,
99
+ const TSearch extends SearchSchema = {},
100
+ >(
101
+ pattern: TPattern,
102
+ handler: ResponseHandler<ExtractParams<TPattern>, TEnv>,
103
+ optionsOrUse?:
104
+ | PathOptions<TName, TSearch>
105
+ | (() => UseItems<ResponseRouteUseItem>),
106
+ use?: () => UseItems<ResponseRouteUseItem>,
107
+ ) => TypedRouteItem<TName, TPattern, unknown, TSearch>;
108
+
109
+ /**
110
+ * Path function for JSON response routes (path.json()).
111
+ * Handler can return plain JSON-serializable values or Response.
112
+ * TData is inferred from the handler's return type (excluding Response/Promise wrappers).
113
+ */
114
+ export type JsonResponsePathFn<TEnv> = <
115
+ const TPattern extends string,
116
+ const TName extends string = UnnamedRoute,
117
+ const TSearch extends SearchSchema = {},
118
+ TData = unknown,
119
+ >(
120
+ pattern: TPattern,
121
+ handler: (
122
+ ctx: ResponseHandlerContext<ExtractParams<TPattern>, TEnv>,
123
+ ) => TData | Response | Promise<TData | Response>,
124
+ optionsOrUse?:
125
+ | PathOptions<TName, TSearch>
126
+ | (() => UseItems<ResponseRouteUseItem>),
127
+ use?: () => UseItems<ResponseRouteUseItem>,
128
+ ) => TypedRouteItem<TName, TPattern, TData, TSearch>;
129
+
130
+ /**
131
+ * Path function for text-based response routes (path.text(), path.html(), path.xml()).
132
+ * Handler can return a string or Response. TData is always `string`.
133
+ */
134
+ export type TextResponsePathFn<TEnv> = <
135
+ const TPattern extends string,
136
+ const TName extends string = UnnamedRoute,
137
+ const TSearch extends SearchSchema = {},
138
+ >(
139
+ pattern: TPattern,
140
+ handler: TextResponseHandler<ExtractParams<TPattern>, TEnv>,
141
+ optionsOrUse?:
142
+ | PathOptions<TName, TSearch>
143
+ | (() => UseItems<ResponseRouteUseItem>),
144
+ use?: () => UseItems<ResponseRouteUseItem>,
145
+ ) => TypedRouteItem<TName, TPattern, string, TSearch>;
146
+
147
+ /**
148
+ * Base include function signature.
149
+ */
150
+ export type IncludeFn<TEnv> = <
151
+ TRoutes extends Record<string, any>,
152
+ const TUrlPrefix extends string,
153
+ const TNamePrefix extends string = LocalOnlyInclude,
154
+ TResponses extends Record<string, unknown> = Record<string, unknown>,
155
+ >(
156
+ prefix: TUrlPrefix,
157
+ patterns: UrlPatterns<TEnv, TRoutes, TResponses>,
158
+ options?: IncludeOptions<TNamePrefix>,
159
+ ) => TypedIncludeItem<TRoutes, TNamePrefix, TUrlPrefix, TResponses>;
160
+
161
+ export type PathHelpers<TEnv> = {
162
+ /**
163
+ * Define a route with URL pattern at definition site
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Pattern and component only
168
+ * path("/about", AboutPage)
169
+ *
170
+ * // With options
171
+ * path("/:slug", PostPage, { name: "post" })
172
+ *
173
+ * // With children (loaders, middleware, etc.)
174
+ * path("/:slug", PostPage, { name: "post" }, () => [
175
+ * loader(PostLoader),
176
+ * ])
177
+ * ```
178
+ */
179
+ path: PathFn<TEnv> & {
180
+ json: JsonResponsePathFn<TEnv>;
181
+ text: TextResponsePathFn<TEnv>;
182
+ html: TextResponsePathFn<TEnv>;
183
+ xml: TextResponsePathFn<TEnv>;
184
+ md: TextResponsePathFn<TEnv>;
185
+ image: ResponsePathFn<TEnv>;
186
+ stream: ResponsePathFn<TEnv>;
187
+ any: ResponsePathFn<TEnv>;
188
+ };
189
+
190
+ /**
191
+ * Define a layout that wraps child routes
192
+ */
193
+ layout: {
194
+ (
195
+ component: ReactNode | Handler<any, any, TEnv> | StaticHandlerDefinition,
196
+ ): TypedLayoutItem<{}, {}>;
197
+ <
198
+ const TChildren extends readonly (
199
+ | LayoutUseItem
200
+ | readonly LayoutUseItem[]
201
+ )[],
202
+ >(
203
+ component: ReactNode | Handler<any, any, TEnv> | StaticHandlerDefinition,
204
+ use: () => TChildren,
205
+ ): TypedLayoutItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
206
+ };
207
+
208
+ /**
209
+ * Include nested URL patterns under a URL prefix.
210
+ *
211
+ * The `name` option controls how child route names appear in the
212
+ * global route map and generated types:
213
+ *
214
+ * ```typescript
215
+ * // Named — children become "blog.index", "blog.post", etc.
216
+ * // Visible in generated types and globally reversible.
217
+ * include("/blog", blogPatterns, { name: "blog" })
218
+ *
219
+ * // Flattened — children merge into the parent namespace as-is.
220
+ * // Equivalent to defining those routes inline at the include site.
221
+ * include("/blog", blogPatterns, { name: "" })
222
+ *
223
+ * // Local-only (default) — children are scoped privately.
224
+ * // Hidden from generated types and global reverse resolution.
225
+ * // Only dot-local reverse (reverse(".child")) works inside.
226
+ * include("/blog", blogPatterns)
227
+ * ```
228
+ */
229
+ include: IncludeFn<TEnv>;
230
+
231
+ /**
232
+ * Define parallel routes that render simultaneously in named slots
233
+ */
234
+ parallel: <
235
+ TSlots extends Record<
236
+ `@${string}`,
237
+ Handler<any, any, TEnv> | ReactNode | StaticHandlerDefinition
238
+ >,
239
+ >(
240
+ slots: TSlots,
241
+ use?: () => ParallelUseItem[],
242
+ ) => ParallelItem;
243
+
244
+ /**
245
+ * Define an intercepting route for soft navigation
246
+ * Note: routeName must match a named path() in this urlpatterns
247
+ */
248
+ intercept: keyof RSCRouter.GeneratedRouteMap extends never
249
+ ? (
250
+ slotName: `@${string}`,
251
+ routeName: string,
252
+ handler: ReactNode | Handler<any, any, TEnv>,
253
+ use?: () => InterceptUseItem[],
254
+ ) => InterceptItem
255
+ : (
256
+ slotName: `@${string}`,
257
+ routeName: (keyof RSCRouter.GeneratedRouteMap & string) | `.${string}`,
258
+ handler: ReactNode | Handler<any, any, TEnv>,
259
+ use?: () => InterceptUseItem[],
260
+ ) => InterceptItem;
261
+
262
+ /**
263
+ * Attach middleware to the current route/layout
264
+ */
265
+ middleware: (...fns: MiddlewareFn<TEnv>[]) => MiddlewareItem;
266
+
267
+ /**
268
+ * Control when a segment should revalidate during navigation
269
+ */
270
+ revalidate: (fn: ShouldRevalidateFn<any, TEnv>) => RevalidateItem;
271
+
272
+ /**
273
+ * Attach a data loader to the current route/layout
274
+ */
275
+ loader: <TData>(
276
+ loaderDef: LoaderDefinition<TData>,
277
+ use?: () => LoaderUseItem[],
278
+ ) => LoaderItem;
279
+
280
+ /**
281
+ * Attach a loading component to the current route/layout
282
+ */
283
+ loading: (component: ReactNode, options?: { ssr?: boolean }) => LoadingItem;
284
+
285
+ /**
286
+ * Attach an error boundary to catch errors in this segment
287
+ */
288
+ errorBoundary: (
289
+ fallback: ReactNode | ErrorBoundaryHandler,
290
+ ) => ErrorBoundaryItem;
291
+
292
+ /**
293
+ * Attach a not-found boundary to handle notFound() calls
294
+ */
295
+ notFoundBoundary: (
296
+ fallback: ReactNode | NotFoundBoundaryHandler,
297
+ ) => NotFoundBoundaryItem;
298
+
299
+ /**
300
+ * Define a condition for when an intercept should activate
301
+ */
302
+ when: (fn: InterceptWhenFn) => WhenItem;
303
+
304
+ /**
305
+ * Define cache configuration for segments
306
+ */
307
+ cache: {
308
+ (): TypedCacheItem<{}, {}>;
309
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
310
+ children: () => TChildren,
311
+ ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
312
+ (options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
313
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
314
+ options: PartialCacheOptions | false,
315
+ use: () => TChildren,
316
+ ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
317
+ };
318
+
319
+ /**
320
+ * Attach a ViewTransition boundary to the current segment or a group of routes
321
+ */
322
+ transition: {
323
+ (): TransitionItem;
324
+ (config: TransitionConfig): TransitionItem;
325
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
326
+ children: () => TChildren,
327
+ ): TypedTransitionItem<
328
+ ExtractRoutes<TChildren>,
329
+ ExtractResponses<TChildren>
330
+ >;
331
+ <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
332
+ config: TransitionConfig,
333
+ children: () => TChildren,
334
+ ): TypedTransitionItem<
335
+ ExtractRoutes<TChildren>,
336
+ ExtractResponses<TChildren>
337
+ >;
338
+ };
339
+ };