vinext 0.0.46 → 0.0.48

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 (351) hide show
  1. package/README.md +8 -6
  2. package/dist/build/layout-classification.js +3 -1
  3. package/dist/build/layout-classification.js.map +1 -1
  4. package/dist/build/prerender.d.ts +2 -1
  5. package/dist/build/prerender.js +80 -24
  6. package/dist/build/prerender.js.map +1 -1
  7. package/dist/build/report.d.ts +9 -5
  8. package/dist/build/report.js +17 -7
  9. package/dist/build/report.js.map +1 -1
  10. package/dist/build/route-classification-injector.d.ts +35 -0
  11. package/dist/build/route-classification-injector.js +61 -0
  12. package/dist/build/route-classification-injector.js.map +1 -0
  13. package/dist/build/route-classification-manifest.d.ts +1 -1
  14. package/dist/build/run-prerender.d.ts +5 -0
  15. package/dist/build/run-prerender.js +4 -1
  16. package/dist/build/run-prerender.js.map +1 -1
  17. package/dist/build/server-manifest.js +2 -7
  18. package/dist/build/server-manifest.js.map +1 -1
  19. package/dist/build/standalone.js +3 -5
  20. package/dist/build/standalone.js.map +1 -1
  21. package/dist/build/static-export.d.ts +1 -1
  22. package/dist/check.js +45 -29
  23. package/dist/check.js.map +1 -1
  24. package/dist/cli-args.d.ts +33 -0
  25. package/dist/cli-args.js +121 -0
  26. package/dist/cli-args.js.map +1 -0
  27. package/dist/cli.js +11 -20
  28. package/dist/cli.js.map +1 -1
  29. package/dist/cloudflare/kv-cache-handler.js +29 -9
  30. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  31. package/dist/config/config-matchers.js +46 -37
  32. package/dist/config/config-matchers.js.map +1 -1
  33. package/dist/config/next-config.d.ts +4 -2
  34. package/dist/config/next-config.js +3 -0
  35. package/dist/config/next-config.js.map +1 -1
  36. package/dist/deploy.d.ts +18 -2
  37. package/dist/deploy.js +47 -4
  38. package/dist/deploy.js.map +1 -1
  39. package/dist/entries/app-rsc-entry.d.ts +4 -3
  40. package/dist/entries/app-rsc-entry.js +379 -858
  41. package/dist/entries/app-rsc-entry.js.map +1 -1
  42. package/dist/entries/app-rsc-manifest.d.ts +1 -1
  43. package/dist/entries/app-rsc-manifest.js +6 -1
  44. package/dist/entries/app-rsc-manifest.js.map +1 -1
  45. package/dist/entries/pages-client-entry.js +3 -2
  46. package/dist/entries/pages-client-entry.js.map +1 -1
  47. package/dist/entries/pages-server-entry.js +19 -61
  48. package/dist/entries/pages-server-entry.js.map +1 -1
  49. package/dist/entries/runtime-entry-module.d.ts +12 -3
  50. package/dist/entries/runtime-entry-module.js +15 -4
  51. package/dist/entries/runtime-entry-module.js.map +1 -1
  52. package/dist/index.js +40 -58
  53. package/dist/index.js.map +1 -1
  54. package/dist/plugins/fonts.js +54 -32
  55. package/dist/plugins/fonts.js.map +1 -1
  56. package/dist/plugins/og-assets.js +15 -16
  57. package/dist/plugins/og-assets.js.map +1 -1
  58. package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
  59. package/dist/plugins/rsc-client-shim-excludes.js +11 -1
  60. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  61. package/dist/routing/app-route-graph.d.ts +195 -0
  62. package/dist/routing/app-route-graph.js +1022 -0
  63. package/dist/routing/app-route-graph.js.map +1 -0
  64. package/dist/routing/app-router.d.ts +14 -88
  65. package/dist/routing/app-router.js +21 -712
  66. package/dist/routing/app-router.js.map +1 -1
  67. package/dist/routing/file-matcher.d.ts +3 -1
  68. package/dist/routing/file-matcher.js +6 -1
  69. package/dist/routing/file-matcher.js.map +1 -1
  70. package/dist/routing/pages-router.js +10 -19
  71. package/dist/routing/pages-router.js.map +1 -1
  72. package/dist/routing/route-matching.d.ts +28 -0
  73. package/dist/routing/route-matching.js +44 -0
  74. package/dist/routing/route-matching.js.map +1 -0
  75. package/dist/routing/route-pattern.js +4 -1
  76. package/dist/routing/route-pattern.js.map +1 -1
  77. package/dist/routing/route-trie.d.ts +8 -0
  78. package/dist/routing/route-trie.js +12 -1
  79. package/dist/routing/route-trie.js.map +1 -1
  80. package/dist/routing/route-validation.js +3 -4
  81. package/dist/routing/route-validation.js.map +1 -1
  82. package/dist/routing/utils.d.ts +8 -1
  83. package/dist/routing/utils.js +25 -2
  84. package/dist/routing/utils.js.map +1 -1
  85. package/dist/server/app-browser-entry.js +145 -294
  86. package/dist/server/app-browser-entry.js.map +1 -1
  87. package/dist/server/app-browser-error.d.ts +3 -4
  88. package/dist/server/app-browser-error.js +8 -4
  89. package/dist/server/app-browser-error.js.map +1 -1
  90. package/dist/server/app-browser-navigation-controller.d.ts +75 -0
  91. package/dist/server/app-browser-navigation-controller.js +290 -0
  92. package/dist/server/app-browser-navigation-controller.js.map +1 -0
  93. package/dist/server/app-browser-state.d.ts +33 -15
  94. package/dist/server/app-browser-state.js +52 -59
  95. package/dist/server/app-browser-state.js.map +1 -1
  96. package/dist/server/app-browser-visible-commit.d.ts +68 -0
  97. package/dist/server/app-browser-visible-commit.js +182 -0
  98. package/dist/server/app-browser-visible-commit.js.map +1 -0
  99. package/dist/server/app-client-reference-preloader.d.ts +15 -0
  100. package/dist/server/app-client-reference-preloader.js +46 -0
  101. package/dist/server/app-client-reference-preloader.js.map +1 -0
  102. package/dist/server/app-elements-wire.d.ts +130 -0
  103. package/dist/server/app-elements-wire.js +205 -0
  104. package/dist/server/app-elements-wire.js.map +1 -0
  105. package/dist/server/app-elements.d.ts +2 -84
  106. package/dist/server/app-elements.js +4 -107
  107. package/dist/server/app-elements.js.map +1 -1
  108. package/dist/server/app-fallback-renderer.d.ts +57 -0
  109. package/dist/server/app-fallback-renderer.js +79 -0
  110. package/dist/server/app-fallback-renderer.js.map +1 -0
  111. package/dist/server/app-hook-warning-suppression.d.ts +7 -0
  112. package/dist/server/app-hook-warning-suppression.js +12 -0
  113. package/dist/server/app-hook-warning-suppression.js.map +1 -0
  114. package/dist/server/app-middleware.d.ts +2 -1
  115. package/dist/server/app-middleware.js +34 -11
  116. package/dist/server/app-middleware.js.map +1 -1
  117. package/dist/server/app-mounted-slots-header.d.ts +17 -0
  118. package/dist/server/app-mounted-slots-header.js +21 -0
  119. package/dist/server/app-mounted-slots-header.js.map +1 -0
  120. package/dist/server/app-page-boundary-render.d.ts +3 -3
  121. package/dist/server/app-page-boundary-render.js +8 -5
  122. package/dist/server/app-page-boundary-render.js.map +1 -1
  123. package/dist/server/app-page-boundary.js +2 -1
  124. package/dist/server/app-page-boundary.js.map +1 -1
  125. package/dist/server/app-page-cache.d.ts +19 -4
  126. package/dist/server/app-page-cache.js +60 -22
  127. package/dist/server/app-page-cache.js.map +1 -1
  128. package/dist/server/app-page-dispatch.d.ts +9 -5
  129. package/dist/server/app-page-dispatch.js +41 -17
  130. package/dist/server/app-page-dispatch.js.map +1 -1
  131. package/dist/server/app-page-element-builder.d.ts +61 -0
  132. package/dist/server/app-page-element-builder.js +142 -0
  133. package/dist/server/app-page-element-builder.js.map +1 -0
  134. package/dist/server/app-page-execution.d.ts +23 -5
  135. package/dist/server/app-page-execution.js +39 -24
  136. package/dist/server/app-page-execution.js.map +1 -1
  137. package/dist/server/app-page-head.js +2 -1
  138. package/dist/server/app-page-head.js.map +1 -1
  139. package/dist/server/app-page-method.js +2 -5
  140. package/dist/server/app-page-method.js.map +1 -1
  141. package/dist/server/app-page-params.d.ts +2 -1
  142. package/dist/server/app-page-params.js +3 -3
  143. package/dist/server/app-page-params.js.map +1 -1
  144. package/dist/server/app-page-probe.d.ts +1 -1
  145. package/dist/server/app-page-probe.js +5 -1
  146. package/dist/server/app-page-probe.js.map +1 -1
  147. package/dist/server/app-page-render.d.ts +6 -2
  148. package/dist/server/app-page-render.js +118 -30
  149. package/dist/server/app-page-render.js.map +1 -1
  150. package/dist/server/app-page-request.d.ts +19 -5
  151. package/dist/server/app-page-request.js +49 -7
  152. package/dist/server/app-page-request.js.map +1 -1
  153. package/dist/server/app-page-response.d.ts +1 -0
  154. package/dist/server/app-page-response.js +6 -9
  155. package/dist/server/app-page-response.js.map +1 -1
  156. package/dist/server/app-page-route-wiring.d.ts +20 -4
  157. package/dist/server/app-page-route-wiring.js +15 -12
  158. package/dist/server/app-page-route-wiring.js.map +1 -1
  159. package/dist/server/app-page-stream.d.ts +7 -0
  160. package/dist/server/app-page-stream.js +9 -2
  161. package/dist/server/app-page-stream.js.map +1 -1
  162. package/dist/server/app-post-middleware-context.d.ts +16 -0
  163. package/dist/server/app-post-middleware-context.js +28 -0
  164. package/dist/server/app-post-middleware-context.js.map +1 -0
  165. package/dist/server/app-prerender-endpoints.js +3 -2
  166. package/dist/server/app-prerender-endpoints.js.map +1 -1
  167. package/dist/server/app-request-context.d.ts +22 -0
  168. package/dist/server/app-request-context.js +30 -0
  169. package/dist/server/app-request-context.js.map +1 -0
  170. package/dist/server/app-route-handler-cache.d.ts +1 -0
  171. package/dist/server/app-route-handler-cache.js +7 -2
  172. package/dist/server/app-route-handler-cache.js.map +1 -1
  173. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  174. package/dist/server/app-route-handler-dispatch.js +8 -5
  175. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  176. package/dist/server/app-route-handler-execution.d.ts +2 -1
  177. package/dist/server/app-route-handler-execution.js +2 -2
  178. package/dist/server/app-route-handler-execution.js.map +1 -1
  179. package/dist/server/app-route-handler-policy.js +13 -13
  180. package/dist/server/app-route-handler-policy.js.map +1 -1
  181. package/dist/server/app-route-handler-response.d.ts +4 -2
  182. package/dist/server/app-route-handler-response.js +9 -7
  183. package/dist/server/app-route-handler-response.js.map +1 -1
  184. package/dist/server/app-route-handler-runtime.d.ts +9 -1
  185. package/dist/server/app-route-handler-runtime.js +11 -1
  186. package/dist/server/app-route-handler-runtime.js.map +1 -1
  187. package/dist/server/app-router-entry.js +9 -4
  188. package/dist/server/app-router-entry.js.map +1 -1
  189. package/dist/server/app-rsc-cache-busting.d.ts +34 -0
  190. package/dist/server/app-rsc-cache-busting.js +137 -0
  191. package/dist/server/app-rsc-cache-busting.js.map +1 -0
  192. package/dist/server/app-rsc-error-handler.d.ts +21 -0
  193. package/dist/server/app-rsc-error-handler.js +30 -0
  194. package/dist/server/app-rsc-error-handler.js.map +1 -0
  195. package/dist/server/app-rsc-handler.d.ts +117 -0
  196. package/dist/server/app-rsc-handler.js +271 -0
  197. package/dist/server/app-rsc-handler.js.map +1 -0
  198. package/dist/server/app-rsc-request-normalization.d.ts +42 -0
  199. package/dist/server/app-rsc-request-normalization.js +67 -0
  200. package/dist/server/app-rsc-request-normalization.js.map +1 -0
  201. package/dist/server/app-rsc-response-finalizer.d.ts +30 -0
  202. package/dist/server/app-rsc-response-finalizer.js +38 -0
  203. package/dist/server/app-rsc-response-finalizer.js.map +1 -0
  204. package/dist/server/app-rsc-route-matching.js +8 -4
  205. package/dist/server/app-rsc-route-matching.js.map +1 -1
  206. package/dist/server/app-segment-config.d.ts +33 -0
  207. package/dist/server/app-segment-config.js +90 -0
  208. package/dist/server/app-segment-config.js.map +1 -0
  209. package/dist/server/app-server-action-execution.d.ts +2 -0
  210. package/dist/server/app-server-action-execution.js +45 -51
  211. package/dist/server/app-server-action-execution.js.map +1 -1
  212. package/dist/server/app-ssr-entry.js +21 -20
  213. package/dist/server/app-ssr-entry.js.map +1 -1
  214. package/dist/server/artifact-compatibility.d.ts +44 -0
  215. package/dist/server/artifact-compatibility.js +82 -0
  216. package/dist/server/artifact-compatibility.js.map +1 -0
  217. package/dist/server/cache-control.d.ts +24 -0
  218. package/dist/server/cache-control.js +33 -0
  219. package/dist/server/cache-control.js.map +1 -0
  220. package/dist/server/cache-proof.d.ts +200 -0
  221. package/dist/server/cache-proof.js +342 -0
  222. package/dist/server/cache-proof.js.map +1 -0
  223. package/dist/server/dev-error-overlay-store.d.ts +23 -0
  224. package/dist/server/dev-error-overlay-store.js +67 -0
  225. package/dist/server/dev-error-overlay-store.js.map +1 -0
  226. package/dist/server/dev-error-overlay.d.ts +15 -0
  227. package/dist/server/dev-error-overlay.js +548 -0
  228. package/dist/server/dev-error-overlay.js.map +1 -0
  229. package/dist/server/dev-origin-check.js +8 -4
  230. package/dist/server/dev-origin-check.js.map +1 -1
  231. package/dist/server/dev-server.js +1 -6
  232. package/dist/server/dev-server.js.map +1 -1
  233. package/dist/server/http-error-responses.d.ts +67 -0
  234. package/dist/server/http-error-responses.js +77 -0
  235. package/dist/server/http-error-responses.js.map +1 -0
  236. package/dist/server/image-optimization.js +2 -1
  237. package/dist/server/image-optimization.js.map +1 -1
  238. package/dist/server/instrumentation-runtime.d.ts +44 -0
  239. package/dist/server/instrumentation-runtime.js +29 -0
  240. package/dist/server/instrumentation-runtime.js.map +1 -0
  241. package/dist/server/isr-cache.d.ts +2 -7
  242. package/dist/server/isr-cache.js +7 -10
  243. package/dist/server/isr-cache.js.map +1 -1
  244. package/dist/server/metadata-route-response.js +6 -5
  245. package/dist/server/metadata-route-response.js.map +1 -1
  246. package/dist/server/metadata-routes.d.ts +1 -0
  247. package/dist/server/metadata-routes.js +6 -0
  248. package/dist/server/metadata-routes.js.map +1 -1
  249. package/dist/server/middleware-matcher.js +2 -2
  250. package/dist/server/middleware-matcher.js.map +1 -1
  251. package/dist/server/middleware-response-headers.js +21 -0
  252. package/dist/server/middleware-response-headers.js.map +1 -1
  253. package/dist/server/middleware-runtime.js +3 -3
  254. package/dist/server/middleware-runtime.js.map +1 -1
  255. package/dist/server/navigation-trace.d.ts +33 -0
  256. package/dist/server/navigation-trace.js +35 -0
  257. package/dist/server/navigation-trace.js.map +1 -0
  258. package/dist/server/next-error-digest.d.ts +44 -0
  259. package/dist/server/next-error-digest.js +40 -0
  260. package/dist/server/next-error-digest.js.map +1 -0
  261. package/dist/server/pages-api-route.js +2 -1
  262. package/dist/server/pages-api-route.js.map +1 -1
  263. package/dist/server/pages-node-compat.js +4 -16
  264. package/dist/server/pages-node-compat.js.map +1 -1
  265. package/dist/server/pages-page-data.d.ts +2 -1
  266. package/dist/server/pages-page-data.js +6 -5
  267. package/dist/server/pages-page-data.js.map +1 -1
  268. package/dist/server/pages-page-response.d.ts +3 -8
  269. package/dist/server/pages-page-response.js +46 -15
  270. package/dist/server/pages-page-response.js.map +1 -1
  271. package/dist/server/prod-server.d.ts +6 -0
  272. package/dist/server/prod-server.js +28 -21
  273. package/dist/server/prod-server.js.map +1 -1
  274. package/dist/server/request-pipeline.d.ts +42 -1
  275. package/dist/server/request-pipeline.js +97 -17
  276. package/dist/server/request-pipeline.js.map +1 -1
  277. package/dist/server/rsc-stream-hints.d.ts +3 -1
  278. package/dist/server/rsc-stream-hints.js +4 -1
  279. package/dist/server/rsc-stream-hints.js.map +1 -1
  280. package/dist/server/seed-cache.js +19 -8
  281. package/dist/server/seed-cache.js.map +1 -1
  282. package/dist/shims/cache-runtime.d.ts +2 -2
  283. package/dist/shims/cache-runtime.js +31 -17
  284. package/dist/shims/cache-runtime.js.map +1 -1
  285. package/dist/shims/cache.d.ts +15 -3
  286. package/dist/shims/cache.js +45 -20
  287. package/dist/shims/cache.js.map +1 -1
  288. package/dist/shims/error-boundary.d.ts +17 -1
  289. package/dist/shims/error-boundary.js +31 -1
  290. package/dist/shims/error-boundary.js.map +1 -1
  291. package/dist/shims/fetch-cache.d.ts +4 -1
  292. package/dist/shims/fetch-cache.js +57 -16
  293. package/dist/shims/fetch-cache.js.map +1 -1
  294. package/dist/shims/head-state.js +2 -3
  295. package/dist/shims/head-state.js.map +1 -1
  296. package/dist/shims/headers.js +4 -44
  297. package/dist/shims/headers.js.map +1 -1
  298. package/dist/shims/i18n-state.js +2 -3
  299. package/dist/shims/i18n-state.js.map +1 -1
  300. package/dist/shims/image.js +93 -5
  301. package/dist/shims/image.js.map +1 -1
  302. package/dist/shims/internal/als-registry.d.ts +15 -0
  303. package/dist/shims/internal/als-registry.js +55 -0
  304. package/dist/shims/internal/als-registry.js.map +1 -0
  305. package/dist/shims/internal/cookie-serialize.d.ts +46 -0
  306. package/dist/shims/internal/cookie-serialize.js +51 -0
  307. package/dist/shims/internal/cookie-serialize.js.map +1 -0
  308. package/dist/shims/link.js +31 -26
  309. package/dist/shims/link.js.map +1 -1
  310. package/dist/shims/metadata.d.ts +26 -1
  311. package/dist/shims/metadata.js +94 -4
  312. package/dist/shims/metadata.js.map +1 -1
  313. package/dist/shims/navigation-state.js +2 -3
  314. package/dist/shims/navigation-state.js.map +1 -1
  315. package/dist/shims/navigation.d.ts +2 -7
  316. package/dist/shims/navigation.js +44 -36
  317. package/dist/shims/navigation.js.map +1 -1
  318. package/dist/shims/request-context.js +2 -4
  319. package/dist/shims/request-context.js.map +1 -1
  320. package/dist/shims/request-state-types.d.ts +1 -1
  321. package/dist/shims/router-state.js +2 -3
  322. package/dist/shims/router-state.js.map +1 -1
  323. package/dist/shims/router.js +2 -2
  324. package/dist/shims/router.js.map +1 -1
  325. package/dist/shims/server.js +5 -30
  326. package/dist/shims/server.js.map +1 -1
  327. package/dist/shims/slot.d.ts +1 -1
  328. package/dist/shims/slot.js +5 -4
  329. package/dist/shims/slot.js.map +1 -1
  330. package/dist/shims/thenable-params.d.ts +5 -2
  331. package/dist/shims/thenable-params.js +26 -6
  332. package/dist/shims/thenable-params.js.map +1 -1
  333. package/dist/shims/unified-request-context.d.ts +1 -1
  334. package/dist/shims/unified-request-context.js +3 -14
  335. package/dist/shims/unified-request-context.js.map +1 -1
  336. package/dist/shims/use-merged-ref.d.ts +7 -0
  337. package/dist/shims/use-merged-ref.js +40 -0
  338. package/dist/shims/use-merged-ref.js.map +1 -0
  339. package/dist/utils/base-path.d.ts +7 -1
  340. package/dist/utils/base-path.js +12 -1
  341. package/dist/utils/base-path.js.map +1 -1
  342. package/dist/utils/cache-control-metadata.d.ts +6 -0
  343. package/dist/utils/cache-control-metadata.js +16 -0
  344. package/dist/utils/cache-control-metadata.js.map +1 -0
  345. package/dist/utils/safe-json-file.d.ts +18 -0
  346. package/dist/utils/safe-json-file.js +25 -0
  347. package/dist/utils/safe-json-file.js.map +1 -0
  348. package/dist/utils/text-stream.d.ts +29 -0
  349. package/dist/utils/text-stream.js +66 -0
  350. package/dist/utils/text-stream.js.map +1 -0
  351. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-routes.js","names":[],"sources":["../../src/server/metadata-routes.ts"],"sourcesContent":["/**\n * File-based metadata route handling.\n *\n * Next.js supports special files in the app/ directory that auto-generate\n * metadata routes:\n * - sitemap.ts/.xml → /sitemap.xml (application/xml)\n * - robots.ts/.txt → /robots.txt (text/plain)\n * - manifest.ts/.json/.webmanifest → /manifest.webmanifest (application/manifest+json)\n * - icon.tsx/.png → /icon (image/*)\n * - opengraph-image.tsx/.png → /opengraph-image (image/*)\n * - twitter-image.tsx/.png → /twitter-image (image/*)\n * - apple-icon.tsx/.png → /apple-icon (image/*)\n * - favicon.ico → /favicon.ico (image/x-icon)\n *\n * Dynamic versions (ts/tsx/js) export a default function that returns the data.\n * Static versions (xml/txt/json/png/etc.) are served as-is.\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { matchRoutePattern } from \"../routing/route-pattern.js\";\n\n// -------------------------------------------------------------------\n// Types matching Next.js MetadataRoute\n// -------------------------------------------------------------------\n\nexport type SitemapEntry = {\n url: string;\n lastModified?: string | Date;\n changeFrequency?: \"always\" | \"hourly\" | \"daily\" | \"weekly\" | \"monthly\" | \"yearly\" | \"never\";\n priority?: number;\n alternates?: {\n languages?: Record<string, string>;\n };\n images?: string[];\n videos?: Array<{\n title: string;\n thumbnail_loc: string;\n description: string;\n content_loc?: string;\n player_loc?: string;\n duration?: number;\n expiration_date?: string | Date;\n rating?: number;\n view_count?: number;\n publication_date?: string | Date;\n family_friendly?: \"yes\" | \"no\";\n restriction?: { relationship: \"allow\" | \"deny\"; content: string };\n platform?: { relationship: \"allow\" | \"deny\"; content: string };\n requires_subscription?: \"yes\" | \"no\";\n uploader?: {\n info?: string;\n content?: string;\n };\n live?: \"yes\" | \"no\";\n tag?: string;\n }>;\n};\n\nexport type RobotsRule = {\n userAgent?: string | string[];\n allow?: string | string[];\n disallow?: string | string[];\n crawlDelay?: number;\n};\n\nexport type RobotsConfig = {\n rules: RobotsRule | RobotsRule[];\n sitemap?: string | string[];\n host?: string;\n};\n\nexport type ManifestConfig = {\n name?: string;\n short_name?: string;\n description?: string;\n start_url?: string;\n display?: \"fullscreen\" | \"standalone\" | \"minimal-ui\" | \"browser\";\n background_color?: string;\n theme_color?: string;\n icons?: Array<{\n src: string;\n sizes?: string;\n type?: string;\n purpose?: string;\n }>;\n [key: string]: unknown;\n};\n\n// -------------------------------------------------------------------\n// Known metadata file patterns\n// -------------------------------------------------------------------\n\n/** Map of metadata file base names to their URL path and content type. */\nexport const METADATA_FILE_MAP: Record<\n string,\n {\n /** URL path this file is served at */\n urlPath: string;\n /** Content type for the response */\n contentType: string;\n /** Whether this can be dynamic (.ts/.tsx/.js) */\n canBeDynamic: boolean;\n /** File extensions for static variants */\n staticExtensions: string[];\n /** File extensions for dynamic variants */\n dynamicExtensions: string[];\n /** Whether this can be nested in sub-segments */\n nestable: boolean;\n }\n> = {\n sitemap: {\n urlPath: \"/sitemap.xml\",\n contentType: \"application/xml\",\n canBeDynamic: true,\n staticExtensions: [\".xml\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: true,\n },\n robots: {\n urlPath: \"/robots.txt\",\n contentType: \"text/plain\",\n canBeDynamic: true,\n staticExtensions: [\".txt\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: false,\n },\n manifest: {\n urlPath: \"/manifest.webmanifest\",\n contentType: \"application/manifest+json\",\n canBeDynamic: true,\n staticExtensions: [\".json\", \".webmanifest\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: false,\n },\n favicon: {\n urlPath: \"/favicon.ico\",\n contentType: \"image/x-icon\",\n canBeDynamic: false,\n staticExtensions: [\".ico\"],\n dynamicExtensions: [],\n nestable: false,\n },\n icon: {\n urlPath: \"/icon\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".ico\", \".jpg\", \".jpeg\", \".png\", \".svg\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"opengraph-image\": {\n urlPath: \"/opengraph-image\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\", \".gif\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"twitter-image\": {\n urlPath: \"/twitter-image\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\", \".gif\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"apple-icon\": {\n urlPath: \"/apple-icon\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n};\n\n// -------------------------------------------------------------------\n// Serializers\n// -------------------------------------------------------------------\n\n/** Escape the five XML special characters in text content and attribute values. */\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\n/**\n * Convert a sitemap array to XML string.\n */\nexport function sitemapToXml(entries: SitemapEntry[]): string {\n const hasAlternates = entries.some((entry) => Object.keys(entry.alternates ?? {}).length > 0);\n const hasImages = entries.some((entry) => Boolean(entry.images?.length));\n const hasVideos = entries.some((entry) => Boolean(entry.videos?.length));\n let content = \"\";\n\n content += '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n content += '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n if (hasImages) {\n content += ' xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"';\n }\n if (hasVideos) {\n content += ' xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"';\n }\n if (hasAlternates) {\n content += ' xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n';\n } else {\n content += \">\\n\";\n }\n\n for (const entry of entries) {\n content += \"<url>\\n\";\n content += `<loc>${escapeXml(entry.url)}</loc>\\n`;\n\n const languages = entry.alternates?.languages;\n if (languages && Object.keys(languages).length) {\n for (const language in languages) {\n content += `<xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(language)}\" href=\"${escapeXml(languages[language])}\" />\\n`;\n }\n }\n\n if (entry.images?.length) {\n for (const image of entry.images) {\n content += `<image:image>\\n<image:loc>${escapeXml(image)}</image:loc>\\n</image:image>\\n`;\n }\n }\n\n if (entry.videos?.length) {\n for (const video of entry.videos) {\n const videoFields = [\n \"<video:video>\",\n `<video:title>${escapeXml(String(video.title))}</video:title>`,\n `<video:thumbnail_loc>${escapeXml(String(video.thumbnail_loc))}</video:thumbnail_loc>`,\n `<video:description>${escapeXml(String(video.description))}</video:description>`,\n video.content_loc &&\n `<video:content_loc>${escapeXml(String(video.content_loc))}</video:content_loc>`,\n video.player_loc &&\n `<video:player_loc>${escapeXml(String(video.player_loc))}</video:player_loc>`,\n video.duration && `<video:duration>${video.duration}</video:duration>`,\n video.view_count && `<video:view_count>${video.view_count}</video:view_count>`,\n video.tag && `<video:tag>${escapeXml(String(video.tag))}</video:tag>`,\n video.rating && `<video:rating>${video.rating}</video:rating>`,\n video.expiration_date &&\n `<video:expiration_date>${escapeXml(String(video.expiration_date))}</video:expiration_date>`,\n video.publication_date &&\n `<video:publication_date>${escapeXml(String(video.publication_date))}</video:publication_date>`,\n video.family_friendly &&\n `<video:family_friendly>${video.family_friendly}</video:family_friendly>`,\n video.requires_subscription &&\n `<video:requires_subscription>${video.requires_subscription}</video:requires_subscription>`,\n video.live && `<video:live>${video.live}</video:live>`,\n video.restriction &&\n `<video:restriction relationship=\"${escapeXml(String(video.restriction.relationship))}\">${escapeXml(String(video.restriction.content))}</video:restriction>`,\n video.platform &&\n `<video:platform relationship=\"${escapeXml(String(video.platform.relationship))}\">${escapeXml(String(video.platform.content))}</video:platform>`,\n video.uploader &&\n `<video:uploader${video.uploader.info ? ` info=\"${escapeXml(String(video.uploader.info))}\"` : \"\"}>${escapeXml(String(video.uploader.content))}</video:uploader>`,\n \"</video:video>\\n\",\n ].filter(Boolean);\n content += videoFields.join(\"\\n\");\n }\n }\n\n if (entry.lastModified) {\n content += `<lastmod>${serializeDate(entry.lastModified)}</lastmod>\\n`;\n }\n if (entry.changeFrequency) {\n content += `<changefreq>${entry.changeFrequency}</changefreq>\\n`;\n }\n if (typeof entry.priority === \"number\") {\n content += `<priority>${entry.priority}</priority>\\n`;\n }\n content += \"</url>\\n\";\n }\n\n content += \"</urlset>\\n\";\n return content;\n}\n\n/**\n * Convert a robots config to text format.\n */\nexport function robotsToText(config: RobotsConfig): string {\n const lines: string[] = [];\n const rules = Array.isArray(config.rules) ? config.rules : [config.rules];\n\n for (const rule of rules) {\n const agents = Array.isArray(rule.userAgent) ? rule.userAgent : [rule.userAgent ?? \"*\"];\n\n for (const agent of agents) {\n lines.push(`User-Agent: ${agent}`);\n }\n\n if (rule.allow) {\n const allows = Array.isArray(rule.allow) ? rule.allow : [rule.allow];\n for (const allow of allows) {\n lines.push(`Allow: ${allow}`);\n }\n }\n\n if (rule.disallow) {\n const disallows = Array.isArray(rule.disallow) ? rule.disallow : [rule.disallow];\n for (const disallow of disallows) {\n lines.push(`Disallow: ${disallow}`);\n }\n }\n\n if (rule.crawlDelay !== undefined) {\n lines.push(`Crawl-delay: ${rule.crawlDelay}`);\n }\n\n lines.push(\"\");\n }\n\n if (config.sitemap) {\n const sitemaps = Array.isArray(config.sitemap) ? config.sitemap : [config.sitemap];\n for (const sitemap of sitemaps) {\n lines.push(`Sitemap: ${sitemap}`);\n }\n }\n\n if (config.host) {\n lines.push(`Host: ${config.host}`);\n }\n\n return lines.join(\"\\n\").trim() + \"\\n\";\n}\n\n/**\n * Convert a manifest config to JSON string.\n */\nexport function manifestToJson(config: ManifestConfig): string {\n return JSON.stringify(config, null, 2);\n}\n\nfunction serializeDate(value: string | Date): string {\n return value instanceof Date ? value.toISOString() : value;\n}\n\n// -------------------------------------------------------------------\n// Static metadata URL resolution\n//\n// Ported from Next.js: packages/next/src/lib/metadata/get-metadata-route.ts\n// https://github.com/vercel/next.js/blob/7873aea/packages/next/src/lib/metadata/get-metadata-route.ts\n//\n// Static metadata files (like favicon.ico, icon.png) under dynamic parents\n// get a fixed URL with \"-\" placeholders instead of literal \"[param]\" segments.\n// Route groups and parallel route parents trigger a unique hash suffix to\n// avoid collisions.\n// -------------------------------------------------------------------\n\n/**\n * Regular expression pattern used to match route parameters.\n * Matches both single parameters and parameter groups.\n * Examples:\n * - `[[...slug]]` matches parameter group with key 'slug', repeat: true, optional: true\n * - `[...slug]` matches parameter group with key 'slug', repeat: true, optional: false\n * - `[[foo]]` matches parameter with key 'foo', repeat: false, optional: true\n * - `[bar]` matches parameter with key 'bar', repeat: false, optional: false\n */\nconst PARAMETER_PATTERN = /^([^[]*)\\[((?:\\[[^\\]]*\\])|[^\\]]+)\\](.*)$/;\n\nfunction isGroupSegment(segment: string): boolean {\n return segment.startsWith(\"(\") && segment.endsWith(\")\");\n}\n\nfunction isParallelRouteSegment(segment: string): boolean {\n return segment.startsWith(\"@\") && segment !== \"@children\";\n}\n\nfunction normalizeStaticMetadataRouteSegment(segment: string): string {\n let normalizedSegment = segment;\n let match = normalizedSegment.match(PARAMETER_PATTERN);\n while (match) {\n normalizedSegment = `${match[1]}-${match[3]}`;\n match = normalizedSegment.match(PARAMETER_PATTERN);\n }\n return normalizedSegment;\n}\n\nfunction getStaticMetadataRoute(appDirPath: string): string {\n const segments = appDirPath.split(\"/\").filter(Boolean);\n const normalizedSegments: string[] = [];\n for (const seg of segments) {\n // Strip route groups and all parallel route slots (including @children)\n // from the URL path. The @children slot is the default parallel route\n // and must also be invisible in the URL, matching Next.js behavior.\n if (isGroupSegment(seg) || seg.startsWith(\"@\")) continue;\n normalizedSegments.push(normalizeStaticMetadataRouteSegment(seg));\n }\n return normalizedSegments.length > 0 ? `/${normalizedSegments.join(\"/\")}` : \"\";\n}\n\nfunction hashMetadataRouteParentPath(parentPathname: string): string {\n let hash = 5381;\n for (let i = 0; i < parentPathname.length; i++) {\n hash = ((hash << 5) + hash + parentPathname.charCodeAt(i)) & 0xffffffff;\n }\n return (hash >>> 0).toString(36).slice(0, 6);\n}\n\nfunction getMetadataRouteSuffix(page: string): string {\n const lastSlash = page.lastIndexOf(\"/\");\n const parentPathname = lastSlash > 0 ? page.slice(0, lastSlash) : \"\";\n if (page.endsWith(\"/sitemap\") || page.endsWith(\"/sitemap.xml\")) return \"\";\n const segments = parentPathname.split(\"/\");\n const hasInvisibleParent = segments.some(\n (seg) => isGroupSegment(seg) || isParallelRouteSegment(seg),\n );\n if (!hasInvisibleParent) return \"\";\n return hashMetadataRouteParentPath(parentPathname);\n}\n\nfunction computeMetadataRouteSuffix(\n appDirPath: string,\n leafName: string,\n): { route: string; suffix: string } {\n const route = getStaticMetadataRoute(appDirPath);\n const pagePath =\n appDirPath === \"\" || appDirPath === \"/\" ? `/${leafName}` : `${appDirPath}/${leafName}`;\n const suffix = getMetadataRouteSuffix(pagePath);\n return { route, suffix };\n}\n\nfunction getMetadataRouteFilename(appDirPath: string, lastSegment: string): string {\n const ext = path.posix.extname(lastSegment);\n const name = lastSegment.slice(0, -ext.length || undefined);\n const { suffix } = computeMetadataRouteSuffix(appDirPath, name);\n const routeSuffix = suffix ? `-${suffix}` : \"\";\n return `${name}${routeSuffix}${ext}`;\n}\n\n/**\n * Compute the static URL for a metadata file given its app directory\n * parent path and filename.\n *\n * Example:\n * fillStaticMetadataSegment(\"/\", \"favicon.ico\") -> \"/favicon.ico\"\n * fillStaticMetadataSegment(\"/blog/[slug]\", \"favicon.ico\") -> \"/blog/-/favicon.ico\"\n * fillStaticMetadataSegment(\"/(group)/group\", \"icon.png\") -> \"/group/icon-131tc6.png\"\n */\nexport function fillStaticMetadataSegment(appDirPath: string, lastSegment: string): string {\n const route = getStaticMetadataRoute(appDirPath);\n const filename = getMetadataRouteFilename(appDirPath, lastSegment);\n return route === \"\" ? `/${filename}` : `${route}/${filename}`;\n}\n\n// -------------------------------------------------------------------\n// Metadata route discovery\n// -------------------------------------------------------------------\n\nexport type MetadataFileRoute = {\n /** Type of metadata file */\n type: string;\n /** Whether this is a dynamic (code-generated) route */\n isDynamic: boolean;\n /** Imported dynamic module for code-generated metadata routes. */\n module?: Record<string, unknown>;\n /** Absolute file path */\n filePath: string;\n /** Route prefix where this metadata applies, preserving dynamic segment names. */\n routePrefix: string;\n /** Raw app tree segments where this metadata file is colocated. */\n routeSegments?: string[];\n /** Pattern parts for matching dynamic metadata routes at request time. */\n patternParts?: string[];\n /** URL path this file is served at */\n servedUrl: string;\n /** Content type for the response */\n contentType: string;\n /** Optional metadata used to inject file-based routes into <head>. */\n headData?: MetadataRouteHeadData;\n /** Optional content hash for cache-busting metadata links. */\n contentHash?: string;\n /** Sibling .alt.txt file for static social image metadata routes. */\n altFilePath?: string;\n};\n\nexport type MetadataRouteHeadData =\n | {\n kind: \"favicon\" | \"icon\" | \"apple\";\n href: string;\n type?: string;\n sizes?: string;\n }\n | {\n kind: \"openGraph\" | \"twitter\";\n href: string;\n type?: string;\n width?: number;\n height?: number;\n alt?: string;\n }\n | {\n kind: \"manifest\";\n href: string;\n };\n\nexport function getMetadataRouteKind(\n route: Pick<MetadataFileRoute, \"type\">,\n): MetadataRouteHeadData[\"kind\"] | null {\n if (route.type === \"favicon\") return \"favicon\";\n if (route.type === \"icon\") return \"icon\";\n if (route.type === \"apple-icon\") return \"apple\";\n if (route.type === \"opengraph-image\") return \"openGraph\";\n if (route.type === \"twitter-image\") return \"twitter\";\n if (route.type === \"manifest\") return \"manifest\";\n return null;\n}\n\nexport function getMetadataImageRouteKind(\n route: Pick<MetadataFileRoute, \"type\">,\n): Extract<MetadataRouteHeadData[\"kind\"], \"icon\" | \"apple\" | \"openGraph\" | \"twitter\"> | null {\n const kind = getMetadataRouteKind(route);\n if (kind === \"icon\" || kind === \"apple\" || kind === \"openGraph\" || kind === \"twitter\") {\n return kind;\n }\n return null;\n}\n\nconst metadataImageIdPattern = /^[a-zA-Z0-9-_.]+$/;\n\nexport function isValidMetadataImageId(id: string): boolean {\n return metadataImageIdPattern.test(id);\n}\n\nexport function matchMetadataRoutePattern(\n urlParts: string[],\n patternParts: string[],\n): Record<string, string | string[]> | null {\n return matchRoutePattern(urlParts, patternParts);\n}\n\nfunction metadataRouteSuffix(parentSegments: string[], metaType: string): string {\n if (metaType === \"sitemap\") {\n // Sitemap is exempt per Next.js (robots/manifest are root-only, so\n // invisible parents never apply — but we keep the exemption list\n // matching getMetadataRouteSuffix for defensive consistency).\n return \"\";\n }\n\n const hasInvisibleParent = parentSegments.some(\n (segment) =>\n (segment.startsWith(\"(\") && segment.endsWith(\")\")) ||\n (segment.startsWith(\"@\") && segment !== \"@children\"),\n );\n if (!hasInvisibleParent) return \"\";\n\n return hashMetadataRouteParentPath(`/${parentSegments.join(\"/\")}`);\n}\n\nfunction withMetadataSuffix(urlPath: string, suffix: string): string {\n if (!suffix) return urlPath;\n const parsed = path.posix.parse(urlPath);\n return path.posix.join(parsed.dir || \"/\", `${parsed.name}-${suffix}${parsed.ext}`);\n}\n\nfunction getMetadataServedUrl(\n metaType: string,\n config: { urlPath: string },\n ext: string,\n isDynamic: boolean,\n suffix: string,\n routeBaseName: string,\n): string {\n if (\n isDynamic &&\n (metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\")\n ) {\n return withMetadataSuffix(`/${routeBaseName}`, suffix);\n }\n\n if (isDynamic) {\n return withMetadataSuffix(config.urlPath, suffix);\n }\n\n if (metaType === \"manifest\") {\n return withMetadataSuffix(`/${routeBaseName}${ext}`, suffix);\n }\n\n if (\n metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\"\n ) {\n return withMetadataSuffix(`/${routeBaseName}${ext}`, suffix);\n }\n\n return withMetadataSuffix(config.urlPath, suffix);\n}\n\nexport function matchMetadataFileBaseName(metaType: string, baseName: string): string | null {\n if (baseName === metaType) {\n return baseName;\n }\n\n if (\n metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\"\n ) {\n const suffix = baseName.slice(metaType.length);\n if (/^\\d$/.test(suffix)) {\n return baseName;\n }\n }\n\n return null;\n}\n\n/**\n * Scan an app directory for metadata files.\n */\nexport function scanMetadataFiles(appDir: string): MetadataFileRoute[] {\n const routes: MetadataFileRoute[] = [];\n\n // Scan the app directory recursively\n function scan(dir: string, urlPrefix: string, parentSegments: string[]): void {\n if (!fs.existsSync(dir)) return;\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const dirName = entry.name;\n if (dirName.startsWith(\"_\")) continue;\n\n const isRouteGroup = dirName.startsWith(\"(\") && dirName.endsWith(\")\");\n const isParallelRoute = dirName.startsWith(\"@\");\n const nextUrlPrefix =\n isRouteGroup || isParallelRoute ? urlPrefix : `${urlPrefix}/${dirName}`;\n scan(path.join(dir, dirName), nextUrlPrefix, [...parentSegments, dirName]);\n continue;\n }\n\n // Check each metadata file pattern\n const fileName = entry.name;\n const baseName = fileName.replace(/\\.[^.]+$/, \"\");\n const ext = fileName.slice(baseName.length);\n\n for (const [metaType, config] of Object.entries(METADATA_FILE_MAP)) {\n const routeBaseName = matchMetadataFileBaseName(metaType, baseName);\n if (!routeBaseName) continue;\n\n // Check nestability — non-nestable types only at root\n if (!config.nestable && urlPrefix !== \"\") continue;\n\n // Check if this is a static or dynamic variant\n const isStatic = config.staticExtensions.includes(ext);\n const isDynamic = config.dynamicExtensions.includes(ext);\n\n if (!isStatic && !isDynamic) continue;\n const appDirPath = parentSegments.length > 0 ? `/${parentSegments.join(\"/\")}` : \"\";\n const suffix = metadataRouteSuffix(parentSegments, metaType);\n const urlPath = getMetadataServedUrl(\n metaType,\n config,\n ext,\n isDynamic,\n suffix,\n routeBaseName,\n );\n const servedUrl = isStatic\n ? fillStaticMetadataSegment(appDirPath, `${routeBaseName}${ext}`)\n : urlPrefix === \"\"\n ? urlPath\n : `${urlPrefix}${urlPath}`;\n const altFilePath =\n isStatic && (metaType === \"opengraph-image\" || metaType === \"twitter-image\")\n ? resolveStaticMetadataAltFilePath(dir, baseName)\n : undefined;\n\n routes.push({\n type: metaType,\n isDynamic,\n filePath: path.join(dir, fileName),\n routePrefix: urlPrefix,\n routeSegments: parentSegments,\n servedUrl,\n contentType:\n isStatic && metaType === \"manifest\"\n ? config.contentType\n : isStatic\n ? getStaticContentType(ext, config.contentType)\n : config.contentType,\n altFilePath,\n });\n }\n }\n }\n\n scan(appDir, \"\", []);\n\n // Deduplicate: if both dynamic and static variants exist at the same URL,\n // keep only the dynamic one (matches Next.js behavior).\n const byUrl = new Map<string, MetadataFileRoute>();\n for (const route of routes) {\n const existing = byUrl.get(route.servedUrl);\n if (!existing) {\n byUrl.set(route.servedUrl, route);\n } else if (route.isDynamic && !existing.isDynamic) {\n // Dynamic takes priority over static\n byUrl.set(route.servedUrl, route);\n }\n // If both are static or both dynamic, keep the first one found\n }\n return Array.from(byUrl.values());\n}\n\nfunction resolveStaticMetadataAltFilePath(dir: string, baseName: string): string | undefined {\n const altPath = path.join(dir, `${baseName}.alt.txt`);\n return fs.existsSync(altPath) ? altPath : undefined;\n}\n\nfunction getStaticContentType(ext: string, fallback: string): string {\n const map: Record<string, string> = {\n \".xml\": \"application/xml\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n \".webmanifest\": \"application/manifest+json\",\n \".ico\": \"image/x-icon\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n };\n return map[ext] ?? fallback;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"metadata-routes.js","names":[],"sources":["../../src/server/metadata-routes.ts"],"sourcesContent":["/**\n * File-based metadata route handling.\n *\n * Next.js supports special files in the app/ directory that auto-generate\n * metadata routes:\n * - sitemap.ts/.xml → /sitemap.xml (application/xml)\n * - robots.ts/.txt → /robots.txt (text/plain)\n * - manifest.ts/.json/.webmanifest → /manifest.webmanifest (application/manifest+json)\n * - icon.tsx/.png → /icon (image/*)\n * - opengraph-image.tsx/.png → /opengraph-image (image/*)\n * - twitter-image.tsx/.png → /twitter-image (image/*)\n * - apple-icon.tsx/.png → /apple-icon (image/*)\n * - favicon.ico → /favicon.ico (image/x-icon)\n *\n * Dynamic versions (ts/tsx/js) export a default function that returns the data.\n * Static versions (xml/txt/json/png/etc.) are served as-is.\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { matchRoutePattern } from \"../routing/route-pattern.js\";\n\n// -------------------------------------------------------------------\n// Types matching Next.js MetadataRoute\n// -------------------------------------------------------------------\n\nexport type SitemapEntry = {\n url: string;\n lastModified?: string | Date;\n changeFrequency?: \"always\" | \"hourly\" | \"daily\" | \"weekly\" | \"monthly\" | \"yearly\" | \"never\";\n priority?: number;\n alternates?: {\n languages?: Record<string, string>;\n };\n images?: string[];\n videos?: Array<{\n title: string;\n thumbnail_loc: string;\n description: string;\n content_loc?: string;\n player_loc?: string;\n duration?: number;\n expiration_date?: string | Date;\n rating?: number;\n view_count?: number;\n publication_date?: string | Date;\n family_friendly?: \"yes\" | \"no\";\n restriction?: { relationship: \"allow\" | \"deny\"; content: string };\n platform?: { relationship: \"allow\" | \"deny\"; content: string };\n requires_subscription?: \"yes\" | \"no\";\n uploader?: {\n info?: string;\n content?: string;\n };\n live?: \"yes\" | \"no\";\n tag?: string;\n }>;\n};\n\nexport type RobotsRule = {\n userAgent?: string | string[];\n allow?: string | string[];\n disallow?: string | string[];\n crawlDelay?: number;\n other?: Record<string, string | number | Array<string | number>>;\n};\n\nexport type RobotsConfig = {\n rules: RobotsRule | RobotsRule[];\n sitemap?: string | string[];\n host?: string;\n};\n\nexport type ManifestConfig = {\n name?: string;\n short_name?: string;\n description?: string;\n start_url?: string;\n display?: \"fullscreen\" | \"standalone\" | \"minimal-ui\" | \"browser\";\n background_color?: string;\n theme_color?: string;\n icons?: Array<{\n src: string;\n sizes?: string;\n type?: string;\n purpose?: string;\n }>;\n [key: string]: unknown;\n};\n\n// -------------------------------------------------------------------\n// Known metadata file patterns\n// -------------------------------------------------------------------\n\n/** Map of metadata file base names to their URL path and content type. */\nexport const METADATA_FILE_MAP: Record<\n string,\n {\n /** URL path this file is served at */\n urlPath: string;\n /** Content type for the response */\n contentType: string;\n /** Whether this can be dynamic (.ts/.tsx/.js) */\n canBeDynamic: boolean;\n /** File extensions for static variants */\n staticExtensions: string[];\n /** File extensions for dynamic variants */\n dynamicExtensions: string[];\n /** Whether this can be nested in sub-segments */\n nestable: boolean;\n }\n> = {\n sitemap: {\n urlPath: \"/sitemap.xml\",\n contentType: \"application/xml\",\n canBeDynamic: true,\n staticExtensions: [\".xml\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: true,\n },\n robots: {\n urlPath: \"/robots.txt\",\n contentType: \"text/plain\",\n canBeDynamic: true,\n staticExtensions: [\".txt\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: false,\n },\n manifest: {\n urlPath: \"/manifest.webmanifest\",\n contentType: \"application/manifest+json\",\n canBeDynamic: true,\n staticExtensions: [\".json\", \".webmanifest\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: false,\n },\n favicon: {\n urlPath: \"/favicon.ico\",\n contentType: \"image/x-icon\",\n canBeDynamic: false,\n staticExtensions: [\".ico\"],\n dynamicExtensions: [],\n nestable: false,\n },\n icon: {\n urlPath: \"/icon\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".ico\", \".jpg\", \".jpeg\", \".png\", \".svg\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"opengraph-image\": {\n urlPath: \"/opengraph-image\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\", \".gif\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"twitter-image\": {\n urlPath: \"/twitter-image\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\", \".gif\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"apple-icon\": {\n urlPath: \"/apple-icon\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n};\n\n// -------------------------------------------------------------------\n// Serializers\n// -------------------------------------------------------------------\n\n/** Escape the five XML special characters in text content and attribute values. */\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\n/**\n * Convert a sitemap array to XML string.\n */\nexport function sitemapToXml(entries: SitemapEntry[]): string {\n const hasAlternates = entries.some((entry) => Object.keys(entry.alternates ?? {}).length > 0);\n const hasImages = entries.some((entry) => Boolean(entry.images?.length));\n const hasVideos = entries.some((entry) => Boolean(entry.videos?.length));\n let content = \"\";\n\n content += '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n content += '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n if (hasImages) {\n content += ' xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"';\n }\n if (hasVideos) {\n content += ' xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"';\n }\n if (hasAlternates) {\n content += ' xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n';\n } else {\n content += \">\\n\";\n }\n\n for (const entry of entries) {\n content += \"<url>\\n\";\n content += `<loc>${escapeXml(entry.url)}</loc>\\n`;\n\n const languages = entry.alternates?.languages;\n if (languages && Object.keys(languages).length) {\n for (const language in languages) {\n content += `<xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(language)}\" href=\"${escapeXml(languages[language])}\" />\\n`;\n }\n }\n\n if (entry.images?.length) {\n for (const image of entry.images) {\n content += `<image:image>\\n<image:loc>${escapeXml(image)}</image:loc>\\n</image:image>\\n`;\n }\n }\n\n if (entry.videos?.length) {\n for (const video of entry.videos) {\n const videoFields = [\n \"<video:video>\",\n `<video:title>${escapeXml(String(video.title))}</video:title>`,\n `<video:thumbnail_loc>${escapeXml(String(video.thumbnail_loc))}</video:thumbnail_loc>`,\n `<video:description>${escapeXml(String(video.description))}</video:description>`,\n video.content_loc &&\n `<video:content_loc>${escapeXml(String(video.content_loc))}</video:content_loc>`,\n video.player_loc &&\n `<video:player_loc>${escapeXml(String(video.player_loc))}</video:player_loc>`,\n video.duration && `<video:duration>${video.duration}</video:duration>`,\n video.view_count && `<video:view_count>${video.view_count}</video:view_count>`,\n video.tag && `<video:tag>${escapeXml(String(video.tag))}</video:tag>`,\n video.rating && `<video:rating>${video.rating}</video:rating>`,\n video.expiration_date &&\n `<video:expiration_date>${escapeXml(String(video.expiration_date))}</video:expiration_date>`,\n video.publication_date &&\n `<video:publication_date>${escapeXml(String(video.publication_date))}</video:publication_date>`,\n video.family_friendly &&\n `<video:family_friendly>${video.family_friendly}</video:family_friendly>`,\n video.requires_subscription &&\n `<video:requires_subscription>${video.requires_subscription}</video:requires_subscription>`,\n video.live && `<video:live>${video.live}</video:live>`,\n video.restriction &&\n `<video:restriction relationship=\"${escapeXml(String(video.restriction.relationship))}\">${escapeXml(String(video.restriction.content))}</video:restriction>`,\n video.platform &&\n `<video:platform relationship=\"${escapeXml(String(video.platform.relationship))}\">${escapeXml(String(video.platform.content))}</video:platform>`,\n video.uploader &&\n `<video:uploader${video.uploader.info ? ` info=\"${escapeXml(String(video.uploader.info))}\"` : \"\"}>${escapeXml(String(video.uploader.content))}</video:uploader>`,\n \"</video:video>\\n\",\n ].filter(Boolean);\n content += videoFields.join(\"\\n\");\n }\n }\n\n if (entry.lastModified) {\n content += `<lastmod>${serializeDate(entry.lastModified)}</lastmod>\\n`;\n }\n if (entry.changeFrequency) {\n content += `<changefreq>${entry.changeFrequency}</changefreq>\\n`;\n }\n if (typeof entry.priority === \"number\") {\n content += `<priority>${entry.priority}</priority>\\n`;\n }\n content += \"</url>\\n\";\n }\n\n content += \"</urlset>\\n\";\n return content;\n}\n\n/**\n * Convert a robots config to text format.\n */\nexport function robotsToText(config: RobotsConfig): string {\n const lines: string[] = [];\n const rules = Array.isArray(config.rules) ? config.rules : [config.rules];\n\n for (const rule of rules) {\n const agents = Array.isArray(rule.userAgent) ? rule.userAgent : [rule.userAgent ?? \"*\"];\n\n for (const agent of agents) {\n lines.push(`User-Agent: ${agent}`);\n }\n\n if (rule.allow) {\n const allows = Array.isArray(rule.allow) ? rule.allow : [rule.allow];\n for (const allow of allows) {\n lines.push(`Allow: ${allow}`);\n }\n }\n\n if (rule.disallow) {\n const disallows = Array.isArray(rule.disallow) ? rule.disallow : [rule.disallow];\n for (const disallow of disallows) {\n lines.push(`Disallow: ${disallow}`);\n }\n }\n\n if (rule.crawlDelay !== undefined) {\n lines.push(`Crawl-delay: ${rule.crawlDelay}`);\n }\n\n if (rule.other) {\n for (const key of Object.keys(rule.other)) {\n const value = rule.other[key];\n if (value == null) continue;\n const values = Array.isArray(value) ? value : [value];\n for (const v of values) {\n lines.push(`${key}: ${v}`);\n }\n }\n }\n\n lines.push(\"\");\n }\n\n if (config.sitemap) {\n const sitemaps = Array.isArray(config.sitemap) ? config.sitemap : [config.sitemap];\n for (const sitemap of sitemaps) {\n lines.push(`Sitemap: ${sitemap}`);\n }\n }\n\n if (config.host) {\n lines.push(`Host: ${config.host}`);\n }\n\n return lines.join(\"\\n\").trim() + \"\\n\";\n}\n\n/**\n * Convert a manifest config to JSON string.\n */\nexport function manifestToJson(config: ManifestConfig): string {\n return JSON.stringify(config, null, 2);\n}\n\nfunction serializeDate(value: string | Date): string {\n return value instanceof Date ? value.toISOString() : value;\n}\n\n// -------------------------------------------------------------------\n// Static metadata URL resolution\n//\n// Ported from Next.js: packages/next/src/lib/metadata/get-metadata-route.ts\n// https://github.com/vercel/next.js/blob/7873aea/packages/next/src/lib/metadata/get-metadata-route.ts\n//\n// Static metadata files (like favicon.ico, icon.png) under dynamic parents\n// get a fixed URL with \"-\" placeholders instead of literal \"[param]\" segments.\n// Route groups and parallel route parents trigger a unique hash suffix to\n// avoid collisions.\n// -------------------------------------------------------------------\n\n/**\n * Regular expression pattern used to match route parameters.\n * Matches both single parameters and parameter groups.\n * Examples:\n * - `[[...slug]]` matches parameter group with key 'slug', repeat: true, optional: true\n * - `[...slug]` matches parameter group with key 'slug', repeat: true, optional: false\n * - `[[foo]]` matches parameter with key 'foo', repeat: false, optional: true\n * - `[bar]` matches parameter with key 'bar', repeat: false, optional: false\n */\nconst PARAMETER_PATTERN = /^([^[]*)\\[((?:\\[[^\\]]*\\])|[^\\]]+)\\](.*)$/;\n\nfunction isGroupSegment(segment: string): boolean {\n return segment.startsWith(\"(\") && segment.endsWith(\")\");\n}\n\nfunction isParallelRouteSegment(segment: string): boolean {\n return segment.startsWith(\"@\") && segment !== \"@children\";\n}\n\nfunction normalizeStaticMetadataRouteSegment(segment: string): string {\n let normalizedSegment = segment;\n let match = normalizedSegment.match(PARAMETER_PATTERN);\n while (match) {\n normalizedSegment = `${match[1]}-${match[3]}`;\n match = normalizedSegment.match(PARAMETER_PATTERN);\n }\n return normalizedSegment;\n}\n\nfunction getStaticMetadataRoute(appDirPath: string): string {\n const segments = appDirPath.split(\"/\").filter(Boolean);\n const normalizedSegments: string[] = [];\n for (const seg of segments) {\n // Strip route groups and all parallel route slots (including @children)\n // from the URL path. The @children slot is the default parallel route\n // and must also be invisible in the URL, matching Next.js behavior.\n if (isGroupSegment(seg) || seg.startsWith(\"@\")) continue;\n normalizedSegments.push(normalizeStaticMetadataRouteSegment(seg));\n }\n return normalizedSegments.length > 0 ? `/${normalizedSegments.join(\"/\")}` : \"\";\n}\n\nfunction hashMetadataRouteParentPath(parentPathname: string): string {\n let hash = 5381;\n for (let i = 0; i < parentPathname.length; i++) {\n hash = ((hash << 5) + hash + parentPathname.charCodeAt(i)) & 0xffffffff;\n }\n return (hash >>> 0).toString(36).slice(0, 6);\n}\n\nfunction getMetadataRouteSuffix(page: string): string {\n const lastSlash = page.lastIndexOf(\"/\");\n const parentPathname = lastSlash > 0 ? page.slice(0, lastSlash) : \"\";\n if (page.endsWith(\"/sitemap\") || page.endsWith(\"/sitemap.xml\")) return \"\";\n const segments = parentPathname.split(\"/\");\n const hasInvisibleParent = segments.some(\n (seg) => isGroupSegment(seg) || isParallelRouteSegment(seg),\n );\n if (!hasInvisibleParent) return \"\";\n return hashMetadataRouteParentPath(parentPathname);\n}\n\nfunction computeMetadataRouteSuffix(\n appDirPath: string,\n leafName: string,\n): { route: string; suffix: string } {\n const route = getStaticMetadataRoute(appDirPath);\n const pagePath =\n appDirPath === \"\" || appDirPath === \"/\" ? `/${leafName}` : `${appDirPath}/${leafName}`;\n const suffix = getMetadataRouteSuffix(pagePath);\n return { route, suffix };\n}\n\nfunction getMetadataRouteFilename(appDirPath: string, lastSegment: string): string {\n const ext = path.posix.extname(lastSegment);\n const name = lastSegment.slice(0, -ext.length || undefined);\n const { suffix } = computeMetadataRouteSuffix(appDirPath, name);\n const routeSuffix = suffix ? `-${suffix}` : \"\";\n return `${name}${routeSuffix}${ext}`;\n}\n\n/**\n * Compute the static URL for a metadata file given its app directory\n * parent path and filename.\n *\n * Example:\n * fillStaticMetadataSegment(\"/\", \"favicon.ico\") -> \"/favicon.ico\"\n * fillStaticMetadataSegment(\"/blog/[slug]\", \"favicon.ico\") -> \"/blog/-/favicon.ico\"\n * fillStaticMetadataSegment(\"/(group)/group\", \"icon.png\") -> \"/group/icon-131tc6.png\"\n */\nexport function fillStaticMetadataSegment(appDirPath: string, lastSegment: string): string {\n const route = getStaticMetadataRoute(appDirPath);\n const filename = getMetadataRouteFilename(appDirPath, lastSegment);\n return route === \"\" ? `/${filename}` : `${route}/${filename}`;\n}\n\n// -------------------------------------------------------------------\n// Metadata route discovery\n// -------------------------------------------------------------------\n\nexport type MetadataFileRoute = {\n /** Type of metadata file */\n type: string;\n /** Whether this is a dynamic (code-generated) route */\n isDynamic: boolean;\n /** Imported dynamic module for code-generated metadata routes. */\n module?: Record<string, unknown>;\n /** Absolute file path */\n filePath: string;\n /** Route prefix where this metadata applies, preserving dynamic segment names. */\n routePrefix: string;\n /** Raw app tree segments where this metadata file is colocated. */\n routeSegments?: string[];\n /** Pattern parts for matching dynamic metadata routes at request time. */\n patternParts?: string[];\n /** URL path this file is served at */\n servedUrl: string;\n /** Content type for the response */\n contentType: string;\n /** Optional metadata used to inject file-based routes into <head>. */\n headData?: MetadataRouteHeadData;\n /** Optional content hash for cache-busting metadata links. */\n contentHash?: string;\n /** Sibling .alt.txt file for static social image metadata routes. */\n altFilePath?: string;\n};\n\nexport type MetadataRouteHeadData =\n | {\n kind: \"favicon\" | \"icon\" | \"apple\";\n href: string;\n type?: string;\n sizes?: string;\n }\n | {\n kind: \"openGraph\" | \"twitter\";\n href: string;\n type?: string;\n width?: number;\n height?: number;\n alt?: string;\n }\n | {\n kind: \"manifest\";\n href: string;\n };\n\nexport function getMetadataRouteKind(\n route: Pick<MetadataFileRoute, \"type\">,\n): MetadataRouteHeadData[\"kind\"] | null {\n if (route.type === \"favicon\") return \"favicon\";\n if (route.type === \"icon\") return \"icon\";\n if (route.type === \"apple-icon\") return \"apple\";\n if (route.type === \"opengraph-image\") return \"openGraph\";\n if (route.type === \"twitter-image\") return \"twitter\";\n if (route.type === \"manifest\") return \"manifest\";\n return null;\n}\n\nexport function getMetadataImageRouteKind(\n route: Pick<MetadataFileRoute, \"type\">,\n): Extract<MetadataRouteHeadData[\"kind\"], \"icon\" | \"apple\" | \"openGraph\" | \"twitter\"> | null {\n const kind = getMetadataRouteKind(route);\n if (kind === \"icon\" || kind === \"apple\" || kind === \"openGraph\" || kind === \"twitter\") {\n return kind;\n }\n return null;\n}\n\nconst metadataImageIdPattern = /^[a-zA-Z0-9-_.]+$/;\n\nexport function isValidMetadataImageId(id: string): boolean {\n return metadataImageIdPattern.test(id);\n}\n\nexport function matchMetadataRoutePattern(\n urlParts: string[],\n patternParts: string[],\n): Record<string, string | string[]> | null {\n return matchRoutePattern(urlParts, patternParts);\n}\n\nfunction metadataRouteSuffix(parentSegments: string[], metaType: string): string {\n if (metaType === \"sitemap\") {\n // Sitemap is exempt per Next.js (robots/manifest are root-only, so\n // invisible parents never apply — but we keep the exemption list\n // matching getMetadataRouteSuffix for defensive consistency).\n return \"\";\n }\n\n const hasInvisibleParent = parentSegments.some(\n (segment) =>\n (segment.startsWith(\"(\") && segment.endsWith(\")\")) ||\n (segment.startsWith(\"@\") && segment !== \"@children\"),\n );\n if (!hasInvisibleParent) return \"\";\n\n return hashMetadataRouteParentPath(`/${parentSegments.join(\"/\")}`);\n}\n\nfunction withMetadataSuffix(urlPath: string, suffix: string): string {\n if (!suffix) return urlPath;\n const parsed = path.posix.parse(urlPath);\n return path.posix.join(parsed.dir || \"/\", `${parsed.name}-${suffix}${parsed.ext}`);\n}\n\nfunction getMetadataServedUrl(\n metaType: string,\n config: { urlPath: string },\n ext: string,\n isDynamic: boolean,\n suffix: string,\n routeBaseName: string,\n): string {\n if (\n isDynamic &&\n (metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\")\n ) {\n return withMetadataSuffix(`/${routeBaseName}`, suffix);\n }\n\n if (isDynamic) {\n return withMetadataSuffix(config.urlPath, suffix);\n }\n\n if (metaType === \"manifest\") {\n return withMetadataSuffix(`/${routeBaseName}${ext}`, suffix);\n }\n\n if (\n metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\"\n ) {\n return withMetadataSuffix(`/${routeBaseName}${ext}`, suffix);\n }\n\n return withMetadataSuffix(config.urlPath, suffix);\n}\n\nexport function matchMetadataFileBaseName(metaType: string, baseName: string): string | null {\n if (baseName === metaType) {\n return baseName;\n }\n\n if (\n metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\"\n ) {\n const suffix = baseName.slice(metaType.length);\n if (/^\\d$/.test(suffix)) {\n return baseName;\n }\n }\n\n return null;\n}\n\n/**\n * Scan an app directory for metadata files.\n */\nexport function scanMetadataFiles(appDir: string): MetadataFileRoute[] {\n const routes: MetadataFileRoute[] = [];\n\n // Scan the app directory recursively\n function scan(dir: string, urlPrefix: string, parentSegments: string[]): void {\n if (!fs.existsSync(dir)) return;\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const dirName = entry.name;\n if (dirName.startsWith(\"_\")) continue;\n\n const isRouteGroup = dirName.startsWith(\"(\") && dirName.endsWith(\")\");\n const isParallelRoute = dirName.startsWith(\"@\");\n const nextUrlPrefix =\n isRouteGroup || isParallelRoute ? urlPrefix : `${urlPrefix}/${dirName}`;\n scan(path.join(dir, dirName), nextUrlPrefix, [...parentSegments, dirName]);\n continue;\n }\n\n // Check each metadata file pattern\n const fileName = entry.name;\n const baseName = fileName.replace(/\\.[^.]+$/, \"\");\n const ext = fileName.slice(baseName.length);\n\n for (const [metaType, config] of Object.entries(METADATA_FILE_MAP)) {\n const routeBaseName = matchMetadataFileBaseName(metaType, baseName);\n if (!routeBaseName) continue;\n\n // Check nestability — non-nestable types only at root\n if (!config.nestable && urlPrefix !== \"\") continue;\n\n // Check if this is a static or dynamic variant\n const isStatic = config.staticExtensions.includes(ext);\n const isDynamic = config.dynamicExtensions.includes(ext);\n\n if (!isStatic && !isDynamic) continue;\n const appDirPath = parentSegments.length > 0 ? `/${parentSegments.join(\"/\")}` : \"\";\n const suffix = metadataRouteSuffix(parentSegments, metaType);\n const urlPath = getMetadataServedUrl(\n metaType,\n config,\n ext,\n isDynamic,\n suffix,\n routeBaseName,\n );\n const servedUrl = isStatic\n ? fillStaticMetadataSegment(appDirPath, `${routeBaseName}${ext}`)\n : urlPrefix === \"\"\n ? urlPath\n : `${urlPrefix}${urlPath}`;\n const altFilePath =\n isStatic && (metaType === \"opengraph-image\" || metaType === \"twitter-image\")\n ? resolveStaticMetadataAltFilePath(dir, baseName)\n : undefined;\n\n routes.push({\n type: metaType,\n isDynamic,\n filePath: path.join(dir, fileName),\n routePrefix: urlPrefix,\n routeSegments: parentSegments,\n servedUrl,\n contentType:\n isStatic && metaType === \"manifest\"\n ? config.contentType\n : isStatic\n ? getStaticContentType(ext, config.contentType)\n : config.contentType,\n altFilePath,\n });\n }\n }\n }\n\n scan(appDir, \"\", []);\n\n // Deduplicate: if both dynamic and static variants exist at the same URL,\n // keep only the dynamic one (matches Next.js behavior).\n const byUrl = new Map<string, MetadataFileRoute>();\n for (const route of routes) {\n const existing = byUrl.get(route.servedUrl);\n if (!existing) {\n byUrl.set(route.servedUrl, route);\n } else if (route.isDynamic && !existing.isDynamic) {\n // Dynamic takes priority over static\n byUrl.set(route.servedUrl, route);\n }\n // If both are static or both dynamic, keep the first one found\n }\n return Array.from(byUrl.values());\n}\n\nfunction resolveStaticMetadataAltFilePath(dir: string, baseName: string): string | undefined {\n const altPath = path.join(dir, `${baseName}.alt.txt`);\n return fs.existsSync(altPath) ? altPath : undefined;\n}\n\nfunction getStaticContentType(ext: string, fallback: string): string {\n const map: Record<string, string> = {\n \".xml\": \"application/xml\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n \".webmanifest\": \"application/manifest+json\",\n \".ico\": \"image/x-icon\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n };\n return map[ext] ?? fallback;\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { removeTrailingSlash } from "../utils/base-path.js";
1
2
  import { checkHasConditions, requestContextFromRequest, safeRegExp } from "../config/config-matchers.js";
2
3
  //#region src/server/middleware-matcher.ts
3
4
  const EMPTY_MIDDLEWARE_REQUEST_CONTEXT = {
@@ -46,8 +47,7 @@ function stripLocalePrefix(pathname, i18nConfig) {
46
47
  const segments = pathname.split("/");
47
48
  const firstSegment = segments[1];
48
49
  if (!firstSegment || !i18nConfig.locales.includes(firstSegment)) return null;
49
- const stripped = "/" + segments.slice(2).join("/");
50
- return stripped === "/" ? "/" : stripped.replace(/\/+$/, "") || "/";
50
+ return removeTrailingSlash("/" + segments.slice(2).join("/"));
51
51
  }
52
52
  function matchPattern(pathname, pattern) {
53
53
  let cached = _mwPatternCache.get(pattern);
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-matcher.js","names":[],"sources":["../../src/server/middleware-matcher.ts"],"sourcesContent":["import {\n checkHasConditions,\n requestContextFromRequest,\n safeRegExp,\n type RequestContext,\n} from \"../config/config-matchers.js\";\nimport type { HasCondition, NextI18nConfig } from \"../config/next-config.js\";\n\nexport type MiddlewareMatcherObject = {\n source: string;\n locale?: false;\n has?: HasCondition[];\n missing?: HasCondition[];\n};\n\nexport type MatcherConfig = string | Array<string | MiddlewareMatcherObject>;\n\nconst EMPTY_MIDDLEWARE_REQUEST_CONTEXT: RequestContext = {\n headers: new Headers(),\n cookies: {},\n query: new URLSearchParams(),\n host: \"\",\n};\n\nconst _mwPatternCache = new Map<string, RegExp | null>();\n\nexport function matchesMiddleware(\n pathname: string,\n matcher: MatcherConfig | undefined,\n request?: Request,\n i18nConfig?: NextI18nConfig | null,\n): boolean {\n if (!matcher) {\n return true;\n }\n\n if (typeof matcher === \"string\") {\n return matchMatcherPattern(pathname, matcher, i18nConfig);\n }\n if (!Array.isArray(matcher)) {\n return false;\n }\n\n const requestContext = request\n ? requestContextFromRequest(request)\n : EMPTY_MIDDLEWARE_REQUEST_CONTEXT;\n\n for (const m of matcher) {\n if (typeof m === \"string\") {\n if (matchMatcherPattern(pathname, m, i18nConfig)) {\n return true;\n }\n continue;\n }\n\n if (isValidMiddlewareMatcherObject(m)) {\n if (!matchObjectMatcher(pathname, m, i18nConfig)) {\n continue;\n }\n\n if (!checkHasConditions(m.has, m.missing, requestContext)) {\n continue;\n }\n\n return true;\n }\n }\n\n return false;\n}\n\nfunction isValidMiddlewareMatcherObject(value: unknown): value is MiddlewareMatcherObject {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\n if (!(\"source\" in value) || typeof value.source !== \"string\") return false;\n\n for (const key of Object.keys(value)) {\n if (key !== \"source\" && key !== \"locale\" && key !== \"has\" && key !== \"missing\") {\n return false;\n }\n }\n\n if (\"locale\" in value && value.locale !== undefined && value.locale !== false) return false;\n if (\"has\" in value && value.has !== undefined && !Array.isArray(value.has)) return false;\n if (\"missing\" in value && value.missing !== undefined && !Array.isArray(value.missing)) {\n return false;\n }\n\n return true;\n}\n\nfunction matchMatcherPattern(\n pathname: string,\n pattern: string,\n i18nConfig?: NextI18nConfig | null,\n): boolean {\n if (!i18nConfig) return matchPattern(pathname, pattern);\n\n const localeStrippedPathname = stripLocalePrefix(pathname, i18nConfig);\n return matchPattern(localeStrippedPathname ?? pathname, pattern);\n}\n\nfunction matchObjectMatcher(\n pathname: string,\n matcher: MiddlewareMatcherObject,\n i18nConfig?: NextI18nConfig | null,\n): boolean {\n return matcher.locale === false\n ? matchPattern(pathname, matcher.source)\n : matchMatcherPattern(pathname, matcher.source, i18nConfig);\n}\n\nfunction stripLocalePrefix(pathname: string, i18nConfig: NextI18nConfig): string | null {\n if (pathname === \"/\") return null;\n\n const segments = pathname.split(\"/\");\n const firstSegment = segments[1];\n if (!firstSegment || !i18nConfig.locales.includes(firstSegment)) {\n return null;\n }\n\n const stripped = \"/\" + segments.slice(2).join(\"/\");\n return stripped === \"/\" ? \"/\" : stripped.replace(/\\/+$/, \"\") || \"/\";\n}\n\nexport function matchPattern(pathname: string, pattern: string): boolean {\n let cached = _mwPatternCache.get(pattern);\n if (cached === undefined) {\n cached = compileMatcherPattern(pattern);\n _mwPatternCache.set(pattern, cached);\n }\n if (cached === null) return pathname === pattern;\n return cached.test(pathname);\n}\n\nfunction extractConstraint(str: string, re: RegExp): string | null {\n if (str[re.lastIndex] !== \"(\") return null;\n const start = re.lastIndex + 1;\n let depth = 1;\n let i = start;\n while (i < str.length && depth > 0) {\n if (str[i] === \"(\") depth++;\n else if (str[i] === \")\") depth--;\n i++;\n }\n if (depth !== 0) return null;\n re.lastIndex = i;\n return str.slice(start, i - 1);\n}\n\nfunction compileMatcherPattern(pattern: string): RegExp | null {\n const hasConstraints = /:[\\w-]+[*+]?\\(/.test(pattern);\n\n if (!hasConstraints && (pattern.includes(\"(\") || pattern.includes(\"\\\\\"))) {\n return safeRegExp(\"^\" + pattern + \"$\");\n }\n\n let regexStr = \"\";\n const tokenRe = /\\/:([\\w-]+)\\*|\\/:([\\w-]+)\\+|:([\\w-]+)|[.]|[^/:.]+|./g;\n let tok: RegExpExecArray | null;\n while ((tok = tokenRe.exec(pattern)) !== null) {\n if (tok[1] !== undefined) {\n const constraint = hasConstraints ? extractConstraint(pattern, tokenRe) : null;\n regexStr += constraint !== null ? `(?:/(${constraint}))?` : \"(?:/.*)?\";\n } else if (tok[2] !== undefined) {\n const constraint = hasConstraints ? extractConstraint(pattern, tokenRe) : null;\n regexStr += constraint !== null ? `(?:/(${constraint}))` : \"(?:/.+)\";\n } else if (tok[3] !== undefined) {\n const constraint = hasConstraints ? extractConstraint(pattern, tokenRe) : null;\n const isOptional = pattern[tokenRe.lastIndex] === \"?\";\n if (isOptional) tokenRe.lastIndex += 1;\n\n const group = constraint !== null ? `(${constraint})` : \"([^/]+)\";\n\n if (isOptional && regexStr.endsWith(\"/\")) {\n regexStr = regexStr.slice(0, -1) + `(?:/${group})?`;\n } else if (isOptional) {\n regexStr += `${group}?`;\n } else {\n regexStr += group;\n }\n } else if (tok[0] === \".\") {\n regexStr += \"\\\\.\";\n } else {\n regexStr += tok[0];\n }\n }\n\n return safeRegExp(\"^\" + regexStr + \"$\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"middleware-matcher.js","names":[],"sources":["../../src/server/middleware-matcher.ts"],"sourcesContent":["import {\n checkHasConditions,\n requestContextFromRequest,\n safeRegExp,\n type RequestContext,\n} from \"../config/config-matchers.js\";\nimport type { HasCondition, NextI18nConfig } from \"../config/next-config.js\";\nimport { removeTrailingSlash } from \"../utils/base-path.js\";\n\nexport type MiddlewareMatcherObject = {\n source: string;\n locale?: false;\n has?: HasCondition[];\n missing?: HasCondition[];\n};\n\nexport type MatcherConfig = string | Array<string | MiddlewareMatcherObject>;\n\nconst EMPTY_MIDDLEWARE_REQUEST_CONTEXT: RequestContext = {\n headers: new Headers(),\n cookies: {},\n query: new URLSearchParams(),\n host: \"\",\n};\n\nconst _mwPatternCache = new Map<string, RegExp | null>();\n\nexport function matchesMiddleware(\n pathname: string,\n matcher: MatcherConfig | undefined,\n request?: Request,\n i18nConfig?: NextI18nConfig | null,\n): boolean {\n if (!matcher) {\n return true;\n }\n\n if (typeof matcher === \"string\") {\n return matchMatcherPattern(pathname, matcher, i18nConfig);\n }\n if (!Array.isArray(matcher)) {\n return false;\n }\n\n const requestContext = request\n ? requestContextFromRequest(request)\n : EMPTY_MIDDLEWARE_REQUEST_CONTEXT;\n\n for (const m of matcher) {\n if (typeof m === \"string\") {\n if (matchMatcherPattern(pathname, m, i18nConfig)) {\n return true;\n }\n continue;\n }\n\n if (isValidMiddlewareMatcherObject(m)) {\n if (!matchObjectMatcher(pathname, m, i18nConfig)) {\n continue;\n }\n\n if (!checkHasConditions(m.has, m.missing, requestContext)) {\n continue;\n }\n\n return true;\n }\n }\n\n return false;\n}\n\nfunction isValidMiddlewareMatcherObject(value: unknown): value is MiddlewareMatcherObject {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\n if (!(\"source\" in value) || typeof value.source !== \"string\") return false;\n\n for (const key of Object.keys(value)) {\n if (key !== \"source\" && key !== \"locale\" && key !== \"has\" && key !== \"missing\") {\n return false;\n }\n }\n\n if (\"locale\" in value && value.locale !== undefined && value.locale !== false) return false;\n if (\"has\" in value && value.has !== undefined && !Array.isArray(value.has)) return false;\n if (\"missing\" in value && value.missing !== undefined && !Array.isArray(value.missing)) {\n return false;\n }\n\n return true;\n}\n\nfunction matchMatcherPattern(\n pathname: string,\n pattern: string,\n i18nConfig?: NextI18nConfig | null,\n): boolean {\n if (!i18nConfig) return matchPattern(pathname, pattern);\n\n const localeStrippedPathname = stripLocalePrefix(pathname, i18nConfig);\n return matchPattern(localeStrippedPathname ?? pathname, pattern);\n}\n\nfunction matchObjectMatcher(\n pathname: string,\n matcher: MiddlewareMatcherObject,\n i18nConfig?: NextI18nConfig | null,\n): boolean {\n return matcher.locale === false\n ? matchPattern(pathname, matcher.source)\n : matchMatcherPattern(pathname, matcher.source, i18nConfig);\n}\n\nfunction stripLocalePrefix(pathname: string, i18nConfig: NextI18nConfig): string | null {\n if (pathname === \"/\") return null;\n\n const segments = pathname.split(\"/\");\n const firstSegment = segments[1];\n if (!firstSegment || !i18nConfig.locales.includes(firstSegment)) {\n return null;\n }\n\n const stripped = \"/\" + segments.slice(2).join(\"/\");\n return removeTrailingSlash(stripped);\n}\n\nexport function matchPattern(pathname: string, pattern: string): boolean {\n let cached = _mwPatternCache.get(pattern);\n if (cached === undefined) {\n cached = compileMatcherPattern(pattern);\n _mwPatternCache.set(pattern, cached);\n }\n if (cached === null) return pathname === pattern;\n return cached.test(pathname);\n}\n\nfunction extractConstraint(str: string, re: RegExp): string | null {\n if (str[re.lastIndex] !== \"(\") return null;\n const start = re.lastIndex + 1;\n let depth = 1;\n let i = start;\n while (i < str.length && depth > 0) {\n if (str[i] === \"(\") depth++;\n else if (str[i] === \")\") depth--;\n i++;\n }\n if (depth !== 0) return null;\n re.lastIndex = i;\n return str.slice(start, i - 1);\n}\n\nfunction compileMatcherPattern(pattern: string): RegExp | null {\n const hasConstraints = /:[\\w-]+[*+]?\\(/.test(pattern);\n\n if (!hasConstraints && (pattern.includes(\"(\") || pattern.includes(\"\\\\\"))) {\n return safeRegExp(\"^\" + pattern + \"$\");\n }\n\n let regexStr = \"\";\n const tokenRe = /\\/:([\\w-]+)\\*|\\/:([\\w-]+)\\+|:([\\w-]+)|[.]|[^/:.]+|./g;\n let tok: RegExpExecArray | null;\n while ((tok = tokenRe.exec(pattern)) !== null) {\n if (tok[1] !== undefined) {\n const constraint = hasConstraints ? extractConstraint(pattern, tokenRe) : null;\n regexStr += constraint !== null ? `(?:/(${constraint}))?` : \"(?:/.*)?\";\n } else if (tok[2] !== undefined) {\n const constraint = hasConstraints ? extractConstraint(pattern, tokenRe) : null;\n regexStr += constraint !== null ? `(?:/(${constraint}))` : \"(?:/.+)\";\n } else if (tok[3] !== undefined) {\n const constraint = hasConstraints ? extractConstraint(pattern, tokenRe) : null;\n const isOptional = pattern[tokenRe.lastIndex] === \"?\";\n if (isOptional) tokenRe.lastIndex += 1;\n\n const group = constraint !== null ? `(${constraint})` : \"([^/]+)\";\n\n if (isOptional && regexStr.endsWith(\"/\")) {\n regexStr = regexStr.slice(0, -1) + `(?:/${group})?`;\n } else if (isOptional) {\n regexStr += `${group}?`;\n } else {\n regexStr += group;\n }\n } else if (tok[0] === \".\") {\n regexStr += \"\\\\.\";\n } else {\n regexStr += tok[0];\n }\n }\n\n return safeRegExp(\"^\" + regexStr + \"$\");\n}\n"],"mappings":"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"}
@@ -1,5 +1,22 @@
1
1
  //#region src/server/middleware-response-headers.ts
2
2
  const ADDITIVE_RESPONSE_HEADER_NAMES = new Set(["set-cookie", "vary"]);
3
+ function mergeVaryHeader(target, value) {
4
+ const existing = target.get("Vary");
5
+ const tokens = (existing ? `${existing}, ${value}` : value).split(",").map((token) => token.trim()).filter((token) => token.length > 0);
6
+ if (tokens.some((token) => token === "*")) {
7
+ target.set("Vary", "*");
8
+ return;
9
+ }
10
+ const seen = /* @__PURE__ */ new Set();
11
+ const merged = [];
12
+ for (const token of tokens) {
13
+ const normalized = token.toLowerCase();
14
+ if (seen.has(normalized)) continue;
15
+ seen.add(normalized);
16
+ merged.push(token);
17
+ }
18
+ target.set("Vary", merged.join(", "));
19
+ }
3
20
  /**
4
21
  * Merge middleware response headers into a target Headers object.
5
22
  *
@@ -10,6 +27,10 @@ const ADDITIVE_RESPONSE_HEADER_NAMES = new Set(["set-cookie", "vary"]);
10
27
  function mergeMiddlewareResponseHeaders(target, middlewareHeaders) {
11
28
  if (!middlewareHeaders) return;
12
29
  for (const [key, value] of middlewareHeaders) {
30
+ if (key.toLowerCase() === "vary") {
31
+ mergeVaryHeader(target, value);
32
+ continue;
33
+ }
13
34
  if (ADDITIVE_RESPONSE_HEADER_NAMES.has(key.toLowerCase())) {
14
35
  target.append(key, value);
15
36
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-response-headers.js","names":[],"sources":["../../src/server/middleware-response-headers.ts"],"sourcesContent":["const ADDITIVE_RESPONSE_HEADER_NAMES = new Set([\"set-cookie\", \"vary\"]);\n\n/**\n * Merge middleware response headers into a target Headers object.\n *\n * Set-Cookie and Vary are accumulated (append) since multiple sources can\n * contribute values. All other headers use set() so middleware owns singular\n * response headers like Cache-Control.\n */\nexport function mergeMiddlewareResponseHeaders(\n target: Headers,\n middlewareHeaders: Headers | null,\n): void {\n if (!middlewareHeaders) {\n return;\n }\n\n for (const [key, value] of middlewareHeaders) {\n if (ADDITIVE_RESPONSE_HEADER_NAMES.has(key.toLowerCase())) {\n target.append(key, value);\n continue;\n }\n\n target.set(key, value);\n }\n}\n"],"mappings":";AAAA,MAAM,iCAAiC,IAAI,IAAI,CAAC,cAAc,OAAO,CAAC;;;;;;;;AAStE,SAAgB,+BACd,QACA,mBACM;AACN,KAAI,CAAC,kBACH;AAGF,MAAK,MAAM,CAAC,KAAK,UAAU,mBAAmB;AAC5C,MAAI,+BAA+B,IAAI,IAAI,aAAa,CAAC,EAAE;AACzD,UAAO,OAAO,KAAK,MAAM;AACzB;;AAGF,SAAO,IAAI,KAAK,MAAM"}
1
+ {"version":3,"file":"middleware-response-headers.js","names":[],"sources":["../../src/server/middleware-response-headers.ts"],"sourcesContent":["const ADDITIVE_RESPONSE_HEADER_NAMES = new Set([\"set-cookie\", \"vary\"]);\n\nfunction mergeVaryHeader(target: Headers, value: string): void {\n const existing = target.get(\"Vary\");\n const tokens = (existing ? `${existing}, ${value}` : value)\n .split(\",\")\n .map((token) => token.trim())\n .filter((token) => token.length > 0);\n\n // Per RFC 9110, `Vary: *` means the response varies on all request fields.\n // Combining `*` with field names changes semantics and may be treated\n // inconsistently by caches. Collapse to `*` if any token is `*`.\n if (tokens.some((token) => token === \"*\")) {\n target.set(\"Vary\", \"*\");\n return;\n }\n\n const seen = new Set<string>();\n const merged: string[] = [];\n for (const token of tokens) {\n const normalized = token.toLowerCase();\n if (seen.has(normalized)) continue;\n\n seen.add(normalized);\n merged.push(token);\n }\n\n target.set(\"Vary\", merged.join(\", \"));\n}\n\n/**\n * Merge middleware response headers into a target Headers object.\n *\n * Set-Cookie and Vary are accumulated (append) since multiple sources can\n * contribute values. All other headers use set() so middleware owns singular\n * response headers like Cache-Control.\n */\nexport function mergeMiddlewareResponseHeaders(\n target: Headers,\n middlewareHeaders: Headers | null,\n): void {\n if (!middlewareHeaders) {\n return;\n }\n\n for (const [key, value] of middlewareHeaders) {\n if (key.toLowerCase() === \"vary\") {\n mergeVaryHeader(target, value);\n continue;\n }\n\n if (ADDITIVE_RESPONSE_HEADER_NAMES.has(key.toLowerCase())) {\n target.append(key, value);\n continue;\n }\n\n target.set(key, value);\n }\n}\n"],"mappings":";AAAA,MAAM,iCAAiC,IAAI,IAAI,CAAC,cAAc,OAAO,CAAC;AAEtE,SAAS,gBAAgB,QAAiB,OAAqB;CAC7D,MAAM,WAAW,OAAO,IAAI,OAAO;CACnC,MAAM,UAAU,WAAW,GAAG,SAAS,IAAI,UAAU,OAClD,MAAM,IAAI,CACV,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,QAAQ,UAAU,MAAM,SAAS,EAAE;AAKtC,KAAI,OAAO,MAAM,UAAU,UAAU,IAAI,EAAE;AACzC,SAAO,IAAI,QAAQ,IAAI;AACvB;;CAGF,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,SAAmB,EAAE;AAC3B,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,MAAM,aAAa;AACtC,MAAI,KAAK,IAAI,WAAW,CAAE;AAE1B,OAAK,IAAI,WAAW;AACpB,SAAO,KAAK,MAAM;;AAGpB,QAAO,IAAI,QAAQ,OAAO,KAAK,KAAK,CAAC;;;;;;;;;AAUvC,SAAgB,+BACd,QACA,mBACM;AACN,KAAI,CAAC,kBACH;AAGF,MAAK,MAAM,CAAC,KAAK,UAAU,mBAAmB;AAC5C,MAAI,IAAI,aAAa,KAAK,QAAQ;AAChC,mBAAgB,QAAQ,MAAM;AAC9B;;AAGF,MAAI,+BAA+B,IAAI,IAAI,aAAa,CAAC,EAAE;AACzD,UAAO,OAAO,KAAK,MAAM;AACzB;;AAGF,SAAO,IAAI,KAAK,MAAM"}
@@ -4,6 +4,7 @@ import { shouldKeepMiddlewareHeader } from "./middleware-request-headers.js";
4
4
  import { NextFetchEvent, NextRequest } from "../shims/server.js";
5
5
  import { normalizePath } from "./normalize-path.js";
6
6
  import { matchesMiddleware } from "./middleware-matcher.js";
7
+ import { badRequestResponse, internalServerErrorResponse } from "./http-error-responses.js";
7
8
  import { processMiddlewareHeaders } from "./request-pipeline.js";
8
9
  //#region src/server/middleware-runtime.ts
9
10
  function isMiddlewareHandler(value) {
@@ -57,7 +58,7 @@ function resolveMiddlewarePathname(request) {
57
58
  try {
58
59
  return normalizePath(normalizePathnameForRouteMatchStrict(url.pathname));
59
60
  } catch {
60
- return new Response("Bad Request", { status: 400 });
61
+ return badRequestResponse();
61
62
  }
62
63
  }
63
64
  function createNextRequest(request, normalizedPathname, i18nConfig, basePath) {
@@ -93,10 +94,9 @@ async function executeMiddleware(options) {
93
94
  } catch (e) {
94
95
  console.error("[vinext] Middleware error:", e);
95
96
  const waitUntilPromises = drainFetchEvent(fetchEvent);
96
- const message = options.includeErrorDetails ? "Middleware Error: " + (e instanceof Error ? e.message : String(e)) : "Internal Server Error";
97
97
  return {
98
98
  continue: false,
99
- response: new Response(message, { status: 500 }),
99
+ response: internalServerErrorResponse(options.includeErrorDetails ? "Middleware Error: " + (e instanceof Error ? e.message : String(e)) : "Internal Server Error"),
100
100
  waitUntilPromises
101
101
  };
102
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-runtime.js","names":[],"sources":["../../src/server/middleware-runtime.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport { normalizePathnameForRouteMatchStrict } from \"../routing/utils.js\";\nimport {\n getRequestExecutionContext,\n runWithExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { NextFetchEvent, NextRequest } from \"vinext/shims/server\";\nimport { normalizePath } from \"./normalize-path.js\";\nimport { MatcherConfig, matchesMiddleware } from \"./middleware-matcher.js\";\nimport { shouldKeepMiddlewareHeader } from \"./middleware-request-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\n\nexport type MiddlewareModule = Record<string, unknown>;\n\nexport type MiddlewareResult = {\n continue: boolean;\n redirectUrl?: string;\n redirectStatus?: number;\n rewriteUrl?: string;\n rewriteStatus?: number;\n responseHeaders?: Headers;\n response?: Response;\n waitUntilPromises?: Promise<unknown>[];\n};\n\ntype MiddlewareHandler = (\n request: NextRequest,\n event: NextFetchEvent,\n) => Response | undefined | void | Promise<Response | undefined | void>;\n\ntype MiddlewareConfigExport = {\n matcher?: MatcherConfig;\n};\n\ntype ExecuteMiddlewareOptions = {\n basePath?: string;\n filePath?: string;\n i18nConfig?: NextI18nConfig | null;\n includeErrorDetails?: boolean;\n isProxy: boolean;\n module: MiddlewareModule;\n normalizedPathname?: string;\n request: Request;\n};\n\ntype RunGeneratedMiddlewareOptions = ExecuteMiddlewareOptions & {\n ctx?: ExecutionContextLike;\n};\n\nfunction isMiddlewareHandler(value: unknown): value is MiddlewareHandler {\n return typeof value === \"function\";\n}\n\nfunction isMiddlewareConfigExport(value: unknown): value is MiddlewareConfigExport {\n return !!value && typeof value === \"object\";\n}\n\nfunction middlewareFileLabel(isProxy: boolean): string {\n return isProxy ? \"Proxy\" : \"Middleware\";\n}\n\nfunction middlewareExpectedExport(isProxy: boolean): string {\n return isProxy ? \"proxy\" : \"middleware\";\n}\n\nexport function resolveMiddlewareModuleHandler(\n mod: MiddlewareModule,\n options: { filePath?: string; isProxy: boolean },\n): MiddlewareHandler {\n const handler = options.isProxy ? (mod.proxy ?? mod.default) : (mod.middleware ?? mod.default);\n if (isMiddlewareHandler(handler)) return handler;\n\n const fileLabel = middlewareFileLabel(options.isProxy);\n const expectedExport = middlewareExpectedExport(options.isProxy);\n const fileSuffix = options.filePath ? ` \"${options.filePath}\"` : \"\";\n throw new Error(\n `The ${fileLabel} file${fileSuffix} must export a function named \\`${expectedExport}\\` or a \\`default\\` function.`,\n );\n}\n\nfunction middlewareMatcher(mod: MiddlewareModule): MatcherConfig | undefined {\n const config = mod.config;\n if (!isMiddlewareConfigExport(config)) return undefined;\n return config.matcher;\n}\n\nfunction stripMiddlewareHeadersFromResponse(response: Response): Response {\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nfunction collectMiddlewareHeaders(response: Response): Headers {\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\") || shouldKeepMiddlewareHeader(key)) {\n responseHeaders.append(key, value);\n }\n }\n return responseHeaders;\n}\n\nfunction drainFetchEvent(fetchEvent: NextFetchEvent): Promise<unknown>[] {\n const waitUntilPromises = fetchEvent.waitUntilPromises;\n const drained = fetchEvent.drainWaitUntil();\n const executionContext = getRequestExecutionContext();\n if (executionContext) {\n executionContext.waitUntil(drained);\n } else {\n void drained;\n }\n return waitUntilPromises;\n}\n\nfunction resolveMiddlewarePathname(request: Request): string | Response {\n const url = new URL(request.url);\n try {\n return normalizePath(normalizePathnameForRouteMatchStrict(url.pathname));\n } catch {\n return new Response(\"Bad Request\", { status: 400 });\n }\n}\n\nfunction createNextRequest(\n request: Request,\n normalizedPathname: string,\n i18nConfig?: NextI18nConfig | null,\n basePath?: string,\n): NextRequest {\n const url = new URL(request.url);\n let mwRequest = request;\n if (normalizedPathname !== url.pathname) {\n const mwUrl = new URL(url);\n mwUrl.pathname = normalizedPathname;\n mwRequest = new Request(mwUrl, request);\n }\n\n const nextConfig =\n basePath || i18nConfig\n ? { basePath: basePath ?? \"\", i18n: i18nConfig ?? undefined }\n : undefined;\n\n return mwRequest instanceof NextRequest\n ? mwRequest\n : new NextRequest(mwRequest, nextConfig ? { nextConfig } : undefined);\n}\n\nexport async function executeMiddleware(\n options: ExecuteMiddlewareOptions,\n): Promise<MiddlewareResult> {\n const middlewareFn = resolveMiddlewareModuleHandler(options.module, {\n filePath: options.filePath,\n isProxy: options.isProxy,\n });\n const normalizedPathname =\n options.normalizedPathname ?? resolveMiddlewarePathname(options.request);\n if (normalizedPathname instanceof Response) {\n return { continue: false, response: normalizedPathname };\n }\n\n if (\n !matchesMiddleware(\n normalizedPathname,\n middlewareMatcher(options.module),\n options.request,\n options.i18nConfig,\n )\n ) {\n return { continue: true };\n }\n\n const nextRequest = createNextRequest(\n options.request,\n normalizedPathname,\n options.i18nConfig,\n options.basePath,\n );\n const fetchEvent = new NextFetchEvent({ page: normalizedPathname });\n\n let response: Response | undefined | void;\n try {\n response = await middlewareFn(nextRequest, fetchEvent);\n } catch (e) {\n console.error(\"[vinext] Middleware error:\", e);\n const waitUntilPromises = drainFetchEvent(fetchEvent);\n const message = options.includeErrorDetails\n ? \"Middleware Error: \" + (e instanceof Error ? e.message : String(e))\n : \"Internal Server Error\";\n return {\n continue: false,\n response: new Response(message, { status: 500 }),\n waitUntilPromises,\n };\n }\n\n const waitUntilPromises = drainFetchEvent(fetchEvent);\n\n if (!response) {\n return { continue: true, waitUntilPromises };\n }\n\n if (response.headers.get(\"x-middleware-next\") === \"1\") {\n return {\n continue: true,\n responseHeaders: collectMiddlewareHeaders(response),\n waitUntilPromises,\n };\n }\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"Location\") ?? response.headers.get(\"location\");\n if (location) {\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\") && key.toLowerCase() !== \"location\") {\n responseHeaders.append(key, value);\n }\n }\n return {\n continue: false,\n redirectUrl: location,\n redirectStatus: response.status,\n response: stripMiddlewareHeadersFromResponse(response),\n responseHeaders,\n waitUntilPromises,\n };\n }\n }\n\n const rewriteUrl = response.headers.get(\"x-middleware-rewrite\");\n if (rewriteUrl) {\n let rewritePath: string;\n try {\n const rewriteParsed = new URL(rewriteUrl, options.request.url);\n const requestOrigin = new URL(options.request.url).origin;\n rewritePath =\n rewriteParsed.origin === requestOrigin\n ? rewriteParsed.pathname + rewriteParsed.search\n : rewriteParsed.href;\n } catch {\n rewritePath = rewriteUrl;\n }\n return {\n continue: true,\n rewriteUrl: rewritePath,\n rewriteStatus: response.status !== 200 ? response.status : undefined,\n responseHeaders: collectMiddlewareHeaders(response),\n waitUntilPromises,\n };\n }\n\n return {\n continue: false,\n response: stripMiddlewareHeadersFromResponse(response),\n waitUntilPromises,\n };\n}\n\nexport async function runGeneratedMiddleware(\n options: RunGeneratedMiddlewareOptions,\n): Promise<MiddlewareResult> {\n const run = () => executeMiddleware(options);\n return options.ctx ? runWithExecutionContext(options.ctx, run) : run();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"middleware-runtime.js","names":[],"sources":["../../src/server/middleware-runtime.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport { normalizePathnameForRouteMatchStrict } from \"../routing/utils.js\";\nimport {\n getRequestExecutionContext,\n runWithExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { NextFetchEvent, NextRequest } from \"vinext/shims/server\";\nimport { normalizePath } from \"./normalize-path.js\";\nimport { MatcherConfig, matchesMiddleware } from \"./middleware-matcher.js\";\nimport { shouldKeepMiddlewareHeader } from \"./middleware-request-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\nimport { badRequestResponse, internalServerErrorResponse } from \"./http-error-responses.js\";\n\nexport type MiddlewareModule = Record<string, unknown>;\n\nexport type MiddlewareResult = {\n continue: boolean;\n redirectUrl?: string;\n redirectStatus?: number;\n rewriteUrl?: string;\n rewriteStatus?: number;\n responseHeaders?: Headers;\n response?: Response;\n waitUntilPromises?: Promise<unknown>[];\n};\n\ntype MiddlewareHandler = (\n request: NextRequest,\n event: NextFetchEvent,\n) => Response | undefined | void | Promise<Response | undefined | void>;\n\ntype MiddlewareConfigExport = {\n matcher?: MatcherConfig;\n};\n\ntype ExecuteMiddlewareOptions = {\n basePath?: string;\n filePath?: string;\n i18nConfig?: NextI18nConfig | null;\n includeErrorDetails?: boolean;\n isProxy: boolean;\n module: MiddlewareModule;\n normalizedPathname?: string;\n request: Request;\n};\n\ntype RunGeneratedMiddlewareOptions = ExecuteMiddlewareOptions & {\n ctx?: ExecutionContextLike;\n};\n\nfunction isMiddlewareHandler(value: unknown): value is MiddlewareHandler {\n return typeof value === \"function\";\n}\n\nfunction isMiddlewareConfigExport(value: unknown): value is MiddlewareConfigExport {\n return !!value && typeof value === \"object\";\n}\n\nfunction middlewareFileLabel(isProxy: boolean): string {\n return isProxy ? \"Proxy\" : \"Middleware\";\n}\n\nfunction middlewareExpectedExport(isProxy: boolean): string {\n return isProxy ? \"proxy\" : \"middleware\";\n}\n\nexport function resolveMiddlewareModuleHandler(\n mod: MiddlewareModule,\n options: { filePath?: string; isProxy: boolean },\n): MiddlewareHandler {\n const handler = options.isProxy ? (mod.proxy ?? mod.default) : (mod.middleware ?? mod.default);\n if (isMiddlewareHandler(handler)) return handler;\n\n const fileLabel = middlewareFileLabel(options.isProxy);\n const expectedExport = middlewareExpectedExport(options.isProxy);\n const fileSuffix = options.filePath ? ` \"${options.filePath}\"` : \"\";\n throw new Error(\n `The ${fileLabel} file${fileSuffix} must export a function named \\`${expectedExport}\\` or a \\`default\\` function.`,\n );\n}\n\nfunction middlewareMatcher(mod: MiddlewareModule): MatcherConfig | undefined {\n const config = mod.config;\n if (!isMiddlewareConfigExport(config)) return undefined;\n return config.matcher;\n}\n\nfunction stripMiddlewareHeadersFromResponse(response: Response): Response {\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nfunction collectMiddlewareHeaders(response: Response): Headers {\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\") || shouldKeepMiddlewareHeader(key)) {\n responseHeaders.append(key, value);\n }\n }\n return responseHeaders;\n}\n\nfunction drainFetchEvent(fetchEvent: NextFetchEvent): Promise<unknown>[] {\n const waitUntilPromises = fetchEvent.waitUntilPromises;\n const drained = fetchEvent.drainWaitUntil();\n const executionContext = getRequestExecutionContext();\n if (executionContext) {\n executionContext.waitUntil(drained);\n } else {\n void drained;\n }\n return waitUntilPromises;\n}\n\nfunction resolveMiddlewarePathname(request: Request): string | Response {\n const url = new URL(request.url);\n try {\n return normalizePath(normalizePathnameForRouteMatchStrict(url.pathname));\n } catch {\n return badRequestResponse();\n }\n}\n\nfunction createNextRequest(\n request: Request,\n normalizedPathname: string,\n i18nConfig?: NextI18nConfig | null,\n basePath?: string,\n): NextRequest {\n const url = new URL(request.url);\n let mwRequest = request;\n if (normalizedPathname !== url.pathname) {\n const mwUrl = new URL(url);\n mwUrl.pathname = normalizedPathname;\n mwRequest = new Request(mwUrl, request);\n }\n\n const nextConfig =\n basePath || i18nConfig\n ? { basePath: basePath ?? \"\", i18n: i18nConfig ?? undefined }\n : undefined;\n\n return mwRequest instanceof NextRequest\n ? mwRequest\n : new NextRequest(mwRequest, nextConfig ? { nextConfig } : undefined);\n}\n\nexport async function executeMiddleware(\n options: ExecuteMiddlewareOptions,\n): Promise<MiddlewareResult> {\n const middlewareFn = resolveMiddlewareModuleHandler(options.module, {\n filePath: options.filePath,\n isProxy: options.isProxy,\n });\n const normalizedPathname =\n options.normalizedPathname ?? resolveMiddlewarePathname(options.request);\n if (normalizedPathname instanceof Response) {\n return { continue: false, response: normalizedPathname };\n }\n\n if (\n !matchesMiddleware(\n normalizedPathname,\n middlewareMatcher(options.module),\n options.request,\n options.i18nConfig,\n )\n ) {\n return { continue: true };\n }\n\n const nextRequest = createNextRequest(\n options.request,\n normalizedPathname,\n options.i18nConfig,\n options.basePath,\n );\n const fetchEvent = new NextFetchEvent({ page: normalizedPathname });\n\n let response: Response | undefined | void;\n try {\n response = await middlewareFn(nextRequest, fetchEvent);\n } catch (e) {\n console.error(\"[vinext] Middleware error:\", e);\n const waitUntilPromises = drainFetchEvent(fetchEvent);\n const message = options.includeErrorDetails\n ? \"Middleware Error: \" + (e instanceof Error ? e.message : String(e))\n : \"Internal Server Error\";\n return {\n continue: false,\n response: internalServerErrorResponse(message),\n waitUntilPromises,\n };\n }\n\n const waitUntilPromises = drainFetchEvent(fetchEvent);\n\n if (!response) {\n return { continue: true, waitUntilPromises };\n }\n\n if (response.headers.get(\"x-middleware-next\") === \"1\") {\n return {\n continue: true,\n responseHeaders: collectMiddlewareHeaders(response),\n waitUntilPromises,\n };\n }\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"Location\") ?? response.headers.get(\"location\");\n if (location) {\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\") && key.toLowerCase() !== \"location\") {\n responseHeaders.append(key, value);\n }\n }\n return {\n continue: false,\n redirectUrl: location,\n redirectStatus: response.status,\n response: stripMiddlewareHeadersFromResponse(response),\n responseHeaders,\n waitUntilPromises,\n };\n }\n }\n\n const rewriteUrl = response.headers.get(\"x-middleware-rewrite\");\n if (rewriteUrl) {\n let rewritePath: string;\n try {\n const rewriteParsed = new URL(rewriteUrl, options.request.url);\n const requestOrigin = new URL(options.request.url).origin;\n rewritePath =\n rewriteParsed.origin === requestOrigin\n ? rewriteParsed.pathname + rewriteParsed.search\n : rewriteParsed.href;\n } catch {\n rewritePath = rewriteUrl;\n }\n return {\n continue: true,\n rewriteUrl: rewritePath,\n rewriteStatus: response.status !== 200 ? response.status : undefined,\n responseHeaders: collectMiddlewareHeaders(response),\n waitUntilPromises,\n };\n }\n\n return {\n continue: false,\n response: stripMiddlewareHeadersFromResponse(response),\n waitUntilPromises,\n };\n}\n\nexport async function runGeneratedMiddleware(\n options: RunGeneratedMiddlewareOptions,\n): Promise<MiddlewareResult> {\n const run = () => executeMiddleware(options);\n return options.ctx ? runWithExecutionContext(options.ctx, run) : run();\n}\n"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ //#region src/server/navigation-trace.d.ts
2
+ declare const NAVIGATION_TRACE_SCHEMA_VERSION = 0;
3
+ type NavigationTraceSchemaVersion = 0;
4
+ declare const NavigationTraceReasonCodes: {
5
+ commitCurrent: "NC_COMMIT";
6
+ rootBoundaryChanged: "NC_ROOT";
7
+ rootBoundaryUnknown: "NC_ROOT_UNKNOWN";
8
+ staleOperation: "NC_STALE";
9
+ };
10
+ declare const NavigationTraceTransactionCodes: {
11
+ hardNavigate: "NT_HARD_NAVIGATE";
12
+ noCommit: "NT_NO_COMMIT";
13
+ visibleCommit: "NT_VISIBLE_COMMIT";
14
+ };
15
+ type NavigationTraceReasonCode = (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];
16
+ type NavigationTraceTransactionCode = (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];
17
+ type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;
18
+ type NavigationTraceFieldName = "activeNavigationId" | "currentRootLayoutTreePath" | "nextRootLayoutTreePath" | "operationLane" | "pendingOperationId" | "startedVisibleCommitVersion" | "startedNavigationId";
19
+ type NavigationTraceFieldValue = string | number | boolean | null;
20
+ type NavigationTraceFields = Readonly<Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>>;
21
+ type NavigationTraceEntry = Readonly<{
22
+ code: NavigationTraceCode;
23
+ fields: NavigationTraceFields;
24
+ }>;
25
+ type NavigationTrace = Readonly<{
26
+ schemaVersion: NavigationTraceSchemaVersion;
27
+ entries: readonly NavigationTraceEntry[];
28
+ }>;
29
+ declare function createNavigationTrace(code: NavigationTraceCode, fields?: NavigationTraceFields): NavigationTrace;
30
+ declare function prependNavigationTraceEntry(trace: NavigationTrace, code: NavigationTraceCode, fields?: NavigationTraceFields): NavigationTrace;
31
+ //#endregion
32
+ export { NAVIGATION_TRACE_SCHEMA_VERSION, NavigationTrace, NavigationTraceCode, NavigationTraceEntry, NavigationTraceFieldName, NavigationTraceFieldValue, NavigationTraceFields, NavigationTraceReasonCode, NavigationTraceReasonCodes, NavigationTraceSchemaVersion, NavigationTraceTransactionCode, NavigationTraceTransactionCodes, createNavigationTrace, prependNavigationTraceEntry };
33
+ //# sourceMappingURL=navigation-trace.d.ts.map
@@ -0,0 +1,35 @@
1
+ //#region src/server/navigation-trace.ts
2
+ const NAVIGATION_TRACE_SCHEMA_VERSION = 0;
3
+ const NavigationTraceReasonCodes = {
4
+ commitCurrent: "NC_COMMIT",
5
+ rootBoundaryChanged: "NC_ROOT",
6
+ rootBoundaryUnknown: "NC_ROOT_UNKNOWN",
7
+ staleOperation: "NC_STALE"
8
+ };
9
+ const NavigationTraceTransactionCodes = {
10
+ hardNavigate: "NT_HARD_NAVIGATE",
11
+ noCommit: "NT_NO_COMMIT",
12
+ visibleCommit: "NT_VISIBLE_COMMIT"
13
+ };
14
+ function createNavigationTraceEntry(code, fields = {}) {
15
+ return {
16
+ code,
17
+ fields: { ...fields }
18
+ };
19
+ }
20
+ function createNavigationTrace(code, fields = {}) {
21
+ return {
22
+ schemaVersion: 0,
23
+ entries: [createNavigationTraceEntry(code, fields)]
24
+ };
25
+ }
26
+ function prependNavigationTraceEntry(trace, code, fields = {}) {
27
+ return {
28
+ schemaVersion: trace.schemaVersion,
29
+ entries: [createNavigationTraceEntry(code, fields), ...trace.entries]
30
+ };
31
+ }
32
+ //#endregion
33
+ export { NAVIGATION_TRACE_SCHEMA_VERSION, NavigationTraceReasonCodes, NavigationTraceTransactionCodes, createNavigationTrace, prependNavigationTraceEntry };
34
+
35
+ //# sourceMappingURL=navigation-trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n commitCurrent: \"NC_COMMIT\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n commitCurrent: \"NC_COMMIT\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"currentRootLayoutTreePath\"\n | \"nextRootLayoutTreePath\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,eAAe;CACf,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;AAOD,MAAa,kCAAkC;CAC7C,cAAc;CACd,UAAU;CACV,eAAe;CAChB;AAuCD,SAAS,2BACP,MACA,SAAgC,EAAE,EACZ;AACtB,QAAO;EACL;EACA,QAAQ,EAAE,GAAG,QAAQ;EACtB;;AAGH,SAAgB,sBACd,MACA,SAAgC,EAAE,EACjB;AACjB,QAAO;EACL,eAAA;EACA,SAAS,CAAC,2BAA2B,MAAM,OAAO,CAAC;EACpD;;AAGH,SAAgB,4BACd,OACA,MACA,SAAgC,EAAE,EACjB;AACjB,QAAO;EACL,eAAe,MAAM;EACrB,SAAS,CAAC,2BAA2B,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EACtE"}
@@ -0,0 +1,44 @@
1
+ //#region src/server/next-error-digest.d.ts
2
+ /**
3
+ * Helpers for parsing Next.js error `digest` strings shared across the App
4
+ * Router execution paths (server actions, page renders, route handlers).
5
+ *
6
+ * Next.js encodes special control flow as thrown errors carrying a `digest`
7
+ * field with one of these formats:
8
+ * - `NEXT_REDIRECT;<type>;<encodedUrl>;<status>` — `redirect()` / `permanentRedirect()`
9
+ * - `NEXT_NOT_FOUND` — `notFound()`
10
+ * - `NEXT_HTTP_ERROR_FALLBACK;<status>` — `forbidden()` / `unauthorized()` / etc.
11
+ *
12
+ * Each call site needs slightly different post-processing (URL resolution
13
+ * against the request, 303-vs-307 status overrides for actions, etc.), so
14
+ * these helpers only handle the parsing — callers shape the result.
15
+ */
16
+ type NextRedirectDigest = {
17
+ status: number;
18
+ type: string;
19
+ url: string;
20
+ };
21
+ type NextHttpErrorDigest = {
22
+ status: number;
23
+ };
24
+ /**
25
+ * Pulls a stringified `digest` off an unknown thrown value, or returns null
26
+ * when the value is not a digest-bearing error.
27
+ */
28
+ declare function getNextErrorDigest(error: unknown): string | null;
29
+ /**
30
+ * Parses a `NEXT_REDIRECT;<type>;<encodedUrl>;<status>` digest. Returns null
31
+ * when the digest is not a redirect digest or the encoded URL segment is
32
+ * missing. The `url` is decoded with `decodeURIComponent`; the `status`
33
+ * defaults to 307 when omitted; the `type` defaults to "push".
34
+ */
35
+ declare function parseNextRedirectDigest(digest: string): NextRedirectDigest | null;
36
+ /**
37
+ * Parses a `NEXT_NOT_FOUND` or `NEXT_HTTP_ERROR_FALLBACK;<status>` digest.
38
+ * Returns `{ status: 404 }` for `NEXT_NOT_FOUND` and the parsed status code
39
+ * for the fallback form. Returns null otherwise.
40
+ */
41
+ declare function parseNextHttpErrorDigest(digest: string): NextHttpErrorDigest | null;
42
+ //#endregion
43
+ export { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest };
44
+ //# sourceMappingURL=next-error-digest.d.ts.map
@@ -0,0 +1,40 @@
1
+ //#region src/server/next-error-digest.ts
2
+ /**
3
+ * Pulls a stringified `digest` off an unknown thrown value, or returns null
4
+ * when the value is not a digest-bearing error.
5
+ */
6
+ function getNextErrorDigest(error) {
7
+ if (!error || typeof error !== "object" || !("digest" in error)) return null;
8
+ return String(error.digest);
9
+ }
10
+ /**
11
+ * Parses a `NEXT_REDIRECT;<type>;<encodedUrl>;<status>` digest. Returns null
12
+ * when the digest is not a redirect digest or the encoded URL segment is
13
+ * missing. The `url` is decoded with `decodeURIComponent`; the `status`
14
+ * defaults to 307 when omitted; the `type` defaults to "push".
15
+ */
16
+ function parseNextRedirectDigest(digest) {
17
+ if (!digest.startsWith("NEXT_REDIRECT;")) return null;
18
+ const parts = digest.split(";");
19
+ const encodedUrl = parts[2];
20
+ if (!encodedUrl) return null;
21
+ return {
22
+ status: parts[3] ? parseInt(parts[3], 10) : 307,
23
+ type: parts[1] || "push",
24
+ url: decodeURIComponent(encodedUrl)
25
+ };
26
+ }
27
+ /**
28
+ * Parses a `NEXT_NOT_FOUND` or `NEXT_HTTP_ERROR_FALLBACK;<status>` digest.
29
+ * Returns `{ status: 404 }` for `NEXT_NOT_FOUND` and the parsed status code
30
+ * for the fallback form. Returns null otherwise.
31
+ */
32
+ function parseNextHttpErrorDigest(digest) {
33
+ if (digest === "NEXT_NOT_FOUND") return { status: 404 };
34
+ if (digest.startsWith("NEXT_HTTP_ERROR_FALLBACK;")) return { status: parseInt(digest.split(";")[1], 10) };
35
+ return null;
36
+ }
37
+ //#endregion
38
+ export { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest };
39
+
40
+ //# sourceMappingURL=next-error-digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-error-digest.js","names":[],"sources":["../../src/server/next-error-digest.ts"],"sourcesContent":["/**\n * Helpers for parsing Next.js error `digest` strings shared across the App\n * Router execution paths (server actions, page renders, route handlers).\n *\n * Next.js encodes special control flow as thrown errors carrying a `digest`\n * field with one of these formats:\n * - `NEXT_REDIRECT;<type>;<encodedUrl>;<status>` — `redirect()` / `permanentRedirect()`\n * - `NEXT_NOT_FOUND` — `notFound()`\n * - `NEXT_HTTP_ERROR_FALLBACK;<status>` — `forbidden()` / `unauthorized()` / etc.\n *\n * Each call site needs slightly different post-processing (URL resolution\n * against the request, 303-vs-307 status overrides for actions, etc.), so\n * these helpers only handle the parsing — callers shape the result.\n */\n\ntype NextRedirectDigest = {\n status: number;\n type: string;\n url: string;\n};\n\ntype NextHttpErrorDigest = {\n status: number;\n};\n\n/**\n * Pulls a stringified `digest` off an unknown thrown value, or returns null\n * when the value is not a digest-bearing error.\n */\nexport function getNextErrorDigest(error: unknown): string | null {\n if (!error || typeof error !== \"object\" || !(\"digest\" in error)) {\n return null;\n }\n\n return String(error.digest);\n}\n\n/**\n * Parses a `NEXT_REDIRECT;<type>;<encodedUrl>;<status>` digest. Returns null\n * when the digest is not a redirect digest or the encoded URL segment is\n * missing. The `url` is decoded with `decodeURIComponent`; the `status`\n * defaults to 307 when omitted; the `type` defaults to \"push\".\n */\nexport function parseNextRedirectDigest(digest: string): NextRedirectDigest | null {\n if (!digest.startsWith(\"NEXT_REDIRECT;\")) {\n return null;\n }\n\n const parts = digest.split(\";\");\n const encodedUrl = parts[2];\n if (!encodedUrl) {\n return null;\n }\n\n return {\n status: parts[3] ? parseInt(parts[3], 10) : 307,\n type: parts[1] || \"push\",\n url: decodeURIComponent(encodedUrl),\n };\n}\n\n/**\n * Parses a `NEXT_NOT_FOUND` or `NEXT_HTTP_ERROR_FALLBACK;<status>` digest.\n * Returns `{ status: 404 }` for `NEXT_NOT_FOUND` and the parsed status code\n * for the fallback form. Returns null otherwise.\n */\nexport function parseNextHttpErrorDigest(digest: string): NextHttpErrorDigest | null {\n if (digest === \"NEXT_NOT_FOUND\") {\n return { status: 404 };\n }\n if (digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\")) {\n return { status: parseInt(digest.split(\";\")[1], 10) };\n }\n return null;\n}\n"],"mappings":";;;;;AA6BA,SAAgB,mBAAmB,OAA+B;AAChE,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,EAAE,YAAY,OACvD,QAAO;AAGT,QAAO,OAAO,MAAM,OAAO;;;;;;;;AAS7B,SAAgB,wBAAwB,QAA2C;AACjF,KAAI,CAAC,OAAO,WAAW,iBAAiB,CACtC,QAAO;CAGT,MAAM,QAAQ,OAAO,MAAM,IAAI;CAC/B,MAAM,aAAa,MAAM;AACzB,KAAI,CAAC,WACH,QAAO;AAGT,QAAO;EACL,QAAQ,MAAM,KAAK,SAAS,MAAM,IAAI,GAAG,GAAG;EAC5C,MAAM,MAAM,MAAM;EAClB,KAAK,mBAAmB,WAAW;EACpC;;;;;;;AAQH,SAAgB,yBAAyB,QAA4C;AACnF,KAAI,WAAW,iBACb,QAAO,EAAE,QAAQ,KAAK;AAExB,KAAI,OAAO,WAAW,4BAA4B,CAChD,QAAO,EAAE,QAAQ,SAAS,OAAO,MAAM,IAAI,CAAC,IAAI,GAAG,EAAE;AAEvD,QAAO"}
@@ -1,3 +1,4 @@
1
+ import { internalServerErrorResponse } from "./http-error-responses.js";
1
2
  import { addQueryParam } from "../utils/query.js";
2
3
  import { PagesBodyParseError } from "./pages-media-type.js";
3
4
  import { createPagesReqRes, parsePagesApiBody } from "./pages-node-compat.js";
@@ -31,7 +32,7 @@ async function handlePagesApiRoute(options) {
31
32
  statusText: error.message
32
33
  });
33
34
  options.reportRequestError?.(error instanceof Error ? error : new Error(String(error)), route.pattern);
34
- return new Response("Internal Server Error", { status: 500 });
35
+ return internalServerErrorResponse();
35
36
  }
36
37
  }
37
38
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import type { Route } from \"../routing/pages-router.js\";\nimport { addQueryParam } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\n\ntype PagesApiRouteModule = {\n default?: (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;\n};\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n const query: PagesRequestQuery = { ...params };\n const search = url.split(\"?\")[1];\n if (!search) {\n return query;\n }\n\n for (const [key, value] of new URLSearchParams(search)) {\n addQueryParam(query, key, value);\n }\n\n return query;\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n const handler = route.module.default;\n if (typeof handler !== \"function\") {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n try {\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await handler(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return new Response(\"Internal Server Error\", { status: 500 });\n }\n}\n"],"mappings":";;;;AA6BA,SAAS,mBAAmB,KAAa,QAA8C;CACrF,MAAM,QAA2B,EAAE,GAAG,QAAQ;CAC9C,MAAM,SAAS,IAAI,MAAM,IAAI,CAAC;AAC9B,KAAI,CAAC,OACH,QAAO;AAGT,MAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,OAAO,CACpD,eAAc,OAAO,KAAK,MAAM;AAGlC,QAAO;;AAGT,eAAsB,oBAAoB,SAAwD;AAChG,KAAI,CAAC,QAAQ,MACX,QAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAClC,MAAM,UAAU,MAAM,OAAO;AAC7B,KAAI,OAAO,YAAY,WACrB,QAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;AAGtF,KAAI;EACF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAFW,MAAM,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;AAEF,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI,KAAK;AACT,SAAO,MAAM;UACN,OAAO;AACd,MAAI,iBAAiBA,oBACnB,QAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;AAGC,UAAQ,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;AACD,SAAO,IAAI,SAAS,yBAAyB,EAAE,QAAQ,KAAK,CAAC"}
1
+ {"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import type { Route } from \"../routing/pages-router.js\";\nimport { addQueryParam } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\n\ntype PagesApiRouteModule = {\n default?: (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;\n};\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n const query: PagesRequestQuery = { ...params };\n const search = url.split(\"?\")[1];\n if (!search) {\n return query;\n }\n\n for (const [key, value] of new URLSearchParams(search)) {\n addQueryParam(query, key, value);\n }\n\n return query;\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n const handler = route.module.default;\n if (typeof handler !== \"function\") {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n try {\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await handler(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return internalServerErrorResponse();\n }\n}\n"],"mappings":";;;;;AA8BA,SAAS,mBAAmB,KAAa,QAA8C;CACrF,MAAM,QAA2B,EAAE,GAAG,QAAQ;CAC9C,MAAM,SAAS,IAAI,MAAM,IAAI,CAAC;AAC9B,KAAI,CAAC,OACH,QAAO;AAGT,MAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,OAAO,CACpD,eAAc,OAAO,KAAK,MAAM;AAGlC,QAAO;;AAGT,eAAsB,oBAAoB,SAAwD;AAChG,KAAI,CAAC,QAAQ,MACX,QAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAClC,MAAM,UAAU,MAAM,OAAO;AAC7B,KAAI,OAAO,YAAY,WACrB,QAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;AAGtF,KAAI;EACF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAFW,MAAM,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;AAEF,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI,KAAK;AACT,SAAO,MAAM;UACN,OAAO;AACd,MAAI,iBAAiBA,oBACnB,QAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;AAGC,UAAQ,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;AACD,SAAO,6BAA6B"}