reroute-js 0.40.2 → 0.41.1

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 (194) hide show
  1. package/cli/bin.d.ts +1 -1
  2. package/cli/bin.js +206 -71
  3. package/cli/bin.js.map +13 -13
  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/gen.d.ts.map +1 -1
  13. package/cli/src/commands/index.d.ts +1 -1
  14. package/cli/src/commands/init.d.ts +1 -1
  15. package/cli/src/commands/lib/assets.d.ts +1 -1
  16. package/cli/src/commands/lib/bundler.d.ts +1 -1
  17. package/cli/src/commands/lib/command.d.ts +1 -1
  18. package/cli/src/commands/lib/env.d.ts +1 -1
  19. package/cli/src/commands/lib/index.d.ts +1 -1
  20. package/cli/src/commands/lib/log.d.ts +1 -1
  21. package/cli/src/commands/lib/markdown/availability.d.ts +1 -1
  22. package/cli/src/commands/lib/markdown/index.d.ts +1 -1
  23. package/cli/src/commands/lib/markdown/processor.d.ts +1 -1
  24. package/cli/src/commands/lib/production.d.ts +1 -1
  25. package/cli/src/commands/lib/server.d.ts +1 -1
  26. package/cli/src/commands/lib/streaming/analyzer.d.ts +1 -1
  27. package/cli/src/commands/lib/streaming/suspense.d.ts +1 -1
  28. package/cli/src/commands/lib/tailwind.d.ts +1 -1
  29. package/cli/src/commands/lib/terminal-ui.d.ts +1 -1
  30. package/cli/src/commands/lib/version.d.ts +1 -1
  31. package/cli/src/commands/og.d.ts +1 -1
  32. package/cli/src/commands/start.d.ts +1 -1
  33. package/cli/src/index.d.ts +1 -1
  34. package/core/index.d.ts +1 -1
  35. package/core/index.js +148 -46
  36. package/core/index.js.map +12 -12
  37. package/core/src/bundler/hash.d.ts +1 -1
  38. package/core/src/bundler/index.d.ts +1 -1
  39. package/core/src/config.d.ts +42 -2
  40. package/core/src/config.d.ts.map +1 -1
  41. package/core/src/content/discovery.d.ts +1 -1
  42. package/core/src/content/index.d.ts +1 -1
  43. package/core/src/content/metadata.d.ts +7 -2
  44. package/core/src/content/metadata.d.ts.map +1 -1
  45. package/core/src/index.d.ts +1 -1
  46. package/core/src/llms/extractor.d.ts +1 -1
  47. package/core/src/llms/formatter.d.ts +1 -1
  48. package/core/src/llms/full-generator.d.ts +1 -1
  49. package/core/src/llms/index-generator.d.ts +1 -1
  50. package/core/src/llms/index.d.ts +1 -1
  51. package/core/src/og/discovery.d.ts +1 -1
  52. package/core/src/og/index.d.ts +1 -1
  53. package/core/src/og/meta.d.ts +1 -1
  54. package/core/src/og/render.d.ts +1 -1
  55. package/core/src/og/types.d.ts +1 -1
  56. package/core/src/robots/discovery.d.ts +1 -1
  57. package/core/src/robots/generator.d.ts +1 -1
  58. package/core/src/robots/index.d.ts +1 -1
  59. package/core/src/robots/policies.d.ts +1 -1
  60. package/core/src/rss/discovery.d.ts +1 -1
  61. package/core/src/rss/discovery.d.ts.map +1 -1
  62. package/core/src/rss/generator.d.ts +1 -1
  63. package/core/src/rss/index.d.ts +1 -1
  64. package/core/src/sitemap/discovery.d.ts +1 -1
  65. package/core/src/sitemap/discovery.d.ts.map +1 -1
  66. package/core/src/sitemap/generator.d.ts +1 -1
  67. package/core/src/sitemap/index.d.ts +1 -1
  68. package/core/src/ssr/index.d.ts +1 -1
  69. package/core/src/ssr/lib/cache.d.ts +1 -1
  70. package/core/src/ssr/lib/collections.d.ts +1 -1
  71. package/core/src/ssr/lib/compression.d.ts +1 -1
  72. package/core/src/ssr/lib/compute/content.d.ts +1 -1
  73. package/core/src/ssr/lib/compute/index.d.ts +1 -1
  74. package/core/src/ssr/lib/compute/layouts.d.ts +1 -1
  75. package/core/src/ssr/lib/compute/routes.d.ts +1 -1
  76. package/core/src/ssr/lib/data.d.ts +1 -1
  77. package/core/src/ssr/lib/html.d.ts +6 -1
  78. package/core/src/ssr/lib/html.d.ts.map +1 -1
  79. package/core/src/ssr/lib/imports.d.ts +1 -1
  80. package/core/src/ssr/lib/index.d.ts +1 -1
  81. package/core/src/ssr/lib/layouts.d.ts +1 -1
  82. package/core/src/ssr/lib/metadata.d.ts +3 -3
  83. package/core/src/ssr/lib/metadata.d.ts.map +1 -1
  84. package/core/src/ssr/lib/mime.d.ts +1 -1
  85. package/core/src/ssr/lib/modules.d.ts +1 -1
  86. package/core/src/ssr/lib/path.d.ts +1 -1
  87. package/core/src/ssr/lib/preload.d.ts +1 -1
  88. package/core/src/ssr/lib/scripts/collections.d.ts +1 -1
  89. package/core/src/ssr/lib/scripts/data.d.ts +1 -1
  90. package/core/src/ssr/lib/scripts/escape.d.ts +1 -1
  91. package/core/src/ssr/lib/scripts/feeds.d.ts +1 -1
  92. package/core/src/ssr/lib/scripts/index.d.ts +1 -1
  93. package/core/src/ssr/lib/seed.d.ts +1 -1
  94. package/core/src/ssr/lib/serialize.d.ts +1 -1
  95. package/core/src/ssr/lib/setup.d.ts +3 -2
  96. package/core/src/ssr/lib/setup.d.ts.map +1 -1
  97. package/core/src/ssr/lib/styles.d.ts +1 -1
  98. package/core/src/ssr/lib/template.d.ts +1 -1
  99. package/core/src/ssr/lib/types.d.ts +1 -1
  100. package/core/src/ssr/render.d.ts +3 -2
  101. package/core/src/ssr/render.d.ts.map +1 -1
  102. package/core/src/ssr/stream.d.ts +3 -2
  103. package/core/src/ssr/stream.d.ts.map +1 -1
  104. package/elysia/index.d.ts +1 -1
  105. package/elysia/index.js +326 -127
  106. package/elysia/index.js.map +18 -18
  107. package/elysia/src/index.d.ts +1 -1
  108. package/elysia/src/libs/assets.d.ts +1 -1
  109. package/elysia/src/libs/cache.d.ts +1 -1
  110. package/elysia/src/libs/caching.d.ts +1 -1
  111. package/elysia/src/libs/http.d.ts +1 -1
  112. package/elysia/src/libs/image.d.ts +1 -1
  113. package/elysia/src/libs/index.d.ts +1 -1
  114. package/elysia/src/libs/llms.d.ts +1 -1
  115. package/elysia/src/libs/response.d.ts +1 -1
  116. package/elysia/src/libs/serving.d.ts +1 -1
  117. package/elysia/src/plugin.d.ts +1 -1
  118. package/elysia/src/plugin.d.ts.map +1 -1
  119. package/elysia/src/routes/artifacts.d.ts +1 -1
  120. package/elysia/src/routes/content.d.ts +1 -1
  121. package/elysia/src/routes/image.d.ts +1 -1
  122. package/elysia/src/routes/index.d.ts +1 -1
  123. package/elysia/src/routes/internal.d.ts +1 -1
  124. package/elysia/src/routes/internal.d.ts.map +1 -1
  125. package/elysia/src/routes/llms.d.ts +1 -1
  126. package/elysia/src/routes/og.d.ts +1 -1
  127. package/elysia/src/routes/og.d.ts.map +1 -1
  128. package/elysia/src/routes/redirects.d.ts +1 -1
  129. package/elysia/src/routes/robots.d.ts +1 -1
  130. package/elysia/src/routes/rss.d.ts +2 -2
  131. package/elysia/src/routes/rss.d.ts.map +1 -1
  132. package/elysia/src/routes/search.d.ts +1 -1
  133. package/elysia/src/routes/sitemap.d.ts +2 -2
  134. package/elysia/src/routes/sitemap.d.ts.map +1 -1
  135. package/elysia/src/routes/ssr.d.ts +3 -2
  136. package/elysia/src/routes/ssr.d.ts.map +1 -1
  137. package/elysia/src/routes/static.d.ts +1 -1
  138. package/elysia/src/types.d.ts +1 -1
  139. package/package.json +1 -1
  140. package/react/index.d.ts +1 -1
  141. package/react/index.js +2 -2
  142. package/react/index.js.map +1 -1
  143. package/react/src/components/ClientOnly.d.ts +1 -1
  144. package/react/src/components/ContentRoute.d.ts +1 -1
  145. package/react/src/components/Image.d.ts +1 -1
  146. package/react/src/components/LazyRoute.d.ts +1 -1
  147. package/react/src/components/Link.d.ts +1 -1
  148. package/react/src/components/Markdown.d.ts +1 -1
  149. package/react/src/components/Outlet.d.ts +1 -1
  150. package/react/src/components/index.d.ts +1 -1
  151. package/react/src/hooks/index.d.ts +1 -1
  152. package/react/src/hooks/useContent.d.ts +1 -1
  153. package/react/src/hooks/useData.d.ts +1 -1
  154. package/react/src/hooks/useFeed.d.ts +1 -1
  155. package/react/src/hooks/useLayoutData.d.ts +1 -1
  156. package/react/src/hooks/useLlms.d.ts +1 -1
  157. package/react/src/hooks/useNavigate.d.ts +1 -1
  158. package/react/src/hooks/useParams.d.ts +1 -1
  159. package/react/src/hooks/useRouter.d.ts +1 -1
  160. package/react/src/hooks/useSearch.d.ts +1 -1
  161. package/react/src/hooks/useSearchParams.d.ts +1 -1
  162. package/react/src/hooks/useToc.d.ts +1 -1
  163. package/react/src/index.d.ts +1 -1
  164. package/react/src/lib/collection.d.ts +1 -1
  165. package/react/src/lib/content.d.ts +1 -1
  166. package/react/src/lib/head.d.ts +1 -1
  167. package/react/src/lib/index.d.ts +1 -1
  168. package/react/src/lib/lazy-route.d.ts +1 -1
  169. package/react/src/lib/route-loader.d.ts +1 -1
  170. package/react/src/providers/ContentProvider.d.ts +1 -1
  171. package/react/src/providers/RerouteProvider.d.ts +1 -1
  172. package/react/src/providers/RouterProvider.d.ts +1 -1
  173. package/react/src/providers/index.d.ts +1 -1
  174. package/react/src/types/any.d.ts +1 -1
  175. package/react/src/types/index.d.ts +1 -1
  176. package/react/src/types/router.d.ts +1 -1
  177. package/telemetry/react.d.ts +1 -1
  178. package/telemetry/react.js +2 -2
  179. package/telemetry/react.js.map +1 -1
  180. package/telemetry/server.d.ts +1 -1
  181. package/telemetry/server.js +2 -2
  182. package/telemetry/server.js.map +8 -8
  183. package/telemetry/src/react/api.d.ts +1 -1
  184. package/telemetry/src/react/context.d.ts +1 -1
  185. package/telemetry/src/react/index.d.ts +1 -1
  186. package/telemetry/src/react/telemetry.d.ts +1 -1
  187. package/telemetry/src/server/context.d.ts +1 -1
  188. package/telemetry/src/server/headers/extractor.d.ts +1 -1
  189. package/telemetry/src/server/headers/index.d.ts +1 -1
  190. package/telemetry/src/server/headers/presets.d.ts +1 -1
  191. package/telemetry/src/server/index.d.ts +1 -1
  192. package/telemetry/src/server/instrumentation.d.ts +1 -1
  193. package/telemetry/src/server/plugin.d.ts +1 -1
  194. package/telemetry/src/server/sourcemap.d.ts +1 -1
