reroute-js 1.0.0-alpha.4 → 1.0.0-alpha.41

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 (308) hide show
  1. package/README.md +45 -3
  2. package/cli/bin.d.ts +1 -1
  3. package/cli/bin.js +3229 -1217
  4. package/cli/bin.js.map +66 -53
  5. package/cli/index.d.ts +1 -1
  6. package/cli/index.js +672 -45
  7. package/cli/index.js.map +57 -7
  8. package/cli/src/cli.d.ts +1 -1
  9. package/cli/src/commands/analyze.d.ts +1 -1
  10. package/cli/src/commands/analyze.d.ts.map +1 -1
  11. package/cli/src/commands/build.d.ts +6 -3
  12. package/cli/src/commands/build.d.ts.map +1 -1
  13. package/cli/src/commands/dev.d.ts +6 -6
  14. package/cli/src/commands/dev.d.ts.map +1 -1
  15. package/cli/src/commands/gen.d.ts +4 -1
  16. package/cli/src/commands/gen.d.ts.map +1 -1
  17. package/cli/src/commands/index.d.ts +1 -1
  18. package/cli/src/commands/init.d.ts +1 -1
  19. package/cli/src/commands/lib/assets.d.ts +1 -1
  20. package/cli/src/commands/lib/bundler.d.ts +8 -1
  21. package/cli/src/commands/lib/bundler.d.ts.map +1 -1
  22. package/cli/src/commands/lib/command.d.ts +1 -1
  23. package/cli/src/commands/lib/env.d.ts +4 -3
  24. package/cli/src/commands/lib/env.d.ts.map +1 -1
  25. package/cli/src/commands/lib/images.d.ts +12 -0
  26. package/cli/src/commands/lib/images.d.ts.map +1 -0
  27. package/cli/src/commands/lib/index.d.ts +1 -1
  28. package/cli/src/commands/lib/log.d.ts +1 -1
  29. package/cli/src/commands/lib/markdown/availability.d.ts +1 -1
  30. package/cli/src/commands/lib/markdown/index.d.ts +1 -1
  31. package/cli/src/commands/lib/markdown/processor.d.ts +11 -1
  32. package/cli/src/commands/lib/markdown/processor.d.ts.map +1 -1
  33. package/cli/src/commands/lib/prerender.d.ts +40 -0
  34. package/cli/src/commands/lib/prerender.d.ts.map +1 -0
  35. package/cli/src/commands/lib/production.d.ts +3 -3
  36. package/cli/src/commands/lib/production.d.ts.map +1 -1
  37. package/cli/src/commands/lib/routes.d.ts +40 -0
  38. package/cli/src/commands/lib/routes.d.ts.map +1 -0
  39. package/cli/src/commands/lib/server.d.ts +2 -1
  40. package/cli/src/commands/lib/server.d.ts.map +1 -1
  41. package/cli/src/commands/lib/ssr-strip.d.ts +33 -0
  42. package/cli/src/commands/lib/ssr-strip.d.ts.map +1 -0
  43. package/cli/src/commands/lib/static.d.ts +86 -0
  44. package/cli/src/commands/lib/static.d.ts.map +1 -0
  45. package/cli/src/commands/lib/streaming/analyzer.d.ts +1 -1
  46. package/cli/src/commands/lib/streaming/suspense.d.ts +2 -2
  47. package/cli/src/commands/lib/streaming/suspense.d.ts.map +1 -1
  48. package/cli/src/commands/lib/supervise.d.ts +23 -0
  49. package/cli/src/commands/lib/supervise.d.ts.map +1 -0
  50. package/cli/src/commands/lib/terminal-ui.d.ts +2 -2
  51. package/cli/src/commands/lib/terminal-ui.d.ts.map +1 -1
  52. package/cli/src/commands/lib/theme.d.ts +9 -4
  53. package/cli/src/commands/lib/theme.d.ts.map +1 -1
  54. package/cli/src/commands/lib/version.d.ts +1 -1
  55. package/cli/src/commands/lib/watch.d.ts +37 -0
  56. package/cli/src/commands/lib/watch.d.ts.map +1 -0
  57. package/cli/src/commands/og.d.ts +1 -1
  58. package/cli/src/commands/og.d.ts.map +1 -1
  59. package/cli/src/commands/start.d.ts +2 -2
  60. package/cli/src/commands/start.d.ts.map +1 -1
  61. package/cli/src/commands/static-render.d.ts +18 -0
  62. package/cli/src/commands/static-render.d.ts.map +1 -0
  63. package/cli/src/index.d.ts +1 -1
  64. package/core/index.d.ts +1 -1
  65. package/core/index.js +1102 -369
  66. package/core/index.js.map +40 -37
  67. package/core/src/app-paths.d.ts +32 -0
  68. package/core/src/app-paths.d.ts.map +1 -0
  69. package/core/src/bundler/hash.d.ts +1 -1
  70. package/core/src/bundler/index.d.ts +1 -1
  71. package/core/src/config.d.ts +98 -7
  72. package/core/src/config.d.ts.map +1 -1
  73. package/core/src/content/discovery.d.ts +1 -1
  74. package/core/src/content/index.d.ts +1 -1
  75. package/core/src/content/metadata.d.ts +1 -1
  76. package/core/src/i18n/catalog.d.ts +1 -1
  77. package/core/src/i18n/discover.d.ts +1 -1
  78. package/core/src/i18n/discover.d.ts.map +1 -1
  79. package/core/src/i18n/index.d.ts +2 -2
  80. package/core/src/i18n/index.d.ts.map +1 -1
  81. package/core/src/i18n/messages.d.ts +1 -1
  82. package/core/src/i18n/negotiate.d.ts +1 -1
  83. package/core/src/i18n/pathname.d.ts +32 -4
  84. package/core/src/i18n/pathname.d.ts.map +1 -1
  85. package/core/src/i18n/resolve.d.ts +5 -3
  86. package/core/src/i18n/resolve.d.ts.map +1 -1
  87. package/core/src/i18n/types.d.ts +48 -1
  88. package/core/src/i18n/types.d.ts.map +1 -1
  89. package/core/src/image.d.ts +29 -0
  90. package/core/src/image.d.ts.map +1 -0
  91. package/core/src/index.d.ts +3 -1
  92. package/core/src/index.d.ts.map +1 -1
  93. package/core/src/llms/discovery.d.ts +35 -0
  94. package/core/src/llms/discovery.d.ts.map +1 -0
  95. package/core/src/llms/extractor.d.ts +6 -1
  96. package/core/src/llms/extractor.d.ts.map +1 -1
  97. package/core/src/llms/formatter.d.ts +1 -1
  98. package/core/src/llms/formatter.d.ts.map +1 -1
  99. package/core/src/llms/full-generator.d.ts +3 -1
  100. package/core/src/llms/full-generator.d.ts.map +1 -1
  101. package/core/src/llms/index-generator.d.ts +6 -3
  102. package/core/src/llms/index-generator.d.ts.map +1 -1
  103. package/core/src/llms/index.d.ts +5 -2
  104. package/core/src/llms/index.d.ts.map +1 -1
  105. package/core/src/og/discovery.d.ts +8 -1
  106. package/core/src/og/discovery.d.ts.map +1 -1
  107. package/core/src/og/index.d.ts +1 -1
  108. package/core/src/og/meta.d.ts +1 -1
  109. package/core/src/og/render.d.ts +1 -1
  110. package/core/src/og/types.d.ts +1 -1
  111. package/core/src/robots/discovery.d.ts +1 -1
  112. package/core/src/robots/generator.d.ts +1 -1
  113. package/core/src/robots/generator.d.ts.map +1 -1
  114. package/core/src/robots/index.d.ts +1 -1
  115. package/core/src/robots/policies.d.ts +1 -1
  116. package/core/src/rss/discovery.d.ts +2 -2
  117. package/core/src/rss/discovery.d.ts.map +1 -1
  118. package/core/src/rss/generator.d.ts +1 -1
  119. package/core/src/rss/index.d.ts +1 -1
  120. package/core/src/sitemap/discovery.d.ts +7 -2
  121. package/core/src/sitemap/discovery.d.ts.map +1 -1
  122. package/core/src/sitemap/generator.d.ts +12 -2
  123. package/core/src/sitemap/generator.d.ts.map +1 -1
  124. package/core/src/sitemap/index.d.ts +1 -1
  125. package/core/src/ssr/index.d.ts +1 -1
  126. package/core/src/ssr/lib/cache.d.ts +1 -1
  127. package/core/src/ssr/lib/cleanup.d.ts +1 -1
  128. package/core/src/ssr/lib/collections.d.ts +17 -1
  129. package/core/src/ssr/lib/collections.d.ts.map +1 -1
  130. package/core/src/ssr/lib/compression.d.ts +1 -1
  131. package/core/src/ssr/lib/compute/content.d.ts +1 -1
  132. package/core/src/ssr/lib/compute/index.d.ts +1 -1
  133. package/core/src/ssr/lib/compute/index.d.ts.map +1 -1
  134. package/core/src/ssr/lib/compute/layouts.d.ts +1 -1
  135. package/core/src/ssr/lib/compute/layouts.d.ts.map +1 -1
  136. package/core/src/ssr/lib/compute/routes.d.ts +1 -1
  137. package/core/src/ssr/lib/compute/routes.d.ts.map +1 -1
  138. package/core/src/ssr/lib/content-path.d.ts +13 -2
  139. package/core/src/ssr/lib/content-path.d.ts.map +1 -1
  140. package/core/src/ssr/lib/data.d.ts +1 -1
  141. package/core/src/ssr/lib/html.d.ts +7 -1
  142. package/core/src/ssr/lib/html.d.ts.map +1 -1
  143. package/core/src/ssr/lib/imports.d.ts +8 -3
  144. package/core/src/ssr/lib/imports.d.ts.map +1 -1
  145. package/core/src/ssr/lib/index.d.ts +1 -1
  146. package/core/src/ssr/lib/layouts.d.ts +15 -2
  147. package/core/src/ssr/lib/layouts.d.ts.map +1 -1
  148. package/core/src/ssr/lib/metadata.d.ts +1 -1
  149. package/core/src/ssr/lib/metadata.d.ts.map +1 -1
  150. package/core/src/ssr/lib/mime.d.ts +1 -1
  151. package/core/src/ssr/lib/modules.d.ts +1 -1
  152. package/core/src/ssr/lib/path.d.ts +1 -1
  153. package/core/src/ssr/lib/preload.d.ts +16 -3
  154. package/core/src/ssr/lib/preload.d.ts.map +1 -1
  155. package/core/src/ssr/lib/route-match.d.ts +1 -1
  156. package/core/src/ssr/lib/scripts/collections.d.ts +2 -2
  157. package/core/src/ssr/lib/scripts/collections.d.ts.map +1 -1
  158. package/core/src/ssr/lib/scripts/data.d.ts +1 -1
  159. package/core/src/ssr/lib/scripts/data.d.ts.map +1 -1
  160. package/core/src/ssr/lib/scripts/escape.d.ts +1 -1
  161. package/core/src/ssr/lib/scripts/feeds.d.ts +1 -1
  162. package/core/src/ssr/lib/scripts/index.d.ts +1 -1
  163. package/core/src/ssr/lib/seed.d.ts +6 -1
  164. package/core/src/ssr/lib/seed.d.ts.map +1 -1
  165. package/core/src/ssr/lib/serialize.d.ts +1 -1
  166. package/core/src/ssr/lib/setup.d.ts +2 -2
  167. package/core/src/ssr/lib/setup.d.ts.map +1 -1
  168. package/core/src/ssr/lib/styles.d.ts +5 -4
  169. package/core/src/ssr/lib/styles.d.ts.map +1 -1
  170. package/core/src/ssr/lib/template.d.ts +1 -1
  171. package/core/src/ssr/lib/types.d.ts +36 -2
  172. package/core/src/ssr/lib/types.d.ts.map +1 -1
  173. package/core/src/ssr/render.d.ts +1 -1
  174. package/core/src/ssr/render.d.ts.map +1 -1
  175. package/core/src/ssr/stream.d.ts +1 -1
  176. package/core/src/ssr/stream.d.ts.map +1 -1
  177. package/elysia/index.d.ts +1 -1
  178. package/elysia/index.js +2044 -864
  179. package/elysia/index.js.map +57 -49
  180. package/elysia/src/index.d.ts +2 -1
  181. package/elysia/src/index.d.ts.map +1 -1
  182. package/elysia/src/libs/assets.d.ts +1 -1
  183. package/elysia/src/libs/cache.d.ts +6 -1
  184. package/elysia/src/libs/cache.d.ts.map +1 -1
  185. package/elysia/src/libs/caching.d.ts +1 -1
  186. package/elysia/src/libs/devReload.d.ts +53 -0
  187. package/elysia/src/libs/devReload.d.ts.map +1 -0
  188. package/elysia/src/libs/http.d.ts +7 -1
  189. package/elysia/src/libs/http.d.ts.map +1 -1
  190. package/elysia/src/libs/i18n.d.ts +15 -4
  191. package/elysia/src/libs/i18n.d.ts.map +1 -1
  192. package/elysia/src/libs/image.d.ts +30 -1
  193. package/elysia/src/libs/image.d.ts.map +1 -1
  194. package/elysia/src/libs/index.d.ts +2 -2
  195. package/elysia/src/libs/index.d.ts.map +1 -1
  196. package/elysia/src/libs/lazyData.d.ts +38 -0
  197. package/elysia/src/libs/lazyData.d.ts.map +1 -0
  198. package/elysia/src/libs/llms.d.ts +1 -1
  199. package/elysia/src/libs/response.d.ts +1 -1
  200. package/elysia/src/libs/serving.d.ts +1 -1
  201. package/elysia/src/plugin.d.ts +1 -1
  202. package/elysia/src/plugin.d.ts.map +1 -1
  203. package/elysia/src/routes/artifacts.d.ts +1 -1
  204. package/elysia/src/routes/artifacts.d.ts.map +1 -1
  205. package/elysia/src/routes/content.d.ts +2 -2
  206. package/elysia/src/routes/content.d.ts.map +1 -1
  207. package/elysia/src/routes/image.d.ts +1 -1
  208. package/elysia/src/routes/index.d.ts +1 -1
  209. package/elysia/src/routes/internal.d.ts +18 -2
  210. package/elysia/src/routes/internal.d.ts.map +1 -1
  211. package/elysia/src/routes/liveReloadClient.d.ts +16 -0
  212. package/elysia/src/routes/liveReloadClient.d.ts.map +1 -0
  213. package/elysia/src/routes/llms.d.ts +1 -1
  214. package/elysia/src/routes/llms.d.ts.map +1 -1
  215. package/elysia/src/routes/og.d.ts +1 -1
  216. package/elysia/src/routes/redirects.d.ts +1 -1
  217. package/elysia/src/routes/robots.d.ts +3 -1
  218. package/elysia/src/routes/robots.d.ts.map +1 -1
  219. package/elysia/src/routes/rss.d.ts +1 -1
  220. package/elysia/src/routes/search.d.ts +1 -1
  221. package/elysia/src/routes/sitemap.d.ts +3 -1
  222. package/elysia/src/routes/sitemap.d.ts.map +1 -1
  223. package/elysia/src/routes/ssr.d.ts +4 -2
  224. package/elysia/src/routes/ssr.d.ts.map +1 -1
  225. package/elysia/src/routes/static.d.ts +1 -1
  226. package/elysia/src/routes/themeCssRefresh.d.ts +17 -0
  227. package/elysia/src/routes/themeCssRefresh.d.ts.map +1 -0
  228. package/elysia/src/types.d.ts +1 -1
  229. package/package.json +1 -1
  230. package/react/index.d.ts +1 -1
  231. package/react/index.js +718 -369
  232. package/react/index.js.map +19 -16
  233. package/react/src/components/ClientOnly.d.ts +1 -1
  234. package/react/src/components/ContentRoute.d.ts +1 -1
  235. package/react/src/components/Image.d.ts +5 -1
  236. package/react/src/components/Image.d.ts.map +1 -1
  237. package/react/src/components/LazyRoute.d.ts +1 -1
  238. package/react/src/components/Link.d.ts +18 -5
  239. package/react/src/components/Link.d.ts.map +1 -1
  240. package/react/src/components/Markdown.d.ts +1 -1
  241. package/react/src/components/Markdown.d.ts.map +1 -1
  242. package/react/src/components/Outlet.d.ts +1 -1
  243. package/react/src/components/index.d.ts +1 -1
  244. package/react/src/hooks/index.d.ts +1 -1
  245. package/react/src/hooks/useContent.d.ts +1 -1
  246. package/react/src/hooks/useContent.d.ts.map +1 -1
  247. package/react/src/hooks/useData.d.ts +11 -1
  248. package/react/src/hooks/useData.d.ts.map +1 -1
  249. package/react/src/hooks/useFeed.d.ts +1 -1
  250. package/react/src/hooks/useLayoutData.d.ts +11 -1
  251. package/react/src/hooks/useLayoutData.d.ts.map +1 -1
  252. package/react/src/hooks/useLlms.d.ts +1 -1
  253. package/react/src/hooks/useNavigate.d.ts +1 -1
  254. package/react/src/hooks/useParams.d.ts +1 -1
  255. package/react/src/hooks/useRouter.d.ts +1 -1
  256. package/react/src/hooks/useSearch.d.ts +1 -1
  257. package/react/src/hooks/useSearchParams.d.ts +1 -1
  258. package/react/src/hooks/useToc.d.ts +1 -1
  259. package/react/src/i18n/LocaleProvider.d.ts +20 -2
  260. package/react/src/i18n/LocaleProvider.d.ts.map +1 -1
  261. package/react/src/i18n/helpers.d.ts +31 -3
  262. package/react/src/i18n/helpers.d.ts.map +1 -1
  263. package/react/src/i18n/index.d.ts +2 -2
  264. package/react/src/i18n/index.d.ts.map +1 -1
  265. package/react/src/index.d.ts +1 -1
  266. package/react/src/lib/bundle.d.ts +27 -0
  267. package/react/src/lib/bundle.d.ts.map +1 -0
  268. package/react/src/lib/collection.d.ts +1 -1
  269. package/react/src/lib/content.d.ts +1 -1
  270. package/react/src/lib/head.d.ts +37 -1
  271. package/react/src/lib/head.d.ts.map +1 -1
  272. package/react/src/lib/index.d.ts +4 -1
  273. package/react/src/lib/index.d.ts.map +1 -1
  274. package/react/src/lib/layouts.d.ts +26 -0
  275. package/react/src/lib/layouts.d.ts.map +1 -0
  276. package/react/src/lib/lazy-route.d.ts +12 -19
  277. package/react/src/lib/lazy-route.d.ts.map +1 -1
  278. package/react/src/lib/route-loader.d.ts +1 -1
  279. package/react/src/lib/static-data.d.ts +31 -0
  280. package/react/src/lib/static-data.d.ts.map +1 -0
  281. package/react/src/providers/ContentProvider.d.ts +1 -1
  282. package/react/src/providers/RerouteProvider.d.ts +2 -2
  283. package/react/src/providers/RerouteProvider.d.ts.map +1 -1
  284. package/react/src/providers/RouterProvider.d.ts +31 -3
  285. package/react/src/providers/RouterProvider.d.ts.map +1 -1
  286. package/react/src/providers/index.d.ts +1 -1
  287. package/react/src/types/any.d.ts +1 -1
  288. package/react/src/types/index.d.ts +1 -1
  289. package/react/src/types/router.d.ts +15 -1
  290. package/react/src/types/router.d.ts.map +1 -1
  291. package/telemetry/react.d.ts +1 -1
  292. package/telemetry/react.js +16 -16
  293. package/telemetry/react.js.map +2 -2
  294. package/telemetry/server.d.ts +1 -1
  295. package/telemetry/server.js +82 -232
  296. package/telemetry/server.js.map +30 -24
  297. package/telemetry/src/react/api.d.ts +1 -1
  298. package/telemetry/src/react/context.d.ts +1 -1
  299. package/telemetry/src/react/index.d.ts +1 -1
  300. package/telemetry/src/react/telemetry.d.ts +1 -1
  301. package/telemetry/src/server/context.d.ts +1 -1
  302. package/telemetry/src/server/headers/extractor.d.ts +1 -1
  303. package/telemetry/src/server/headers/index.d.ts +1 -1
  304. package/telemetry/src/server/headers/presets.d.ts +1 -1
  305. package/telemetry/src/server/index.d.ts +1 -1
  306. package/telemetry/src/server/instrumentation.d.ts +1 -1
  307. package/telemetry/src/server/plugin.d.ts +1 -1
  308. package/telemetry/src/server/sourcemap.d.ts +1 -1
