boltdocs 3.3.5 → 3.4.0

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 (126) hide show
  1. package/dist/{adapters-BKzKe2mO.mjs → adapters-BXiBWAKs.mjs} +1 -1
  2. package/dist/{adapters-DwDTQoCG.cjs → adapters-Czl3WtQt.cjs} +1 -1
  3. package/dist/{build-B672n0hL.cjs → build-CNkXRdk8.cjs} +1 -1
  4. package/dist/{build-BVoMHMhw.mjs → build-CqUBsXVC.mjs} +1 -1
  5. package/dist/client/index.cjs +245 -56
  6. package/dist/client/index.d.cts +3 -3
  7. package/dist/client/index.d.ts +3 -3
  8. package/dist/client/index.js +246 -60
  9. package/dist/client/mdx.cjs +1 -1
  10. package/dist/client/mdx.js +1 -1
  11. package/dist/client/primitives.cjs +5 -5
  12. package/dist/client/primitives.d.cts +92 -42
  13. package/dist/client/primitives.d.ts +101 -51
  14. package/dist/client/primitives.js +4 -4
  15. package/dist/client/router.cjs +1 -1
  16. package/dist/client/router.d.cts +1 -1
  17. package/dist/client/router.d.ts +1 -1
  18. package/dist/client/router.js +1 -1
  19. package/dist/client/theme/reset.css +41 -0
  20. package/dist/config-B3SEoVjG.cjs +7 -0
  21. package/dist/{config-PLvresCv.cjs → config-Bfakeadu.cjs} +1 -1
  22. package/dist/config-CTcfF-0c.mjs +7 -0
  23. package/dist/dev-D1DmOSjn.mjs +6 -0
  24. package/dist/dev-DH6cSge8.cjs +6 -0
  25. package/dist/{docs-layout-CbZ7LDRe.js → docs-layout-CmntYM6p.js} +46 -147
  26. package/dist/{docs-layout-vzfXed1Q.cjs → docs-layout-DIgxJ5c7.cjs} +23 -130
  27. package/dist/{doctor-DMECtdK6.cjs → doctor-BLxm2alc.cjs} +1 -1
  28. package/dist/{doctor-FuFY1jBz.cjs → doctor-Dd-JMTRo.cjs} +1 -1
  29. package/dist/{doctor-i8Qmd8DJ.mjs → doctor-DogHujrP.mjs} +1 -1
  30. package/dist/{image-Hnaa2bJd.cjs → image-Bke2ojW1.cjs} +3 -3
  31. package/dist/{image-B-NDSDuY.js → image-CaY2w0ua.js} +2 -1
  32. package/dist/index--xbYbT8N.d.ts +343 -0
  33. package/dist/{index-Bg-JtZeK.d.cts → index-B_o5y34l.d.cts} +112 -13
  34. package/dist/{index-B3o307nd.d.ts → index-Bx0CUd7Q.d.ts} +112 -13
  35. package/dist/index-RK7W_Fxy.d.cts +343 -0
  36. package/dist/{link-CgdI6O2o.js → link-CSe_oD8Y.js} +137 -139
  37. package/dist/{link-vZjmD-es.cjs → link-Xb69Oy2F.cjs} +144 -169
  38. package/dist/{mdx-D0Absdq5.cjs → mdx-BCOrMd-P.cjs} +68 -16
  39. package/dist/{mdx-BRT71V5Q.js → mdx-BijiEbkp.js} +62 -15
  40. package/dist/{native-nLA4Jr0T.cjs → native-BbtRkce5.cjs} +1 -1
  41. package/dist/node/cli-entry.cjs +1 -1
  42. package/dist/node/cli-entry.mjs +1 -1
  43. package/dist/node/highlight.d.cts +2 -2
  44. package/dist/node/highlight.d.mts +2 -2
  45. package/dist/node/index.cjs +1 -1
  46. package/dist/node/index.d.cts +19 -37
  47. package/dist/node/index.d.mts +20 -38
  48. package/dist/node/index.mjs +1 -1
  49. package/dist/node/mdx/shiki-adapter.cjs +1 -1
  50. package/dist/node/mdx/shiki-adapter.d.cts +7 -2
  51. package/dist/node/mdx/shiki-adapter.d.mts +7 -2
  52. package/dist/node/mdx/shiki-adapter.mjs +1 -1
  53. package/dist/node-BgiLCa0I.cjs +39 -0
  54. package/dist/node-Da3tYBHo.mjs +39 -0
  55. package/dist/{package-CNqjEYE1.cjs → package-D1gVs5gQ.cjs} +1 -1
  56. package/dist/{package-sdcKhDhe.mjs → package-YgQJn3Yh.mjs} +1 -1
  57. package/dist/pages-external-B_r6gvqP.cjs +6 -0
  58. package/dist/pages-external-jmK7AHaO.mjs +6 -0
  59. package/dist/{parser-CD8Oo8qh.mjs → parser-CvNZc5s3.mjs} +1 -1
  60. package/dist/{parser-vPaKvzLp.cjs → parser-DJLWTiO-.cjs} +1 -1
  61. package/dist/plugin-DW9K2fW5.mjs +69 -0
  62. package/dist/plugin-NwGKyTJX.cjs +69 -0
  63. package/dist/{plugin-context-DuSg-Hax.mjs → plugin-context-COh-cbsW.mjs} +1 -1
  64. package/dist/{plugin-context-CscLcXjH.cjs → plugin-context-FIHaWn6r.cjs} +2 -2
  65. package/dist/{plugin-lifecycle-BywrEoWK.cjs → plugin-lifecycle-D9fTRaWY.cjs} +1 -1
  66. package/dist/{registry-BbB6NqSv.d.cts → registry-BFmzj1yg.d.mts} +1 -1
  67. package/dist/{registry-sJqDv0kE.d.mts → registry-BoswPzYV.d.cts} +1 -1
  68. package/dist/{resolve-C5rT6B21.mjs → resolve-5puUe7eS.mjs} +1 -1
  69. package/dist/{resolve-BelytNYR.cjs → resolve-CF4ZLfqx.cjs} +1 -1
  70. package/dist/route-paths-B6ocUfNY.cjs +6 -0
  71. package/dist/route-paths-DyDji4bX.mjs +6 -0
  72. package/dist/{router-CZBxMRAH.js → router-B5e8k4qK.js} +175 -10
  73. package/dist/{router-C3kygdRK.cjs → router-DKC0Lu0n.cjs} +204 -9
  74. package/dist/{routes-C3_w9fLX.cjs → routes-D55M8UrH.cjs} +1 -1
  75. package/dist/routes-DdE6Lfcl.cjs +6 -0
  76. package/dist/routes-_I_8PQYF.mjs +6 -0
  77. package/dist/{search-dialog-x_qHU8ty.cjs → search-dialog-BOQRHKTb.cjs} +197 -24
  78. package/dist/{search-dialog-BqkzDTq2.js → search-dialog-BXil4_7P.js} +190 -29
  79. package/dist/search-dialog-CwlBd-Mu.cjs +747 -0
  80. package/dist/{search-dialog-B9mdxsUC.js → search-dialog-D3Obh3eA.js} +1 -1
  81. package/dist/search-dialog-DeplpVEB.js +717 -0
  82. package/dist/{search-dialog-DCtm2dyR.cjs → search-dialog-cHXR5zhL.cjs} +1 -1
  83. package/dist/server/index.cjs +1 -1
  84. package/dist/server/index.d.mts +1 -1
  85. package/dist/server/index.mjs +1 -1
  86. package/dist/ssg-static-options-Br1_u9qp.mjs +6 -0
  87. package/dist/ssg-static-options-CVvGKM8i.cjs +6 -0
  88. package/dist/types-58Ac3UGI.d.cts +114 -0
  89. package/dist/types-BwnGf-1E.d.mts +114 -0
  90. package/dist/virtual-modules-C4-qxFlL.cjs +40 -0
  91. package/dist/virtual-modules-DiWUKJGP.mjs +40 -0
  92. package/package.json +8 -5
  93. package/src/shared/types.ts +133 -987
  94. package/dist/config-CrsQJHQz.cjs +0 -7
  95. package/dist/config-DC0nMMk7.mjs +0 -7
  96. package/dist/dev-B49V6O6p.mjs +0 -6
  97. package/dist/dev-DbuhNcF5.cjs +0 -6
  98. package/dist/index-CgWkOCCn.d.cts +0 -1193
  99. package/dist/index-CuNSD3E2.d.ts +0 -1193
  100. package/dist/node-BljvHMpS.cjs +0 -23
  101. package/dist/node-CWxGw4H4.mjs +0 -23
  102. package/dist/pages-external-BBw8ObVK.mjs +0 -6
  103. package/dist/pages-external-DPiPFxxP.cjs +0 -6
  104. package/dist/plugin-BPcm1cU0.mjs +0 -69
  105. package/dist/plugin-WUhxnpko.cjs +0 -69
  106. package/dist/routes-C0kb4ue6.cjs +0 -6
  107. package/dist/routes-C4wrLWwu.mjs +0 -6
  108. package/dist/search-dialog-Bp_ouN1c.cjs +0 -550
  109. package/dist/search-dialog-an2BNMj6.js +0 -526
  110. package/dist/types-Db6zToZH.d.mts +0 -975
  111. package/dist/types-o7iZ2BAR.d.cts +0 -975
  112. package/dist/virtual-modules-B2X4Ht2r.mjs +0 -39
  113. package/dist/virtual-modules-DPsdHKcu.cjs +0 -39
  114. /package/dist/{audit-CMc_ydRr.mjs → audit-CYAkXXvP.mjs} +0 -0
  115. /package/dist/{audit-CHkGiV3c.cjs → audit-DxCZZTuX.cjs} +0 -0
  116. /package/dist/{csp-BiGAG8aF.cjs → csp-B-gc2Iha.cjs} +0 -0
  117. /package/dist/{csp-D0BOH8ae.mjs → csp-f8DOcI_7.mjs} +0 -0
  118. /package/dist/{generator-BCrZL53x.cjs → generator-CBAPKY6r.cjs} +0 -0
  119. /package/dist/{generator-CFukoGa0.mjs → generator-MRpn-yp6.mjs} +0 -0
  120. /package/dist/{handler-Lex5DbvG.mjs → handler-DBZqoWt2.mjs} +0 -0
  121. /package/dist/{handler-Ch-Q9NAB.cjs → handler-ryZR9Q41.cjs} +0 -0
  122. /package/dist/{index-HAwIo4nZ.d.mts → index-CPr34I2C.d.mts} +0 -0
  123. /package/dist/{native-BYKMke79.mjs → native-DZ6WMwjG.mjs} +0 -0
  124. /package/dist/{native-BOet8hpE.cjs → native-DeKxny_T.cjs} +0 -0
  125. /package/dist/{update-check-BXD1atVv.mjs → update-check-BXx8te9F.mjs} +0 -0
  126. /package/dist/{update-check-DFQZyoSU.cjs → update-check-CiIeC7CX.cjs} +0 -0
