vinext 0.0.47 → 0.0.49

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 (271) hide show
  1. package/README.md +1 -1
  2. package/dist/build/layout-classification.js +3 -1
  3. package/dist/build/layout-classification.js.map +1 -1
  4. package/dist/build/prerender.js +10 -10
  5. package/dist/build/prerender.js.map +1 -1
  6. package/dist/build/report.d.ts +8 -4
  7. package/dist/build/report.js +17 -7
  8. package/dist/build/report.js.map +1 -1
  9. package/dist/build/run-prerender.d.ts +5 -0
  10. package/dist/build/run-prerender.js +4 -1
  11. package/dist/build/run-prerender.js.map +1 -1
  12. package/dist/build/server-manifest.js +2 -7
  13. package/dist/build/server-manifest.js.map +1 -1
  14. package/dist/build/standalone.js +3 -5
  15. package/dist/build/standalone.js.map +1 -1
  16. package/dist/check.js +45 -29
  17. package/dist/check.js.map +1 -1
  18. package/dist/cli-args.d.ts +3 -1
  19. package/dist/cli-args.js +18 -1
  20. package/dist/cli-args.js.map +1 -1
  21. package/dist/cli.js +9 -1
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config/config-matchers.js +46 -37
  24. package/dist/config/config-matchers.js.map +1 -1
  25. package/dist/deploy.d.ts +18 -2
  26. package/dist/deploy.js +47 -4
  27. package/dist/deploy.js.map +1 -1
  28. package/dist/entries/app-rsc-entry.js +11 -9
  29. package/dist/entries/app-rsc-entry.js.map +1 -1
  30. package/dist/entries/app-rsc-manifest.js +4 -1
  31. package/dist/entries/app-rsc-manifest.js.map +1 -1
  32. package/dist/entries/pages-client-entry.js +3 -2
  33. package/dist/entries/pages-client-entry.js.map +1 -1
  34. package/dist/entries/pages-server-entry.js +21 -62
  35. package/dist/entries/pages-server-entry.js.map +1 -1
  36. package/dist/entries/runtime-entry-module.d.ts +12 -3
  37. package/dist/entries/runtime-entry-module.js +15 -4
  38. package/dist/entries/runtime-entry-module.js.map +1 -1
  39. package/dist/index.js +12 -7
  40. package/dist/index.js.map +1 -1
  41. package/dist/init.d.ts +1 -1
  42. package/dist/init.js +2 -2
  43. package/dist/init.js.map +1 -1
  44. package/dist/plugins/og-assets.js +15 -16
  45. package/dist/plugins/og-assets.js.map +1 -1
  46. package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
  47. package/dist/plugins/rsc-client-shim-excludes.js +10 -1
  48. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  49. package/dist/routing/app-route-graph.d.ts +90 -4
  50. package/dist/routing/app-route-graph.js +210 -7
  51. package/dist/routing/app-route-graph.js.map +1 -1
  52. package/dist/routing/app-router.d.ts +15 -3
  53. package/dist/routing/app-router.js +20 -23
  54. package/dist/routing/app-router.js.map +1 -1
  55. package/dist/routing/file-matcher.d.ts +3 -1
  56. package/dist/routing/file-matcher.js +6 -1
  57. package/dist/routing/file-matcher.js.map +1 -1
  58. package/dist/routing/pages-router.js +10 -19
  59. package/dist/routing/pages-router.js.map +1 -1
  60. package/dist/routing/route-matching.d.ts +28 -0
  61. package/dist/routing/route-matching.js +44 -0
  62. package/dist/routing/route-matching.js.map +1 -0
  63. package/dist/routing/route-pattern.js +4 -1
  64. package/dist/routing/route-pattern.js.map +1 -1
  65. package/dist/routing/route-trie.d.ts +8 -0
  66. package/dist/routing/route-trie.js +12 -1
  67. package/dist/routing/route-trie.js.map +1 -1
  68. package/dist/routing/route-validation.js +3 -4
  69. package/dist/routing/route-validation.js.map +1 -1
  70. package/dist/routing/utils.d.ts +8 -1
  71. package/dist/routing/utils.js +25 -2
  72. package/dist/routing/utils.js.map +1 -1
  73. package/dist/server/api-handler.js +2 -8
  74. package/dist/server/api-handler.js.map +1 -1
  75. package/dist/server/app-browser-entry.js +66 -49
  76. package/dist/server/app-browser-entry.js.map +1 -1
  77. package/dist/server/app-browser-navigation-controller.d.ts +7 -5
  78. package/dist/server/app-browser-navigation-controller.js +43 -35
  79. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  80. package/dist/server/app-browser-state.d.ts +33 -15
  81. package/dist/server/app-browser-state.js +52 -59
  82. package/dist/server/app-browser-state.js.map +1 -1
  83. package/dist/server/app-browser-visible-commit.d.ts +68 -0
  84. package/dist/server/app-browser-visible-commit.js +182 -0
  85. package/dist/server/app-browser-visible-commit.js.map +1 -0
  86. package/dist/server/app-client-reference-preloader.d.ts +15 -0
  87. package/dist/server/app-client-reference-preloader.js +46 -0
  88. package/dist/server/app-client-reference-preloader.js.map +1 -0
  89. package/dist/server/app-elements-wire.d.ts +130 -0
  90. package/dist/server/app-elements-wire.js +205 -0
  91. package/dist/server/app-elements-wire.js.map +1 -0
  92. package/dist/server/app-elements.d.ts +2 -84
  93. package/dist/server/app-elements.js +3 -102
  94. package/dist/server/app-elements.js.map +1 -1
  95. package/dist/server/app-fallback-renderer.d.ts +1 -1
  96. package/dist/server/app-middleware.d.ts +2 -1
  97. package/dist/server/app-middleware.js +34 -11
  98. package/dist/server/app-middleware.js.map +1 -1
  99. package/dist/server/app-page-boundary-render.d.ts +1 -1
  100. package/dist/server/app-page-boundary-render.js +8 -5
  101. package/dist/server/app-page-boundary-render.js.map +1 -1
  102. package/dist/server/app-page-boundary.js +2 -1
  103. package/dist/server/app-page-boundary.js.map +1 -1
  104. package/dist/server/app-page-cache.d.ts +1 -0
  105. package/dist/server/app-page-cache.js +8 -13
  106. package/dist/server/app-page-cache.js.map +1 -1
  107. package/dist/server/app-page-dispatch.d.ts +2 -1
  108. package/dist/server/app-page-dispatch.js +18 -10
  109. package/dist/server/app-page-dispatch.js.map +1 -1
  110. package/dist/server/app-page-element-builder.d.ts +1 -1
  111. package/dist/server/app-page-element-builder.js +8 -5
  112. package/dist/server/app-page-element-builder.js.map +1 -1
  113. package/dist/server/app-page-execution.d.ts +23 -5
  114. package/dist/server/app-page-execution.js +39 -24
  115. package/dist/server/app-page-execution.js.map +1 -1
  116. package/dist/server/app-page-head.js +2 -1
  117. package/dist/server/app-page-head.js.map +1 -1
  118. package/dist/server/app-page-method.js +2 -5
  119. package/dist/server/app-page-method.js.map +1 -1
  120. package/dist/server/app-page-probe.d.ts +1 -1
  121. package/dist/server/app-page-probe.js +5 -1
  122. package/dist/server/app-page-probe.js.map +1 -1
  123. package/dist/server/app-page-render.d.ts +1 -1
  124. package/dist/server/app-page-render.js +38 -3
  125. package/dist/server/app-page-render.js.map +1 -1
  126. package/dist/server/app-page-request.d.ts +0 -1
  127. package/dist/server/app-page-request.js +7 -10
  128. package/dist/server/app-page-request.js.map +1 -1
  129. package/dist/server/app-page-response.js +3 -2
  130. package/dist/server/app-page-response.js.map +1 -1
  131. package/dist/server/app-page-route-wiring.d.ts +5 -2
  132. package/dist/server/app-page-route-wiring.js +15 -12
  133. package/dist/server/app-page-route-wiring.js.map +1 -1
  134. package/dist/server/app-page-stream.d.ts +7 -0
  135. package/dist/server/app-page-stream.js +9 -2
  136. package/dist/server/app-page-stream.js.map +1 -1
  137. package/dist/server/app-prerender-endpoints.js +3 -2
  138. package/dist/server/app-prerender-endpoints.js.map +1 -1
  139. package/dist/server/app-route-handler-cache.js +2 -1
  140. package/dist/server/app-route-handler-cache.js.map +1 -1
  141. package/dist/server/app-route-handler-dispatch.js +6 -5
  142. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  143. package/dist/server/app-route-handler-policy.js +13 -13
  144. package/dist/server/app-route-handler-policy.js.map +1 -1
  145. package/dist/server/app-route-handler-response.js +2 -1
  146. package/dist/server/app-route-handler-response.js.map +1 -1
  147. package/dist/server/app-route-handler-runtime.d.ts +9 -1
  148. package/dist/server/app-route-handler-runtime.js +11 -1
  149. package/dist/server/app-route-handler-runtime.js.map +1 -1
  150. package/dist/server/app-router-entry.js +9 -4
  151. package/dist/server/app-router-entry.js.map +1 -1
  152. package/dist/server/app-rsc-cache-busting.d.ts +34 -0
  153. package/dist/server/app-rsc-cache-busting.js +137 -0
  154. package/dist/server/app-rsc-cache-busting.js.map +1 -0
  155. package/dist/server/app-rsc-handler.js +22 -11
  156. package/dist/server/app-rsc-handler.js.map +1 -1
  157. package/dist/server/app-rsc-request-normalization.d.ts +4 -2
  158. package/dist/server/app-rsc-request-normalization.js +10 -6
  159. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  160. package/dist/server/app-rsc-response-finalizer.js +1 -1
  161. package/dist/server/app-rsc-route-matching.js +8 -4
  162. package/dist/server/app-rsc-route-matching.js.map +1 -1
  163. package/dist/server/app-segment-config.js +4 -0
  164. package/dist/server/app-segment-config.js.map +1 -1
  165. package/dist/server/app-server-action-execution.js +43 -51
  166. package/dist/server/app-server-action-execution.js.map +1 -1
  167. package/dist/server/app-ssr-entry.js +21 -20
  168. package/dist/server/app-ssr-entry.js.map +1 -1
  169. package/dist/server/artifact-compatibility.d.ts +44 -0
  170. package/dist/server/artifact-compatibility.js +82 -0
  171. package/dist/server/artifact-compatibility.js.map +1 -0
  172. package/dist/server/cache-proof.d.ts +200 -0
  173. package/dist/server/cache-proof.js +342 -0
  174. package/dist/server/cache-proof.js.map +1 -0
  175. package/dist/server/dev-origin-check.js +8 -4
  176. package/dist/server/dev-origin-check.js.map +1 -1
  177. package/dist/server/dev-server.js +6 -16
  178. package/dist/server/dev-server.js.map +1 -1
  179. package/dist/server/http-error-responses.d.ts +67 -0
  180. package/dist/server/http-error-responses.js +77 -0
  181. package/dist/server/http-error-responses.js.map +1 -0
  182. package/dist/server/image-optimization.js +2 -1
  183. package/dist/server/image-optimization.js.map +1 -1
  184. package/dist/server/metadata-route-response.js +6 -5
  185. package/dist/server/metadata-route-response.js.map +1 -1
  186. package/dist/server/metadata-routes.d.ts +1 -0
  187. package/dist/server/metadata-routes.js +6 -0
  188. package/dist/server/metadata-routes.js.map +1 -1
  189. package/dist/server/middleware-matcher.js +2 -2
  190. package/dist/server/middleware-matcher.js.map +1 -1
  191. package/dist/server/middleware-response-headers.js +21 -0
  192. package/dist/server/middleware-response-headers.js.map +1 -1
  193. package/dist/server/middleware-runtime.js +3 -3
  194. package/dist/server/middleware-runtime.js.map +1 -1
  195. package/dist/server/navigation-trace.d.ts +33 -0
  196. package/dist/server/navigation-trace.js +35 -0
  197. package/dist/server/navigation-trace.js.map +1 -0
  198. package/dist/server/next-error-digest.d.ts +44 -0
  199. package/dist/server/next-error-digest.js +40 -0
  200. package/dist/server/next-error-digest.js.map +1 -0
  201. package/dist/server/pages-api-route.js +4 -7
  202. package/dist/server/pages-api-route.js.map +1 -1
  203. package/dist/server/pages-node-compat.js +4 -16
  204. package/dist/server/pages-node-compat.js.map +1 -1
  205. package/dist/server/pages-page-response.d.ts +2 -8
  206. package/dist/server/pages-page-response.js +44 -14
  207. package/dist/server/pages-page-response.js.map +1 -1
  208. package/dist/server/prod-server.d.ts +6 -0
  209. package/dist/server/prod-server.js +28 -21
  210. package/dist/server/prod-server.js.map +1 -1
  211. package/dist/server/request-pipeline.d.ts +42 -1
  212. package/dist/server/request-pipeline.js +97 -17
  213. package/dist/server/request-pipeline.js.map +1 -1
  214. package/dist/shims/cache-runtime.d.ts +2 -2
  215. package/dist/shims/cache-runtime.js +3 -6
  216. package/dist/shims/cache-runtime.js.map +1 -1
  217. package/dist/shims/cache.js +3 -5
  218. package/dist/shims/cache.js.map +1 -1
  219. package/dist/shims/fetch-cache.js +2 -3
  220. package/dist/shims/fetch-cache.js.map +1 -1
  221. package/dist/shims/head-state.js +2 -3
  222. package/dist/shims/head-state.js.map +1 -1
  223. package/dist/shims/headers.js +4 -44
  224. package/dist/shims/headers.js.map +1 -1
  225. package/dist/shims/i18n-state.js +2 -3
  226. package/dist/shims/i18n-state.js.map +1 -1
  227. package/dist/shims/internal/als-registry.d.ts +15 -0
  228. package/dist/shims/internal/als-registry.js +55 -0
  229. package/dist/shims/internal/als-registry.js.map +1 -0
  230. package/dist/shims/internal/cookie-serialize.d.ts +46 -0
  231. package/dist/shims/internal/cookie-serialize.js +51 -0
  232. package/dist/shims/internal/cookie-serialize.js.map +1 -0
  233. package/dist/shims/link.js +31 -26
  234. package/dist/shims/link.js.map +1 -1
  235. package/dist/shims/metadata.d.ts +26 -1
  236. package/dist/shims/metadata.js +94 -4
  237. package/dist/shims/metadata.js.map +1 -1
  238. package/dist/shims/navigation-state.js +2 -3
  239. package/dist/shims/navigation-state.js.map +1 -1
  240. package/dist/shims/navigation.d.ts +2 -7
  241. package/dist/shims/navigation.js +44 -36
  242. package/dist/shims/navigation.js.map +1 -1
  243. package/dist/shims/request-context.js +2 -4
  244. package/dist/shims/request-context.js.map +1 -1
  245. package/dist/shims/router-state.js +2 -3
  246. package/dist/shims/router-state.js.map +1 -1
  247. package/dist/shims/router.js +2 -2
  248. package/dist/shims/router.js.map +1 -1
  249. package/dist/shims/server.js +5 -30
  250. package/dist/shims/server.js.map +1 -1
  251. package/dist/shims/slot.d.ts +1 -1
  252. package/dist/shims/slot.js +5 -4
  253. package/dist/shims/slot.js.map +1 -1
  254. package/dist/shims/thenable-params.d.ts +5 -2
  255. package/dist/shims/thenable-params.js +26 -6
  256. package/dist/shims/thenable-params.js.map +1 -1
  257. package/dist/shims/unified-request-context.js +2 -14
  258. package/dist/shims/unified-request-context.js.map +1 -1
  259. package/dist/utils/base-path.d.ts +7 -1
  260. package/dist/utils/base-path.js +12 -1
  261. package/dist/utils/base-path.js.map +1 -1
  262. package/dist/utils/query.d.ts +8 -1
  263. package/dist/utils/query.js +12 -1
  264. package/dist/utils/query.js.map +1 -1
  265. package/dist/utils/safe-json-file.d.ts +18 -0
  266. package/dist/utils/safe-json-file.js +25 -0
  267. package/dist/utils/safe-json-file.js.map +1 -0
  268. package/dist/utils/text-stream.d.ts +29 -0
  269. package/dist/utils/text-stream.js +66 -0
  270. package/dist/utils/text-stream.js.map +1 -0
  271. package/package.json +5 -5
