reroute-js 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (252) hide show
  1. package/README.md +7 -3
  2. package/cli/bin.d.ts +1 -1
  3. package/cli/bin.js +1618 -958
  4. package/cli/bin.js.map +38 -35
  5. package/cli/index.d.ts +1 -1
  6. package/cli/index.js +628 -40
  7. package/cli/index.js.map +53 -5
  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 +2 -2
  12. package/cli/src/commands/dev.d.ts +6 -6
  13. package/cli/src/commands/dev.d.ts.map +1 -1
  14. package/cli/src/commands/gen.d.ts +4 -1
  15. package/cli/src/commands/gen.d.ts.map +1 -1
  16. package/cli/src/commands/index.d.ts +1 -1
  17. package/cli/src/commands/init.d.ts +1 -1
  18. package/cli/src/commands/lib/assets.d.ts +1 -1
  19. package/cli/src/commands/lib/bundler.d.ts +7 -1
  20. package/cli/src/commands/lib/bundler.d.ts.map +1 -1
  21. package/cli/src/commands/lib/command.d.ts +1 -1
  22. package/cli/src/commands/lib/env.d.ts +1 -1
  23. package/cli/src/commands/lib/index.d.ts +1 -1
  24. package/cli/src/commands/lib/log.d.ts +1 -1
  25. package/cli/src/commands/lib/markdown/availability.d.ts +1 -1
  26. package/cli/src/commands/lib/markdown/index.d.ts +1 -1
  27. package/cli/src/commands/lib/markdown/processor.d.ts +1 -1
  28. package/cli/src/commands/lib/production.d.ts +1 -1
  29. package/cli/src/commands/lib/server.d.ts +2 -1
  30. package/cli/src/commands/lib/server.d.ts.map +1 -1
  31. package/cli/src/commands/lib/streaming/analyzer.d.ts +1 -1
  32. package/cli/src/commands/lib/streaming/suspense.d.ts +2 -2
  33. package/cli/src/commands/lib/streaming/suspense.d.ts.map +1 -1
  34. package/cli/src/commands/lib/terminal-ui.d.ts +2 -2
  35. package/cli/src/commands/lib/terminal-ui.d.ts.map +1 -1
  36. package/cli/src/commands/lib/theme.d.ts +7 -4
  37. package/cli/src/commands/lib/theme.d.ts.map +1 -1
  38. package/cli/src/commands/lib/version.d.ts +1 -1
  39. package/cli/src/commands/lib/watch.d.ts +26 -0
  40. package/cli/src/commands/lib/watch.d.ts.map +1 -0
  41. package/cli/src/commands/og.d.ts +1 -1
  42. package/cli/src/commands/og.d.ts.map +1 -1
  43. package/cli/src/commands/start.d.ts +2 -2
  44. package/cli/src/commands/start.d.ts.map +1 -1
  45. package/cli/src/index.d.ts +1 -1
  46. package/core/index.d.ts +1 -1
  47. package/core/index.js +712 -279
  48. package/core/index.js.map +25 -23
  49. package/core/src/app-paths.d.ts +32 -0
  50. package/core/src/app-paths.d.ts.map +1 -0
  51. package/core/src/bundler/hash.d.ts +1 -1
  52. package/core/src/bundler/index.d.ts +1 -1
  53. package/core/src/config.d.ts +51 -7
  54. package/core/src/config.d.ts.map +1 -1
  55. package/core/src/content/discovery.d.ts +1 -1
  56. package/core/src/content/index.d.ts +1 -1
  57. package/core/src/content/metadata.d.ts +1 -1
  58. package/core/src/i18n/catalog.d.ts +1 -1
  59. package/core/src/i18n/discover.d.ts +1 -1
  60. package/core/src/i18n/index.d.ts +1 -1
  61. package/core/src/i18n/messages.d.ts +1 -1
  62. package/core/src/i18n/negotiate.d.ts +1 -1
  63. package/core/src/i18n/pathname.d.ts +1 -1
  64. package/core/src/i18n/resolve.d.ts +4 -3
  65. package/core/src/i18n/resolve.d.ts.map +1 -1
  66. package/core/src/i18n/types.d.ts +5 -1
  67. package/core/src/i18n/types.d.ts.map +1 -1
  68. package/core/src/index.d.ts +2 -1
  69. package/core/src/index.d.ts.map +1 -1
  70. package/core/src/llms/discovery.d.ts +35 -0
  71. package/core/src/llms/discovery.d.ts.map +1 -0
  72. package/core/src/llms/extractor.d.ts +6 -1
  73. package/core/src/llms/extractor.d.ts.map +1 -1
  74. package/core/src/llms/formatter.d.ts +1 -1
  75. package/core/src/llms/formatter.d.ts.map +1 -1
  76. package/core/src/llms/full-generator.d.ts +3 -1
  77. package/core/src/llms/full-generator.d.ts.map +1 -1
  78. package/core/src/llms/index-generator.d.ts +6 -3
  79. package/core/src/llms/index-generator.d.ts.map +1 -1
  80. package/core/src/llms/index.d.ts +5 -2
  81. package/core/src/llms/index.d.ts.map +1 -1
  82. package/core/src/og/discovery.d.ts +1 -1
  83. package/core/src/og/index.d.ts +1 -1
  84. package/core/src/og/meta.d.ts +1 -1
  85. package/core/src/og/render.d.ts +1 -1
  86. package/core/src/og/types.d.ts +1 -1
  87. package/core/src/robots/discovery.d.ts +1 -1
  88. package/core/src/robots/generator.d.ts +1 -1
  89. package/core/src/robots/generator.d.ts.map +1 -1
  90. package/core/src/robots/index.d.ts +1 -1
  91. package/core/src/robots/policies.d.ts +1 -1
  92. package/core/src/rss/discovery.d.ts +2 -2
  93. package/core/src/rss/discovery.d.ts.map +1 -1
  94. package/core/src/rss/generator.d.ts +1 -1
  95. package/core/src/rss/index.d.ts +1 -1
  96. package/core/src/sitemap/discovery.d.ts +7 -2
  97. package/core/src/sitemap/discovery.d.ts.map +1 -1
  98. package/core/src/sitemap/generator.d.ts +1 -1
  99. package/core/src/sitemap/index.d.ts +1 -1
  100. package/core/src/ssr/index.d.ts +1 -1
  101. package/core/src/ssr/lib/cache.d.ts +1 -1
  102. package/core/src/ssr/lib/cleanup.d.ts +1 -1
  103. package/core/src/ssr/lib/collections.d.ts +17 -1
  104. package/core/src/ssr/lib/collections.d.ts.map +1 -1
  105. package/core/src/ssr/lib/compression.d.ts +1 -1
  106. package/core/src/ssr/lib/compute/content.d.ts +1 -1
  107. package/core/src/ssr/lib/compute/index.d.ts +1 -1
  108. package/core/src/ssr/lib/compute/layouts.d.ts +1 -1
  109. package/core/src/ssr/lib/compute/routes.d.ts +1 -1
  110. package/core/src/ssr/lib/content-path.d.ts +1 -1
  111. package/core/src/ssr/lib/data.d.ts +1 -1
  112. package/core/src/ssr/lib/html.d.ts +1 -1
  113. package/core/src/ssr/lib/imports.d.ts +8 -3
  114. package/core/src/ssr/lib/imports.d.ts.map +1 -1
  115. package/core/src/ssr/lib/index.d.ts +1 -1
  116. package/core/src/ssr/lib/layouts.d.ts +1 -1
  117. package/core/src/ssr/lib/metadata.d.ts +1 -1
  118. package/core/src/ssr/lib/mime.d.ts +1 -1
  119. package/core/src/ssr/lib/modules.d.ts +1 -1
  120. package/core/src/ssr/lib/path.d.ts +1 -1
  121. package/core/src/ssr/lib/preload.d.ts +1 -1
  122. package/core/src/ssr/lib/route-match.d.ts +1 -1
  123. package/core/src/ssr/lib/scripts/collections.d.ts +2 -2
  124. package/core/src/ssr/lib/scripts/collections.d.ts.map +1 -1
  125. package/core/src/ssr/lib/scripts/data.d.ts +1 -1
  126. package/core/src/ssr/lib/scripts/escape.d.ts +1 -1
  127. package/core/src/ssr/lib/scripts/feeds.d.ts +1 -1
  128. package/core/src/ssr/lib/scripts/index.d.ts +1 -1
  129. package/core/src/ssr/lib/seed.d.ts +6 -1
  130. package/core/src/ssr/lib/seed.d.ts.map +1 -1
  131. package/core/src/ssr/lib/serialize.d.ts +1 -1
  132. package/core/src/ssr/lib/setup.d.ts +2 -2
  133. package/core/src/ssr/lib/setup.d.ts.map +1 -1
  134. package/core/src/ssr/lib/styles.d.ts +5 -4
  135. package/core/src/ssr/lib/styles.d.ts.map +1 -1
  136. package/core/src/ssr/lib/template.d.ts +1 -1
  137. package/core/src/ssr/lib/types.d.ts +15 -1
  138. package/core/src/ssr/lib/types.d.ts.map +1 -1
  139. package/core/src/ssr/render.d.ts +1 -1
  140. package/core/src/ssr/render.d.ts.map +1 -1
  141. package/core/src/ssr/stream.d.ts +1 -1
  142. package/core/src/ssr/stream.d.ts.map +1 -1
  143. package/elysia/index.d.ts +1 -1
  144. package/elysia/index.js +971 -432
  145. package/elysia/index.js.map +38 -33
  146. package/elysia/src/index.d.ts +1 -1
  147. package/elysia/src/libs/assets.d.ts +1 -1
  148. package/elysia/src/libs/cache.d.ts +6 -1
  149. package/elysia/src/libs/cache.d.ts.map +1 -1
  150. package/elysia/src/libs/caching.d.ts +1 -1
  151. package/elysia/src/libs/http.d.ts +1 -1
  152. package/elysia/src/libs/i18n.d.ts +2 -2
  153. package/elysia/src/libs/i18n.d.ts.map +1 -1
  154. package/elysia/src/libs/image.d.ts +1 -1
  155. package/elysia/src/libs/index.d.ts +1 -1
  156. package/elysia/src/libs/llms.d.ts +1 -1
  157. package/elysia/src/libs/response.d.ts +1 -1
  158. package/elysia/src/libs/serving.d.ts +1 -1
  159. package/elysia/src/plugin.d.ts +1 -1
  160. package/elysia/src/plugin.d.ts.map +1 -1
  161. package/elysia/src/routes/artifacts.d.ts +1 -1
  162. package/elysia/src/routes/artifacts.d.ts.map +1 -1
  163. package/elysia/src/routes/content.d.ts +2 -2
  164. package/elysia/src/routes/content.d.ts.map +1 -1
  165. package/elysia/src/routes/image.d.ts +1 -1
  166. package/elysia/src/routes/index.d.ts +1 -1
  167. package/elysia/src/routes/internal.d.ts +1 -1
  168. package/elysia/src/routes/internal.d.ts.map +1 -1
  169. package/elysia/src/routes/liveReloadClient.d.ts +16 -0
  170. package/elysia/src/routes/liveReloadClient.d.ts.map +1 -0
  171. package/elysia/src/routes/llms.d.ts +1 -1
  172. package/elysia/src/routes/llms.d.ts.map +1 -1
  173. package/elysia/src/routes/og.d.ts +1 -1
  174. package/elysia/src/routes/redirects.d.ts +1 -1
  175. package/elysia/src/routes/robots.d.ts +3 -1
  176. package/elysia/src/routes/robots.d.ts.map +1 -1
  177. package/elysia/src/routes/rss.d.ts +1 -1
  178. package/elysia/src/routes/search.d.ts +1 -1
  179. package/elysia/src/routes/sitemap.d.ts +3 -1
  180. package/elysia/src/routes/sitemap.d.ts.map +1 -1
  181. package/elysia/src/routes/ssr.d.ts +4 -2
  182. package/elysia/src/routes/ssr.d.ts.map +1 -1
  183. package/elysia/src/routes/static.d.ts +1 -1
  184. package/elysia/src/routes/themeCssRefresh.d.ts +17 -0
  185. package/elysia/src/routes/themeCssRefresh.d.ts.map +1 -0
  186. package/elysia/src/types.d.ts +1 -1
  187. package/package.json +1 -1
  188. package/react/index.d.ts +1 -1
  189. package/react/index.js +203 -107
  190. package/react/index.js.map +8 -7
  191. package/react/src/components/ClientOnly.d.ts +1 -1
  192. package/react/src/components/ContentRoute.d.ts +1 -1
  193. package/react/src/components/Image.d.ts +1 -1
  194. package/react/src/components/LazyRoute.d.ts +1 -1
  195. package/react/src/components/Link.d.ts +1 -1
  196. package/react/src/components/Markdown.d.ts +1 -1
  197. package/react/src/components/Outlet.d.ts +1 -1
  198. package/react/src/components/index.d.ts +1 -1
  199. package/react/src/hooks/index.d.ts +1 -1
  200. package/react/src/hooks/useContent.d.ts +1 -1
  201. package/react/src/hooks/useContent.d.ts.map +1 -1
  202. package/react/src/hooks/useData.d.ts +1 -1
  203. package/react/src/hooks/useFeed.d.ts +1 -1
  204. package/react/src/hooks/useLayoutData.d.ts +1 -1
  205. package/react/src/hooks/useLlms.d.ts +1 -1
  206. package/react/src/hooks/useNavigate.d.ts +1 -1
  207. package/react/src/hooks/useParams.d.ts +1 -1
  208. package/react/src/hooks/useRouter.d.ts +1 -1
  209. package/react/src/hooks/useSearch.d.ts +1 -1
  210. package/react/src/hooks/useSearchParams.d.ts +1 -1
  211. package/react/src/hooks/useToc.d.ts +1 -1
  212. package/react/src/i18n/LocaleProvider.d.ts +1 -1
  213. package/react/src/i18n/LocaleProvider.d.ts.map +1 -1
  214. package/react/src/i18n/helpers.d.ts +1 -1
  215. package/react/src/i18n/index.d.ts +1 -1
  216. package/react/src/index.d.ts +1 -1
  217. package/react/src/lib/bundle.d.ts +27 -0
  218. package/react/src/lib/bundle.d.ts.map +1 -0
  219. package/react/src/lib/collection.d.ts +1 -1
  220. package/react/src/lib/content.d.ts +1 -1
  221. package/react/src/lib/head.d.ts +1 -1
  222. package/react/src/lib/index.d.ts +2 -1
  223. package/react/src/lib/index.d.ts.map +1 -1
  224. package/react/src/lib/lazy-route.d.ts +7 -21
  225. package/react/src/lib/lazy-route.d.ts.map +1 -1
  226. package/react/src/lib/route-loader.d.ts +1 -1
  227. package/react/src/providers/ContentProvider.d.ts +1 -1
  228. package/react/src/providers/RerouteProvider.d.ts +2 -2
  229. package/react/src/providers/RerouteProvider.d.ts.map +1 -1
  230. package/react/src/providers/RouterProvider.d.ts +1 -1
  231. package/react/src/providers/index.d.ts +1 -1
  232. package/react/src/types/any.d.ts +1 -1
  233. package/react/src/types/index.d.ts +1 -1
  234. package/react/src/types/router.d.ts +1 -1
  235. package/telemetry/react.d.ts +1 -1
  236. package/telemetry/react.js +16 -16
  237. package/telemetry/react.js.map +2 -2
  238. package/telemetry/server.d.ts +1 -1
  239. package/telemetry/server.js +60 -228
  240. package/telemetry/server.js.map +20 -16
  241. package/telemetry/src/react/api.d.ts +1 -1
  242. package/telemetry/src/react/context.d.ts +1 -1
  243. package/telemetry/src/react/index.d.ts +1 -1
  244. package/telemetry/src/react/telemetry.d.ts +1 -1
  245. package/telemetry/src/server/context.d.ts +1 -1
  246. package/telemetry/src/server/headers/extractor.d.ts +1 -1
  247. package/telemetry/src/server/headers/index.d.ts +1 -1
  248. package/telemetry/src/server/headers/presets.d.ts +1 -1
  249. package/telemetry/src/server/index.d.ts +1 -1
  250. package/telemetry/src/server/instrumentation.d.ts +1 -1
  251. package/telemetry/src/server/plugin.d.ts +1 -1
  252. 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.2
