reroute-js 0.40.1 → 0.41.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 (187) hide show
  1. package/cli/bin.d.ts +1 -1
  2. package/cli/bin.js +121 -40
  3. package/cli/bin.js.map +10 -10
  4. package/cli/index.d.ts +1 -1
  5. package/cli/index.js +4 -4
  6. package/cli/index.js.map +1 -1
  7. package/cli/src/cli.d.ts +1 -1
  8. package/cli/src/commands/analyze.d.ts +1 -1
  9. package/cli/src/commands/build.d.ts +1 -1
  10. package/cli/src/commands/dev.d.ts +1 -1
  11. package/cli/src/commands/gen.d.ts +1 -1
  12. package/cli/src/commands/index.d.ts +1 -1
  13. package/cli/src/commands/init.d.ts +1 -1
  14. package/cli/src/commands/lib/assets.d.ts +1 -1
  15. package/cli/src/commands/lib/bundler.d.ts +1 -1
  16. package/cli/src/commands/lib/command.d.ts +1 -1
  17. package/cli/src/commands/lib/env.d.ts +1 -1
  18. package/cli/src/commands/lib/index.d.ts +1 -1
  19. package/cli/src/commands/lib/log.d.ts +1 -1
  20. package/cli/src/commands/lib/markdown/availability.d.ts +1 -1
  21. package/cli/src/commands/lib/markdown/index.d.ts +1 -1
  22. package/cli/src/commands/lib/markdown/processor.d.ts +1 -1
  23. package/cli/src/commands/lib/production.d.ts +1 -1
  24. package/cli/src/commands/lib/server.d.ts +1 -1
  25. package/cli/src/commands/lib/streaming/analyzer.d.ts +1 -1
  26. package/cli/src/commands/lib/streaming/suspense.d.ts +1 -1
  27. package/cli/src/commands/lib/tailwind.d.ts +1 -1
  28. package/cli/src/commands/lib/terminal-ui.d.ts +1 -1
  29. package/cli/src/commands/lib/version.d.ts +1 -1
  30. package/cli/src/commands/og.d.ts +1 -1
  31. package/cli/src/commands/start.d.ts +1 -1
  32. package/cli/src/index.d.ts +1 -1
  33. package/core/index.d.ts +1 -1
  34. package/core/index.js +117 -36
  35. package/core/index.js.map +10 -10
  36. package/core/src/bundler/hash.d.ts +1 -1
  37. package/core/src/bundler/index.d.ts +1 -1
  38. package/core/src/config.d.ts +42 -2
  39. package/core/src/config.d.ts.map +1 -1
  40. package/core/src/content/discovery.d.ts +1 -1
  41. package/core/src/content/index.d.ts +1 -1
  42. package/core/src/content/metadata.d.ts +7 -2
  43. package/core/src/content/metadata.d.ts.map +1 -1
  44. package/core/src/index.d.ts +1 -1
  45. package/core/src/llms/extractor.d.ts +1 -1
  46. package/core/src/llms/formatter.d.ts +1 -1
  47. package/core/src/llms/full-generator.d.ts +1 -1
  48. package/core/src/llms/index-generator.d.ts +1 -1
  49. package/core/src/llms/index.d.ts +1 -1
  50. package/core/src/og/discovery.d.ts +1 -1
  51. package/core/src/og/index.d.ts +1 -1
  52. package/core/src/og/meta.d.ts +1 -1
  53. package/core/src/og/render.d.ts +1 -1
  54. package/core/src/og/types.d.ts +1 -1
  55. package/core/src/robots/discovery.d.ts +1 -1
  56. package/core/src/robots/generator.d.ts +1 -1
  57. package/core/src/robots/index.d.ts +1 -1
  58. package/core/src/robots/policies.d.ts +1 -1
  59. package/core/src/rss/discovery.d.ts +1 -1
  60. package/core/src/rss/generator.d.ts +1 -1
  61. package/core/src/rss/index.d.ts +1 -1
  62. package/core/src/sitemap/discovery.d.ts +1 -1
  63. package/core/src/sitemap/generator.d.ts +1 -1
  64. package/core/src/sitemap/index.d.ts +1 -1
  65. package/core/src/ssr/index.d.ts +1 -1
  66. package/core/src/ssr/lib/cache.d.ts +1 -1
  67. package/core/src/ssr/lib/collections.d.ts +1 -1
  68. package/core/src/ssr/lib/compression.d.ts +1 -1
  69. package/core/src/ssr/lib/compute/content.d.ts +1 -1
  70. package/core/src/ssr/lib/compute/index.d.ts +1 -1
  71. package/core/src/ssr/lib/compute/layouts.d.ts +1 -1
  72. package/core/src/ssr/lib/compute/routes.d.ts +1 -1
  73. package/core/src/ssr/lib/data.d.ts +1 -1
  74. package/core/src/ssr/lib/html.d.ts +6 -1
  75. package/core/src/ssr/lib/html.d.ts.map +1 -1
  76. package/core/src/ssr/lib/imports.d.ts +1 -1
  77. package/core/src/ssr/lib/index.d.ts +1 -1
  78. package/core/src/ssr/lib/layouts.d.ts +1 -1
  79. package/core/src/ssr/lib/metadata.d.ts +3 -3
  80. package/core/src/ssr/lib/metadata.d.ts.map +1 -1
  81. package/core/src/ssr/lib/mime.d.ts +1 -1
  82. package/core/src/ssr/lib/modules.d.ts +1 -1
  83. package/core/src/ssr/lib/path.d.ts +1 -1
  84. package/core/src/ssr/lib/preload.d.ts +1 -1
  85. package/core/src/ssr/lib/scripts/collections.d.ts +1 -1
  86. package/core/src/ssr/lib/scripts/data.d.ts +1 -1
  87. package/core/src/ssr/lib/scripts/escape.d.ts +1 -1
  88. package/core/src/ssr/lib/scripts/feeds.d.ts +1 -1
  89. package/core/src/ssr/lib/scripts/index.d.ts +1 -1
  90. package/core/src/ssr/lib/seed.d.ts +1 -1
  91. package/core/src/ssr/lib/serialize.d.ts +1 -1
  92. package/core/src/ssr/lib/setup.d.ts +3 -2
  93. package/core/src/ssr/lib/setup.d.ts.map +1 -1
  94. package/core/src/ssr/lib/styles.d.ts +1 -1
  95. package/core/src/ssr/lib/template.d.ts +1 -1
  96. package/core/src/ssr/lib/types.d.ts +1 -1
  97. package/core/src/ssr/render.d.ts +3 -2
  98. package/core/src/ssr/render.d.ts.map +1 -1
  99. package/core/src/ssr/stream.d.ts +3 -2
  100. package/core/src/ssr/stream.d.ts.map +1 -1
  101. package/elysia/index.d.ts +1 -1
  102. package/elysia/index.js +120 -36
  103. package/elysia/index.js.map +12 -12
  104. package/elysia/src/index.d.ts +1 -1
  105. package/elysia/src/libs/assets.d.ts +1 -1
  106. package/elysia/src/libs/cache.d.ts +1 -1
  107. package/elysia/src/libs/caching.d.ts +1 -1
  108. package/elysia/src/libs/http.d.ts +1 -1
  109. package/elysia/src/libs/image.d.ts +1 -1
  110. package/elysia/src/libs/index.d.ts +1 -1
  111. package/elysia/src/libs/llms.d.ts +1 -1
  112. package/elysia/src/libs/response.d.ts +1 -1
  113. package/elysia/src/libs/serving.d.ts +1 -1
  114. package/elysia/src/plugin.d.ts +1 -1
  115. package/elysia/src/plugin.d.ts.map +1 -1
  116. package/elysia/src/routes/artifacts.d.ts +1 -1
  117. package/elysia/src/routes/content.d.ts +1 -1
  118. package/elysia/src/routes/image.d.ts +1 -1
  119. package/elysia/src/routes/index.d.ts +1 -1
  120. package/elysia/src/routes/internal.d.ts +1 -1
  121. package/elysia/src/routes/llms.d.ts +1 -1
  122. package/elysia/src/routes/og.d.ts +1 -1
  123. package/elysia/src/routes/redirects.d.ts +1 -1
  124. package/elysia/src/routes/robots.d.ts +1 -1
  125. package/elysia/src/routes/rss.d.ts +1 -1
  126. package/elysia/src/routes/search.d.ts +1 -1
  127. package/elysia/src/routes/sitemap.d.ts +1 -1
  128. package/elysia/src/routes/ssr.d.ts +3 -2
  129. package/elysia/src/routes/ssr.d.ts.map +1 -1
  130. package/elysia/src/routes/static.d.ts +1 -1
  131. package/elysia/src/types.d.ts +1 -1
  132. package/package.json +1 -1
  133. package/react/index.d.ts +1 -1
  134. package/react/index.js +2 -2
  135. package/react/index.js.map +1 -1
  136. package/react/src/components/ClientOnly.d.ts +1 -1
  137. package/react/src/components/ContentRoute.d.ts +1 -1
  138. package/react/src/components/Image.d.ts +1 -1
  139. package/react/src/components/LazyRoute.d.ts +1 -1
  140. package/react/src/components/Link.d.ts +1 -1
  141. package/react/src/components/Markdown.d.ts +1 -1
  142. package/react/src/components/Outlet.d.ts +1 -1
  143. package/react/src/components/index.d.ts +1 -1
  144. package/react/src/hooks/index.d.ts +1 -1
  145. package/react/src/hooks/useContent.d.ts +1 -1
  146. package/react/src/hooks/useData.d.ts +1 -1
  147. package/react/src/hooks/useFeed.d.ts +1 -1
  148. package/react/src/hooks/useLayoutData.d.ts +1 -1
  149. package/react/src/hooks/useLlms.d.ts +1 -1
  150. package/react/src/hooks/useNavigate.d.ts +1 -1
  151. package/react/src/hooks/useParams.d.ts +1 -1
  152. package/react/src/hooks/useRouter.d.ts +1 -1
  153. package/react/src/hooks/useSearch.d.ts +1 -1
  154. package/react/src/hooks/useSearchParams.d.ts +1 -1
  155. package/react/src/hooks/useToc.d.ts +1 -1
  156. package/react/src/index.d.ts +1 -1
  157. package/react/src/lib/collection.d.ts +1 -1
  158. package/react/src/lib/content.d.ts +1 -1
  159. package/react/src/lib/head.d.ts +1 -1
  160. package/react/src/lib/index.d.ts +1 -1
  161. package/react/src/lib/lazy-route.d.ts +1 -1
  162. package/react/src/lib/route-loader.d.ts +1 -1
  163. package/react/src/providers/ContentProvider.d.ts +1 -1
  164. package/react/src/providers/RerouteProvider.d.ts +1 -1
  165. package/react/src/providers/RouterProvider.d.ts +1 -1
  166. package/react/src/providers/index.d.ts +1 -1
  167. package/react/src/types/any.d.ts +1 -1
  168. package/react/src/types/index.d.ts +1 -1
  169. package/react/src/types/router.d.ts +1 -1
  170. package/telemetry/react.d.ts +1 -1
  171. package/telemetry/react.js +2 -2
  172. package/telemetry/react.js.map +1 -1
  173. package/telemetry/server.d.ts +1 -1
  174. package/telemetry/server.js +2 -2
  175. package/telemetry/server.js.map +8 -8
  176. package/telemetry/src/react/api.d.ts +1 -1
  177. package/telemetry/src/react/context.d.ts +1 -1
  178. package/telemetry/src/react/index.d.ts +1 -1
  179. package/telemetry/src/react/telemetry.d.ts +1 -1
  180. package/telemetry/src/server/context.d.ts +1 -1
  181. package/telemetry/src/server/headers/extractor.d.ts +1 -1
  182. package/telemetry/src/server/headers/index.d.ts +1 -1
  183. package/telemetry/src/server/headers/presets.d.ts +1 -1
  184. package/telemetry/src/server/index.d.ts +1 -1
  185. package/telemetry/src/server/instrumentation.d.ts +1 -1
  186. package/telemetry/src/server/plugin.d.ts +1 -1
  187. package/telemetry/src/server/sourcemap.d.ts +1 -1
