vinext 0.0.52 → 0.0.54

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 (330) hide show
  1. package/README.md +1 -1
  2. package/dist/build/clean-output.d.ts +14 -0
  3. package/dist/build/clean-output.js +36 -0
  4. package/dist/build/clean-output.js.map +1 -0
  5. package/dist/build/inline-css.d.ts +7 -0
  6. package/dist/build/inline-css.js +50 -0
  7. package/dist/build/inline-css.js.map +1 -0
  8. package/dist/build/prerender.d.ts +6 -2
  9. package/dist/build/prerender.js +51 -12
  10. package/dist/build/prerender.js.map +1 -1
  11. package/dist/build/run-prerender.js +10 -1
  12. package/dist/build/run-prerender.js.map +1 -1
  13. package/dist/build/static-export.d.ts +5 -0
  14. package/dist/build/static-export.js +8 -3
  15. package/dist/build/static-export.js.map +1 -1
  16. package/dist/check.js +4 -0
  17. package/dist/check.js.map +1 -1
  18. package/dist/cli.js +19 -4
  19. package/dist/cli.js.map +1 -1
  20. package/dist/client/instrumentation-client-inject.d.ts +34 -0
  21. package/dist/client/instrumentation-client-inject.js +57 -0
  22. package/dist/client/instrumentation-client-inject.js.map +1 -0
  23. package/dist/client/navigation-runtime.d.ts +16 -2
  24. package/dist/client/navigation-runtime.js +16 -1
  25. package/dist/client/navigation-runtime.js.map +1 -1
  26. package/dist/client/vinext-next-data.d.ts +2 -1
  27. package/dist/client/vinext-next-data.js.map +1 -1
  28. package/dist/client/window-next.d.ts +17 -2
  29. package/dist/client/window-next.js.map +1 -1
  30. package/dist/cloudflare/tpr.js +1 -1
  31. package/dist/cloudflare/tpr.js.map +1 -1
  32. package/dist/config/config-matchers.js +2 -1
  33. package/dist/config/config-matchers.js.map +1 -1
  34. package/dist/config/next-config.d.ts +95 -4
  35. package/dist/config/next-config.js +173 -14
  36. package/dist/config/next-config.js.map +1 -1
  37. package/dist/deploy.js +42 -7
  38. package/dist/deploy.js.map +1 -1
  39. package/dist/entries/app-browser-entry.d.ts +11 -1
  40. package/dist/entries/app-browser-entry.js +16 -6
  41. package/dist/entries/app-browser-entry.js.map +1 -1
  42. package/dist/entries/app-rsc-entry.d.ts +12 -3
  43. package/dist/entries/app-rsc-entry.js +41 -8
  44. package/dist/entries/app-rsc-entry.js.map +1 -1
  45. package/dist/entries/app-rsc-manifest.d.ts +21 -1
  46. package/dist/entries/app-rsc-manifest.js +6 -4
  47. package/dist/entries/app-rsc-manifest.js.map +1 -1
  48. package/dist/entries/pages-client-entry.d.ts +4 -1
  49. package/dist/entries/pages-client-entry.js +40 -3
  50. package/dist/entries/pages-client-entry.js.map +1 -1
  51. package/dist/entries/pages-server-entry.js +292 -34
  52. package/dist/entries/pages-server-entry.js.map +1 -1
  53. package/dist/entries/runtime-entry-module.d.ts +1 -10
  54. package/dist/entries/runtime-entry-module.js +2 -12
  55. package/dist/entries/runtime-entry-module.js.map +1 -1
  56. package/dist/index.js +91 -10
  57. package/dist/index.js.map +1 -1
  58. package/dist/plugins/fonts.js +25 -2
  59. package/dist/plugins/fonts.js.map +1 -1
  60. package/dist/plugins/remove-console.d.ts +16 -0
  61. package/dist/plugins/remove-console.js +176 -0
  62. package/dist/plugins/remove-console.js.map +1 -0
  63. package/dist/routing/app-route-graph.d.ts +24 -1
  64. package/dist/routing/app-route-graph.js +52 -4
  65. package/dist/routing/app-route-graph.js.map +1 -1
  66. package/dist/routing/app-router.d.ts +2 -2
  67. package/dist/routing/app-router.js +2 -2
  68. package/dist/routing/app-router.js.map +1 -1
  69. package/dist/routing/file-matcher.d.ts +21 -1
  70. package/dist/routing/file-matcher.js +39 -1
  71. package/dist/routing/file-matcher.js.map +1 -1
  72. package/dist/routing/pages-router.d.ts +1 -1
  73. package/dist/routing/pages-router.js +10 -3
  74. package/dist/routing/pages-router.js.map +1 -1
  75. package/dist/routing/route-trie.js +13 -18
  76. package/dist/routing/route-trie.js.map +1 -1
  77. package/dist/routing/utils.d.ts +11 -1
  78. package/dist/routing/utils.js +15 -1
  79. package/dist/routing/utils.js.map +1 -1
  80. package/dist/server/api-handler.js +19 -10
  81. package/dist/server/api-handler.js.map +1 -1
  82. package/dist/server/app-browser-action-result.d.ts +16 -1
  83. package/dist/server/app-browser-action-result.js +15 -1
  84. package/dist/server/app-browser-action-result.js.map +1 -1
  85. package/dist/server/app-browser-entry.js +47 -28
  86. package/dist/server/app-browser-entry.js.map +1 -1
  87. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  88. package/dist/server/app-browser-navigation-controller.js +4 -0
  89. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  90. package/dist/server/app-elements-wire.d.ts +13 -4
  91. package/dist/server/app-elements-wire.js +10 -1
  92. package/dist/server/app-elements-wire.js.map +1 -1
  93. package/dist/server/app-elements.d.ts +2 -2
  94. package/dist/server/app-elements.js +2 -2
  95. package/dist/server/app-elements.js.map +1 -1
  96. package/dist/server/app-fallback-renderer.d.ts +27 -8
  97. package/dist/server/app-fallback-renderer.js +19 -8
  98. package/dist/server/app-fallback-renderer.js.map +1 -1
  99. package/dist/server/app-history-state.js +6 -2
  100. package/dist/server/app-history-state.js.map +1 -1
  101. package/dist/server/app-inline-css-client.d.ts +7 -0
  102. package/dist/server/app-inline-css-client.js +37 -0
  103. package/dist/server/app-inline-css-client.js.map +1 -0
  104. package/dist/server/app-interception-context-header.d.ts +33 -0
  105. package/dist/server/app-interception-context-header.js +44 -0
  106. package/dist/server/app-interception-context-header.js.map +1 -0
  107. package/dist/server/app-mounted-slots-header.d.ts +19 -0
  108. package/dist/server/app-mounted-slots-header.js +40 -1
  109. package/dist/server/app-mounted-slots-header.js.map +1 -1
  110. package/dist/server/app-optimistic-routing.js +26 -18
  111. package/dist/server/app-optimistic-routing.js.map +1 -1
  112. package/dist/server/app-page-boundary-render.d.ts +1 -0
  113. package/dist/server/app-page-boundary-render.js +2 -0
  114. package/dist/server/app-page-boundary-render.js.map +1 -1
  115. package/dist/server/app-page-boundary.d.ts +22 -1
  116. package/dist/server/app-page-boundary.js +30 -3
  117. package/dist/server/app-page-boundary.js.map +1 -1
  118. package/dist/server/app-page-cache.d.ts +9 -3
  119. package/dist/server/app-page-cache.js +14 -8
  120. package/dist/server/app-page-cache.js.map +1 -1
  121. package/dist/server/app-page-dispatch.d.ts +13 -1
  122. package/dist/server/app-page-dispatch.js +136 -82
  123. package/dist/server/app-page-dispatch.js.map +1 -1
  124. package/dist/server/app-page-element-builder.d.ts +2 -1
  125. package/dist/server/app-page-element-builder.js +17 -30
  126. package/dist/server/app-page-element-builder.js.map +1 -1
  127. package/dist/server/app-page-execution.d.ts +1 -0
  128. package/dist/server/app-page-execution.js +2 -0
  129. package/dist/server/app-page-execution.js.map +1 -1
  130. package/dist/server/app-page-head.d.ts +1 -0
  131. package/dist/server/app-page-head.js +8 -0
  132. package/dist/server/app-page-head.js.map +1 -1
  133. package/dist/server/app-page-render-identity.d.ts +22 -0
  134. package/dist/server/app-page-render-identity.js +42 -0
  135. package/dist/server/app-page-render-identity.js.map +1 -0
  136. package/dist/server/app-page-render-observation.js +1 -1
  137. package/dist/server/app-page-render.d.ts +9 -1
  138. package/dist/server/app-page-render.js +8 -2
  139. package/dist/server/app-page-render.js.map +1 -1
  140. package/dist/server/app-page-request.d.ts +6 -3
  141. package/dist/server/app-page-request.js +5 -2
  142. package/dist/server/app-page-request.js.map +1 -1
  143. package/dist/server/app-page-response.d.ts +11 -1
  144. package/dist/server/app-page-response.js +16 -4
  145. package/dist/server/app-page-response.js.map +1 -1
  146. package/dist/server/app-page-route-wiring.d.ts +16 -0
  147. package/dist/server/app-page-route-wiring.js +25 -10
  148. package/dist/server/app-page-route-wiring.js.map +1 -1
  149. package/dist/server/app-page-stream.d.ts +12 -0
  150. package/dist/server/app-page-stream.js +3 -0
  151. package/dist/server/app-page-stream.js.map +1 -1
  152. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  153. package/dist/server/app-route-handler-dispatch.js +3 -0
  154. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  155. package/dist/server/app-route-handler-execution.d.ts +1 -0
  156. package/dist/server/app-route-handler-execution.js +1 -0
  157. package/dist/server/app-route-handler-execution.js.map +1 -1
  158. package/dist/server/app-route-handler-response.js +38 -6
  159. package/dist/server/app-route-handler-response.js.map +1 -1
  160. package/dist/server/app-rsc-handler.d.ts +16 -3
  161. package/dist/server/app-rsc-handler.js +60 -11
  162. package/dist/server/app-rsc-handler.js.map +1 -1
  163. package/dist/server/app-rsc-request-normalization.d.ts +2 -1
  164. package/dist/server/app-rsc-request-normalization.js +6 -4
  165. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  166. package/dist/server/app-segment-config.d.ts +4 -1
  167. package/dist/server/app-segment-config.js +6 -1
  168. package/dist/server/app-segment-config.js.map +1 -1
  169. package/dist/server/app-server-action-execution.d.ts +22 -3
  170. package/dist/server/app-server-action-execution.js +46 -7
  171. package/dist/server/app-server-action-execution.js.map +1 -1
  172. package/dist/server/app-ssr-entry.d.ts +6 -0
  173. package/dist/server/app-ssr-entry.js +57 -6
  174. package/dist/server/app-ssr-entry.js.map +1 -1
  175. package/dist/server/app-ssr-error-meta.js +3 -3
  176. package/dist/server/app-ssr-error-meta.js.map +1 -1
  177. package/dist/server/app-ssr-stream.d.ts +25 -1
  178. package/dist/server/app-ssr-stream.js +237 -19
  179. package/dist/server/app-ssr-stream.js.map +1 -1
  180. package/dist/server/app-static-generation.d.ts +1 -0
  181. package/dist/server/app-static-generation.js +2 -1
  182. package/dist/server/app-static-generation.js.map +1 -1
  183. package/dist/server/client-trace-metadata.d.ts +31 -0
  184. package/dist/server/client-trace-metadata.js +83 -0
  185. package/dist/server/client-trace-metadata.js.map +1 -0
  186. package/dist/server/cookie-utils.d.ts +13 -0
  187. package/dist/server/cookie-utils.js +20 -0
  188. package/dist/server/cookie-utils.js.map +1 -0
  189. package/dist/server/default-not-found-module.d.ts +20 -0
  190. package/dist/server/default-not-found-module.js +20 -0
  191. package/dist/server/default-not-found-module.js.map +1 -0
  192. package/dist/server/dev-server.d.ts +8 -1
  193. package/dist/server/dev-server.js +56 -11
  194. package/dist/server/dev-server.js.map +1 -1
  195. package/dist/server/headers.d.ts +5 -1
  196. package/dist/server/headers.js +5 -1
  197. package/dist/server/headers.js.map +1 -1
  198. package/dist/server/html.d.ts +2 -1
  199. package/dist/server/html.js +6 -1
  200. package/dist/server/html.js.map +1 -1
  201. package/dist/server/image-optimization.d.ts +13 -4
  202. package/dist/server/image-optimization.js +15 -4
  203. package/dist/server/image-optimization.js.map +1 -1
  204. package/dist/server/isr-cache.d.ts +7 -5
  205. package/dist/server/isr-cache.js +17 -6
  206. package/dist/server/isr-cache.js.map +1 -1
  207. package/dist/server/middleware-runtime.js +1 -2
  208. package/dist/server/middleware-runtime.js.map +1 -1
  209. package/dist/server/middleware.js +1 -1
  210. package/dist/server/middleware.js.map +1 -1
  211. package/dist/server/pages-api-route.d.ts +18 -0
  212. package/dist/server/pages-api-route.js +3 -1
  213. package/dist/server/pages-api-route.js.map +1 -1
  214. package/dist/server/pages-body-parser-config.d.ts +60 -0
  215. package/dist/server/pages-body-parser-config.js +79 -0
  216. package/dist/server/pages-body-parser-config.js.map +1 -0
  217. package/dist/server/pages-data-route.js +1 -0
  218. package/dist/server/pages-data-route.js.map +1 -1
  219. package/dist/server/pages-default-404.d.ts +31 -0
  220. package/dist/server/pages-default-404.js +40 -0
  221. package/dist/server/pages-default-404.js.map +1 -0
  222. package/dist/server/pages-document-initial-props.d.ts +7 -0
  223. package/dist/server/pages-document-initial-props.js +14 -0
  224. package/dist/server/pages-document-initial-props.js.map +1 -0
  225. package/dist/server/pages-node-compat.d.ts +10 -0
  226. package/dist/server/pages-node-compat.js +12 -1
  227. package/dist/server/pages-node-compat.js.map +1 -1
  228. package/dist/server/pages-page-data.d.ts +40 -0
  229. package/dist/server/pages-page-data.js +19 -14
  230. package/dist/server/pages-page-data.js.map +1 -1
  231. package/dist/server/pages-page-method.d.ts +48 -0
  232. package/dist/server/pages-page-method.js +19 -0
  233. package/dist/server/pages-page-method.js.map +1 -0
  234. package/dist/server/pages-page-response.d.ts +8 -0
  235. package/dist/server/pages-page-response.js +21 -11
  236. package/dist/server/pages-page-response.js.map +1 -1
  237. package/dist/server/pages-serializable-props.d.ts +25 -0
  238. package/dist/server/pages-serializable-props.js +69 -0
  239. package/dist/server/pages-serializable-props.js.map +1 -0
  240. package/dist/server/prerender-route-params.d.ts +14 -0
  241. package/dist/server/prerender-route-params.js +94 -0
  242. package/dist/server/prerender-route-params.js.map +1 -0
  243. package/dist/server/prod-server.d.ts +3 -23
  244. package/dist/server/prod-server.js +43 -57
  245. package/dist/server/prod-server.js.map +1 -1
  246. package/dist/server/proxy-trust.d.ts +41 -0
  247. package/dist/server/proxy-trust.js +70 -0
  248. package/dist/server/proxy-trust.js.map +1 -0
  249. package/dist/server/request-pipeline.d.ts +3 -3
  250. package/dist/server/request-pipeline.js +5 -4
  251. package/dist/server/request-pipeline.js.map +1 -1
  252. package/dist/server/seed-cache.js +12 -6
  253. package/dist/server/seed-cache.js.map +1 -1
  254. package/dist/server/server-action-not-found.js +3 -2
  255. package/dist/server/server-action-not-found.js.map +1 -1
  256. package/dist/server/static-file-cache.js +2 -1
  257. package/dist/server/static-file-cache.js.map +1 -1
  258. package/dist/server/streaming-metadata.d.ts +5 -0
  259. package/dist/server/streaming-metadata.js +10 -0
  260. package/dist/server/streaming-metadata.js.map +1 -0
  261. package/dist/shims/app-router-scroll-state.d.ts +14 -0
  262. package/dist/shims/app-router-scroll-state.js +51 -0
  263. package/dist/shims/app-router-scroll-state.js.map +1 -0
  264. package/dist/shims/app-router-scroll.d.ts +28 -0
  265. package/dist/shims/app-router-scroll.js +115 -0
  266. package/dist/shims/app-router-scroll.js.map +1 -0
  267. package/dist/shims/before-interactive-context.d.ts +30 -0
  268. package/dist/shims/before-interactive-context.js +10 -0
  269. package/dist/shims/before-interactive-context.js.map +1 -0
  270. package/dist/shims/cache-runtime.d.ts +1 -1
  271. package/dist/shims/cache-runtime.js +14 -1
  272. package/dist/shims/cache-runtime.js.map +1 -1
  273. package/dist/shims/cache.d.ts +6 -0
  274. package/dist/shims/cache.js +7 -0
  275. package/dist/shims/cache.js.map +1 -1
  276. package/dist/shims/default-not-found.d.ts +12 -0
  277. package/dist/shims/default-not-found.js +61 -0
  278. package/dist/shims/default-not-found.js.map +1 -0
  279. package/dist/shims/error.js +3 -0
  280. package/dist/shims/error.js.map +1 -1
  281. package/dist/shims/font-local.d.ts +5 -0
  282. package/dist/shims/font-local.js +6 -2
  283. package/dist/shims/font-local.js.map +1 -1
  284. package/dist/shims/head.js +4 -4
  285. package/dist/shims/head.js.map +1 -1
  286. package/dist/shims/headers.d.ts +13 -2
  287. package/dist/shims/headers.js +73 -22
  288. package/dist/shims/headers.js.map +1 -1
  289. package/dist/shims/image.d.ts +1 -1
  290. package/dist/shims/image.js +4 -4
  291. package/dist/shims/image.js.map +1 -1
  292. package/dist/shims/internal/app-route-detection.d.ts +37 -0
  293. package/dist/shims/internal/app-route-detection.js +69 -0
  294. package/dist/shims/internal/app-route-detection.js.map +1 -0
  295. package/dist/shims/internal/pages-data-target.d.ts +58 -0
  296. package/dist/shims/internal/pages-data-target.js +91 -0
  297. package/dist/shims/internal/pages-data-target.js.map +1 -0
  298. package/dist/shims/internal/pages-data-url.d.ts +42 -0
  299. package/dist/shims/internal/pages-data-url.js +73 -0
  300. package/dist/shims/internal/pages-data-url.js.map +1 -0
  301. package/dist/shims/link.d.ts +18 -2
  302. package/dist/shims/link.js +129 -15
  303. package/dist/shims/link.js.map +1 -1
  304. package/dist/shims/metadata.d.ts +9 -7
  305. package/dist/shims/metadata.js +70 -7
  306. package/dist/shims/metadata.js.map +1 -1
  307. package/dist/shims/navigation.d.ts +1 -2
  308. package/dist/shims/navigation.js +94 -20
  309. package/dist/shims/navigation.js.map +1 -1
  310. package/dist/shims/router.d.ts +5 -0
  311. package/dist/shims/router.js +389 -80
  312. package/dist/shims/router.js.map +1 -1
  313. package/dist/shims/script.d.ts +11 -1
  314. package/dist/shims/script.js +158 -15
  315. package/dist/shims/script.js.map +1 -1
  316. package/dist/shims/server.js +1 -0
  317. package/dist/shims/server.js.map +1 -1
  318. package/dist/shims/url-utils.d.ts +2 -1
  319. package/dist/shims/url-utils.js +15 -4
  320. package/dist/shims/url-utils.js.map +1 -1
  321. package/dist/utils/html-limited-bots.d.ts +5 -0
  322. package/dist/utils/html-limited-bots.js +15 -0
  323. package/dist/utils/html-limited-bots.js.map +1 -0
  324. package/dist/utils/path.d.ts +13 -0
  325. package/dist/utils/path.js +16 -0
  326. package/dist/utils/path.js.map +1 -0
  327. package/dist/utils/query.d.ts +6 -0
  328. package/dist/utils/query.js +10 -1
  329. package/dist/utils/query.js.map +1 -1
  330. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"app-route-graph.js","names":[],"sources":["../../src/routing/app-route-graph.ts"],"sourcesContent":["/**\n * App Router route graph construction.\n *\n * Scans app/ directories and materializes route metadata before the request-time\n * matcher consumes it. Keep request matching and cache ownership in app-router.ts.\n */\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { compareRoutes, decodeRouteSegment } from \"./utils.js\";\nimport { scanWithExtensions, type ValidFileMatcher } from \"./file-matcher.js\";\nimport { validateRoutePatterns } from \"./route-validation.js\";\n\nexport type InterceptingRoute = {\n /** The interception convention: \".\" | \"..\" | \"../..\" | \"...\" */\n convention: string;\n /** The URL pattern this intercepts (e.g. \"/photos/:id\") */\n targetPattern: string;\n /**\n * URL pattern of the *intercepting route* — the path that owns the slot\n * containing this interception marker, with route groups and `@slot`\n * segments stripped. Mirrors Next.js' `interceptingRoute` from\n * `extractInterceptionRouteInformation`.\n *\n * Used at request time to gate `findIntercept` against the Next-URL /\n * interception-context header: an intercept only fires when the source\n * pathname matches `^<sourceMatchPattern>(?:/.*)?$`. Without this gate\n * a direct RSC fetch to the intercept target would render the modal\n * instead of the underlying page.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/lib/generate-interception-routes-rewrites.ts\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/interception-routes.ts\n */\n sourceMatchPattern: string;\n /** Absolute path to the intercepting page component */\n pagePath: string;\n /** Absolute layout paths inside the intercepting route tree, outermost to innermost */\n layoutPaths: string[];\n /** Parameter names for dynamic segments */\n params: string[];\n};\n\nexport type ParallelSlot = {\n /** Graph-owned semantic slot identity. Required on AppRouteGraphParallelSlot. */\n id?: string;\n /** Stable slot identity (name + owning directory), used for route serialization keys. */\n key: string;\n /** Slot name (e.g. \"team\" from @team) */\n name: string;\n /** Absolute path to the @slot directory that owns this slot. Internal routing metadata. */\n ownerDir: string;\n /** Stable tree path for the directory whose layout owns this slot. */\n ownerTreePath: string;\n /** Whether the slot owner directory declares its own page component. */\n hasPage: boolean;\n /** Absolute path to the slot's page component */\n pagePath: string | null;\n /** Absolute path to the slot's default.tsx fallback */\n defaultPath: string | null;\n /** Absolute path to the slot's layout component (wraps slot content) */\n layoutPath: string | null;\n /** Absolute path to the slot's loading component */\n loadingPath: string | null;\n /** Absolute path to the slot's error component */\n errorPath: string | null;\n /** Intercepting routes within this slot */\n interceptingRoutes: InterceptingRoute[];\n /**\n * The layout index (0-based, in route.layouts[]) that this slot belongs to.\n * Slots are passed as props to the layout at their directory level, not\n * necessarily the innermost layout. -1 means \"innermost\" (legacy default).\n */\n layoutIndex: number;\n /**\n * Filesystem segments from the slot's root directory to its active page.\n * Used at render time to compute segments for useSelectedLayoutSegment(slotName).\n * For a page at the slot root (@team/page.tsx), this is [].\n * For a sub-page (@team/members/page.tsx), this is [\"members\"].\n * null when the slot has no active page (showing default.tsx fallback).\n */\n routeSegments: string[] | null;\n /**\n * Full URL pattern parts for the slot's active page (owner prefix +\n * slot-relative pattern). Set when an inherited slot mirrors a sub-page\n * whose param names may differ from the route's. The runtime matches the\n * request URL against these parts to extract slot-specific params.\n */\n slotPatternParts?: string[];\n /**\n * Param names captured by `slotPatternParts`, in order of appearance.\n * Used at runtime to decide whether to extract slot-specific params or\n * reuse the route's matched params.\n */\n slotParamNames?: string[];\n};\n\nexport type AppRoute = {\n /** Graph-owned semantic identities. Required on AppRouteGraphRoute. */\n ids?: AppRouteSemanticIds;\n /** URL pattern, e.g. \"/\" or \"/about\" or \"/blog/:slug\" */\n pattern: string;\n /** Absolute file path to the page component */\n pagePath: string | null;\n /** Absolute file path to the route handler (route.ts) */\n routePath: string | null;\n /** Ordered list of layout files from root to leaf */\n layouts: string[];\n /** Ordered list of all discovered template files from root to leaf (not necessarily aligned 1:1 with layouts) */\n templates: string[];\n /** Parallel route slots (from @slot directories at the route's directory level) */\n parallelSlots: ParallelSlot[];\n /** Loading component path */\n loadingPath: string | null;\n /** Error component path (leaf directory only) */\n errorPath: string | null;\n /**\n * Per-layout error boundary paths, aligned with the layouts array.\n * Each entry is the error.tsx at the same directory level as the\n * corresponding layout (or null if that level has no error.tsx).\n */\n layoutErrorPaths: (string | null)[];\n /** Per-segment error boundary paths, aligned with errorTreePositions. */\n errorPaths?: string[];\n /** Tree position (directory depth from app/ root) for each error boundary. */\n errorTreePositions?: number[];\n /** Not-found component path (nearest, walking up from page dir) */\n notFoundPath: string | null;\n /**\n * Not-found component paths per layout level (aligned with layouts array).\n * Each entry is the not-found.tsx at that layout's directory, or null.\n * Used to create per-layout NotFoundBoundary so that notFound() thrown from\n * a layout is caught by the parent layout's boundary (matching Next.js behavior).\n */\n notFoundPaths: (string | null)[];\n /**\n * Forbidden component paths per layout level (aligned with layouts array).\n * Each entry is the forbidden.tsx at that layout's directory, or null.\n * Used to create per-layout ForbiddenBoundary.\n */\n forbiddenPaths: (string | null)[];\n /** Forbidden component path (403) at the route's directory level */\n forbiddenPath: string | null;\n /** Unauthorized component path (401) at the route's directory level */\n unauthorizedPath: string | null;\n /** Unauthorized component paths per layout level (aligned with layouts array). */\n unauthorizedPaths: (string | null)[];\n /**\n * Filesystem segments from app/ root to the route's directory.\n * Includes route groups and dynamic segments (as template strings like \"[id]\").\n * Used at render time to compute the child segments for useSelectedLayoutSegments().\n */\n routeSegments: string[];\n /** Tree position (directory depth from app/ root) for each template. */\n templateTreePositions?: number[];\n /**\n * Tree position (directory depth from app/ root) for each layout.\n * Used to slice routeSegments and determine which segments are below each layout.\n * For example, root layout = 0, a layout at app/blog/ = 1, app/blog/(group)/ = 2.\n * Unlike the old layoutSegmentDepths, this counts ALL directory levels including\n * route groups and parallel slots.\n */\n layoutTreePositions: number[];\n /** Whether this is a dynamic route */\n isDynamic: boolean;\n /** Parameter names for dynamic segments */\n params: string[];\n /** Dynamic parameter names captured by the route's root layout. */\n rootParamNames?: string[];\n /** Pre-split pattern segments (computed once at scan time, reused per request) */\n patternParts: string[];\n};\n\nexport type AppRouteSemanticIds = {\n route: string;\n page: string | null;\n routeHandler: string | null;\n rootBoundary: RootBoundaryId | null;\n layouts: readonly string[];\n templates: readonly string[];\n /**\n * Bridge map for the current route metadata shape: keyed by `slot.key`\n * (`name@relative/path` infrastructure id), value is the graph-owned semantic slot id.\n */\n slots: Readonly<Record<string, string>>;\n};\n\nexport type AppRouteGraphParallelSlot = ParallelSlot & {\n id: string;\n};\n\nexport type AppRouteGraphRoute = Omit<AppRoute, \"ids\" | \"parallelSlots\" | \"rootParamNames\"> & {\n ids: AppRouteSemanticIds;\n parallelSlots: AppRouteGraphParallelSlot[];\n rootParamNames: string[];\n};\n\ntype Flavor<T, Brand extends string> = T & { readonly __flavor?: Brand };\n\nexport type GraphVersion = Flavor<string, \"GraphVersion\">;\nexport type RootBoundaryId = Flavor<string, \"RootBoundaryId\">;\n\nexport type RouteManifestRoute = {\n id: string;\n pattern: string;\n patternParts: readonly string[];\n isDynamic: boolean;\n paramNames: readonly string[];\n rootParamNames: readonly string[];\n rootBoundaryId: RootBoundaryId | null;\n pageId: string | null;\n routeHandlerId: string | null;\n layoutIds: readonly string[];\n templateIds: readonly string[];\n slotIds: readonly string[];\n};\n\nexport type RouteManifestPage = {\n id: string;\n routeId: string;\n pattern: string;\n};\n\nexport type RouteManifestRouteHandler = {\n id: string;\n routeId: string;\n pattern: string;\n};\n\nexport type RouteManifestLayout = {\n id: string;\n treePath: string;\n patternParts: readonly string[];\n paramNames: readonly string[];\n rootBoundaryId: RootBoundaryId | null;\n};\n\nexport type RouteManifestTemplate = {\n id: string;\n treePath: string;\n rootBoundaryId: RootBoundaryId | null;\n ownerLayoutId: string | null;\n reset: {\n kind: \"remountSubtree\";\n treePath: string;\n };\n};\n\nexport type RouteManifestSlot = {\n id: string;\n key: string;\n name: string;\n ownerTreePath: string;\n ownerLayoutId: string | null;\n rootBoundaryId: RootBoundaryId | null;\n defaultId: string | null;\n hasDefault: boolean;\n hasPage: boolean;\n};\n\nexport type RouteManifestDefault = {\n id: string;\n slotId: string;\n ownerTreePath: string;\n ownerLayoutId: string | null;\n rootBoundaryId: RootBoundaryId | null;\n};\n\nexport type RouteManifestSlotBindingState = \"active\" | \"default\" | \"unmatched\";\n\nexport type RouteManifestSlotBinding = {\n id: string;\n routeId: string;\n slotId: string;\n ownerLayoutId: string | null;\n state: RouteManifestSlotBindingState;\n defaultId: string | null;\n routeSegments: readonly string[] | null;\n slotPatternParts?: readonly string[];\n slotParamNames?: readonly string[];\n};\n\nexport type RouteManifestInterception = {\n id: string;\n sourcePattern: string;\n sourcePatternParts: readonly string[];\n targetPattern: string;\n targetPatternParts: readonly string[];\n slotId: string;\n ownerLayoutId: string | null;\n interceptingRouteId: string | null;\n targetRouteId: string | null;\n};\n\nexport type RouteManifestBoundaryOutcome = \"error\" | \"forbidden\" | \"notFound\" | \"unauthorized\";\n\nexport type RouteManifestBoundary = {\n id: string;\n outcome: RouteManifestBoundaryOutcome;\n treePath: string;\n ownerLayoutId: string | null;\n rootBoundaryId: RootBoundaryId | null;\n};\n\nexport type RouteManifestRootBoundary = {\n id: RootBoundaryId;\n layoutId: string;\n treePath: string;\n};\n\nexport type StaticSegmentGraph = {\n routes: ReadonlyMap<string, RouteManifestRoute>;\n pages: ReadonlyMap<string, RouteManifestPage>;\n routeHandlers: ReadonlyMap<string, RouteManifestRouteHandler>;\n layouts: ReadonlyMap<string, RouteManifestLayout>;\n templates: ReadonlyMap<string, RouteManifestTemplate>;\n slots: ReadonlyMap<string, RouteManifestSlot>;\n defaults: ReadonlyMap<string, RouteManifestDefault>;\n slotBindings: ReadonlyMap<string, RouteManifestSlotBinding>;\n interceptions: ReadonlyMap<string, RouteManifestInterception>;\n interceptionsBySlotId: ReadonlyMap<string, readonly RouteManifestInterception[]>;\n boundaries: ReadonlyMap<string, RouteManifestBoundary>;\n rootBoundaries: ReadonlyMap<RootBoundaryId, RouteManifestRootBoundary>;\n};\n\nexport type RouteManifest = {\n graphVersion: GraphVersion;\n segmentGraph: StaticSegmentGraph;\n};\n\nfunction createAppRouteGraphRouteId(pattern: string): string {\n return `route:${pattern}`;\n}\n\nfunction createAppRouteGraphPageId(pattern: string): string {\n return `page:${pattern}`;\n}\n\nfunction createAppRouteGraphRouteHandlerId(pattern: string): string {\n return `route-handler:${pattern}`;\n}\n\nfunction createAppRouteGraphLayoutId(treePath: string): string {\n return `layout:${treePath}`;\n}\n\nfunction createAppRouteGraphTemplateId(treePath: string): string {\n return `template:${treePath}`;\n}\n\nfunction createAppRouteGraphSlotId(slotName: string, ownerTreePath: string): string {\n return `slot:${slotName}:${ownerTreePath}`;\n}\n\nfunction createAppRouteGraphDefaultId(slotId: string): string {\n return `default:${slotId}`;\n}\n\nfunction createAppRouteGraphInterceptionId(\n slotId: string,\n sourcePattern: string,\n targetPattern: string,\n): string {\n return `interception:${slotId}:${sourcePattern}->${targetPattern}`;\n}\n\nfunction createAppRouteGraphRootBoundaryId(treePath: string): RootBoundaryId {\n return `root-boundary:${treePath}`;\n}\n\nfunction compareStableStrings(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\nfunction sortedMapValues<T>(map: ReadonlyMap<string, T>): T[] {\n return Array.from(map.entries())\n .sort(([left], [right]) => compareStableStrings(left, right))\n .map(([, value]) => value);\n}\n\nfunction createRouteManifest(routes: readonly AppRouteGraphRoute[]): RouteManifest {\n const segmentGraph = createStaticSegmentGraph(routes);\n\n return {\n graphVersion: createRouteManifestGraphVersion(segmentGraph),\n segmentGraph,\n };\n}\n\nfunction createStaticSegmentGraph(routes: readonly AppRouteGraphRoute[]): StaticSegmentGraph {\n const routeEntries = new Map<string, RouteManifestRoute>();\n const pages = new Map<string, RouteManifestPage>();\n const routeHandlers = new Map<string, RouteManifestRouteHandler>();\n const layouts = new Map<string, RouteManifestLayout>();\n const templates = new Map<string, RouteManifestTemplate>();\n const slots = new Map<string, RouteManifestSlot>();\n const defaults = new Map<string, RouteManifestDefault>();\n const slotBindings = new Map<string, RouteManifestSlotBinding>();\n const interceptions = new Map<string, RouteManifestInterception>();\n const boundaries = new Map<string, RouteManifestBoundary>();\n const rootBoundaries = new Map<RootBoundaryId, RouteManifestRootBoundary>();\n const routeIdByPattern = createRouteManifestRouteIdByPattern(routes);\n\n for (const route of routes) {\n routeEntries.set(route.ids.route, {\n id: route.ids.route,\n pattern: route.pattern,\n patternParts: [...route.patternParts],\n isDynamic: route.isDynamic,\n paramNames: [...route.params],\n rootParamNames: [...route.rootParamNames],\n rootBoundaryId: route.ids.rootBoundary,\n pageId: route.ids.page,\n routeHandlerId: route.ids.routeHandler,\n layoutIds: [...route.ids.layouts],\n templateIds: [...route.ids.templates],\n slotIds: route.parallelSlots.map((slot) => slot.id).sort(compareStableStrings),\n });\n\n if (route.ids.page) {\n pages.set(route.ids.page, {\n id: route.ids.page,\n routeId: route.ids.route,\n pattern: route.pattern,\n });\n }\n\n if (route.ids.routeHandler) {\n routeHandlers.set(route.ids.routeHandler, {\n id: route.ids.routeHandler,\n routeId: route.ids.route,\n pattern: route.pattern,\n });\n }\n\n for (const [index, layoutId] of route.ids.layouts.entries()) {\n const treePosition = route.layoutTreePositions[index];\n assertRouteManifestTreePosition(\"layout\", route, layoutId, treePosition);\n\n const treePath = createAppRouteGraphTreePath(route.routeSegments, treePosition);\n const existingLayout = layouts.get(layoutId);\n if (existingLayout) {\n assertRouteManifestRootBoundary(\"layout\", route, layoutId, existingLayout.rootBoundaryId);\n }\n const layoutRouteParts = convertTreePathToRouteParts(treePath);\n const layout = {\n id: layoutId,\n treePath,\n patternParts: layoutRouteParts.urlSegments,\n paramNames: layoutRouteParts.params,\n rootBoundaryId: route.ids.rootBoundary,\n };\n layouts.set(layoutId, layout);\n addRouteManifestBoundaryFacts({\n boundaries,\n route,\n layoutId,\n treePath,\n layoutIndex: index,\n });\n\n if (index === 0 && route.ids.rootBoundary) {\n rootBoundaries.set(route.ids.rootBoundary, {\n id: route.ids.rootBoundary,\n layoutId,\n treePath,\n });\n }\n }\n\n addRouteManifestSegmentErrorBoundaryFacts({ boundaries, route });\n\n for (const [index, templateId] of route.ids.templates.entries()) {\n const treePosition = route.templateTreePositions?.[index];\n assertRouteManifestTreePosition(\"template\", route, templateId, treePosition);\n const treePath = createAppRouteGraphTreePath(route.routeSegments, treePosition);\n\n const existingTemplate = templates.get(templateId);\n if (existingTemplate) {\n assertRouteManifestRootBoundary(\n \"template\",\n route,\n templateId,\n existingTemplate.rootBoundaryId,\n );\n }\n templates.set(templateId, {\n id: templateId,\n treePath,\n rootBoundaryId: route.ids.rootBoundary,\n ownerLayoutId: findRouteManifestOwnerLayoutId(route, treePosition),\n reset: {\n kind: \"remountSubtree\",\n treePath,\n },\n });\n }\n\n for (const slot of route.parallelSlots) {\n const ownerLayoutId = findSlotOwnerLayoutId(route, slot);\n const defaultId = slot.defaultPath ? createAppRouteGraphDefaultId(slot.id) : null;\n if (slot.layoutPath) {\n // Materialize the slot-local layout as its own entry so consumers\n // (e.g. typegen) can distinguish it from the owning layout. Note\n // that this layout may have zero entries in `slots`: the slot\n // itself is registered below against `ownerLayoutId`, which points\n // to the ancestor layout that owns the slot prop.\n const slotLayoutTreePath = createSlotLayoutTreePath(slot);\n const slotLayoutId = createAppRouteGraphLayoutId(slotLayoutTreePath);\n const existingLayout = layouts.get(slotLayoutId);\n if (existingLayout) {\n assertRouteManifestRootBoundary(\n \"layout\",\n route,\n slotLayoutId,\n existingLayout.rootBoundaryId,\n );\n }\n const slotLayoutRouteParts = convertTreePathToRouteParts(slotLayoutTreePath);\n layouts.set(slotLayoutId, {\n id: slotLayoutId,\n treePath: slotLayoutTreePath,\n patternParts: slotLayoutRouteParts.urlSegments,\n paramNames: slotLayoutRouteParts.params,\n rootBoundaryId: route.ids.rootBoundary,\n });\n }\n slots.set(slot.id, {\n id: slot.id,\n key: slot.key,\n name: slot.name,\n ownerTreePath: slot.ownerTreePath,\n ownerLayoutId,\n rootBoundaryId: ownerLayoutId ? route.ids.rootBoundary : null,\n defaultId,\n hasDefault: slot.defaultPath !== null,\n hasPage: slot.hasPage,\n });\n if (defaultId) {\n defaults.set(defaultId, {\n id: defaultId,\n slotId: slot.id,\n ownerTreePath: slot.ownerTreePath,\n ownerLayoutId,\n rootBoundaryId: ownerLayoutId ? route.ids.rootBoundary : null,\n });\n }\n const binding = createRouteManifestSlotBinding(route, slot, ownerLayoutId, defaultId);\n slotBindings.set(binding.id, binding);\n addRouteManifestInterceptionFacts({\n interceptions,\n ownerLayoutId,\n route,\n routeIdByPattern,\n slot,\n });\n }\n }\n\n const interceptionsBySlotId = createRouteManifestInterceptionsBySlotId(interceptions);\n\n return {\n routes: routeEntries,\n pages,\n routeHandlers,\n layouts,\n templates,\n slots,\n defaults,\n slotBindings,\n interceptions,\n interceptionsBySlotId,\n boundaries,\n rootBoundaries,\n };\n}\n\nfunction createRouteManifestRouteIdByPattern(\n routes: readonly AppRouteGraphRoute[],\n): ReadonlyMap<string, string> {\n return new Map(routes.map((route) => [route.pattern, route.ids.route]));\n}\n\nfunction findRouteManifestOwnerLayoutId(\n route: AppRouteGraphRoute,\n treePosition: number,\n): string | null {\n const layoutIndex = route.layoutTreePositions.indexOf(treePosition);\n return route.ids.layouts[layoutIndex] ?? null;\n}\n\nfunction findSlotOwnerLayoutId(\n route: AppRouteGraphRoute,\n slot: AppRouteGraphParallelSlot,\n): string | null {\n if (slot.layoutIndex < 0) return null;\n return route.ids.layouts[slot.layoutIndex] ?? null;\n}\n\nfunction createSlotLayoutTreePath(slot: AppRouteGraphParallelSlot): string {\n const slotSegment = `@${slot.name}`;\n if (slot.ownerTreePath === \"/\") return `/${slotSegment}`;\n return `${slot.ownerTreePath}/${slotSegment}`;\n}\n\nfunction createRouteManifestSlotBinding(\n route: AppRouteGraphRoute,\n slot: AppRouteGraphParallelSlot,\n ownerLayoutId: string | null,\n defaultId: string | null,\n): RouteManifestSlotBinding {\n const state = getRouteManifestSlotBindingState(slot);\n const binding: RouteManifestSlotBinding = {\n id: `${route.ids.route}::${slot.id}`,\n routeId: route.ids.route,\n slotId: slot.id,\n ownerLayoutId,\n state,\n defaultId: state === \"default\" ? defaultId : null,\n routeSegments: slot.routeSegments ? [...slot.routeSegments] : null,\n };\n\n if (slot.slotPatternParts) {\n binding.slotPatternParts = [...slot.slotPatternParts];\n }\n if (slot.slotParamNames) {\n binding.slotParamNames = [...slot.slotParamNames];\n }\n\n return binding;\n}\n\nfunction addRouteManifestInterceptionFacts(input: {\n interceptions: Map<string, RouteManifestInterception>;\n ownerLayoutId: string | null;\n route: AppRouteGraphRoute;\n routeIdByPattern: ReadonlyMap<string, string>;\n slot: AppRouteGraphParallelSlot;\n}): void {\n for (const interception of input.slot.interceptingRoutes) {\n const id = createAppRouteGraphInterceptionId(\n input.slot.id,\n interception.sourceMatchPattern,\n interception.targetPattern,\n );\n input.interceptions.set(id, {\n id,\n sourcePattern: interception.sourceMatchPattern,\n sourcePatternParts: splitRouteManifestPatternParts(interception.sourceMatchPattern),\n targetPattern: interception.targetPattern,\n targetPatternParts: splitRouteManifestPatternParts(interception.targetPattern),\n slotId: input.slot.id,\n ownerLayoutId: input.ownerLayoutId,\n interceptingRouteId: input.routeIdByPattern.get(interception.sourceMatchPattern) ?? null,\n targetRouteId: input.routeIdByPattern.get(interception.targetPattern) ?? null,\n });\n }\n}\n\nfunction createRouteManifestInterceptionsBySlotId(\n interceptions: ReadonlyMap<string, RouteManifestInterception>,\n): ReadonlyMap<string, readonly RouteManifestInterception[]> {\n const interceptionsBySlotId = new Map<string, RouteManifestInterception[]>();\n for (const interception of interceptions.values()) {\n const existing = interceptionsBySlotId.get(interception.slotId);\n if (existing) {\n existing.push(interception);\n } else {\n interceptionsBySlotId.set(interception.slotId, [interception]);\n }\n }\n\n for (const slotInterceptions of interceptionsBySlotId.values()) {\n slotInterceptions.sort((left, right) => compareStableStrings(left.id, right.id));\n }\n\n return new Map(\n Array.from(interceptionsBySlotId.entries()).sort(([left], [right]) =>\n compareStableStrings(left, right),\n ),\n );\n}\n\nfunction splitRouteManifestPatternParts(pattern: string): string[] {\n return pattern.split(\"/\").filter((part) => part.length > 0);\n}\n\nfunction getRouteManifestSlotBindingState(\n slot: AppRouteGraphParallelSlot,\n): RouteManifestSlotBindingState {\n if (slot.pagePath) return \"active\";\n if (slot.defaultPath) return \"default\";\n return \"unmatched\";\n}\n\nfunction addRouteManifestBoundaryFacts(input: {\n boundaries: Map<string, RouteManifestBoundary>;\n route: AppRouteGraphRoute;\n layoutId: string;\n treePath: string;\n layoutIndex: number;\n}): void {\n addRouteManifestBoundaryFact(input, \"error\", input.route.layoutErrorPaths[input.layoutIndex]);\n addRouteManifestBoundaryFact(input, \"notFound\", input.route.notFoundPaths[input.layoutIndex]);\n addRouteManifestBoundaryFact(input, \"forbidden\", input.route.forbiddenPaths[input.layoutIndex]);\n addRouteManifestBoundaryFact(\n input,\n \"unauthorized\",\n input.route.unauthorizedPaths[input.layoutIndex],\n );\n}\n\nfunction addRouteManifestSegmentErrorBoundaryFacts(input: {\n boundaries: Map<string, RouteManifestBoundary>;\n route: AppRouteGraphRoute;\n}): void {\n for (const [index, boundaryPath] of (input.route.errorPaths ?? []).entries()) {\n const treePosition = input.route.errorTreePositions?.[index];\n assertRouteManifestBoundaryTreePosition(input.route, boundaryPath, treePosition);\n const ownerLayoutId = findRouteManifestOwnerLayoutId(input.route, treePosition);\n if (ownerLayoutId !== null) continue;\n\n const treePath = createAppRouteGraphTreePath(input.route.routeSegments, treePosition);\n addRouteManifestBoundaryFact(\n {\n boundaries: input.boundaries,\n route: input.route,\n layoutId: ownerLayoutId,\n treePath,\n },\n \"error\",\n boundaryPath,\n );\n }\n}\n\nfunction addRouteManifestBoundaryFact(\n input: {\n boundaries: Map<string, RouteManifestBoundary>;\n route: AppRouteGraphRoute;\n layoutId: string | null;\n treePath: string;\n },\n outcome: RouteManifestBoundaryOutcome,\n boundaryPath: string | null | undefined,\n): void {\n if (!boundaryPath) return;\n\n const id = `boundary:${outcome}:${input.treePath}`;\n input.boundaries.set(id, {\n id,\n outcome,\n treePath: input.treePath,\n ownerLayoutId: input.layoutId,\n rootBoundaryId: input.route.ids.rootBoundary,\n });\n}\n\nfunction assertRouteManifestTreePosition(\n kind: \"layout\" | \"template\",\n route: AppRouteGraphRoute,\n id: string,\n treePosition: number | undefined,\n): asserts treePosition is number {\n if (treePosition !== undefined) return;\n\n throw new Error(\n `[vinext] App route graph invariant violated: missing ${kind} tree position for ${id} on ${route.pattern}`,\n );\n}\n\nfunction assertRouteManifestBoundaryTreePosition(\n route: AppRouteGraphRoute,\n boundaryPath: string,\n treePosition: number | undefined,\n): asserts treePosition is number {\n if (treePosition !== undefined) return;\n\n throw new Error(\n `[vinext] App route graph invariant violated: missing boundary tree position for ${boundaryPath} on ${route.pattern}`,\n );\n}\n\nfunction assertRouteManifestRootBoundary(\n kind: \"layout\" | \"template\",\n route: AppRouteGraphRoute,\n id: string,\n existingRootBoundaryId: RootBoundaryId | null,\n): void {\n if (existingRootBoundaryId === route.ids.rootBoundary) return;\n\n throw new Error(\n `[vinext] App route graph invariant violated: ${kind} ${id} is shared across root boundaries (${existingRootBoundaryId ?? \"none\"} and ${route.ids.rootBoundary ?? \"none\"}) on ${route.pattern}`,\n );\n}\n\nfunction createRouteManifestGraphVersion(segmentGraph: StaticSegmentGraph): GraphVersion {\n // The manifest hash is canonical only if top-level map keys are sorted and\n // inner route arrays keep their own semantic order: layoutIds/templateIds in\n // tree-position order, and slotIds in compareStableStrings order.\n const stableShape = {\n routes: sortedMapValues(segmentGraph.routes),\n pages: sortedMapValues(segmentGraph.pages),\n routeHandlers: sortedMapValues(segmentGraph.routeHandlers),\n layouts: sortedMapValues(segmentGraph.layouts),\n templates: sortedMapValues(segmentGraph.templates),\n slots: sortedMapValues(segmentGraph.slots),\n defaults: sortedMapValues(segmentGraph.defaults),\n slotBindings: sortedMapValues(segmentGraph.slotBindings),\n interceptions: sortedMapValues(segmentGraph.interceptions),\n interceptionsBySlotId: sortedMapValues(segmentGraph.interceptionsBySlotId),\n boundaries: sortedMapValues(segmentGraph.boundaries),\n rootBoundaries: sortedMapValues(segmentGraph.rootBoundaries),\n };\n return `graph:${createHash(\"sha256\").update(JSON.stringify(stableShape)).digest(\"hex\")}`;\n}\n\nexport async function buildAppRouteGraph(\n appDir: string,\n matcher: ValidFileMatcher,\n): Promise<{ routes: AppRouteGraphRoute[]; routeManifest: RouteManifest }> {\n // Find all page.tsx and route.ts files, excluding @slot directories\n // (slot pages are not standalone routes — they're rendered as props of their parent layout)\n // and _private folders (Next.js convention for colocated non-route files).\n //\n // Interception marker directories (e.g. `(.)photo`, `(..)showcase`,\n // `(..)(..)hoge`, `(...)photos`) are also excluded from the global page\n // scan because the marker is not a real URL segment — Next.js treats these\n // as a separate route family resolved via interception rewrites. Without\n // this exclusion the scanner would register patterns like\n // `/templates/(..)showcase` as standalone routes, breaking the build (and\n // any URL containing the marker).\n //\n // See https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/interception-routes.ts\n const routes: AppRouteGraphRoute[] = [];\n\n const excludeDir = (name: string) =>\n name.startsWith(\"@\") || name.startsWith(\"_\") || isInterceptionMarkerDir(name);\n\n // Process page files in a single pass\n // Use function form of exclude for Node < 22.14 compatibility (string arrays require >= 22.14)\n for await (const file of scanWithExtensions(\"**/page\", appDir, matcher.extensions, excludeDir)) {\n const route = fileToAppRoute(file, appDir, \"page\", matcher);\n if (route) routes.push(route);\n }\n\n // Process route handler files (API routes) in a single pass\n for await (const file of scanWithExtensions(\"**/route\", appDir, matcher.extensions, excludeDir)) {\n const route = fileToAppRoute(file, appDir, \"route\", matcher);\n if (route) routes.push(route);\n }\n\n // Layouts with parallel slot pages are valid route entries even when the\n // segment has no children page. Next.js uses this for modal/feed patterns\n // like app/user/[id]/layout + @feed/page + @modal/default.\n const routePatterns = new Set(routes.map((route) => route.pattern));\n // Ghost parents are layout-only routes whose URL pattern collides with an\n // existing route (e.g. sibling route groups like (group-a)/layout.tsx and\n // (group-b)/page.tsx both anchored at \"/\"). Their slot directories still\n // contribute synthetic sub-routes (e.g. @parallel/[...catcher]/page.tsx →\n // /:catcher+), but the ghost itself is not added to the routes table.\n const ghostParentRoutes: AppRouteGraphRoute[] = [];\n for await (const file of scanWithExtensions(\n \"**/layout\",\n appDir,\n matcher.extensions,\n excludeDir,\n )) {\n const dir = path.dirname(file);\n const routeDir = dir === \".\" ? appDir : path.join(appDir, dir);\n if (!hasParallelSlotDirectory(routeDir)) continue;\n if (discoverParallelSlots(routeDir, appDir, matcher).length === 0) continue;\n\n const route = directoryToAppRoute(dir, appDir, matcher, null, null);\n if (!route) continue;\n if (routePatterns.has(route.pattern)) {\n ghostParentRoutes.push(route);\n continue;\n }\n\n routes.push(route);\n routePatterns.add(route.pattern);\n }\n\n // Discover sub-routes created by nested pages within parallel slots.\n // In Next.js, pages nested inside @slot directories create additional URL routes.\n // For example, @audience/demographics/page.tsx at app/parallel-routes/ creates\n // a route at /parallel-routes/demographics.\n const slotSubRoutes = discoverSlotSubRoutes(routes, matcher, ghostParentRoutes);\n routes.push(...slotSubRoutes);\n\n validatePageRouteConflicts(routes, appDir);\n validateRoutePatterns(routes.map((route) => route.pattern));\n const interceptTargetPatterns = [\n ...new Set(\n routes.flatMap((route) =>\n route.parallelSlots.flatMap((slot) =>\n slot.interceptingRoutes.map((intercept) => intercept.targetPattern),\n ),\n ),\n ),\n ];\n validateRoutePatterns(interceptTargetPatterns);\n\n // Sort: static routes first, then dynamic, then catch-all\n routes.sort(compareRoutes);\n\n return { routes, routeManifest: createRouteManifest(routes) };\n}\n\nfunction hasParallelSlotDirectory(dir: string): boolean {\n try {\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .some((entry) => entry.isDirectory() && entry.name.startsWith(\"@\"));\n } catch {\n return false;\n }\n}\n\nfunction validatePageRouteConflicts(routes: readonly AppRoute[], appDir: string): void {\n const byPattern = new Map<string, { pagePath: string | null; routePath: string | null }>();\n\n // validateRoutePatterns() would also reject page/route pairs because they\n // share a URL pattern. Keep this pass first so the error names both files.\n for (const route of routes) {\n const entry = byPattern.get(route.pattern);\n if (!entry) {\n byPattern.set(route.pattern, {\n pagePath: route.pagePath,\n routePath: route.routePath,\n });\n continue;\n }\n\n if (!entry.pagePath && route.pagePath) {\n entry.pagePath = route.pagePath;\n }\n if (!entry.routePath && route.routePath) {\n entry.routePath = route.routePath;\n }\n }\n\n for (const [pattern, entry] of byPattern) {\n if (!entry.pagePath || !entry.routePath) continue;\n\n throw new Error(\n `Conflicting route and page at ${pattern}: route at ${formatAppFilePath(\n entry.routePath,\n appDir,\n )} and page at ${formatAppFilePath(entry.pagePath, appDir)}`,\n );\n }\n}\n\nfunction formatAppFilePath(filePath: string, appDir: string): string {\n const relativePath = path.relative(appDir, filePath).replace(/\\\\/g, \"/\");\n const parsedPath = path.parse(relativePath);\n const withoutExtension = path.join(parsedPath.dir, parsedPath.name).replace(/\\\\/g, \"/\");\n return withoutExtension.startsWith(\"/\") ? withoutExtension : `/${withoutExtension}`;\n}\n\n/**\n * Discover sub-routes created by nested pages within parallel slots.\n *\n * In Next.js, pages nested inside @slot directories create additional URL routes.\n * For example, given:\n * app/parallel-routes/@audience/demographics/page.tsx\n * This creates a route at /parallel-routes/demographics where:\n * - children slot → parent's default.tsx\n * - @audience slot → @audience/demographics/page.tsx (matched)\n * - other slots → their default.tsx (fallback)\n */\nfunction discoverSlotSubRoutes(\n routes: AppRouteGraphRoute[],\n matcher: ValidFileMatcher,\n ghostParents: readonly AppRouteGraphRoute[] = [],\n): AppRouteGraphRoute[] {\n const syntheticRoutes: AppRouteGraphRoute[] = [];\n\n // O(1) lookup for existing routes by pattern — avoids O(n) routes.find() per sub-path per parent.\n // Updated as new synthetic routes are pushed so that later parents can see earlier synthetic entries.\n const routesByPattern = new Map<string, AppRoute>(routes.map((r) => [r.pattern, r]));\n\n const applySlotSubPages = (\n route: AppRoute,\n slotPages: Map<string, string>,\n rawSegments: string[],\n ): void => {\n route.parallelSlots = route.parallelSlots.map((slot) => {\n const subPage = slotPages.get(slot.key);\n if (subPage !== undefined) {\n return { ...slot, pagePath: subPage, routeSegments: rawSegments };\n }\n return slot;\n });\n };\n\n // Iterate real routes first so that later ghost-parent passes can detect\n // synthetic conflicts against routes the real pass minted.\n const allParents: AppRouteGraphRoute[] = [...routes, ...ghostParents];\n for (const parentRoute of allParents) {\n if (parentRoute.parallelSlots.length === 0) continue;\n\n // Only page-bearing routes or layout-only UI routes (not route handlers)\n // can own nested parallel-slot sub-routes.\n const isLayoutOnlyUiRoute =\n !parentRoute.pagePath && !parentRoute.routePath && parentRoute.layouts.length > 0;\n if (!parentRoute.pagePath && !isLayoutOnlyUiRoute) continue;\n\n // For page-bearing routes, the route directory is the page's directory.\n // For layout-only routes (no page.tsx), proxy the route directory through\n // the innermost layout — it lives at the same filesystem level as the route.\n const parentPageDir = parentRoute.pagePath\n ? path.dirname(parentRoute.pagePath)\n : path.dirname(parentRoute.layouts[parentRoute.layouts.length - 1]);\n\n // Collect sub-paths from all slots.\n // Map: normalized visible sub-path -> slot pages, raw filesystem segments (for routeSegments),\n // and the pre-computed convertedSubRoute (to avoid a redundant re-conversion in the merge loop).\n const subPathMap = new Map<\n string,\n {\n // Raw filesystem segments (with route groups, @slots, etc.) used for routeSegments so\n // that useSelectedLayoutSegments() sees the correct segment list at runtime.\n rawSegments: string[];\n // Pre-computed URL parts, params, isDynamic from convertSegmentsToRouteParts.\n converted: { urlSegments: string[]; params: string[]; isDynamic: boolean };\n slotPages: Map<string, string>;\n }\n >();\n\n for (const slot of parentRoute.parallelSlots) {\n // Only scan sub-pages from slots owned by this route directory.\n // Inherited slots with the same name live in different owner dirs.\n if (path.dirname(slot.ownerDir) !== parentPageDir) {\n continue;\n }\n const slotDir = slot.ownerDir;\n if (!fs.existsSync(slotDir)) continue;\n\n const subPages = findSlotSubPages(slotDir, matcher);\n for (const { relativePath, pagePath } of subPages) {\n const subSegments = relativePath.split(path.sep);\n const convertedSubRoute = convertSegmentsToRouteParts(subSegments);\n if (!convertedSubRoute) continue;\n\n const { urlSegments } = convertedSubRoute;\n const normalizedSubPath = urlSegments.join(\"/\");\n let subPathEntry = subPathMap.get(normalizedSubPath);\n\n if (!subPathEntry) {\n subPathEntry = {\n rawSegments: subSegments,\n converted: convertedSubRoute,\n slotPages: new Map(),\n };\n subPathMap.set(normalizedSubPath, subPathEntry);\n }\n\n const existingSlotPage = subPathEntry.slotPages.get(slot.key);\n if (existingSlotPage) {\n const pattern = joinRoutePattern(parentRoute.pattern, normalizedSubPath);\n throw new Error(\n `You cannot have two routes that resolve to the same path (\"${pattern}\").`,\n );\n }\n\n subPathEntry.slotPages.set(slot.key, pagePath);\n }\n }\n\n if (subPathMap.size === 0) continue;\n\n // Find the default.tsx for the children slot at the parent directory.\n // When the parent route has a children page, a default.tsx is required so\n // the synthetic sub-route has a fallback for the children slot. Layout-only\n // parent routes (no page.tsx) do not need a default — the children slot was\n // never occupied at the parent level, so the sub-route simply renders null.\n const childrenDefault = findFile(parentPageDir, \"default\", matcher);\n if (parentRoute.pagePath && !childrenDefault) continue;\n\n for (const { rawSegments, converted: convertedSubRoute, slotPages } of subPathMap.values()) {\n const {\n urlSegments: urlParts,\n params: subParams,\n isDynamic: subIsDynamic,\n } = convertedSubRoute;\n\n const subUrlPath = urlParts.join(\"/\");\n const pattern = joinRoutePattern(parentRoute.pattern, subUrlPath);\n\n const existingRoute = routesByPattern.get(pattern);\n if (existingRoute) {\n if (existingRoute.routePath && !existingRoute.pagePath) {\n throw new Error(\n `You cannot have two routes that resolve to the same path (\"${pattern}\").`,\n );\n }\n applySlotSubPages(existingRoute, slotPages, rawSegments);\n continue;\n }\n\n // Skip synthetic routes that would structurally conflict with an existing\n // route (same shape, different param names). The slot content is handled\n // by findMirroredSlotPage for the existing route instead.\n // Scan routesByPattern (not just the original routes array) so synthetic\n // routes created earlier in this loop are also visible.\n const syntheticParts = [...parentRoute.patternParts, ...urlParts];\n const hasStructuralConflict = Array.from(routesByPattern.values()).some((r) =>\n patternsStructurallyEquivalent(r.patternParts, syntheticParts),\n );\n if (hasStructuralConflict) continue;\n\n // Build parallel slots for this sub-route: matching slots get the sub-page,\n // non-matching slots get null pagePath (rendering falls back to defaultPath)\n const subSlots: AppRouteGraphParallelSlot[] = parentRoute.parallelSlots.map((slot) => {\n const subPage = slotPages.get(slot.key);\n return {\n ...slot,\n pagePath: subPage || null,\n routeSegments: subPage ? rawSegments : null,\n };\n });\n\n const newRoute: AppRouteGraphRoute = {\n ids: createAppRouteSemanticIds({\n pattern,\n pagePath: childrenDefault,\n routePath: null,\n routeSegments: [...parentRoute.routeSegments, ...rawSegments],\n layoutTreePositions: parentRoute.layoutTreePositions,\n templateTreePositions: parentRoute.templateTreePositions,\n slots: subSlots,\n }),\n pattern,\n pagePath: childrenDefault, // children slot uses parent's default.tsx as page\n routePath: null,\n layouts: parentRoute.layouts,\n templates: parentRoute.templates,\n parallelSlots: subSlots,\n loadingPath: parentRoute.loadingPath,\n errorPath: parentRoute.errorPath,\n layoutErrorPaths: parentRoute.layoutErrorPaths,\n notFoundPath: parentRoute.notFoundPath,\n notFoundPaths: parentRoute.notFoundPaths,\n forbiddenPaths: parentRoute.forbiddenPaths,\n forbiddenPath: parentRoute.forbiddenPath,\n unauthorizedPath: parentRoute.unauthorizedPath,\n unauthorizedPaths: parentRoute.unauthorizedPaths,\n routeSegments: [...parentRoute.routeSegments, ...rawSegments],\n templateTreePositions: parentRoute.templateTreePositions,\n layoutTreePositions: parentRoute.layoutTreePositions,\n isDynamic: parentRoute.isDynamic || subIsDynamic,\n params: [...parentRoute.params, ...subParams],\n rootParamNames: parentRoute.rootParamNames,\n patternParts: [...parentRoute.patternParts, ...urlParts],\n };\n syntheticRoutes.push(newRoute);\n routesByPattern.set(pattern, newRoute);\n }\n }\n\n return syntheticRoutes;\n}\n\n/**\n * Find all page files in subdirectories of a parallel slot directory.\n * Returns relative paths (from the slot dir) and absolute page paths.\n * Skips the root page.tsx (already handled as the slot's main page)\n * and intercepting route directories.\n */\ntype SlotSubPageEntry = { relativePath: string; pagePath: string };\n\n// Per-build memo: a slot directory's sub-pages depend only on the directory\n// contents and the matcher's accepted extensions. Inherited slots get scanned\n// once per descendant route, so without memoization a route N segments deep\n// pays O(N) full subtree walks for every shared ancestor slot.\n//\n// Keyed by matcher (one matcher per build) so the cache is naturally scoped\n// to a single build run and gets collected when the build finishes — no\n// cross-build pollution in long-lived dev servers.\nconst findSlotSubPagesCache = new WeakMap<ValidFileMatcher, Map<string, SlotSubPageEntry[]>>();\n\nfunction findSlotSubPages(slotDir: string, matcher: ValidFileMatcher): SlotSubPageEntry[] {\n let perMatcher = findSlotSubPagesCache.get(matcher);\n if (!perMatcher) {\n perMatcher = new Map();\n findSlotSubPagesCache.set(matcher, perMatcher);\n }\n const cached = perMatcher.get(slotDir);\n if (cached) return cached;\n\n const results: SlotSubPageEntry[] = [];\n\n function scan(dir: string): void {\n if (!fs.existsSync(dir)) return;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip intercepting route directories\n if (matchInterceptConvention(entry.name)) continue;\n // Skip private folders (prefixed with _)\n if (entry.name.startsWith(\"_\")) continue;\n\n const subDir = path.join(dir, entry.name);\n const page = findFile(subDir, \"page\", matcher);\n if (page) {\n const relativePath = path.relative(slotDir, subDir);\n results.push({ relativePath, pagePath: page });\n }\n // Continue scanning deeper for nested sub-pages\n scan(subDir);\n }\n }\n\n scan(slotDir);\n perMatcher.set(slotDir, results);\n return results;\n}\n\n/**\n * Convert a file path relative to app/ into an AppRoute.\n */\nfunction fileToAppRoute(\n file: string,\n appDir: string,\n type: \"page\" | \"route\",\n matcher: ValidFileMatcher,\n): AppRouteGraphRoute | null {\n // Remove the filename (page.tsx or route.ts)\n const dir = path.dirname(file);\n return directoryToAppRoute(\n dir,\n appDir,\n matcher,\n type === \"page\" ? path.join(appDir, file) : null,\n type === \"route\" ? path.join(appDir, file) : null,\n );\n}\n\nfunction directoryToAppRoute(\n dir: string,\n appDir: string,\n matcher: ValidFileMatcher,\n pagePath: string | null,\n routePath: string | null,\n): AppRouteGraphRoute | null {\n const segments = dir === \".\" ? [] : dir.split(path.sep);\n\n const params: string[] = [];\n let isDynamic = false;\n\n const convertedRoute = convertSegmentsToRouteParts(segments);\n if (!convertedRoute) return null;\n\n const { urlSegments, params: routeParams, isDynamic: routeIsDynamic } = convertedRoute;\n params.push(...routeParams);\n isDynamic = routeIsDynamic;\n\n const pattern = \"/\" + urlSegments.join(\"/\");\n\n // Discover layouts and templates from root to leaf\n const layouts = discoverLayouts(segments, appDir, matcher);\n const templates = discoverTemplates(segments, appDir, matcher);\n const templateTreePositions = computeLayoutTreePositions(appDir, templates);\n\n // Compute the tree position (directory depth) for each layout.\n const layoutTreePositions = computeLayoutTreePositions(appDir, layouts);\n\n // Discover per-segment error boundaries. Next.js loader trees carry an\n // error convention for a segment even when that segment has no layout.\n // In Next.js, each segment independently wraps its children with an ErrorBoundary.\n // This array enables interleaving error boundaries with layouts in the rendering.\n const layoutErrorPaths = discoverLayoutAlignedErrors(segments, appDir, matcher);\n const errorEntries = discoverSegmentErrors(segments, appDir, matcher);\n const errorPaths = errorEntries.map((entry) => entry.path);\n const errorTreePositions = errorEntries.map((entry) => entry.treePosition);\n\n // Discover loading, error in the route's directory\n const routeDir = dir === \".\" ? appDir : path.join(appDir, dir);\n const loadingPath = findFile(routeDir, \"loading\", matcher);\n const errorPath = findFile(routeDir, \"error\", matcher);\n\n // Discover not-found/forbidden/unauthorized: walk from route directory up to root (nearest wins).\n const notFoundPath = discoverBoundaryFile(segments, appDir, \"not-found\", matcher);\n const forbiddenPath = discoverBoundaryFile(segments, appDir, \"forbidden\", matcher);\n const unauthorizedPath = discoverBoundaryFile(segments, appDir, \"unauthorized\", matcher);\n\n // Discover per-layout not-found files (one per layout directory).\n // These are used for per-layout NotFoundBoundary to match Next.js behavior where\n // notFound() thrown from a layout is caught by the parent layout's boundary.\n const notFoundPaths = discoverBoundaryFilePerLayout(layouts, \"not-found\", matcher);\n const forbiddenPaths = discoverBoundaryFilePerLayout(layouts, \"forbidden\", matcher);\n const unauthorizedPaths = discoverBoundaryFilePerLayout(layouts, \"unauthorized\", matcher);\n\n // Discover parallel slots (@team, @analytics, etc.).\n // Slots at the route's own directory use page.tsx; slots at ancestor directories\n // (inherited from parent layouts) use default.tsx as fallback.\n const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher);\n\n return {\n ids: createAppRouteSemanticIds({\n pattern: pattern === \"/\" ? \"/\" : pattern,\n pagePath,\n routePath,\n routeSegments: segments,\n layoutTreePositions,\n templateTreePositions,\n slots: parallelSlots,\n }),\n pattern: pattern === \"/\" ? \"/\" : pattern,\n pagePath,\n routePath,\n layouts,\n templates,\n parallelSlots,\n loadingPath,\n errorPath,\n layoutErrorPaths,\n errorPaths,\n errorTreePositions,\n notFoundPath,\n notFoundPaths,\n forbiddenPaths,\n forbiddenPath,\n unauthorizedPath,\n unauthorizedPaths,\n routeSegments: segments,\n templateTreePositions,\n layoutTreePositions,\n isDynamic,\n params,\n rootParamNames: computeRootParamNames(segments, layoutTreePositions),\n patternParts: urlSegments,\n };\n}\n\nfunction dynamicParamNameFromSegment(segment: string): string | null {\n if (segment.startsWith(\"[[...\") && segment.endsWith(\"]]\")) return segment.slice(5, -2);\n if (segment.startsWith(\"[...\") && segment.endsWith(\"]\")) return segment.slice(4, -1);\n if (segment.startsWith(\"[\") && segment.endsWith(\"]\")) return segment.slice(1, -1);\n return null;\n}\n\nexport function computeRootParamNames(\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n): string[] {\n const rootLayoutPosition = layoutTreePositions[0];\n if (rootLayoutPosition == null || rootLayoutPosition <= 0) return [];\n\n const names: string[] = [];\n for (const segment of routeSegments.slice(0, rootLayoutPosition)) {\n const name = dynamicParamNameFromSegment(segment);\n if (name && !names.includes(name)) names.push(name);\n }\n return names;\n}\n\nfunction resolveRootBoundaryId(\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n): RootBoundaryId | null {\n const rootLayoutPosition = layoutTreePositions[0];\n if (rootLayoutPosition === undefined) return null;\n\n // Position 0 is the app root layout and still owns a real root boundary.\n // Only a missing layout position means the route is layoutless.\n return createAppRouteGraphRootBoundaryId(\n createAppRouteGraphTreePath(routeSegments, rootLayoutPosition),\n );\n}\n\nfunction createAppRouteSemanticIds(input: {\n pattern: string;\n pagePath: string | null;\n routePath: string | null;\n routeSegments: readonly string[];\n layoutTreePositions: readonly number[];\n templateTreePositions?: readonly number[];\n slots: readonly AppRouteGraphParallelSlot[];\n}): AppRouteSemanticIds {\n const slots: Record<string, string> = {};\n for (const slot of input.slots) {\n slots[slot.key] = slot.id;\n }\n\n return {\n route: createAppRouteGraphRouteId(input.pattern),\n page: input.pagePath ? createAppRouteGraphPageId(input.pattern) : null,\n routeHandler: input.routePath ? createAppRouteGraphRouteHandlerId(input.pattern) : null,\n rootBoundary: resolveRootBoundaryId(input.routeSegments, input.layoutTreePositions),\n layouts: input.layoutTreePositions.map((treePosition) =>\n createAppRouteGraphLayoutId(createAppRouteGraphTreePath(input.routeSegments, treePosition)),\n ),\n templates: (input.templateTreePositions ?? []).map((treePosition) =>\n createAppRouteGraphTemplateId(createAppRouteGraphTreePath(input.routeSegments, treePosition)),\n ),\n slots,\n };\n}\n\nfunction createAppRouteGraphTreePath(\n routeSegments: readonly string[],\n treePosition: number,\n): string {\n const treePathSegments = routeSegments.slice(0, treePosition);\n if (treePathSegments.length === 0) {\n return \"/\";\n }\n return `/${treePathSegments.join(\"/\")}`;\n}\n\nfunction convertTreePathToRouteParts(treePath: string): {\n urlSegments: string[];\n params: string[];\n} {\n if (treePath === \"/\") return { urlSegments: [], params: [] };\n const segments = treePath.split(\"/\").filter(Boolean);\n const routeParts = convertSegmentsToRouteParts(segments);\n if (!routeParts) {\n throw new Error(`Invalid App Router layout tree path \"${treePath}\".`);\n }\n return { urlSegments: routeParts.urlSegments, params: routeParts.params };\n}\n\n/**\n * Compute the tree position (directory depth from app root) for each layout.\n * Root layout = 0, a layout at app/blog/ = 1, app/blog/(group)/ = 2.\n * Counts ALL directory levels including route groups and parallel slots.\n */\nfunction computeLayoutTreePositions(appDir: string, layouts: string[]): number[] {\n return layouts.map((layoutPath) => {\n const layoutDir = path.dirname(layoutPath);\n if (layoutDir === appDir) return 0;\n const relative = path.relative(appDir, layoutDir);\n return relative.split(path.sep).length;\n });\n}\n\n/**\n * Discover all layout files from root to the given directory.\n * Each level of the directory tree may have a layout.tsx.\n */\nfunction discoverLayouts(segments: string[], appDir: string, matcher: ValidFileMatcher): string[] {\n const layouts: string[] = [];\n\n // Check root layout\n const rootLayout = findFile(appDir, \"layout\", matcher);\n if (rootLayout) layouts.push(rootLayout);\n\n // Check each directory level\n let currentDir = appDir;\n for (const segment of segments) {\n currentDir = path.join(currentDir, segment);\n const layout = findFile(currentDir, \"layout\", matcher);\n if (layout) layouts.push(layout);\n }\n\n return layouts;\n}\n\n/**\n * Discover all template files from root to the given directory.\n * Each level of the directory tree may have a template.tsx.\n * Templates are like layouts but re-mount on navigation.\n */\nfunction discoverTemplates(\n segments: string[],\n appDir: string,\n matcher: ValidFileMatcher,\n): string[] {\n const templates: string[] = [];\n\n // Check root template\n const rootTemplate = findFile(appDir, \"template\", matcher);\n if (rootTemplate) templates.push(rootTemplate);\n\n // Check each directory level\n let currentDir = appDir;\n for (const segment of segments) {\n currentDir = path.join(currentDir, segment);\n const template = findFile(currentDir, \"template\", matcher);\n if (template) templates.push(template);\n }\n\n return templates;\n}\n\n/**\n * Discover error.tsx files by segment tree position.\n *\n * Next.js stores conventions on every loader-tree segment; a route-group\n * directory with error.tsx but no sibling layout.tsx must still wrap its\n * descendants. Keeping positions explicit avoids conflating segment boundaries\n * with layout component ownership.\n */\nfunction discoverSegmentErrors(\n segments: string[],\n appDir: string,\n matcher: ValidFileMatcher,\n): { path: string; treePosition: number }[] {\n const errors: { path: string; treePosition: number }[] = [];\n\n const rootError = findFile(appDir, \"error\", matcher);\n if (rootError) {\n errors.push({ path: rootError, treePosition: 0 });\n }\n\n // Check each directory level\n let currentDir = appDir;\n for (let index = 0; index < segments.length; index++) {\n const segment = segments[index];\n currentDir = path.join(currentDir, segment);\n const error = findFile(currentDir, \"error\", matcher);\n if (error) {\n errors.push({ path: error, treePosition: index + 1 });\n }\n }\n\n return errors;\n}\n\n/**\n * Discover error.tsx files aligned with the layouts array.\n *\n * Route manifests still model layout-owned boundary facts by layout index.\n * Keep this layout-aligned compatibility shape separate from segment-owned\n * error boundaries so route-group errors without layouts do not get attributed\n * to unrelated layouts.\n */\nfunction discoverLayoutAlignedErrors(\n segments: string[],\n appDir: string,\n matcher: ValidFileMatcher,\n): (string | null)[] {\n const errors: (string | null)[] = [];\n\n const rootLayout = findFile(appDir, \"layout\", matcher);\n if (rootLayout) {\n errors.push(findFile(appDir, \"error\", matcher));\n }\n\n let currentDir = appDir;\n for (const segment of segments) {\n currentDir = path.join(currentDir, segment);\n const layout = findFile(currentDir, \"layout\", matcher);\n if (layout) {\n errors.push(findFile(currentDir, \"error\", matcher));\n }\n }\n\n return errors;\n}\n\n/**\n * Discover the nearest boundary file (not-found, forbidden, unauthorized)\n * by walking from the route's directory up to the app root.\n * Returns the first (closest) file found, or null.\n */\nfunction discoverBoundaryFile(\n segments: string[],\n appDir: string,\n fileName: string,\n matcher: ValidFileMatcher,\n): string | null {\n // Build all directory paths from leaf to root\n const dirs: string[] = [];\n let dir = appDir;\n dirs.push(dir);\n for (const segment of segments) {\n dir = path.join(dir, segment);\n dirs.push(dir);\n }\n\n // Walk from leaf (last) to root (first)\n for (let i = dirs.length - 1; i >= 0; i--) {\n const f = findFile(dirs[i], fileName, matcher);\n if (f) return f;\n }\n return null;\n}\n\n/**\n * Discover boundary files (not-found, forbidden, unauthorized) at each layout directory.\n * Returns an array aligned with the layouts array, where each entry is the boundary\n * file at that layout's directory, or null if none exists there.\n *\n * This is used for per-layout error boundaries. In Next.js, each layout level\n * has its own boundary that wraps the layout's children. When notFound() is thrown\n * from a layout, it propagates up to the parent layout's boundary.\n */\nfunction discoverBoundaryFilePerLayout(\n layouts: string[],\n fileName: string,\n matcher: ValidFileMatcher,\n): (string | null)[] {\n return layouts.map((layoutPath) => {\n const layoutDir = path.dirname(layoutPath);\n return findFile(layoutDir, fileName, matcher);\n });\n}\n\n/**\n * Discover parallel slots inherited from ancestor directories.\n *\n * In Next.js, parallel slots belong to the layout that defines them. When a\n * child route is rendered, its parent layout's slots must still be present.\n * If the child doesn't have matching content in a slot, the slot's default.tsx\n * is rendered instead.\n *\n * Walk from appDir through each segment to the route's directory. At each level\n * that has @slot dirs, collect them. Slots at the route's own directory level\n * use page.tsx; slots at ancestor levels use default.tsx only.\n */\nfunction discoverInheritedParallelSlots(\n segments: string[],\n appDir: string,\n routeDir: string,\n matcher: ValidFileMatcher,\n): AppRouteGraphParallelSlot[] {\n const slotMap = new Map<string, AppRouteGraphParallelSlot>();\n\n // Walk from appDir through each segment, tracking layout indices.\n // layoutIndex tracks which position in the route's layouts[] array corresponds\n // to a given directory. Only directories with a layout.tsx file increment.\n // segmentIndex aligns each entry with `segments`: dirsToCheck[i] is reached\n // after consuming segments[0..i-1], so segments.slice(i) are the segments\n // below this directory (used to mirror inherited slot sub-pages).\n let currentDir = appDir;\n const dirsToCheck: { dir: string; layoutIdx: number; segmentIndex: number }[] = [];\n let layoutIdx = findFile(appDir, \"layout\", matcher) ? 0 : -1;\n dirsToCheck.push({ dir: appDir, layoutIdx, segmentIndex: 0 });\n\n for (let i = 0; i < segments.length; i++) {\n currentDir = path.join(currentDir, segments[i]);\n if (findFile(currentDir, \"layout\", matcher)) {\n layoutIdx++;\n }\n dirsToCheck.push({ dir: currentDir, layoutIdx, segmentIndex: i + 1 });\n }\n\n const routeHasLayout = layoutIdx >= 0;\n\n for (const { dir, layoutIdx: lvlLayoutIdx, segmentIndex } of dirsToCheck) {\n // Once a route has a root layout below app/, slots discovered before that\n // layout are above the root and cannot be owned by any layout in this route.\n // Layout-less routes keep their legacy slot metadata here; validation is separate.\n if (lvlLayoutIdx < 0 && routeHasLayout) continue;\n\n const isOwnDir = dir === routeDir;\n const slotLayoutIdx = Math.max(lvlLayoutIdx, 0);\n const slotsAtLevel = discoverParallelSlots(dir, appDir, matcher);\n const segmentsBelow = segments.slice(segmentIndex);\n\n for (const slot of slotsAtLevel) {\n if (isOwnDir) {\n // At the route's own directory: use page.tsx (normal behavior)\n slot.layoutIndex = slotLayoutIdx;\n slotMap.set(slot.key, slot);\n } else {\n // At an ancestor directory: the slot's own page.tsx belongs to the\n // parent route. Look for a mirrored sub-page at @slot/<segments-below>\n // (e.g. @breadcrumbs/about/page.tsx for /about), falling back to\n // default.tsx when no mirror exists. The mirror search also accepts\n // pattern-compatible matches (e.g. slot's [name] for route's [id]) so\n // the runtime can extract slot-specific params via slotPatternParts.\n const mirror = findMirroredSlotPage(slot.ownerDir, segmentsBelow, matcher);\n let slotPatternParts: string[] | undefined;\n let slotParamNames: string[] | undefined;\n if (mirror) {\n const ownerSegments = segments.slice(0, segmentIndex);\n const ownerUrl = convertSegmentsToRouteParts([...ownerSegments]);\n slotPatternParts = [...(ownerUrl?.urlSegments ?? []), ...mirror.slotUrlSegments];\n slotParamNames = [...(ownerUrl?.params ?? []), ...mirror.slotParamNames];\n }\n const inheritedSlot: AppRouteGraphParallelSlot = {\n ...slot,\n pagePath: mirror?.pagePath ?? null,\n layoutIndex: slotLayoutIdx,\n routeSegments: mirror?.segments ?? null,\n slotPatternParts,\n slotParamNames,\n // defaultPath, loadingPath, errorPath, interceptingRoutes remain\n };\n slotMap.set(slot.key, inheritedSlot);\n }\n }\n }\n\n return Array.from(slotMap.values());\n}\n\n/**\n * Look for a page file inside a parallel slot directory that mirrors the\n * route's path below the slot's owner. The match falls through two tiers:\n * 1. Literal filesystem path — fast path when route and slot share shape.\n * 2. Scored pattern compatibility — enumerate sub-pages, accept those\n * whose URL pattern can match the route's URL space (slot dynamic\n * markers may have different names than the route's, and slot\n * catch-alls may subsume the route), and pick the most-specific via\n * `scoreSlotPattern`. Exact URL-parts equality (e.g. through route\n * groups appearing on only one side, like `(marketing)/about` ↔\n * `@breadcrumbs/about`) naturally wins because all literal segments\n * score highest.\n *\n * Returns the slot sub-page's absolute path, its raw filesystem segments\n * (for `routeSegments`), and its URL parts / param names (for\n * `slotPatternParts` / `slotParamNames`). Returns null when no mirror matches.\n */\nfunction findMirroredSlotPage(\n slotDir: string,\n segmentsBelow: readonly string[],\n matcher: ValidFileMatcher,\n): {\n pagePath: string;\n segments: string[];\n slotUrlSegments: string[];\n slotParamNames: string[];\n} | null {\n if (segmentsBelow.length === 0) return null;\n\n // Convert once: both tiers need the URL form of the route's segments below\n // this directory.\n const routeUrl = convertSegmentsToRouteParts([...segmentsBelow]);\n\n // Tier 1: literal filesystem match.\n const literalDir = path.join(slotDir, ...segmentsBelow);\n const literalPage = findFile(literalDir, \"page\", matcher);\n if (literalPage) {\n return {\n pagePath: literalPage,\n segments: [...segmentsBelow],\n slotUrlSegments: routeUrl?.urlSegments ?? [],\n slotParamNames: routeUrl?.params ?? [],\n };\n }\n\n if (!routeUrl || routeUrl.urlSegments.length === 0) return null;\n\n // Tier 2: enumerate slot sub-pages and pick the most-specific compatible\n // pattern. Exact URL-parts matches naturally win the score.\n type Candidate = {\n pagePath: string;\n segments: string[];\n slotUrlSegments: string[];\n slotParamNames: string[];\n score: number;\n };\n let best: Candidate | null = null;\n for (const { relativePath, pagePath } of findSlotSubPages(slotDir, matcher)) {\n const slotSegments = relativePath.split(path.sep);\n const slotUrl = convertSegmentsToRouteParts(slotSegments);\n if (!slotUrl) continue;\n if (!patternsCompatible(slotUrl.urlSegments, routeUrl.urlSegments)) continue;\n const score = scoreSlotPattern(slotUrl.urlSegments);\n if (!best || score > best.score) {\n best = {\n pagePath,\n segments: slotSegments,\n slotUrlSegments: slotUrl.urlSegments,\n slotParamNames: slotUrl.params,\n score,\n };\n }\n }\n\n return best;\n}\n\n/**\n * Whether a slot pattern can match the same URL space as the route's URL\n * parts (where the route's parts are themselves a pattern, since a route\n * file like `[id]/page.tsx` produces `:id`).\n *\n * - `:name+` (catch-all) consumes one-or-more remaining segments.\n * - `:name*` (optional catch-all) consumes zero-or-more.\n * - `:name` (single dynamic) consumes exactly one segment, matching any\n * route segment (literal or dynamic).\n * - Literal slot segments must equal the route's segment exactly; a literal\n * slot segment paired with a dynamic route segment is rejected because we\n * can't know statically whether the runtime value will equal the literal.\n * This also means a literal slot sub-page never matches a catch-all route\n * (e.g. slot `about/page.tsx` is not bound to a route `[...slug]`) — the\n * catch-all might or might not resolve to \"about\" at request time.\n */\nfunction patternsCompatible(slotParts: readonly string[], routeParts: readonly string[]): boolean {\n let i = 0;\n let j = 0;\n while (i < slotParts.length) {\n const sp = slotParts[i];\n if (sp.endsWith(\"+\")) return j < routeParts.length;\n if (sp.endsWith(\"*\")) return true;\n if (j >= routeParts.length) return false;\n const rp = routeParts[j];\n if (sp.startsWith(\":\")) {\n i++;\n j++;\n continue;\n }\n if (rp.startsWith(\":\")) return false;\n if (sp !== rp) return false;\n i++;\n j++;\n }\n return j === routeParts.length;\n}\n\n/**\n * Score a slot pattern by specificity so the most-specific match wins:\n * literal > single dynamic > catch-all > optional catch-all.\n *\n * Required catch-all (`:name+`, ≥1 segment) is more constrained than the\n * optional variant (`:name*`, ≥0 segments), so it scores higher.\n */\nfunction scoreSlotPattern(urlSegments: readonly string[]): number {\n let score = 0;\n for (const seg of urlSegments) {\n if (seg.endsWith(\"*\")) score += 1;\n else if (seg.endsWith(\"+\")) score += 2;\n else if (seg.startsWith(\":\")) score += 3;\n else score += 4;\n }\n return score;\n}\n\n/**\n * Map a pattern segment to the tree-node type used by Next.js' route\n * validator. Two segments are structurally equivalent iff they share the\n * same tree-node type.\n */\nfunction segmentTreeNodeType(seg: string): string {\n if (!seg.startsWith(\":\")) return `literal:${seg}`;\n if (seg.endsWith(\"*\")) return \"optionalCatchAll\";\n if (seg.endsWith(\"+\")) return \"catchAll\";\n return \"dynamic\";\n}\n\nfunction patternsStructurallyEquivalent(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (segmentTreeNodeType(a[i]) !== segmentTreeNodeType(b[i])) return false;\n }\n return true;\n}\n\n/**\n * Discover parallel route slots (@team, @analytics, etc.) in a directory.\n * Returns a ParallelSlot for each @-prefixed subdirectory that has a page or default component.\n */\nfunction discoverParallelSlots(\n dir: string,\n appDir: string,\n matcher: ValidFileMatcher,\n): AppRouteGraphParallelSlot[] {\n if (!fs.existsSync(dir)) return [];\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n const slots: AppRouteGraphParallelSlot[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.startsWith(\"@\")) continue;\n\n const slotName = entry.name.slice(1); // \"@team\" -> \"team\"\n const slotDir = path.join(dir, entry.name);\n\n const pagePath = findFile(slotDir, \"page\", matcher);\n const defaultPath = findFile(slotDir, \"default\", matcher);\n const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);\n\n // Only include slots that have at least a page, default, or intercepting route\n if (!pagePath && !defaultPath && interceptingRoutes.length === 0) continue;\n\n const ownerSegments = path\n .relative(appDir, dir)\n .split(path.sep)\n .filter((segment) => segment.length > 0);\n const ownerTreePath = createAppRouteGraphTreePath(ownerSegments, ownerSegments.length);\n\n slots.push({\n id: createAppRouteGraphSlotId(slotName, ownerTreePath),\n key: `${slotName}@${path.relative(appDir, slotDir).replace(/\\\\/g, \"/\")}`,\n name: slotName,\n ownerDir: slotDir,\n ownerTreePath,\n hasPage: pagePath !== null,\n pagePath,\n defaultPath,\n layoutPath: findFile(slotDir, \"layout\", matcher),\n loadingPath: findFile(slotDir, \"loading\", matcher),\n errorPath: findFile(slotDir, \"error\", matcher),\n interceptingRoutes,\n layoutIndex: -1, // Will be set by discoverInheritedParallelSlots\n routeSegments: pagePath ? [] : null,\n });\n }\n\n return slots;\n}\n\n/**\n * The interception convention prefix patterns.\n * (.) — same level, (..) — one level up, (..)(..)\" — two levels up, (...) — root\n */\nconst INTERCEPT_PATTERNS = [\n { prefix: \"(...)\", convention: \"...\" },\n { prefix: \"(..)(..)\", convention: \"../..\" },\n { prefix: \"(..)\", convention: \"..\" },\n { prefix: \"(.)\", convention: \".\" },\n] as const;\n\n/**\n * Check whether a directory name begins with an interception route marker.\n *\n * Matches the prefixes listed in {@link INTERCEPT_PATTERNS}: `(.)`, `(..)`,\n * `(...)`, `(..)(..)`. The marker is not a real URL segment, so the global\n * page/route scanner must skip these directories to avoid materialising\n * literal patterns like `/templates/(..)showcase`. Interception target\n * registration happens separately via {@link discoverInterceptingRoutes}.\n */\nfunction isInterceptionMarkerDir(name: string): boolean {\n return matchInterceptConvention(name) !== null;\n}\n\n/**\n * Discover intercepting routes inside a parallel slot directory.\n *\n * Intercepting routes use conventions like (.)photo, (..)feed, (...), etc.\n * They intercept navigation to another route and render within the slot instead.\n *\n * @param slotDir - The parallel slot directory (e.g. app/feed/@modal)\n * @param routeDir - The directory of the route that owns this slot (e.g. app/feed)\n * @param appDir - The root app directory\n */\nfunction discoverInterceptingRoutes(\n slotDir: string,\n routeDir: string,\n appDir: string,\n matcher: ValidFileMatcher,\n): InterceptingRoute[] {\n if (!fs.existsSync(slotDir)) return [];\n\n const results: InterceptingRoute[] = [];\n\n // Recursively scan for page files inside intercepting directories\n scanForInterceptingPages(slotDir, routeDir, appDir, results, matcher);\n\n return results;\n}\n\n/**\n * Recursively scan a directory tree for page.tsx files that are inside\n * intercepting route directories.\n */\nfunction scanForInterceptingPages(\n currentDir: string,\n routeDir: string,\n appDir: string,\n results: InterceptingRoute[],\n matcher: ValidFileMatcher,\n): void {\n if (!fs.existsSync(currentDir)) return;\n\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip private folders (prefixed with _)\n if (entry.name.startsWith(\"_\")) continue;\n\n // Check if this directory name starts with an interception convention\n const interceptMatch = matchInterceptConvention(entry.name);\n\n if (interceptMatch) {\n // This directory is the start of an intercepting route\n // e.g. \"(.)photos\" means intercept same-level \"photos\" route\n const restOfName = entry.name.slice(interceptMatch.prefix.length);\n const interceptDir = path.join(currentDir, entry.name);\n\n // Find page files within this intercepting directory tree.\n // `currentDir` is the *parent* of the marker dir — used by\n // computeInterceptSourceMatchPattern to derive the intercepting-route\n // URL (the path that owns the slot containing the marker).\n collectInterceptingPages(\n interceptDir,\n interceptDir,\n interceptMatch.convention,\n restOfName,\n routeDir,\n appDir,\n currentDir,\n results,\n matcher,\n );\n } else {\n // Regular subdirectory — keep scanning for intercepting dirs\n scanForInterceptingPages(\n path.join(currentDir, entry.name),\n routeDir,\n appDir,\n results,\n matcher,\n );\n }\n }\n}\n\n/**\n * Match a directory name against interception convention prefixes.\n */\nfunction matchInterceptConvention(name: string): { prefix: string; convention: string } | null {\n for (const pattern of INTERCEPT_PATTERNS) {\n if (name.startsWith(pattern.prefix)) {\n return pattern;\n }\n }\n return null;\n}\n\n/**\n * Collect page.tsx files inside an intercepting route directory tree\n * and compute their target URL patterns.\n */\nfunction collectInterceptingPages(\n currentDir: string,\n interceptRoot: string,\n convention: string,\n interceptSegment: string,\n routeDir: string,\n appDir: string,\n /**\n * Filesystem directory that owns the slot containing the interception\n * marker — i.e. the parent of the marker dir. Used to derive the\n * intercepting-route URL pattern that gates `findIntercept` at request\n * time. With route groups and `@slot` segments stripped, this becomes\n * Next.js' `interceptingRoute`.\n */\n interceptParentDir: string,\n results: InterceptingRoute[],\n matcher: ValidFileMatcher,\n parentLayoutPaths: readonly string[] = [],\n): void {\n const currentLayoutPath = findFile(currentDir, \"layout\", matcher);\n const layoutPaths = currentLayoutPath\n ? [...parentLayoutPaths, currentLayoutPath]\n : parentLayoutPaths;\n\n // Check for page.tsx in current directory\n const page = findFile(currentDir, \"page\", matcher);\n if (page) {\n const targetPattern = computeInterceptTarget(\n convention,\n interceptSegment,\n currentDir,\n interceptRoot,\n routeDir,\n appDir,\n );\n if (targetPattern) {\n const sourceMatchPattern = computeInterceptSourceMatchPattern(interceptParentDir, appDir);\n results.push({\n convention,\n layoutPaths: [...layoutPaths],\n targetPattern: targetPattern.pattern,\n sourceMatchPattern,\n pagePath: page,\n params: targetPattern.params,\n });\n }\n }\n\n // Recurse into subdirectories for nested intercepting routes\n if (!fs.existsSync(currentDir)) return;\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip private folders (prefixed with _)\n if (entry.name.startsWith(\"_\")) continue;\n collectInterceptingPages(\n path.join(currentDir, entry.name),\n interceptRoot,\n convention,\n interceptSegment,\n routeDir,\n appDir,\n interceptParentDir,\n results,\n matcher,\n layoutPaths,\n );\n }\n}\n\n/**\n * Compute the URL pattern for the *intercepting route* — the path that\n * owns the slot containing the interception marker. Route groups (`(name)`)\n * and parallel slots (`@slot`) are stripped because Next.js'\n * `normalizeAppPath` treats them as invisible in the URL.\n *\n * Mirrors Next.js' computation in `extractInterceptionRouteInformation`:\n * `interceptingRoute = normalizeAppPath(path.split(marker, 2)[0])`.\n *\n * Returns `/` for the app root.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/interception-routes.ts\n */\nfunction computeInterceptSourceMatchPattern(interceptParentDir: string, appDir: string): string {\n const segments = path.relative(appDir, interceptParentDir).split(path.sep).filter(Boolean);\n const converted = convertSegmentsToRouteParts(segments);\n const urlSegments = converted\n ? converted.urlSegments\n : segments.filter((segment) => !isInvisibleSegment(segment));\n if (urlSegments.length === 0) return \"/\";\n return \"/\" + urlSegments.join(\"/\");\n}\n\n/**\n * Check whether a path segment is invisible in the URL (route groups, parallel slots, \".\").\n *\n * Used by computeInterceptTarget, convertSegmentsToRouteParts, and\n * hasRemainingVisibleSegments — keep this the single source of truth.\n */\nexport function isInvisibleSegment(segment: string): boolean {\n if (segment === \".\") return true;\n if (segment.startsWith(\"(\") && segment.endsWith(\")\")) return true;\n if (segment.startsWith(\"@\")) return true;\n return false;\n}\n\n/**\n * Compute the target URL pattern for an intercepting route.\n *\n * Interception conventions (..), (..)(..)\" climb by *visible route segments*\n * (not filesystem directories). Route groups like (marketing) and parallel\n * slots like @modal are invisible and must be skipped when counting levels.\n *\n * - (.) same level: resolve relative to routeDir\n * - (..) one level up: climb 1 visible segment\n * - (..)(..) two levels up: climb 2 visible segments\n * - (...) root: resolve from appDir\n */\nfunction computeInterceptTarget(\n convention: string,\n interceptSegment: string,\n currentDir: string,\n interceptRoot: string,\n routeDir: string,\n appDir: string,\n): { pattern: string; params: string[] } | null {\n // Determine the base segments for target resolution.\n // We work on route segments (not filesystem paths) so that route groups\n // and parallel slots are properly skipped when climbing.\n const routeSegments = path.relative(appDir, routeDir).split(path.sep).filter(Boolean);\n\n let baseParts: string[];\n switch (convention) {\n case \".\":\n baseParts = routeSegments;\n break;\n case \"..\":\n case \"../..\": {\n const levelsToClimb = convention === \"..\" ? 1 : 2;\n let climbed = 0;\n let cutIndex = routeSegments.length;\n while (cutIndex > 0 && climbed < levelsToClimb) {\n cutIndex--;\n if (!isInvisibleSegment(routeSegments[cutIndex])) {\n climbed++;\n }\n }\n if (climbed < levelsToClimb) {\n const interceptionRoute = formatInterceptionRoutePath(\n routeSegments,\n convention,\n interceptSegment,\n path.relative(interceptRoot, currentDir).split(path.sep).filter(Boolean),\n );\n if (convention === \"..\") {\n throw new Error(\n `Invalid interception route: ${interceptionRoute}. Cannot use (..) marker at the root level, use (.) instead.`,\n );\n }\n throw new Error(\n `Invalid interception route: ${interceptionRoute}. Cannot use (..)(..) marker at the root level or one level up.`,\n );\n }\n baseParts = routeSegments.slice(0, cutIndex);\n break;\n }\n case \"...\":\n baseParts = [];\n break;\n default:\n return null;\n }\n\n // Add the intercept segment and any nested path segments\n const nestedParts = path.relative(interceptRoot, currentDir).split(path.sep).filter(Boolean);\n const allSegments = [...baseParts, interceptSegment, ...nestedParts];\n\n const convertedTarget = convertSegmentsToRouteParts(allSegments);\n if (!convertedTarget) return null;\n\n const { urlSegments, params } = convertedTarget;\n\n const pattern = \"/\" + urlSegments.join(\"/\");\n return { pattern: pattern === \"/\" ? \"/\" : pattern, params };\n}\n\nfunction formatInterceptionRoutePath(\n routeSegments: string[],\n convention: string,\n interceptSegment: string,\n nestedParts: string[],\n): string {\n const marker = markerForInterceptionConvention(convention);\n const convertedRoute = convertSegmentsToRouteParts(routeSegments);\n const prefix = convertedRoute\n ? convertedRoute.urlSegments\n : routeSegments.filter((segment) => !isInvisibleSegment(segment));\n const routePath = [...prefix, `${marker}${interceptSegment}`, ...nestedParts]\n .filter(Boolean)\n .join(\"/\");\n return routePath ? `/${routePath}` : \"/\";\n}\n\nfunction markerForInterceptionConvention(convention: string): string {\n switch (convention) {\n case \".\":\n return \"(.)\";\n case \"..\":\n return \"(..)\";\n case \"../..\":\n return \"(..)(..)\";\n case \"...\":\n return \"(...)\";\n default:\n return \"\";\n }\n}\n\n/**\n * Find a file by name (without extension) in a directory.\n * Checks configured pageExtensions.\n */\nfunction findFile(dir: string, name: string, matcher: ValidFileMatcher): string | null {\n for (const ext of matcher.dottedExtensions) {\n const filePath = path.join(dir, name + ext);\n if (fs.existsSync(filePath)) return filePath;\n }\n return null;\n}\n\n/**\n * Convert filesystem path segments to URL route parts, skipping invisible segments\n * (route groups, @slots, \".\") and converting dynamic segment syntax to Express-style\n * patterns (e.g. \"[id]\" → \":id\", \"[...slug]\" → \":slug+\").\n */\nexport function convertSegmentsToRouteParts(\n segments: readonly string[],\n): { urlSegments: string[]; params: string[]; isDynamic: boolean } | null {\n const urlSegments: string[] = [];\n const params: string[] = [];\n let isDynamic = false;\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n\n if (isInvisibleSegment(segment)) continue;\n\n // Catch-all segments are only valid in terminal URL position.\n // Matches Next.js PARAMETER_PATTERN: any non-] chars inside brackets.\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/get-dynamic-param.ts\n const catchAllMatch = segment.match(/^\\[\\.\\.\\.([^\\]]+)\\]$/);\n if (catchAllMatch) {\n if (hasRemainingVisibleSegments(segments, i + 1)) return null;\n // Guard: names ending in + or * would collide with internal pattern\n // modifiers (:name+ catch-all, :name* optional-catch-all).\n if (catchAllMatch[1].endsWith(\"+\") || catchAllMatch[1].endsWith(\"*\")) return null;\n isDynamic = true;\n params.push(catchAllMatch[1]);\n urlSegments.push(`:${catchAllMatch[1]}+`);\n continue;\n }\n\n const optionalCatchAllMatch = segment.match(/^\\[\\[\\.\\.\\.([^\\]]+)\\]\\]$/);\n if (optionalCatchAllMatch) {\n if (hasRemainingVisibleSegments(segments, i + 1)) return null;\n if (optionalCatchAllMatch[1].endsWith(\"+\") || optionalCatchAllMatch[1].endsWith(\"*\"))\n return null;\n isDynamic = true;\n params.push(optionalCatchAllMatch[1]);\n urlSegments.push(`:${optionalCatchAllMatch[1]}*`);\n continue;\n }\n\n const dynamicMatch = segment.match(/^\\[([^\\]]+)\\]$/);\n if (dynamicMatch) {\n if (dynamicMatch[1].endsWith(\"+\") || dynamicMatch[1].endsWith(\"*\")) return null;\n isDynamic = true;\n params.push(dynamicMatch[1]);\n urlSegments.push(`:${dynamicMatch[1]}`);\n continue;\n }\n\n urlSegments.push(decodeRouteSegment(segment));\n }\n\n return { urlSegments, params, isDynamic };\n}\n\nfunction hasRemainingVisibleSegments(segments: readonly string[], startIndex: number): boolean {\n for (let i = startIndex; i < segments.length; i++) {\n if (!isInvisibleSegment(segments[i])) return true;\n }\n return false;\n}\n\nfunction joinRoutePattern(basePattern: string, subPath: string): string {\n if (!subPath) return basePattern;\n return basePattern === \"/\" ? `/${subPath}` : `${basePattern}/${subPath}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-route-graph.js","names":[],"sources":["../../src/routing/app-route-graph.ts"],"sourcesContent":["/**\n * App Router route graph construction.\n *\n * Scans app/ directories and materializes route metadata before the request-time\n * matcher consumes it. Keep request matching and cache ownership in app-router.ts.\n */\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { compareRoutes, decodeRouteSegment } from \"./utils.js\";\nimport { scanWithExtensions, type ValidFileMatcher } from \"./file-matcher.js\";\nimport { validateRoutePatterns } from \"./route-validation.js\";\n\nexport type InterceptingRoute = {\n /** The interception convention: \".\" | \"..\" | \"../..\" | \"...\" */\n convention: string;\n /** The URL pattern this intercepts (e.g. \"/photos/:id\") */\n targetPattern: string;\n /**\n * URL pattern of the *intercepting route* — the path that owns the slot\n * containing this interception marker, with route groups and `@slot`\n * segments stripped. Mirrors Next.js' `interceptingRoute` from\n * `extractInterceptionRouteInformation`.\n *\n * Used at request time to gate `findIntercept` against the Next-URL /\n * interception-context header: an intercept only fires when the source\n * pathname matches `^<sourceMatchPattern>(?:/.*)?$`. Without this gate\n * a direct RSC fetch to the intercept target would render the modal\n * instead of the underlying page.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/lib/generate-interception-routes-rewrites.ts\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/interception-routes.ts\n */\n sourceMatchPattern: string;\n /** Absolute path to the intercepting page component */\n pagePath: string;\n /** Absolute layout paths inside the intercepting route tree, outermost to innermost */\n layoutPaths: string[];\n /** Parameter names for dynamic segments */\n params: string[];\n};\n\nexport type ParallelSlot = {\n /** Graph-owned semantic slot identity. Required on AppRouteGraphParallelSlot. */\n id?: string;\n /** Stable slot identity (name + owning directory), used for route serialization keys. */\n key: string;\n /** Slot name (e.g. \"team\" from @team) */\n name: string;\n /** Absolute path to the @slot directory that owns this slot. Internal routing metadata. */\n ownerDir: string;\n /** Stable tree path for the directory whose layout owns this slot. */\n ownerTreePath: string;\n /** Whether the slot owner directory declares its own page component. */\n hasPage: boolean;\n /** Absolute path to the slot's page component */\n pagePath: string | null;\n /** Absolute path to the slot's default.tsx fallback */\n defaultPath: string | null;\n /** Absolute path to the slot's layout component (wraps slot content) */\n layoutPath: string | null;\n /** Absolute path to the slot's loading component */\n loadingPath: string | null;\n /** Absolute path to the slot's error component */\n errorPath: string | null;\n /** Intercepting routes within this slot */\n interceptingRoutes: InterceptingRoute[];\n /**\n * The layout index (0-based, in route.layouts[]) that this slot belongs to.\n * Slots are passed as props to the layout at their directory level, not\n * necessarily the innermost layout. -1 means \"innermost\" (legacy default).\n */\n layoutIndex: number;\n /**\n * Filesystem segments from the slot's root directory to its active page.\n * Used at render time to compute segments for useSelectedLayoutSegment(slotName).\n * For a page at the slot root (@team/page.tsx), this is [].\n * For a sub-page (@team/members/page.tsx), this is [\"members\"].\n * null when the slot has no active page (showing default.tsx fallback).\n */\n routeSegments: string[] | null;\n /**\n * Full URL pattern parts for the slot's active page (owner prefix +\n * slot-relative pattern). Set when an inherited slot mirrors a sub-page\n * whose param names may differ from the route's. The runtime matches the\n * request URL against these parts to extract slot-specific params.\n */\n slotPatternParts?: string[];\n /**\n * Param names captured by `slotPatternParts`, in order of appearance.\n * Used at runtime to decide whether to extract slot-specific params or\n * reuse the route's matched params.\n */\n slotParamNames?: string[];\n};\n\nexport type AppRoute = {\n /** Graph-owned semantic identities. Required on AppRouteGraphRoute. */\n ids?: AppRouteSemanticIds;\n /** URL pattern, e.g. \"/\" or \"/about\" or \"/blog/:slug\" */\n pattern: string;\n /** Absolute file path to the page component */\n pagePath: string | null;\n /** Absolute file path to the route handler (route.ts) */\n routePath: string | null;\n /** Ordered list of layout files from root to leaf */\n layouts: string[];\n /** Ordered list of all discovered template files from root to leaf (not necessarily aligned 1:1 with layouts) */\n templates: string[];\n /** Parallel route slots (from @slot directories at the route's directory level) */\n parallelSlots: ParallelSlot[];\n /** Loading component path */\n loadingPath: string | null;\n /** Error component path (leaf directory only) */\n errorPath: string | null;\n /**\n * Per-layout error boundary paths, aligned with the layouts array.\n * Each entry is the error.tsx at the same directory level as the\n * corresponding layout (or null if that level has no error.tsx).\n */\n layoutErrorPaths: (string | null)[];\n /** Per-segment error boundary paths, aligned with errorTreePositions. */\n errorPaths?: string[];\n /** Tree position (directory depth from app/ root) for each error boundary. */\n errorTreePositions?: number[];\n /** Not-found component path (nearest, walking up from page dir) */\n notFoundPath: string | null;\n /**\n * Not-found component paths per layout level (aligned with layouts array).\n * Each entry is the not-found.tsx at that layout's directory, or null.\n * Used to create per-layout NotFoundBoundary so that notFound() thrown from\n * a layout is caught by the parent layout's boundary (matching Next.js behavior).\n */\n notFoundPaths: (string | null)[];\n /**\n * Forbidden component paths per layout level (aligned with layouts array).\n * Each entry is the forbidden.tsx at that layout's directory, or null.\n * Used to create per-layout ForbiddenBoundary.\n */\n forbiddenPaths: (string | null)[];\n /** Forbidden component path (403) at the route's directory level */\n forbiddenPath: string | null;\n /** Unauthorized component path (401) at the route's directory level */\n unauthorizedPath: string | null;\n /** Unauthorized component paths per layout level (aligned with layouts array). */\n unauthorizedPaths: (string | null)[];\n /**\n * Filesystem segments from app/ root to the route's directory.\n * Includes route groups and dynamic segments (as template strings like \"[id]\").\n * Used at render time to compute the child segments for useSelectedLayoutSegments().\n */\n routeSegments: string[];\n /** Tree position (directory depth from app/ root) for each template. */\n templateTreePositions?: number[];\n /**\n * Tree position (directory depth from app/ root) for each layout.\n * Used to slice routeSegments and determine which segments are below each layout.\n * For example, root layout = 0, a layout at app/blog/ = 1, app/blog/(group)/ = 2.\n * Unlike the old layoutSegmentDepths, this counts ALL directory levels including\n * route groups and parallel slots.\n */\n layoutTreePositions: number[];\n /** Whether this is a dynamic route */\n isDynamic: boolean;\n /** Parameter names for dynamic segments */\n params: string[];\n /** Dynamic parameter names captured by the route's root layout. */\n rootParamNames?: string[];\n /** Pre-split pattern segments (computed once at scan time, reused per request) */\n patternParts: string[];\n};\n\nexport type AppRouteSemanticIds = {\n route: string;\n page: string | null;\n routeHandler: string | null;\n rootBoundary: RootBoundaryId | null;\n layouts: readonly string[];\n templates: readonly string[];\n /**\n * Bridge map for the current route metadata shape: keyed by `slot.key`\n * (`name@relative/path` infrastructure id), value is the graph-owned semantic slot id.\n */\n slots: Readonly<Record<string, string>>;\n};\n\nexport type AppRouteGraphParallelSlot = ParallelSlot & {\n id: string;\n};\n\nexport type AppRouteGraphRoute = Omit<AppRoute, \"ids\" | \"parallelSlots\" | \"rootParamNames\"> & {\n ids: AppRouteSemanticIds;\n parallelSlots: AppRouteGraphParallelSlot[];\n rootParamNames: string[];\n};\n\ntype Flavor<T, Brand extends string> = T & { readonly __flavor?: Brand };\n\nexport type GraphVersion = Flavor<string, \"GraphVersion\">;\nexport type RootBoundaryId = Flavor<string, \"RootBoundaryId\">;\n\nexport type RouteManifestRoute = {\n id: string;\n pattern: string;\n patternParts: readonly string[];\n isDynamic: boolean;\n paramNames: readonly string[];\n rootParamNames: readonly string[];\n rootBoundaryId: RootBoundaryId | null;\n pageId: string | null;\n routeHandlerId: string | null;\n layoutIds: readonly string[];\n templateIds: readonly string[];\n slotIds: readonly string[];\n};\n\nexport type RouteManifestPage = {\n id: string;\n routeId: string;\n pattern: string;\n};\n\nexport type RouteManifestRouteHandler = {\n id: string;\n routeId: string;\n pattern: string;\n};\n\nexport type RouteManifestLayout = {\n id: string;\n treePath: string;\n patternParts: readonly string[];\n paramNames: readonly string[];\n rootBoundaryId: RootBoundaryId | null;\n};\n\nexport type RouteManifestTemplate = {\n id: string;\n treePath: string;\n rootBoundaryId: RootBoundaryId | null;\n ownerLayoutId: string | null;\n reset: {\n kind: \"remountSubtree\";\n treePath: string;\n };\n};\n\nexport type RouteManifestSlot = {\n id: string;\n key: string;\n name: string;\n ownerTreePath: string;\n ownerLayoutId: string | null;\n rootBoundaryId: RootBoundaryId | null;\n defaultId: string | null;\n hasDefault: boolean;\n hasPage: boolean;\n};\n\nexport type RouteManifestDefault = {\n id: string;\n slotId: string;\n ownerTreePath: string;\n ownerLayoutId: string | null;\n rootBoundaryId: RootBoundaryId | null;\n};\n\nexport type RouteManifestSlotBindingState = \"active\" | \"default\" | \"unmatched\";\n\nexport type RouteManifestSlotBinding = {\n id: string;\n routeId: string;\n slotId: string;\n ownerLayoutId: string | null;\n state: RouteManifestSlotBindingState;\n defaultId: string | null;\n routeSegments: readonly string[] | null;\n slotPatternParts?: readonly string[];\n slotParamNames?: readonly string[];\n};\n\nexport type RouteManifestInterception = {\n id: string;\n sourcePattern: string;\n sourcePatternParts: readonly string[];\n targetPattern: string;\n targetPatternParts: readonly string[];\n slotId: string;\n ownerLayoutId: string | null;\n interceptingRouteId: string | null;\n targetRouteId: string | null;\n};\n\nexport type RouteManifestBoundaryOutcome = \"error\" | \"forbidden\" | \"notFound\" | \"unauthorized\";\n\nexport type RouteManifestBoundary = {\n id: string;\n outcome: RouteManifestBoundaryOutcome;\n treePath: string;\n ownerLayoutId: string | null;\n rootBoundaryId: RootBoundaryId | null;\n};\n\nexport type RouteManifestRootBoundary = {\n id: RootBoundaryId;\n layoutId: string;\n treePath: string;\n};\n\nexport type StaticSegmentGraph = {\n routes: ReadonlyMap<string, RouteManifestRoute>;\n pages: ReadonlyMap<string, RouteManifestPage>;\n routeHandlers: ReadonlyMap<string, RouteManifestRouteHandler>;\n layouts: ReadonlyMap<string, RouteManifestLayout>;\n templates: ReadonlyMap<string, RouteManifestTemplate>;\n slots: ReadonlyMap<string, RouteManifestSlot>;\n defaults: ReadonlyMap<string, RouteManifestDefault>;\n slotBindings: ReadonlyMap<string, RouteManifestSlotBinding>;\n interceptions: ReadonlyMap<string, RouteManifestInterception>;\n interceptionsBySlotId: ReadonlyMap<string, readonly RouteManifestInterception[]>;\n boundaries: ReadonlyMap<string, RouteManifestBoundary>;\n rootBoundaries: ReadonlyMap<RootBoundaryId, RouteManifestRootBoundary>;\n};\n\nexport type RouteManifest = {\n graphVersion: GraphVersion;\n segmentGraph: StaticSegmentGraph;\n};\n\nfunction createAppRouteGraphRouteId(pattern: string): string {\n return `route:${pattern}`;\n}\n\nfunction createAppRouteGraphPageId(pattern: string): string {\n return `page:${pattern}`;\n}\n\nfunction createAppRouteGraphRouteHandlerId(pattern: string): string {\n return `route-handler:${pattern}`;\n}\n\nfunction createAppRouteGraphLayoutId(treePath: string): string {\n return `layout:${treePath}`;\n}\n\nfunction createAppRouteGraphTemplateId(treePath: string): string {\n return `template:${treePath}`;\n}\n\nfunction createAppRouteGraphSlotId(slotName: string, ownerTreePath: string): string {\n return `slot:${slotName}:${ownerTreePath}`;\n}\n\nfunction createAppRouteGraphDefaultId(slotId: string): string {\n return `default:${slotId}`;\n}\n\nfunction createAppRouteGraphInterceptionId(\n slotId: string,\n sourcePattern: string,\n targetPattern: string,\n): string {\n return `interception:${slotId}:${sourcePattern}->${targetPattern}`;\n}\n\nfunction createAppRouteGraphRootBoundaryId(treePath: string): RootBoundaryId {\n return `root-boundary:${treePath}`;\n}\n\nfunction compareStableStrings(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\nfunction sortedMapValues<T>(map: ReadonlyMap<string, T>): T[] {\n return Array.from(map.entries())\n .sort(([left], [right]) => compareStableStrings(left, right))\n .map(([, value]) => value);\n}\n\nfunction createRouteManifest(routes: readonly AppRouteGraphRoute[]): RouteManifest {\n const segmentGraph = createStaticSegmentGraph(routes);\n\n return {\n graphVersion: createRouteManifestGraphVersion(segmentGraph),\n segmentGraph,\n };\n}\n\nfunction createStaticSegmentGraph(routes: readonly AppRouteGraphRoute[]): StaticSegmentGraph {\n const routeEntries = new Map<string, RouteManifestRoute>();\n const pages = new Map<string, RouteManifestPage>();\n const routeHandlers = new Map<string, RouteManifestRouteHandler>();\n const layouts = new Map<string, RouteManifestLayout>();\n const templates = new Map<string, RouteManifestTemplate>();\n const slots = new Map<string, RouteManifestSlot>();\n const defaults = new Map<string, RouteManifestDefault>();\n const slotBindings = new Map<string, RouteManifestSlotBinding>();\n const interceptions = new Map<string, RouteManifestInterception>();\n const boundaries = new Map<string, RouteManifestBoundary>();\n const rootBoundaries = new Map<RootBoundaryId, RouteManifestRootBoundary>();\n const routeIdByPattern = createRouteManifestRouteIdByPattern(routes);\n\n for (const route of routes) {\n routeEntries.set(route.ids.route, {\n id: route.ids.route,\n pattern: route.pattern,\n patternParts: [...route.patternParts],\n isDynamic: route.isDynamic,\n paramNames: [...route.params],\n rootParamNames: [...route.rootParamNames],\n rootBoundaryId: route.ids.rootBoundary,\n pageId: route.ids.page,\n routeHandlerId: route.ids.routeHandler,\n layoutIds: [...route.ids.layouts],\n templateIds: [...route.ids.templates],\n slotIds: route.parallelSlots.map((slot) => slot.id).sort(compareStableStrings),\n });\n\n if (route.ids.page) {\n pages.set(route.ids.page, {\n id: route.ids.page,\n routeId: route.ids.route,\n pattern: route.pattern,\n });\n }\n\n if (route.ids.routeHandler) {\n routeHandlers.set(route.ids.routeHandler, {\n id: route.ids.routeHandler,\n routeId: route.ids.route,\n pattern: route.pattern,\n });\n }\n\n for (const [index, layoutId] of route.ids.layouts.entries()) {\n const treePosition = route.layoutTreePositions[index];\n assertRouteManifestTreePosition(\"layout\", route, layoutId, treePosition);\n\n const treePath = createAppRouteGraphTreePath(route.routeSegments, treePosition);\n const existingLayout = layouts.get(layoutId);\n if (existingLayout) {\n assertRouteManifestRootBoundary(\"layout\", route, layoutId, existingLayout.rootBoundaryId);\n }\n const layoutRouteParts = convertTreePathToRouteParts(treePath);\n const layout = {\n id: layoutId,\n treePath,\n patternParts: layoutRouteParts.urlSegments,\n paramNames: layoutRouteParts.params,\n rootBoundaryId: route.ids.rootBoundary,\n };\n layouts.set(layoutId, layout);\n addRouteManifestBoundaryFacts({\n boundaries,\n route,\n layoutId,\n treePath,\n layoutIndex: index,\n });\n\n if (index === 0 && route.ids.rootBoundary) {\n rootBoundaries.set(route.ids.rootBoundary, {\n id: route.ids.rootBoundary,\n layoutId,\n treePath,\n });\n }\n }\n\n addRouteManifestSegmentErrorBoundaryFacts({ boundaries, route });\n\n for (const [index, templateId] of route.ids.templates.entries()) {\n const treePosition = route.templateTreePositions?.[index];\n assertRouteManifestTreePosition(\"template\", route, templateId, treePosition);\n const treePath = createAppRouteGraphTreePath(route.routeSegments, treePosition);\n\n const existingTemplate = templates.get(templateId);\n if (existingTemplate) {\n assertRouteManifestRootBoundary(\n \"template\",\n route,\n templateId,\n existingTemplate.rootBoundaryId,\n );\n }\n templates.set(templateId, {\n id: templateId,\n treePath,\n rootBoundaryId: route.ids.rootBoundary,\n ownerLayoutId: findRouteManifestOwnerLayoutId(route, treePosition),\n reset: {\n kind: \"remountSubtree\",\n treePath,\n },\n });\n }\n\n for (const slot of route.parallelSlots) {\n const ownerLayoutId = findSlotOwnerLayoutId(route, slot);\n const defaultId = slot.defaultPath ? createAppRouteGraphDefaultId(slot.id) : null;\n if (slot.layoutPath) {\n // Materialize the slot-local layout as its own entry so consumers\n // (e.g. typegen) can distinguish it from the owning layout. Note\n // that this layout may have zero entries in `slots`: the slot\n // itself is registered below against `ownerLayoutId`, which points\n // to the ancestor layout that owns the slot prop.\n const slotLayoutTreePath = createSlotLayoutTreePath(slot);\n const slotLayoutId = createAppRouteGraphLayoutId(slotLayoutTreePath);\n const existingLayout = layouts.get(slotLayoutId);\n if (existingLayout) {\n assertRouteManifestRootBoundary(\n \"layout\",\n route,\n slotLayoutId,\n existingLayout.rootBoundaryId,\n );\n }\n const slotLayoutRouteParts = convertTreePathToRouteParts(slotLayoutTreePath);\n layouts.set(slotLayoutId, {\n id: slotLayoutId,\n treePath: slotLayoutTreePath,\n patternParts: slotLayoutRouteParts.urlSegments,\n paramNames: slotLayoutRouteParts.params,\n rootBoundaryId: route.ids.rootBoundary,\n });\n }\n slots.set(slot.id, {\n id: slot.id,\n key: slot.key,\n name: slot.name,\n ownerTreePath: slot.ownerTreePath,\n ownerLayoutId,\n rootBoundaryId: ownerLayoutId ? route.ids.rootBoundary : null,\n defaultId,\n hasDefault: slot.defaultPath !== null,\n hasPage: slot.hasPage,\n });\n if (defaultId) {\n defaults.set(defaultId, {\n id: defaultId,\n slotId: slot.id,\n ownerTreePath: slot.ownerTreePath,\n ownerLayoutId,\n rootBoundaryId: ownerLayoutId ? route.ids.rootBoundary : null,\n });\n }\n const binding = createRouteManifestSlotBinding(route, slot, ownerLayoutId, defaultId);\n slotBindings.set(binding.id, binding);\n addRouteManifestInterceptionFacts({\n interceptions,\n ownerLayoutId,\n route,\n routeIdByPattern,\n slot,\n });\n }\n }\n\n const interceptionsBySlotId = createRouteManifestInterceptionsBySlotId(interceptions);\n\n return {\n routes: routeEntries,\n pages,\n routeHandlers,\n layouts,\n templates,\n slots,\n defaults,\n slotBindings,\n interceptions,\n interceptionsBySlotId,\n boundaries,\n rootBoundaries,\n };\n}\n\nfunction createRouteManifestRouteIdByPattern(\n routes: readonly AppRouteGraphRoute[],\n): ReadonlyMap<string, string> {\n return new Map(routes.map((route) => [route.pattern, route.ids.route]));\n}\n\nfunction findRouteManifestOwnerLayoutId(\n route: AppRouteGraphRoute,\n treePosition: number,\n): string | null {\n const layoutIndex = route.layoutTreePositions.indexOf(treePosition);\n return route.ids.layouts[layoutIndex] ?? null;\n}\n\nfunction findSlotOwnerLayoutId(\n route: AppRouteGraphRoute,\n slot: AppRouteGraphParallelSlot,\n): string | null {\n if (slot.layoutIndex < 0) return null;\n return route.ids.layouts[slot.layoutIndex] ?? null;\n}\n\nfunction createSlotLayoutTreePath(slot: AppRouteGraphParallelSlot): string {\n const slotSegment = `@${slot.name}`;\n if (slot.ownerTreePath === \"/\") return `/${slotSegment}`;\n return `${slot.ownerTreePath}/${slotSegment}`;\n}\n\nfunction createRouteManifestSlotBinding(\n route: AppRouteGraphRoute,\n slot: AppRouteGraphParallelSlot,\n ownerLayoutId: string | null,\n defaultId: string | null,\n): RouteManifestSlotBinding {\n const state = getRouteManifestSlotBindingState(slot);\n const binding: RouteManifestSlotBinding = {\n id: `${route.ids.route}::${slot.id}`,\n routeId: route.ids.route,\n slotId: slot.id,\n ownerLayoutId,\n state,\n defaultId: state === \"default\" ? defaultId : null,\n routeSegments: slot.routeSegments ? [...slot.routeSegments] : null,\n };\n\n if (slot.slotPatternParts) {\n binding.slotPatternParts = [...slot.slotPatternParts];\n }\n if (slot.slotParamNames) {\n binding.slotParamNames = [...slot.slotParamNames];\n }\n\n return binding;\n}\n\nfunction addRouteManifestInterceptionFacts(input: {\n interceptions: Map<string, RouteManifestInterception>;\n ownerLayoutId: string | null;\n route: AppRouteGraphRoute;\n routeIdByPattern: ReadonlyMap<string, string>;\n slot: AppRouteGraphParallelSlot;\n}): void {\n for (const interception of input.slot.interceptingRoutes) {\n const id = createAppRouteGraphInterceptionId(\n input.slot.id,\n interception.sourceMatchPattern,\n interception.targetPattern,\n );\n input.interceptions.set(id, {\n id,\n sourcePattern: interception.sourceMatchPattern,\n sourcePatternParts: splitRouteManifestPatternParts(interception.sourceMatchPattern),\n targetPattern: interception.targetPattern,\n targetPatternParts: splitRouteManifestPatternParts(interception.targetPattern),\n slotId: input.slot.id,\n ownerLayoutId: input.ownerLayoutId,\n interceptingRouteId: input.routeIdByPattern.get(interception.sourceMatchPattern) ?? null,\n targetRouteId: input.routeIdByPattern.get(interception.targetPattern) ?? null,\n });\n }\n}\n\nfunction createRouteManifestInterceptionsBySlotId(\n interceptions: ReadonlyMap<string, RouteManifestInterception>,\n): ReadonlyMap<string, readonly RouteManifestInterception[]> {\n const interceptionsBySlotId = new Map<string, RouteManifestInterception[]>();\n for (const interception of interceptions.values()) {\n const existing = interceptionsBySlotId.get(interception.slotId);\n if (existing) {\n existing.push(interception);\n } else {\n interceptionsBySlotId.set(interception.slotId, [interception]);\n }\n }\n\n for (const slotInterceptions of interceptionsBySlotId.values()) {\n slotInterceptions.sort((left, right) => compareStableStrings(left.id, right.id));\n }\n\n return new Map(\n Array.from(interceptionsBySlotId.entries()).sort(([left], [right]) =>\n compareStableStrings(left, right),\n ),\n );\n}\n\nfunction splitRouteManifestPatternParts(pattern: string): string[] {\n return pattern.split(\"/\").filter((part) => part.length > 0);\n}\n\nfunction getRouteManifestSlotBindingState(\n slot: AppRouteGraphParallelSlot,\n): RouteManifestSlotBindingState {\n if (slot.pagePath) return \"active\";\n if (slot.defaultPath) return \"default\";\n return \"unmatched\";\n}\n\nfunction addRouteManifestBoundaryFacts(input: {\n boundaries: Map<string, RouteManifestBoundary>;\n route: AppRouteGraphRoute;\n layoutId: string;\n treePath: string;\n layoutIndex: number;\n}): void {\n addRouteManifestBoundaryFact(input, \"error\", input.route.layoutErrorPaths[input.layoutIndex]);\n addRouteManifestBoundaryFact(input, \"notFound\", input.route.notFoundPaths[input.layoutIndex]);\n addRouteManifestBoundaryFact(input, \"forbidden\", input.route.forbiddenPaths[input.layoutIndex]);\n addRouteManifestBoundaryFact(\n input,\n \"unauthorized\",\n input.route.unauthorizedPaths[input.layoutIndex],\n );\n}\n\nfunction addRouteManifestSegmentErrorBoundaryFacts(input: {\n boundaries: Map<string, RouteManifestBoundary>;\n route: AppRouteGraphRoute;\n}): void {\n for (const [index, boundaryPath] of (input.route.errorPaths ?? []).entries()) {\n const treePosition = input.route.errorTreePositions?.[index];\n assertRouteManifestBoundaryTreePosition(input.route, boundaryPath, treePosition);\n const ownerLayoutId = findRouteManifestOwnerLayoutId(input.route, treePosition);\n if (ownerLayoutId !== null) continue;\n\n const treePath = createAppRouteGraphTreePath(input.route.routeSegments, treePosition);\n addRouteManifestBoundaryFact(\n {\n boundaries: input.boundaries,\n route: input.route,\n layoutId: ownerLayoutId,\n treePath,\n },\n \"error\",\n boundaryPath,\n );\n }\n}\n\nfunction addRouteManifestBoundaryFact(\n input: {\n boundaries: Map<string, RouteManifestBoundary>;\n route: AppRouteGraphRoute;\n layoutId: string | null;\n treePath: string;\n },\n outcome: RouteManifestBoundaryOutcome,\n boundaryPath: string | null | undefined,\n): void {\n if (!boundaryPath) return;\n\n const id = `boundary:${outcome}:${input.treePath}`;\n input.boundaries.set(id, {\n id,\n outcome,\n treePath: input.treePath,\n ownerLayoutId: input.layoutId,\n rootBoundaryId: input.route.ids.rootBoundary,\n });\n}\n\nfunction assertRouteManifestTreePosition(\n kind: \"layout\" | \"template\",\n route: AppRouteGraphRoute,\n id: string,\n treePosition: number | undefined,\n): asserts treePosition is number {\n if (treePosition !== undefined) return;\n\n throw new Error(\n `[vinext] App route graph invariant violated: missing ${kind} tree position for ${id} on ${route.pattern}`,\n );\n}\n\nfunction assertRouteManifestBoundaryTreePosition(\n route: AppRouteGraphRoute,\n boundaryPath: string,\n treePosition: number | undefined,\n): asserts treePosition is number {\n if (treePosition !== undefined) return;\n\n throw new Error(\n `[vinext] App route graph invariant violated: missing boundary tree position for ${boundaryPath} on ${route.pattern}`,\n );\n}\n\nfunction assertRouteManifestRootBoundary(\n kind: \"layout\" | \"template\",\n route: AppRouteGraphRoute,\n id: string,\n existingRootBoundaryId: RootBoundaryId | null,\n): void {\n if (existingRootBoundaryId === route.ids.rootBoundary) return;\n\n throw new Error(\n `[vinext] App route graph invariant violated: ${kind} ${id} is shared across root boundaries (${existingRootBoundaryId ?? \"none\"} and ${route.ids.rootBoundary ?? \"none\"}) on ${route.pattern}`,\n );\n}\n\nfunction createRouteManifestGraphVersion(segmentGraph: StaticSegmentGraph): GraphVersion {\n // The manifest hash is canonical only if top-level map keys are sorted and\n // inner route arrays keep their own semantic order: layoutIds/templateIds in\n // tree-position order, and slotIds in compareStableStrings order.\n const stableShape = {\n routes: sortedMapValues(segmentGraph.routes),\n pages: sortedMapValues(segmentGraph.pages),\n routeHandlers: sortedMapValues(segmentGraph.routeHandlers),\n layouts: sortedMapValues(segmentGraph.layouts),\n templates: sortedMapValues(segmentGraph.templates),\n slots: sortedMapValues(segmentGraph.slots),\n defaults: sortedMapValues(segmentGraph.defaults),\n slotBindings: sortedMapValues(segmentGraph.slotBindings),\n interceptions: sortedMapValues(segmentGraph.interceptions),\n interceptionsBySlotId: sortedMapValues(segmentGraph.interceptionsBySlotId),\n boundaries: sortedMapValues(segmentGraph.boundaries),\n rootBoundaries: sortedMapValues(segmentGraph.rootBoundaries),\n };\n return `graph:${createHash(\"sha256\").update(JSON.stringify(stableShape)).digest(\"hex\")}`;\n}\n\nexport async function buildAppRouteGraph(\n appDir: string,\n matcher: ValidFileMatcher,\n): Promise<{ routes: AppRouteGraphRoute[]; routeManifest: RouteManifest }> {\n // Find all page.tsx and route.ts files, excluding @slot directories\n // (slot pages are not standalone routes — they're rendered as props of their parent layout)\n // and _private folders (Next.js convention for colocated non-route files).\n //\n // The `@children` directory is special: Next.js treats `@children` as\n // transparent — `app/@children/page.tsx` provides the layout's children\n // prop for `/` and registers a real page route at `/`. This mirrors the\n // Next.js types plugin (which skips `@children` when enumerating slots)\n // and `normalizeAppPath` (which strips any `@` segment including\n // `@children` from the URL). See:\n // - packages/next/src/build/webpack/plugins/next-types-plugin/index.ts\n // - packages/next/src/shared/lib/router/utils/app-paths.ts\n // - packages/next/src/build/normalize-catchall-routes.ts\n //\n // Interception marker directories (e.g. `(.)photo`, `(..)showcase`,\n // `(..)(..)hoge`, `(...)photos`) are also excluded from the global page\n // scan because the marker is not a real URL segment — Next.js treats these\n // as a separate route family resolved via interception rewrites. Without\n // this exclusion the scanner would register patterns like\n // `/templates/(..)showcase` as standalone routes, breaking the build (and\n // any URL containing the marker).\n //\n // See https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/interception-routes.ts\n const routes: AppRouteGraphRoute[] = [];\n\n const excludeDir = (name: string) =>\n (name.startsWith(\"@\") && name !== \"@children\") ||\n name.startsWith(\"_\") ||\n isInterceptionMarkerDir(name);\n\n // Process page files in a single pass\n // Use function form of exclude for Node < 22.14 compatibility (string arrays require >= 22.14)\n for await (const file of scanWithExtensions(\"**/page\", appDir, matcher.extensions, excludeDir)) {\n const route = fileToAppRoute(file, appDir, \"page\", matcher);\n if (route) routes.push(route);\n }\n\n // Process route handler files (API routes) in a single pass\n for await (const file of scanWithExtensions(\"**/route\", appDir, matcher.extensions, excludeDir)) {\n const route = fileToAppRoute(file, appDir, \"route\", matcher);\n if (route) routes.push(route);\n }\n\n // Layouts with parallel slot pages are valid route entries even when the\n // segment has no children page. Next.js uses this for modal/feed patterns\n // like app/user/[id]/layout + @feed/page + @modal/default.\n const routePatterns = new Set(routes.map((route) => route.pattern));\n // Ghost parents are layout-only routes whose URL pattern collides with an\n // existing route (e.g. sibling route groups like (group-a)/layout.tsx and\n // (group-b)/page.tsx both anchored at \"/\"). Their slot directories still\n // contribute synthetic sub-routes (e.g. @parallel/[...catcher]/page.tsx →\n // /:catcher+), but the ghost itself is not added to the routes table.\n const ghostParentRoutes: AppRouteGraphRoute[] = [];\n for await (const file of scanWithExtensions(\n \"**/layout\",\n appDir,\n matcher.extensions,\n excludeDir,\n )) {\n const dir = path.dirname(file);\n const routeDir = dir === \".\" ? appDir : path.join(appDir, dir);\n if (!hasParallelSlotDirectory(routeDir)) continue;\n if (discoverParallelSlots(routeDir, appDir, matcher).length === 0) continue;\n\n const route = directoryToAppRoute(dir, appDir, matcher, null, null);\n if (!route) continue;\n if (routePatterns.has(route.pattern)) {\n ghostParentRoutes.push(route);\n continue;\n }\n\n routes.push(route);\n routePatterns.add(route.pattern);\n }\n\n // Discover sub-routes created by nested pages within parallel slots.\n // In Next.js, pages nested inside @slot directories create additional URL routes.\n // For example, @audience/demographics/page.tsx at app/parallel-routes/ creates\n // a route at /parallel-routes/demographics.\n const slotSubRoutes = discoverSlotSubRoutes(routes, matcher, ghostParentRoutes);\n routes.push(...slotSubRoutes);\n\n validatePageRouteConflicts(routes, appDir);\n validateRoutePatterns(routes.map((route) => route.pattern));\n const interceptTargetPatterns = [\n ...new Set(\n routes.flatMap((route) =>\n route.parallelSlots.flatMap((slot) =>\n slot.interceptingRoutes.map((intercept) => intercept.targetPattern),\n ),\n ),\n ),\n ];\n validateRoutePatterns(interceptTargetPatterns);\n\n // Sort: static routes first, then dynamic, then catch-all\n routes.sort(compareRoutes);\n\n return { routes, routeManifest: createRouteManifest(routes) };\n}\n\nfunction hasParallelSlotDirectory(dir: string): boolean {\n try {\n return fs.readdirSync(dir, { withFileTypes: true }).some(\n (entry) =>\n entry.isDirectory() &&\n entry.name.startsWith(\"@\") &&\n // `@children` is not a parallel slot — see discoverParallelSlots.\n entry.name !== \"@children\",\n );\n } catch {\n return false;\n }\n}\n\nfunction validatePageRouteConflicts(routes: readonly AppRoute[], appDir: string): void {\n const byPattern = new Map<string, { pagePath: string | null; routePath: string | null }>();\n\n // validateRoutePatterns() would also reject page/route pairs because they\n // share a URL pattern. Keep this pass first so the error names both files.\n for (const route of routes) {\n const entry = byPattern.get(route.pattern);\n if (!entry) {\n byPattern.set(route.pattern, {\n pagePath: route.pagePath,\n routePath: route.routePath,\n });\n continue;\n }\n\n if (!entry.pagePath && route.pagePath) {\n entry.pagePath = route.pagePath;\n }\n if (!entry.routePath && route.routePath) {\n entry.routePath = route.routePath;\n }\n }\n\n for (const [pattern, entry] of byPattern) {\n if (!entry.pagePath || !entry.routePath) continue;\n\n throw new Error(\n `Conflicting route and page at ${pattern}: route at ${formatAppFilePath(\n entry.routePath,\n appDir,\n )} and page at ${formatAppFilePath(entry.pagePath, appDir)}`,\n );\n }\n}\n\nfunction formatAppFilePath(filePath: string, appDir: string): string {\n const relativePath = path.relative(appDir, filePath).replace(/\\\\/g, \"/\");\n const parsedPath = path.parse(relativePath);\n const withoutExtension = path.join(parsedPath.dir, parsedPath.name).replace(/\\\\/g, \"/\");\n return withoutExtension.startsWith(\"/\") ? withoutExtension : `/${withoutExtension}`;\n}\n\n/**\n * Discover sub-routes created by nested pages within parallel slots.\n *\n * In Next.js, pages nested inside @slot directories create additional URL routes.\n * For example, given:\n * app/parallel-routes/@audience/demographics/page.tsx\n * This creates a route at /parallel-routes/demographics where:\n * - children slot → parent's default.tsx\n * - @audience slot → @audience/demographics/page.tsx (matched)\n * - other slots → their default.tsx (fallback)\n */\nfunction discoverSlotSubRoutes(\n routes: AppRouteGraphRoute[],\n matcher: ValidFileMatcher,\n ghostParents: readonly AppRouteGraphRoute[] = [],\n): AppRouteGraphRoute[] {\n const syntheticRoutes: AppRouteGraphRoute[] = [];\n\n // O(1) lookup for existing routes by pattern — avoids O(n) routes.find() per sub-path per parent.\n // Updated as new synthetic routes are pushed so that later parents can see earlier synthetic entries.\n const routesByPattern = new Map<string, AppRoute>(routes.map((r) => [r.pattern, r]));\n\n const applySlotSubPages = (\n route: AppRoute,\n slotPages: Map<string, string>,\n rawSegments: string[],\n ): void => {\n route.parallelSlots = route.parallelSlots.map((slot) => {\n const subPage = slotPages.get(slot.key);\n if (subPage !== undefined) {\n return { ...slot, pagePath: subPage, routeSegments: rawSegments };\n }\n return slot;\n });\n };\n\n // Iterate real routes first so that later ghost-parent passes can detect\n // synthetic conflicts against routes the real pass minted.\n const allParents: AppRouteGraphRoute[] = [...routes, ...ghostParents];\n for (const parentRoute of allParents) {\n if (parentRoute.parallelSlots.length === 0) continue;\n\n // Only page-bearing routes or layout-only UI routes (not route handlers)\n // can own nested parallel-slot sub-routes.\n const isLayoutOnlyUiRoute =\n !parentRoute.pagePath && !parentRoute.routePath && parentRoute.layouts.length > 0;\n if (!parentRoute.pagePath && !isLayoutOnlyUiRoute) continue;\n\n // For page-bearing routes, the route directory is the page's directory.\n // For layout-only routes (no page.tsx), proxy the route directory through\n // the innermost layout — it lives at the same filesystem level as the route.\n const parentPageDir = parentRoute.pagePath\n ? path.dirname(parentRoute.pagePath)\n : path.dirname(parentRoute.layouts[parentRoute.layouts.length - 1]);\n\n // Collect sub-paths from all slots.\n // Map: normalized visible sub-path -> slot pages, raw filesystem segments (for routeSegments),\n // and the pre-computed convertedSubRoute (to avoid a redundant re-conversion in the merge loop).\n const subPathMap = new Map<\n string,\n {\n // Raw filesystem segments (with route groups, @slots, etc.) used for routeSegments so\n // that useSelectedLayoutSegments() sees the correct segment list at runtime.\n rawSegments: string[];\n // Pre-computed URL parts, params, isDynamic from convertSegmentsToRouteParts.\n converted: { urlSegments: string[]; params: string[]; isDynamic: boolean };\n slotPages: Map<string, string>;\n }\n >();\n\n for (const slot of parentRoute.parallelSlots) {\n // Only scan sub-pages from slots owned by this route directory.\n // Inherited slots with the same name live in different owner dirs.\n if (path.dirname(slot.ownerDir) !== parentPageDir) {\n continue;\n }\n const slotDir = slot.ownerDir;\n if (!fs.existsSync(slotDir)) continue;\n\n const subPages = findSlotSubPages(slotDir, matcher);\n for (const { relativePath, pagePath } of subPages) {\n const subSegments = relativePath.split(path.sep);\n const convertedSubRoute = convertSegmentsToRouteParts(subSegments);\n if (!convertedSubRoute) continue;\n\n const { urlSegments } = convertedSubRoute;\n const normalizedSubPath = urlSegments.join(\"/\");\n let subPathEntry = subPathMap.get(normalizedSubPath);\n\n if (!subPathEntry) {\n subPathEntry = {\n rawSegments: subSegments,\n converted: convertedSubRoute,\n slotPages: new Map(),\n };\n subPathMap.set(normalizedSubPath, subPathEntry);\n }\n\n const existingSlotPage = subPathEntry.slotPages.get(slot.key);\n if (existingSlotPage) {\n const pattern = joinRoutePattern(parentRoute.pattern, normalizedSubPath);\n throw new Error(\n `You cannot have two routes that resolve to the same path (\"${pattern}\").`,\n );\n }\n\n subPathEntry.slotPages.set(slot.key, pagePath);\n }\n }\n\n if (subPathMap.size === 0) continue;\n\n // Find the default.tsx for the children slot at the parent directory.\n // When the parent route has a children page, a default.tsx is required so\n // the synthetic sub-route has a fallback for the children slot. Layout-only\n // parent routes (no page.tsx) do not need a default — the children slot was\n // never occupied at the parent level, so the sub-route simply renders null.\n const childrenDefault = findFile(parentPageDir, \"default\", matcher);\n if (parentRoute.pagePath && !childrenDefault) continue;\n\n for (const { rawSegments, converted: convertedSubRoute, slotPages } of subPathMap.values()) {\n const {\n urlSegments: urlParts,\n params: subParams,\n isDynamic: subIsDynamic,\n } = convertedSubRoute;\n\n const subUrlPath = urlParts.join(\"/\");\n const pattern = joinRoutePattern(parentRoute.pattern, subUrlPath);\n\n const existingRoute = routesByPattern.get(pattern);\n if (existingRoute) {\n if (existingRoute.routePath && !existingRoute.pagePath) {\n throw new Error(\n `You cannot have two routes that resolve to the same path (\"${pattern}\").`,\n );\n }\n applySlotSubPages(existingRoute, slotPages, rawSegments);\n continue;\n }\n\n // Skip synthetic routes that would structurally conflict with an existing\n // route (same shape, different param names). The slot content is handled\n // by findMirroredSlotPage for the existing route instead.\n // Scan routesByPattern (not just the original routes array) so synthetic\n // routes created earlier in this loop are also visible.\n const syntheticParts = [...parentRoute.patternParts, ...urlParts];\n const hasStructuralConflict = Array.from(routesByPattern.values()).some((r) =>\n patternsStructurallyEquivalent(r.patternParts, syntheticParts),\n );\n if (hasStructuralConflict) continue;\n\n // Build parallel slots for this sub-route: matching slots get the sub-page,\n // non-matching slots get null pagePath (rendering falls back to defaultPath)\n const subSlots: AppRouteGraphParallelSlot[] = parentRoute.parallelSlots.map((slot) => {\n const subPage = slotPages.get(slot.key);\n return {\n ...slot,\n pagePath: subPage || null,\n routeSegments: subPage ? rawSegments : null,\n };\n });\n\n const newRoute: AppRouteGraphRoute = {\n ids: createAppRouteSemanticIds({\n pattern,\n pagePath: childrenDefault,\n routePath: null,\n routeSegments: [...parentRoute.routeSegments, ...rawSegments],\n layoutTreePositions: parentRoute.layoutTreePositions,\n templateTreePositions: parentRoute.templateTreePositions,\n slots: subSlots,\n }),\n pattern,\n pagePath: childrenDefault, // children slot uses parent's default.tsx as page\n routePath: null,\n layouts: parentRoute.layouts,\n templates: parentRoute.templates,\n parallelSlots: subSlots,\n loadingPath: parentRoute.loadingPath,\n errorPath: parentRoute.errorPath,\n layoutErrorPaths: parentRoute.layoutErrorPaths,\n notFoundPath: parentRoute.notFoundPath,\n notFoundPaths: parentRoute.notFoundPaths,\n forbiddenPaths: parentRoute.forbiddenPaths,\n forbiddenPath: parentRoute.forbiddenPath,\n unauthorizedPath: parentRoute.unauthorizedPath,\n unauthorizedPaths: parentRoute.unauthorizedPaths,\n routeSegments: [...parentRoute.routeSegments, ...rawSegments],\n templateTreePositions: parentRoute.templateTreePositions,\n layoutTreePositions: parentRoute.layoutTreePositions,\n isDynamic: parentRoute.isDynamic || subIsDynamic,\n params: [...parentRoute.params, ...subParams],\n rootParamNames: parentRoute.rootParamNames,\n patternParts: [...parentRoute.patternParts, ...urlParts],\n };\n syntheticRoutes.push(newRoute);\n routesByPattern.set(pattern, newRoute);\n }\n }\n\n return syntheticRoutes;\n}\n\n/**\n * Find all page files in subdirectories of a parallel slot directory.\n * Returns relative paths (from the slot dir) and absolute page paths.\n * Skips the root page.tsx (already handled as the slot's main page)\n * and intercepting route directories.\n */\ntype SlotSubPageEntry = { relativePath: string; pagePath: string };\n\n// Per-build memo: a slot directory's sub-pages depend only on the directory\n// contents and the matcher's accepted extensions. Inherited slots get scanned\n// once per descendant route, so without memoization a route N segments deep\n// pays O(N) full subtree walks for every shared ancestor slot.\n//\n// Keyed by matcher (one matcher per build) so the cache is naturally scoped\n// to a single build run and gets collected when the build finishes — no\n// cross-build pollution in long-lived dev servers.\nconst findSlotSubPagesCache = new WeakMap<ValidFileMatcher, Map<string, SlotSubPageEntry[]>>();\n\nfunction findSlotSubPages(slotDir: string, matcher: ValidFileMatcher): SlotSubPageEntry[] {\n let perMatcher = findSlotSubPagesCache.get(matcher);\n if (!perMatcher) {\n perMatcher = new Map();\n findSlotSubPagesCache.set(matcher, perMatcher);\n }\n const cached = perMatcher.get(slotDir);\n if (cached) return cached;\n\n const results: SlotSubPageEntry[] = [];\n\n function scan(dir: string): void {\n if (!fs.existsSync(dir)) return;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip intercepting route directories\n if (matchInterceptConvention(entry.name)) continue;\n // Skip private folders (prefixed with _)\n if (entry.name.startsWith(\"_\")) continue;\n\n const subDir = path.join(dir, entry.name);\n const page = findFile(subDir, \"page\", matcher);\n if (page) {\n const relativePath = path.relative(slotDir, subDir);\n results.push({ relativePath, pagePath: page });\n }\n // Continue scanning deeper for nested sub-pages\n scan(subDir);\n }\n }\n\n scan(slotDir);\n perMatcher.set(slotDir, results);\n return results;\n}\n\n/**\n * Convert a file path relative to app/ into an AppRoute.\n */\nfunction fileToAppRoute(\n file: string,\n appDir: string,\n type: \"page\" | \"route\",\n matcher: ValidFileMatcher,\n): AppRouteGraphRoute | null {\n // Remove the filename (page.tsx or route.ts)\n let dir = path.dirname(file);\n\n // `@children` is transparent in routing: `app/foo/@children/page.tsx`\n // provides the children prop for `/foo` and registers a real page route\n // at `/foo`. Strip a trailing `@children` segment so the route is\n // anchored at its parent directory — that way slot discovery treats\n // sibling `@slot` directories as owned (not inherited) and the route's\n // layouts/boundaries are sourced from the parent. Mirrors Next.js'\n // `normalizeAppPath` which drops any `@` segment (including `@children`)\n // from the URL. See packages/next/src/shared/lib/router/utils/app-paths.ts.\n if (type === \"page\" && dir !== \".\" && path.basename(dir) === \"@children\") {\n const parent = path.dirname(dir);\n dir = parent === \"\" || parent === \".\" ? \".\" : parent;\n }\n\n return directoryToAppRoute(\n dir,\n appDir,\n matcher,\n type === \"page\" ? path.join(appDir, file) : null,\n type === \"route\" ? path.join(appDir, file) : null,\n );\n}\n\nfunction directoryToAppRoute(\n dir: string,\n appDir: string,\n matcher: ValidFileMatcher,\n pagePath: string | null,\n routePath: string | null,\n): AppRouteGraphRoute | null {\n const segments = dir === \".\" ? [] : dir.split(path.sep);\n\n const params: string[] = [];\n let isDynamic = false;\n\n const convertedRoute = convertSegmentsToRouteParts(segments);\n if (!convertedRoute) return null;\n\n const { urlSegments, params: routeParams, isDynamic: routeIsDynamic } = convertedRoute;\n params.push(...routeParams);\n isDynamic = routeIsDynamic;\n\n const pattern = \"/\" + urlSegments.join(\"/\");\n\n // Discover layouts and templates from root to leaf\n const layouts = discoverLayouts(segments, appDir, matcher);\n const templates = discoverTemplates(segments, appDir, matcher);\n const templateTreePositions = computeLayoutTreePositions(appDir, templates);\n\n // Compute the tree position (directory depth) for each layout.\n const layoutTreePositions = computeLayoutTreePositions(appDir, layouts);\n\n // Discover per-segment error boundaries. Next.js loader trees carry an\n // error convention for a segment even when that segment has no layout.\n // In Next.js, each segment independently wraps its children with an ErrorBoundary.\n // This array enables interleaving error boundaries with layouts in the rendering.\n const layoutErrorPaths = discoverLayoutAlignedErrors(segments, appDir, matcher);\n const errorEntries = discoverSegmentErrors(segments, appDir, matcher);\n const errorPaths = errorEntries.map((entry) => entry.path);\n const errorTreePositions = errorEntries.map((entry) => entry.treePosition);\n\n // Discover loading, error in the route's directory\n const routeDir = dir === \".\" ? appDir : path.join(appDir, dir);\n const loadingPath = findFile(routeDir, \"loading\", matcher);\n const errorPath = findFile(routeDir, \"error\", matcher);\n\n // Discover not-found/forbidden/unauthorized: walk from route directory up to root (nearest wins).\n const notFoundPath = discoverBoundaryFile(segments, appDir, \"not-found\", matcher);\n const forbiddenPath = discoverBoundaryFile(segments, appDir, \"forbidden\", matcher);\n const unauthorizedPath = discoverBoundaryFile(segments, appDir, \"unauthorized\", matcher);\n\n // Discover per-layout not-found files (one per layout directory).\n // These are used for per-layout NotFoundBoundary to match Next.js behavior where\n // notFound() thrown from a layout is caught by the parent layout's boundary.\n const notFoundPaths = discoverBoundaryFilePerLayout(layouts, \"not-found\", matcher);\n const forbiddenPaths = discoverBoundaryFilePerLayout(layouts, \"forbidden\", matcher);\n const unauthorizedPaths = discoverBoundaryFilePerLayout(layouts, \"unauthorized\", matcher);\n\n // Discover parallel slots (@team, @analytics, etc.).\n // Slots at the route's own directory use page.tsx; slots at ancestor directories\n // (inherited from parent layouts) use default.tsx as fallback.\n const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher);\n\n return {\n ids: createAppRouteSemanticIds({\n pattern: pattern === \"/\" ? \"/\" : pattern,\n pagePath,\n routePath,\n routeSegments: segments,\n layoutTreePositions,\n templateTreePositions,\n slots: parallelSlots,\n }),\n pattern: pattern === \"/\" ? \"/\" : pattern,\n pagePath,\n routePath,\n layouts,\n templates,\n parallelSlots,\n loadingPath,\n errorPath,\n layoutErrorPaths,\n errorPaths,\n errorTreePositions,\n notFoundPath,\n notFoundPaths,\n forbiddenPaths,\n forbiddenPath,\n unauthorizedPath,\n unauthorizedPaths,\n routeSegments: segments,\n templateTreePositions,\n layoutTreePositions,\n isDynamic,\n params,\n rootParamNames: computeRootParamNames(segments, layoutTreePositions),\n patternParts: urlSegments,\n };\n}\n\nfunction dynamicParamNameFromSegment(segment: string): string | null {\n if (segment.startsWith(\"[[...\") && segment.endsWith(\"]]\")) return segment.slice(5, -2);\n if (segment.startsWith(\"[...\") && segment.endsWith(\"]\")) return segment.slice(4, -1);\n if (segment.startsWith(\"[\") && segment.endsWith(\"]\")) return segment.slice(1, -1);\n return null;\n}\n\nexport function computeRootParamNames(\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n): string[] {\n const rootLayoutPosition = layoutTreePositions[0];\n if (rootLayoutPosition == null || rootLayoutPosition <= 0) return [];\n\n const names: string[] = [];\n for (const segment of routeSegments.slice(0, rootLayoutPosition)) {\n const name = dynamicParamNameFromSegment(segment);\n if (name && !names.includes(name)) names.push(name);\n }\n return names;\n}\n\nfunction resolveRootBoundaryId(\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n): RootBoundaryId | null {\n const rootLayoutPosition = layoutTreePositions[0];\n if (rootLayoutPosition === undefined) return null;\n\n // Position 0 is the app root layout and still owns a real root boundary.\n // Only a missing layout position means the route is layoutless.\n return createAppRouteGraphRootBoundaryId(\n createAppRouteGraphTreePath(routeSegments, rootLayoutPosition),\n );\n}\n\nfunction createAppRouteSemanticIds(input: {\n pattern: string;\n pagePath: string | null;\n routePath: string | null;\n routeSegments: readonly string[];\n layoutTreePositions: readonly number[];\n templateTreePositions?: readonly number[];\n slots: readonly AppRouteGraphParallelSlot[];\n}): AppRouteSemanticIds {\n const slots: Record<string, string> = {};\n for (const slot of input.slots) {\n slots[slot.key] = slot.id;\n }\n\n return {\n route: createAppRouteGraphRouteId(input.pattern),\n page: input.pagePath ? createAppRouteGraphPageId(input.pattern) : null,\n routeHandler: input.routePath ? createAppRouteGraphRouteHandlerId(input.pattern) : null,\n rootBoundary: resolveRootBoundaryId(input.routeSegments, input.layoutTreePositions),\n layouts: input.layoutTreePositions.map((treePosition) =>\n createAppRouteGraphLayoutId(createAppRouteGraphTreePath(input.routeSegments, treePosition)),\n ),\n templates: (input.templateTreePositions ?? []).map((treePosition) =>\n createAppRouteGraphTemplateId(createAppRouteGraphTreePath(input.routeSegments, treePosition)),\n ),\n slots,\n };\n}\n\nfunction createAppRouteGraphTreePath(\n routeSegments: readonly string[],\n treePosition: number,\n): string {\n const treePathSegments = routeSegments.slice(0, treePosition);\n if (treePathSegments.length === 0) {\n return \"/\";\n }\n return `/${treePathSegments.join(\"/\")}`;\n}\n\nfunction convertTreePathToRouteParts(treePath: string): {\n urlSegments: string[];\n params: string[];\n} {\n if (treePath === \"/\") return { urlSegments: [], params: [] };\n const segments = treePath.split(\"/\").filter(Boolean);\n const routeParts = convertSegmentsToRouteParts(segments);\n if (!routeParts) {\n throw new Error(`Invalid App Router layout tree path \"${treePath}\".`);\n }\n return { urlSegments: routeParts.urlSegments, params: routeParts.params };\n}\n\n/**\n * Compute the tree position (directory depth from app root) for each layout.\n * Root layout = 0, a layout at app/blog/ = 1, app/blog/(group)/ = 2.\n * Counts ALL directory levels including route groups and parallel slots.\n */\nfunction computeLayoutTreePositions(appDir: string, layouts: string[]): number[] {\n return layouts.map((layoutPath) => {\n const layoutDir = path.dirname(layoutPath);\n if (layoutDir === appDir) return 0;\n const relative = path.relative(appDir, layoutDir);\n return relative.split(path.sep).length;\n });\n}\n\n/**\n * Discover all layout files from root to the given directory.\n * Each level of the directory tree may have a layout.tsx.\n */\nfunction discoverLayouts(segments: string[], appDir: string, matcher: ValidFileMatcher): string[] {\n const layouts: string[] = [];\n\n // Check root layout\n const rootLayout = findFile(appDir, \"layout\", matcher);\n if (rootLayout) layouts.push(rootLayout);\n\n // Check each directory level\n let currentDir = appDir;\n for (const segment of segments) {\n currentDir = path.join(currentDir, segment);\n const layout = findFile(currentDir, \"layout\", matcher);\n if (layout) layouts.push(layout);\n }\n\n return layouts;\n}\n\n/**\n * Discover all template files from root to the given directory.\n * Each level of the directory tree may have a template.tsx.\n * Templates are like layouts but re-mount on navigation.\n */\nfunction discoverTemplates(\n segments: string[],\n appDir: string,\n matcher: ValidFileMatcher,\n): string[] {\n const templates: string[] = [];\n\n // Check root template\n const rootTemplate = findFile(appDir, \"template\", matcher);\n if (rootTemplate) templates.push(rootTemplate);\n\n // Check each directory level\n let currentDir = appDir;\n for (const segment of segments) {\n currentDir = path.join(currentDir, segment);\n const template = findFile(currentDir, \"template\", matcher);\n if (template) templates.push(template);\n }\n\n return templates;\n}\n\n/**\n * Discover error.tsx files by segment tree position.\n *\n * Next.js stores conventions on every loader-tree segment; a route-group\n * directory with error.tsx but no sibling layout.tsx must still wrap its\n * descendants. Keeping positions explicit avoids conflating segment boundaries\n * with layout component ownership.\n */\nfunction discoverSegmentErrors(\n segments: string[],\n appDir: string,\n matcher: ValidFileMatcher,\n): { path: string; treePosition: number }[] {\n const errors: { path: string; treePosition: number }[] = [];\n\n const rootError = findFile(appDir, \"error\", matcher);\n if (rootError) {\n errors.push({ path: rootError, treePosition: 0 });\n }\n\n // Check each directory level\n let currentDir = appDir;\n for (let index = 0; index < segments.length; index++) {\n const segment = segments[index];\n currentDir = path.join(currentDir, segment);\n const error = findFile(currentDir, \"error\", matcher);\n if (error) {\n errors.push({ path: error, treePosition: index + 1 });\n }\n }\n\n return errors;\n}\n\n/**\n * Discover error.tsx files aligned with the layouts array.\n *\n * Route manifests still model layout-owned boundary facts by layout index.\n * Keep this layout-aligned compatibility shape separate from segment-owned\n * error boundaries so route-group errors without layouts do not get attributed\n * to unrelated layouts.\n */\nfunction discoverLayoutAlignedErrors(\n segments: string[],\n appDir: string,\n matcher: ValidFileMatcher,\n): (string | null)[] {\n const errors: (string | null)[] = [];\n\n const rootLayout = findFile(appDir, \"layout\", matcher);\n if (rootLayout) {\n errors.push(findFile(appDir, \"error\", matcher));\n }\n\n let currentDir = appDir;\n for (const segment of segments) {\n currentDir = path.join(currentDir, segment);\n const layout = findFile(currentDir, \"layout\", matcher);\n if (layout) {\n errors.push(findFile(currentDir, \"error\", matcher));\n }\n }\n\n return errors;\n}\n\n/**\n * Discover the nearest boundary file (not-found, forbidden, unauthorized)\n * by walking from the route's directory up to the app root.\n * Returns the first (closest) file found, or null.\n */\nfunction discoverBoundaryFile(\n segments: string[],\n appDir: string,\n fileName: string,\n matcher: ValidFileMatcher,\n): string | null {\n // Build all directory paths from leaf to root\n const dirs: string[] = [];\n let dir = appDir;\n dirs.push(dir);\n for (const segment of segments) {\n dir = path.join(dir, segment);\n dirs.push(dir);\n }\n\n // Walk from leaf (last) to root (first)\n for (let i = dirs.length - 1; i >= 0; i--) {\n const f = findFile(dirs[i], fileName, matcher);\n if (f) return f;\n }\n return null;\n}\n\n/**\n * Discover boundary files (not-found, forbidden, unauthorized) at each layout directory.\n * Returns an array aligned with the layouts array, where each entry is the boundary\n * file at that layout's directory, or null if none exists there.\n *\n * This is used for per-layout error boundaries. In Next.js, each layout level\n * has its own boundary that wraps the layout's children. When notFound() is thrown\n * from a layout, it propagates up to the parent layout's boundary.\n */\nfunction discoverBoundaryFilePerLayout(\n layouts: string[],\n fileName: string,\n matcher: ValidFileMatcher,\n): (string | null)[] {\n return layouts.map((layoutPath) => {\n const layoutDir = path.dirname(layoutPath);\n return findFile(layoutDir, fileName, matcher);\n });\n}\n\n/**\n * Discover parallel slots inherited from ancestor directories.\n *\n * In Next.js, parallel slots belong to the layout that defines them. When a\n * child route is rendered, its parent layout's slots must still be present.\n * If the child doesn't have matching content in a slot, the slot's default.tsx\n * is rendered instead.\n *\n * Walk from appDir through each segment to the route's directory. At each level\n * that has @slot dirs, collect them. Slots at the route's own directory level\n * use page.tsx; slots at ancestor levels use default.tsx only.\n */\nfunction discoverInheritedParallelSlots(\n segments: string[],\n appDir: string,\n routeDir: string,\n matcher: ValidFileMatcher,\n): AppRouteGraphParallelSlot[] {\n const slotMap = new Map<string, AppRouteGraphParallelSlot>();\n\n // Walk from appDir through each segment, tracking layout indices.\n // layoutIndex tracks which position in the route's layouts[] array corresponds\n // to a given directory. Only directories with a layout.tsx file increment.\n // segmentIndex aligns each entry with `segments`: dirsToCheck[i] is reached\n // after consuming segments[0..i-1], so segments.slice(i) are the segments\n // below this directory (used to mirror inherited slot sub-pages).\n let currentDir = appDir;\n const dirsToCheck: { dir: string; layoutIdx: number; segmentIndex: number }[] = [];\n let layoutIdx = findFile(appDir, \"layout\", matcher) ? 0 : -1;\n dirsToCheck.push({ dir: appDir, layoutIdx, segmentIndex: 0 });\n\n for (let i = 0; i < segments.length; i++) {\n currentDir = path.join(currentDir, segments[i]);\n if (findFile(currentDir, \"layout\", matcher)) {\n layoutIdx++;\n }\n dirsToCheck.push({ dir: currentDir, layoutIdx, segmentIndex: i + 1 });\n }\n\n const routeHasLayout = layoutIdx >= 0;\n\n for (const { dir, layoutIdx: lvlLayoutIdx, segmentIndex } of dirsToCheck) {\n // Once a route has a root layout below app/, slots discovered before that\n // layout are above the root and cannot be owned by any layout in this route.\n // Layout-less routes keep their legacy slot metadata here; validation is separate.\n if (lvlLayoutIdx < 0 && routeHasLayout) continue;\n\n const isOwnDir = dir === routeDir;\n const slotLayoutIdx = Math.max(lvlLayoutIdx, 0);\n const slotsAtLevel = discoverParallelSlots(dir, appDir, matcher);\n const segmentsBelow = segments.slice(segmentIndex);\n\n for (const slot of slotsAtLevel) {\n if (isOwnDir) {\n // At the route's own directory: use page.tsx (normal behavior)\n slot.layoutIndex = slotLayoutIdx;\n slotMap.set(slot.key, slot);\n } else {\n // At an ancestor directory: the slot's own page.tsx belongs to the\n // parent route. Look for a mirrored sub-page at @slot/<segments-below>\n // (e.g. @breadcrumbs/about/page.tsx for /about), falling back to\n // default.tsx when no mirror exists. The mirror search also accepts\n // pattern-compatible matches (e.g. slot's [name] for route's [id]) so\n // the runtime can extract slot-specific params via slotPatternParts.\n const mirror = findMirroredSlotPage(slot.ownerDir, segmentsBelow, matcher);\n let slotPatternParts: string[] | undefined;\n let slotParamNames: string[] | undefined;\n if (mirror) {\n const ownerSegments = segments.slice(0, segmentIndex);\n const ownerUrl = convertSegmentsToRouteParts([...ownerSegments]);\n slotPatternParts = [...(ownerUrl?.urlSegments ?? []), ...mirror.slotUrlSegments];\n slotParamNames = [...(ownerUrl?.params ?? []), ...mirror.slotParamNames];\n }\n const inheritedSlot: AppRouteGraphParallelSlot = {\n ...slot,\n pagePath: mirror?.pagePath ?? null,\n layoutIndex: slotLayoutIdx,\n routeSegments: mirror?.segments ?? null,\n slotPatternParts,\n slotParamNames,\n // defaultPath, loadingPath, errorPath, interceptingRoutes remain\n };\n slotMap.set(slot.key, inheritedSlot);\n }\n }\n }\n\n return Array.from(slotMap.values());\n}\n\n/**\n * Look for a page file inside a parallel slot directory that mirrors the\n * route's path below the slot's owner. The match falls through two tiers:\n * 1. Literal filesystem path — fast path when route and slot share shape.\n * 2. Scored pattern compatibility — enumerate sub-pages, accept those\n * whose URL pattern can match the route's URL space (slot dynamic\n * markers may have different names than the route's, and slot\n * catch-alls may subsume the route), and pick the most-specific via\n * `scoreSlotPattern`. Exact URL-parts equality (e.g. through route\n * groups appearing on only one side, like `(marketing)/about` ↔\n * `@breadcrumbs/about`) naturally wins because all literal segments\n * score highest.\n *\n * Returns the slot sub-page's absolute path, its raw filesystem segments\n * (for `routeSegments`), and its URL parts / param names (for\n * `slotPatternParts` / `slotParamNames`). Returns null when no mirror matches.\n */\nfunction findMirroredSlotPage(\n slotDir: string,\n segmentsBelow: readonly string[],\n matcher: ValidFileMatcher,\n): {\n pagePath: string;\n segments: string[];\n slotUrlSegments: string[];\n slotParamNames: string[];\n} | null {\n if (segmentsBelow.length === 0) return null;\n\n // Convert once: both tiers need the URL form of the route's segments below\n // this directory.\n const routeUrl = convertSegmentsToRouteParts([...segmentsBelow]);\n\n // Tier 1: literal filesystem match.\n const literalDir = path.join(slotDir, ...segmentsBelow);\n const literalPage = findFile(literalDir, \"page\", matcher);\n if (literalPage) {\n return {\n pagePath: literalPage,\n segments: [...segmentsBelow],\n slotUrlSegments: routeUrl?.urlSegments ?? [],\n slotParamNames: routeUrl?.params ?? [],\n };\n }\n\n if (!routeUrl || routeUrl.urlSegments.length === 0) return null;\n\n // Tier 2: enumerate slot sub-pages and pick the most-specific compatible\n // pattern. Exact URL-parts matches naturally win the score.\n type Candidate = {\n pagePath: string;\n segments: string[];\n slotUrlSegments: string[];\n slotParamNames: string[];\n score: number;\n };\n let best: Candidate | null = null;\n for (const { relativePath, pagePath } of findSlotSubPages(slotDir, matcher)) {\n const slotSegments = relativePath.split(path.sep);\n const slotUrl = convertSegmentsToRouteParts(slotSegments);\n if (!slotUrl) continue;\n if (!patternsCompatible(slotUrl.urlSegments, routeUrl.urlSegments)) continue;\n const score = scoreSlotPattern(slotUrl.urlSegments);\n if (!best || score > best.score) {\n best = {\n pagePath,\n segments: slotSegments,\n slotUrlSegments: slotUrl.urlSegments,\n slotParamNames: slotUrl.params,\n score,\n };\n }\n }\n\n return best;\n}\n\n/**\n * Whether a slot pattern can match the same URL space as the route's URL\n * parts (where the route's parts are themselves a pattern, since a route\n * file like `[id]/page.tsx` produces `:id`).\n *\n * - `:name+` (catch-all) consumes one-or-more remaining segments.\n * - `:name*` (optional catch-all) consumes zero-or-more.\n * - `:name` (single dynamic) consumes exactly one segment, matching any\n * route segment (literal or dynamic).\n * - Literal slot segments must equal the route's segment exactly; a literal\n * slot segment paired with a dynamic route segment is rejected because we\n * can't know statically whether the runtime value will equal the literal.\n * This also means a literal slot sub-page never matches a catch-all route\n * (e.g. slot `about/page.tsx` is not bound to a route `[...slug]`) — the\n * catch-all might or might not resolve to \"about\" at request time.\n */\nfunction patternsCompatible(slotParts: readonly string[], routeParts: readonly string[]): boolean {\n let i = 0;\n let j = 0;\n while (i < slotParts.length) {\n const sp = slotParts[i];\n if (sp.endsWith(\"+\")) return j < routeParts.length;\n if (sp.endsWith(\"*\")) return true;\n if (j >= routeParts.length) return false;\n const rp = routeParts[j];\n if (sp.startsWith(\":\")) {\n i++;\n j++;\n continue;\n }\n if (rp.startsWith(\":\")) return false;\n if (sp !== rp) return false;\n i++;\n j++;\n }\n return j === routeParts.length;\n}\n\n/**\n * Score a slot pattern by specificity so the most-specific match wins:\n * literal > single dynamic > catch-all > optional catch-all.\n *\n * Required catch-all (`:name+`, ≥1 segment) is more constrained than the\n * optional variant (`:name*`, ≥0 segments), so it scores higher.\n */\nfunction scoreSlotPattern(urlSegments: readonly string[]): number {\n let score = 0;\n for (const seg of urlSegments) {\n if (seg.endsWith(\"*\")) score += 1;\n else if (seg.endsWith(\"+\")) score += 2;\n else if (seg.startsWith(\":\")) score += 3;\n else score += 4;\n }\n return score;\n}\n\n/**\n * Map a pattern segment to the tree-node type used by Next.js' route\n * validator. Two segments are structurally equivalent iff they share the\n * same tree-node type.\n */\nfunction segmentTreeNodeType(seg: string): string {\n if (!seg.startsWith(\":\")) return `literal:${seg}`;\n if (seg.endsWith(\"*\")) return \"optionalCatchAll\";\n if (seg.endsWith(\"+\")) return \"catchAll\";\n return \"dynamic\";\n}\n\nfunction patternsStructurallyEquivalent(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (segmentTreeNodeType(a[i]) !== segmentTreeNodeType(b[i])) return false;\n }\n return true;\n}\n\n/**\n * Discover parallel route slots (@team, @analytics, etc.) in a directory.\n * Returns a ParallelSlot for each @-prefixed subdirectory that has a page or default component.\n */\nfunction discoverParallelSlots(\n dir: string,\n appDir: string,\n matcher: ValidFileMatcher,\n): AppRouteGraphParallelSlot[] {\n if (!fs.existsSync(dir)) return [];\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n const slots: AppRouteGraphParallelSlot[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.startsWith(\"@\")) continue;\n // `@children` is not a parallel slot — Next.js maps it to the layout's\n // `children` prop, i.e., it provides the route's page rather than an\n // independent slot. Skip it here so it never appears in parallelSlots.\n // See packages/next/src/build/webpack/plugins/next-types-plugin/index.ts\n // and packages/next/src/build/normalize-catchall-routes.ts.\n if (entry.name === \"@children\") continue;\n\n const slotName = entry.name.slice(1); // \"@team\" -> \"team\"\n const slotDir = path.join(dir, entry.name);\n\n const pagePath = findFile(slotDir, \"page\", matcher);\n const defaultPath = findFile(slotDir, \"default\", matcher);\n const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);\n\n // Only include slots that have at least a page, default, or intercepting route\n if (!pagePath && !defaultPath && interceptingRoutes.length === 0) continue;\n\n const ownerSegments = path\n .relative(appDir, dir)\n .split(path.sep)\n .filter((segment) => segment.length > 0);\n const ownerTreePath = createAppRouteGraphTreePath(ownerSegments, ownerSegments.length);\n\n slots.push({\n id: createAppRouteGraphSlotId(slotName, ownerTreePath),\n key: `${slotName}@${path.relative(appDir, slotDir).replace(/\\\\/g, \"/\")}`,\n name: slotName,\n ownerDir: slotDir,\n ownerTreePath,\n hasPage: pagePath !== null,\n pagePath,\n defaultPath,\n layoutPath: findFile(slotDir, \"layout\", matcher),\n loadingPath: findFile(slotDir, \"loading\", matcher),\n errorPath: findFile(slotDir, \"error\", matcher),\n interceptingRoutes,\n layoutIndex: -1, // Will be set by discoverInheritedParallelSlots\n routeSegments: pagePath ? [] : null,\n });\n }\n\n return slots;\n}\n\n/**\n * The interception convention prefix patterns.\n * (.) — same level, (..) — one level up, (..)(..)\" — two levels up, (...) — root\n */\nconst INTERCEPT_PATTERNS = [\n { prefix: \"(...)\", convention: \"...\" },\n { prefix: \"(..)(..)\", convention: \"../..\" },\n { prefix: \"(..)\", convention: \"..\" },\n { prefix: \"(.)\", convention: \".\" },\n] as const;\n\n/**\n * Check whether a directory name begins with an interception route marker.\n *\n * Matches the prefixes listed in {@link INTERCEPT_PATTERNS}: `(.)`, `(..)`,\n * `(...)`, `(..)(..)`. The marker is not a real URL segment, so the global\n * page/route scanner must skip these directories to avoid materialising\n * literal patterns like `/templates/(..)showcase`. Interception target\n * registration happens separately via {@link discoverInterceptingRoutes}.\n */\nfunction isInterceptionMarkerDir(name: string): boolean {\n return matchInterceptConvention(name) !== null;\n}\n\n/**\n * Discover intercepting routes inside a parallel slot directory.\n *\n * Intercepting routes use conventions like (.)photo, (..)feed, (...), etc.\n * They intercept navigation to another route and render within the slot instead.\n *\n * @param slotDir - The parallel slot directory (e.g. app/feed/@modal)\n * @param routeDir - The directory of the route that owns this slot (e.g. app/feed)\n * @param appDir - The root app directory\n */\nfunction discoverInterceptingRoutes(\n slotDir: string,\n routeDir: string,\n appDir: string,\n matcher: ValidFileMatcher,\n): InterceptingRoute[] {\n if (!fs.existsSync(slotDir)) return [];\n\n const results: InterceptingRoute[] = [];\n\n // Recursively scan for page files inside intercepting directories\n scanForInterceptingPages(slotDir, routeDir, appDir, results, matcher);\n\n return results;\n}\n\n/**\n * Recursively scan a directory tree for page.tsx files that are inside\n * intercepting route directories.\n */\nfunction scanForInterceptingPages(\n currentDir: string,\n routeDir: string,\n appDir: string,\n results: InterceptingRoute[],\n matcher: ValidFileMatcher,\n): void {\n if (!fs.existsSync(currentDir)) return;\n\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip private folders (prefixed with _)\n if (entry.name.startsWith(\"_\")) continue;\n\n // Check if this directory name starts with an interception convention\n const interceptMatch = matchInterceptConvention(entry.name);\n\n if (interceptMatch) {\n // This directory is the start of an intercepting route\n // e.g. \"(.)photos\" means intercept same-level \"photos\" route\n const restOfName = entry.name.slice(interceptMatch.prefix.length);\n const interceptDir = path.join(currentDir, entry.name);\n\n // Find page files within this intercepting directory tree.\n // `currentDir` is the *parent* of the marker dir — used by\n // computeInterceptSourceMatchPattern to derive the intercepting-route\n // URL (the path that owns the slot containing the marker).\n collectInterceptingPages(\n interceptDir,\n interceptDir,\n interceptMatch.convention,\n restOfName,\n routeDir,\n appDir,\n currentDir,\n results,\n matcher,\n );\n } else {\n // Regular subdirectory — keep scanning for intercepting dirs\n scanForInterceptingPages(\n path.join(currentDir, entry.name),\n routeDir,\n appDir,\n results,\n matcher,\n );\n }\n }\n}\n\n/**\n * Match a directory name against interception convention prefixes.\n */\nfunction matchInterceptConvention(name: string): { prefix: string; convention: string } | null {\n for (const pattern of INTERCEPT_PATTERNS) {\n if (name.startsWith(pattern.prefix)) {\n return pattern;\n }\n }\n return null;\n}\n\n/**\n * Collect page.tsx files inside an intercepting route directory tree\n * and compute their target URL patterns.\n */\nfunction collectInterceptingPages(\n currentDir: string,\n interceptRoot: string,\n convention: string,\n interceptSegment: string,\n routeDir: string,\n appDir: string,\n /**\n * Filesystem directory that owns the slot containing the interception\n * marker — i.e. the parent of the marker dir. Used to derive the\n * intercepting-route URL pattern that gates `findIntercept` at request\n * time. With route groups and `@slot` segments stripped, this becomes\n * Next.js' `interceptingRoute`.\n */\n interceptParentDir: string,\n results: InterceptingRoute[],\n matcher: ValidFileMatcher,\n parentLayoutPaths: readonly string[] = [],\n): void {\n const currentLayoutPath = findFile(currentDir, \"layout\", matcher);\n const layoutPaths = currentLayoutPath\n ? [...parentLayoutPaths, currentLayoutPath]\n : parentLayoutPaths;\n\n // Check for page.tsx in current directory\n const page = findFile(currentDir, \"page\", matcher);\n if (page) {\n const targetPattern = computeInterceptTarget(\n convention,\n interceptSegment,\n currentDir,\n interceptRoot,\n routeDir,\n appDir,\n );\n if (targetPattern) {\n const sourceMatchPattern = computeInterceptSourceMatchPattern(interceptParentDir, appDir);\n results.push({\n convention,\n layoutPaths: [...layoutPaths],\n targetPattern: targetPattern.pattern,\n sourceMatchPattern,\n pagePath: page,\n params: targetPattern.params,\n });\n }\n }\n\n // Recurse into subdirectories for nested intercepting routes\n if (!fs.existsSync(currentDir)) return;\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip private folders (prefixed with _)\n if (entry.name.startsWith(\"_\")) continue;\n collectInterceptingPages(\n path.join(currentDir, entry.name),\n interceptRoot,\n convention,\n interceptSegment,\n routeDir,\n appDir,\n interceptParentDir,\n results,\n matcher,\n layoutPaths,\n );\n }\n}\n\n/**\n * Compute the URL pattern for the *intercepting route* — the path that\n * owns the slot containing the interception marker. Route groups (`(name)`)\n * and parallel slots (`@slot`) are stripped because Next.js'\n * `normalizeAppPath` treats them as invisible in the URL.\n *\n * Mirrors Next.js' computation in `extractInterceptionRouteInformation`:\n * `interceptingRoute = normalizeAppPath(path.split(marker, 2)[0])`.\n *\n * Returns `/` for the app root.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/interception-routes.ts\n */\nfunction computeInterceptSourceMatchPattern(interceptParentDir: string, appDir: string): string {\n const segments = path.relative(appDir, interceptParentDir).split(path.sep).filter(Boolean);\n const converted = convertSegmentsToRouteParts(segments);\n const urlSegments = converted\n ? converted.urlSegments\n : segments.filter((segment) => !isInvisibleSegment(segment));\n if (urlSegments.length === 0) return \"/\";\n return \"/\" + urlSegments.join(\"/\");\n}\n\n/**\n * Check whether a path segment is invisible in the URL (route groups, parallel slots, \".\").\n *\n * Used by computeInterceptTarget, convertSegmentsToRouteParts, and\n * hasRemainingVisibleSegments — keep this the single source of truth.\n */\nexport function isInvisibleSegment(segment: string): boolean {\n if (segment === \".\") return true;\n if (segment.startsWith(\"(\") && segment.endsWith(\")\")) return true;\n if (segment.startsWith(\"@\")) return true;\n return false;\n}\n\n/**\n * Compute the target URL pattern for an intercepting route.\n *\n * Interception conventions (..), (..)(..)\" climb by *visible route segments*\n * (not filesystem directories). Route groups like (marketing) and parallel\n * slots like @modal are invisible and must be skipped when counting levels.\n *\n * - (.) same level: resolve relative to routeDir\n * - (..) one level up: climb 1 visible segment\n * - (..)(..) two levels up: climb 2 visible segments\n * - (...) root: resolve from appDir\n */\nfunction computeInterceptTarget(\n convention: string,\n interceptSegment: string,\n currentDir: string,\n interceptRoot: string,\n routeDir: string,\n appDir: string,\n): { pattern: string; params: string[] } | null {\n // Determine the base segments for target resolution.\n // We work on route segments (not filesystem paths) so that route groups\n // and parallel slots are properly skipped when climbing.\n const routeSegments = path.relative(appDir, routeDir).split(path.sep).filter(Boolean);\n\n let baseParts: string[];\n switch (convention) {\n case \".\":\n baseParts = routeSegments;\n break;\n case \"..\":\n case \"../..\": {\n const levelsToClimb = convention === \"..\" ? 1 : 2;\n let climbed = 0;\n let cutIndex = routeSegments.length;\n while (cutIndex > 0 && climbed < levelsToClimb) {\n cutIndex--;\n if (!isInvisibleSegment(routeSegments[cutIndex])) {\n climbed++;\n }\n }\n if (climbed < levelsToClimb) {\n const interceptionRoute = formatInterceptionRoutePath(\n routeSegments,\n convention,\n interceptSegment,\n path.relative(interceptRoot, currentDir).split(path.sep).filter(Boolean),\n );\n if (convention === \"..\") {\n throw new Error(\n `Invalid interception route: ${interceptionRoute}. Cannot use (..) marker at the root level, use (.) instead.`,\n );\n }\n throw new Error(\n `Invalid interception route: ${interceptionRoute}. Cannot use (..)(..) marker at the root level or one level up.`,\n );\n }\n baseParts = routeSegments.slice(0, cutIndex);\n break;\n }\n case \"...\":\n baseParts = [];\n break;\n default:\n return null;\n }\n\n // Add the intercept segment and any nested path segments\n const nestedParts = path.relative(interceptRoot, currentDir).split(path.sep).filter(Boolean);\n const allSegments = [...baseParts, interceptSegment, ...nestedParts];\n\n const convertedTarget = convertSegmentsToRouteParts(allSegments);\n if (!convertedTarget) return null;\n\n const { urlSegments, params } = convertedTarget;\n\n const pattern = \"/\" + urlSegments.join(\"/\");\n return { pattern: pattern === \"/\" ? \"/\" : pattern, params };\n}\n\nfunction formatInterceptionRoutePath(\n routeSegments: string[],\n convention: string,\n interceptSegment: string,\n nestedParts: string[],\n): string {\n const marker = markerForInterceptionConvention(convention);\n const convertedRoute = convertSegmentsToRouteParts(routeSegments);\n const prefix = convertedRoute\n ? convertedRoute.urlSegments\n : routeSegments.filter((segment) => !isInvisibleSegment(segment));\n const routePath = [...prefix, `${marker}${interceptSegment}`, ...nestedParts]\n .filter(Boolean)\n .join(\"/\");\n return routePath ? `/${routePath}` : \"/\";\n}\n\nfunction markerForInterceptionConvention(convention: string): string {\n switch (convention) {\n case \".\":\n return \"(.)\";\n case \"..\":\n return \"(..)\";\n case \"../..\":\n return \"(..)(..)\";\n case \"...\":\n return \"(...)\";\n default:\n return \"\";\n }\n}\n\n/**\n * Find a file by name (without extension) in a directory.\n * Checks configured pageExtensions.\n */\nfunction findFile(dir: string, name: string, matcher: ValidFileMatcher): string | null {\n for (const ext of matcher.dottedExtensions) {\n const filePath = path.join(dir, name + ext);\n if (fs.existsSync(filePath)) return filePath;\n }\n return null;\n}\n\n/**\n * Convert filesystem path segments to URL route parts, skipping invisible segments\n * (route groups, @slots, \".\") and converting dynamic segment syntax to Express-style\n * patterns (e.g. \"[id]\" → \":id\", \"[...slug]\" → \":slug+\").\n */\nexport function convertSegmentsToRouteParts(\n segments: readonly string[],\n): { urlSegments: string[]; params: string[]; isDynamic: boolean } | null {\n const urlSegments: string[] = [];\n const params: string[] = [];\n let isDynamic = false;\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n\n if (isInvisibleSegment(segment)) continue;\n\n // Catch-all segments are only valid in terminal URL position.\n // Matches Next.js PARAMETER_PATTERN: any non-] chars inside brackets.\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/get-dynamic-param.ts\n const catchAllMatch = segment.match(/^\\[\\.\\.\\.([^\\]]+)\\]$/);\n if (catchAllMatch) {\n if (hasRemainingVisibleSegments(segments, i + 1)) return null;\n // Guard: names ending in + or * would collide with internal pattern\n // modifiers (:name+ catch-all, :name* optional-catch-all).\n if (catchAllMatch[1].endsWith(\"+\") || catchAllMatch[1].endsWith(\"*\")) return null;\n isDynamic = true;\n params.push(catchAllMatch[1]);\n urlSegments.push(`:${catchAllMatch[1]}+`);\n continue;\n }\n\n const optionalCatchAllMatch = segment.match(/^\\[\\[\\.\\.\\.([^\\]]+)\\]\\]$/);\n if (optionalCatchAllMatch) {\n if (hasRemainingVisibleSegments(segments, i + 1)) return null;\n if (optionalCatchAllMatch[1].endsWith(\"+\") || optionalCatchAllMatch[1].endsWith(\"*\"))\n return null;\n isDynamic = true;\n params.push(optionalCatchAllMatch[1]);\n urlSegments.push(`:${optionalCatchAllMatch[1]}*`);\n continue;\n }\n\n const dynamicMatch = segment.match(/^\\[([^\\]]+)\\]$/);\n if (dynamicMatch) {\n if (dynamicMatch[1].endsWith(\"+\") || dynamicMatch[1].endsWith(\"*\")) return null;\n isDynamic = true;\n params.push(dynamicMatch[1]);\n urlSegments.push(`:${dynamicMatch[1]}`);\n continue;\n }\n\n urlSegments.push(decodeRouteSegment(segment));\n }\n\n return { urlSegments, params, isDynamic };\n}\n\nfunction hasRemainingVisibleSegments(segments: readonly string[], startIndex: number): boolean {\n for (let i = startIndex; i < segments.length; i++) {\n if (!isInvisibleSegment(segments[i])) return true;\n }\n return false;\n}\n\nfunction joinRoutePattern(basePattern: string, subPath: string): string {\n if (!subPath) return basePattern;\n return basePattern === \"/\" ? `/${subPath}` : `${basePattern}/${subPath}`;\n}\n\n/**\n * Returns the unique static sibling segment names at each dynamic URL level\n * of the matched route. Mirrors Next.js's `getStaticSiblingSegments` from\n * the next-app-loader: for `/products/[id]` with a sibling route at\n * `/products/sale`, the dynamic `[id]` segment has `staticSiblings: ['sale']`.\n *\n * The returned list flattens siblings across all dynamic positions and is\n * intended for the RSC payload — the client router uses it to determine if\n * a cached dynamic-route prefetch can be reused when navigating to a static\n * sibling URL.\n *\n * Ported from Next.js: packages/next/src/build/webpack/loaders/next-app-loader/index.ts\n * (getStaticSiblingSegments).\n *\n * Route group segments and parallel-route slot segments are part of the\n * filesystem tree but not the URL namespace — sibling computation is done on\n * the URL-level `patternParts`, so they are correctly transparent here.\n */\nexport function computeAppRouteStaticSiblings(\n allRoutes: readonly { patternParts?: readonly string[] | null }[],\n matchedRoute: { patternParts?: readonly string[] | null },\n): string[] {\n const siblings = new Set<string>();\n const parts = matchedRoute.patternParts;\n if (!parts) return [];\n\n for (let level = 0; level < parts.length; level++) {\n const segmentAtLevel = parts[level];\n // Only compute siblings for dynamic segments (`:id`, `:rest+`, `:rest*`).\n if (!segmentAtLevel.startsWith(\":\")) continue;\n\n for (const otherRoute of allRoutes) {\n const otherParts = otherRoute.patternParts;\n if (!otherParts || otherParts.length <= level) continue;\n\n // Parent prefix (segments before `level`) must match exactly. We\n // intentionally do not normalize dynamic-to-dynamic equivalence here:\n // siblings are only collected when the prefix is literally the same,\n // matching Next.js's path-string comparison.\n let prefixMatches = true;\n for (let i = 0; i < level; i++) {\n if (parts[i] !== otherParts[i]) {\n prefixMatches = false;\n break;\n }\n }\n if (!prefixMatches) continue;\n\n const otherSegmentAtLevel = otherParts[level];\n if (otherSegmentAtLevel === segmentAtLevel) continue;\n // Only collect static siblings.\n if (otherSegmentAtLevel.startsWith(\":\")) continue;\n\n siblings.add(otherSegmentAtLevel);\n }\n }\n\n return Array.from(siblings);\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ValidFileMatcher } from "./file-matcher.js";
2
- import { AppRoute, AppRouteGraphRoute, RouteManifest, computeRootParamNames, convertSegmentsToRouteParts } from "./app-route-graph.js";
2
+ import { AppRoute, AppRouteGraphRoute, RouteManifest, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts } from "./app-route-graph.js";
3
3
 
4
4
  //#region src/routing/app-router.d.ts
5
5
  type AppRouteGraph = {
@@ -27,5 +27,5 @@ declare function matchAppRoute(url: string, routes: AppRoute[]): {
27
27
  params: Record<string, string | string[]>;
28
28
  } | null;
29
29
  //#endregion
30
- export { type AppRoute, appRouteGraph, appRouter, computeRootParamNames, convertSegmentsToRouteParts, invalidateAppRouteCache, matchAppRoute };
30
+ export { type AppRoute, appRouteGraph, appRouter, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, invalidateAppRouteCache, matchAppRoute };
31
31
  //# sourceMappingURL=app-router.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { createValidFileMatcher } from "./file-matcher.js";
2
2
  import { createRouteTrieCache, matchRouteWithTrie } from "./route-matching.js";
3
- import { buildAppRouteGraph, computeRootParamNames, convertSegmentsToRouteParts } from "./app-route-graph.js";
3
+ import { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts } from "./app-route-graph.js";
4
4
  //#region src/routing/app-router.ts
5
5
  /**
6
6
  * App Router file-system routing.
@@ -56,6 +56,6 @@ function matchAppRoute(url, routes) {
56
56
  return matchRouteWithTrie(url, routes, appTrieCache);
57
57
  }
58
58
  //#endregion
59
- export { appRouteGraph, appRouter, computeRootParamNames, convertSegmentsToRouteParts, invalidateAppRouteCache, matchAppRoute };
59
+ export { appRouteGraph, appRouter, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, invalidateAppRouteCache, matchAppRoute };
60
60
 
61
61
  //# sourceMappingURL=app-router.js.map