package/elysia/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * reroute-js v0.40.2
2
+ * reroute-js v0.41.1
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(() => {
@@ -1806,7 +1845,25 @@ function generateOgUrl(baseUrl, pathname) {
1806
1845
  const ogUrl = `${cleanBaseUrl}${normalizedPath}`;
1807
1846
  return `<meta property="og:url" content="${ogUrl}" />`;
1808
1847
  }
1809
- 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) {
1810
1867
  let perPageHead = "";
1811
1868
  let pageLang;
1812
1869
  let statusOverride = currentStatusOverride;
@@ -1815,7 +1872,7 @@ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, curren
1815
1872
  }, (lang) => {
1816
1873
  if (!pageLang)
1817
1874
  pageLang = lang;
1818
- });
1875
+ }, ogConfig);
1819
1876
  const shouldGenerateCanonical = autoCanonical !== false && baseUrl !== undefined;
1820
1877
  if (shouldGenerateCanonical) {
1821
1878
  const canonicalTag = generateCanonicalUrl(baseUrl, pathname);
@@ -1825,8 +1882,15 @@ ${canonicalTag}`;
1825
1882
  perPageHead += `
1826
1883
  ${ogUrlTag}`;
1827
1884
  }
1885
+ if (ogConfig) {
1886
+ const ogGlobalTags = generateGlobalOGTags(ogConfig);
1887
+ if (ogGlobalTags) {
1888
+ perPageHead += `
1889
+ ${ogGlobalTags}`;
1890
+ }
1891
+ }
1828
1892
  try {
1829
- const ogMetaTags = await generateOGImageMetaTags(pathname, clientDir, ogConfig);
1893
+ const ogMetaTags = await generateOGImageMetaTags(pathname, clientDir, ogImageConfig);
1830
1894
  if (ogMetaTags) {
1831
1895
  perPageHead += `
1832
1896
  ${ogMetaTags}`;
@@ -1838,22 +1902,22 @@ ${ogMetaTags}`;
1838
1902
  perPageHead += head;
1839
1903
  }, (lang) => {
1840
1904
  pageLang = lang;
1841
- });
1842
- const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData);
1905
+ }, ogConfig);
1906
+ const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig);
1843
1907
  perPageHead += routeResult.head;