package/core/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * reroute-js v0.40.1
2
+ * reroute-js v0.41.0
3
3
  *
4
4
  * @license MIT
5
5
  * @copyright 2026 stewones <hi@stewan.io>
@@ -168,7 +168,7 @@ async function getContentMeta(absPath, isWatchMode) {
168
168
  }
169
169
  }
170
170
  }
171
- function buildHeadFromMeta(meta) {
171
+ function buildHeadFromMeta(meta, ogConfig) {
172
172
  if (!meta || typeof meta !== "object")
173
173
  return "";
174
174
  const parts = [];
@@ -178,6 +178,23 @@ function buildHeadFromMeta(meta) {
178
178
  parts.push(`<title>${escapeHtml(title)}</title>`);
179
179
  if (description)
180
180
  parts.push(`<meta name="description" content="${escapeHtml(description)}" />`);
181
+ const ogType = typeof meta.ogType === "string" ? meta.ogType : ogConfig?.defaultType || "website";
182
+ parts.push(`<meta property="og:type" content="${escapeHtml(ogType)}" />`);
183
+ if (title) {
184
+ parts.push(`<meta property="og:title" content="${escapeHtml(title)}" />`);
185
+ }
186
+ const finalDescription = description || ogConfig?.siteDescription;
187
+ if (finalDescription) {
188
+ parts.push(`<meta property="og:description" content="${escapeHtml(finalDescription)}" />`);
189
+ }
190
+ const twitterCard = ogConfig?.twitterCard || "summary_large_image";
191
+ parts.push(`<meta name="twitter:card" content="${twitterCard}" />`);
192
+ if (title) {
193
+ parts.push(`<meta name="twitter:title" content="${escapeHtml(title)}" />`);
194
+ }
195
+ if (finalDescription) {
196
+ parts.push(`<meta name="twitter:description" content="${escapeHtml(finalDescription)}" />`);
197
+ }
181
198
  return parts.length ? `
182
199
  ${parts.join(`
183
200
  `)}` : "";
@@ -1640,6 +1657,28 @@ function removeDefaultMetaTags(templateHtml) {
1640
1657
  } catch {}
1641
1658
  return result;
1642
1659
  }
1660
+ function removeOverriddenMetaTags(templateHtml, injectedHead) {
1661
+ let result = templateHtml;
1662
+ try {
1663
+ const injectedOgProps = [
1664
+ ...injectedHead.matchAll(/<meta\s+property\s*=\s*['"]([^'"]+)['"][^>]*>/gi)
1665
+ ].map((m) => m[1].toLowerCase());
1666
+ const injectedNameMetas = [
1667
+ ...injectedHead.matchAll(/<meta\s+name\s*=\s*['"]([^'"]+)['"][^>]*>/gi)
1668
+ ].map((m) => m[1].toLowerCase());
1669
+ for (const prop of injectedOgProps) {
1670
+ const escapedProp = prop.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1671
+ const regex = new RegExp(`<meta\\s+property\\s*=\\s*['"]${escapedProp}['"][^>]*>`, "gi");
1672
+ result = result.replace(regex, "");
1673
+ }
1674
+ for (const name of injectedNameMetas) {
1675
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1676
+ const regex = new RegExp(`<meta\\s+name\\s*=\\s*['"]${escapedName}['"][^>]*>`, "gi");
1677
+ result = result.replace(regex, "");
1678
+ }
1679
+ } catch {}
1680
+ return result;
1681
+ }
1643
1682
  function deduplicateHeadContent(templateHtml, headToInject) {
1644
1683
  let cleanedTemplate = templateHtml;
1645
1684
  let cleanedHead = headToInject;
@@ -1650,6 +1689,7 @@ function deduplicateHeadContent(templateHtml, headToInject) {
1650
1689
  } else if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(cleanedHead)) {
1651
1690
  cleanedTemplate = cleanedTemplate.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
1652
1691
  }
1692
+ cleanedTemplate = removeOverriddenMetaTags(cleanedTemplate, cleanedHead);
1653
1693
  } catch {}
1654
1694
  return { cleanedTemplate, cleanedHead };
1655
1695
  }