package/core/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * reroute-js v1.0.0-alpha.4
2
+ * reroute-js v1.0.0-alpha.41
3
3
  *
4
4
  * @license MIT
5
5
  * @copyright 2026 stewones <hi@stewan.io>
@@ -25,6 +25,31 @@ var __export = (target, all) => {
25
25
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
26
26
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
27
27
 
28
+ // packages/core/src/app-paths.ts
29
+ import { posix } from "node:path";
30
+ function toPosix(p) {
31
+ return p.replace(/\\/g, "/");
32
+ }
33
+ function resolveAppPaths(config = {}) {
34
+ const src = config.app?.src ?? DEFAULT_APP_SRC;
35
+ const server = config.app?.server ?? DEFAULT_APP_SERVER;
36
+ const clientDir = toPosix(posix.dirname(src));
37
+ return {
38
+ src,
39
+ clientDir,
40
+ routesDir: toPosix(posix.join(clientDir, "routes")),
41
+ cssEntry: toPosix(posix.join(clientDir, "index.css")),
42
+ assetsDir: toPosix(posix.join(clientDir, "assets")),
43
+ server
44
+ };
45
+ }
46
+ function importFromReroute(relPath) {
47
+ const cleaned = toPosix(relPath).replace(/^\.\//, "").replace(/\.(tsx|ts|jsx|js)$/, "");
48
+ return `../${cleaned}`;
49
+ }
50
+ var DEFAULT_APP_SRC = "./src/client/App", DEFAULT_APP_SERVER = "./src/index.ts";
51
+ var init_app_paths = () => {};
52
+
28
53
  // packages/core/src/bundler/hash.ts
29
54
  async function generateContentHash(content) {
30
55
  const data = new TextEncoder().encode(content);
@@ -261,6 +286,9 @@ async function discoverI18n(cwd, options = {}) {
261
286
  const defaultLocale = options.defaultLocale ?? DEFAULT_LOCALE;
262
287
  const cookie = options.cookie ?? DEFAULT_COOKIE;
263
288
  const redirectContentOnNegotiate = options.redirectContentOnNegotiate ?? true;
289
+ const prefixPages = options.prefixPages ?? false;
290
+ const unprefixedPaths = options.unprefixedPaths ?? [];
291
+ const localeParam = options.localeParam ?? "";
264
292
  const absDir = join2(cwd, localesDir);
265
293
  const disabled = {
266
294
  enabled: false,
@@ -269,6 +297,9 @@ async function discoverI18n(cwd, options = {}) {
269
297
  localesDir,
270
298
  cookie,
271
299
  redirectContentOnNegotiate,
300
+ prefixPages,
301
+ unprefixedPaths,
302
+ localeParam,
272
303
  catalogs: {}
273
304
  };
274
305
  let catalogs;
@@ -292,6 +323,9 @@ async function discoverI18n(cwd, options = {}) {
292
323
  localesDir,
293
324
  cookie,
294
325
  redirectContentOnNegotiate,
326
+ prefixPages,
327
+ unprefixedPaths,
328
+ localeParam,
295
329
  catalogs
296
330
  };
297
331
  }
@@ -390,14 +424,18 @@ var init_negotiate = () => {};
390
424
  // packages/core/src/i18n/pathname.ts
391
425
  var exports_pathname = {};
392
426
  __export(exports_pathname, {
393
- toOgLocale: () => toOgLocale,
394
- parseContentPath: () => parseContentPath,
395
- normalizePathname: () => normalizePathname,
396
- looksLikeLocale: () => looksLikeLocale,
397
- localizeHref: () => localizeHref,
398
- localizeContentHref: () => localizeContentHref,
427
+ contentKey: () => contentKey,
399
428
  hreflangTags: () => hreflangTags,
400
- contentKey: () => contentKey
429
+ isUnprefixedPath: () => isUnprefixedPath,
430
+ localizeContentHref: () => localizeContentHref,
431
+ localizeHref: () => localizeHref,
432
+ localizePagePath: () => localizePagePath,
433
+ looksLikeLocale: () => looksLikeLocale,
434
+ normalizePathname: () => normalizePathname,
435
+ pageHreflangTags: () => pageHreflangTags,
436
+ parseContentPath: () => parseContentPath,
437
+ parseLocalePrefix: () => parseLocalePrefix,
438
+ toOgLocale: () => toOgLocale
401
439
  });
402
440
  function looksLikeLocale(segment) {
403
441
  return /^[a-z]{2}(?:-[A-Za-z0-9]{2,8})*$/i.test(segment);
@@ -426,7 +464,7 @@ function parseContentPath(pathname, availableLocales = [], collections) {
426
464
  collection,
427
465
  name: third,
428
466
  locale,
429
- routingPathname: `/${collection}/${third}`,
467
+ routingPathname: `/${[collection, ...parts.slice(2)].join("/")}`,
430
468
  pathname: normalized
431
469
  };
432
470
  }
@@ -434,7 +472,7 @@ function parseContentPath(pathname, availableLocales = [], collections) {
434
472
  return {
435
473
  collection,
436
474
  name: second,
437
- routingPathname: `/${collection}/${second}`,
475
+ routingPathname: `/${parts.join("/")}`,
438
476
  pathname: normalized
439
477
  };
440
478
  }
@@ -444,13 +482,36 @@ function localizeContentHref(collection, name, locale, defaultLocale) {
444
482
  }
445
483
  return `/${collection}/${locale}/${name}`;
446
484
  }
447
- function localizeHref(to, locale, defaultLocale, availableLocales = [], collections) {
485
+ function parseLocalePrefix(pathname, availableLocales) {
486
+ const [, segment = "", ...rest] = normalizePathname(pathname).split("/");
487
+ const locale = availableLocales.find((l) => l.toLowerCase() === segment.toLowerCase());
488
+ if (!locale)
489
+ return;
490
+ return { locale, segment, routingPathname: `/${rest.join("/")}` };
491
+ }
492
+ function localizePagePath(pathname, locale, defaultLocale) {
493
+ if (locale === defaultLocale)
494
+ return pathname;
495
+ return pathname === "/" ? `/${locale}` : `/${locale}${pathname}`;
496
+ }
497
+ function isUnprefixedPath(pathname, unprefixedPaths = []) {
498
+ const path = normalizePathname(pathname);
499
+ return unprefixedPaths.some((prefix) => {
500
+ const base = prefix.replace(/\/+$/, "");
501
+ return base === "" || path === base || path.startsWith(`${base}/`);
502
+ });
503
+ }
504
+ function localizeHref(to, locale, defaultLocale, availableLocales = [], collections, prefixPages) {
448
505
  try {
449
506
  const url = new URL(to, "http://local");
450
- const parsed = parseContentPath(url.pathname, availableLocales, collections);
451
- if (!parsed)
507
+ const parsed = parseContentPath(url.pathname, availableLocales, prefixPages ? collections ?? [] : collections);
508
+ if (parsed) {
509
+ url.pathname = localizeContentHref(parsed.collection, parsed.name, locale, defaultLocale);
510
+ } else if (prefixPages && to.startsWith("/") && url.origin === "http://local" && !/\.[^/]+$/.test(url.pathname) && !parseLocalePrefix(url.pathname, availableLocales) && !isUnprefixedPath(url.pathname, prefixPages.unprefixedPaths)) {
511
+ url.pathname = localizePagePath(url.pathname, locale, defaultLocale);
512
+ } else {
452
513
  return to;
453
- url.pathname = localizeContentHref(parsed.collection, parsed.name, locale, defaultLocale);
514
+ }
454
515
  return `${url.pathname}${url.search}${url.hash}`;
455
516
  } catch {
456
517
  return to;
@@ -465,24 +526,111 @@ function contentKey(collection, name, locale, defaultLocale = "en-US") {
465
526
  function toOgLocale(locale) {
466
527
  return locale.replace(/-/g, "_");
467
528
  }
468
- function hreflangTags(baseUrl, collection, name, locales, defaultLocale) {
529
+ function alternateLinks(baseUrl, locales, defaultLocale, pathFor) {
469
530
  const base = baseUrl.replace(/\/$/, "");
470
- const tags = [];
471
- for (const locale of locales) {
472
- const path = localizeContentHref(collection, name, locale, defaultLocale);
473
- tags.push(`<link rel="alternate" hreflang="${locale}" href="${base}${path}" />`);
474
- }
475
- const defaultPath = localizeContentHref(collection, name, defaultLocale, defaultLocale);
476
- tags.push(`<link rel="alternate" hreflang="x-default" href="${base}${defaultPath}" />`);
477
- return tags.join(`
531
+ return [...locales, "x-default"].map((hreflang) => {
532
+ const path = pathFor(hreflang === "x-default" ? defaultLocale : hreflang);
533
+ return `<link rel="alternate" hreflang="${hreflang}" href="${base}${path}" />`;
534
+ }).join(`
478
535
  `);
479
536
  }
537
+ function hreflangTags(baseUrl, collection, name, locales, defaultLocale) {
538
+ return alternateLinks(baseUrl, locales, defaultLocale, (locale) => localizeContentHref(collection, name, locale, defaultLocale));
539
+ }
540
+ function pageHreflangTags(baseUrl, routingPathname, locales, defaultLocale) {
541
+ return alternateLinks(baseUrl, locales, defaultLocale, (locale) => localizePagePath(routingPathname, locale, defaultLocale));
542
+ }
480
543
  var init_pathname = () => {};
481
544
 
482
545
  // packages/core/src/i18n/resolve.ts
546
+ function canonicalLocale(value, availableLocales) {
547
+ return availableLocales.find((l) => l.toLowerCase() === value.toLowerCase()) || value;
548
+ }
549
+ function parseLangParam(search, isAvailable, availableLocales) {
550
+ if (!search)
551
+ return;
552
+ const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
553
+ const raw = params.get("lang") ?? undefined;
554
+ if (!isAvailable(raw))
555
+ return;
556
+ return canonicalLocale(raw, availableLocales);
557
+ }
558
+ function stripLangParam(search) {
559
+ if (!search)
560
+ return "";
561
+ const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
562
+ params.delete("lang");
563
+ const rest = params.toString();
564
+ return rest ? `?${rest}` : "";
565
+ }
566
+ function unprefix(pagePathname, search, defaultLocale) {
567
+ const query = search ? `?${search.replace(/^\?/, "")}` : "";
568
+ return {
569
+ locale: defaultLocale,
570
+ routingPathname: pagePathname,
571
+ fromPath: true,
572
+ fromQuery: false,
573
+ redirectTo: `${pagePathname}${query}`,
574
+ permanent: true,
575
+ urlOnly: true
576
+ };
577
+ }
578
+ function resolvePrefixedLocale(input) {
579
+ const prefix = parseLocalePrefix(input.pathname, input.availableLocales);
580
+ const pagePathname = prefix?.routingPathname ?? normalizePathname(input.pathname);
581
+ if (!isUnprefixedPath(pagePathname, input.unprefixedPaths)) {
582
+ return resolvePrefixedPage(input, prefix, pagePathname);
583
+ }
584
+ return prefix ? unprefix(pagePathname, input.search, input.defaultLocale) : resolveNegotiatedLocale(input);
585
+ }
586
+ function resolvePrefixedPage(input, prefix, pagePathname) {
587
+ const { search, availableLocales, defaultLocale } = input;
588
+ const isAvailable = (locale2) => !!locale2 && availableLocales.some((l) => l.toLowerCase() === locale2.toLowerCase());
589
+ const parsed = parseContentPath(pagePathname, availableLocales, input.collections ?? []);
590
+ const urlLocale = parsed?.locale ?? prefix?.locale ?? defaultLocale;
591
+ const queryLocale = parseLangParam(search, isAvailable, availableLocales);
592
+ const locale = queryLocale ?? urlLocale;
593
+ const misplaced = !!prefix && (!!parsed || prefix.locale === defaultLocale || prefix.segment !== prefix.locale);
594
+ const defaultSegment = !prefix && parsed?.locale === defaultLocale;
595
+ const canonical = parsed ? localizeContentHref(parsed.collection, parsed.name, locale, defaultLocale) : localizePagePath(pagePathname, locale, defaultLocale);
596
+ return {
597
+ locale,
598
+ routingPathname: parsed?.routingPathname ?? pagePathname,
599
+ fromPath: !!(parsed?.locale || prefix),
600
+ fromQuery: !!queryLocale,
601
+ redirectTo: queryLocale || misplaced || defaultSegment ? `${canonical}${stripLangParam(search)}` : undefined,
602
+ permanent: !queryLocale && (misplaced || defaultSegment),
603
+ urlOnly: true,
604
+ parsed: parsed ? { ...parsed, locale } : undefined
605
+ };
606
+ }
607
+ function resolveParamLocale(input, localeParam) {
608
+ const { pathname, search, availableLocales, defaultLocale } = input;
609
+ const parsed = parseContentPath(pathname, availableLocales, input.collections);
610
+ const named = new URLSearchParams(search ?? "").get(localeParam);
611
+ const param = named ? availableLocales.find((l) => l.toLowerCase() === named.toLowerCase()) : undefined;
612
+ const pathLocale = parsed?.locale && canonicalLocale(parsed.locale, availableLocales);
613
+ const locale = pathLocale || param || defaultLocale;
614
+ return {
615
+ locale,
616
+ routingPathname: parsed?.routingPathname ?? normalizePathname(pathname),
617
+ fromPath: !!pathLocale,
618
+ fromQuery: false,
619
+ urlOnly: true,
620
+ parsed: parsed ? { ...parsed, locale: pathLocale || undefined } : undefined
621
+ };
622
+ }
483
623
  function resolveLocale(input) {
624
+ if (input.prefixPages)
625
+ return resolvePrefixedLocale(input);
626
+ if (input.localeParam)
627
+ return resolveParamLocale(input, input.localeParam);
628
+ return resolveNegotiatedLocale(input);
629
+ }
630
+ function resolveNegotiatedLocale(input) {
484
631
  const {
485
632
  pathname,
633
+ search,
486
634
  cookieHeader,
487
635
  acceptLanguage,
488
636
  availableLocales,
@@ -493,14 +641,32 @@ function resolveLocale(input) {
493
641
  const parsed = parseContentPath(pathname, availableLocales, collections);
494
642
  const availableLower = new Set(availableLocales.map((l) => l.toLowerCase()));
495
643
  const isAvailable = (locale) => !!locale && availableLower.has(locale.toLowerCase());
644
+ const routingPathname = parsed?.routingPathname ?? pathname.split("?")[0];
645
+ const restSearch = stripLangParam(search);
646
+ const queryLocale = parseLangParam(search, isAvailable, availableLocales);
647
+ if (queryLocale) {
648
+ const target = parsed ? localizeContentHref(parsed.collection, parsed.name, queryLocale, defaultLocale) : routingPathname;
649
+ return {
650
+ locale: queryLocale,
651
+ routingPathname,
652
+ fromPath: false,
653
+ fromQuery: true,
654
+ redirectTo: `${target}${restSearch}`,
655
+ parsed: parsed ? {
656
+ ...parsed,
657
+ locale: queryLocale === defaultLocale ? undefined : queryLocale
658
+ } : undefined
659
+ };
660
+ }
496
661
  if (parsed?.locale && isAvailable(parsed.locale)) {
497
- const locale = availableLocales.find((l) => l.toLowerCase() === parsed.locale?.toLowerCase()) || parsed.locale;
662
+ const locale = canonicalLocale(parsed.locale, availableLocales);
498
663
  if (locale === defaultLocale && parsed.pathname !== parsed.routingPathname) {
499
664
  return {
500
665
  locale,
501
666
  routingPathname: parsed.routingPathname,
502
667
  fromPath: true,
503
- redirectTo: parsed.routingPathname,
668
+ fromQuery: false,
669
+ redirectTo: `${parsed.routingPathname}${restSearch}`,
504
670
  parsed: { ...parsed, locale }
505
671
  };
506
672
  }
@@ -508,17 +674,18 @@ function resolveLocale(input) {
508
674
  locale,
509
675
  routingPathname: parsed.routingPathname,
510
676
  fromPath: true,
677
+ fromQuery: false,
511
678
  parsed: { ...parsed, locale }
512
679
  };
513
680
  }
514
- const routingPathname = parsed?.routingPathname ?? pathname.split("?")[0];
515
681
  const cookieLocale = parseCookieValue(cookieHeader, cookieName);
516
682
  if (isAvailable(cookieLocale)) {
517
- const locale = availableLocales.find((l) => l.toLowerCase() === cookieLocale.toLowerCase()) || cookieLocale;
683
+ const locale = canonicalLocale(cookieLocale, availableLocales);
518
684
  return {
519
685
  locale,
520
686
  routingPathname,
521
687
  fromPath: false,
688
+ fromQuery: false,
522
689
  parsed: parsed ? { ...parsed, locale: undefined } : undefined
523
690
  };
524
691
  }
@@ -527,13 +694,14 @@ function resolveLocale(input) {
527
694
  locale: negotiated,
528
695
  routingPathname,
529
696
  fromPath: false,
697
+ fromQuery: false,
530
698
  parsed: parsed ? { ...parsed, locale: undefined } : undefined
531
699
  };
532
700
  }
533
701
  function contentNegotiateRedirect(resolution, defaultLocale, enabled) {
534
702
  if (!enabled)
535
703
  return;
536
- if (resolution.fromPath)
704
+ if (resolution.fromPath || resolution.fromQuery)
537
705
  return;
538
706
  if (resolution.locale === defaultLocale)
539
707
  return;
@@ -558,6 +726,58 @@ var init_i18n = __esm(() => {
558
726
  init_resolve();
559
727
  });
560
728
 
729
+ // packages/core/src/image.ts
730
+ function uniquePositiveWidths(widths) {
731
+ return [...new Set(widths.filter((width) => width > 0))].sort((a, b) => a - b);
732
+ }
733
+ function resolveImagePreprocess(image) {
734
+ const preprocess = image?.preprocess;
735
+ if (!preprocess) {
736
+ return {
737
+ enabled: false,
738
+ widths: [...DEFAULT_IMAGE_DEVICE_SIZES],
739
+ formats: [...DEFAULT_PREPROCESS_FORMATS],
740
+ quality: DEFAULT_IMAGE_QUALITY,
741
+ qualities: [DEFAULT_IMAGE_QUALITY]
742
+ };
743
+ }
744
+ const options = preprocess === true ? {} : preprocess;
745
+ const quality = options.quality ?? DEFAULT_IMAGE_QUALITY;
746
+ return {
747
+ enabled: true,
748
+ widths: uniquePositiveWidths([
749
+ options.mobile ?? DEFAULT_PREPROCESS_SIZES.mobile,
750
+ options.tablet ?? DEFAULT_PREPROCESS_SIZES.tablet,
751
+ options.desktop ?? DEFAULT_PREPROCESS_SIZES.desktop
752
+ ]),
753
+ formats: options.formats?.length ? options.formats : [...DEFAULT_PREPROCESS_FORMATS],
754
+ quality,
755
+ qualities: uniquePositiveWidths(options.qualities ?? [quality])
756
+ };
757
+ }
758
+ function resolveImageDeviceSizes(image) {
759
+ return resolveImagePreprocess(image).widths;
760
+ }
761
+ var DEFAULT_IMAGE_DEVICE_SIZES, DEFAULT_PREPROCESS_SIZES, DEFAULT_PREPROCESS_FORMATS, DEFAULT_IMAGE_QUALITY = 75;
762
+ var init_image = __esm(() => {
763
+ DEFAULT_IMAGE_DEVICE_SIZES = [
764
+ 640,
765
+ 750,
766
+ 828,
767
+ 1080,
768
+ 1200,
769
+ 1920,
770
+ 2048,
771
+ 3840
772
+ ];
773
+ DEFAULT_PREPROCESS_SIZES = {
774
+ mobile: 640,
775
+ tablet: 1024,
776
+ desktop: 1920
777
+ };
778
+ DEFAULT_PREPROCESS_FORMATS = ["webp", "avif"];
779
+ });
780
+
561
781
  // packages/telemetry/src/server/context.ts
562
782
  import { AsyncLocalStorage } from "node:async_hooks";
563
783
  var contextStorage;
@@ -1049,11 +1269,39 @@ function cleanupPathScopedSSRData(pathname) {
1049
1269
  }
1050
1270
 
1051
1271
  // packages/core/src/ssr/lib/imports.ts
1272
+ import { copyFile, realpath, stat as stat3, unlink } from "node:fs/promises";
1273
+ import { basename as basename2, dirname, extname as extname2, join as join3 } from "node:path";
1052
1274
  import { pathToFileURL as pathToFileURL3 } from "node:url";
1275
+ function clearWatchImportCache() {
1276
+ watchImportCache.clear();
1277
+ }
1278
+ function bustCopyPath(absolutePath) {
1279
+ const dir = dirname(absolutePath);
1280
+ const ext = extname2(absolutePath);
1281
+ const base = basename2(absolutePath, ext);
1282
+ const token = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1283
+ return join3(dir, `${base}.bust-${token}${ext}`);
1284
+ }
1053
1285
  async function dynamicImport(absolutePath, isWatchMode) {
1054
1286
  const href = pathToFileURL3(absolutePath).href;
1055
- const url = isWatchMode ? `${href}?t=${Date.now()}` : href;
1056
- return await import(url);
1287
+ if (!isWatchMode) {
1288
+ return await import(href);
1289
+ }
1290
+ const resolved = await realpath(absolutePath);
1291
+ const mtimeMs = (await stat3(resolved)).mtimeMs;
1292
+ const cached = watchImportCache.get(resolved);
1293
+ if (cached && cached.mtimeMs === mtimeMs) {
1294
+ return cached.mod;
1295
+ }
1296
+ const tmp = bustCopyPath(resolved);
1297
+ await copyFile(resolved, tmp);
1298
+ try {
1299
+ const mod = await import(pathToFileURL3(tmp).href);
1300
+ watchImportCache.set(resolved, { mtimeMs, mod });
1301
+ return mod;
1302
+ } finally {
1303
+ await unlink(tmp).catch(() => {});
1304
+ }
1057
1305
  }
1058
1306
  function isThenable(value) {
1059
1307
  return typeof value === "object" && value !== null && typeof value.then === "function";
@@ -1061,7 +1309,10 @@ function isThenable(value) {
1061
1309
  function toPromise(input) {
1062
1310
  return input instanceof Promise ? input : Promise.resolve(input);
1063
1311
  }
1064
- var init_imports = () => {};
1312
+ var watchImportCache;
1313
+ var init_imports = __esm(() => {
1314
+ watchImportCache = new Map;
1315
+ });
1065
1316
 
1066
1317
  // packages/core/src/ssr/lib/collections.ts
1067
1318
  async function loadCollections(cwd, isWatchMode) {
@@ -1078,6 +1329,21 @@ function setGlobalCollections(byCollectionForSSR) {
1078
1329
  globalThis.__REROUTE_COLLECTIONS__ = byCollectionForSSR;
1079
1330
  } catch {}
1080
1331
  }
1332
+ function resetSSRContentResults() {
1333
+ try {
1334
+ globalThis.__REROUTE_SSR_RESULTS__ = {};
1335
+ } catch {}
1336
+ }
1337
+ function takeSSRContentResults() {
1338
+ try {
1339
+ const g = globalThis;
1340
+ const results = g.__REROUTE_SSR_RESULTS__;
1341
+ g.__REROUTE_SSR_RESULTS__ = {};
1342
+ return results;
1343
+ } catch {
1344
+ return;
1345
+ }
1346
+ }
1081
1347
  var init_collections = __esm(() => {
1082
1348
  init_imports();
1083
1349
  });
@@ -1252,7 +1518,9 @@ function matchRoutes(routes, pathname) {
1252
1518
  // packages/core/src/ssr/lib/content-path.ts
1253
1519
  var exports_content_path = {};
1254
1520
  __export(exports_content_path, {
1255
- resolveContentPathParts: () => resolveContentPathParts
1521
+ pagePathname: () => pagePathname,
1522
+ resolveContentPathParts: () => resolveContentPathParts,
1523
+ routingPathname: () => routingPathname
1256
1524
  });
1257
1525
  function resolveContentPathParts(pathname) {
1258
1526
  const pathOnly = pathname.split("?")[0].split("#")[0];
@@ -1280,16 +1548,27 @@ function resolveContentPathParts(pathname) {
1280
1548
  name: parts[2],
1281
1549
  locale,
1282
1550
  key: contentKey(parts[0], parts[2], locale, defaultLocale),
1283
- routingPathname: `/${parts[0]}/${parts[2]}`
1551
+ routingPathname: `/${[parts[0], ...parts.slice(2)].join("/")}`
1284
1552
  };
1285
1553
  }
1286
1554
  return {
1287
1555
  collection: parts[0],
1288
1556
  name: parts[1],
1289
1557
  key: `${parts[0]}:${parts[1]}`,
1290
- routingPathname: `/${parts[0]}/${parts[1]}`
1558
+ routingPathname: `/${parts.join("/")}`
1291
1559
  };
1292
1560
  }
1561
+ function pagePathname(pathname) {
1562
+ const pathOnly = pathname.split("?")[0].split("#")[0];
1563
+ const i18n = globalThis.__REROUTE_I18N__;
1564
+ if (!i18n?.prefixPages)
1565
+ return pathOnly;
1566
+ return parseLocalePrefix(pathOnly, i18n.locales || [])?.routingPathname ?? pathOnly;
1567
+ }
1568
+ function routingPathname(pathname) {
1569
+ const page = pagePathname(pathname);
1570
+ return resolveContentPathParts(page)?.routingPathname ?? page;
1571
+ }
1293
1572
  var init_content_path = __esm(() => {
1294
1573
  init_pathname();
1295
1574
  });
@@ -1400,15 +1679,23 @@ var init_content2 = __esm(() => {
1400
1679
  });
1401
1680
 
1402
1681
  // packages/core/src/ssr/lib/layouts.ts
1403
- function getMatchingLayouts(pathname, layouts) {
1682
+ function layoutCovers(pattern, pathname) {
1683
+ const base = pattern.replace(/\/+$/, "");
1684
+ if (base === "")
1685
+ return true;
1686
+ return pathname === base || pathname.startsWith(`${base}/`);
1687
+ }
1688
+ function layoutWraps(layout, pathname, routePattern) {
1689
+ if (Array.isArray(layout?.routes)) {
1690
+ return routePattern !== undefined && layout.routes.includes(routePattern);
1691
+ }
1692
+ return layoutCovers(String(layout?.pattern || "/"), pathname);
1693
+ }
1694
+ function getMatchingLayouts(pathname, layouts, routes) {
1404
1695
  if (!Array.isArray(layouts))
1405
1696
  return [];
1406
- return layouts.filter((layout) => {
1407
- const pattern = String(layout?.pattern || "/");
1408
- if (pattern === "/")
1409
- return true;
1410
- return pathname.startsWith(pattern);
1411
- }).sort((a, b) => {
1697
+ const routePattern = Array.isArray(routes) ? matchRoutes(routes, pathname)?.route.pattern : undefined;
1698
+ return layouts.filter((layout) => layoutWraps(layout, pathname, routePattern)).sort((a, b) => {
1412
1699
  const aDepth = getPatternDepth(a?.pattern);
1413
1700
  const bDepth = getPatternDepth(b?.pattern);
1414
1701
  return aDepth - bDepth;
@@ -1423,6 +1710,7 @@ function createLayoutCacheKey(pattern, pathname) {
1423
1710
  function createLayoutDataKey(pattern) {
1424
1711
  return `__layout:${pattern}`;
1425
1712
  }
1713
+ var init_layouts = () => {};
1426
1714
 
1427
1715
  // packages/core/src/ssr/lib/compute/layouts.ts
1428
1716
  async function loadLayoutSSRExport(layout, clientDir, isWatchMode) {
@@ -1522,7 +1810,8 @@ async function computeLayoutData(pathname, clientDir, _cwd, isWatchMode, options
1522
1810
  const maxAgeMs = maxAge * 1000;
1523
1811
  try {
1524
1812
  const layouts = routesModule?.layouts;
1525
- const matchingLayouts = getMatchingLayouts(pathname, layouts);
1813
+ const routes = routesModule?.routes;
1814
+ const matchingLayouts = getMatchingLayouts(routingPathname(pathname), layouts, routes);
1526
1815
  for (const layout of matchingLayouts) {
1527
1816
  try {
1528
1817
  const layoutStatus = await processLayout(layout, pathname, clientDir, isWatchMode, streaming, maxAgeMs, searchParams, ssrData, pendingTasks, options.headers);
@@ -1549,9 +1838,11 @@ function mergeLayoutData(ssrData, pathname) {
1549
1838
  ssrData[pathname] = layoutData;
1550
1839
  }
1551
1840
  }
1552
- var init_layouts = __esm(() => {
1841
+ var init_layouts2 = __esm(() => {
1553
1842
  init_cache();
1843
+ init_content_path();
1554
1844
  init_imports();
1845
+ init_layouts();
1555
1846
  });
1556
1847
 
1557
1848
  // packages/core/src/ssr/lib/compute/routes.ts
@@ -1594,9 +1885,7 @@ async function computeRouteData(pathname, clientDir, _cwd, isWatchMode, options,
1594
1885
  }).catch(() => {}));
1595
1886
  };
1596
1887
  try {
1597
- const resolved = resolveContentPathParts(pathname);
1598
- const pathnameOnly = (resolved?.routingPathname || pathname).split("?")[0];
1599
- const match = typeof routesModule?.matchRoute === "function" ? routesModule.matchRoute(pathnameOnly) : null;
1888
+ const match = typeof routesModule?.matchRoute === "function" ? routesModule.matchRoute(routingPathname(pathname)) : null;
1600
1889
  const route = match?.route;
1601
1890
  const params = match?.params || {};
1602
1891
  if (!route || typeof route.path !== "string") {
@@ -1801,6 +2090,8 @@ async function computeSSRData(pathname, clientDir, cwd, isWatchMode, options = {
1801
2090
  const statusContainer = { value: undefined };
1802
2091
  const allPendingTasks = [];
1803
2092
  const streaming = options.streaming === true;
2093
+ const layouts = options.only !== "page";
2094
+ const page = options.only !== "layouts";
1804
2095
  const routesModule = await loadRoutesModule(cwd, isWatchMode);
1805
2096
  if (!routesModule) {
1806
2097
  return {
@@ -1809,20 +2100,24 @@ async function computeSSRData(pathname, clientDir, cwd, isWatchMode, options = {
1809
2100
  statusContainer
1810
2101
  };
1811
2102
  }
1812
- try {
1813
- const layoutResult = await computeLayoutData(pathname, clientDir, cwd, isWatchMode, options, searchParams, routesModule, ssrData);
1814
- mergeComputeResult(layoutResult, ssrData, statusContainer, allPendingTasks, streaming);
1815
- } catch {}
1816
- try {
1817
- const contentResult = await computeContentData(pathname, options, searchParams, ssrData);
1818
- error = mergeComputeResult(contentResult, ssrData, statusContainer, allPendingTasks, streaming);
1819
- } catch {}
1820
- try {
1821
- const routeResult = await computeRouteData(pathname, clientDir, cwd, isWatchMode, options, searchParams, routesModule, ssrData);
1822
- const routeError = mergeComputeResult(routeResult, ssrData, statusContainer, allPendingTasks, streaming);
1823
- if (routeError)
1824
- error = routeError;
1825
- } catch {}
2103
+ if (layouts) {
2104
+ try {
2105
+ const layoutResult = await computeLayoutData(pathname, clientDir, cwd, isWatchMode, options, searchParams, routesModule, ssrData);
2106
+ mergeComputeResult(layoutResult, ssrData, statusContainer, allPendingTasks, streaming);
2107
+ } catch {}
2108
+ }
2109
+ if (page) {
2110
+ try {
2111
+ const contentResult = await computeContentData(pathname, options, searchParams, ssrData);
2112
+ error = mergeComputeResult(contentResult, ssrData, statusContainer, allPendingTasks, streaming);
2113
+ } catch {}
2114
+ try {
2115
+ const routeResult = await computeRouteData(pathname, clientDir, cwd, isWatchMode, options, searchParams, routesModule, ssrData);
2116
+ const routeError = mergeComputeResult(routeResult, ssrData, statusContainer, allPendingTasks, streaming);
2117
+ if (routeError)
2118
+ error = routeError;
2119
+ } catch {}
2120
+ }
1826
2121
  if (!streaming) {
1827
2122
  mergeLayoutData(ssrData, pathname);
1828
2123
  }
@@ -1843,15 +2138,15 @@ function setGlobalSSRData(data) {
1843
2138
  var init_compute = __esm(() => {
1844
2139
  init_imports();
1845
2140
  init_content2();
1846
- init_layouts();
2141
+ init_layouts2();
1847
2142
  init_routes();
1848
2143
  init_content2();
1849
- init_layouts();
2144
+ init_layouts2();
1850
2145
  init_routes();
1851
2146
  });
1852
2147
 
1853
2148
  // packages/core/src/ssr/lib/modules.ts
1854
- import { readdir as readdir3, stat as stat3 } from "node:fs/promises";
2149
+ import { readdir as readdir3, stat as stat4 } from "node:fs/promises";
1855
2150
  async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode) {
1856
2151
  try {
1857
2152
  const resolved = resolveContentPathParts(pathname);
@@ -1909,7 +2204,7 @@ async function tryChunkImport(collection, name, cwd, isWatchMode) {
1909
2204
  let latestM = 0;
1910
2205
  for (const f of matches) {
1911
2206
  try {
1912
- const s = await stat3(join(chunkDir, f));
2207
+ const s = await stat4(join(chunkDir, f));
1913
2208
  if (s.mtimeMs >= latestM) {
1914
2209
  latestM = s.mtimeMs;
1915
2210
  latest = f;
@@ -1966,6 +2261,16 @@ function touchModule(key) {
1966
2261
  evictLRUModule();
1967
2262
  }
1968
2263
  }
2264
+ function clearSSRModuleStores() {
2265
+ const g = globalThis;
2266
+ if (g.__REROUTE_SSR_MODULES__) {
2267
+ g.__REROUTE_SSR_MODULES__ = {};
2268
+ }
2269
+ if (g.__REROUTE_SSR_EXPORTS__) {
2270
+ g.__REROUTE_SSR_EXPORTS__ = {};
2271
+ }
2272
+ moduleAccessOrder.length = 0;
2273
+ }
1969
2274
  async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
1970
2275
  try {
1971
2276
  const resolved = resolveContentPathParts(pathname);
@@ -2148,12 +2453,14 @@ async function loadLayoutData(pathname, clientDir, cwd, isWatchMode, searchParam
2148
2453
  const allData = {};
2149
2454
  try {
2150
2455
  let layouts = globalThis.__REROUTE_LAYOUTS__;
2456
+ let routes = globalThis.__REROUTE_ROUTES__;
2151
2457
  if (!layouts) {
2152
2458
  const routesPath = join(cwd, ".reroute", "routes.ts");
2153
2459
  const m = await dynamicImport(routesPath, isWatchMode);
2154
2460
  layouts = m?.layouts;
2461
+ routes = m?.routes;
2155
2462
  }
2156
- const matchingLayouts = getMatchingLayouts(pathname, layouts);
2463
+ const matchingLayouts = getMatchingLayouts(pathname, layouts, routes);
2157
2464
  for (const layout of matchingLayouts) {
2158
2465
  const result = await processLayout2(layout, pathname, clientDir, isWatchMode, searchParams);
2159
2466
  if (result) {
@@ -2175,6 +2482,7 @@ function createLazyMarker(pathname, key) {
2175
2482
  var init_data = __esm(() => {
2176
2483
  init_content_path();
2177
2484
  init_imports();
2485
+ init_layouts();
2178
2486
  init_seed();
2179
2487
  });
2180
2488
 
@@ -2292,6 +2600,11 @@ function deduplicateMetaByProperty(headContent) {
2292
2600
  }
2293
2601
  return result;
2294
2602
  }
2603
+ function markPageHead(head) {
2604
+ return `<!--reroute:head-->${head ? `
2605
+ ${head}
2606
+ ` : ""}<!--/reroute:head-->`;
2607
+ }
2295
2608
  function deduplicateMetaTags(headContent) {
2296
2609
  try {
2297
2610
  let result = headContent;
@@ -2416,11 +2729,20 @@ async function collectOGCandidatePaths(currentDir, parts, depth, pathsToTry, all
2416
2729
  pathsToTry.push(join(currentDir, "[og].tsx"));
2417
2730
  }
2418
2731
  }
2732
+ function ogRoutesDirs(clientDir, appRoutesDir) {
2733
+ const dirs = [join(clientDir, "routes")];
2734
+ if (appRoutesDir && PRODUCTION_CLIENT_DIR.test(clientDir)) {
2735
+ dirs.push(join(clientDir.replace(PRODUCTION_CLIENT_DIR, ""), appRoutesDir));
2736
+ }
2737
+ return dirs;
2738
+ }
2419
2739
  async function findOGImageForPath(pathname, clientDir) {
2420
2740
  const parts = pathname.split("/").filter(Boolean).filter((p) => !p.startsWith("__reroute"));
2421
- const routesDir = join(clientDir, "routes");
2741
+ const appRoutesDir = PRODUCTION_CLIENT_DIR.test(clientDir) ? resolveAppPaths(await loadConfig(clientDir.replace(PRODUCTION_CLIENT_DIR, ""))).routesDir : undefined;
2422
2742
  const pathsToTry = [];
2423
- await collectOGCandidatePaths(routesDir, parts, 0, pathsToTry, true);
2743
+ for (const routesDir of ogRoutesDirs(clientDir, appRoutesDir)) {
2744
+ await collectOGCandidatePaths(routesDir, parts, 0, pathsToTry, true);
2745
+ }
2424
2746
  const uniquePaths = [...new Set(pathsToTry)];
2425
2747
  for (const path of uniquePaths) {
2426
2748
  try {
@@ -2461,10 +2783,13 @@ function extractParamsFromPath(pathname, ogPath, clientDir) {
2461
2783
  }
2462
2784
  return params;
2463
2785
  }
2464
- var CATCH_ALL_ROUTE_DIRECTORY, DYNAMIC_ROUTE_DIRECTORY;
2786
+ var CATCH_ALL_ROUTE_DIRECTORY, DYNAMIC_ROUTE_DIRECTORY, PRODUCTION_CLIENT_DIR;
2465
2787
  var init_discovery2 = __esm(() => {
2788
+ init_app_paths();
2789
+ init_config();
2466
2790
  CATCH_ALL_ROUTE_DIRECTORY = /^\[\.\.\.([^\]]+)\]$/;
2467
2791
  DYNAMIC_ROUTE_DIRECTORY = /^\[(?:\.\.\.)?[^\]]+\]$/;
2792
+ PRODUCTION_CLIENT_DIR = /[\\/]\.reroute[\\/]?$/;
2468
2793
  });
2469
2794
 
2470
2795
  // packages/core/src/og/meta.ts
@@ -2556,9 +2881,8 @@ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, curren
2556
2881
  let perPageHead = "";
2557
2882
  let pageLang;
2558
2883
  let statusOverride = currentStatusOverride;
2559
- const resolved = resolveContentPathParts(pathname);
2560
- const routingPathname = resolved?.routingPathname || pathname;
2561
- await extractLayoutMetadata(routingPathname, clientDir, cwd, isWatchMode, (head) => {
2884
+ const routingPathname2 = routingPathname(pathname);
2885
+ await extractLayoutMetadata(routingPathname2, pathname, clientDir, cwd, isWatchMode, (head) => {
2562
2886
  perPageHead += head;
2563
2887
  }, (lang) => {
2564
2888
  if (!pageLang)
@@ -2594,11 +2918,14 @@ ${ogMetaTags}`;
2594
2918
  }, (lang) => {
2595
2919
  pageLang = lang;
2596
2920
  }, ogConfig, titleSuffix, baseUrl);
2597
- const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname);
2921
+ const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname2);
2598
2922
  perPageHead += routeResult.head;
2599
2923
  if (routeResult.lang)
2600
2924
  pageLang = routeResult.lang;
2601
2925
  statusOverride = routeResult.statusOverride;
2926
+ if (baseUrl && !(statusOverride && statusOverride >= 400)) {
2927
+ perPageHead += pageI18nHead(baseUrl, pathname);
2928
+ }
2602
2929
  return {
2603
2930
  perPageHead,
2604
2931
  pageLang,
@@ -2606,7 +2933,7 @@ ${ogMetaTags}`;
2606
2933
  ssrExport: routeResult.ssrExport
2607
2934
  };
2608
2935
  }
2609
- async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig, titleSuffix) {
2936
+ async function processLayoutForMetadata(layout, requestPathname, clientDir, isWatchMode, addHead, setLang, ogConfig, titleSuffix) {
2610
2937
  if (typeof layout?.path !== "string")
2611
2938
  return;
2612
2939
  try {
@@ -2615,7 +2942,7 @@ async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead,
2615
2942
  if (meta)
2616
2943
  addHead(buildHeadFromMeta(meta, ogConfig, titleSuffix));
2617
2944
  if (ssr) {
2618
- const ssrHead = extractSSRHead(ssr, undefined, ogConfig, undefined, meta, titleSuffix);
2945
+ const ssrHead = extractSSRHead(ssr, requestPathname, undefined, ogConfig, undefined, meta, titleSuffix);
2619
2946
  if (ssrHead)
2620
2947
  addHead(`
2621
2948
  ${ssrHead}`);
@@ -2625,15 +2952,36 @@ ${ssrHead}`);
2625
2952
  }
2626
2953
  } catch {}
2627
2954
  }
2628
- async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang, ogConfig, titleSuffix) {
2955
+ async function extractLayoutMetadata(pathname, requestPathname, clientDir, cwd, isWatchMode, addHead, setLang, ogConfig, titleSuffix) {
2629
2956
  try {
2630
2957
  const m = await loadRoutesModule(cwd, isWatchMode);
2631
- const matchingLayouts = getMatchingLayouts(pathname, m?.layouts);
2958
+ const matchingLayouts = getMatchingLayouts(pathname, m?.layouts, m?.routes);
2632
2959
  for (const layout of matchingLayouts) {
2633
- await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig, titleSuffix);
2960
+ await processLayoutForMetadata(layout, requestPathname, clientDir, isWatchMode, addHead, setLang, ogConfig, titleSuffix);
2634
2961
  }
2635
2962
  } catch {}
2636
2963
  }
2964
+ function readI18n() {
2965
+ return globalThis.__REROUTE_I18N__;
2966
+ }
2967
+ function isContentUrl(i18n, collection) {
2968
+ return !i18n.prefixPages || !!i18n.collections?.includes(collection);
2969
+ }
2970
+ function pageI18nHead(baseUrl, pathname) {
2971
+ const i18n = readI18n();
2972
+ if (!(i18n?.enabled && i18n.prefixPages && i18n.locales))
2973
+ return "";
2974
+ if (i18n.locales.length < 2)
2975
+ return "";
2976
+ const resolved = resolveContentPathParts(pathname);
2977
+ if (resolved && isContentUrl(i18n, resolved.collection))
2978
+ return "";
2979
+ const page = pagePathname(pathname);
2980
+ if (isUnprefixedPath(page, i18n.unprefixedPaths))
2981
+ return "";
2982
+ return `
2983
+ ${pageHreflangTags(baseUrl, page, i18n.locales, i18n.defaultLocale || "en-US")}`;
2984
+ }
2637
2985
  function resolveContentLocales(collection, name, fallbackLocales) {
2638
2986
  const g = globalThis;
2639
2987
  const byCollection = g.__REROUTE_COLLECTIONS__;
@@ -2673,15 +3021,15 @@ function extractContentMetadata(pathname, addHead, setLang, ogConfig, titleSuffi
2673
3021
  const meta = exp?.meta;
2674
3022
  const ssr = exp?.ssr;
2675
3023
  addHead(buildHeadFromMeta(meta, ogConfig, titleSuffix));
2676
- const ssrHead = extractSSRHead(ssr, undefined, ogConfig, undefined, meta, titleSuffix);
3024
+ const ssrHead = extractSSRHead(ssr, pathname, undefined, ogConfig, undefined, meta, titleSuffix);
2677
3025
  if (ssrHead)
2678
3026
  addHead(`
2679
3027
  ${ssrHead}`);
2680
3028
  const lang = extractSSRLang(ssr);
2681
3029
  if (lang)
2682
3030
  setLang(lang);
2683
- const i18n = g.__REROUTE_I18N__;
2684
- if (i18n?.enabled && baseUrl && i18n.locales && i18n.locales.length > 1) {
3031
+ const i18n = readI18n();
3032
+ if (i18n?.enabled && baseUrl && i18n.locales && i18n.locales.length > 1 && isContentUrl(i18n, resolved.collection)) {
2685
3033
  const locales = resolveContentLocales(resolved.collection, resolved.name, i18n.locales);
2686
3034
  addContentI18nHead(addHead, baseUrl, resolved.collection, resolved.name, locales, i18n.defaultLocale || "en-US", i18n.locale || i18n.defaultLocale || "en-US");
2687
3035
  }
@@ -2707,9 +3055,9 @@ function getContentMetaFromExports(pathname) {
2707
3055
  return;
2708
3056
  }
2709
3057
  }
2710
- async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname) {
3058
+ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname2) {
2711
3059
  const pathnameOnly = pathname.split("?")[0];
2712
- const matchPath = (routingPathname || pathname).split("?")[0];
3060
+ const matchPath = (routingPathname2 || pathname).split("?")[0];
2713
3061
  const match = typeof m.matchRoute === "function" ? m.matchRoute(matchPath) : null;
2714
3062
  const r = match?.route;
2715
3063
  if (!r) {
@@ -2734,7 +3082,7 @@ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode,
2734
3082
  }
2735
3083
  const contentMeta = getContentMetaFromExports(pathnameOnly);
2736
3084
  const headMeta = contentMeta || meta;
2737
- const ssrHead = extractSSRHead(ssr, routeData, ogConfig, head, headMeta, titleSuffix);
3085
+ const ssrHead = extractSSRHead(ssr, pathname, routeData, ogConfig, head, headMeta, titleSuffix);
2738
3086
  if (ssrHead)
2739
3087
  head += `
2740
3088
  ${ssrHead}`;
@@ -2750,7 +3098,7 @@ ${ssrHead}`;
2750
3098
  }
2751
3099
  return { head: "", statusOverride };
2752
3100
  }
2753
- async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig, titleSuffix, routingPathname) {
3101
+ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig, titleSuffix, routingPathname2) {
2754
3102
  let head = "";
2755
3103
  let lang;
2756
3104
  let statusOverride = currentStatusOverride;
@@ -2760,14 +3108,14 @@ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, curre
2760
3108
  if (!m) {
2761
3109
  return { head, lang, statusOverride: statusOverride || 404 };
2762
3110
  }
2763
- const matchPath = (routingPathname || pathname).split("?")[0];
3111
+ const matchPath = (routingPathname2 || pathname).split("?")[0];
2764
3112
  const match = typeof m.matchRoute === "function" ? m.matchRoute(matchPath) : null;
2765
3113
  const r = match?.route;
2766
3114
  if (!r) {
2767
3115
  statusOverride = statusOverride || 404;
2768
3116
  }
2769
3117
  if (r && typeof r.path === "string") {
2770
- const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname);
3118
+ const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname2);
2771
3119
  head = result.head;
2772
3120
  lang = result.lang;
2773
3121
  statusOverride = result.statusOverride;
@@ -2807,7 +3155,7 @@ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatc
2807
3155
  const { meta, ssr } = await loadModuleMetaAndSSR(chosen, abs, isWatchMode);
2808
3156
  if (meta)
2809
3157
  head += buildHeadFromMeta(meta, ogConfig, titleSuffix);
2810
- const ssrHead = extractSSRHead(ssr, undefined, ogConfig, undefined, meta, titleSuffix);
3158
+ const ssrHead = extractSSRHead(ssr, pathname, undefined, ogConfig, undefined, meta, titleSuffix);
2811
3159
  if (ssrHead)
2812
3160
  head += `
2813
3161
  ${ssrHead}`;
@@ -2870,13 +3218,17 @@ function generateMissingOGTags(head, ogConfig) {
2870
3218
  ${additionalTags.join(`
2871
3219
  `)}` : "";
2872
3220
  }
2873
- function extractSSRHead(ssr, data, ogConfig, existingHead, meta, titleSuffix) {
3221
+ function extractSSRHead(ssr, pathname, data, ogConfig, existingHead, meta, titleSuffix) {
2874
3222
  if (!ssr)
2875
3223
  return "";
2876
3224
  let headContent = "";
2877
3225
  if (typeof ssr.head === "function") {
2878
3226
  try {
2879
- const result = ssr.head({ data, meta });
3227
+ const result = ssr.head({
3228
+ pathname,
3229
+ data,
3230
+ meta
3231
+ });
2880
3232
  if (typeof result === "string")
2881
3233
  headContent = result;
2882
3234
  else if (Array.isArray(result))
@@ -2947,10 +3299,11 @@ var init_metadata2 = __esm(() => {
2947
3299
  init_compute();
2948
3300
  init_content_path();
2949
3301
  init_imports();
3302
+ init_layouts();
2950
3303
  });
2951
3304
 
2952
3305
  // packages/core/src/ssr/lib/preload.ts
2953
- import { readdir as readdir5, stat as stat4 } from "node:fs/promises";
3306
+ import { readdir as readdir5, readFile, stat as stat5 } from "node:fs/promises";
2954
3307
  async function preloadContentModule(pathname, clientDir, cwd, isWatchMode) {
2955
3308
  let extraHead = "";
2956
3309
  let hydrationScript = "";
@@ -2984,14 +3337,14 @@ async function isContentCollection(clientDir, collection) {
2984
3337
  if (isProduction) {
2985
3338
  const collectionFile = join(clientDir, "collections", `${collection}.js`);
2986
3339
  try {
2987
- const s2 = await stat4(collectionFile);
3340
+ const s2 = await stat5(collectionFile);
2988
3341
  return s2?.isFile() ?? false;
2989
3342
  } catch {
2990
3343
  return false;
2991
3344
  }
2992
3345
  }
2993
3346
  const maybeDir = join(clientDir, "routes", collection, "content");
2994
- const s = await stat4(maybeDir);
3347
+ const s = await stat5(maybeDir);
2995
3348
  return typeof s?.isDirectory === "function" ? s.isDirectory() : true;
2996
3349
  } catch {
2997
3350
  return false;
@@ -3002,7 +3355,7 @@ async function findLatestCandidate(chunkDir, candidates) {
3002
3355
  let latestM = 0;
3003
3356
  for (const candidateName of candidates) {
3004
3357
  try {
3005
- const s = await stat4(join(chunkDir, candidateName));
3358
+ const s = await stat5(join(chunkDir, candidateName));
3006
3359
  if (s.mtimeMs >= latestM) {
3007
3360
  latestM = s.mtimeMs;
3008
3361
  latest = candidateName;
@@ -3053,15 +3406,37 @@ function resetSSRAccessTracking() {
3053
3406
  globalThis.__REROUTE_SSR_ACCESSED__ = {};
3054
3407
  } catch {}
3055
3408
  }
3056
- function createBundlePreload(bundleUrl) {
3409
+ async function bundleImports(cwd, bundleUrl) {
3410
+ const key = `${cwd}:${bundleUrl}`;
3411
+ if (bundleImportsCache?.key === key)
3412
+ return bundleImportsCache.hrefs;
3413
+ const slash = bundleUrl.lastIndexOf("/");
3414
+ const base = bundleUrl.slice(0, slash + 1);
3415
+ const entry = bundleUrl.slice(slash + 1);
3416
+ let hrefs = [];
3417
+ try {
3418
+ const raw = await readFile(bundlePreloadPath(join(cwd, ".reroute", "bundles")), "utf8");
3419
+ const manifest = JSON.parse(raw);
3420
+ if (manifest.entry === entry && Array.isArray(manifest.imports)) {
3421
+ hrefs = manifest.imports.filter((file) => typeof file === "string").map((file) => `${base}${file}`);
3422
+ }
3423
+ } catch {}
3424
+ bundleImportsCache = { key, hrefs };
3425
+ return hrefs;
3426
+ }
3427
+ function createBundlePreload(bundleUrl, imports = []) {
3057
3428
  try {
3058
3429
  if (typeof bundleUrl === "string" && bundleUrl.endsWith(".js")) {
3059
- return `
3060
- <link rel="modulepreload" href="${bundleUrl}" />`;
3430
+ return [bundleUrl, ...imports].map((href) => `
3431
+ <link rel="modulepreload" href="${href}" />`).join("");
3061
3432
  }
3062
3433
  } catch {}
3063
3434
  return "";
3064
3435
  }
3436
+ function bundlePreloadPath(bundlesDir) {
3437
+ return join(bundlesDir, "preload.json");
3438
+ }
3439
+ var bundleImportsCache = null;
3065
3440
  var init_preload = __esm(() => {
3066
3441
  init_imports();
3067
3442
  });
@@ -3188,23 +3563,34 @@ function parseAccessTracking(accessedCollections) {
3188
3563
  }
3189
3564
  return usage;
3190
3565
  }
3191
- function processCollections(accessedCollections, byCollectionForSSR) {
3566
+ function processCapturedResults(capturedResults, byCollectionForSSR) {
3192
3567
  const subset = {};
3193
3568
  const partial = {};
3194
3569
  try {
3195
3570
  const g = globalThis;
3196
- const ssrResults = g.__REROUTE_SSR_RESULTS__;
3197
- if (ssrResults && typeof ssrResults === "object") {
3198
- for (const [collection, items] of Object.entries(ssrResults)) {
3199
- if (Array.isArray(items) && items.length > 0) {
3200
- subset[collection] = items;
3201
- const full = byCollectionForSSR?.[collection] || [];
3202
- partial[collection] = items.length < full.length;
3203
- }
3571
+ const ssrResults = capturedResults ?? g.__REROUTE_SSR_RESULTS__;
3572
+ if (!ssrResults || typeof ssrResults !== "object")
3573
+ return;
3574
+ for (const [collection, items] of Object.entries(ssrResults)) {
3575
+ if (Array.isArray(items) && items.length > 0) {
3576
+ subset[collection] = items;
3577
+ const full = byCollectionForSSR?.[collection] || [];
3578
+ partial[collection] = items.length < full.length;
3204
3579
  }
3205
- return { subset, partial };
3206
3580
  }
3207
- } catch {}
3581
+ } catch {
3582
+ return;
3583
+ }
3584
+ if (Object.keys(subset).length === 0)
3585
+ return;
3586
+ return { subset, partial };
3587
+ }
3588
+ function processCollections(accessedCollections, byCollectionForSSR, capturedResults) {
3589
+ const captured = processCapturedResults(capturedResults, byCollectionForSSR);
3590
+ if (captured)
3591
+ return captured;
3592
+ const subset = {};
3593
+ const partial = {};
3208
3594
  const sortByDate = (order) => (a, b) => {
3209
3595
  const da = a?.meta?.date ? Date.parse(String(a.meta.date)) : 0;
3210
3596
  const db = b?.meta?.date ? Date.parse(String(b.meta.date)) : 0;
@@ -3251,7 +3637,7 @@ function createI18nScript(i18n) {
3251
3637
  }
3252
3638
  }
3253
3639
  function createContentCaptureScript() {
3254
- return `<script>(function(){try{var w=window;w.__REROUTE_INITIAL_HYDRATION__=true;var h={};document.querySelectorAll('[data-reroute-key]').forEach(function(el){var k=el.getAttribute('data-reroute-key');if(k)h[k]=el.innerHTML;});w.__REROUTE_CONTENT_HTML__=h;var r=document.querySelector('[data-reroute-route="ssr"]');if(r)w.__REROUTE_ROUTE_HTML__=r.innerHTML;}catch(e){}})();</script>`;
3640
+ return `<script>(function(){try{var w=window;w.__REROUTE_INITIAL_HYDRATION__=true;var h={};document.querySelectorAll('[data-reroute-key]').forEach(function(el){var k=el.getAttribute('data-reroute-key');if(k)h[k]=el.innerHTML;});w.__REROUTE_CONTENT_HTML__=h;var r=document.querySelector('[data-reroute-route="ssr"]');if(r){w.__REROUTE_ROUTE_HTML__=r.innerHTML;}else{var root=document.getElementById('root');if(root)w.__REROUTE_ROUTE_HTML__=root.innerHTML;}}catch(e){}})();</script>`;
3255
3641
  }
3256
3642
  function createSSRExportsScript(pathname) {
3257
3643
  try {
@@ -3340,7 +3726,8 @@ function createDataScript(ssrData, errorMsg, pathname, browserTelemetryConfig, t
3340
3726
  const duplicatedData = duplicateQueryParamData(ssrData);
3341
3727
  const dataJson = escapeJsonForScript(JSON.stringify(duplicatedData));
3342
3728
  const keysJson = escapeJsonForScript(JSON.stringify(Object.keys(ssrData)));
3343
- script += `<script>(function(){try{var w=(typeof window!=='undefined'?window:globalThis);w.__REROUTE_DATA__=Object.assign({},w.__REROUTE_DATA__||{},${dataJson});try{w.dispatchEvent(new CustomEvent('__reroute_data__',{detail:{keys:${keysJson}}}));}catch(e){}}catch(e){}})();</script>`;
3729
+ const pathJson = escapeJsonForScript(JSON.stringify(pathname ?? null));
3730
+ script += `<script>(function(){try{var w=(typeof window!=='undefined'?window:globalThis);var d=Object.assign({},${dataJson});var k=${keysJson};var p=${pathJson};var h=Object.prototype.hasOwnProperty;var s=w.location?w.location.search:'';if(p?(s?(h.call(d,p)?!h.call(d,p+s):false):false):false){d[p+s]=d[p];k.push(p+s);}w.__REROUTE_DATA__=Object.assign({},w.__REROUTE_DATA__||{},d);try{w.dispatchEvent(new CustomEvent('__reroute_data__',{detail:{keys:k}}));}catch(e){}}catch(e){}})();</script>`;
3344
3731
  } catch (error) {
3345
3732
  console.error("[reroute] Failed to serialize SSR data:", error);
3346
3733
  }
@@ -3388,43 +3775,69 @@ var init_scripts = __esm(() => {
3388
3775
  });
3389
3776
 
3390
3777
  // packages/core/src/ssr/lib/styles.ts
3391
- async function inlineThemeCSS(clientDir, minify = false, isWatchMode = false) {
3778
+ import { createHash } from "node:crypto";
3779
+ import { readdirSync } from "node:fs";
3780
+ import { resolve } from "node:path";
3781
+ function themeCssHash(css) {
3782
+ return createHash("sha1").update(css).digest("hex").slice(0, 8);
3783
+ }
3784
+ function themeCssFileName(css) {
3785
+ return `index.${themeCssHash(css)}.css`;
3786
+ }
3787
+ function themeLink(href) {
3788
+ return `<link rel="stylesheet" href="${href}" data-reroute="theme">`;
3789
+ }
3790
+ function bundlesDirs(clientDir) {
3791
+ return [1, 2, 3, 4].map((levels) => resolve(clientDir, ...Array(levels).fill(".."), ".reroute", "bundles"));
3792
+ }
3793
+ async function readFileIfExists(path) {
3794
+ if (!await Bun.file(path).exists())
3795
+ return "";
3796
+ const { readFileSync } = await import("node:fs");
3797
+ return readFileSync(path, "utf-8");
3798
+ }
3799
+ async function readThemeFromBundles(clientDir) {
3800
+ for (const dir of bundlesDirs(clientDir)) {
3801
+ try {
3802
+ const hashed = readdirSync(dir).find((name) => HASHED_THEME_RE.test(name));
3803
+ if (hashed) {
3804
+ const css2 = await readFileIfExists(join(dir, hashed));
3805
+ if (css2)
3806
+ return { css: css2, href: `/bundles/${hashed}` };
3807
+ }
3808
+ const css = await readFileIfExists(join(dir, "index.css"));
3809
+ if (css)
3810
+ return { css, href: `/bundles/${themeCssFileName(css)}` };
3811
+ } catch {}
3812
+ }
3813
+ return null;
3814
+ }
3815
+ function bundledThemeCss() {
3816
+ return globalThis.__REROUTE_THEME_CSS__ || "";
3817
+ }
3818
+ async function inlineThemeCSS(clientDir, isWatchMode = false) {
3392
3819
  try {
3393
- const bundledCss = globalThis.__REROUTE_THEME_CSS__;
3394
- if (bundledCss) {
3395
- const css2 = minify ? minifyCSS(bundledCss) : bundledCss;
3396
- return `<style data-reroute="theme">${css2}</style>`;
3397
- }
3398
3820
  if (isWatchMode) {
3399
- const timestamp = Date.now();
3400
- return `<link rel="stylesheet" href="/.reroute/index.css?t=${timestamp}" data-reroute="theme">`;
3401
- }
3402
- const candidates = [
3403
- join(clientDir, "..", ".reroute", "index.css"),
3404
- join(clientDir, "..", "..", ".reroute", "index.css"),
3405
- join(clientDir, "..", "..", "..", ".reroute", "index.css"),
3406
- join(clientDir, "..", "..", "..", "..", ".reroute", "index.css")
3407
- ];
3408
- let cssPath = "";
3409
- for (const p of candidates) {
3410
- if (await Bun.file(p).exists()) {
3411
- cssPath = p;
3412
- break;
3413
- }
3821
+ return themeLink(`${THEME_CSS_WATCH_HREF}?t=${Date.now()}`);
3414
3822
  }
3415
- if (!cssPath)
3823
+ const fromDisk = await readThemeFromBundles(clientDir);
3824
+ const css = bundledThemeCss() || fromDisk?.css;
3825
+ if (!css)
3416
3826
  return "";
3417
- const { readFileSync } = await import("node:fs");
3418
- const css = readFileSync(cssPath, "utf-8");
3419
- return `<style data-reroute="theme">${minifyCSS(css)}</style>`;
3827
+ if (bundledThemeCss()) {
3828
+ return themeLink(`/bundles/${themeCssFileName(css)}`);
3829
+ }
3830
+ if (fromDisk)
3831
+ return themeLink(fromDisk.href);
3832
+ return "";
3420
3833
  } catch {
3421
3834
  return "";
3422
3835
  }
3423
3836
  }
3424
- function minifyCSS(css) {
3425
- return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/\s*([{}:;,>+~])\s*/g, "$1").replace(/;}/g, "}").trim();
3426
- }
3427
- var init_styles = () => {};
3837
+ var THEME_CSS_WATCH_HREF = "/bundles/index.css", HASHED_THEME_RE;
3838
+ var init_styles = __esm(() => {
3839
+ HASHED_THEME_RE = /^index\.[a-z0-9]{8,}\.css$/i;
3840
+ });
3428
3841
 
3429
3842
  // packages/core/src/ssr/lib/setup.ts
3430
3843
  async function performSSRSetup(options, streaming = false) {
@@ -3493,7 +3906,8 @@ async function performSSRSetupInternal(options, streaming, timeoutState) {
3493
3906
  });
3494
3907
  assertNotTimedOut();
3495
3908
  resetSSRAccessTracking();
3496
- const bundlePreload = createBundlePreload(bundleUrl);
3909
+ resetSSRContentResults();
3910
+ const bundlePreload = createBundlePreload(bundleUrl, await bundleImports(cwd, bundleUrl));
3497
3911
  const preloadResult = await withSpan("ssr.preload", async (span) => {
3498
3912
  span.setAttribute("pathname", pathname);
3499
3913
  const result = await preloadContentModule(pathname, clientDir, cwd, isWatchMode);
@@ -3529,7 +3943,7 @@ async function performSSRSetupInternal(options, streaming, timeoutState) {
3529
3943
  setGlobalCollections(byCollectionForSSR);
3530
3944
  const usingCachedCSS = !!options.cachedThemeCSS;
3531
3945
  const inlineStyleTag = await withSpan("ssr.inline.css", async (span) => {
3532
- const css = options.cachedThemeCSS ? options.cachedThemeCSS : await inlineThemeCSS(clientDir, !streaming, isWatchMode);
3946
+ const css = options.cachedThemeCSS ? options.cachedThemeCSS : await inlineThemeCSS(clientDir, isWatchMode);
3533
3947
  span.setAttributes({
3534
3948
  "reroute.cached": usingCachedCSS,
3535
3949
  "reroute.css.size": css.length
@@ -3568,12 +3982,12 @@ async function performSSRSetupInternal(options, streaming, timeoutState) {
3568
3982
  pending: computeResult.pending
3569
3983
  };
3570
3984
  }
3571
- function generateCollectionScripts(byCollectionForSSR) {
3985
+ function generateCollectionScripts(byCollectionForSSR, capturedResults) {
3572
3986
  try {
3573
3987
  const g = globalThis;
3574
3988
  const acc = g.__REROUTE_SSR_ACCESSED__;
3575
3989
  if (acc) {
3576
- const { subset, partial } = processCollections(acc, byCollectionForSSR);
3990
+ const { subset, partial } = processCollections(acc, byCollectionForSSR, capturedResults);
3577
3991
  if (Object.keys(subset).length > 0) {
3578
3992
  return createCollectionScript(subset, partial);
3579
3993
  }
@@ -3632,6 +4046,7 @@ var init_lib = __esm(() => {
3632
4046
  init_compute();
3633
4047
  init_html();
3634
4048
  init_imports();
4049
+ init_layouts();
3635
4050
  init_metadata2();
3636
4051
  init_modules();
3637
4052
  init_preload();
@@ -3725,13 +4140,16 @@ async function renderSSRDocument(options) {
3725
4140
  }, false);
3726
4141
  const duplicatedData = duplicateQueryParamData(setup2.ssrData);
3727
4142
  setGlobalSSRData(duplicatedData);
4143
+ let capturedResults;
3728
4144
  const appHtml = await withSpan("ssr.render.react", async (span) => {
3729
4145
  const componentWithPathname = cloneElement(rootComponent, {
3730
4146
  pathname,
3731
4147
  searchParams
3732
4148
  });
3733
4149
  span.setAttribute("reroute.pathname", pathname);
4150
+ resetSSRContentResults();
3734
4151
  const html3 = renderToString(componentWithPathname);
4152
+ capturedResults = takeSSRContentResults();
3735
4153
  span.setAttribute("reroute.html.final.size", html3.length);
3736
4154
  return html3;
3737
4155
  });
@@ -3740,7 +4158,7 @@ async function renderSSRDocument(options) {
3740
4158
  span.setAttribute("reroute.template.size", template2.length);
3741
4159
  return template2;
3742
4160
  });
3743
- const collectionScripts = generateCollectionScripts(setup2.byCollectionForSSR);
4161
+ const collectionScripts = generateCollectionScripts(setup2.byCollectionForSSR, capturedResults);
3744
4162
  const config = await loadConfig(cwd);
3745
4163
  const browserTelemetryConfigRaw = config.telemetry?.browser;
3746
4164
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
@@ -3758,11 +4176,11 @@ async function renderSSRDocument(options) {
3758
4176
  if (setup2.metadataResult.statusOverride !== undefined) {
3759
4177
  statusOverride = setup2.metadataResult.statusOverride;
3760
4178
  }
3761
- const extraHead = setup2.bundlePreload + setup2.preloadExtraHead;
4179
+ const extraHead = appendLlmsAlternateHead(setup2.bundlePreload + setup2.preloadExtraHead, pathname, statusOverride || 200, config.llms);
3762
4180
  const combinedHead = dedent([
3763
4181
  dedent(head) || "",
3764
4182
  dedent(extraHead),
3765
- dedent(setup2.metadataResult.perPageHead)
4183
+ markPageHead(dedent(setup2.metadataResult.perPageHead))
3766
4184
  ].filter(Boolean).join(`
3767
4185
  `));
3768
4186
  const i18nLocale = options.i18n?.enabled ? String(options.i18n.locale || "") : "";
@@ -3788,14 +4206,24 @@ async function renderSSRDocument(options) {
3788
4206
  var init_render = __esm(() => {
3789
4207
  init_server2();
3790
4208
  init_config();
4209
+ init_discovery3();
3791
4210
  init_lib();
3792
4211
  init_html();
3793
4212
  });
3794
4213
 
3795
4214
  // packages/core/src/llms/formatter.ts
4215
+ function leadingTitleLine(text) {
4216
+ const first = text.trimStart().split(/\r?\n/, 1)[0]?.trim();
4217
+ if (!first)
4218
+ return;
4219
+ return first.replace(/^#\s+/, "").trim();
4220
+ }
4221
+ function hasLeadingTitle(text, title) {
4222
+ return leadingTitleLine(text) === title.trim();
4223
+ }
3796
4224
  function formatAsText(content) {
3797
4225
  const parts = [];
3798
- if (content.title) {
4226
+ if (content.title && !hasLeadingTitle(content.body, content.title)) {
3799
4227
  parts.push(content.title);
3800
4228
  parts.push("");
3801
4229
  }
@@ -3805,7 +4233,7 @@ function formatAsText(content) {
3805
4233
  }
3806
4234
  function formatAsMarkdown(content) {
3807
4235
  const parts = [];
3808
- if (content.title) {
4236
+ if (content.title && !hasLeadingTitle(content.markdown, content.title)) {
3809
4237
  parts.push(`# ${content.title}`);
3810
4238
  parts.push("");
3811
4239
  }
@@ -3934,6 +4362,9 @@ Formats: .txt | .md | Accept: text/plain | Accept: text/markdown`;
3934
4362
  // packages/core/src/llms/extractor.ts
3935
4363
  import { pathToFileURL as pathToFileURL5 } from "node:url";
3936
4364
  import { renderToStaticMarkup } from "react-dom/server";
4365
+ function stripLayoutChrome(html2) {
4366
+ return html2.replace(/<nav[\s\S]*?<\/nav>/gi, "").replace(/<header[\s\S]*?<\/header>/gi, "").replace(/<aside[\s\S]*?<\/aside>/gi, "");
4367
+ }
3937
4368
  function shouldExcludeRoute(pathname, excludeRoutes) {
3938
4369
  if (!excludeRoutes || excludeRoutes.length === 0) {
3939
4370
  return false;
@@ -4056,10 +4487,7 @@ async function extractSSRContent(pathname, rootComponent, clientDir, cwd, isWatc
4056
4487
  if (appDivMatch) {
4057
4488
  contentHtml = appDivMatch[1];
4058
4489
  }
4059
- contentHtml = contentHtml.replace(/<nav[\s\S]*?<\/nav>/gi, "");
4060
- contentHtml = contentHtml.replace(/<footer[\s\S]*?<\/footer>/gi, "");
4061
- contentHtml = contentHtml.replace(/<header[\s\S]*?<\/header>/gi, "");
4062
- contentHtml = contentHtml.replace(/<aside[\s\S]*?<\/aside>/gi, "");
4490
+ contentHtml = stripLayoutChrome(contentHtml);
4063
4491
  return {
4064
4492
  title: extractTitle(html2),
4065
4493
  body: stripHtmlTags(contentHtml),
@@ -4092,37 +4520,154 @@ async function extractContentForLLMs(options) {
4092
4520
  throw new Error("Content not found");
4093
4521
  }
4094
4522
  if (format === "md") {
4095
- const parts2 = [];
4096
- if (content.title) {
4097
- parts2.push(`# ${content.title}`);
4098
- parts2.push("");
4099
- }
4100
- parts2.push(content.markdown);
4101
- return parts2.join(`
4102
- `);
4103
- }
4104
- const parts = [];
4105
- if (content.title) {
4106
- parts.push(content.title);
4107
- parts.push("");
4523
+ return formatAsMarkdown({
4524
+ title: content.title,
4525
+ markdown: content.markdown
4526
+ });
4108
4527
  }
4109
- parts.push(content.body);
4110
- return parts.join(`
4111
- `);
4528
+ return formatAsText({
4529
+ title: content.title,
4530
+ body: content.body
4531
+ });
4112
4532
  }
4113
4533
  var init_extractor = __esm(() => {
4114
4534
  init_render();
4115
4535
  });
4116
4536
 
4537
+ // packages/core/src/llms/discovery.ts
4538
+ function yesNo(value) {
4539
+ return value === false ? "no" : "yes";
4540
+ }
4541
+ function formatContentSignal(policy, whenUndefined = "omit") {
4542
+ if (policy === false)
4543
+ return;
4544
+ if (policy === undefined && whenUndefined === "omit")
4545
+ return;
4546
+ const resolved = {
4547
+ search: true,
4548
+ aiInput: true,
4549
+ aiTrain: true,
4550
+ ...policy
4551
+ };
4552
+ return `ai-train=${yesNo(resolved.aiTrain)}, search=${yesNo(resolved.search)}, ai-input=${yesNo(resolved.aiInput)}`;
4553
+ }
4554
+ function markdownTwinPath(pathname) {
4555
+ const path2 = pathname.split("?")[0];
4556
+ if (path2 === "/" || path2 === "")
4557
+ return "/index.md";
4558
+ return `${path2.replace(/\/$/, "")}.md`;
4559
+ }
4560
+ function shouldAdvertiseMarkdownTwin(pathname, llmsConfig) {
4561
+ if (!llmsConfig?.enabled)
4562
+ return false;
4563
+ if (llmsConfig.enableMarkdownExtension === false)
4564
+ return false;
4565
+ if (shouldExcludeRoute(pathname, llmsConfig.excludeRoutes))
4566
+ return false;
4567
+ return true;
4568
+ }
4569
+ function llmsAlternateLinkTag(pathname, llmsConfig) {
4570
+ if (!shouldAdvertiseMarkdownTwin(pathname, llmsConfig))
4571
+ return "";
4572
+ return `<link rel="alternate" type="text/markdown" href="${markdownTwinPath(pathname)}" />`;
4573
+ }
4574
+ function mergeVary(existing, token) {
4575
+ const parts = (existing ?? "").split(",").map((part) => part.trim()).filter(Boolean);
4576
+ if (!parts.some((part) => part.toLowerCase() === token.toLowerCase())) {
4577
+ parts.push(token);
4578
+ }
4579
+ return parts.join(", ");
4580
+ }
4581
+ function appendLinkValues(existing, values) {
4582
+ const current = (existing ?? "").split(",").map((part) => part.trim()).filter(Boolean);
4583
+ for (const value of values) {
4584
+ if (!current.includes(value))
4585
+ current.push(value);
4586
+ }
4587
+ return current.join(", ");
4588
+ }
4589
+ function buildLlmsDiscovery(pathname, llmsConfig) {
4590
+ if (!llmsConfig?.enabled)
4591
+ return null;
4592
+ const linkValues = [];
4593
+ if (shouldAdvertiseMarkdownTwin(pathname, llmsConfig)) {
4594
+ linkValues.push(`<${markdownTwinPath(pathname)}>; rel="alternate"; type="text/markdown"`);
4595
+ }
4596
+ if (llmsConfig.enableIndex !== false) {
4597
+ linkValues.push('</llms.txt>; rel="llms-txt"');
4598
+ }
4599
+ const contentSignal = formatContentSignal(llmsConfig.contentSignal, "default");
4600
+ const vary = llmsConfig.enableContentNegotiation !== false ? "Accept" : undefined;
4601
+ if (linkValues.length === 0 && !contentSignal && !vary)
4602
+ return null;
4603
+ return { linkValues, contentSignal, vary };
4604
+ }
4605
+ function writeHeader(headers2, canonical, value) {
4606
+ const lower = canonical.toLowerCase();
4607
+ if (headers2[lower] !== undefined)
4608
+ headers2[lower] = value;
4609
+ if (headers2[canonical] !== undefined || headers2[lower] === undefined) {
4610
+ headers2[canonical] = value;
4611
+ }
4612
+ }
4613
+ function readHeader(headers2, canonical) {
4614
+ return headers2[canonical] ?? headers2[canonical.toLowerCase()];
4615
+ }
4616
+ function applyLlmsDiscoveryHeaders(headers2, pathname, llmsConfig, status = 200) {
4617
+ if (status < 200 || status >= 300)
4618
+ return;
4619
+ const discovery2 = buildLlmsDiscovery(pathname, llmsConfig);
4620
+ if (!discovery2)
4621
+ return;
4622
+ if (discovery2.linkValues.length > 0) {
4623
+ writeHeader(headers2, "Link", appendLinkValues(readHeader(headers2, "Link"), discovery2.linkValues));
4624
+ }
4625
+ if (discovery2.contentSignal) {
4626
+ writeHeader(headers2, "Content-Signal", discovery2.contentSignal);
4627
+ }
4628
+ if (discovery2.vary) {
4629
+ writeHeader(headers2, "Vary", mergeVary(readHeader(headers2, "Vary"), discovery2.vary));
4630
+ }
4631
+ }
4632
+ function appendLlmsAlternateHead(extraHead, pathname, status, llmsConfig) {
4633
+ if (status !== 200)
4634
+ return extraHead;
4635
+ const tag = llmsAlternateLinkTag(pathname, llmsConfig);
4636
+ return tag ? `${extraHead}
4637
+ ${tag}` : extraHead;
4638
+ }
4639
+ var init_discovery3 = __esm(() => {
4640
+ init_extractor();
4641
+ });
4642
+
4117
4643
  // packages/core/src/llms/index-generator.ts
4118
4644
  var exports_index_generator = {};
4119
4645
  __export(exports_index_generator, {
4120
- generateLLMsIndex: () => generateLLMsIndex,
4121
- discoverStaticRoutes: () => discoverStaticRoutes,
4646
+ discoverCollectionRoutes: () => discoverCollectionRoutes,
4122
4647
  discoverSSRDataRoutes: () => discoverSSRDataRoutes,
4123
- discoverCollectionRoutes: () => discoverCollectionRoutes
4648
+ discoverStaticRoutes: () => discoverStaticRoutes,
4649
+ generateLLMsIndex: () => generateLLMsIndex
4124
4650
  });
4125
4651
  import { pathToFileURL as pathToFileURL6 } from "node:url";
4652
+ function oneLine(value) {
4653
+ return value.replace(/\s+/g, " ").trim();
4654
+ }
4655
+ function stringField(record, key) {
4656
+ const value = record?.[key];
4657
+ if (typeof value !== "string")
4658
+ return;
4659
+ const trimmed = oneLine(value);
4660
+ return trimmed.length > 0 ? trimmed : undefined;
4661
+ }
4662
+ function metaFromUnknown(meta) {
4663
+ if (!meta || typeof meta !== "object")
4664
+ return {};
4665
+ const record = meta;
4666
+ return {
4667
+ title: stringField(record, "title") ?? stringField(record, "name"),
4668
+ description: stringField(record, "description") ?? stringField(record, "excerpt")
4669
+ };
4670
+ }
4126
4671
  async function discoverStaticRoutes(cwd, isWatchMode) {
4127
4672
  const routes = [];
4128
4673
  try {
@@ -4139,8 +4684,11 @@ async function discoverStaticRoutes(cwd, isWatchMode) {
4139
4684
  if (pattern.includes("[404]") || pattern.includes("[layout]") || pattern.includes("[skeleton]") || pattern.includes(":")) {
4140
4685
  continue;
4141
4686
  }
4687
+ const { title, description } = metaFromUnknown(route?.meta);
4142
4688
  routes.push({
4143
- path: pattern
4689
+ path: pattern,
4690
+ title,
4691
+ description
4144
4692
  });
4145
4693
  }
4146
4694
  }
@@ -4163,11 +4711,13 @@ function createRouteEntriesFromItems(items, collection) {
4163
4711
  for (const item of items) {
4164
4712
  const href = String(item.href || "");
4165
4713
  if (href) {
4166
- const title = item.meta?.title || item.meta?.name || item.name;
4714
+ const fromMeta = metaFromUnknown(item.meta);
4715
+ const title = fromMeta.title || (typeof item.name === "string" ? item.name : undefined);
4167
4716
  routes.push({
4168
4717
  path: href,
4169
4718
  section: collection,
4170
- title
4719
+ title,
4720
+ description: fromMeta.description
4171
4721
  });
4172
4722
  }
4173
4723
  }
@@ -4208,7 +4758,7 @@ async function discoverCollectionRoutes(cwd, collections2, isWatchMode, llmsConf
4208
4758
  }
4209
4759
  async function loadRouteModule(cwd, routePath, isWatchMode) {
4210
4760
  try {
4211
- const abs = join(cwd, "src", "client", "routes", routePath);
4761
+ const abs = join(cwd, resolveAppPaths(await loadConfig(cwd)).routesDir, routePath);
4212
4762
  const modUrl = `${pathToFileURL6(abs).href}${isWatchMode ? `?t=${Date.now()}` : ""}`;
4213
4763
  return await import(modUrl);
4214
4764
  } catch {
@@ -4233,9 +4783,13 @@ function createEntriesFromArray(array, routePath) {
4233
4783
  continue;
4234
4784
  const identifier = extractIdentifier(item);
4235
4785
  if (identifier) {
4786
+ const fromItem = metaFromUnknown(item);
4787
+ const fromMeta = metaFromUnknown(item.meta);
4236
4788
  entries.push({
4237
4789
  path: `${routePath}/${identifier}`,
4238
- section: routePath.split("/").filter(Boolean)[0]
4790
+ section: routePath.split("/").filter(Boolean)[0],
4791
+ title: fromItem.title ?? fromMeta.title,
4792
+ description: fromItem.description ?? fromMeta.description
4239
4793
  });
4240
4794
  }
4241
4795
  }
@@ -4341,13 +4895,21 @@ function formatRouteUrl(routePath, baseUrl) {
4341
4895
  function getRouteTitle(route) {
4342
4896
  return route.title || (route.path === "/" ? "Home" : route.path.split("/").pop() || "Page");
4343
4897
  }
4344
- function addRootRoutes(parts, rootRoutes, baseUrl, isSingleCollection) {
4345
- if (isSingleCollection || rootRoutes.length === 0)
4898
+ function formatIndexLine(route, url, summaries) {
4899
+ const link = `- [${getRouteTitle(route)}](${url})`;
4900
+ if (!(summaries && route.description))
4901
+ return link;
4902
+ return `${link}: ${route.description}`;
4903
+ }
4904
+ function summariesEnabled(llmsConfig) {
4905
+ return llmsConfig?.indexSummaries !== false;
4906
+ }
4907
+ function addRootRoutes(parts, rootRoutes, baseUrl, isScoped, llmsConfig) {
4908
+ if (isScoped || rootRoutes.length === 0)
4346
4909
  return;
4910
+ const summaries = summariesEnabled(llmsConfig);
4347
4911
  for (const route of rootRoutes) {
4348
- const title = getRouteTitle(route);
4349
- const url = formatRouteUrl(route.path, baseUrl);
4350
- parts.push(`- [${title}](${url})`);
4912
+ parts.push(formatIndexLine(route, formatRouteUrl(route.path, baseUrl), summaries));
4351
4913
  }
4352
4914
  parts.push("");
4353
4915
  }
@@ -4358,19 +4920,18 @@ function addCollectionSection(parts, collection, routes, baseUrl, llmsConfig) {
4358
4920
  const sectionName = collection.charAt(0).toUpperCase() + collection.slice(1);
4359
4921
  parts.push(`## ${sectionName}`);
4360
4922
  parts.push("");
4923
+ const summaries = summariesEnabled(llmsConfig);
4361
4924
  for (const route of filteredRoutes) {
4362
- const title = route.title || route.path.split("/").pop() || "Untitled";
4363
- const url = `${baseUrl}${route.path}.txt`;
4364
- parts.push(`- [${title}](${url})`);
4925
+ parts.push(formatIndexLine(route, `${baseUrl}${route.path}.txt`, summaries));
4365
4926
  }
4366
4927
  parts.push("");
4367
4928
  }
4368
- function shouldIncludeSection(section, isSingleCollection, targetCollection) {
4369
- return !isSingleCollection || section === targetCollection;
4929
+ function shouldIncludeSection(section, isScoped, targetCollection) {
4930
+ return !isScoped || section === targetCollection;
4370
4931
  }
4371
- function addSSRDataSection(parts, routePattern, routes, baseUrl, isSingleCollection, targetCollection, llmsConfig) {
4932
+ function addSSRDataSection(parts, routePattern, routes, baseUrl, isScoped, targetCollection, llmsConfig) {
4372
4933
  const routeSection = routePattern.split("/").filter(Boolean)[0];
4373
- if (!shouldIncludeSection(routeSection, isSingleCollection, targetCollection)) {
4934
+ if (!shouldIncludeSection(routeSection, isScoped, targetCollection)) {
4374
4935
  return;
4375
4936
  }
4376
4937
  const filteredRoutes = routes.filter((r) => !shouldExcludeRoute(r.path, llmsConfig?.excludeRoutes));
@@ -4379,15 +4940,14 @@ function addSSRDataSection(parts, routePattern, routes, baseUrl, isSingleCollect
4379
4940
  const sectionName = routeSection?.charAt(0).toUpperCase() + routeSection?.slice(1) || "Content";
4380
4941
  parts.push(`## ${sectionName}`);
4381
4942
  parts.push("");
4943
+ const summaries = summariesEnabled(llmsConfig);
4382
4944
  for (const route of filteredRoutes) {
4383
- const title = route.title || route.path.split("/").pop() || "Untitled";
4384
- const url = `${baseUrl}${route.path}.txt`;
4385
- parts.push(`- [${title}](${url})`);
4945
+ parts.push(formatIndexLine(route, `${baseUrl}${route.path}.txt`, summaries));
4386
4946
  }
4387
4947
  parts.push("");
4388
4948
  }
4389
- function addStaticSection(parts, section, routes, baseUrl, isSingleCollection, targetCollection, collectionsMap, llmsConfig) {
4390
- if (!shouldIncludeSection(section, isSingleCollection, targetCollection)) {
4949
+ function addStaticSection(parts, section, routes, baseUrl, isScoped, targetCollection, collectionsMap, llmsConfig) {
4950
+ if (!shouldIncludeSection(section, isScoped, targetCollection)) {
4391
4951
  return;
4392
4952
  }
4393
4953
  const filteredRoutes = routes.filter((r) => !shouldExcludeRoute(r.path, llmsConfig?.excludeRoutes));
@@ -4396,24 +4956,23 @@ function addStaticSection(parts, section, routes, baseUrl, isSingleCollection, t
4396
4956
  const sectionName = section.charAt(0).toUpperCase() + section.slice(1);
4397
4957
  parts.push(`## ${sectionName}`);
4398
4958
  parts.push("");
4959
+ const summaries = summariesEnabled(llmsConfig);
4399
4960
  for (const route of filteredRoutes) {
4400
- const title = route.title || route.path.split("/").pop() || "Untitled";
4401
- const url = `${baseUrl}${route.path}.txt`;
4402
- parts.push(`- [${title}](${url})`);
4961
+ parts.push(formatIndexLine(route, `${baseUrl}${route.path}.txt`, summaries));
4403
4962
  }
4404
4963
  parts.push("");
4405
4964
  }
4406
4965
  async function generateLLMsIndex(options) {
4407
4966
  const { cwd, collections: collections2, baseUrl, isWatchMode, llmsConfig } = options;
4967
+ const targetCollection = options.targetCollection ?? null;
4968
+ const isScoped = targetCollection !== null;
4408
4969
  const parts = [];
4409
4970
  addIndexHeader(parts, llmsConfig);
4410
4971
  const staticRoutes = await discoverStaticRoutes(cwd, isWatchMode);
4411
4972
  const collectionsMap = await discoverCollectionRoutes(cwd, collections2, isWatchMode, llmsConfig);
4412
4973
  const ssrDataRoutes = await discoverSSRDataRoutes(cwd, staticRoutes, isWatchMode);
4413
- const isSingleCollection = collections2.length === 1;
4414
- const targetCollection = isSingleCollection ? collections2[0] : null;
4415
4974
  const { sections, rootRoutes } = groupStaticRoutes(staticRoutes, llmsConfig);
4416
- addRootRoutes(parts, rootRoutes, baseUrl, isSingleCollection);
4975
+ addRootRoutes(parts, rootRoutes, baseUrl, isScoped, llmsConfig);
4417
4976
  for (const [collection, routes] of collectionsMap.entries()) {
4418
4977
  if (routes.length > 0) {
4419
4978
  addCollectionSection(parts, collection, routes, baseUrl, llmsConfig);
@@ -4421,12 +4980,12 @@ async function generateLLMsIndex(options) {
4421
4980
  }
4422
4981
  for (const [routePattern, routes] of ssrDataRoutes.entries()) {
4423
4982
  if (routes.length > 0) {
4424
- addSSRDataSection(parts, routePattern, routes, baseUrl, isSingleCollection, targetCollection, llmsConfig);
4983
+ addSSRDataSection(parts, routePattern, routes, baseUrl, isScoped, targetCollection, llmsConfig);
4425
4984
  }
4426
4985
  }
4427
4986
  for (const [section, routes] of sections.entries()) {
4428
4987
  if (routes.length > 0) {
4429
- addStaticSection(parts, section, routes, baseUrl, isSingleCollection, targetCollection, collectionsMap, llmsConfig);
4988
+ addStaticSection(parts, section, routes, baseUrl, isScoped, targetCollection, collectionsMap, llmsConfig);
4430
4989
  }
4431
4990
  }
4432
4991
  parts.push("---");
@@ -4436,6 +4995,8 @@ async function generateLLMsIndex(options) {
4436
4995
  `);
4437
4996
  }
4438
4997
  var init_index_generator = __esm(() => {
4998
+ init_app_paths();
4999
+ init_config();
4439
5000
  init_extractor();
4440
5001
  });
4441
5002
 
@@ -4489,6 +5050,9 @@ async function discoverAllRoutes(cwd, collections2, isWatchMode, llmsConfig) {
4489
5050
  }
4490
5051
  return allRoutes;
4491
5052
  }
5053
+ function routeBelongsToCollection(path2, collection) {
5054
+ return path2 === `/${collection}` || path2.startsWith(`/${collection}/`);
5055
+ }
4492
5056
  function formatContentBlock(content, routePath, baseUrl) {
4493
5057
  const parts = [];
4494
5058
  const lines = content.split(`
@@ -4558,7 +5122,9 @@ function buildFooter(parts) {
4558
5122
  async function generateLLMsFullContent(options) {
4559
5123
  const { cwd, collections: collections2, baseUrl, isWatchMode, llmsConfig } = options;
4560
5124
  const parts = buildHeader(baseUrl, llmsConfig);
4561
- const allRoutes = await discoverAllRoutes(cwd, collections2, isWatchMode, llmsConfig);
5125
+ const discovered = await discoverAllRoutes(cwd, collections2, isWatchMode, llmsConfig);
5126
+ const targetCollection = options.targetCollection;
5127
+ const allRoutes = targetCollection ? discovered.filter((route) => routeBelongsToCollection(route.path, targetCollection)) : discovered;
4562
5128
  const maxItems = llmsConfig?.maxItems || 1e4;
4563
5129
  const routesToProcess = allRoutes.slice(0, maxItems);
4564
5130
  const extracted = await extractRouteContents(routesToProcess, options);
@@ -4578,6 +5144,7 @@ var init_full_generator = __esm(() => {
4578
5144
 
4579
5145
  // packages/core/src/llms/index.ts
4580
5146
  var init_llms = __esm(() => {
5147
+ init_discovery3();
4581
5148
  init_extractor();
4582
5149
  init_full_generator();
4583
5150
  init_index_generator();
@@ -4744,7 +5311,7 @@ async function discoverRobotsData(cwd, isWatchMode, robotsConfig, sitemapConfig,
4744
5311
  redirectSourcePaths
4745
5312
  };
4746
5313
  }
4747
- var init_discovery3 = () => {};
5314
+ var init_discovery4 = () => {};
4748
5315
 
4749
5316
  // packages/core/src/robots/generator.ts
4750
5317
  function getEffectivePolicies(policies) {
@@ -4757,10 +5324,16 @@ function getEffectivePolicies(policies) {
4757
5324
  }
4758
5325
  ];
4759
5326
  }
5327
+ function robotsDisallowPath(path2) {
5328
+ return path2 === "/" ? "/$" : path2;
5329
+ }
5330
+ function exactDisallowPath(path2) {
5331
+ return path2.endsWith("$") ? path2 : `${path2}$`;
5332
+ }
4760
5333
  function getAutoDisallows(discovery2) {
4761
5334
  return new Set([
4762
- ...discovery2.sitemapExcludedRoutes,
4763
- ...discovery2.redirectSourcePaths
5335
+ ...discovery2.sitemapExcludedRoutes.map(robotsDisallowPath),
5336
+ ...discovery2.redirectSourcePaths.map(exactDisallowPath)
4764
5337
  ]);
4765
5338
  }
4766
5339
  function addAllowDirectives(lines, policy) {
@@ -4787,8 +5360,16 @@ function addDisallowDirectives(lines, policy, autoDisallows) {
4787
5360
  }
4788
5361
  }
4789
5362
  }
4790
- function addPolicyBlock(lines, policy, autoDisallows) {
5363
+ function addContentSignalLine(lines, policy, robotsConfig) {
5364
+ if (policy.userAgent !== "*")
5365
+ return;
5366
+ const value = formatContentSignal(robotsConfig.contentSignal);
5367
+ if (value)
5368
+ lines.push(`Content-Signal: ${value}`);
5369
+ }
5370
+ function addPolicyBlock(lines, policy, autoDisallows, robotsConfig) {
4791
5371
  lines.push(`User-agent: ${policy.userAgent}`);
5372
+ addContentSignalLine(lines, policy, robotsConfig);
4792
5373
  addAllowDirectives(lines, policy);
4793
5374
  addDisallowDirectives(lines, policy, autoDisallows);
4794
5375
  if (policy.crawlDelay !== undefined) {
@@ -4814,7 +5395,7 @@ function generateRobots(discovery2, robotsConfig, sitemapEnabled) {
4814
5395
  const effectivePolicies = getEffectivePolicies(policies);
4815
5396
  const autoDisallows = getAutoDisallows(discovery2);
4816
5397
  for (const policy of effectivePolicies) {
4817
- addPolicyBlock(lines, policy, autoDisallows);
5398
+ addPolicyBlock(lines, policy, autoDisallows, robotsConfig);
4818
5399
  }
4819
5400
  addGlobalCrawlDelay(lines, crawlDelay, effectivePolicies);
4820
5401
  if (customRules) {
@@ -4826,6 +5407,9 @@ function generateRobots(discovery2, robotsConfig, sitemapEnabled) {
4826
5407
  `).trim()}
4827
5408
  `;
4828
5409
  }
5410
+ var init_generator = __esm(() => {
5411
+ init_discovery3();
5412
+ });
4829
5413
 
4830
5414
  // packages/core/src/robots/policies.ts
4831
5415
  function blockAICrawlers(crawlers) {
@@ -4896,17 +5480,20 @@ var init_policies = __esm(() => {
4896
5480
 
4897
5481
  // packages/core/src/robots/index.ts
4898
5482
  var init_robots = __esm(() => {
4899
- init_discovery3();
5483
+ init_discovery4();
5484
+ init_generator();
4900
5485
  init_policies();
4901
5486
  });
4902
5487
 
4903
5488
  // packages/core/src/sitemap/discovery.ts
4904
5489
  var exports_discovery = {};
4905
5490
  __export(exports_discovery, {
4906
- discoverSitemapData: () => discoverSitemapData,
4907
- discoverSSRDataRoutes: () => discoverSSRDataRoutes2,
5491
+ buildSitemapLoc: () => buildSitemapLoc,
5492
+ discoverCollectionContent: () => discoverCollectionContent,
5493
+ discoverDynamicSitemapRoutes: () => discoverDynamicSitemapRoutes,
4908
5494
  discoverRoutes: () => discoverRoutes,
4909
- discoverCollectionContent: () => discoverCollectionContent
5495
+ discoverSSRDataRoutes: () => discoverSSRDataRoutes2,
5496
+ discoverSitemapData: () => discoverSitemapData
4910
5497
  });
4911
5498
  async function loadRoutesModule2(cwd, isWatchMode) {
4912
5499
  let routes = globalThis.__REROUTE_ROUTES__;
@@ -5170,7 +5757,7 @@ function extractIdentifierFromItem(item, routePattern, sitemapConfig) {
5170
5757
  console.warn("[reroute/sitemap] extractUrl failed:", error);
5171
5758
  }
5172
5759
  }
5173
- const identifier = item.version || item.slug || item.id || item.name || item.key;
5760
+ const identifier = item.version || item.slug || item.id || item.name || item.key || item.username;
5174
5761
  return identifier ? identifier : null;
5175
5762
  }
5176
5763
  function extractLastmodFromItem(item, sitemapConfig) {
@@ -5195,15 +5782,42 @@ function extractLastmodFromItem(item, sitemapConfig) {
5195
5782
  }
5196
5783
  return;
5197
5784
  }
5198
- function createEntryFromItem(item, routePattern, baseUrl, sitemapConfig) {
5199
- const identifier = extractIdentifierFromItem(item, routePattern, sitemapConfig);
5200
- if (!identifier) {
5201
- return null;
5785
+ function buildSitemapLoc(baseUrl, routePattern, identifier) {
5786
+ const base = baseUrl.replace(/\/$/, "");
5787
+ const dynamicParams = routePattern.match(/:[^/]+/g) ?? [];
5788
+ if (dynamicParams.length === 0) {
5789
+ return `${base}${routePattern}/${identifier}`;
5202
5790
  }
5203
- const url = `${baseUrl}${routePattern}/${identifier}`;
5204
- const entry = {
5205
- loc: url,
5206
- changefreq: sitemapConfig?.changefreq || "weekly",
5791
+ if (identifier.startsWith("/")) {
5792
+ return `${base}${identifier}`;
5793
+ }
5794
+ if (dynamicParams.length === 1) {
5795
+ return `${base}${routePattern.replace(/:[^/]+/, identifier)}`;
5796
+ }
5797
+ return `${base}${routePattern.replace(/:[^/]+/, identifier)}`;
5798
+ }
5799
+ function resolveItemLoc(item, baseUrl, routePattern, identifier) {
5800
+ if (typeof item.loc === "string") {
5801
+ if (item.loc.startsWith("http://") || item.loc.startsWith("https://")) {
5802
+ return item.loc;
5803
+ }
5804
+ if (item.loc.startsWith("/")) {
5805
+ return `${baseUrl.replace(/\/$/, "")}${item.loc}`;
5806
+ }
5807
+ }
5808
+ if (typeof item.href === "string" && item.href.startsWith("/")) {
5809
+ return `${baseUrl.replace(/\/$/, "")}${item.href}`;
5810
+ }
5811
+ return buildSitemapLoc(baseUrl, routePattern, identifier);
5812
+ }
5813
+ function createEntryFromItem(item, routePattern, baseUrl, sitemapConfig) {
5814
+ const identifier = extractIdentifierFromItem(item, routePattern, sitemapConfig);
5815
+ if (!identifier) {
5816
+ return null;
5817
+ }
5818
+ const entry = {
5819
+ loc: resolveItemLoc(item, baseUrl, routePattern, identifier),
5820
+ changefreq: sitemapConfig?.changefreq || "weekly",
5207
5821
  priority: sitemapConfig?.priority !== undefined ? sitemapConfig.priority : 0.6
5208
5822
  };
5209
5823
  const lastmod = extractLastmodFromItem(item, sitemapConfig);
@@ -5212,6 +5826,50 @@ function createEntryFromItem(item, routePattern, baseUrl, sitemapConfig) {
5212
5826
  }
5213
5827
  return entry;
5214
5828
  }
5829
+ async function loadRouteSitemapFn(cwd, route, isWatchMode) {
5830
+ const bundledRoutes = globalThis.__REROUTE_ROUTES__;
5831
+ if (bundledRoutes && Array.isArray(bundledRoutes)) {
5832
+ const bundledRoute = bundledRoutes.find((r) => r?.pattern === route.pattern);
5833
+ const sitemapFn = bundledRoute?.ssr?.sitemap;
5834
+ return typeof sitemapFn === "function" ? sitemapFn : null;
5835
+ }
5836
+ try {
5837
+ const routeModulePath = join(cwd, "src", "client", "routes", route.path);
5838
+ const mod = await import(Bun.pathToFileURL(routeModulePath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
5839
+ const sitemapFn = mod?.ssr?.sitemap;
5840
+ return typeof sitemapFn === "function" ? sitemapFn : null;
5841
+ } catch {
5842
+ return null;
5843
+ }
5844
+ }
5845
+ async function discoverDynamicSitemapRoutes(cwd, dynamicRoutes, isWatchMode, baseUrl, sitemapConfig) {
5846
+ const sitemapRoutes = new Map;
5847
+ const routePromises = dynamicRoutes.map(async (route) => {
5848
+ if (sitemapConfig?.excludeDiscovery?.some((excluded) => route.pattern.startsWith(excluded))) {
5849
+ return null;
5850
+ }
5851
+ const sitemapFn = await loadRouteSitemapFn(cwd, route, isWatchMode);
5852
+ if (!sitemapFn)
5853
+ return null;
5854
+ try {
5855
+ const result = await sitemapFn();
5856
+ const entries = extractEntriesFromData(result, route.pattern, baseUrl, sitemapConfig);
5857
+ if (entries.length > 0) {
5858
+ return { pattern: route.pattern, entries };
5859
+ }
5860
+ } catch (error) {
5861
+ console.warn(`[reroute/sitemap] ssr.sitemap failed for ${route.pattern}:`, error);
5862
+ }
5863
+ return null;
5864
+ });
5865
+ const results = await Promise.all(routePromises);
5866
+ for (const result of results) {
5867
+ if (result) {
5868
+ sitemapRoutes.set(result.pattern, result.entries);
5869
+ }
5870
+ }
5871
+ return sitemapRoutes;
5872
+ }
5215
5873
  async function discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig) {
5216
5874
  const { staticRoutes, dynamicRoutes } = await discoverRoutes(cwd, isWatchMode);
5217
5875
  const collectionsMap = new Map;
@@ -5222,6 +5880,10 @@ async function discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, site
5222
5880
  }
5223
5881
  }
5224
5882
  const ssrDataRoutes = await discoverSSRDataRoutes2(cwd, staticRoutes, isWatchMode, baseUrl, sitemapConfig);
5883
+ const dynamicSitemapRoutes = await discoverDynamicSitemapRoutes(cwd, dynamicRoutes, isWatchMode, baseUrl, sitemapConfig);
5884
+ for (const [pattern, entries] of dynamicSitemapRoutes.entries()) {
5885
+ ssrDataRoutes.set(pattern, entries);
5886
+ }
5225
5887
  return {
5226
5888
  staticRoutes,
5227
5889
  dynamicRoutes,
@@ -5229,7 +5891,7 @@ async function discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, site
5229
5891
  ssrDataRoutes
5230
5892
  };
5231
5893
  }
5232
- var init_discovery4 = () => {};
5894
+ var init_discovery5 = () => {};
5233
5895
 
5234
5896
  // packages/core/src/rss/discovery.ts
5235
5897
  import { pathToFileURL as pathToFileURL7 } from "node:url";
@@ -5345,7 +6007,7 @@ async function discoverCollectionFeedItems(cwd, collection, isWatchMode, baseUrl
5345
6007
  async function discoverSSRDataFeedItems(cwd, routePattern, routePath, isWatchMode, baseUrl, rssConfig) {
5346
6008
  const items = [];
5347
6009
  try {
5348
- const abs = join(cwd, "src", "client", "routes", routePath);
6010
+ const abs = join(cwd, resolveAppPaths(await loadConfig(cwd)).routesDir, routePath);
5349
6011
  const mod = await import(pathToFileURL7(abs).href + (isWatchMode ? `?t=${Date.now()}` : ""));
5350
6012
  const ssr = mod?.ssr;
5351
6013
  const dataFn = ssr?.data;
@@ -5497,7 +6159,7 @@ async function discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfi
5497
6159
  }
5498
6160
  const ssrDataFeeds = new Map;
5499
6161
  const bundledRoutes = globalThis.__REROUTE_ROUTES__;
5500
- const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery4(), exports_discovery));
6162
+ const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery5(), exports_discovery));
5501
6163
  const { staticRoutes } = await discoverRoutes2(cwd, isWatchMode);
5502
6164
  if (bundledRoutes && Array.isArray(bundledRoutes)) {
5503
6165
  const routePromises = staticRoutes.map(async (route) => {
@@ -5554,7 +6216,10 @@ async function discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfi
5554
6216
  ssrDataFeeds
5555
6217
  };
5556
6218
  }
5557
- var init_discovery5 = () => {};
6219
+ var init_discovery6 = __esm(() => {
6220
+ init_app_paths();
6221
+ init_config();
6222
+ });
5558
6223
 
5559
6224
  // packages/core/src/rss/generator.ts
5560
6225
  function generateRSSXML(feed, options = {}) {
@@ -5667,7 +6332,7 @@ function escapeXml(unsafe) {
5667
6332
 
5668
6333
  // packages/core/src/rss/index.ts
5669
6334
  var init_rss = __esm(() => {
5670
- init_discovery5();
6335
+ init_discovery6();
5671
6336
  });
5672
6337
 
5673
6338
  // packages/core/src/sitemap/generator.ts
@@ -5695,18 +6360,43 @@ function createStaticEntry(route, baseUrl, defaultChangefreq, defaultPriority) {
5695
6360
  priority: route.priority !== undefined ? route.priority : loc === "/" ? 1 : defaultPriority
5696
6361
  };
5697
6362
  }
5698
- function collectAllEntries(discovery4, baseUrl, changefreq, priority, excludeRoutes) {
6363
+ function localizePageEntry(entry, baseUrl, i18n) {
6364
+ const base = baseUrl.replace(/\/$/, "");
6365
+ if (!(i18n && entry.loc.startsWith(base)))
6366
+ return [entry];
6367
+ const path2 = entry.loc.slice(base.length) || "/";
6368
+ if (parseContentPath(path2, i18n.locales, i18n.collections))
6369
+ return [entry];
6370
+ if (isUnprefixedPath(path2, i18n.unprefixedPaths))
6371
+ return [entry];
6372
+ const { locales, defaultLocale } = i18n;
6373
+ const urlFor = (locale) => `${base}${localizePagePath(path2, locale, defaultLocale)}`;
6374
+ const alternates = [
6375
+ ...locales.map((locale) => ({ hreflang: locale, href: urlFor(locale) })),
6376
+ { hreflang: "x-default", href: urlFor(defaultLocale) }
6377
+ ];
6378
+ return locales.map((locale) => ({
6379
+ ...entry,
6380
+ loc: urlFor(locale),
6381
+ alternates
6382
+ }));
6383
+ }
6384
+ function collectAllEntries(discovery4, baseUrl, changefreq, priority, excludeRoutes, i18n) {
5699
6385
  const allEntries = [];
6386
+ const addPage = (entry) => {
6387
+ allEntries.push(...localizePageEntry(entry, baseUrl, i18n));
6388
+ };
5700
6389
  for (const route of discovery4.staticRoutes) {
5701
6390
  if (shouldIncludeRoute(route.pattern, excludeRoutes)) {
5702
- allEntries.push(createStaticEntry(route, baseUrl, changefreq, priority));
6391
+ addPage(createStaticEntry(route, baseUrl, changefreq, priority));
5703
6392
  }
5704
6393
  }
5705
6394
  for (const [_collection, entries] of discovery4.collections.entries()) {
5706
6395
  allEntries.push(...entries);
5707
6396
  }
5708
6397
  for (const [_pattern, entries] of discovery4.ssrDataRoutes.entries()) {
5709
- allEntries.push(...entries);
6398
+ for (const entry of entries)
6399
+ addPage(entry);
5710
6400
  }
5711
6401
  return allEntries;
5712
6402
  }
@@ -5752,7 +6442,7 @@ async function generateSitemap(discovery4, baseUrl, options = {}) {
5752
6442
  priority = 0.5,
5753
6443
  maxUrlsPerPage = DEFAULT_MAX_URLS
5754
6444
  } = options;
5755
- const allEntries = collectAllEntries(discovery4, baseUrl, changefreq, priority, options.excludeRoutes);
6445
+ const allEntries = collectAllEntries(discovery4, baseUrl, changefreq, priority, options.excludeRoutes, options.i18n);
5756
6446
  sortEntries(allEntries);
5757
6447
  const needsIndex = allEntries.length > maxUrlsPerPage;
5758
6448
  if (needsIndex) {
@@ -5812,12 +6502,14 @@ function escapeXml2(unsafe) {
5812
6502
  return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
5813
6503
  }
5814
6504
  var DEFAULT_MAX_URLS = 50000;
5815
- var init_generator = () => {};
6505
+ var init_generator2 = __esm(() => {
6506
+ init_pathname();
6507
+ });
5816
6508
 
5817
6509
  // packages/core/src/sitemap/index.ts
5818
6510
  var init_sitemap = __esm(() => {
5819
- init_discovery4();
5820
- init_generator();
6511
+ init_discovery5();
6512
+ init_generator2();
5821
6513
  });
5822
6514
 
5823
6515
  // packages/core/src/ssr/stream.ts
@@ -5895,15 +6587,16 @@ async function renderSSRDocumentStream(options) {
5895
6587
  const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${pageLang}"`) : `${attrs} lang="${pageLang}"`;
5896
6588
  return `<html${newAttrs}>`;
5897
6589
  });
5898
- const extraHead = setup2.bundlePreload + setup2.preloadExtraHead + setup2.metadataResult.perPageHead;
5899
- if (/<title[\s\S]*?<\/title>/i.test(extraHead)) {
6590
+ const extraHeadBase = setup2.bundlePreload + setup2.preloadExtraHead + markPageHead(setup2.metadataResult.perPageHead);
6591
+ if (/<title[\s\S]*?<\/title>/i.test(extraHeadBase)) {
5900
6592
  headWithLang = headWithLang.replace(/<title[\s\S]*?<\/title>/i, "");
5901
6593
  }
5902
- if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHead)) {
6594
+ if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHeadBase)) {
5903
6595
  headWithLang = headWithLang.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
5904
6596
  }
5905
- headWithLang = removeOverriddenMetaTags(headWithLang, extraHead);
6597
+ headWithLang = removeOverriddenMetaTags(headWithLang, extraHeadBase);
5906
6598
  const config = await loadConfig(cwd);
6599
+ const extraHead = appendLlmsAlternateHead(extraHeadBase, pathname, statusOverride || 200, config.llms);
5907
6600
  const browserTelemetryConfigRaw = config.telemetry?.browser;
5908
6601
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
5909
6602
  const browserTelemetryConfig = serializeBrowserTelemetryConfig2(browserTelemetryConfigRaw);
@@ -5980,11 +6673,11 @@ async function streamSSRContent(writer, encoder, ctx) {
5980
6673
  const reactStream = await streamPromise;
5981
6674
  if (streamError)
5982
6675
  throw streamError;
5983
- const streamTimeoutPromise = new Promise((resolve) => {
6676
+ const streamTimeoutPromise = new Promise((resolve2) => {
5984
6677
  timeoutId = setTimeout(() => {
5985
6678
  console.warn(`[reroute] Stream timeout after ${STREAM_TIMEOUT_MS}ms for ${ctx.pathname}, forcing close`);
5986
6679
  streamTimedOut = true;
5987
- resolve({ done: true, value: undefined });
6680
+ resolve2({ done: true, value: undefined });
5988
6681
  }, STREAM_TIMEOUT_MS);
5989
6682
  });
5990
6683
  const reader = reactStream.getReader();
@@ -6081,7 +6774,10 @@ function generateMetaUpdateScript(ctx, ssrDataSnapshot) {
6081
6774
  }
6082
6775
  let headResult;
6083
6776
  try {
6084
- headResult = ctx.ssrExport.head({ data: routeData });
6777
+ headResult = ctx.ssrExport.head({
6778
+ pathname: ctx.pathname,
6779
+ data: routeData
6780
+ });
6085
6781
  } catch (err) {
6086
6782
  console.error("[reroute] Error calling ssr.head() at stream end:", err);
6087
6783
  return "";
@@ -6161,6 +6857,7 @@ function unescapeHtmlEntities(str) {
6161
6857
  var init_stream = __esm(() => {
6162
6858
  init_server2();
6163
6859
  init_config();
6860
+ init_discovery3();
6164
6861
  init_lib();
6165
6862
  init_html();
6166
6863
  init_imports();
@@ -6175,10 +6872,12 @@ var init_ssr = __esm(() => {
6175
6872
 
6176
6873
  // packages/core/src/index.ts
6177
6874
  var init_src = __esm(() => {
6875
+ init_app_paths();
6178
6876
  init_bundler();
6179
6877
  init_config();
6180
6878
  init_content();
6181
6879
  init_i18n();
6880
+ init_image();
6182
6881
  init_llms();
6183
6882
  init_og();
6184
6883
  init_robots();
@@ -6194,137 +6893,171 @@ var init_core = __esm(() => {
6194
6893
  init_core();
6195
6894
 
6196
6895
  export {
6197
- toPromise,
6198
- toOgLocale,
6199
- toBytes,
6200
- stripStart,
6201
- stripHtmlTags,
6202
- stripEnd,
6203
- statusCache,
6204
- ssrCache,
6205
- splitTemplate,
6206
- shouldExcludeRoute,
6207
- setGlobalSSRData,
6208
- setGlobalCollections,
6209
- seedSSRModuleForPath,
6210
- resolveLocale,
6211
- resetSSRAccessTracking,
6212
- renderSSRDocumentStream,
6213
- renderSSRDocument,
6214
- renderOGImageToPNG,
6215
- removeOverriddenMetaTags,
6216
- processCollections,
6217
- preloadContentModule,
6218
- performSSRSetup,
6219
- parseCookieValue,
6220
- parseContentPath,
6221
- normalizePathname,
6222
- negotiateLocale,
6223
- mergeLayoutData,
6224
- matchRoutes,
6225
- matchRoutePattern,
6226
- lookupMessage,
6227
- looksLikeLocale,
6228
- localizeHref,
6229
- localizeContentHref,
6230
- loadRoutesModule,
6231
- loadOGImageComponent,
6232
- loadIndexHtml,
6233
- loadConfig,
6234
- loadCollections,
6235
- listContentFiles,
6236
- join,
6237
- isThenable,
6238
- isCompressible,
6239
- inlineThemeCSS,
6240
- importContentModuleForPath,
6241
- htmlToMarkdown,
6242
- hreflangTags,
6243
- gzipIfAccepted,
6244
- getSitemapExcludedRoutes,
6245
- getRedirectSourcePaths,
6246
- getPatternDepth,
6247
- getMimeType,
6248
- getMessage,
6249
- getMatchingLayouts,
6250
- getContentMeta,
6251
- generateSitemapXML,
6252
- generateSitemapIndexXML,
6253
- generateSitemap,
6254
- generateRobots,
6255
- generateRSSXML,
6256
- generateOGImageMetaTags,
6257
- generateLLMsIndex,
6258
- generateLLMsFullContent,
6259
- generateLLMsFooter,
6260
- generateHydrationScripts,
6261
- generateFeed,
6262
- generateContentHash,
6263
- generateCollectionScripts,
6264
- generateAtomXML,
6265
- formatMessage,
6266
- formatAsText,
6267
- formatAsMarkdown,
6268
- findOGImageForPath,
6269
- extractTitle,
6270
- extractParamsFromPath,
6271
- extractPageMetadata,
6272
- extractContentForLLMs,
6273
- extname,
6274
- escapeXml2 as escapeXml,
6275
- escapeJsonForScript,
6276
- dynamicImport,
6277
- duplicateQueryParamData,
6278
- discoverSitemapData,
6279
- discoverSSRDataRoutes2 as discoverSSRDataRoutes,
6280
- discoverSSRDataFeedItems,
6281
- discoverRoutesForRobots,
6282
- discoverRoutes,
6283
- discoverRobotsData,
6284
- discoverRSSData,
6285
- discoverI18n,
6286
- discoverCollections,
6287
- discoverCollectionContent,
6288
- defineConfig,
6289
- deduplicateMetaTags,
6290
- createTranslator,
6291
- createLlmsScript,
6292
- createLayoutDataKey,
6293
- createLayoutCacheKey,
6294
- createFeedsScript,
6295
- createDataScript,
6296
- createCollectionScript,
6297
- createBundlePreload,
6298
- contentNegotiateRedirect,
6299
- contentKey,
6300
- computeSSRDataForPath,
6301
- computeSSRData,
6302
- computeRouteData,
6303
- computeLayoutData,
6304
- computeContentData,
6305
- compressStreamIfAccepted,
6306
- compareRouteSpecificity,
6307
- cleanupPathScopedSSRData,
6308
- buildLocaleCookie,
6309
- buildHeadFromMeta,
6310
- blockSearchCrawlers,
6311
- blockAITrainingCrawlers,
6312
- blockAICrawlers,
6313
- basename,
6314
- applyIndexTemplate,
6315
- allowSearchCrawlers,
6316
- allowAICrawlers,
6317
- acceptsGzip,
6318
- acceptsBrotli,
6319
- TTLCache,
6320
- SSRDataCache,
6321
- SEARCH_CRAWLERS,
6322
- LRUCache,
6323
- DefaultOGTemplate,
6324
- DEFAULT_LOCALES_DIR,
6325
- DEFAULT_LOCALE,
6896
+ AI_CRAWLERS,
6897
+ DEFAULT_APP_SERVER,
6898
+ DEFAULT_APP_SRC,
6326
6899
  DEFAULT_COOKIE,
6327
- AI_CRAWLERS
6900
+ DEFAULT_IMAGE_DEVICE_SIZES,
6901
+ DEFAULT_IMAGE_QUALITY,
6902
+ DEFAULT_LOCALE,
6903
+ DEFAULT_LOCALES_DIR,
6904
+ DEFAULT_PREPROCESS_FORMATS,
6905
+ DEFAULT_PREPROCESS_SIZES,
6906
+ DefaultOGTemplate,
6907
+ LRUCache,
6908
+ SEARCH_CRAWLERS,
6909
+ SSRDataCache,
6910
+ TTLCache,
6911
+ acceptsBrotli,
6912
+ acceptsGzip,
6913
+ allowAICrawlers,
6914
+ allowSearchCrawlers,
6915
+ appendLlmsAlternateHead,
6916
+ applyIndexTemplate,
6917
+ applyLlmsDiscoveryHeaders,
6918
+ basename,
6919
+ blockAICrawlers,
6920
+ blockAITrainingCrawlers,
6921
+ blockSearchCrawlers,
6922
+ buildHeadFromMeta,
6923
+ buildLlmsDiscovery,
6924
+ buildLocaleCookie,
6925
+ buildSitemapLoc,
6926
+ bundleImports,
6927
+ bundlePreloadPath,
6928
+ cleanupPathScopedSSRData,
6929
+ clearSSRModuleStores,
6930
+ clearWatchImportCache,
6931
+ compareRouteSpecificity,
6932
+ compressStreamIfAccepted,
6933
+ computeContentData,
6934
+ computeLayoutData,
6935
+ computeRouteData,
6936
+ computeSSRData,
6937
+ computeSSRDataForPath,
6938
+ contentKey,
6939
+ contentNegotiateRedirect,
6940
+ createBundlePreload,
6941
+ createCollectionScript,
6942
+ createDataScript,
6943
+ createFeedsScript,
6944
+ createLayoutCacheKey,
6945
+ createLayoutDataKey,
6946
+ createLlmsScript,
6947
+ createTranslator,
6948
+ deduplicateMetaTags,
6949
+ defineConfig,
6950
+ discoverCollectionContent,
6951
+ discoverCollections,
6952
+ discoverDynamicSitemapRoutes,
6953
+ discoverI18n,
6954
+ discoverRSSData,
6955
+ discoverRobotsData,
6956
+ discoverRoutes,
6957
+ discoverRoutesForRobots,
6958
+ discoverSSRDataFeedItems,
6959
+ discoverSSRDataRoutes2 as discoverSSRDataRoutes,
6960
+ discoverSitemapData,
6961
+ duplicateQueryParamData,
6962
+ dynamicImport,
6963
+ escapeJsonForScript,
6964
+ escapeXml2 as escapeXml,
6965
+ extname,
6966
+ extractContentForLLMs,
6967
+ extractPageMetadata,
6968
+ extractParamsFromPath,
6969
+ extractTitle,
6970
+ findOGImageForPath,
6971
+ formatAsMarkdown,
6972
+ formatAsText,
6973
+ formatContentSignal,
6974
+ formatMessage,
6975
+ generateAtomXML,
6976
+ generateCollectionScripts,
6977
+ generateContentHash,
6978
+ generateFeed,
6979
+ generateHydrationScripts,
6980
+ generateLLMsFooter,
6981
+ generateLLMsFullContent,
6982
+ generateLLMsIndex,
6983
+ generateOGImageMetaTags,
6984
+ generateRSSXML,
6985
+ generateRobots,
6986
+ generateSitemap,
6987
+ generateSitemapIndexXML,
6988
+ generateSitemapXML,
6989
+ getContentMeta,
6990
+ getMatchingLayouts,
6991
+ getMessage,
6992
+ getMimeType,
6993
+ getPatternDepth,
6994
+ getRedirectSourcePaths,
6995
+ getSitemapExcludedRoutes,
6996
+ gzipIfAccepted,
6997
+ hreflangTags,
6998
+ htmlToMarkdown,
6999
+ importContentModuleForPath,
7000
+ importFromReroute,
7001
+ inlineThemeCSS,
7002
+ isCompressible,
7003
+ isThenable,
7004
+ isUnprefixedPath,
7005
+ join,
7006
+ layoutCovers,
7007
+ layoutWraps,
7008
+ listContentFiles,
7009
+ llmsAlternateLinkTag,
7010
+ loadCollections,
7011
+ loadConfig,
7012
+ loadIndexHtml,
7013
+ loadOGImageComponent,
7014
+ loadRoutesModule,
7015
+ localizeContentHref,
7016
+ localizeHref,
7017
+ localizePagePath,
7018
+ looksLikeLocale,
7019
+ lookupMessage,
7020
+ markPageHead,
7021
+ markdownTwinPath,
7022
+ matchRoutePattern,
7023
+ matchRoutes,
7024
+ mergeLayoutData,
7025
+ mergeVary,
7026
+ negotiateLocale,
7027
+ normalizePathname,
7028
+ pageHreflangTags,
7029
+ parseContentPath,
7030
+ parseCookieValue,
7031
+ parseLocalePrefix,
7032
+ performSSRSetup,
7033
+ preloadContentModule,
7034
+ processCollections,
7035
+ removeOverriddenMetaTags,
7036
+ renderOGImageToPNG,
7037
+ renderSSRDocument,
7038
+ renderSSRDocumentStream,
7039
+ resetSSRAccessTracking,
7040
+ resetSSRContentResults,
7041
+ resolveAppPaths,
7042
+ resolveImageDeviceSizes,
7043
+ resolveImagePreprocess,
7044
+ resolveLocale,
7045
+ seedSSRModuleForPath,
7046
+ setGlobalCollections,
7047
+ setGlobalSSRData,
7048
+ shouldAdvertiseMarkdownTwin,
7049
+ shouldExcludeRoute,
7050
+ splitTemplate,
7051
+ ssrCache,
7052
+ statusCache,
7053
+ stripEnd,
7054
+ stripHtmlTags,
7055
+ stripLayoutChrome,
7056
+ stripStart,
7057
+ takeSSRContentResults,
7058
+ toBytes,
7059
+ toOgLocale,
7060
+ toPromise
6328
7061
  };
6329
7062
 
6330
- //# debugId=D5B84417D804DD6B64756E2164756E21
7063
+ //# debugId=8141BDE4E1BF49A664756E2164756E21