@@ -3,6 +3,7 @@ import { scanWithExtensions } from "./file-matcher.js";
3
3
  import { validateRoutePatterns } from "./route-validation.js";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
+ import { createHash } from "node:crypto";
6
7
  //#region src/routing/app-route-graph.ts
7
8
  /**
8
9
  * App Router route graph construction.
@@ -10,6 +11,139 @@ import path from "node:path";
10
11
  * Scans app/ directories and materializes route metadata before the request-time
11
12
  * matcher consumes it. Keep request matching and cache ownership in app-router.ts.
12
13
  */
14
+ function createAppRouteGraphRouteId(pattern) {
15
+ return `route:${pattern}`;
16
+ }
17
+ function createAppRouteGraphPageId(pattern) {
18
+ return `page:${pattern}`;
19
+ }
20
+ function createAppRouteGraphRouteHandlerId(pattern) {
21
+ return `route-handler:${pattern}`;
22
+ }
23
+ function createAppRouteGraphLayoutId(treePath) {
24
+ return `layout:${treePath}`;
25
+ }
26
+ function createAppRouteGraphTemplateId(treePath) {
27
+ return `template:${treePath}`;
28
+ }
29
+ function createAppRouteGraphSlotId(slotName, ownerTreePath) {
30
+ return `slot:${slotName}:${ownerTreePath}`;
31
+ }
32
+ function createAppRouteGraphRootBoundaryId(treePath) {
33
+ return `root-boundary:${treePath}`;
34
+ }
35
+ function compareStableStrings(left, right) {
36
+ if (left < right) return -1;
37
+ if (left > right) return 1;
38
+ return 0;
39
+ }
40
+ function sortedMapValues(map) {
41
+ return Array.from(map.entries()).sort(([left], [right]) => compareStableStrings(left, right)).map(([, value]) => value);
42
+ }
43
+ function createRouteManifest(routes) {
44
+ const segmentGraph = createStaticSegmentGraph(routes);
45
+ return {
46
+ graphVersion: createRouteManifestGraphVersion(segmentGraph),
47
+ segmentGraph
48
+ };
49
+ }
50
+ function createStaticSegmentGraph(routes) {
51
+ const routeEntries = /* @__PURE__ */ new Map();
52
+ const pages = /* @__PURE__ */ new Map();
53
+ const routeHandlers = /* @__PURE__ */ new Map();
54
+ const layouts = /* @__PURE__ */ new Map();
55
+ const templates = /* @__PURE__ */ new Map();
56
+ const slots = /* @__PURE__ */ new Map();
57
+ const rootBoundaries = /* @__PURE__ */ new Map();
58
+ for (const route of routes) {
59
+ routeEntries.set(route.ids.route, {
60
+ id: route.ids.route,
61
+ pattern: route.pattern,
62
+ patternParts: [...route.patternParts],
63
+ isDynamic: route.isDynamic,
64
+ paramNames: [...route.params],
65
+ rootParamNames: [...route.rootParamNames],
66
+ rootBoundaryId: route.ids.rootBoundary,
67
+ pageId: route.ids.page,
68
+ routeHandlerId: route.ids.routeHandler,
69
+ layoutIds: [...route.ids.layouts],
70
+ templateIds: [...route.ids.templates],
71
+ slotIds: route.parallelSlots.map((slot) => slot.id).sort(compareStableStrings)
72
+ });
73
+ if (route.ids.page) pages.set(route.ids.page, {
74
+ id: route.ids.page,
75
+ routeId: route.ids.route,
76
+ pattern: route.pattern
77
+ });
78
+ if (route.ids.routeHandler) routeHandlers.set(route.ids.routeHandler, {
79
+ id: route.ids.routeHandler,
80
+ routeId: route.ids.route,
81
+ pattern: route.pattern
82
+ });
83
+ for (const [index, layoutId] of route.ids.layouts.entries()) {
84
+ const treePosition = route.layoutTreePositions[index];
85
+ assertRouteManifestTreePosition("layout", route, layoutId, treePosition);
86
+ const treePath = createAppRouteGraphTreePath(route.routeSegments, treePosition);
87
+ const existingLayout = layouts.get(layoutId);
88
+ if (existingLayout) assertRouteManifestRootBoundary("layout", route, layoutId, existingLayout.rootBoundaryId);
89
+ layouts.set(layoutId, {
90
+ id: layoutId,
91
+ treePath,
92
+ rootBoundaryId: route.ids.rootBoundary
93
+ });
94
+ if (index === 0 && route.ids.rootBoundary) rootBoundaries.set(route.ids.rootBoundary, {
95
+ id: route.ids.rootBoundary,
96
+ layoutId,
97
+ treePath
98
+ });
99
+ }
100
+ for (const [index, templateId] of route.ids.templates.entries()) {
101
+ const treePosition = route.templateTreePositions?.[index];
102
+ assertRouteManifestTreePosition("template", route, templateId, treePosition);
103
+ const existingTemplate = templates.get(templateId);
104
+ if (existingTemplate) assertRouteManifestRootBoundary("template", route, templateId, existingTemplate.rootBoundaryId);
105
+ templates.set(templateId, {
106
+ id: templateId,
107
+ treePath: createAppRouteGraphTreePath(route.routeSegments, treePosition),
108
+ rootBoundaryId: route.ids.rootBoundary
109
+ });
110
+ }
111
+ for (const slot of route.parallelSlots) slots.set(slot.id, {
112
+ id: slot.id,
113
+ key: slot.key,
114
+ name: slot.name
115
+ });
116
+ }
117
+ return {
118
+ routes: routeEntries,
119
+ pages,
120
+ routeHandlers,
121
+ layouts,
122
+ templates,
123
+ slots,
124
+ rootBoundaries
125
+ };
126
+ }
127
+ function assertRouteManifestTreePosition(kind, route, id, treePosition) {
128
+ if (treePosition !== void 0) return;
129
+ throw new Error(`[vinext] App route graph invariant violated: missing ${kind} tree position for ${id} on ${route.pattern}`);
130
+ }
131
+ function assertRouteManifestRootBoundary(kind, route, id, existingRootBoundaryId) {
132
+ if (existingRootBoundaryId === route.ids.rootBoundary) return;
133
+ throw new Error(`[vinext] App route graph invariant violated: ${kind} ${id} is shared across root boundaries (${existingRootBoundaryId ?? "none"} and ${route.ids.rootBoundary ?? "none"}) on ${route.pattern}`);
134
+ }
135
+ function createRouteManifestGraphVersion(segmentGraph) {
136
+ const stableShape = {
137
+ routes: sortedMapValues(segmentGraph.routes),
138
+ pages: sortedMapValues(segmentGraph.pages),
139
+ routeHandlers: sortedMapValues(segmentGraph.routeHandlers),
140
+ layouts: sortedMapValues(segmentGraph.layouts),
141
+ templates: sortedMapValues(segmentGraph.templates),
142
+ slots: sortedMapValues(segmentGraph.slots),
143
+ rootBoundaries: sortedMapValues(segmentGraph.rootBoundaries)
144
+ };
145
+ return `graph:${createHash("sha256").update(JSON.stringify(stableShape)).digest("hex")}`;
146
+ }
13
147
  async function buildAppRouteGraph(appDir, matcher) {
14
148
  const routes = [];
15
149
  const excludeDir = (name) => name.startsWith("@") || name.startsWith("_");
@@ -38,7 +172,10 @@ async function buildAppRouteGraph(appDir, matcher) {
38
172
  validateRoutePatterns(routes.map((route) => route.pattern));
39
173
  validateRoutePatterns([...new Set(routes.flatMap((route) => route.parallelSlots.flatMap((slot) => slot.interceptingRoutes.map((intercept) => intercept.targetPattern))))]);
40
174
  routes.sort(compareRoutes);
41
- return { routes };
175
+ return {
176
+ routes,
177
+ routeManifest: createRouteManifest(routes)
178
+ };
42
179
  }
43
180
  function hasParallelSlotDirectory(dir) {
44
181
  try {
@@ -99,8 +236,9 @@ function discoverSlotSubRoutes(routes, matcher) {
99
236
  };
100
237
  for (const parentRoute of routes) {
101
238
  if (parentRoute.parallelSlots.length === 0) continue;
102
- if (!parentRoute.pagePath) continue;
103
- const parentPageDir = path.dirname(parentRoute.pagePath);
239
+ const isLayoutOnlyUiRoute = !parentRoute.pagePath && !parentRoute.routePath && parentRoute.layouts.length > 0;
240
+ if (!parentRoute.pagePath && !isLayoutOnlyUiRoute) continue;
241
+ const parentPageDir = parentRoute.pagePath ? path.dirname(parentRoute.pagePath) : path.dirname(parentRoute.layouts[parentRoute.layouts.length - 1]);
104
242
  const subPathMap = /* @__PURE__ */ new Map();
105
243
  for (const slot of parentRoute.parallelSlots) {
106
244
  if (path.dirname(slot.ownerDir) !== parentPageDir) continue;
@@ -131,7 +269,7 @@ function discoverSlotSubRoutes(routes, matcher) {
131
269
  }
132
270
  if (subPathMap.size === 0) continue;
133
271
  const childrenDefault = findFile(parentPageDir, "default", matcher);
134
- if (!childrenDefault) continue;
272
+ if (parentRoute.pagePath && !childrenDefault) continue;
135
273
  for (const { rawSegments, converted: convertedSubRoute, slotPages } of subPathMap.values()) {
136
274
  const { urlSegments: urlParts, params: subParams, isDynamic: subIsDynamic } = convertedSubRoute;
137
275
  const subUrlPath = urlParts.join("/");
@@ -142,6 +280,8 @@ function discoverSlotSubRoutes(routes, matcher) {
142
280
  applySlotSubPages(existingRoute, slotPages, rawSegments);
143
281
  continue;
144
282
  }
283
+ const syntheticParts = [...parentRoute.patternParts, ...urlParts];
284
+ if (Array.from(routesByPattern.values()).some((r) => patternsStructurallyEquivalent(r.patternParts, syntheticParts))) continue;
145
285
  const subSlots = parentRoute.parallelSlots.map((slot) => {
146
286
  const subPage = slotPages.get(slot.key);
147
287
  return {
@@ -151,6 +291,15 @@ function discoverSlotSubRoutes(routes, matcher) {
151
291
  };
152
292
  });
153
293
  const newRoute = {
294
+ ids: createAppRouteSemanticIds({
295
+ pattern,
296
+ pagePath: childrenDefault,
297
+ routePath: null,
298
+ routeSegments: [...parentRoute.routeSegments, ...rawSegments],
299
+ layoutTreePositions: parentRoute.layoutTreePositions,
300
+ templateTreePositions: parentRoute.templateTreePositions,
301
+ slots: subSlots
302
+ }),
154
303
  pattern,
155
304
  pagePath: childrenDefault,
156
305
  routePath: null,
@@ -245,6 +394,15 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
245
394
  const unauthorizedPaths = discoverBoundaryFilePerLayout(layouts, "unauthorized", matcher);
246
395
  const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher);
247
396
  return {
397
+ ids: createAppRouteSemanticIds({
398
+ pattern: pattern === "/" ? "/" : pattern,
399
+ pagePath,
400
+ routePath,
401
+ routeSegments: segments,
402
+ layoutTreePositions,
403
+ templateTreePositions,
404
+ slots: parallelSlots
405
+ }),
248
406
  pattern: pattern === "/" ? "/" : pattern,
249
407
  pagePath,
250
408
  routePath,
@@ -285,6 +443,29 @@ function computeRootParamNames(routeSegments, layoutTreePositions) {
285
443
  }
286
444
  return names;
287
445
  }
446
+ function resolveRootBoundaryId(routeSegments, layoutTreePositions) {
447
+ const rootLayoutPosition = layoutTreePositions[0];
448
+ if (rootLayoutPosition === void 0) return null;
449
+ return createAppRouteGraphRootBoundaryId(createAppRouteGraphTreePath(routeSegments, rootLayoutPosition));
450
+ }
451
+ function createAppRouteSemanticIds(input) {
452
+ const slots = {};
453
+ for (const slot of input.slots) slots[slot.key] = slot.id;
454
+ return {
455
+ route: createAppRouteGraphRouteId(input.pattern),
456
+ page: input.pagePath ? createAppRouteGraphPageId(input.pattern) : null,
457
+ routeHandler: input.routePath ? createAppRouteGraphRouteHandlerId(input.pattern) : null,
458
+ rootBoundary: resolveRootBoundaryId(input.routeSegments, input.layoutTreePositions),
459
+ layouts: input.layoutTreePositions.map((treePosition) => createAppRouteGraphLayoutId(createAppRouteGraphTreePath(input.routeSegments, treePosition))),
460
+ templates: (input.templateTreePositions ?? []).map((treePosition) => createAppRouteGraphTemplateId(createAppRouteGraphTreePath(input.routeSegments, treePosition))),
461
+ slots
462
+ };
463
+ }
464
+ function createAppRouteGraphTreePath(routeSegments, treePosition) {
465
+ const treePathSegments = routeSegments.slice(0, treePosition);
466
+ if (treePathSegments.length === 0) return "/";
467
+ return `/${treePathSegments.join("/")}`;
468
+ }
288
469
  /**
289
470
  * Compute the tree position (directory depth from app root) for each layout.
290
471
  * Root layout = 0, a layout at app/blog/ = 1, app/blog/(group)/ = 2.
@@ -545,6 +726,22 @@ function scoreSlotPattern(urlSegments) {
545
726
  return score;
546
727
  }
547
728
  /**
729
+ * Map a pattern segment to the tree-node type used by Next.js' route
730
+ * validator. Two segments are structurally equivalent iff they share the
731
+ * same tree-node type.
732
+ */
733
+ function segmentTreeNodeType(seg) {
734
+ if (!seg.startsWith(":")) return `literal:${seg}`;
735
+ if (seg.endsWith("*")) return "optionalCatchAll";
736
+ if (seg.endsWith("+")) return "catchAll";
737
+ return "dynamic";
738
+ }
739
+ function patternsStructurallyEquivalent(a, b) {
740
+ if (a.length !== b.length) return false;
741
+ for (let i = 0; i < a.length; i++) if (segmentTreeNodeType(a[i]) !== segmentTreeNodeType(b[i])) return false;
742
+ return true;
743
+ }
744
+ /**
548
745
  * Discover parallel route slots (@team, @analytics, etc.) in a directory.
549
746
  * Returns a ParallelSlot for each @-prefixed subdirectory that has a page or default component.
550
747
  */
@@ -560,7 +757,10 @@ function discoverParallelSlots(dir, appDir, matcher) {
560
757
  const defaultPath = findFile(slotDir, "default", matcher);
561
758
  const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);
562
759
  if (!pagePath && !defaultPath && interceptingRoutes.length === 0) continue;
760
+ const ownerSegments = path.relative(appDir, dir).split(path.sep).filter((segment) => segment.length > 0);
761
+ const ownerTreePath = createAppRouteGraphTreePath(ownerSegments, ownerSegments.length);
563
762
  slots.push({
763
+ id: createAppRouteGraphSlotId(slotName, ownerTreePath),
564
764
  key: `${slotName}@${path.relative(appDir, slotDir).replace(/\\/g, "/")}`,
565
765
  name: slotName,
566
766
  ownerDir: slotDir,
@@ -774,24 +974,27 @@ function convertSegmentsToRouteParts(segments) {
774
974
  for (let i = 0; i < segments.length; i++) {
775
975
  const segment = segments[i];
776
976
  if (isInvisibleSegment(segment)) continue;
777
- const catchAllMatch = segment.match(/^\[\.\.\.([\w-]+)\]$/);
977
+ const catchAllMatch = segment.match(/^\[\.\.\.([^\]]+)\]$/);
778
978
  if (catchAllMatch) {
779
979
  if (hasRemainingVisibleSegments(segments, i + 1)) return null;
980
+ if (catchAllMatch[1].endsWith("+") || catchAllMatch[1].endsWith("*")) return null;
780
981
  isDynamic = true;
781
982
  params.push(catchAllMatch[1]);
782
983
  urlSegments.push(`:${catchAllMatch[1]}+`);
783
984
  continue;
784
985
  }
785
- const optionalCatchAllMatch = segment.match(/^\[\[\.\.\.([\w-]+)\]\]$/);
986
+ const optionalCatchAllMatch = segment.match(/^\[\[\.\.\.([^\]]+)\]\]$/);
786
987
  if (optionalCatchAllMatch) {
787
988
  if (hasRemainingVisibleSegments(segments, i + 1)) return null;
989
+ if (optionalCatchAllMatch[1].endsWith("+") || optionalCatchAllMatch[1].endsWith("*")) return null;
788
990
  isDynamic = true;
789
991
  params.push(optionalCatchAllMatch[1]);
790
992
  urlSegments.push(`:${optionalCatchAllMatch[1]}*`);
791
993
  continue;
792
994
  }
793
- const dynamicMatch = segment.match(/^\[([\w-]+)\]$/);
995
+ const dynamicMatch = segment.match(/^\[([^\]]+)\]$/);
794
996
  if (dynamicMatch) {
997
+ if (dynamicMatch[1].endsWith("+") || dynamicMatch[1].endsWith("*")) return null;
795
998
  isDynamic = true;
796
999
  params.push(dynamicMatch[1]);
797
1000
  urlSegments.push(`:${dynamicMatch[1]}`);