@@ -1768,7 +1808,6 @@ async function generateOGImageMetaTags(pathname, clientDir, ogConfig) {
1768
1808
  return `<meta property="og:image" content="${ogImagePath}" />
1769
1809
  <meta property="og:image:width" content="${width}" />
1770
1810
  <meta property="og:image:height" content="${height}" />
1771
- <meta name="twitter:card" content="summary_large_image" />
1772
1811
  <meta name="twitter:image" content="${ogImagePath}" />`;
1773
1812
  }
1774
1813
  var init_meta = __esm(() => {
@@ -1776,6 +1815,22 @@ var init_meta = __esm(() => {
1776
1815
  });
1777
1816
 
1778
1817
  // packages/core/src/ssr/lib/metadata.ts
1818
+ async function loadModuleMetaAndSSR(moduleObj, absolutePath, isWatchMode) {
1819
+ const bundledMeta = moduleObj?.meta;
1820
+ const bundledSSR = moduleObj?.ssr;
1821
+ if (bundledMeta !== undefined || bundledSSR !== undefined) {
1822
+ return { meta: bundledMeta, ssr: bundledSSR };
1823
+ }
1824
+ try {
1825
+ const mod = await dynamicImport(absolutePath, isWatchMode);
1826
+ return {
1827
+ meta: mod?.meta,
1828
+ ssr: mod?.ssr
1829
+ };
1830
+ } catch {
1831
+ return {};
1832
+ }
1833
+ }
1779
1834
  function generateCanonicalUrl(baseUrl, pathname) {
1780
1835
  const cleanBaseUrl = baseUrl.replace(/\/$/, "");
1781
1836
  const cleanPathname = pathname.split("?")[0];
@@ -1790,7 +1845,25 @@ function generateOgUrl(baseUrl, pathname) {
1790
1845
  const ogUrl = `${cleanBaseUrl}${normalizedPath}`;
1791
1846
  return `<meta property="og:url" content="${ogUrl}" />`;
1792
1847
  }
1793
- async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ogConfig, baseUrl, autoCanonical, ssrData) {
1848
+ function generateGlobalOGTags(ogConfig) {
1849
+ const tags = [];
1850
+ if (ogConfig.siteName) {
1851
+ tags.push(`<meta property="og:site_name" content="${escapeHtml2(ogConfig.siteName)}" />`);
1852
+ }
1853
+ if (ogConfig.locale) {
1854
+ tags.push(`<meta property="og:locale" content="${escapeHtml2(ogConfig.locale)}" />`);
1855
+ }
1856
+ if (ogConfig.twitterSite) {
1857
+ const handle = ogConfig.twitterSite.startsWith("@") ? ogConfig.twitterSite : `@${ogConfig.twitterSite}`;
1858
+ tags.push(`<meta name="twitter:site" content="${escapeHtml2(handle)}" />`);
1859
+ }
1860
+ return tags.length ? tags.join(`
1861
+ `) : "";
1862
+ }
1863
+ function escapeHtml2(input) {
1864
+ return input.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1865
+ }
1866
+ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ogImageConfig, ogConfig, baseUrl, autoCanonical, ssrData) {
1794
1867
  let perPageHead = "";
1795
1868
  let pageLang;
1796
1869
  let statusOverride = currentStatusOverride;
@@ -1799,7 +1872,7 @@ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, curren
1799
1872
  }, (lang) => {
1800
1873
  if (!pageLang)
1801
1874
  pageLang = lang;
1802
- });
1875
+ }, ogConfig);
1803
1876
  const shouldGenerateCanonical = autoCanonical !== false && baseUrl !== undefined;