2
+ * reroute-js v1.0.0-alpha.21
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);
@@ -390,14 +415,14 @@ var init_negotiate = () => {};
390
415
  // packages/core/src/i18n/pathname.ts
391
416
  var exports_pathname = {};
392
417
  __export(exports_pathname, {
393
- toOgLocale: () => toOgLocale,
394
- parseContentPath: () => parseContentPath,
395
- normalizePathname: () => normalizePathname,
396
- looksLikeLocale: () => looksLikeLocale,
397
- localizeHref: () => localizeHref,
398
- localizeContentHref: () => localizeContentHref,
418
+ contentKey: () => contentKey,
399
419
  hreflangTags: () => hreflangTags,
400
- contentKey: () => contentKey
420
+ localizeContentHref: () => localizeContentHref,
421
+ localizeHref: () => localizeHref,
422
+ looksLikeLocale: () => looksLikeLocale,
423
+ normalizePathname: () => normalizePathname,
424
+ parseContentPath: () => parseContentPath,
425
+ toOgLocale: () => toOgLocale
401
426
  });
402
427
  function looksLikeLocale(segment) {
403
428
  return /^[a-z]{2}(?:-[A-Za-z0-9]{2,8})*$/i.test(segment);
@@ -480,9 +505,30 @@ function hreflangTags(baseUrl, collection, name, locales, defaultLocale) {
480
505
  var init_pathname = () => {};
481
506
 
482
507
  // packages/core/src/i18n/resolve.ts
508
+ function canonicalLocale(value, availableLocales) {
509
+ return availableLocales.find((l) => l.toLowerCase() === value.toLowerCase()) || value;
510
+ }
511
+ function parseLangParam(search, isAvailable, availableLocales) {
512
+ if (!search)
513
+ return;
514
+ const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
515
+ const raw = params.get("lang") ?? undefined;
516
+ if (!isAvailable(raw))
517
+ return;
518
+ return canonicalLocale(raw, availableLocales);
519
+ }
520
+ function stripLangParam(search) {
521
+ if (!search)
522
+ return "";
523
+ const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
524
+ params.delete("lang");
525
+ const rest = params.toString();
526
+ return rest ? `?${rest}` : "";
527
+ }
483
528
  function resolveLocale(input) {
484
529
  const {
485
530
  pathname,
531
+ search,
486
532
  cookieHeader,
487
533
  acceptLanguage,
488
534
  availableLocales,
@@ -493,14 +539,32 @@ function resolveLocale(input) {
493
539
  const parsed = parseContentPath(pathname, availableLocales, collections);
494
540
  const availableLower = new Set(availableLocales.map((l) => l.toLowerCase()));
495
541
  const isAvailable = (locale) => !!locale && availableLower.has(locale.toLowerCase());
542
+ const routingPathname = parsed?.routingPathname ?? pathname.split("?")[0];
543
+ const restSearch = stripLangParam(search);
544
+ const queryLocale = parseLangParam(search, isAvailable, availableLocales);
545
+ if (queryLocale) {
546
+ const target = parsed ? localizeContentHref(parsed.collection, parsed.name, queryLocale, defaultLocale) : routingPathname;
547
+ return {
548
+ locale: queryLocale,
549
+ routingPathname,
550
+ fromPath: false,
551
+ fromQuery: true,
552
+ redirectTo: `${target}${restSearch}`,
553
+ parsed: parsed ? {
554
+ ...parsed,
555
+ locale: queryLocale === defaultLocale ? undefined : queryLocale
556
+ } : undefined
557
+ };
558
+ }
496
559
  if (parsed?.locale && isAvailable(parsed.locale)) {
497
- const locale = availableLocales.find((l) => l.toLowerCase() === parsed.locale?.toLowerCase()) || parsed.locale;
560
+ const locale = canonicalLocale(parsed.locale, availableLocales);
498
561
  if (locale === defaultLocale && parsed.pathname !== parsed.routingPathname) {
499
562
  return {
500
563
  locale,
501
564
  routingPathname: parsed.routingPathname,
502
565
  fromPath: true,
503
- redirectTo: parsed.routingPathname,
566
+ fromQuery: false,
567
+ redirectTo: `${parsed.routingPathname}${restSearch}`,
504
568
  parsed: { ...parsed, locale }
505
569
  };
506
570
  }
@@ -508,17 +572,18 @@ function resolveLocale(input) {
508
572
  locale,
509
573
  routingPathname: parsed.routingPathname,
510
574
  fromPath: true,
575
+ fromQuery: false,
511
576
  parsed: { ...parsed, locale }
512
577
  };
513
578
  }
514
- const routingPathname = parsed?.routingPathname ?? pathname.split("?")[0];
515
579
  const cookieLocale = parseCookieValue(cookieHeader, cookieName);
516
580
  if (isAvailable(cookieLocale)) {
517
- const locale = availableLocales.find((l) => l.toLowerCase() === cookieLocale.toLowerCase()) || cookieLocale;
581
+ const locale = canonicalLocale(cookieLocale, availableLocales);
518
582
  return {
519
583
  locale,
520
584
  routingPathname,
521
585
  fromPath: false,
586
+ fromQuery: false,
522
587
  parsed: parsed ? { ...parsed, locale: undefined } : undefined
523
588
  };
524
589
  }
@@ -527,13 +592,14 @@ function resolveLocale(input) {
527
592
  locale: negotiated,
528
593
  routingPathname,
529
594
  fromPath: false,
595
+ fromQuery: false,
530
596
  parsed: parsed ? { ...parsed, locale: undefined } : undefined
531
597
  };
532
598
  }
533
599
  function contentNegotiateRedirect(resolution, defaultLocale, enabled) {
534
600
  if (!enabled)
535
601
  return;
536
- if (resolution.fromPath)
602
+ if (resolution.fromPath || resolution.fromQuery)
537
603
  return;
538
604
  if (resolution.locale === defaultLocale)
539
605
  return;
@@ -1049,11 +1115,39 @@ function cleanupPathScopedSSRData(pathname) {
1049
1115
  }
1050
1116
 
1051
1117
  // packages/core/src/ssr/lib/imports.ts
1118
+ import { copyFile, realpath, stat as stat3, unlink } from "node:fs/promises";
1119
+ import { basename as basename2, dirname, extname as extname2, join as join3 } from "node:path";
1052
1120
  import { pathToFileURL as pathToFileURL3 } from "node:url";
1121
+ function clearWatchImportCache() {
1122
+ watchImportCache.clear();
1123
+ }
1124
+ function bustCopyPath(absolutePath) {
1125
+ const dir = dirname(absolutePath);
1126
+ const ext = extname2(absolutePath);
1127
+ const base = basename2(absolutePath, ext);
1128
+ const token = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1129
+ return join3(dir, `${base}.bust-${token}${ext}`);
1130
+ }
1053
1131
  async function dynamicImport(absolutePath, isWatchMode) {
1054
1132
  const href = pathToFileURL3(absolutePath).href;
1055
- const url = isWatchMode ? `${href}?t=${Date.now()}` : href;
1056
- return await import(url);
1133
+ if (!isWatchMode) {
1134
+ return await import(href);
1135
+ }
1136
+ const resolved = await realpath(absolutePath);
1137
+ const mtimeMs = (await stat3(resolved)).mtimeMs;
1138
+ const cached = watchImportCache.get(resolved);
1139
+ if (cached && cached.mtimeMs === mtimeMs) {
1140
+ return cached.mod;
1141
+ }
1142
+ const tmp = bustCopyPath(resolved);
1143
+ await copyFile(resolved, tmp);
1144
+ try {
1145
+ const mod = await import(pathToFileURL3(tmp).href);
1146
+ watchImportCache.set(resolved, { mtimeMs, mod });
1147
+ return mod;
1148
+ } finally {
1149
+ await unlink(tmp).catch(() => {});
1150
+ }
1057
1151
  }
1058
1152
  function isThenable(value) {
1059
1153
  return typeof value === "object" && value !== null && typeof value.then === "function";
@@ -1061,7 +1155,10 @@ function isThenable(value) {
1061
1155
  function toPromise(input) {
1062
1156
  return input instanceof Promise ? input : Promise.resolve(input);
1063
1157
  }
1064
- var init_imports = () => {};
1158
+ var watchImportCache;
1159
+ var init_imports = __esm(() => {
1160
+ watchImportCache = new Map;
1161
+ });
1065
1162
 
1066
1163
  // packages/core/src/ssr/lib/collections.ts
1067
1164
  async function loadCollections(cwd, isWatchMode) {
@@ -1078,6 +1175,21 @@ function setGlobalCollections(byCollectionForSSR) {
1078
1175
  globalThis.__REROUTE_COLLECTIONS__ = byCollectionForSSR;
1079
1176
  } catch {}
1080
1177
  }
1178
+ function resetSSRContentResults() {
1179
+ try {
1180
+ globalThis.__REROUTE_SSR_RESULTS__ = {};
1181
+ } catch {}
1182
+ }
1183
+ function takeSSRContentResults() {
1184
+ try {
1185
+ const g = globalThis;
1186
+ const results = g.__REROUTE_SSR_RESULTS__;
1187
+ g.__REROUTE_SSR_RESULTS__ = {};
1188
+ return results;
1189
+ } catch {
1190
+ return;
1191
+ }
1192
+ }
1081
1193
  var init_collections = __esm(() => {
1082
1194
  init_imports();
1083
1195
  });
@@ -1851,7 +1963,7 @@ var init_compute = __esm(() => {
1851
1963
  });
1852
1964
 
1853
1965
  // packages/core/src/ssr/lib/modules.ts
1854
- import { readdir as readdir3, stat as stat3 } from "node:fs/promises";
1966
+ import { readdir as readdir3, stat as stat4 } from "node:fs/promises";
1855
1967
  async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode) {
1856
1968
  try {
1857
1969
  const resolved = resolveContentPathParts(pathname);
@@ -1909,7 +2021,7 @@ async function tryChunkImport(collection, name, cwd, isWatchMode) {
1909
2021
  let latestM = 0;
1910
2022
  for (const f of matches) {
1911
2023
  try {
1912
- const s = await stat3(join(chunkDir, f));
2024
+ const s = await stat4(join(chunkDir, f));
1913
2025
  if (s.mtimeMs >= latestM) {
1914
2026
  latestM = s.mtimeMs;
1915
2027
  latest = f;
@@ -1966,6 +2078,16 @@ function touchModule(key) {
1966
2078
  evictLRUModule();
1967
2079
  }
1968
2080
  }
2081
+ function clearSSRModuleStores() {
2082
+ const g = globalThis;
2083
+ if (g.__REROUTE_SSR_MODULES__) {
2084
+ g.__REROUTE_SSR_MODULES__ = {};
2085
+ }
2086
+ if (g.__REROUTE_SSR_EXPORTS__) {
2087
+ g.__REROUTE_SSR_EXPORTS__ = {};
2088
+ }
2089
+ moduleAccessOrder.length = 0;
2090
+ }
1969
2091
  async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
1970
2092
  try {
1971
2093
  const resolved = resolveContentPathParts(pathname);
@@ -2950,7 +3072,7 @@ var init_metadata2 = __esm(() => {
2950
3072
  });
2951
3073
 
2952
3074
  // packages/core/src/ssr/lib/preload.ts
2953
- import { readdir as readdir5, stat as stat4 } from "node:fs/promises";
3075
+ import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
2954
3076
  async function preloadContentModule(pathname, clientDir, cwd, isWatchMode) {
2955
3077
  let extraHead = "";
2956
3078
  let hydrationScript = "";
@@ -2984,14 +3106,14 @@ async function isContentCollection(clientDir, collection) {
2984
3106
  if (isProduction) {
2985
3107
  const collectionFile = join(clientDir, "collections", `${collection}.js`);
2986
3108
  try {
2987
- const s2 = await stat4(collectionFile);
3109
+ const s2 = await stat5(collectionFile);
2988
3110
  return s2?.isFile() ?? false;
2989
3111
  } catch {
2990
3112
  return false;
2991
3113
  }
2992
3114
  }
2993
3115
  const maybeDir = join(clientDir, "routes", collection, "content");
2994
- const s = await stat4(maybeDir);
3116
+ const s = await stat5(maybeDir);
2995
3117
  return typeof s?.isDirectory === "function" ? s.isDirectory() : true;
2996
3118
  } catch {
2997
3119
  return false;
@@ -3002,7 +3124,7 @@ async function findLatestCandidate(chunkDir, candidates) {
3002
3124
  let latestM = 0;
3003
3125
  for (const candidateName of candidates) {
3004
3126
  try {
3005
- const s = await stat4(join(chunkDir, candidateName));
3127
+ const s = await stat5(join(chunkDir, candidateName));
3006
3128
  if (s.mtimeMs >= latestM) {
3007
3129
  latestM = s.mtimeMs;
3008
3130
  latest = candidateName;
@@ -3188,23 +3310,34 @@ function parseAccessTracking(accessedCollections) {
3188
3310
  }
3189
3311
  return usage;
3190
3312
  }
3191
- function processCollections(accessedCollections, byCollectionForSSR) {
3313
+ function processCapturedResults(capturedResults, byCollectionForSSR) {
3192
3314
  const subset = {};
3193
3315
  const partial = {};
3194
3316
  try {
3195
3317
  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
- }
3318
+ const ssrResults = capturedResults ?? g.__REROUTE_SSR_RESULTS__;
3319
+ if (!ssrResults || typeof ssrResults !== "object")
3320
+ return;
3321
+ for (const [collection, items] of Object.entries(ssrResults)) {
3322
+ if (Array.isArray(items) && items.length > 0) {
3323
+ subset[collection] = items;
3324
+ const full = byCollectionForSSR?.[collection] || [];
3325
+ partial[collection] = items.length < full.length;
3204
3326
  }
3205
- return { subset, partial };
3206
3327
  }
3207
- } catch {}
3328
+ } catch {
3329
+ return;
3330
+ }
3331
+ if (Object.keys(subset).length === 0)
3332
+ return;
3333
+ return { subset, partial };
3334
+ }
3335
+ function processCollections(accessedCollections, byCollectionForSSR, capturedResults) {
3336
+ const captured = processCapturedResults(capturedResults, byCollectionForSSR);
3337
+ if (captured)
3338
+ return captured;
3339
+ const subset = {};
3340
+ const partial = {};
3208
3341
  const sortByDate = (order) => (a, b) => {
3209
3342
  const da = a?.meta?.date ? Date.parse(String(a.meta.date)) : 0;
3210
3343
  const db = b?.meta?.date ? Date.parse(String(b.meta.date)) : 0;
@@ -3251,7 +3384,7 @@ function createI18nScript(i18n) {
3251
3384
  }
3252
3385
  }
3253
3386
  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>`;
3387
+ 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
3388
  }
3256
3389
  function createSSRExportsScript(pathname) {
3257
3390
  try {
@@ -3388,43 +3521,73 @@ var init_scripts = __esm(() => {
3388
3521
  });
3389
3522
 
3390
3523
  // packages/core/src/ssr/lib/styles.ts
3391
- async function inlineThemeCSS(clientDir, minify = false, isWatchMode = false) {
3524
+ import { createHash } from "node:crypto";
3525
+ import { readdirSync } from "node:fs";
3526
+ function themeCssHash(css) {
3527
+ return createHash("sha1").update(css).digest("hex").slice(0, 8);
3528
+ }
3529
+ function themeCssFileName(css) {
3530
+ return `index.${themeCssHash(css)}.css`;
3531
+ }
3532
+ function themeLink(href) {
3533
+ return `<link rel="stylesheet" href="${href}" data-reroute="theme">`;
3534
+ }
3535
+ function bundlesDirs(clientDir) {
3536
+ return [
3537
+ join(clientDir, "..", ".reroute", "bundles"),
3538
+ join(clientDir, "..", "..", ".reroute", "bundles"),
3539
+ join(clientDir, "..", "..", "..", ".reroute", "bundles"),
3540
+ join(clientDir, "..", "..", "..", "..", ".reroute", "bundles")
3541
+ ];
3542
+ }
3543
+ async function readFileIfExists(path) {
3544
+ if (!await Bun.file(path).exists())
3545
+ return "";
3546
+ const { readFileSync } = await import("node:fs");
3547
+ return readFileSync(path, "utf-8");
3548
+ }
3549
+ async function readThemeFromBundles(clientDir) {
3550
+ for (const dir of bundlesDirs(clientDir)) {
3551
+ try {
3552
+ const hashed = readdirSync(dir).find((name) => HASHED_THEME_RE.test(name));
3553
+ if (hashed) {
3554
+ const css2 = await readFileIfExists(join(dir, hashed));
3555
+ if (css2)
3556
+ return { css: css2, href: `/bundles/${hashed}` };
3557
+ }
3558
+ const css = await readFileIfExists(join(dir, "index.css"));
3559
+ if (css)
3560
+ return { css, href: `/bundles/${themeCssFileName(css)}` };
3561
+ } catch {}
3562
+ }
3563
+ return null;
3564
+ }
3565
+ function bundledThemeCss() {
3566
+ return globalThis.__REROUTE_THEME_CSS__ || "";
3567
+ }
3568
+ async function inlineThemeCSS(clientDir, isWatchMode = false) {
3392
3569
  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
3570
  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
- }
3571
+ return themeLink(`${THEME_CSS_WATCH_HREF}?t=${Date.now()}`);
3414
3572
  }
3415
- if (!cssPath)
3573
+ const fromDisk = await readThemeFromBundles(clientDir);
3574
+ const css = bundledThemeCss() || fromDisk?.css;
3575
+ if (!css)
3416
3576
  return "";
3417
- const { readFileSync } = await import("node:fs");
3418
- const css = readFileSync(cssPath, "utf-8");
3419
- return `<style data-reroute="theme">${minifyCSS(css)}</style>`;
3577
+ if (bundledThemeCss()) {
3578
+ return themeLink(`/bundles/${themeCssFileName(css)}`);
3579
+ }
3580
+ if (fromDisk)
3581
+ return themeLink(fromDisk.href);
3582
+ return "";
3420
3583
  } catch {
3421
3584
  return "";
3422
3585
  }
3423
3586
  }
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 = () => {};
3587
+ var THEME_CSS_WATCH_HREF = "/bundles/index.css", HASHED_THEME_RE;
3588
+ var init_styles = __esm(() => {
3589
+ HASHED_THEME_RE = /^index\.[a-z0-9]{8,}\.css$/i;
3590
+ });
3428
3591
 
3429
3592
  // packages/core/src/ssr/lib/setup.ts
3430
3593
  async function performSSRSetup(options, streaming = false) {
@@ -3493,6 +3656,7 @@ async function performSSRSetupInternal(options, streaming, timeoutState) {
3493
3656
  });
3494
3657
  assertNotTimedOut();
3495
3658
  resetSSRAccessTracking();
3659
+ resetSSRContentResults();
3496
3660
  const bundlePreload = createBundlePreload(bundleUrl);
3497
3661
  const preloadResult = await withSpan("ssr.preload", async (span) => {
3498
3662
  span.setAttribute("pathname", pathname);
@@ -3529,7 +3693,7 @@ async function performSSRSetupInternal(options, streaming, timeoutState) {
3529
3693
  setGlobalCollections(byCollectionForSSR);
3530
3694
  const usingCachedCSS = !!options.cachedThemeCSS;
3531
3695
  const inlineStyleTag = await withSpan("ssr.inline.css", async (span) => {
3532
- const css = options.cachedThemeCSS ? options.cachedThemeCSS : await inlineThemeCSS(clientDir, !streaming, isWatchMode);
3696
+ const css = options.cachedThemeCSS ? options.cachedThemeCSS : await inlineThemeCSS(clientDir, isWatchMode);
3533
3697
  span.setAttributes({
3534
3698
  "reroute.cached": usingCachedCSS,
3535
3699
  "reroute.css.size": css.length
@@ -3568,12 +3732,12 @@ async function performSSRSetupInternal(options, streaming, timeoutState) {
3568
3732
  pending: computeResult.pending
3569
3733
  };
3570
3734
  }
3571
- function generateCollectionScripts(byCollectionForSSR) {
3735
+ function generateCollectionScripts(byCollectionForSSR, capturedResults) {
3572
3736
  try {
3573
3737
  const g = globalThis;
3574
3738
  const acc = g.__REROUTE_SSR_ACCESSED__;
3575
3739
  if (acc) {
3576
- const { subset, partial } = processCollections(acc, byCollectionForSSR);
3740
+ const { subset, partial } = processCollections(acc, byCollectionForSSR, capturedResults);
3577
3741
  if (Object.keys(subset).length > 0) {
3578
3742
  return createCollectionScript(subset, partial);
3579
3743
  }
@@ -3725,13 +3889,16 @@ async function renderSSRDocument(options) {
3725
3889
  }, false);
3726
3890
  const duplicatedData = duplicateQueryParamData(setup2.ssrData);
3727
3891
  setGlobalSSRData(duplicatedData);
3892
+ let capturedResults;
3728
3893
  const appHtml = await withSpan("ssr.render.react", async (span) => {
3729
3894
  const componentWithPathname = cloneElement(rootComponent, {
3730
3895
  pathname,
3731
3896
  searchParams
3732
3897
  });
3733
3898
  span.setAttribute("reroute.pathname", pathname);
3899
+ resetSSRContentResults();
3734
3900
  const html3 = renderToString(componentWithPathname);
3901
+ capturedResults = takeSSRContentResults();
3735
3902
  span.setAttribute("reroute.html.final.size", html3.length);
3736
3903
  return html3;
3737
3904
  });
@@ -3740,7 +3907,7 @@ async function renderSSRDocument(options) {
3740
3907
  span.setAttribute("reroute.template.size", template2.length);
3741
3908
  return template2;
3742
3909
  });
3743
- const collectionScripts = generateCollectionScripts(setup2.byCollectionForSSR);
3910
+ const collectionScripts = generateCollectionScripts(setup2.byCollectionForSSR, capturedResults);
3744
3911
  const config = await loadConfig(cwd);
3745
3912
  const browserTelemetryConfigRaw = config.telemetry?.browser;
3746
3913
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
@@ -3758,7 +3925,7 @@ async function renderSSRDocument(options) {
3758
3925
  if (setup2.metadataResult.statusOverride !== undefined) {
3759
3926
  statusOverride = setup2.metadataResult.statusOverride;
3760
3927
  }
3761
- const extraHead = setup2.bundlePreload + setup2.preloadExtraHead;
3928
+ const extraHead = appendLlmsAlternateHead(setup2.bundlePreload + setup2.preloadExtraHead, pathname, statusOverride || 200, config.llms);
3762
3929
  const combinedHead = dedent([
3763
3930
  dedent(head) || "",
3764
3931
  dedent(extraHead),
@@ -3788,14 +3955,24 @@ async function renderSSRDocument(options) {
3788
3955
  var init_render = __esm(() => {
3789
3956
  init_server2();
3790
3957
  init_config();
3958
+ init_discovery3();
3791
3959
  init_lib();
3792
3960
  init_html();
3793
3961
  });
3794
3962
 
3795
3963
  // packages/core/src/llms/formatter.ts
3964
+ function leadingTitleLine(text) {
3965
+ const first = text.trimStart().split(/\r?\n/, 1)[0]?.trim();
3966
+ if (!first)
3967
+ return;
3968
+ return first.replace(/^#\s+/, "").trim();
3969
+ }
3970
+ function hasLeadingTitle(text, title) {
3971
+ return leadingTitleLine(text) === title.trim();
3972
+ }
3796
3973
  function formatAsText(content) {
3797
3974
  const parts = [];
3798
- if (content.title) {
3975
+ if (content.title && !hasLeadingTitle(content.body, content.title)) {
3799
3976
  parts.push(content.title);
3800
3977
  parts.push("");
3801
3978
  }
@@ -3805,7 +3982,7 @@ function formatAsText(content) {
3805
3982
  }
3806
3983
  function formatAsMarkdown(content) {
3807
3984
  const parts = [];
3808
- if (content.title) {
3985
+ if (content.title && !hasLeadingTitle(content.markdown, content.title)) {
3809
3986
  parts.push(`# ${content.title}`);
3810
3987
  parts.push("");
3811
3988
  }
@@ -3934,6 +4111,9 @@ Formats: .txt | .md | Accept: text/plain | Accept: text/markdown`;
3934
4111
  // packages/core/src/llms/extractor.ts
3935
4112
  import { pathToFileURL as pathToFileURL5 } from "node:url";
3936
4113
  import { renderToStaticMarkup } from "react-dom/server";
4114
+ function stripLayoutChrome(html2) {
4115
+ return html2.replace(/<nav[\s\S]*?<\/nav>/gi, "").replace(/<header[\s\S]*?<\/header>/gi, "").replace(/<aside[\s\S]*?<\/aside>/gi, "");
4116
+ }
3937
4117
  function shouldExcludeRoute(pathname, excludeRoutes) {
3938
4118
  if (!excludeRoutes || excludeRoutes.length === 0) {
3939
4119
  return false;
@@ -4056,10 +4236,7 @@ async function extractSSRContent(pathname, rootComponent, clientDir, cwd, isWatc
4056
4236
  if (appDivMatch) {
4057
4237
  contentHtml = appDivMatch[1];
4058
4238
  }
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, "");
4239
+ contentHtml = stripLayoutChrome(contentHtml);
4063
4240
  return {
4064
4241
  title: extractTitle(html2),
4065
4242
  body: stripHtmlTags(contentHtml),
@@ -4092,37 +4269,154 @@ async function extractContentForLLMs(options) {
4092
4269
  throw new Error("Content not found");
4093
4270
  }
4094
4271
  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("");
4272
+ return formatAsMarkdown({
4273
+ title: content.title,
4274
+ markdown: content.markdown
4275
+ });
4108
4276
  }
4109
- parts.push(content.body);
4110
- return parts.join(`
4111
- `);
4277
+ return formatAsText({
4278
+ title: content.title,
4279
+ body: content.body
4280
+ });
4112
4281
  }
4113
4282
  var init_extractor = __esm(() => {
4114
4283
  init_render();
4115
4284
  });
4116
4285
 
4286
+ // packages/core/src/llms/discovery.ts
4287
+ function yesNo(value) {
4288
+ return value === false ? "no" : "yes";
4289
+ }
4290
+ function formatContentSignal(policy, whenUndefined = "omit") {
4291
+ if (policy === false)
4292
+ return;
4293
+ if (policy === undefined && whenUndefined === "omit")
4294
+ return;
4295
+ const resolved = {
4296
+ search: true,
4297
+ aiInput: true,
4298
+ aiTrain: true,
4299
+ ...policy
4300
+ };
4301
+ return `ai-train=${yesNo(resolved.aiTrain)}, search=${yesNo(resolved.search)}, ai-input=${yesNo(resolved.aiInput)}`;
4302
+ }
4303
+ function markdownTwinPath(pathname) {
4304
+ const path2 = pathname.split("?")[0];
4305
+ if (path2 === "/" || path2 === "")
4306
+ return "/index.md";
4307
+ return `${path2.replace(/\/$/, "")}.md`;
4308
+ }
4309
+ function shouldAdvertiseMarkdownTwin(pathname, llmsConfig) {
4310
+ if (!llmsConfig?.enabled)
4311
+ return false;
4312
+ if (llmsConfig.enableMarkdownExtension === false)
4313
+ return false;
4314
+ if (shouldExcludeRoute(pathname, llmsConfig.excludeRoutes))
4315
+ return false;
4316
+ return true;
4317
+ }
4318
+ function llmsAlternateLinkTag(pathname, llmsConfig) {
4319
+ if (!shouldAdvertiseMarkdownTwin(pathname, llmsConfig))
4320
+ return "";
4321
+ return `<link rel="alternate" type="text/markdown" href="${markdownTwinPath(pathname)}" />`;
4322
+ }
4323
+ function mergeVary(existing, token) {
4324
+ const parts = (existing ?? "").split(",").map((part) => part.trim()).filter(Boolean);
4325
+ if (!parts.some((part) => part.toLowerCase() === token.toLowerCase())) {
4326
+ parts.push(token);
4327
+ }
4328
+ return parts.join(", ");
4329
+ }
4330
+ function appendLinkValues(existing, values) {
4331
+ const current = (existing ?? "").split(",").map((part) => part.trim()).filter(Boolean);
4332
+ for (const value of values) {
4333
+ if (!current.includes(value))
4334
+ current.push(value);
4335
+ }
4336
+ return current.join(", ");
4337
+ }
4338
+ function buildLlmsDiscovery(pathname, llmsConfig) {
4339
+ if (!llmsConfig?.enabled)
4340
+ return null;
4341
+ const linkValues = [];
4342
+ if (shouldAdvertiseMarkdownTwin(pathname, llmsConfig)) {
4343
+ linkValues.push(`<${markdownTwinPath(pathname)}>; rel="alternate"; type="text/markdown"`);
4344
+ }
4345
+ if (llmsConfig.enableIndex !== false) {
4346
+ linkValues.push('</llms.txt>; rel="llms-txt"');
4347
+ }
4348
+ const contentSignal = formatContentSignal(llmsConfig.contentSignal, "default");
4349
+ const vary = llmsConfig.enableContentNegotiation !== false ? "Accept" : undefined;
4350
+ if (linkValues.length === 0 && !contentSignal && !vary)
4351
+ return null;
4352
+ return { linkValues, contentSignal, vary };
4353
+ }
4354
+ function writeHeader(headers2, canonical, value) {
4355
+ const lower = canonical.toLowerCase();
4356
+ if (headers2[lower] !== undefined)
4357
+ headers2[lower] = value;
4358
+ if (headers2[canonical] !== undefined || headers2[lower] === undefined) {
4359
+ headers2[canonical] = value;
4360
+ }
4361
+ }
4362
+ function readHeader(headers2, canonical) {
4363
+ return headers2[canonical] ?? headers2[canonical.toLowerCase()];
4364
+ }
4365
+ function applyLlmsDiscoveryHeaders(headers2, pathname, llmsConfig, status = 200) {
4366
+ if (status < 200 || status >= 300)
4367
+ return;
4368
+ const discovery2 = buildLlmsDiscovery(pathname, llmsConfig);
4369
+ if (!discovery2)
4370
+ return;
4371
+ if (discovery2.linkValues.length > 0) {
4372
+ writeHeader(headers2, "Link", appendLinkValues(readHeader(headers2, "Link"), discovery2.linkValues));
4373
+ }
4374
+ if (discovery2.contentSignal) {
4375
+ writeHeader(headers2, "Content-Signal", discovery2.contentSignal);
4376
+ }
4377
+ if (discovery2.vary) {
4378
+ writeHeader(headers2, "Vary", mergeVary(readHeader(headers2, "Vary"), discovery2.vary));
4379
+ }
4380
+ }
4381
+ function appendLlmsAlternateHead(extraHead, pathname, status, llmsConfig) {
4382
+ if (status !== 200)
4383
+ return extraHead;
4384
+ const tag = llmsAlternateLinkTag(pathname, llmsConfig);
4385
+ return tag ? `${extraHead}
4386
+ ${tag}` : extraHead;
4387
+ }
4388
+ var init_discovery3 = __esm(() => {
4389
+ init_extractor();
4390
+ });
4391
+
4117
4392
  // packages/core/src/llms/index-generator.ts
4118
4393
  var exports_index_generator = {};
4119
4394
  __export(exports_index_generator, {
4120
- generateLLMsIndex: () => generateLLMsIndex,
4121
- discoverStaticRoutes: () => discoverStaticRoutes,
4395
+ discoverCollectionRoutes: () => discoverCollectionRoutes,
4122
4396
  discoverSSRDataRoutes: () => discoverSSRDataRoutes,
4123
- discoverCollectionRoutes: () => discoverCollectionRoutes
4397
+ discoverStaticRoutes: () => discoverStaticRoutes,
4398
+ generateLLMsIndex: () => generateLLMsIndex
4124
4399
  });
4125
4400
  import { pathToFileURL as pathToFileURL6 } from "node:url";
4401
+ function oneLine(value) {
4402
+ return value.replace(/\s+/g, " ").trim();
4403
+ }
4404
+ function stringField(record, key) {
4405
+ const value = record?.[key];
4406
+ if (typeof value !== "string")
4407
+ return;
4408
+ const trimmed = oneLine(value);
4409
+ return trimmed.length > 0 ? trimmed : undefined;
4410
+ }
4411
+ function metaFromUnknown(meta) {
4412
+ if (!meta || typeof meta !== "object")
4413
+ return {};
4414
+ const record = meta;
4415
+ return {
4416
+ title: stringField(record, "title") ?? stringField(record, "name"),
4417
+ description: stringField(record, "description") ?? stringField(record, "excerpt")
4418
+ };
4419
+ }
4126
4420
  async function discoverStaticRoutes(cwd, isWatchMode) {
4127
4421
  const routes = [];
4128
4422
  try {
@@ -4139,8 +4433,11 @@ async function discoverStaticRoutes(cwd, isWatchMode) {
4139
4433
  if (pattern.includes("[404]") || pattern.includes("[layout]") || pattern.includes("[skeleton]") || pattern.includes(":")) {
4140
4434
  continue;
4141
4435
  }
4436
+ const { title, description } = metaFromUnknown(route?.meta);
4142
4437
  routes.push({
4143
- path: pattern
4438
+ path: pattern,
4439
+ title,
4440
+ description
4144
4441
  });
4145
4442
  }
4146
4443
  }
@@ -4163,11 +4460,13 @@ function createRouteEntriesFromItems(items, collection) {
4163
4460
  for (const item of items) {
4164
4461
  const href = String(item.href || "");
4165
4462
  if (href) {
4166
- const title = item.meta?.title || item.meta?.name || item.name;
4463
+ const fromMeta = metaFromUnknown(item.meta);
4464
+ const title = fromMeta.title || (typeof item.name === "string" ? item.name : undefined);
4167
4465
  routes.push({
4168
4466
  path: href,
4169
4467
  section: collection,
4170
- title
4468
+ title,
4469
+ description: fromMeta.description
4171
4470
  });
4172
4471
  }
4173
4472
  }
@@ -4208,7 +4507,7 @@ async function discoverCollectionRoutes(cwd, collections2, isWatchMode, llmsConf
4208
4507
  }
4209
4508
  async function loadRouteModule(cwd, routePath, isWatchMode) {
4210
4509
  try {
4211
- const abs = join(cwd, "src", "client", "routes", routePath);
4510
+ const abs = join(cwd, resolveAppPaths(await loadConfig(cwd)).routesDir, routePath);
4212
4511
  const modUrl = `${pathToFileURL6(abs).href}${isWatchMode ? `?t=${Date.now()}` : ""}`;
4213
4512
  return await import(modUrl);
4214
4513
  } catch {
@@ -4233,9 +4532,13 @@ function createEntriesFromArray(array, routePath) {
4233
4532
  continue;
4234
4533
  const identifier = extractIdentifier(item);
4235
4534
  if (identifier) {
4535
+ const fromItem = metaFromUnknown(item);
4536
+ const fromMeta = metaFromUnknown(item.meta);
4236
4537
  entries.push({
4237
4538
  path: `${routePath}/${identifier}`,
4238
- section: routePath.split("/").filter(Boolean)[0]
4539
+ section: routePath.split("/").filter(Boolean)[0],
4540
+ title: fromItem.title ?? fromMeta.title,
4541
+ description: fromItem.description ?? fromMeta.description
4239
4542
  });
4240
4543
  }
4241
4544
  }
@@ -4341,13 +4644,21 @@ function formatRouteUrl(routePath, baseUrl) {
4341
4644
  function getRouteTitle(route) {
4342
4645
  return route.title || (route.path === "/" ? "Home" : route.path.split("/").pop() || "Page");
4343
4646
  }
4344
- function addRootRoutes(parts, rootRoutes, baseUrl, isSingleCollection) {
4345
- if (isSingleCollection || rootRoutes.length === 0)
4647
+ function formatIndexLine(route, url, summaries) {
4648
+ const link = `- [${getRouteTitle(route)}](${url})`;
4649
+ if (!(summaries && route.description))
4650
+ return link;
4651
+ return `${link}: ${route.description}`;
4652
+ }
4653
+ function summariesEnabled(llmsConfig) {
4654
+ return llmsConfig?.indexSummaries !== false;
4655
+ }
4656
+ function addRootRoutes(parts, rootRoutes, baseUrl, isScoped, llmsConfig) {
4657
+ if (isScoped || rootRoutes.length === 0)
4346
4658
  return;
4659
+ const summaries = summariesEnabled(llmsConfig);
4347
4660
  for (const route of rootRoutes) {
4348
- const title = getRouteTitle(route);
4349
- const url = formatRouteUrl(route.path, baseUrl);
4350
- parts.push(`- [${title}](${url})`);
4661
+ parts.push(formatIndexLine(route, formatRouteUrl(route.path, baseUrl), summaries));
4351
4662
  }
4352
4663
  parts.push("");
4353
4664
  }
@@ -4358,19 +4669,18 @@ function addCollectionSection(parts, collection, routes, baseUrl, llmsConfig) {
4358
4669
  const sectionName = collection.charAt(0).toUpperCase() + collection.slice(1);
4359
4670
  parts.push(`## ${sectionName}`);
4360
4671
  parts.push("");
4672
+ const summaries = summariesEnabled(llmsConfig);
4361
4673
  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})`);
4674
+ parts.push(formatIndexLine(route, `${baseUrl}${route.path}.txt`, summaries));
4365
4675
  }
4366
4676
  parts.push("");
4367
4677
  }
4368
- function shouldIncludeSection(section, isSingleCollection, targetCollection) {
4369
- return !isSingleCollection || section === targetCollection;
4678
+ function shouldIncludeSection(section, isScoped, targetCollection) {
4679
+ return !isScoped || section === targetCollection;
4370
4680
  }
4371
- function addSSRDataSection(parts, routePattern, routes, baseUrl, isSingleCollection, targetCollection, llmsConfig) {
4681
+ function addSSRDataSection(parts, routePattern, routes, baseUrl, isScoped, targetCollection, llmsConfig) {
4372
4682
  const routeSection = routePattern.split("/").filter(Boolean)[0];
4373
- if (!shouldIncludeSection(routeSection, isSingleCollection, targetCollection)) {
4683
+ if (!shouldIncludeSection(routeSection, isScoped, targetCollection)) {
4374
4684
  return;
4375
4685
  }
4376
4686
  const filteredRoutes = routes.filter((r) => !shouldExcludeRoute(r.path, llmsConfig?.excludeRoutes));
@@ -4379,15 +4689,14 @@ function addSSRDataSection(parts, routePattern, routes, baseUrl, isSingleCollect
4379
4689
  const sectionName = routeSection?.charAt(0).toUpperCase() + routeSection?.slice(1) || "Content";
4380
4690
  parts.push(`## ${sectionName}`);
4381
4691
  parts.push("");
4692
+ const summaries = summariesEnabled(llmsConfig);
4382
4693
  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})`);
4694
+ parts.push(formatIndexLine(route, `${baseUrl}${route.path}.txt`, summaries));
4386
4695
  }
4387
4696
  parts.push("");
4388
4697
  }
4389
- function addStaticSection(parts, section, routes, baseUrl, isSingleCollection, targetCollection, collectionsMap, llmsConfig) {
4390
- if (!shouldIncludeSection(section, isSingleCollection, targetCollection)) {
4698
+ function addStaticSection(parts, section, routes, baseUrl, isScoped, targetCollection, collectionsMap, llmsConfig) {
4699
+ if (!shouldIncludeSection(section, isScoped, targetCollection)) {
4391
4700
  return;
4392
4701
  }
4393
4702
  const filteredRoutes = routes.filter((r) => !shouldExcludeRoute(r.path, llmsConfig?.excludeRoutes));
@@ -4396,24 +4705,23 @@ function addStaticSection(parts, section, routes, baseUrl, isSingleCollection, t
4396
4705
  const sectionName = section.charAt(0).toUpperCase() + section.slice(1);
4397
4706
  parts.push(`## ${sectionName}`);
4398
4707
  parts.push("");
4708
+ const summaries = summariesEnabled(llmsConfig);
4399
4709
  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})`);
4710
+ parts.push(formatIndexLine(route, `${baseUrl}${route.path}.txt`, summaries));
4403
4711
  }
4404
4712
  parts.push("");
4405
4713
  }
4406
4714
  async function generateLLMsIndex(options) {
4407
4715
  const { cwd, collections: collections2, baseUrl, isWatchMode, llmsConfig } = options;
4716
+ const targetCollection = options.targetCollection ?? null;
4717
+ const isScoped = targetCollection !== null;
4408
4718
  const parts = [];
4409
4719
  addIndexHeader(parts, llmsConfig);
4410
4720
  const staticRoutes = await discoverStaticRoutes(cwd, isWatchMode);
4411
4721
  const collectionsMap = await discoverCollectionRoutes(cwd, collections2, isWatchMode, llmsConfig);
4412
4722
  const ssrDataRoutes = await discoverSSRDataRoutes(cwd, staticRoutes, isWatchMode);
4413
- const isSingleCollection = collections2.length === 1;
4414
- const targetCollection = isSingleCollection ? collections2[0] : null;
4415
4723
  const { sections, rootRoutes } = groupStaticRoutes(staticRoutes, llmsConfig);
4416
- addRootRoutes(parts, rootRoutes, baseUrl, isSingleCollection);
4724
+ addRootRoutes(parts, rootRoutes, baseUrl, isScoped, llmsConfig);
4417
4725
  for (const [collection, routes] of collectionsMap.entries()) {
4418
4726
  if (routes.length > 0) {
4419
4727
  addCollectionSection(parts, collection, routes, baseUrl, llmsConfig);
@@ -4421,12 +4729,12 @@ async function generateLLMsIndex(options) {
4421
4729
  }
4422
4730
  for (const [routePattern, routes] of ssrDataRoutes.entries()) {
4423
4731
  if (routes.length > 0) {
4424
- addSSRDataSection(parts, routePattern, routes, baseUrl, isSingleCollection, targetCollection, llmsConfig);
4732
+ addSSRDataSection(parts, routePattern, routes, baseUrl, isScoped, targetCollection, llmsConfig);
4425
4733
  }
4426
4734
  }
4427
4735
  for (const [section, routes] of sections.entries()) {
4428
4736
  if (routes.length > 0) {
4429
- addStaticSection(parts, section, routes, baseUrl, isSingleCollection, targetCollection, collectionsMap, llmsConfig);
4737
+ addStaticSection(parts, section, routes, baseUrl, isScoped, targetCollection, collectionsMap, llmsConfig);
4430
4738
  }
4431
4739
  }
4432
4740
  parts.push("---");
@@ -4436,6 +4744,8 @@ async function generateLLMsIndex(options) {
4436
4744
  `);
4437
4745
  }
4438
4746
  var init_index_generator = __esm(() => {
4747
+ init_app_paths();
4748
+ init_config();
4439
4749
  init_extractor();
4440
4750
  });
4441
4751
 
@@ -4489,6 +4799,9 @@ async function discoverAllRoutes(cwd, collections2, isWatchMode, llmsConfig) {
4489
4799
  }
4490
4800
  return allRoutes;
4491
4801
  }
4802
+ function routeBelongsToCollection(path2, collection) {
4803
+ return path2 === `/${collection}` || path2.startsWith(`/${collection}/`);
4804
+ }
4492
4805
  function formatContentBlock(content, routePath, baseUrl) {
4493
4806
  const parts = [];
4494
4807
  const lines = content.split(`
@@ -4558,7 +4871,9 @@ function buildFooter(parts) {
4558
4871
  async function generateLLMsFullContent(options) {
4559
4872
  const { cwd, collections: collections2, baseUrl, isWatchMode, llmsConfig } = options;
4560
4873
  const parts = buildHeader(baseUrl, llmsConfig);
4561
- const allRoutes = await discoverAllRoutes(cwd, collections2, isWatchMode, llmsConfig);
4874
+ const discovered = await discoverAllRoutes(cwd, collections2, isWatchMode, llmsConfig);
4875
+ const targetCollection = options.targetCollection;
4876
+ const allRoutes = targetCollection ? discovered.filter((route) => routeBelongsToCollection(route.path, targetCollection)) : discovered;
4562
4877
  const maxItems = llmsConfig?.maxItems || 1e4;
4563
4878
  const routesToProcess = allRoutes.slice(0, maxItems);
4564
4879
  const extracted = await extractRouteContents(routesToProcess, options);
@@ -4578,6 +4893,7 @@ var init_full_generator = __esm(() => {
4578
4893
 
4579
4894
  // packages/core/src/llms/index.ts
4580
4895
  var init_llms = __esm(() => {
4896
+ init_discovery3();
4581
4897
  init_extractor();
4582
4898
  init_full_generator();
4583
4899
  init_index_generator();
@@ -4744,7 +5060,7 @@ async function discoverRobotsData(cwd, isWatchMode, robotsConfig, sitemapConfig,
4744
5060
  redirectSourcePaths
4745
5061
  };
4746
5062
  }
4747
- var init_discovery3 = () => {};
5063
+ var init_discovery4 = () => {};
4748
5064
 
4749
5065
  // packages/core/src/robots/generator.ts
4750
5066
  function getEffectivePolicies(policies) {
@@ -4757,10 +5073,13 @@ function getEffectivePolicies(policies) {
4757
5073
  }
4758
5074
  ];
4759
5075
  }
5076
+ function robotsDisallowPath(path2) {
5077
+ return path2 === "/" ? "/$" : path2;
5078
+ }
4760
5079
  function getAutoDisallows(discovery2) {
4761
5080
  return new Set([
4762
- ...discovery2.sitemapExcludedRoutes,
4763
- ...discovery2.redirectSourcePaths
5081
+ ...discovery2.sitemapExcludedRoutes.map(robotsDisallowPath),
5082
+ ...discovery2.redirectSourcePaths.map(robotsDisallowPath)
4764
5083
  ]);
4765
5084
  }
4766
5085
  function addAllowDirectives(lines, policy) {
@@ -4787,8 +5106,16 @@ function addDisallowDirectives(lines, policy, autoDisallows) {
4787
5106
  }
4788
5107
  }
4789
5108
  }
4790
- function addPolicyBlock(lines, policy, autoDisallows) {
5109
+ function addContentSignalLine(lines, policy, robotsConfig) {
5110
+ if (policy.userAgent !== "*")
5111
+ return;
5112
+ const value = formatContentSignal(robotsConfig.contentSignal);
5113
+ if (value)
5114
+ lines.push(`Content-Signal: ${value}`);
5115
+ }
5116
+ function addPolicyBlock(lines, policy, autoDisallows, robotsConfig) {
4791
5117
  lines.push(`User-agent: ${policy.userAgent}`);
5118
+ addContentSignalLine(lines, policy, robotsConfig);
4792
5119
  addAllowDirectives(lines, policy);
4793
5120
  addDisallowDirectives(lines, policy, autoDisallows);
4794
5121
  if (policy.crawlDelay !== undefined) {
@@ -4814,7 +5141,7 @@ function generateRobots(discovery2, robotsConfig, sitemapEnabled) {
4814
5141
  const effectivePolicies = getEffectivePolicies(policies);
4815
5142
  const autoDisallows = getAutoDisallows(discovery2);
4816
5143
  for (const policy of effectivePolicies) {
4817
- addPolicyBlock(lines, policy, autoDisallows);
5144
+ addPolicyBlock(lines, policy, autoDisallows, robotsConfig);
4818
5145
  }
4819
5146
  addGlobalCrawlDelay(lines, crawlDelay, effectivePolicies);
4820
5147
  if (customRules) {
@@ -4826,6 +5153,9 @@ function generateRobots(discovery2, robotsConfig, sitemapEnabled) {
4826
5153
  `).trim()}
4827
5154
  `;
4828
5155
  }
5156
+ var init_generator = __esm(() => {
5157
+ init_discovery3();
5158
+ });
4829
5159
 
4830
5160
  // packages/core/src/robots/policies.ts
4831
5161
  function blockAICrawlers(crawlers) {
@@ -4896,17 +5226,20 @@ var init_policies = __esm(() => {
4896
5226
 
4897
5227
  // packages/core/src/robots/index.ts
4898
5228
  var init_robots = __esm(() => {
4899
- init_discovery3();
5229
+ init_discovery4();
5230
+ init_generator();
4900
5231
  init_policies();
4901
5232
  });
4902
5233
 
4903
5234
  // packages/core/src/sitemap/discovery.ts
4904
5235
  var exports_discovery = {};
4905
5236
  __export(exports_discovery, {
4906
- discoverSitemapData: () => discoverSitemapData,
4907
- discoverSSRDataRoutes: () => discoverSSRDataRoutes2,
5237
+ buildSitemapLoc: () => buildSitemapLoc,
5238
+ discoverCollectionContent: () => discoverCollectionContent,
5239
+ discoverDynamicSitemapRoutes: () => discoverDynamicSitemapRoutes,
4908
5240
  discoverRoutes: () => discoverRoutes,
4909
- discoverCollectionContent: () => discoverCollectionContent
5241
+ discoverSSRDataRoutes: () => discoverSSRDataRoutes2,
5242
+ discoverSitemapData: () => discoverSitemapData
4910
5243
  });
4911
5244
  async function loadRoutesModule2(cwd, isWatchMode) {
4912
5245
  let routes = globalThis.__REROUTE_ROUTES__;
@@ -5170,7 +5503,7 @@ function extractIdentifierFromItem(item, routePattern, sitemapConfig) {
5170
5503
  console.warn("[reroute/sitemap] extractUrl failed:", error);
5171
5504
  }
5172
5505
  }
5173
- const identifier = item.version || item.slug || item.id || item.name || item.key;
5506
+ const identifier = item.version || item.slug || item.id || item.name || item.key || item.username;
5174
5507
  return identifier ? identifier : null;
5175
5508
  }
5176
5509
  function extractLastmodFromItem(item, sitemapConfig) {
@@ -5195,14 +5528,41 @@ function extractLastmodFromItem(item, sitemapConfig) {
5195
5528
  }
5196
5529
  return;
5197
5530
  }
5531
+ function buildSitemapLoc(baseUrl, routePattern, identifier) {
5532
+ const base = baseUrl.replace(/\/$/, "");
5533
+ const dynamicParams = routePattern.match(/:[^/]+/g) ?? [];
5534
+ if (dynamicParams.length === 0) {
5535
+ return `${base}${routePattern}/${identifier}`;
5536
+ }
5537
+ if (identifier.startsWith("/")) {
5538
+ return `${base}${identifier}`;
5539
+ }
5540
+ if (dynamicParams.length === 1) {
5541
+ return `${base}${routePattern.replace(/:[^/]+/, identifier)}`;
5542
+ }
5543
+ return `${base}${routePattern.replace(/:[^/]+/, identifier)}`;
5544
+ }
5545
+ function resolveItemLoc(item, baseUrl, routePattern, identifier) {
5546
+ if (typeof item.loc === "string") {
5547
+ if (item.loc.startsWith("http://") || item.loc.startsWith("https://")) {
5548
+ return item.loc;
5549
+ }
5550
+ if (item.loc.startsWith("/")) {
5551
+ return `${baseUrl.replace(/\/$/, "")}${item.loc}`;
5552
+ }
5553
+ }
5554
+ if (typeof item.href === "string" && item.href.startsWith("/")) {
5555
+ return `${baseUrl.replace(/\/$/, "")}${item.href}`;
5556
+ }
5557
+ return buildSitemapLoc(baseUrl, routePattern, identifier);
5558
+ }
5198
5559
  function createEntryFromItem(item, routePattern, baseUrl, sitemapConfig) {
5199
5560
  const identifier = extractIdentifierFromItem(item, routePattern, sitemapConfig);
5200
5561
  if (!identifier) {
5201
5562
  return null;
5202
5563
  }
5203
- const url = `${baseUrl}${routePattern}/${identifier}`;
5204
5564
  const entry = {
5205
- loc: url,
5565
+ loc: resolveItemLoc(item, baseUrl, routePattern, identifier),
5206
5566
  changefreq: sitemapConfig?.changefreq || "weekly",
5207
5567
  priority: sitemapConfig?.priority !== undefined ? sitemapConfig.priority : 0.6
5208
5568
  };
@@ -5212,6 +5572,50 @@ function createEntryFromItem(item, routePattern, baseUrl, sitemapConfig) {
5212
5572
  }
5213
5573
  return entry;
5214
5574
  }
5575
+ async function loadRouteSitemapFn(cwd, route, isWatchMode) {
5576
+ const bundledRoutes = globalThis.__REROUTE_ROUTES__;
5577
+ if (bundledRoutes && Array.isArray(bundledRoutes)) {
5578
+ const bundledRoute = bundledRoutes.find((r) => r?.pattern === route.pattern);
5579
+ const sitemapFn = bundledRoute?.ssr?.sitemap;
5580
+ return typeof sitemapFn === "function" ? sitemapFn : null;
5581
+ }
5582
+ try {
5583
+ const routeModulePath = join(cwd, "src", "client", "routes", route.path);
5584
+ const mod = await import(Bun.pathToFileURL(routeModulePath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
5585
+ const sitemapFn = mod?.ssr?.sitemap;
5586
+ return typeof sitemapFn === "function" ? sitemapFn : null;
5587
+ } catch {
5588
+ return null;
5589
+ }
5590
+ }
5591
+ async function discoverDynamicSitemapRoutes(cwd, dynamicRoutes, isWatchMode, baseUrl, sitemapConfig) {
5592
+ const sitemapRoutes = new Map;
5593
+ const routePromises = dynamicRoutes.map(async (route) => {
5594
+ if (sitemapConfig?.excludeDiscovery?.some((excluded) => route.pattern.startsWith(excluded))) {
5595
+ return null;
5596
+ }
5597
+ const sitemapFn = await loadRouteSitemapFn(cwd, route, isWatchMode);
5598
+ if (!sitemapFn)
5599
+ return null;
5600
+ try {
5601
+ const result = await sitemapFn();
5602
+ const entries = extractEntriesFromData(result, route.pattern, baseUrl, sitemapConfig);
5603
+ if (entries.length > 0) {
5604
+ return { pattern: route.pattern, entries };
5605
+ }
5606
+ } catch (error) {
5607
+ console.warn(`[reroute/sitemap] ssr.sitemap failed for ${route.pattern}:`, error);
5608
+ }
5609
+ return null;
5610
+ });
5611
+ const results = await Promise.all(routePromises);
5612
+ for (const result of results) {
5613
+ if (result) {
5614
+ sitemapRoutes.set(result.pattern, result.entries);
5615
+ }
5616
+ }
5617
+ return sitemapRoutes;
5618
+ }
5215
5619
  async function discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig) {
5216
5620
  const { staticRoutes, dynamicRoutes } = await discoverRoutes(cwd, isWatchMode);
5217
5621
  const collectionsMap = new Map;
@@ -5222,6 +5626,10 @@ async function discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, site
5222
5626
  }
5223
5627
  }
5224
5628
  const ssrDataRoutes = await discoverSSRDataRoutes2(cwd, staticRoutes, isWatchMode, baseUrl, sitemapConfig);
5629
+ const dynamicSitemapRoutes = await discoverDynamicSitemapRoutes(cwd, dynamicRoutes, isWatchMode, baseUrl, sitemapConfig);
5630
+ for (const [pattern, entries] of dynamicSitemapRoutes.entries()) {
5631
+ ssrDataRoutes.set(pattern, entries);
5632
+ }
5225
5633
  return {
5226
5634
  staticRoutes,
5227
5635
  dynamicRoutes,
@@ -5229,7 +5637,7 @@ async function discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, site
5229
5637
  ssrDataRoutes
5230
5638
  };
5231
5639
  }
5232
- var init_discovery4 = () => {};
5640
+ var init_discovery5 = () => {};
5233
5641
 
5234
5642
  // packages/core/src/rss/discovery.ts
5235
5643
  import { pathToFileURL as pathToFileURL7 } from "node:url";
@@ -5345,7 +5753,7 @@ async function discoverCollectionFeedItems(cwd, collection, isWatchMode, baseUrl
5345
5753
  async function discoverSSRDataFeedItems(cwd, routePattern, routePath, isWatchMode, baseUrl, rssConfig) {
5346
5754
  const items = [];
5347
5755
  try {
5348
- const abs = join(cwd, "src", "client", "routes", routePath);
5756
+ const abs = join(cwd, resolveAppPaths(await loadConfig(cwd)).routesDir, routePath);
5349
5757
  const mod = await import(pathToFileURL7(abs).href + (isWatchMode ? `?t=${Date.now()}` : ""));
5350
5758
  const ssr = mod?.ssr;
5351
5759
  const dataFn = ssr?.data;
@@ -5497,7 +5905,7 @@ async function discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfi
5497
5905
  }
5498
5906
  const ssrDataFeeds = new Map;
5499
5907
  const bundledRoutes = globalThis.__REROUTE_ROUTES__;
5500
- const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery4(), exports_discovery));
5908
+ const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery5(), exports_discovery));
5501
5909
  const { staticRoutes } = await discoverRoutes2(cwd, isWatchMode);
5502
5910
  if (bundledRoutes && Array.isArray(bundledRoutes)) {
5503
5911
  const routePromises = staticRoutes.map(async (route) => {
@@ -5554,7 +5962,10 @@ async function discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfi
5554
5962
  ssrDataFeeds
5555
5963
  };
5556
5964
  }
5557
- var init_discovery5 = () => {};
5965
+ var init_discovery6 = __esm(() => {
5966
+ init_app_paths();
5967
+ init_config();
5968
+ });
5558
5969
 
5559
5970
  // packages/core/src/rss/generator.ts
5560
5971
  function generateRSSXML(feed, options = {}) {
@@ -5667,7 +6078,7 @@ function escapeXml(unsafe) {
5667
6078
 
5668
6079
  // packages/core/src/rss/index.ts
5669
6080
  var init_rss = __esm(() => {
5670
- init_discovery5();
6081
+ init_discovery6();
5671
6082
  });
5672
6083
 
5673
6084
  // packages/core/src/sitemap/generator.ts
@@ -5812,12 +6223,12 @@ function escapeXml2(unsafe) {
5812
6223
  return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
5813
6224
  }
5814
6225
  var DEFAULT_MAX_URLS = 50000;
5815
- var init_generator = () => {};
6226
+ var init_generator2 = () => {};
5816
6227
 
5817
6228
  // packages/core/src/sitemap/index.ts
5818
6229
  var init_sitemap = __esm(() => {
5819
- init_discovery4();
5820
- init_generator();
6230
+ init_discovery5();
6231
+ init_generator2();
5821
6232
  });
5822
6233
 
5823
6234
  // packages/core/src/ssr/stream.ts
@@ -5895,15 +6306,16 @@ async function renderSSRDocumentStream(options) {
5895
6306
  const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${pageLang}"`) : `${attrs} lang="${pageLang}"`;
5896
6307
  return `<html${newAttrs}>`;
5897
6308
  });
5898
- const extraHead = setup2.bundlePreload + setup2.preloadExtraHead + setup2.metadataResult.perPageHead;
5899
- if (/<title[\s\S]*?<\/title>/i.test(extraHead)) {
6309
+ const extraHeadBase = setup2.bundlePreload + setup2.preloadExtraHead + setup2.metadataResult.perPageHead;
6310
+ if (/<title[\s\S]*?<\/title>/i.test(extraHeadBase)) {
5900
6311
  headWithLang = headWithLang.replace(/<title[\s\S]*?<\/title>/i, "");
5901
6312
  }
5902
- if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHead)) {
6313
+ if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHeadBase)) {
5903
6314
  headWithLang = headWithLang.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
5904
6315
  }
5905
- headWithLang = removeOverriddenMetaTags(headWithLang, extraHead);
6316
+ headWithLang = removeOverriddenMetaTags(headWithLang, extraHeadBase);
5906
6317
  const config = await loadConfig(cwd);
6318
+ const extraHead = appendLlmsAlternateHead(extraHeadBase, pathname, statusOverride || 200, config.llms);
5907
6319
  const browserTelemetryConfigRaw = config.telemetry?.browser;
5908
6320
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
5909
6321
  const browserTelemetryConfig = serializeBrowserTelemetryConfig2(browserTelemetryConfigRaw);
@@ -6161,6 +6573,7 @@ function unescapeHtmlEntities(str) {
6161
6573
  var init_stream = __esm(() => {
6162
6574
  init_server2();
6163
6575
  init_config();
6576
+ init_discovery3();
6164
6577
  init_lib();
6165
6578
  init_html();
6166
6579
  init_imports();
@@ -6175,6 +6588,7 @@ var init_ssr = __esm(() => {
6175
6588
 
6176
6589
  // packages/core/src/index.ts
6177
6590
  var init_src = __esm(() => {
6591
+ init_app_paths();
6178
6592
  init_bundler();
6179
6593
  init_config();
6180
6594
  init_content();
@@ -6194,137 +6608,156 @@ var init_core = __esm(() => {
6194
6608
  init_core();
6195
6609
 
6196
6610
  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,
6611
+ AI_CRAWLERS,
6612
+ DEFAULT_APP_SERVER,
6613
+ DEFAULT_APP_SRC,
6326
6614
  DEFAULT_COOKIE,
6327
- AI_CRAWLERS
6615
+ DEFAULT_LOCALE,
6616
+ DEFAULT_LOCALES_DIR,
6617
+ DefaultOGTemplate,
6618
+ LRUCache,
6619
+ SEARCH_CRAWLERS,
6620
+ SSRDataCache,
6621
+ TTLCache,
6622
+ acceptsBrotli,
6623
+ acceptsGzip,
6624
+ allowAICrawlers,
6625
+ allowSearchCrawlers,
6626
+ appendLlmsAlternateHead,
6627
+ applyIndexTemplate,
6628
+ applyLlmsDiscoveryHeaders,
6629
+ basename,
6630
+ blockAICrawlers,
6631
+ blockAITrainingCrawlers,
6632
+ blockSearchCrawlers,
6633
+ buildHeadFromMeta,
6634
+ buildLlmsDiscovery,
6635
+ buildLocaleCookie,
6636
+ buildSitemapLoc,
6637
+ cleanupPathScopedSSRData,
6638
+ clearSSRModuleStores,
6639
+ clearWatchImportCache,
6640
+ compareRouteSpecificity,
6641
+ compressStreamIfAccepted,
6642
+ computeContentData,
6643
+ computeLayoutData,
6644
+ computeRouteData,
6645
+ computeSSRData,
6646
+ computeSSRDataForPath,
6647
+ contentKey,
6648
+ contentNegotiateRedirect,
6649
+ createBundlePreload,
6650
+ createCollectionScript,
6651
+ createDataScript,
6652
+ createFeedsScript,
6653
+ createLayoutCacheKey,
6654
+ createLayoutDataKey,
6655
+ createLlmsScript,
6656
+ createTranslator,
6657
+ deduplicateMetaTags,
6658
+ defineConfig,
6659
+ discoverCollectionContent,
6660
+ discoverCollections,
6661
+ discoverDynamicSitemapRoutes,
6662
+ discoverI18n,
6663
+ discoverRSSData,
6664
+ discoverRobotsData,
6665
+ discoverRoutes,
6666
+ discoverRoutesForRobots,
6667
+ discoverSSRDataFeedItems,
6668
+ discoverSSRDataRoutes2 as discoverSSRDataRoutes,
6669
+ discoverSitemapData,
6670
+ duplicateQueryParamData,
6671
+ dynamicImport,
6672
+ escapeJsonForScript,
6673
+ escapeXml2 as escapeXml,
6674
+ extname,
6675
+ extractContentForLLMs,
6676
+ extractPageMetadata,
6677
+ extractParamsFromPath,
6678
+ extractTitle,
6679
+ findOGImageForPath,
6680
+ formatAsMarkdown,
6681
+ formatAsText,
6682
+ formatContentSignal,
6683
+ formatMessage,
6684
+ generateAtomXML,
6685
+ generateCollectionScripts,
6686
+ generateContentHash,
6687
+ generateFeed,
6688
+ generateHydrationScripts,
6689
+ generateLLMsFooter,
6690
+ generateLLMsFullContent,
6691
+ generateLLMsIndex,
6692
+ generateOGImageMetaTags,
6693
+ generateRSSXML,
6694
+ generateRobots,
6695
+ generateSitemap,
6696
+ generateSitemapIndexXML,
6697
+ generateSitemapXML,
6698
+ getContentMeta,
6699
+ getMatchingLayouts,
6700
+ getMessage,
6701
+ getMimeType,
6702
+ getPatternDepth,
6703
+ getRedirectSourcePaths,
6704
+ getSitemapExcludedRoutes,
6705
+ gzipIfAccepted,
6706
+ hreflangTags,
6707
+ htmlToMarkdown,
6708
+ importContentModuleForPath,
6709
+ importFromReroute,
6710
+ inlineThemeCSS,
6711
+ isCompressible,
6712
+ isThenable,
6713
+ join,
6714
+ listContentFiles,
6715
+ llmsAlternateLinkTag,
6716
+ loadCollections,
6717
+ loadConfig,
6718
+ loadIndexHtml,
6719
+ loadOGImageComponent,
6720
+ loadRoutesModule,
6721
+ localizeContentHref,
6722
+ localizeHref,
6723
+ looksLikeLocale,
6724
+ lookupMessage,
6725
+ markdownTwinPath,
6726
+ matchRoutePattern,
6727
+ matchRoutes,
6728
+ mergeLayoutData,
6729
+ mergeVary,
6730
+ negotiateLocale,
6731
+ normalizePathname,
6732
+ parseContentPath,
6733
+ parseCookieValue,
6734
+ performSSRSetup,
6735
+ preloadContentModule,
6736
+ processCollections,
6737
+ removeOverriddenMetaTags,
6738
+ renderOGImageToPNG,
6739
+ renderSSRDocument,
6740
+ renderSSRDocumentStream,
6741
+ resetSSRAccessTracking,
6742
+ resetSSRContentResults,
6743
+ resolveAppPaths,
6744
+ resolveLocale,
6745
+ seedSSRModuleForPath,
6746
+ setGlobalCollections,
6747
+ setGlobalSSRData,
6748
+ shouldAdvertiseMarkdownTwin,
6749
+ shouldExcludeRoute,
6750
+ splitTemplate,
6751
+ ssrCache,
6752
+ statusCache,
6753
+ stripEnd,
6754
+ stripHtmlTags,
6755
+ stripLayoutChrome,
6756
+ stripStart,
6757
+ takeSSRContentResults,
6758
+ toBytes,
6759
+ toOgLocale,
6760
+ toPromise
6328
6761
  };
6329
6762
 
6330
- //# debugId=526DAF189345000E64756E2164756E21
6763
+ //# debugId=BAAD947D1936157964756E2164756E21