1844
1908
  if (routeResult.lang)
1845
1909
  pageLang = routeResult.lang;
1846
1910
  statusOverride = routeResult.statusOverride;
1847
1911
  return { perPageHead, pageLang, statusOverride };
1848
1912
  }
1849
- async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang) {
1913
+ async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig) {
1850
1914
  if (typeof layout?.path !== "string")
1851
1915
  return;
1852
1916
  try {
1853
1917
  const abs = join(clientDir, "routes", String(layout.path));
1854
1918
  const { meta, ssr } = await loadModuleMetaAndSSR(layout, abs, isWatchMode);
1855
1919
  if (meta)
1856
- addHead(buildHeadFromMeta(meta));
1920
+ addHead(buildHeadFromMeta(meta, ogConfig));
1857
1921
  if (ssr) {
1858
1922
  const ssrHead = extractSSRHead(ssr);
1859
1923
  if (ssrHead)
@@ -1865,16 +1929,16 @@ ${ssrHead}`);
1865
1929
  }
1866
1930
  } catch {}
1867
1931
  }
1868
- async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang) {
1932
+ async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang, ogConfig) {
1869
1933
  try {
1870
1934
  const m = await loadRoutesModule(cwd, isWatchMode);
1871
1935
  const matchingLayouts = getMatchingLayouts(pathname, m?.layouts);
1872
1936
  for (const layout of matchingLayouts) {
1873
- await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang);
1937
+ await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig);
1874
1938
  }
1875
1939
  } catch {}
1876
1940
  }
1877
- function extractContentMetadata(pathname, addHead, setLang) {
1941
+ function extractContentMetadata(pathname, addHead, setLang, ogConfig) {
1878
1942
  try {
1879
1943
  const parts = pathname.split("/").filter(Boolean);
1880
1944
  if (parts.length < 2)
@@ -1884,7 +1948,7 @@ function extractContentMetadata(pathname, addHead, setLang) {
1884
1948
  const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
1885
1949
  const meta = exp?.meta;
1886
1950
  const ssr = exp?.ssr;
1887
- addHead(buildHeadFromMeta(meta));
1951
+ addHead(buildHeadFromMeta(meta, ogConfig));
1888
1952
  const ssrHead = extractSSRHead(ssr);
1889
1953
  if (ssrHead)
1890
1954
  addHead(`
@@ -1894,7 +1958,7 @@ ${ssrHead}`);
1894
1958
  setLang(lang);
1895
1959
  } catch {}
1896
1960
  }
1897
- async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData) {
1961
+ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig) {
1898
1962
  const pathnameOnly = pathname.split("?")[0];
1899
1963
  const match = typeof m.matchRoute === "function" ? m.matchRoute(pathnameOnly) : null;
1900
1964
  const r = match?.route;
@@ -1907,7 +1971,7 @@ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode,
1907
1971
  const { meta, ssr } = await loadModuleMetaAndSSR(r, abs, isWatchMode);
1908
1972
  let head = "";
1909
1973
  if (meta)
1910
- head += buildHeadFromMeta(meta);
1974
+ head += buildHeadFromMeta(meta, ogConfig);
1911
1975
  if (ssr) {
1912
1976
  const routeData = ssrData && typeof ssrData === "object" ? ssrData[pathname] : undefined;
1913
1977
  const ssrHead = extractSSRHead(ssr, routeData);
@@ -1921,7 +1985,7 @@ ${ssrHead}`;
1921
1985
  }
1922
1986
  return { head: "", statusOverride };
1923
1987
  }
1924
- async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData) {
1988
+ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig) {
1925
1989
  let head = "";
1926
1990
  let lang;
1927
1991
  let statusOverride = currentStatusOverride;
@@ -1937,14 +2001,14 @@ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, curre
1937
2001
  statusOverride = statusOverride || 404;
1938
2002
  }
1939
2003
  if (r && typeof r.path === "string") {
1940
- const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData);
2004
+ const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig);
1941
2005
  head = result.head;
1942
2006
  lang = result.lang;
1943
2007
  statusOverride = result.statusOverride;
1944
2008
  } else {
1945
2009
  head += await extractNotFoundMetadata(pathname, clientDir, m, isWatchMode, (l) => {
1946
2010
  lang = l;
1947
- });
2011
+ }, ogConfig);
1948
2012
  }
1949
2013
  } catch {}
1950
2014
  return { head, lang, statusOverride };
@@ -1964,7 +2028,7 @@ function findBestNotFoundRoute(list, pathname) {
1964
2028
  }
1965
2029
  return chosen;
1966
2030
  }