@@ -3,18 +3,19 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { A as Languages, B as TextAlignStart, C as FaceBad, F as Moon, K as BoltdocsProvider, L as Pencil, N as Menu, O as Home, P as Monitor, S as ExternalLink, T as FaceRegular, U as ConfigContext, V as X, W as useConfig, _ as ChevronLeft, a as useViewTransition, b as Copy, c as RoutesProvider, d as resolvePublicAssetUrl, g as ChevronDown, h as Check, i as startViewTransition, m as ArrowLeft, o as cn, q as useBoltdocsContext, s as useLocalizedTo, t as Link, u as normalizePath, v as ChevronRight, w as FaceGood, y as CircleHelp, z as Sun } from "../link-CgdI6O2o.js";
7
- import { A as useRouteData, B as normalizeBasename, C as Outlet, D as useMatches, E as useLocation, F as PrefetchContext, I as RouteDataContext, L as defaultNavigate, M as LocationProvider, N as MatchesContext, O as useNavigate, P as NavigateContext, R as addBasename, S as resolveRouteBranch, T as useLoaderData, V as stripBasename, _ as stripSiteProtocol, a as getConfiguredVersions, b as matchRouteBranch, c as hasUriScheme, d as isConfiguredVersion, f as normalizeUrlBase, g as splitUrlReference, h as resolveUrlReference, i as getConfiguredLocales, j as LocationContext, k as usePrefetch, l as hasUrlBase, m as parseUrlReference, n as buildUrl, o as getVersionPrefixSegments, p as normalizeUrlPath, r as classifyUrlPath, s as getVersionSegments, t as addUrlBase, u as isConfiguredLocale, v as stripUrlBase, w as OutletContext, x as matchRouteBranchWithParams, y as RouteRenderer, z as hasBasename } from "../router-CZBxMRAH.js";
8
- import { _ as useTheme, g as ThemeProvider } from "../image-B-NDSDuY.js";
9
- import { a as useCopyButton, i as useExpandable, n as Timeline, o as copyToClipboard, r as useCodeBlockFeedback, t as mdx_components_default } from "../mdx-BRT71V5Q.js";
10
- import { A as UIProvider, C as IconRenderer, E as Menu$1, O as ButtonGroup, S as useSidebar, T as Tabs$1, f as PageNav$1, j as useUI, k as Breadcrumbs$2, m as OnThisPage$1, n as Sidebar$1, t as DocsLayout$1, w as resolveIcon, x as useSearchHighlight } from "../docs-layout-CbZ7LDRe.js";
11
- import { i as useRoutes, n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-an2BNMj6.js";
12
- import { i as ErrorBoundary$1, n as Navbar$1, o as Button$1, r as Github } from "../search-dialog-BqkzDTq2.js";
6
+ import { B as X, C as FaceGood, D as Home, H as BoltdocsProvider, I as Pencil, M as Menu$1, N as Monitor, P as Moon, R as Sun, S as FaceBad, U as useBoltdocsContext, _ as ChevronRight, a as useLocalizedTo, g as ChevronLeft, h as ChevronDown, i as cn, k as Languages, l as normalizePath, m as Check, o as RoutesProvider, p as ArrowLeft, t as Link, u as resolvePublicAssetUrl, v as CircleHelp, w as FaceRegular, x as ExternalLink, y as Copy, z as TextAlignStart } from "../link-CSe_oD8Y.js";
7
+ import { A as useRouteData, B as ConfigContext, C as Outlet, D as useMatches, E as useLocation, F as PrefetchContext, G as normalizeBasename, I as RouteDataContext, K as stripBasename, L as defaultNavigate, M as LocationProvider, N as MatchesContext, O as useNavigate, P as NavigateContext, R as startViewTransition, S as resolveRouteBranch, T as useLoaderData, U as addBasename, V as useConfig, W as hasBasename, _ as stripSiteProtocol, a as getConfiguredVersions, b as matchRouteBranch, c as hasUriScheme, d as isConfiguredVersion, f as normalizeUrlBase, g as splitUrlReference, h as resolveUrlReference, i as getConfiguredLocales, j as LocationContext, k as usePrefetch, l as hasUrlBase, m as parseUrlReference, n as buildUrl, o as getVersionPrefixSegments, p as normalizeUrlPath, r as classifyUrlPath, s as getVersionSegments, t as addUrlBase, u as isConfiguredLocale, v as stripUrlBase, w as OutletContext, x as matchRouteBranchWithParams, y as RouteRenderer, z as useViewTransition } from "../router-B5e8k4qK.js";
8
+ import { _ as useTheme, g as ThemeProvider } from "../image-CaY2w0ua.js";
9
+ import { a as useExpandable, i as useCodeBlockFeedback, n as Timeline, o as useCopyButton, r as formatDeterministicDate, s as copyToClipboard, t as mdx_components_default } from "../mdx-BijiEbkp.js";
10
+ import { A as useUI, C as resolveIcon, D as ButtonGroup, O as Breadcrumbs$2, S as IconRenderer, T as Menu$2, f as PageNav$1, k as UIProvider, m as OnThisPage$1, n as Sidebar$1, t as DocsLayout$1, w as Tabs$1, x as useSidebar } from "../docs-layout-CmntYM6p.js";
11
+ import { a as useRoutes, i as InternalErrorBoundary, r as useSearch, t as SearchDialog } from "../search-dialog-DeplpVEB.js";
12
+ import { a as Github, c as Button$1, i as Navbar$1, o as ErrorBoundary$1, r as useSearchHighlight } from "../search-dialog-BXil4_7P.js";
13
13
  import { ViteReactSSG } from "@bdocs/ssg";
14
14
  import { Suspense, createContext, isValidElement, lazy, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
15
15
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
16
  import { Button } from "react-aria-components";
17
17
  import * as ReactHelmetAsync from "react-helmet-async";
18
+ import pluginSlots from "virtual:boltdocs-client-registry";
18
19
  import virtualCustomComponents from "virtual:boltdocs-mdx-components";
19
20
  import fetchPageSource from "virtual:boltdocs-page-source";
20
21
  import UserLayout from "virtual:boltdocs-layout";
@@ -450,6 +451,20 @@ function useCurrentPostData() {
450
451
  return use(CurrentPostContext);
451
452
  }
452
453
 
454
+ //#endregion
455
+ //#region src/client/components/plugin-floating-slots.tsx
456
+ const floatingComponents = (pluginSlots["floating:after"] ?? []).map((entry) => ({
457
+ id: entry.id,
458
+ Component: lazy(entry.load)
459
+ }));
460
+ function PluginFloatingSlots() {
461
+ if (floatingComponents.length === 0) return null;
462
+ return /* @__PURE__ */ jsx(Suspense, {
463
+ fallback: null,
464
+ children: floatingComponents.map(({ id, Component }) => /* @__PURE__ */ jsx(Component, {}, id))
465
+ });
466
+ }
467
+
453
468
  //#endregion
454
469
  //#region src/client/ssg/boltdocs-shell.tsx
455
470
  /**
@@ -581,9 +596,9 @@ function BoltdocsShell({ config, routes, components = {}, collectionsData, conte
581
596
  siteDescription: config.theme?.description,
582
597
  routes
583
598
  }),
584
- /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx("div", {
599
+ /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsxs("div", {
585
600
  className: cn("boltdocs-shell-content h-screen overflow-hidden", contentClassName),
586
- children: /* @__PURE__ */ jsx(Outlet, {})
601
+ children: [/* @__PURE__ */ jsx(Outlet, {}), /* @__PURE__ */ jsx(PluginFloatingSlots, {})]
587
602
  }) })