1804
1877
  if (shouldGenerateCanonical) {
1805
1878
  const canonicalTag = generateCanonicalUrl(baseUrl, pathname);
@@ -1809,8 +1882,15 @@ ${canonicalTag}`;
1809
1882
  perPageHead += `
1810
1883
  ${ogUrlTag}`;
1811
1884
  }
1885
+ if (ogConfig) {
1886
+ const ogGlobalTags = generateGlobalOGTags(ogConfig);
1887
+ if (ogGlobalTags) {
1888
+ perPageHead += `
1889
+ ${ogGlobalTags}`;
1890
+ }
1891
+ }
1812
1892
  try {
1813
- const ogMetaTags = await generateOGImageMetaTags(pathname, clientDir, ogConfig);
1893
+ const ogMetaTags = await generateOGImageMetaTags(pathname, clientDir, ogImageConfig);
1814
1894
  if (ogMetaTags) {
1815
1895
  perPageHead += `
1816
1896
  ${ogMetaTags}`;
@@ -1822,24 +1902,22 @@ ${ogMetaTags}`;
1822
1902
  perPageHead += head;
1823
1903
  }, (lang) => {
1824
1904
  pageLang = lang;
1825
- });
1826
- const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData);
1905
+ }, ogConfig);
1906
+ const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig);
1827
1907
  perPageHead += routeResult.head;