1967
- async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatchMode, setLang) {
2031
+ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatchMode, setLang, ogConfig) {
1968
2032
  let head = "";
1969
2033
  try {
1970
2034
  const list = routesModule?.notFoundRoutes;
@@ -1975,7 +2039,7 @@ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatc
1975
2039
  const abs = join(clientDir, "routes", String(chosen.path));
1976
2040
  const { meta, ssr } = await loadModuleMetaAndSSR(chosen, abs, isWatchMode);
1977
2041
  if (meta)
1978
- head += buildHeadFromMeta(meta);
2042
+ head += buildHeadFromMeta(meta, ogConfig);
1979
2043
  const ssrHead = extractSSRHead(ssr);
1980
2044
  if (ssrHead)
1981
2045
  head += `
@@ -2562,7 +2626,7 @@ async function performSSRSetupInternal(options, streaming) {
2562
2626
  statusOverride = computeResult.statusContainer.value;
2563
2627
  }
2564
2628
  const metadataResult = await withSpan("ssr.extract.metadata", async (span) => {
2565
- 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);
2566
2630
  span.setAttributes({
2567
2631
  "reroute.pathname": pathname,
2568
2632
  "reroute.metadata.exists": !!result.perPageHead
@@ -2732,6 +2796,7 @@ async function renderSSRDocument(options) {
2732
2796
  maxAge,
2733
2797
  searchParams,
2734
2798
  ogConfig,
2799
+ ogMetaConfig: options.ogMetaConfig,
2735
2800
  baseUrl: options.baseUrl,
2736
2801
  autoCanonical: options.autoCanonical,
2737
2802
  cachedCollections: options.cachedCollections,
@@ -3996,13 +4061,13 @@ async function discoverSSRDataRoutes2(cwd, staticRoutes, isWatchMode, baseUrl, s
3996
4061
  const ssrDataRoutes = new Map;
3997
4062
  const bundledRoutes = globalThis.__REROUTE_ROUTES__;
3998
4063
  if (bundledRoutes && Array.isArray(bundledRoutes)) {
3999
- for (const route of staticRoutes) {
4064
+ const routePromises = staticRoutes.map(async (route) => {
4000
4065
  if (sitemapConfig?.excludeDiscovery?.some((excluded) => route.pattern.startsWith(excluded))) {
4001
- continue;
4066
+ return null;
4002
4067
  }
4003
4068
  const bundledRoute = bundledRoutes.find((r) => r?.pattern === route.pattern);
4004
4069
  if (!bundledRoute)
4005
- continue;
4070
+ return null;
4006
4071
  const ssr = bundledRoute?.ssr;
4007
4072
  const dataFn = ssr?.data;
4008
4073
  if (typeof dataFn === "function") {
@@ -4015,15 +4080,22 @@ async function discoverSSRDataRoutes2(cwd, staticRoutes, isWatchMode, baseUrl, s
4015
4080
  });
4016
4081
  const entries = extractEntriesFromData(result, route.pattern, baseUrl, sitemapConfig);
4017
4082
  if (entries.length > 0) {
4018
- ssrDataRoutes.set(route.pattern, entries);
4083
+ return { pattern: route.pattern, entries };
4019
4084
  }
4020
4085
  } catch {}
4021
4086
  }
4087
+ return null;
4088
+ });
4089
+ const results = await Promise.all(routePromises);
4090
+ for (const result of results) {
4091
+ if (result) {
4092
+ ssrDataRoutes.set(result.pattern, result.entries);
4093
+ }
4022
4094
  }
4023
4095
  } else {
4024
- for (const route of staticRoutes) {
4096
+ const routePromises = staticRoutes.map(async (route) => {
4025
4097
  if (sitemapConfig?.excludeDiscovery?.some((excluded) => route.pattern.startsWith(excluded))) {
4026
- continue;
4098
+ return null;
4027
4099
  }
4028
4100
  try {
4029
4101
  const routeModulePath = join(cwd, "src", "client", "routes", route.path);
@@ -4039,10 +4111,17 @@ async function discoverSSRDataRoutes2(cwd, staticRoutes, isWatchMode, baseUrl, s
4039
4111
  });
4040
4112
  const entries = extractEntriesFromData(result, route.pattern, baseUrl, sitemapConfig);
4041
4113
  if (entries.length > 0) {
4042
- ssrDataRoutes.set(route.pattern, entries);
4114
+ return { pattern: route.pattern, entries };
4043
4115
  }
4044
4116
  }
4045
4117
  } catch {}
4118
+ return null;
4119
+ });
4120
+ const results = await Promise.all(routePromises);
4121
+ for (const result of results) {
4122
+ if (result) {
4123
+ ssrDataRoutes.set(result.pattern, result.entries);
4124
+ }
4046
4125
  }
4047
4126
  }
4048
4127
  return ssrDataRoutes;
@@ -4418,24 +4497,28 @@ function createRSSItemFromData(item, routePattern, baseUrl, rssConfig) {
4418
4497
  }
4419
4498
  async function discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfig) {
4420
4499
  const collectionsMap = new Map;
4421
- for (const collection of collections2) {
4500
+ const collectionPromises = collections2.map(async (collection) => {
4422
4501
  const items = await discoverCollectionFeedItems(cwd, collection, isWatchMode, baseUrl, rssConfig);
4423
- if (items.length > 0) {
4424
- collectionsMap.set(collection, items);
4502
+ return items.length > 0 ? { collection, items } : null;
4503
+ });
4504
+ const collectionResults = await Promise.all(collectionPromises);
4505
+ for (const result of collectionResults) {
4506
+ if (result) {
4507
+ collectionsMap.set(result.collection, result.items);
4425
4508
  }
4426
4509
  }
4427
4510
  const ssrDataFeeds = new Map;
4428
4511
  const bundledRoutes = globalThis.__REROUTE_ROUTES__;
4512
+ const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery4(), exports_discovery));
4513
+ const { staticRoutes } = await discoverRoutes2(cwd, isWatchMode);
4429
4514
  if (bundledRoutes && Array.isArray(bundledRoutes)) {
4430
- const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery4(), exports_discovery));
4431
- const { staticRoutes } = await discoverRoutes2(cwd, isWatchMode);
4432
- for (const route of staticRoutes) {
4515
+ const routePromises = staticRoutes.map(async (route) => {
4433
4516
  if (rssConfig?.excludeDiscovery?.some((excluded) => route.pattern.startsWith(excluded))) {
4434
- continue;
4517
+ return null;
4435
4518
  }
4436
4519
  const bundledRoute = bundledRoutes.find((r) => r?.pattern === route.pattern);
4437
4520
  if (!bundledRoute)
4438
- continue;
4521
+ return null;
4439
4522
  const ssr = bundledRoute?.ssr;
4440
4523
  const dataFn = ssr?.data;
4441
4524
  if (typeof dataFn === "function") {
@@ -4448,21 +4531,33 @@ async function discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfi
4448
4531
  });
4449
4532
  const items = extractRSSItemsFromData(result, route.pattern, baseUrl, rssConfig);
4450
4533
  if (items.length > 0) {
4451
- ssrDataFeeds.set(route.pattern, items);
4534
+ return { pattern: route.pattern, items };
4452
4535
  }
4453
4536
  } catch {}
4454
4537
  }
4538
+ return null;
4539
+ });
4540
+ const results = await Promise.all(routePromises);
4541
+ for (const result of results) {
4542
+ if (result) {
4543
+ ssrDataFeeds.set(result.pattern, result.items);
4544
+ }
4455
4545
  }
4456
4546
  } else {
4457
- const { discoverRoutes: discoverRoutes2 } = await Promise.resolve().then(() => (init_discovery4(), exports_discovery));
4458
- const { staticRoutes } = await discoverRoutes2(cwd, isWatchMode);
4459
- for (const route of staticRoutes) {
4547
+ const routePromises = staticRoutes.map(async (route) => {
4460
4548
  if (rssConfig?.excludeDiscovery?.some((excluded) => route.pattern.startsWith(excluded))) {
4461
- continue;
4549
+ return null;
4462
4550
  }
4463
4551
  const items = await discoverSSRDataFeedItems(cwd, route.pattern, route.path, isWatchMode, baseUrl, rssConfig);
4464
4552
  if (items.length > 0) {
4465
- ssrDataFeeds.set(route.pattern, items);
4553
+ return { pattern: route.pattern, items };
4554
+ }
4555
+ return null;
4556
+ });
4557
+ const results = await Promise.all(routePromises);
4558
+ for (const result of results) {
4559
+ if (result) {
4560
+ ssrDataFeeds.set(result.pattern, result.items);
4466
4561
  }
4467
4562
  }
4468
4563
  }
@@ -4842,6 +4937,7 @@ async function renderSSRDocumentStream(options) {
4842
4937
  maxAge,
4843
4938
  searchParams,
4844
4939
  ogConfig,
4940
+ ogMetaConfig: options.ogMetaConfig,
4845
4941
  baseUrl: options.baseUrl,
4846
4942
  autoCanonical: options.autoCanonical,
4847
4943
  cachedCollections: options.cachedCollections,
@@ -4876,7 +4972,11 @@ async function renderSSRDocumentStream(options) {
4876
4972
  };
4877
4973
  });
4878
4974
  const pageLang = setup2.metadataResult.pageLang || lang;
4879
- let headWithLang = htmlHead.replace(/<html([^>]*)>/i, `<html$1 lang="${pageLang}">`);
4975
+ let headWithLang = htmlHead.replace(/<html([^>]*)>/i, (_m, attrs) => {
4976
+ const hasLang = /(^|\s)lang\s*=/.test(attrs);
4977
+ const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${pageLang}"`) : `${attrs} lang="${pageLang}"`;
4978
+ return `<html${newAttrs}>`;
4979
+ });
4880
4980
  const extraHead = setup2.bundlePreload + setup2.preloadExtraHead + setup2.metadataResult.perPageHead;