588
603
  ]
589
604
  })
@@ -636,12 +651,12 @@ function DocPage({ route, content: Content, mdxComponents: propComponents }) {
636
651
  /**
637
652
  * Renders an MDX page by consuming pre-loaded route data.
638
653
  *
639
- * - If the route belongs to a collection (`data.collection` is set), wraps
640
- * the content with `CurrentPostProvider` so that `usePost()` (called without
641
- * a slug) can read the current post's data from context.
654
+ * - If the route belongs to a collection, wraps the content with
655
+ * `CurrentPostProvider` so that `usePost()` (called without a slug) can read
656
+ * the current post's data from context.
642
657
  * - Otherwise, renders the standard `DocPage` layout.
643
658
  */
644
- function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostComponent: CollectionPost }) {
659
+ function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostComponent: CollectionPost, collection, route: routeProp }) {
645
660
  const data = useLoaderData();
646
661
  const mdxComponents = {
647
662
  ...useMdxComponents(),
@@ -649,30 +664,37 @@ function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostCo
649
664
  };
650
665
  if (!MDXComponent) return null;
651
666
  const collectionData = data || {};
652
- if (!!collectionData?.collection && !!collectionData?.route) {
667
+ const isCollection = collection ? true : !!collectionData?.collection && !!collectionData?.route;
668
+ /**
669
+ * The loader's own copy of the route, falling back to the route table so the
670
+ * first client render has the same metadata the server used.
671
+ */
672
+ const postRoute = collectionData.route ?? routeProp;
673
+ const postHeadings = collectionData.headings ?? routeProp?.headings ?? [];
674
+ if (isCollection) {
653
675
  const postElement = CollectionPost ? /* @__PURE__ */ jsx(CollectionPost, {
654
676
  MDXComponent,
655
677
  mdxComponents
656
678
  }) : /* @__PURE__ */ jsx(DocPage, {
657
679
  route: {
658
- path: collectionData.route?.path || "",
659
- filePath: collectionData.route?.filePath || "",
660
- title: collectionData.route?.title,
661
- description: collectionData.route?.description,
662
- headings: collectionData.headings || [],
663
- locale: collectionData.route?.locale,
664
- version: collectionData.route?.version,
665
- lastUpdated: collectionData.route?.lastUpdated,
666
- frontmatter: collectionData.route?.frontmatter
680
+ path: postRoute?.path || "",
681
+ filePath: postRoute?.filePath || "",
682
+ title: postRoute?.title,
683
+ description: postRoute?.description,
684
+ headings: postHeadings,
685
+ locale: postRoute?.locale,
686
+ version: postRoute?.version,
687
+ lastUpdated: postRoute?.lastUpdated,
688
+ frontmatter: postRoute?.frontmatter
667
689
  },
668
690
  content: MDXComponent,
669
691
  mdxComponents
670
692
  });
671
693
  return /* @__PURE__ */ jsx(CurrentPostProvider, {
672
694
  value: {
673
- route: collectionData.route,
674
- headings: collectionData.headings,
675
- collection: collectionData.collection
695
+ route: postRoute,
696
+ headings: postHeadings,
697
+ collection: collection ?? collectionData.collection
676
698
  },
677
699
  children: postElement
678
700
  });
@@ -825,14 +847,14 @@ function CopyMarkdown({ content, mdxRaw, route, className }) {
825
847
  className: cn("hidden md:flex items-center gap-2 px-5 py-2 bg-transparent text-[0.8125rem] font-semibold h-9 shrink-0 outline-none select-none cursor-pointer border-none", "text-body transition-all duration-300 hover:bg-primary-500/5", copied && "text-emerald-500 hover:bg-emerald-500/5"),
826
848
  children: [copied ? /* @__PURE__ */ jsx(Check, { size: 16 }) : /* @__PURE__ */ jsx(Copy, { size: 16 }), copied ? "Copied!" : "Copy Markdown"]
827
849
  }),
828
- /* @__PURE__ */ jsxs(Menu$1.Trigger, {
850
+ /* @__PURE__ */ jsxs(Menu$2.Trigger, {
829
851
  placement: "bottom end",
830
852
  children: [/* @__PURE__ */ jsx(Button$1, {
831
853
  className: cn("flex items-center justify-center px-2.5 md:px-3.5 h-8 md:h-9 border-none border-l border-subtle/50 text-muted rounded-none bg-transparent shrink-0 outline-none select-none cursor-pointer", "transition-all duration-300 hover:bg-primary-500/5 hover:text-primary-500"),
832
854
  children: /* @__PURE__ */ jsx(ChevronDown, { size: 14 })
833
- }), /* @__PURE__ */ jsxs(Menu$1.Root, {
855
+ }), /* @__PURE__ */ jsxs(Menu$2.Root, {
834
856
  className: "w-52 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
835
- children: [/* @__PURE__ */ jsxs(Menu$1.Item, {
857
+ children: [/* @__PURE__ */ jsxs(Menu$2.Item, {
836
858
  onAction: handleCopy,
837
859
  className: "flex items-center px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group",
838
860
  children: [/* @__PURE__ */ jsx(Copy, {
@@ -842,7 +864,7 @@ function CopyMarkdown({ content, mdxRaw, route, className }) {
842
864
  className: "ml-2",
843
865
  children: "Copy Markdown"
844
866
  })]
845
- }), /* @__PURE__ */ jsxs(Menu$1.Item, {
867
+ }), /* @__PURE__ */ jsxs(Menu$2.Item, {
846
868
  onAction: handleOpenRaw,
847
869
  className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group",
848
870
  children: [/* @__PURE__ */ jsx(ExternalLink, {
@@ -984,7 +1006,13 @@ function useNavbar() {
984
1006
  return {
985
1007
  links,
986
1008
  title,
987
- logo: !logo ? null : typeof logo === "string" ? logo : resolvedTheme === "dark" ? logo.dark : logo.light,
1009
+ logo: !logo ? null : typeof logo === "string" ? {
1010
+ light: logo,
1011
+ dark: null
1012
+ } : {
1013
+ light: logo.light,
1014
+ dark: logo.dark
1015
+ },
988
1016
  logoProps: {
989
1017
  alt: (logo && typeof logo === "object" ? logo.alt : void 0) || title,
990
1018
  width: logo && typeof logo === "object" ? logo.width : void 0,
@@ -1007,7 +1035,7 @@ function ThemeToggle({ className }) {
1007
1035
  }, []);
1008
1036
  if (!mounted) return /* @__PURE__ */ jsx("div", { className: cn("h-9 w-9", className) });
1009
1037
  const Icon = theme === "system" ? Monitor : theme === "dark" ? Moon : Sun;
1010
- return /* @__PURE__ */ jsxs(Menu$1.Trigger, {
1038
+ return /* @__PURE__ */ jsxs(Menu$2.Trigger, {
1011
1039
  placement: "bottom right",
1012
1040
  children: [/* @__PURE__ */ jsx(Button, {
1013
1041
  className: cn("flex h-9 w-9 items-center justify-center rounded-xl text-muted transition-colors hover:bg-surface hover:text-body outline-none border-none bg-transparent cursor-pointer", className),
@@ -1016,7 +1044,7 @@ function ThemeToggle({ className }) {
1016
1044
  size: 20,
1017
1045
  className: "animate-in fade-in zoom-in duration-300"
1018
1046
  })
1019
- }), /* @__PURE__ */ jsxs(Menu$1.Root, {
1047
+ }), /* @__PURE__ */ jsxs(Menu$2.Root, {
1020
1048
  selectionMode: "single",
1021
1049
  selectedKeys: [theme],
1022
1050
  onSelectionChange: (keys) => {
@@ -1025,7 +1053,7 @@ function ThemeToggle({ className }) {
1025
1053
  },
1026
1054
  className: "w-36 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
1027
1055
  children: [
1028
- /* @__PURE__ */ jsxs(Menu$1.Item, {
1056
+ /* @__PURE__ */ jsxs(Menu$2.Item, {
1029
1057
  id: "light",
1030
1058
  className: "group flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
1031
1059
  children: [/* @__PURE__ */ jsx(Sun, {
@@ -1036,7 +1064,7 @@ function ThemeToggle({ className }) {
1036
1064
  children: "Light"
1037
1065
  })]
1038
1066
  }),
1039
- /* @__PURE__ */ jsxs(Menu$1.Item, {
1067
+ /* @__PURE__ */ jsxs(Menu$2.Item, {
1040
1068
  id: "dark",
1041
1069
  className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
1042
1070
  children: [/* @__PURE__ */ jsx(Moon, {
@@ -1047,7 +1075,7 @@ function ThemeToggle({ className }) {
1047
1075
  children: "Dark"
1048
1076
  })]
1049
1077
  }),
1050
- /* @__PURE__ */ jsxs(Menu$1.Item, {
1078
+ /* @__PURE__ */ jsxs(Menu$2.Item, {
1051
1079
  id: "system",
1052
1080
  className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
1053
1081
  children: [/* @__PURE__ */ jsx(Monitor, {
@@ -1147,6 +1175,7 @@ function Tabs({ tabs, routes, allRoutes, className }) {
1147
1175
  return /* @__PURE__ */ jsx("div", {
1148
1176
  className: cn("mx-auto max-w-(--breakpoint-3xl) px-4 md:px-6 select-none", className),
1149
1177
  children: /* @__PURE__ */ jsxs(Tabs$1.List, {
1178
+ role: "none",
1150
1179
  className: "border-none py-0 scrollbar-hide relative flex flex-row items-center overflow-x-auto",
1151
1180
  children: [tabs.map((tab, index) => {
1152
1181
  const isActive = index === activeIndex;
@@ -1232,17 +1261,17 @@ function useVersion() {
1232
1261
  function VersionSelector({ className }) {
1233
1262
  const { currentVersionLabel, availableVersions, handleVersionChange } = useVersion();
1234
1263
  if (availableVersions.length === 0) return null;
1235
- return /* @__PURE__ */ jsxs(Menu$1.Trigger, { children: [/* @__PURE__ */ jsxs(Button$1, {
1264
+ return /* @__PURE__ */ jsxs(Menu$2.Trigger, { children: [/* @__PURE__ */ jsxs(Button$1, {
1236
1265
  className: cn("flex h-9 items-center justify-between gap-2 border border-subtle bg-surface px-4 py-1.5 rounded-xl text-xs font-semibold text-body hover:bg-primary-50/20 hover:border-primary-500/50 transition-all duration-300 outline-none select-none cursor-pointer", className),
1237
1266
  children: [/* @__PURE__ */ jsx("span", {
1238
1267
  className: "font-semibold text-[0.8125rem]",
1239
1268
  children: currentVersionLabel
1240
1269
  }), /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
1241
- }), /* @__PURE__ */ jsx(Menu$1.Root, {
1270
+ }), /* @__PURE__ */ jsx(Menu$2.Root, {
1242
1271
  className: "w-40 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
1243
- children: /* @__PURE__ */ jsx(Menu$1.Section, {
1272
+ children: /* @__PURE__ */ jsx(Menu$2.Section, {
1244
1273
  items: availableVersions,
1245
- children: (version) => /* @__PURE__ */ jsx(Menu$1.Item, {
1274
+ children: (version) => /* @__PURE__ */ jsx(Menu$2.Item, {
1246
1275
  onPress: () => handleVersionChange(version.value),
1247
1276
  className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body hover:bg-primary-50/50 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
1248
1277
  children: version.label
@@ -1690,7 +1719,7 @@ function useFeedback(options = {}) {
1690
1719
  function I18nSelector({ className }) {
1691
1720
  const { currentLocale, availableLocales, handleLocaleChange } = useI18n();
1692
1721
  if (availableLocales.length === 0) return null;
1693
- return /* @__PURE__ */ jsxs(Menu$1.Trigger, { children: [/* @__PURE__ */ jsxs(Button$1, {
1722
+ return /* @__PURE__ */ jsxs(Menu$2.Trigger, { children: [/* @__PURE__ */ jsxs(Button$1, {
1694
1723
  className: cn("flex h-9 items-center justify-between gap-2 border border-subtle bg-surface px-4 py-1.5 rounded-xl text-xs font-semibold text-body hover:bg-primary-50/20 hover:border-primary-500/50 transition-all duration-300 outline-none select-none cursor-pointer", className),
1695
1724
  children: [/* @__PURE__ */ jsxs("div", {
1696
1725
  className: "flex items-center gap-1.5",
@@ -1699,11 +1728,11 @@ function I18nSelector({ className }) {
1699
1728
  children: currentLocale || "en"
1700
1729
  })]
1701
1730
  }), /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
1702
- }), /* @__PURE__ */ jsx(Menu$1.Root, {
1731
+ }), /* @__PURE__ */ jsx(Menu$2.Root, {
1703
1732
  className: "w-40 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
1704
- children: /* @__PURE__ */ jsx(Menu$1.Section, {
1733
+ children: /* @__PURE__ */ jsx(Menu$2.Section, {
1705
1734
  items: availableLocales,
1706
- children: (locale) => /* @__PURE__ */ jsx(Menu$1.Item, {
1735
+ children: (locale) => /* @__PURE__ */ jsx(Menu$2.Item, {
1707
1736
  onPress: () => handleLocaleChange(locale.value),
1708
1737
  className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
1709
1738
  children: /* @__PURE__ */ jsx("span", { children: locale.label })
@@ -1714,7 +1743,7 @@ function I18nSelector({ className }) {
1714
1743
 
1715
1744
  //#endregion
1716
1745
  //#region src/client/components/ui-base/navbar.tsx
1717
- const SearchDialog$1 = lazy(() => import("../search-dialog-B9mdxsUC.js").then((m) => ({ default: m.SearchDialog })));
1746
+ const SearchDialog$1 = lazy(() => import("../search-dialog-D3Obh3eA.js").then((m) => ({ default: m.SearchDialog })));
1718
1747
  function Navbar({ className }) {
1719
1748
  const { links, title, logo, logoProps, github, social, config } = useNavbar();
1720
1749
  const { routes, allRoutes, currentRoute, isCollectionPage, currentVersion, currentLocale } = useRoutes();
@@ -1732,10 +1761,12 @@ function Navbar({ className }) {
1732
1761
  onPress: toggleSidebar,
1733
1762
  className: "mr-2 lg:hidden p-1.5 h-8 w-8 flex items-center justify-center bg-transparent border-none outline-none select-none cursor-pointer rounded-xl hover:bg-primary-50/50 transition-colors",
1734
1763
  "aria-label": isSidebarOpen ? "Close sidebar" : "Open sidebar",
1735
- children: isSidebarOpen ? /* @__PURE__ */ jsx(X, { className: "w-5 h-5 text-body" }) : /* @__PURE__ */ jsx(Menu, { className: "w-5 h-5 text-body" })
1764
+ children: isSidebarOpen ? /* @__PURE__ */ jsx(X, { className: "w-5 h-5 text-body" }) : /* @__PURE__ */ jsx(Menu$1, { className: "w-5 h-5 text-body" })
1736
1765
  }),
1737
1766
  logo && /* @__PURE__ */ jsx(Navbar$1.Logo, {
1738
- src: logo,
1767
+ src: logo.light,
1768
+ srcLight: logo.light,
1769
+ srcDark: logo.dark,
1739
1770
  alt: logoProps?.alt || title,
1740
1771
  width: logoProps?.width ?? 24,
1741
1772
  height: logoProps?.height ?? 24,
@@ -1986,8 +2017,30 @@ const mergeSlots = (defaults, overrides) => {
1986
2017
  function SidebarMain({ routes, config, className }) {
1987
2018
  const { logo, title, logoProps } = useNavbar();
1988
2019
  const { closeSidebar } = useUI();
1989
- const SidebarLogo = logo ? /* @__PURE__ */ jsx("img", {
1990
- src: resolvePublicAssetUrl(logo, config.base),
2020
+ /**
2021
+ * Both logo variants are rendered and CSS selects the visible one.
2022
+ *
2023
+ * Resolving the source from the theme would make the server and the browser
2024
+ * emit different `src` values, which is a hydration mismatch. The `dark`
2025
+ * class on `<html>` is set before first paint, so there is no flash.
2026
+ */
2027
+ const SidebarLogo = logo ? logo.dark && logo.dark !== logo.light ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("img", {
2028
+ src: resolvePublicAssetUrl(logo.light, config.base),
2029
+ alt: logoProps?.alt || title,
2030
+ width: 24,
2031
+ height: 24,
2032
+ "data-logo-theme": "light",
2033
+ className: "rounded-xl dark:hidden"
2034
+ }), /* @__PURE__ */ jsx("img", {
2035
+ src: resolvePublicAssetUrl(logo.dark, config.base),
2036
+ alt: logoProps?.alt || title,
2037
+ width: 24,
2038
+ height: 24,
2039
+ "data-logo-theme": "dark",
2040
+ "aria-hidden": "true",
2041
+ className: "hidden rounded-xl dark:block"
2042
+ })] }) : /* @__PURE__ */ jsx("img", {
2043
+ src: resolvePublicAssetUrl(logo.light, config.base),
1991
2044
  alt: logoProps?.alt || title,
1992
2045
  width: 24,
1993
2046
  height: 24,
@@ -2118,7 +2171,7 @@ function Feedback({ className }) {
2118
2171
  className: "flex flex-col gap-4",
2119
2172
  children: [/* @__PURE__ */ jsxs("div", {
2120
2173
  className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
2121
- children: [/* @__PURE__ */ jsx("h4", {
2174
+ children: [/* @__PURE__ */ jsx("h3", {
2122
2175
  className: "text-base font-semibold text-default",
2123
2176
  children: "Was this page helpful?"
2124
2177
  }), /* @__PURE__ */ jsxs("div", {
@@ -2304,7 +2357,9 @@ const EagerMdxElement = ({ moduleLoader, moduleKey, route, components, collectio
2304
2357
  return /* @__PURE__ */ jsx(MdxPage, {
2305
2358
  MDXComponent,
2306
2359
  mdxComponents: components ?? {},
2307
- collectionPostComponent
2360
+ collectionPostComponent,
2361
+ collection: route.collection,
2362
+ route
2308
2363
  });
2309
2364
  };
2310
2365
  const NotFoundWrapper = () => {
@@ -2351,7 +2406,7 @@ function DocsLayout({ collectionsData }) {
2351
2406
 
2352
2407
  //#endregion
2353
2408
  //#region src/client/ssg/create-routes.utils.ts
2354
- function withBase(path, config) {
2409
+ function withBase$1(path, config) {
2355
2410
  const base = config.base || "/";
2356
2411
  if (path.startsWith(base)) return path;
2357
2412
  return `${base === "/" ? "" : base.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}` || "/";
@@ -2447,7 +2502,7 @@ function buildDocRoutes(options) {
2447
2502
  const docRoutes = docMetadata.map((route) => {
2448
2503
  const moduleKey = resolveModuleKey(route.filePath, moduleMap);
2449
2504
  const moduleLoader = moduleKey ? mdxModules[moduleKey] : null;
2450
- const fullPath = withBase(route.path === "" ? "/" : route.path, config);
2505
+ const fullPath = withBase$1(route.path === "" ? "/" : route.path, config);
2451
2506
  const path = fullPath === baseDocsPath ? "." : fullPath.startsWith(baseDocsPath + "/") ? fullPath.slice(baseDocsPath.length + 1) : fullPath;
2452
2507
  const routeRecord = {
2453
2508
  path,
@@ -2574,7 +2629,7 @@ function buildDocRoutes(options) {
2574
2629
  fallback: true,
2575
2630
  seo: {
2576
2631
  ...matchedMetaObj.seo,
2577
- canonical: config.siteUrl ? `${config.siteUrl.replace(/\/$/, "")}${withBase(bPath, config)}` : withBase(bPath, config)
2632
+ canonical: config.siteUrl ? `${config.siteUrl.replace(/\/$/, "")}${withBase$1(bPath, config)}` : withBase$1(bPath, config)
2578
2633
  }
2579
2634
  } : {
2580
2635
  path: bPath,
@@ -2641,7 +2696,7 @@ function buildDocRoutes(options) {
2641
2696
  //#endregion
2642
2697
  //#region src/client/ssg/external-page-wrapper.tsx
2643
2698
  function ExternalPageWrapper({ children }) {
2644
- return /* @__PURE__ */ jsx("div", {
2699
+ return /* @__PURE__ */ jsx("main", {
2645
2700
  className: "boltdocs-external-content h-screen overflow-y-auto",
2646
2701
  children
2647
2702
  });
@@ -2649,16 +2704,33 @@ function ExternalPageWrapper({ children }) {
2649
2704
 
2650
2705
  //#endregion
2651
2706
  //#region src/client/ssg/create-routes.external.tsx
2652
- function getLocales(config) {
2707
+ function getLocales$1(config) {
2653
2708
  if (!config.i18n) return [];
2654
2709
  return Array.isArray(config.i18n.locales) ? config.i18n.locales : Object.keys(config.i18n.locales);
2655
2710
  }
2711
+ /**
2712
+ * Lists the locale-prefixed variants of a path.
2713
+ *
2714
+ * The default locale is skipped on purpose. It is already the unprefixed path,
2715
+ * so prefixing it would mint a second URL for the same page: a site with
2716
+ * `defaultLocale: 'en'` would serve both `/about` and `/en/about`. That is not
2717
+ * a harmless duplicate. The docs site is served under a base, and the SSG path
2718
+ * collector prepends the base to the prefixed variant, so it emitted
2719
+ * `/docs/en/about` — a URL the client router never learns about, because the
2720
+ * base is not part of the route. Visitors landing there got a 404 on a page
2721
+ * the build had itself written.
2722
+ *
2723
+ * A developer configuring a second locale should not have to know this, so the
2724
+ * redundant variant is never generated in the first place.
2725
+ */
2656
2726
  function getLocalizedPaths(pathname, config) {
2657
2727
  const paths = [{
2658
2728
  path: pathname,
2659
2729
  locale: config.i18n?.defaultLocale
2660
2730
  }];
2661
- for (const locale of getLocales(config)) {
2731
+ const defaultLocale = config.i18n?.defaultLocale;
2732
+ for (const locale of getLocales$1(config)) {
2733
+ if (locale === defaultLocale) continue;
2662
2734
  const localizedPath = pathname === "/" ? `/${locale}` : `/${locale}${pathname}`;
2663
2735
  if (!paths.some((entry) => entry.path === localizedPath)) paths.push({
2664
2736
  path: localizedPath,
@@ -2782,7 +2854,7 @@ function buildExternalFileRoutes(options) {
2782
2854
  metadata
2783
2855
  };
2784
2856
  const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ jsx(Fragment$1, { children }));
2785
- const locales = getLocales(config);
2857
+ const locales = getLocales$1(config);
2786
2858
  const isLocalizedPath = (pathname) => locales.some((locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`));
2787
2859
  const localeOfPath = (pathname) => {
2788
2860
  const first = pathname.split("/").filter(Boolean)[0];
@@ -2977,7 +3049,7 @@ function DefaultCollectionList() {
2977
3049
  }),
2978
3050
  post.date && /* @__PURE__ */ jsx("time", {
2979
3051
  className: "text-xs text-muted block mb-2",
2980
- children: new Date(post.date).toLocaleDateString()
3052
+ children: formatDeterministicDate(post.date, { month: "short" })
2981
3053
  }),
2982
3054
  post.excerpt && /* @__PURE__ */ jsx("p", {
2983
3055
  className: "text-sm text-body",
@@ -3219,6 +3291,106 @@ function buildCollectionRoutes(options) {
3219
3291
  };
3220
3292
  }
3221
3293
 
3294
+ //#endregion
3295
+ //#region src/client/ssg/create-routes.redirect.tsx
3296
+ function normalize(value) {
3297
+ const [withoutHash] = value.split("#");
3298
+ const queryIndex = withoutHash.indexOf("?");
3299
+ const rawPath = queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);
3300
+ const query = queryIndex === -1 ? "" : withoutHash.slice(queryIndex);
3301
+ const collapsed = `/${rawPath}`.replace(/\/{2,}/g, "/");
3302
+ return `${collapsed === "/" ? "/" : collapsed.replace(/\/+$/, "")}${query}`;
3303
+ }
3304
+ function isExternalTarget(to) {
3305
+ return /^[a-z][a-z0-9+.-]*:/i.test(to) || to.startsWith("//");
3306
+ }
3307
+ function getLocales(config) {
3308
+ const locales = config.i18n?.locales;
3309
+ if (!locales) return [];
3310
+ return Array.isArray(locales) ? locales : Object.keys(locales);
3311
+ }
3312
+ function withBase(pathname, base) {
3313
+ if (base === "/" || !base) return pathname;
3314
+ const normalizedBase = `/${base.replace(/^\/+|\/+$/g, "")}`;
3315
+ if (pathname === "/") return normalizedBase;
3316
+ return `${normalizedBase}${pathname}`;
3317
+ }
3318
+ /**
3319
+ * Collapses redirect chains and rejects cycles in the browser as well, so a
3320
+ * misconfigured site fails visibly instead of trapping the visitor.
3321
+ */
3322
+ function buildRedirectMap(config) {
3323
+ const map = /* @__PURE__ */ new Map();
3324
+ const entries = config.redirects ?? [];
3325
+ for (const entry of entries) {
3326
+ const from = normalize(entry.from);
3327
+ const sources = entry.locale ? getLocales(config).map((locale) => from === `/${locale}` || from.startsWith(`/${locale}/`) ? from : from === "/" ? `/${locale}` : `/${locale}${from}`) : [from];
3328
+ for (const source of sources) {
3329
+ const to = isExternalTarget(entry.to) ? entry.to : withBase(normalize(entry.to), config.base ?? "/");
3330
+ map.set(source, to);
3331
+ }
3332
+ }
3333
+ for (const [source, direct] of map) {
3334
+ let current = direct;
3335
+ const seen = new Set([source]);
3336
+ for (let depth = 0; depth < 10; depth++) {
3337
+ const nextPath = current.split("?")[0];
3338
+ const next = map.get(nextPath);
3339
+ if (!next || seen.has(nextPath)) break;
3340
+ seen.add(nextPath);
3341
+ current = next;
3342
+ }
3343
+ map.set(source, current);
3344
+ }
3345
+ return map;
3346
+ }
3347
+ /**
3348
+ * Performs the redirect during render effects. A short delay lets the static
3349
+ * host serve the prerendered redirect document first on a cold load, while a
3350
+ * client-side navigation never flashes the destination page.
3351
+ */
3352
+ function RedirectBoundary({ to }) {
3353
+ const navigate = useNavigate();
3354
+ useEffect(() => {
3355
+ if (isExternalTarget(to)) {
3356
+ window.location.replace(to);
3357
+ return;
3358
+ }
3359
+ navigate(to, { replace: true });
3360
+ }, [navigate, to]);
3361
+ return /* @__PURE__ */ jsx("main", {
3362
+ className: "boltdocs-page w-full pt-4 pb-20 px-4 sm:px-8",
3363
+ children: /* @__PURE__ */ jsx("div", {
3364
+ className: "mx-auto w-full max-w-3xl sm:max-w-4xl",
3365
+ children: /* @__PURE__ */ jsxs("p", {
3366
+ className: "text-paragraph",
3367
+ children: [
3368
+ "Redirecting to ",
3369
+ /* @__PURE__ */ jsx("a", {
3370
+ href: to,
3371
+ children: to
3372
+ }),
3373
+ "…"
3374
+ ]
3375
+ })
3376
+ })
3377
+ });
3378
+ }
3379
+ /**
3380
+ * Builds client-side redirect routes from `config.redirects`.
3381
+ *
3382
+ * Redirect sources are appended after the real routes so an existing page always
3383
+ * wins, and before the catch-all so a redirect is never shadowed by the 404.
3384
+ */
3385
+ function buildRedirectRoutes({ config }) {
3386
+ const map = buildRedirectMap(config);
3387
+ if (map.size === 0) return [];
3388
+ return [...map.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([from, to]) => ({
3389
+ path: from,
3390
+ element: /* @__PURE__ */ jsx(RedirectBoundary, { to })
3391
+ }));
3392
+ }
3393
+
3222
3394
  //#endregion
3223
3395
  //#region src/client/ssg/create-routes.tsx
3224
3396
  function createRoutes(options) {
@@ -3244,6 +3416,7 @@ function createRoutes(options) {
3244
3416
  };
3245
3417
  filteredExternalFileRoutes.children = externalFileRoutes.children.filter((route) => !route.path || acceptedExternalFilePaths.has(route.path));
3246
3418
  const collectionRoutes = buildCollectionRoutes(options);
3419
+ const redirectRoutes = buildRedirectRoutes({ config });
3247
3420
  const children = [
3248
3421
  {
3249
3422
  path: baseDocsPath,
@@ -3253,6 +3426,7 @@ function createRoutes(options) {
3253
3426
  ...externalRoutes.children,
3254
3427
  ...filteredExternalFileRoutes.children,
3255
3428
  ...collectionRoutes.children,
3429
+ ...redirectRoutes,
3256
3430
  {
3257
3431
  path: "*",
3258
3432
  element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(NotFoundWrapper, {}) }) })
@@ -3287,6 +3461,18 @@ function createRoutes(options) {
3287
3461
  };
3288
3462
  }
3289
3463
 
3464
+ //#endregion
3465
+ //#region src/client/collections/utils.ts
3466
+ /**
3467
+ * Formats a date to a human-readable string.
3468
+ *
3469
+ * Locale and time zone are pinned so the server and the browser produce
3470
+ * identical text during hydration. See `formatDeterministicDate`.
3471
+ */
3472
+ function formatDate(date, options = {}) {
3473
+ return formatDeterministicDate(date, options);
3474
+ }
3475
+
3290
3476
  //#endregion
3291
3477
  //#region src/client/components/docs-layout-default.tsx
3292
3478
  /**
@@ -3412,4 +3598,4 @@ function useCodeBlock(props) {
3412
3598
  }
3413
3599
 
3414
3600
  //#endregion
3415
- export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, CurrentPostProvider, DocsLayoutComponent as DocsLayout, ErrorBoundary, LocationContext, LocationProvider, MatchesContext, MdxPage, Navbar, NavigateContext, NotFound, OnThisPage, Outlet, OutletContext, PageNav, PrefetchContext, RouteDataContext, RouteRenderer, SearchDialog, Sidebar, StructuredData, Timeline, ViteReactSSG, addBasename, addUrlBase, buildUrl, classifyUrlPath, cn, copyToClipboard, createArticleStructuredData, createBreadcrumbStructuredData, createRoutes, createStructuredData, createWebSiteStructuredData, defaultNavigate, defineStructuredData, getConfiguredLocales, getConfiguredVersions, getStarsRepo, getTranslated, getVersionPrefixSegments, getVersionSegments, hasBasename, hasUriScheme, hasUrlBase, isConfiguredLocale, isConfiguredVersion, matchRouteBranch, matchRouteBranchWithParams, normalizeBasename, normalizeUrlBase, normalizeUrlPath, parseUrlReference, reactToText, resolvePublicAssetUrl, resolveRouteBranch, resolveUrlReference, splitUrlReference, startViewTransition, stripBasename, stripSiteProtocol, stripUrlBase, useAnalytics, useBreadcrumbs, useCodeBlock, useCodeBlockFeedback, useConfig, useCopyButton, useExpandable, useFeedback, useHeadings, useI18n, useLoaderData, useLocalizedTo, useLocation, useMatches, useMdxComponents, useMergedComponents, useNavbar, useNavigate, usePageNav, usePost, usePosts, usePrefetch, useRecentPosts, useRouteData, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion, useViewTransition };
3601
+ export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, CurrentPostProvider, DocsLayoutComponent as DocsLayout, ErrorBoundary, LocationContext, LocationProvider, MatchesContext, MdxPage, Navbar, NavigateContext, NotFound, OnThisPage, Outlet, OutletContext, PageNav, PrefetchContext, RouteDataContext, RouteRenderer, SearchDialog, Sidebar, StructuredData, Timeline, ViteReactSSG, addBasename, addUrlBase, buildUrl, classifyUrlPath, cn, copyToClipboard, createArticleStructuredData, createBreadcrumbStructuredData, createRoutes, createStructuredData, createWebSiteStructuredData, defaultNavigate, defineStructuredData, formatDate, formatDeterministicDate, getConfiguredLocales, getConfiguredVersions, getStarsRepo, getTranslated, getVersionPrefixSegments, getVersionSegments, hasBasename, hasUriScheme, hasUrlBase, isConfiguredLocale, isConfiguredVersion, matchRouteBranch, matchRouteBranchWithParams, normalizeBasename, normalizeUrlBase, normalizeUrlPath, parseUrlReference, reactToText, resolvePublicAssetUrl, resolveRouteBranch, resolveUrlReference, splitUrlReference, startViewTransition, stripBasename, stripSiteProtocol, stripUrlBase, useAnalytics, useBreadcrumbs, useCodeBlock, useCodeBlockFeedback, useConfig, useCopyButton, useExpandable, useFeedback, useHeadings, useI18n, useLoaderData, useLocalizedTo, useLocation, useMatches, useMdxComponents, useMergedComponents, useNavbar, useNavigate, usePageNav, usePost, usePosts, usePrefetch, useRecentPosts, useRouteData, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion, useViewTransition };
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
7
- const require_mdx = require('../mdx-D0Absdq5.cjs');
7
+ const require_mdx = require('../mdx-BCOrMd-P.cjs');
8
8
 
9
9
  //#region src/client/mdx.ts
10
10
  const { Card, Cards, Callout, Field, Image } = require_mdx.mdx_components_default;
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { t as mdx_components_default } from "../mdx-BRT71V5Q.js";
6
+ import { t as mdx_components_default } from "../mdx-BijiEbkp.js";
7
7
 
8
8
  //#region src/client/mdx.ts
9
9
  const { Card, Cards, Callout, Field, Image } = mdx_components_default;
@@ -4,11 +4,11 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
7
- const require_router = require('../router-C3kygdRK.cjs');
8
- const require_link = require('../link-vZjmD-es.cjs');
9
- const require_image = require('../image-Hnaa2bJd.cjs');
10
- const require_docs_layout = require('../docs-layout-vzfXed1Q.cjs');
11
- const require_search_dialog = require('../search-dialog-x_qHU8ty.cjs');
7
+ const require_router = require('../router-DKC0Lu0n.cjs');
8
+ const require_link = require('../link-Xb69Oy2F.cjs');
9
+ const require_image = require('../image-Bke2ojW1.cjs');
10
+ const require_docs_layout = require('../docs-layout-DIgxJ5c7.cjs');
11
+ const require_search_dialog = require('../search-dialog-BOQRHKTb.cjs');
12
12
  let react_jsx_runtime = require("react/jsx-runtime");
13
13
 
14
14
  //#region src/client/components/primitives/skeleton.tsx