1828
1908
  if (routeResult.lang)
1829
1909
  pageLang = routeResult.lang;
1830
1910
  statusOverride = routeResult.statusOverride;
1831
1911
  return { perPageHead, pageLang, statusOverride };
1832
1912
  }
1833
- async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang) {
1913
+ async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig) {
1834
1914
  if (typeof layout?.path !== "string")
1835
1915
  return;
1836
1916
  try {
1837
1917
  const abs = join(clientDir, "routes", String(layout.path));
1838
- const mod = await dynamicImport(abs, isWatchMode);
1839
- const meta = mod?.meta;
1840
- const ssr = mod?.ssr;
1918
+ const { meta, ssr } = await loadModuleMetaAndSSR(layout, abs, isWatchMode);
1841
1919
  if (meta)
1842
- addHead(buildHeadFromMeta(meta));
1920
+ addHead(buildHeadFromMeta(meta, ogConfig));
1843
1921
  if (ssr) {
1844
1922
  const ssrHead = extractSSRHead(ssr);
1845
1923
  if (ssrHead)
@@ -1851,17 +1929,16 @@ ${ssrHead}`);
1851
1929
  }
1852
1930
  } catch {}
1853
1931
  }
1854
- async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang) {
1932
+ async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang, ogConfig) {
1855
1933
  try {
1856
- const routesPath = join(cwd, ".reroute", "routes.ts");
1857
- const m = await dynamicImport(routesPath, isWatchMode);
1934
+ const m = await loadRoutesModule(cwd, isWatchMode);
1858
1935
  const matchingLayouts = getMatchingLayouts(pathname, m?.layouts);
1859
1936
  for (const layout of matchingLayouts) {
1860
- await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang);
1937
+ await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig);
1861
1938
  }
1862
1939
  } catch {}
1863
1940
  }
1864
- function extractContentMetadata(pathname, addHead, setLang) {
1941
+ function extractContentMetadata(pathname, addHead, setLang, ogConfig) {
1865
1942
  try {
1866
1943
  const parts = pathname.split("/").filter(Boolean);
1867
1944
  if (parts.length < 2)
@@ -1871,7 +1948,7 @@ function extractContentMetadata(pathname, addHead, setLang) {
1871
1948
  const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
1872
1949
  const meta = exp?.meta;
1873
1950
  const ssr = exp?.ssr;
1874
- addHead(buildHeadFromMeta(meta));
1951
+ addHead(buildHeadFromMeta(meta, ogConfig));
1875
1952
  const ssrHead = extractSSRHead(ssr);
1876
1953
  if (ssrHead)
1877
1954
  addHead(`
@@ -1881,7 +1958,7 @@ ${ssrHead}`);
1881
1958
  setLang(lang);
1882
1959
  } catch {}
1883
1960
  }
1884
- async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData) {
1961
+ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig) {
1885
1962
  const pathnameOnly = pathname.split("?")[0];
1886
1963
  const match = typeof m.matchRoute === "function" ? m.matchRoute(pathnameOnly) : null;
1887
1964
  const r = match?.route;
@@ -1891,12 +1968,10 @@ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode,
1891
1968
  if (r && typeof r.path === "string") {
1892
1969
  try {
1893
1970
  const abs = join(clientDir, "routes", String(r.path));
1894
- const mod = await dynamicImport(abs, isWatchMode);
1895
- const meta = mod?.meta;
1896
- const ssr = mod?.ssr;
1971
+ const { meta, ssr } = await loadModuleMetaAndSSR(r, abs, isWatchMode);
1897
1972
  let head = "";
1898
1973
  if (meta)
1899
- head += buildHeadFromMeta(meta);
1974
+ head += buildHeadFromMeta(meta, ogConfig);
1900
1975
  if (ssr) {
1901
1976
  const routeData = ssrData && typeof ssrData === "object" ? ssrData[pathname] : undefined;
1902
1977
  const ssrHead = extractSSRHead(ssr, routeData);
@@ -1910,7 +1985,7 @@ ${ssrHead}`;
1910
1985
  }
1911
1986
  return { head: "", statusOverride };
1912
1987
  }
1913
- async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData) {
1988
+ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig) {
1914
1989
  let head = "";
1915
1990
  let lang;
1916
1991
  let statusOverride = currentStatusOverride;
@@ -1926,14 +2001,14 @@ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, curre
1926
2001
  statusOverride = statusOverride || 404;
1927
2002
  }