4881
4981
  if (/<title[\s\S]*?<\/title>/i.test(extraHead)) {
4882
4982
  headWithLang = headWithLang.replace(/<title[\s\S]*?<\/title>/i, "");
@@ -4884,6 +4984,7 @@ async function renderSSRDocumentStream(options) {
4884
4984
  if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHead)) {
4885
4985
  headWithLang = headWithLang.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
4886
4986
  }
4987
+ headWithLang = removeOverriddenMetaTags(headWithLang, extraHead);
4887
4988
  const config = await loadConfig(cwd);
4888
4989
  const browserTelemetryConfigRaw = config.telemetry?.browser;
4889
4990
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
@@ -4932,7 +5033,7 @@ async function streamSSRContent(writer, encoder, ctx) {
4932
5033
  try {
4933
5034
  const combinedHead = deduplicateMetaTags([ctx.inlineStyleTag, ctx.head, ctx.extraHead].filter(Boolean).join(`
4934
5035
  `));
4935
- const headWithLangAndContent = ctx.headWithLang.replace(/<html([^>]*)>/i, `<html$1 lang="${ctx.pageLang}">`).replace(/<\/head>/i, `${combinedHead ? `${combinedHead}
5036
+ const headWithLangAndContent = ctx.headWithLang.replace(/<\/head>/i, `${combinedHead ? `${combinedHead}
4936
5037
  ` : ""}</head>`);
4937
5038
  const headContent = `${headWithLangAndContent}`;
4938
5039
  await writer.write(encoder.encode(headContent));
@@ -5072,6 +5173,7 @@ __export(exports_core, {
5072
5173
  renderSSRDocumentStream: () => renderSSRDocumentStream,
5073
5174
  renderSSRDocument: () => renderSSRDocument,
5074
5175
  renderOGImageToPNG: () => renderOGImageToPNG,
5176
+ removeOverriddenMetaTags: () => removeOverriddenMetaTags,
5075
5177
  processCollections: () => processCollections,
5076
5178
  preloadContentModule: () => preloadContentModule,
5077
5179
  performSSRSetup: () => performSSRSetup,
@@ -5970,6 +6072,8 @@ let hasConnected = false;
5970
6072
  let wasDisconnected = false;
5971
6073
  let reloadTriggered = false;
5972
6074
  let rebuildNotice = null;
6075
+ let reconnectAttempts = 0;
6076
+ let isReconnecting = false;
5973
6077
 
5974
6078
  function showRebuildNotice() {
5975
6079
  if (rebuildNotice) return;
@@ -6047,6 +6151,43 @@ function hideRebuildNotice() {
6047
6151
  }
6048
6152
  }
6049
6153
 
6154
+ // Check if server is ready before attempting SSE connection
6155
+ async function waitForServer() {
6156
+ const maxAttempts = 60; // 30 seconds max
6157
+ for (let i = 0; i < maxAttempts; i++) {
6158
+ try {
6159
+ const res = await fetch('/__reroute_watch.js', { method: 'HEAD' });
6160
+ if (res.ok) return true;
6161
+ } catch {
6162
+ // Server not ready, continue waiting
6163
+ }
6164
+ await new Promise(r => setTimeout(r, 500));
6165
+ }
6166
+ return false;
6167
+ }
6168
+
6169
+ async function scheduleReconnect() {
6170
+ if (reloadTriggered || isReconnecting) return;
6171
+ isReconnecting = true;
6172
+
6173
+ // Exponential backoff: 300ms, 600ms, 1200ms, max 2000ms
6174
+ const delay = Math.min(300 * Math.pow(2, reconnectAttempts), 2000);
6175
+ reconnectAttempts++;
6176
+
6177
+ await new Promise(r => setTimeout(r, delay));
6178
+
6179
+ // Wait for server to be ready before creating EventSource
6180
+ const ready = await waitForServer();
6181
+ isReconnecting = false;
6182
+
6183
+ if (ready && !reloadTriggered) {
6184
+ connect();
6185
+ } else if (!reloadTriggered) {
6186
+ // Server still not ready, try again
6187
+ scheduleReconnect();
6188
+ }
6189
+ }
6190
+
6050
6191
  function connect() {
6051
6192
  if (reloadTriggered) return;
6052
6193
 
@@ -6054,6 +6195,7 @@ function connect() {
6054
6195
 
6055
6196
  eventSource.addEventListener('message', (e) => {
6056
6197
  if (e.data === 'connected') {
6198
+ reconnectAttempts = 0; // Reset backoff on successful connection
6057
6199
  if (hasConnected && wasDisconnected && !reloadTriggered) {
6058
6200
  console.log('[reroute] ✓ Server restarted, reloading...');
6059
6201
  reloadTriggered = true;
@@ -6077,11 +6219,12 @@ function connect() {
6077
6219
  if (reloadTriggered) return;
6078
6220
  wasDisconnected = true;
6079
6221
  eventSource?.close();
6080
- if (hasConnected) {
6222
+ if (hasConnected && reconnectAttempts === 0) {
6223
+ // Only log on first disconnect to reduce console spam
6081
6224
  console.log('[reroute] \uD83D\uDD04 Server restarting...');
6082
6225
  showRebuildNotice();
6083
6226
  }
6084
- setTimeout(connect, 1000);
6227
+ scheduleReconnect();
6085
6228
  });
6086
6229
  }
6087
6230
 
@@ -6704,6 +6847,7 @@ function registerOGRoutes(app, options) {
6704
6847
  const width = ogConfig.width ?? 1200;
6705
6848
  const height = ogConfig.height ?? 630;
6706
6849
  const maxAge = ogConfig.maxAge ?? 3600;
6850
+ const generatingImages = new Set;
6707
6851
  function normalizeOgPathname(urlPathname) {
6708
6852
  let pathname = urlPathname.replace(/^\/__reroute_og/, "").replace(/\.png$/, "");
6709
6853
  if (pathname === "/index" || pathname === "index") {
@@ -6725,7 +6869,7 @@ function registerOGRoutes(app, options) {
6725
6869
  }
6726
6870
  return;
6727
6871
  }
6728
- async function generateOgImage(pathname, clientDir2, cwd2, isWatchMode2, ogConfig2, width2, height2, set) {
6872
+ async function generateOgImage(pathname, clientDir2, cwd2, isWatchMode2, ogConfig2, width2, height2) {
6729
6873
  const ogPath = await findOGImageForPath(pathname, clientDir2);
6730
6874
  const Component = await loadOgComponent(ogPath, ogConfig2, cwd2, isWatchMode2);
6731
6875
  if (!Component) {
@@ -6795,10 +6939,6 @@ function registerOGRoutes(app, options) {
6795
6939
  if (maxAge > 0) {
6796
6940
  ogCache.set(pathname, { buffer, exp: Date.now() + maxAge * 1000 });
6797
6941
  }
6798
- set.headers["content-type"] = "image/png";
6799
- set.headers["cache-control"] = `public, max-age=${maxAge}`;
6800
- set.headers["Reroute-Cache"] = "MISS";
6801
- return new Response(buffer);
6802
6942
  }
6803
6943
  app.get("/__reroute_og/*", async ({ request, set }) => {
6804
6944
  try {
@@ -6807,9 +6947,30 @@ function registerOGRoutes(app, options) {
6807
6947
  const cachedResponse = checkOgCache(pathname, set);
6808
6948
  if (cachedResponse)
6809
6949
  return cachedResponse;
6810
- return await generateOgImage(pathname, clientDir, cwd, isWatchMode, ogConfig, width, height, set);
6950
+ if (generatingImages.has(pathname)) {
6951
+ set.status = 404;
6952
+ set.headers["Retry-After"] = "2";
6953
+ return new Response("Image generation in progress", {
6954
+ status: 404,
6955
+ headers: { "Content-Type": "text/plain" }
6956
+ });
6957
+ }
6958
+ generatingImages.add(pathname);
6959
+ generateOgImage(pathname, clientDir, cwd, isWatchMode, ogConfig, width, height).then(() => {
6960
+ console.log(`[reroute/og] Generated image for: ${pathname}`);
6961
+ }).catch((error) => {
6962
+ console.error(`[reroute/og] Failed to generate image for ${pathname}:`, error);
6963
+ }).finally(() => {
6964
+ generatingImages.delete(pathname);
6965
+ });
6966
+ set.status = 404;
6967
+ set.headers["Retry-After"] = "2";
6968
+ return new Response("Image not yet available, please retry", {
6969
+ status: 404,
6970
+ headers: { "Content-Type": "text/plain" }
6971
+ });
6811
6972
  } catch (error) {
6812
- console.error("[reroute] Failed to generate OG image:", error);
6973
+ console.error("[reroute] Failed to handle OG image request:", error);
6813
6974
  set.status = 500;
6814
6975
  return new Response("Internal Server Error", {
6815
6976
  status: 500,
@@ -6953,6 +7114,23 @@ function registerRobotsRoute(app, options) {
6953
7114
  // packages/elysia/src/routes/rss.ts
6954
7115
  init_core();
6955
7116
  import { NotFoundError as NotFoundError8 } from "elysia";
7117
+ var rssDiscoveryCache = new LRUCache(1);
7118
+ async function getOrDiscoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfig) {
7119
+ if (isWatchMode) {
7120
+ return discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfig);
7121
+ }
7122
+ const cacheKey = "rss:discovery";
7123
+ const cached = rssDiscoveryCache.get(cacheKey);
7124
+ if (cached && cached.exp > Date.now()) {
7125
+ return cached.discovery;
7126
+ }
7127
+ const discovery5 = await discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfig);
7128
+ rssDiscoveryCache.set(cacheKey, {
7129
+ discovery: discovery5,
7130
+ exp: Date.now() + 5 * 60 * 1000
7131
+ });
7132
+ return discovery5;
7133
+ }
6956
7134
  function createFeedTitle(configTitle, name) {
6957
7135
  return configTitle ?? `${name.charAt(0).toUpperCase() + name.slice(1)} Feed`;
6958
7136
  }
@@ -6983,7 +7161,7 @@ async function registerMainFeedRoute(app, cwd, collections2, baseUrl, isWatchMod
6983
7161
  if (cached) {
6984
7162
  return feedResponse(cached.xml, format, { maxAge, cacheStatus: "HIT" });
6985
7163
  }
6986
- const discovery5 = await discoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfig);
7164
+ const discovery5 = await getOrDiscoverRSSData(cwd, collections2, baseUrl, isWatchMode, rssConfig);
6987
7165
  const allItems = [
6988
7166
  ...Array.from(discovery5.collections.values()).flat(),
6989
7167
  ...Array.from(discovery5.ssrDataFeeds.values()).flat()
@@ -7022,7 +7200,7 @@ function registerCollectionFeedRoutes(app, collections2, options) {
7022
7200
  cacheStatus: "HIT"
7023
7201
  });
7024
7202
  }
7025
- const discovery5 = await discoverRSSData(options.cwd, [collection], options.baseUrl, options.isWatchMode, options.rssConfig);
7203
+ const discovery5 = await getOrDiscoverRSSData(options.cwd, [collection], options.baseUrl, options.isWatchMode, options.rssConfig);
7026
7204
  const items = discovery5.collections.get(collection) ?? [];
7027
7205
  if (items.length === 0)
7028
7206
  throw new NotFoundError8;
@@ -7083,7 +7261,7 @@ async function generateSSRDataFeed(route, options) {
7083
7261
  }
7084
7262
  let items = await discoverSSRDataFeedItems(options.cwd, route.pattern, route.path, options.isWatchMode, options.baseUrl, options.rssConfig);
7085
7263
  if (items.length === 0 && route.isLayout) {
7086
- const discovery5 = await discoverRSSData(options.cwd, [], options.baseUrl, options.isWatchMode, options.rssConfig);
7264
+ const discovery5 = await getOrDiscoverRSSData(options.cwd, [], options.baseUrl, options.isWatchMode, options.rssConfig);
7087
7265
  items = discovery5.ssrDataFeeds.get(route.pattern) ?? [];
7088
7266
  }
7089
7267
  if (items.length === 0)
@@ -7140,7 +7318,6 @@ async function registerRSSRoutes(app, options) {
7140
7318
  const feedDescription = rssConfig?.description ?? "Latest updates";
7141
7319
  const availableFeeds = ["/feed.xml"];
7142
7320
  registerMainFeedRoute(app, cwd, collections2, baseUrl, isWatchMode, rssCache, format, limit, maxAge, ttlMs, feedTitle, feedDescription, rssConfig);
7143
- const ssrDataRoutes = await discoverSSRRoutes(cwd, isWatchMode);
7144
7321
  registerCollectionFeedRoutes(app, collections2, {
7145
7322
  cwd,
7146
7323
  clientDir,
@@ -7154,6 +7331,11 @@ async function registerRSSRoutes(app, options) {
7154
7331
  rssConfig,
7155
7332
  availableFeeds
7156
7333
  });
7334
+ if (isWatchMode) {
7335
+ globalThis.__REROUTE_AVAILABLE_FEEDS__ = availableFeeds;
7336
+ return app;
7337
+ }
7338
+ const ssrDataRoutes = await discoverSSRRoutes(cwd, isWatchMode);
7157
7339
  const routesWithFeeds = await discoverRoutesWithFeeds(ssrDataRoutes, collections2, {
7158
7340
  cwd,
7159
7341
  clientDir,
@@ -7304,9 +7486,26 @@ function registerSearchRoute(app, cwd, directive, maxAge, searchConfig) {
7304
7486
  // packages/elysia/src/routes/sitemap.ts
7305
7487
  init_core();
7306
7488
  import { NotFoundError as NotFoundError9 } from "elysia";
7489
+ var sitemapDiscoveryCache = new LRUCache(1);
7490
+ async function getOrDiscoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig) {
7491
+ if (isWatchMode) {
7492
+ return discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig);
7493
+ }
7494
+ const cacheKey = "sitemap:discovery";
7495
+ const cached = sitemapDiscoveryCache.get(cacheKey);
7496
+ if (cached && cached.exp > Date.now()) {
7497
+ return cached.discovery;
7498
+ }
7499
+ const discovery5 = await discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig);
7500
+ sitemapDiscoveryCache.set(cacheKey, {
7501
+ discovery: discovery5,
7502
+ exp: Date.now() + 5 * 60 * 1000
7503
+ });
7504
+ return discovery5;
7505
+ }
7307
7506
  async function generateAndCacheSitemap(options, _ttlMs) {
7308
7507
  const { cwd, collections: collections2, baseUrl, isWatchMode, sitemapConfig } = options;
7309
- const discovery5 = await discoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig);
7508
+ const discovery5 = await getOrDiscoverSitemapData(cwd, collections2, baseUrl, isWatchMode, sitemapConfig);
7310
7509
  const result = await generateSitemap(discovery5, baseUrl, {
7311
7510
  changefreq: sitemapConfig?.changefreq,
7312
7511
  priority: sitemapConfig?.priority,
@@ -7552,6 +7751,7 @@ function registerSSRRoutes(app, options) {
7552
7751
  maxAge,
7553
7752
  searchParams,
7554
7753
  ogConfig: options.ogConfig,
7754
+ ogMetaConfig: options.ogMetaConfig,
7555
7755
  baseUrl: options.baseUrl,
7556
7756
  autoCanonical: options.autoCanonical,
7557
7757
  parentSpan: renderSpan,
@@ -7730,6 +7930,7 @@ function registerSSRRoutes(app, options) {
7730
7930
  maxAge,
7731
7931
  searchParams,
7732
7932
  ogConfig: options.ogConfig,
7933
+ ogMetaConfig: options.ogMetaConfig,
7733
7934
  baseUrl: options.baseUrl,
7734
7935
  autoCanonical: options.autoCanonical,
7735
7936
  parentSpan: renderSpan,
@@ -8033,8 +8234,24 @@ var reroute = () => async (app) => {
8033
8234
  const shouldIgnore = !ignorePatterns.length ? () => false : (file) => ignorePatterns.find((pattern) => typeof pattern === "string" ? file.includes(pattern) : pattern.test(file));
8034
8235
  const isWatchMode = Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
8035
8236
  const dataCacheControl = `${directive}, max-age=${maxAge}`;
8036
- if (isWatchMode)
8237
+ if (isWatchMode) {
8037
8238
  console.log(`[reroute] Live reload enabled`);
8239
+ registerLiveReloadRoutes(app, liveReloadState);
8240
+ app.post("/__reroute_rebuilding", () => {
8241
+ console.log("[reroute] Rebuild notification received, notifying browsers...");
8242
+ notifyRebuilding();
8243
+ return new Response(JSON.stringify({ ok: true, clients: liveReloadState.clients.size }), {
8244
+ headers: { "content-type": "application/json" }
8245
+ });
8246
+ });
8247
+ app.post("/__reroute_reload", () => {
8248
+ console.log(`[reroute] Reload notification received, notifying ${liveReloadState.clients.size} browser(s)...`);
8249
+ notifyReload();
8250
+ return new Response(JSON.stringify({ ok: true, clients: liveReloadState.clients.size }), {
8251
+ headers: { "content-type": "application/json" }
8252
+ });
8253
+ });
8254
+ }
8038
8255
  const readBundleUrl = async () => {
8039
8256
  const bundlesDir = `${cwd}/.reroute/bundles`;
8040
8257
  const maxAttempts = isWatchMode ? 500 : 10;
@@ -8081,25 +8298,6 @@ var reroute = () => async (app) => {
8081
8298
  isWatchMode,
8082
8299
  maxAge
8083
8300
  });
8084
- if (isWatchMode) {
8085
- registerLiveReloadRoutes(app, liveReloadState);
8086
- }
8087
- if (isWatchMode) {
8088
- app.post("/__reroute_rebuilding", () => {
8089
- console.log("[reroute] Rebuild notification received, notifying browsers...");
8090
- notifyRebuilding();
8091
- return new Response(JSON.stringify({ ok: true, clients: liveReloadState.clients.size }), {
8092
- headers: { "content-type": "application/json" }
8093
- });
8094
- });
8095
- app.post("/__reroute_reload", () => {
8096
- console.log(`[reroute] Reload notification received, notifying ${liveReloadState.clients.size} browser(s)...`);
8097
- notifyReload();
8098
- return new Response(JSON.stringify({ ok: true, clients: liveReloadState.clients.size }), {
8099
- headers: { "content-type": "application/json" }
8100
- });
8101
- });
8102
- }
8103
8301
  registerArtifactsRoutes(app, cwd, fileCache, {
8104
8302
  bundleMaxAge,
8105
8303
  directive,
@@ -8148,6 +8346,39 @@ var reroute = () => async (app) => {
8148
8346
  console.error("[reroute] Failed to register robots route:", error);
8149
8347
  }
8150
8348
  }
8349
+ if (sitemapEnabled && sitemapBaseUrl) {
8350
+ try {
8351
+ registerSitemapRoutes(app, {
8352
+ cwd,
8353
+ collections: collections2,
8354
+ baseUrl: sitemapBaseUrl,
8355
+ maxAge,
8356
+ isWatchMode,
8357
+ sitemapCache,
8358
+ sitemapConfig
8359
+ });
8360
+ console.log(`[reroute] Sitemap enabled at ${sitemapBaseUrl}/sitemap.xml`);
8361
+ } catch (error) {
8362
+ console.error("[reroute] Failed to register sitemap routes:", error);
8363
+ }
8364
+ }
8365
+ if (rssEnabled && rssBaseUrl) {
8366
+ try {
8367
+ await registerRSSRoutes(app, {
8368
+ cwd,
8369
+ clientDir,
8370
+ collections: collections2,
8371
+ baseUrl: rssBaseUrl,
8372
+ maxAge,
8373
+ isWatchMode,
8374
+ rssCache,
8375
+ rssConfig
8376
+ });
8377
+ console.log(`[reroute] RSS feeds enabled at ${rssBaseUrl}/feed.xml`);
8378
+ } catch (error) {
8379
+ console.error("[reroute] Failed to register RSS routes:", error);
8380
+ }
8381
+ }
8151
8382
  if (llmsEnabled && llmsConfig) {
8152
8383
  try {
8153
8384
  registerLLMsRoutes(app, {
@@ -8178,6 +8409,20 @@ var reroute = () => async (app) => {
8178
8409
  console.error("[reroute] Failed to register LLMs routes:", error);
8179
8410
  }
8180
8411
  }
8412
+ if (ogEnabled && ogConfig) {
8413
+ try {
8414
+ registerOGRoutes(app, {
8415
+ clientDir,
8416
+ cwd,
8417
+ isWatchMode,
8418
+ ogConfig,
8419
+ ogCache
8420
+ });
8421
+ console.log("[reroute] OG image generation enabled");
8422
+ } catch (error) {
8423
+ console.error("[reroute] Failed to register OG routes:", error);
8424
+ }
8425
+ }
8181
8426
  registerSSRRoutes(app, {
8182
8427
  rootComponent,
8183
8428
  clientDir,
@@ -8197,56 +8442,10 @@ var reroute = () => async (app) => {
8197
8442
  streamingEnabled,
8198
8443
  streamingTimeout: globalConfig.streaming?.timeout,
8199
8444
  ogConfig,
8445
+ ogMetaConfig: globalConfig.og,
8200
8446
  baseUrl,
8201
8447
  autoCanonical
8202
8448
  });
8203
- if (sitemapEnabled && sitemapBaseUrl) {
8204
- try {
8205
- registerSitemapRoutes(app, {
8206
- cwd,
8207
- collections: collections2,
8208
- baseUrl: sitemapBaseUrl,
8209
- maxAge,
8210
- isWatchMode,
8211
- sitemapCache,
8212
- sitemapConfig
8213
- });
8214
- console.log(`[reroute] Sitemap enabled at ${sitemapBaseUrl}/sitemap.xml`);
8215
- } catch (error) {
8216
- console.error("[reroute] Failed to register sitemap routes:", error);
8217
- }
8218
- }
8219
- if (rssEnabled && rssBaseUrl) {
8220
- try {
8221
- await registerRSSRoutes(app, {
8222
- cwd,
8223
- clientDir,
8224
- collections: collections2,
8225
- baseUrl: rssBaseUrl,
8226
- maxAge,
8227
- isWatchMode,
8228
- rssCache,
8229
- rssConfig
8230
- });
8231
- console.log(`[reroute] RSS feeds enabled at ${rssBaseUrl}/feed.xml`);
8232
- } catch (error) {
8233
- console.error("[reroute] Failed to register RSS routes:", error);
8234
- }
8235
- }
8236
- if (ogEnabled && ogConfig) {
8237
- try {
8238
- registerOGRoutes(app, {
8239
- clientDir,
8240
- cwd,
8241
- isWatchMode,
8242
- ogConfig,
8243
- ogCache
8244
- });
8245
- console.log("[reroute] OG image generation enabled");
8246
- } catch (error) {
8247
- console.error("[reroute] Failed to register OG routes:", error);
8248
- }
8249
- }
8250
8449
  } catch (error) {
8251
8450
  console.error("[reroute] Failed to register SSR routes:", error);
8252
8451
  throw error;
@@ -8267,4 +8466,4 @@ export {
8267
8466
  reroute
8268
8467
  };
8269
8468
 
8270
- //# debugId=E9B46B80C24001D364756E2164756E21
8469
+ //# debugId=B3B56B145A0DCF8164756E2164756E21