1928
2003
  if (r && typeof r.path === "string") {
1929
- const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData);
2004
+ const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig);
1930
2005
  head = result.head;
1931
2006
  lang = result.lang;
1932
2007
  statusOverride = result.statusOverride;
1933
2008
  } else {
1934
2009
  head += await extractNotFoundMetadata(pathname, clientDir, m, isWatchMode, (l) => {
1935
2010
  lang = l;
1936
- });
2011
+ }, ogConfig);
1937
2012
  }
1938
2013
  } catch {}
1939
2014
  return { head, lang, statusOverride };
@@ -1953,7 +2028,7 @@ function findBestNotFoundRoute(list, pathname) {
1953
2028
  }
1954
2029
  return chosen;
1955
2030
  }
1956
- async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatchMode, setLang) {
2031
+ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatchMode, setLang, ogConfig) {
1957
2032
  let head = "";
1958
2033
  try {
1959
2034
  const list = routesModule?.notFoundRoutes;
@@ -1962,11 +2037,9 @@ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatc
1962
2037
  const chosen = findBestNotFoundRoute(list, pathname);
1963
2038
  if (chosen && typeof chosen.path === "string") {
1964
2039
  const abs = join(clientDir, "routes", String(chosen.path));
1965
- const mod = await dynamicImport(abs, isWatchMode);
1966
- const meta = mod?.meta;
1967
- const ssr = mod?.ssr;
2040
+ const { meta, ssr } = await loadModuleMetaAndSSR(chosen, abs, isWatchMode);
1968
2041
  if (meta)
1969
- head += buildHeadFromMeta(meta);
2042
+ head += buildHeadFromMeta(meta, ogConfig);
1970
2043
  const ssrHead = extractSSRHead(ssr);
1971
2044
  if (ssrHead)
1972
2045
  head += `
@@ -2553,7 +2626,7 @@ async function performSSRSetupInternal(options, streaming) {
2553
2626
  statusOverride = computeResult.statusContainer.value;
2554
2627
  }
2555
2628
  const metadataResult = await withSpan("ssr.extract.metadata", async (span) => {
2556
- const result = await extractPageMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ogConfig, options.baseUrl, options.autoCanonical, computeResult.data);
2629
+ const result = await extractPageMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ogConfig, options.ogMetaConfig, options.baseUrl, options.autoCanonical, computeResult.data);
2557
2630
  span.setAttributes({
2558
2631
  "reroute.pathname": pathname,
2559
2632
  "reroute.metadata.exists": !!result.perPageHead
@@ -2723,6 +2796,7 @@ async function renderSSRDocument(options) {
2723
2796
  maxAge,
2724
2797
  searchParams,
2725
2798
  ogConfig,
2799
+ ogMetaConfig: options.ogMetaConfig,
2726
2800
  baseUrl: options.baseUrl,
2727
2801
  autoCanonical: options.autoCanonical,
2728
2802
  cachedCollections: options.cachedCollections,
@@ -4833,6 +4907,7 @@ async function renderSSRDocumentStream(options) {
4833
4907
  maxAge,
4834
4908
  searchParams,
4835
4909
  ogConfig,
4910
+ ogMetaConfig: options.ogMetaConfig,
4836
4911
  baseUrl: options.baseUrl,
4837
4912
  autoCanonical: options.autoCanonical,
4838
4913
  cachedCollections: options.cachedCollections,
@@ -4867,7 +4942,11 @@ async function renderSSRDocumentStream(options) {
4867
4942
  };
4868
4943
  });
4869
4944
  const pageLang = setup2.metadataResult.pageLang || lang;
4870
- let headWithLang = htmlHead.replace(/<html([^>]*)>/i, `<html$1 lang="${pageLang}">`);
4945
+ let headWithLang = htmlHead.replace(/<html([^>]*)>/i, (_m, attrs) => {
4946
+ const hasLang = /(^|\s)lang\s*=/.test(attrs);
4947
+ const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${pageLang}"`) : `${attrs} lang="${pageLang}"`;
4948
+ return `<html${newAttrs}>`;
4949
+ });
4871
4950
  const extraHead = setup2.bundlePreload + setup2.preloadExtraHead + setup2.metadataResult.perPageHead;
4872
4951
  if (/<title[\s\S]*?<\/title>/i.test(extraHead)) {
4873
4952
  headWithLang = headWithLang.replace(/<title[\s\S]*?<\/title>/i, "");
@@ -4875,6 +4954,7 @@ async function renderSSRDocumentStream(options) {
4875
4954
  if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHead)) {
4876
4955
  headWithLang = headWithLang.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
4877
4956
  }
4957
+ headWithLang = removeOverriddenMetaTags(headWithLang, extraHead);
4878
4958
  const config = await loadConfig(cwd);
4879
4959
  const browserTelemetryConfigRaw = config.telemetry?.browser;
4880
4960
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
@@ -4923,7 +5003,7 @@ async function streamSSRContent(writer, encoder, ctx) {
4923
5003
  try {
4924
5004
  const combinedHead = deduplicateMetaTags([ctx.inlineStyleTag, ctx.head, ctx.extraHead].filter(Boolean).join(`
4925
5005
  `));
4926
- const headWithLangAndContent = ctx.headWithLang.replace(/<html([^>]*)>/i, `<html$1 lang="${ctx.pageLang}">`).replace(/<\/head>/i, `${combinedHead ? `${combinedHead}
5006
+ const headWithLangAndContent = ctx.headWithLang.replace(/<\/head>/i, `${combinedHead ? `${combinedHead}
4927
5007
  ` : ""}</head>`);
4928
5008
  const headContent = `${headWithLangAndContent}`;
4929
5009
  await writer.write(encoder.encode(headContent));
@@ -5067,6 +5147,7 @@ export {
5067
5147
  renderSSRDocumentStream,
5068
5148
  renderSSRDocument,
5069
5149
  renderOGImageToPNG,
5150
+ removeOverriddenMetaTags,
5070
5151
  processCollections,
5071
5152
  preloadContentModule,
5072
5153
  performSSRSetup,
@@ -5158,4 +5239,4 @@ export {
5158
5239
  AI_CRAWLERS
5159
5240
  };
5160
5241
 
5161
- //# debugId=E62D0A5A4385690C64756E2164756E21
5242
+ //# debugId=017ADDEC50C3D37964756E2164756E21