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/cli/bin.d.ts 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>
package/cli/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
  /**
4
- * reroute-js v0.40.1
4
+ * reroute-js v0.41.0
5
5
  *
6
6
  * @license MIT
7
7
  * @copyright 2026 stewones <hi@stewan.io>
@@ -48,7 +48,7 @@ async function getVersionString() {
48
48
  }
49
49
  async function getVersion() {
50
50
  if (true) {
51
- return "0.40.1";
51
+ return "0.41.0";
52
52
  }
53
53
  const possiblePaths = [
54
54
  path.join(import.meta.dir, "../../../../package.json"),
@@ -66,7 +66,7 @@ async function getVersion() {
66
66
  }
67
67
  async function getCommit() {
68
68
  if (true) {
69
- return "3de1ba2";
69
+ return "fdadb6d";
70
70
  }
71
71
  return "dev";
72
72
  }
@@ -475,7 +475,7 @@ async function getContentMeta(absPath, isWatchMode) {
475
475
  }
476
476
  }
477
477
  }
478
- function buildHeadFromMeta(meta) {
478
+ function buildHeadFromMeta(meta, ogConfig) {
479
479
  if (!meta || typeof meta !== "object")
480
480
  return "";
481
481
  const parts = [];
@@ -485,6 +485,23 @@ function buildHeadFromMeta(meta) {
485
485
  parts.push(`<title>${escapeHtml(title)}</title>`);
486
486
  if (description)
487
487
  parts.push(`<meta name="description" content="${escapeHtml(description)}" />`);
488
+ const ogType = typeof meta.ogType === "string" ? meta.ogType : ogConfig?.defaultType || "website";
489
+ parts.push(`<meta property="og:type" content="${escapeHtml(ogType)}" />`);
490
+ if (title) {
491
+ parts.push(`<meta property="og:title" content="${escapeHtml(title)}" />`);
492
+ }
493
+ const finalDescription = description || ogConfig?.siteDescription;
494
+ if (finalDescription) {
495
+ parts.push(`<meta property="og:description" content="${escapeHtml(finalDescription)}" />`);
496
+ }
497
+ const twitterCard = ogConfig?.twitterCard || "summary_large_image";
498
+ parts.push(`<meta name="twitter:card" content="${twitterCard}" />`);
499
+ if (title) {
500
+ parts.push(`<meta name="twitter:title" content="${escapeHtml(title)}" />`);
501
+ }
502
+ if (finalDescription) {
503
+ parts.push(`<meta name="twitter:description" content="${escapeHtml(finalDescription)}" />`);
504
+ }
488
505
  return parts.length ? `
489
506
  ${parts.join(`
490
507
  `)}` : "";
@@ -1947,6 +1964,28 @@ function removeDefaultMetaTags(templateHtml) {
1947
1964
  } catch {}
1948
1965
  return result;
1949
1966
  }
1967
+ function removeOverriddenMetaTags(templateHtml, injectedHead) {
1968
+ let result = templateHtml;
1969
+ try {
1970
+ const injectedOgProps = [
1971
+ ...injectedHead.matchAll(/<meta\s+property\s*=\s*['"]([^'"]+)['"][^>]*>/gi)
1972
+ ].map((m) => m[1].toLowerCase());
1973
+ const injectedNameMetas = [
1974
+ ...injectedHead.matchAll(/<meta\s+name\s*=\s*['"]([^'"]+)['"][^>]*>/gi)
1975
+ ].map((m) => m[1].toLowerCase());
1976
+ for (const prop of injectedOgProps) {
1977
+ const escapedProp = prop.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1978
+ const regex = new RegExp(`<meta\\s+property\\s*=\\s*['"]${escapedProp}['"][^>]*>`, "gi");
1979
+ result = result.replace(regex, "");
1980
+ }
1981
+ for (const name of injectedNameMetas) {
1982
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1983
+ const regex = new RegExp(`<meta\\s+name\\s*=\\s*['"]${escapedName}['"][^>]*>`, "gi");
1984
+ result = result.replace(regex, "");
1985
+ }
1986
+ } catch {}
1987
+ return result;
1988
+ }
1950
1989
  function deduplicateHeadContent(templateHtml, headToInject) {
1951
1990
  let cleanedTemplate = templateHtml;
1952
1991
  let cleanedHead = headToInject;
@@ -1957,6 +1996,7 @@ function deduplicateHeadContent(templateHtml, headToInject) {
1957
1996
  } else if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(cleanedHead)) {
1958
1997
  cleanedTemplate = cleanedTemplate.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
1959
1998
  }
1999
+ cleanedTemplate = removeOverriddenMetaTags(cleanedTemplate, cleanedHead);
1960
2000
  } catch {}
1961
2001
  return { cleanedTemplate, cleanedHead };
1962
2002
  }
@@ -2075,7 +2115,6 @@ async function generateOGImageMetaTags(pathname, clientDir, ogConfig) {
2075
2115
  return `<meta property="og:image" content="${ogImagePath}" />
2076
2116
  <meta property="og:image:width" content="${width}" />
2077
2117
  <meta property="og:image:height" content="${height}" />
2078
- <meta name="twitter:card" content="summary_large_image" />
2079
2118
  <meta name="twitter:image" content="${ogImagePath}" />`;
2080
2119
  }
2081
2120
  var init_meta = __esm(() => {
@@ -2083,6 +2122,22 @@ var init_meta = __esm(() => {
2083
2122
  });
2084
2123
 
2085
2124
  // packages/core/src/ssr/lib/metadata.ts
2125
+ async function loadModuleMetaAndSSR(moduleObj, absolutePath, isWatchMode) {
2126
+ const bundledMeta = moduleObj?.meta;
2127
+ const bundledSSR = moduleObj?.ssr;
2128
+ if (bundledMeta !== undefined || bundledSSR !== undefined) {
2129
+ return { meta: bundledMeta, ssr: bundledSSR };
2130
+ }
2131
+ try {
2132
+ const mod = await dynamicImport(absolutePath, isWatchMode);
2133
+ return {
2134
+ meta: mod?.meta,
2135
+ ssr: mod?.ssr
2136
+ };
2137
+ } catch {
2138
+ return {};
2139
+ }
2140
+ }
2086
2141
  function generateCanonicalUrl(baseUrl, pathname) {
2087
2142
  const cleanBaseUrl = baseUrl.replace(/\/$/, "");
2088
2143
  const cleanPathname = pathname.split("?")[0];
@@ -2097,7 +2152,25 @@ function generateOgUrl(baseUrl, pathname) {
2097
2152
  const ogUrl = `${cleanBaseUrl}${normalizedPath}`;
2098
2153
  return `<meta property="og:url" content="${ogUrl}" />`;
2099
2154
  }
2100
- async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ogConfig, baseUrl, autoCanonical, ssrData) {
2155
+ function generateGlobalOGTags(ogConfig) {
2156
+ const tags = [];
2157
+ if (ogConfig.siteName) {
2158
+ tags.push(`<meta property="og:site_name" content="${escapeHtml2(ogConfig.siteName)}" />`);
2159
+ }
2160
+ if (ogConfig.locale) {
2161
+ tags.push(`<meta property="og:locale" content="${escapeHtml2(ogConfig.locale)}" />`);
2162
+ }
2163
+ if (ogConfig.twitterSite) {
2164
+ const handle = ogConfig.twitterSite.startsWith("@") ? ogConfig.twitterSite : `@${ogConfig.twitterSite}`;
2165
+ tags.push(`<meta name="twitter:site" content="${escapeHtml2(handle)}" />`);
2166
+ }
2167
+ return tags.length ? tags.join(`
2168
+ `) : "";
2169
+ }
2170
+ function escapeHtml2(input) {
2171
+ return input.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
2172
+ }
2173
+ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ogImageConfig, ogConfig, baseUrl, autoCanonical, ssrData) {
2101
2174
  let perPageHead = "";
2102
2175
  let pageLang;
2103
2176
  let statusOverride = currentStatusOverride;
@@ -2106,7 +2179,7 @@ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, curren
2106
2179
  }, (lang) => {
2107
2180
  if (!pageLang)
2108
2181
  pageLang = lang;
2109
- });
2182
+ }, ogConfig);
2110
2183
  const shouldGenerateCanonical = autoCanonical !== false && baseUrl !== undefined;
2111
2184
  if (shouldGenerateCanonical) {
2112
2185
  const canonicalTag = generateCanonicalUrl(baseUrl, pathname);
@@ -2116,8 +2189,15 @@ ${canonicalTag}`;
2116
2189
  perPageHead += `
2117
2190
  ${ogUrlTag}`;
2118
2191
  }
2192
+ if (ogConfig) {
2193
+ const ogGlobalTags = generateGlobalOGTags(ogConfig);
2194
+ if (ogGlobalTags) {
2195
+ perPageHead += `
2196
+ ${ogGlobalTags}`;
2197
+ }
2198
+ }
2119
2199
  try {
2120
- const ogMetaTags = await generateOGImageMetaTags(pathname, clientDir, ogConfig);
2200
+ const ogMetaTags = await generateOGImageMetaTags(pathname, clientDir, ogImageConfig);
2121
2201
  if (ogMetaTags) {
2122
2202
  perPageHead += `
2123
2203
  ${ogMetaTags}`;
@@ -2129,24 +2209,22 @@ ${ogMetaTags}`;
2129
2209
  perPageHead += head;
2130
2210
  }, (lang) => {
2131
2211
  pageLang = lang;
2132
- });
2133
- const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData);
2212
+ }, ogConfig);
2213
+ const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig);
2134
2214
  perPageHead += routeResult.head;
2135
2215
  if (routeResult.lang)
2136
2216
  pageLang = routeResult.lang;
2137
2217
  statusOverride = routeResult.statusOverride;
2138
2218
  return { perPageHead, pageLang, statusOverride };
2139
2219
  }
2140
- async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang) {
2220
+ async function processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig) {
2141
2221
  if (typeof layout?.path !== "string")
2142
2222
  return;
2143
2223
  try {
2144
2224
  const abs = join2(clientDir, "routes", String(layout.path));
2145
- const mod = await dynamicImport(abs, isWatchMode);
2146
- const meta = mod?.meta;
2147
- const ssr = mod?.ssr;
2225
+ const { meta, ssr } = await loadModuleMetaAndSSR(layout, abs, isWatchMode);
2148
2226
  if (meta)
2149
- addHead(buildHeadFromMeta(meta));
2227
+ addHead(buildHeadFromMeta(meta, ogConfig));
2150
2228
  if (ssr) {
2151
2229
  const ssrHead = extractSSRHead(ssr);
2152
2230
  if (ssrHead)
@@ -2158,17 +2236,16 @@ ${ssrHead}`);
2158
2236
  }
2159
2237
  } catch {}
2160
2238
  }
2161
- async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang) {
2239
+ async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addHead, setLang, ogConfig) {
2162
2240
  try {
2163
- const routesPath = join2(cwd, ".reroute", "routes.ts");
2164
- const m = await dynamicImport(routesPath, isWatchMode);
2241
+ const m = await loadRoutesModule(cwd, isWatchMode);
2165
2242
  const matchingLayouts = getMatchingLayouts(pathname, m?.layouts);
2166
2243
  for (const layout of matchingLayouts) {
2167
- await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang);
2244
+ await processLayoutForMetadata(layout, clientDir, isWatchMode, addHead, setLang, ogConfig);
2168
2245
  }
2169
2246
  } catch {}
2170
2247
  }
2171
- function extractContentMetadata(pathname, addHead, setLang) {
2248
+ function extractContentMetadata(pathname, addHead, setLang, ogConfig) {
2172
2249
  try {
2173
2250
  const parts = pathname.split("/").filter(Boolean);
2174
2251
  if (parts.length < 2)
@@ -2178,7 +2255,7 @@ function extractContentMetadata(pathname, addHead, setLang) {
2178
2255
  const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
2179
2256
  const meta = exp?.meta;
2180
2257
  const ssr = exp?.ssr;
2181
- addHead(buildHeadFromMeta(meta));
2258
+ addHead(buildHeadFromMeta(meta, ogConfig));
2182
2259
  const ssrHead = extractSSRHead(ssr);
2183
2260
  if (ssrHead)
2184
2261
  addHead(`
@@ -2188,7 +2265,7 @@ ${ssrHead}`);
2188
2265
  setLang(lang);
2189
2266
  } catch {}
2190
2267
  }
2191
- async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData) {
2268
+ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig) {
2192
2269
  const pathnameOnly = pathname.split("?")[0];
2193
2270
  const match = typeof m.matchRoute === "function" ? m.matchRoute(pathnameOnly) : null;
2194
2271
  const r = match?.route;
@@ -2198,12 +2275,10 @@ async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode,
2198
2275
  if (r && typeof r.path === "string") {
2199
2276
  try {
2200
2277
  const abs = join2(clientDir, "routes", String(r.path));
2201
- const mod = await dynamicImport(abs, isWatchMode);
2202
- const meta = mod?.meta;
2203
- const ssr = mod?.ssr;
2278
+ const { meta, ssr } = await loadModuleMetaAndSSR(r, abs, isWatchMode);
2204
2279
  let head = "";
2205
2280
  if (meta)
2206
- head += buildHeadFromMeta(meta);
2281
+ head += buildHeadFromMeta(meta, ogConfig);
2207
2282
  if (ssr) {
2208
2283
  const routeData = ssrData && typeof ssrData === "object" ? ssrData[pathname] : undefined;
2209
2284
  const ssrHead = extractSSRHead(ssr, routeData);
@@ -2217,7 +2292,7 @@ ${ssrHead}`;
2217
2292
  }
2218
2293
  return { head: "", statusOverride };
2219
2294
  }
2220
- async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData) {
2295
+ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig) {
2221
2296
  let head = "";
2222
2297
  let lang;
2223
2298
  let statusOverride = currentStatusOverride;
@@ -2233,14 +2308,14 @@ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, curre
2233
2308
  statusOverride = statusOverride || 404;
2234
2309
  }
2235
2310
  if (r && typeof r.path === "string") {
2236
- const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData);
2311
+ const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig);
2237
2312
  head = result.head;
2238
2313
  lang = result.lang;
2239
2314
  statusOverride = result.statusOverride;
2240
2315
  } else {
2241
2316
  head += await extractNotFoundMetadata(pathname, clientDir, m, isWatchMode, (l) => {
2242
2317
  lang = l;
2243
- });
2318
+ }, ogConfig);
2244
2319
  }
2245
2320
  } catch {}
2246
2321
  return { head, lang, statusOverride };
@@ -2260,7 +2335,7 @@ function findBestNotFoundRoute(list, pathname) {
2260
2335
  }
2261
2336
  return chosen;
2262
2337
  }
2263
- async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatchMode, setLang) {
2338
+ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatchMode, setLang, ogConfig) {
2264
2339
  let head = "";
2265
2340
  try {
2266
2341
  const list = routesModule?.notFoundRoutes;
@@ -2269,11 +2344,9 @@ async function extractNotFoundMetadata(pathname, clientDir, routesModule, isWatc
2269
2344
  const chosen = findBestNotFoundRoute(list, pathname);
2270
2345
  if (chosen && typeof chosen.path === "string") {
2271
2346
  const abs = join2(clientDir, "routes", String(chosen.path));
2272
- const mod = await dynamicImport(abs, isWatchMode);
2273
- const meta = mod?.meta;
2274
- const ssr = mod?.ssr;
2347
+ const { meta, ssr } = await loadModuleMetaAndSSR(chosen, abs, isWatchMode);
2275
2348
  if (meta)
2276
- head += buildHeadFromMeta(meta);
2349
+ head += buildHeadFromMeta(meta, ogConfig);
2277
2350
  const ssrHead = extractSSRHead(ssr);
2278
2351
  if (ssrHead)
2279
2352
  head += `
@@ -2860,7 +2933,7 @@ async function performSSRSetupInternal(options, streaming) {
2860
2933
  statusOverride = computeResult.statusContainer.value;
2861
2934
  }
2862
2935
  const metadataResult = await withSpan("ssr.extract.metadata", async (span) => {
2863
- const result = await extractPageMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ogConfig, options.baseUrl, options.autoCanonical, computeResult.data);
2936
+ const result = await extractPageMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ogConfig, options.ogMetaConfig, options.baseUrl, options.autoCanonical, computeResult.data);
2864
2937
  span.setAttributes({
2865
2938
  "reroute.pathname": pathname,
2866
2939
  "reroute.metadata.exists": !!result.perPageHead
@@ -3030,6 +3103,7 @@ async function renderSSRDocument(options) {
3030
3103
  maxAge,
3031
3104
  searchParams,
3032
3105
  ogConfig,
3106
+ ogMetaConfig: options.ogMetaConfig,
3033
3107
  baseUrl: options.baseUrl,
3034
3108
  autoCanonical: options.autoCanonical,
3035
3109
  cachedCollections: options.cachedCollections,
@@ -5140,6 +5214,7 @@ async function renderSSRDocumentStream(options) {
5140
5214
  maxAge,
5141
5215
  searchParams,
5142
5216
  ogConfig,
5217
+ ogMetaConfig: options.ogMetaConfig,
5143
5218
  baseUrl: options.baseUrl,
5144
5219
  autoCanonical: options.autoCanonical,
5145
5220
  cachedCollections: options.cachedCollections,
@@ -5174,7 +5249,11 @@ async function renderSSRDocumentStream(options) {
5174
5249
  };
5175
5250
  });
5176
5251
  const pageLang = setup2.metadataResult.pageLang || lang;
5177
- let headWithLang = htmlHead.replace(/<html([^>]*)>/i, `<html$1 lang="${pageLang}">`);
5252
+ let headWithLang = htmlHead.replace(/<html([^>]*)>/i, (_m, attrs) => {
5253
+ const hasLang = /(^|\s)lang\s*=/.test(attrs);
5254
+ const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${pageLang}"`) : `${attrs} lang="${pageLang}"`;
5255
+ return `<html${newAttrs}>`;
5256
+ });
5178
5257
  const extraHead = setup2.bundlePreload + setup2.preloadExtraHead + setup2.metadataResult.perPageHead;
5179
5258
  if (/<title[\s\S]*?<\/title>/i.test(extraHead)) {
5180
5259
  headWithLang = headWithLang.replace(/<title[\s\S]*?<\/title>/i, "");
@@ -5182,6 +5261,7 @@ async function renderSSRDocumentStream(options) {
5182
5261
  if (/<meta\s+name\s*=\s*['"]description['"][^>]*>/i.test(extraHead)) {
5183
5262
  headWithLang = headWithLang.replace(/<meta\s+name\s*=\s*['"]description['"][^>]*>/i, "");
5184
5263
  }
5264
+ headWithLang = removeOverriddenMetaTags(headWithLang, extraHead);
5185
5265
  const config = await loadConfig(cwd);
5186
5266
  const browserTelemetryConfigRaw = config.telemetry?.browser;
5187
5267
  const { serializeBrowserTelemetryConfig: serializeBrowserTelemetryConfig2 } = await Promise.resolve().then(() => exports_serialize);
@@ -5230,7 +5310,7 @@ async function streamSSRContent(writer, encoder, ctx) {
5230
5310
  try {
5231
5311
  const combinedHead = deduplicateMetaTags([ctx.inlineStyleTag, ctx.head, ctx.extraHead].filter(Boolean).join(`
5232
5312
  `));
5233
- const headWithLangAndContent = ctx.headWithLang.replace(/<html([^>]*)>/i, `<html$1 lang="${ctx.pageLang}">`).replace(/<\/head>/i, `${combinedHead ? `${combinedHead}
5313
+ const headWithLangAndContent = ctx.headWithLang.replace(/<\/head>/i, `${combinedHead ? `${combinedHead}
5234
5314
  ` : ""}</head>`);
5235
5315
  const headContent = `${headWithLangAndContent}`;
5236
5316
  await writer.write(encoder.encode(headContent));
@@ -5370,6 +5450,7 @@ __export(exports_core, {
5370
5450
  renderSSRDocumentStream: () => renderSSRDocumentStream,
5371
5451
  renderSSRDocument: () => renderSSRDocument,
5372
5452
  renderOGImageToPNG: () => renderOGImageToPNG,
5453
+ removeOverriddenMetaTags: () => removeOverriddenMetaTags,
5373
5454
  processCollections: () => processCollections,
5374
5455
  preloadContentModule: () => preloadContentModule,
5375
5456
  performSSRSetup: () => performSSRSetup,
@@ -105691,7 +105772,7 @@ async function getVersionString2() {
105691
105772
  }
105692
105773
  async function getVersion2() {
105693
105774
  if (true) {
105694
- return "0.40.1";
105775
+ return "0.41.0";
105695
105776
  }
105696
105777
  const possiblePaths = [
105697
105778
  path3.join(import.meta.dir, "../../../package.json"),
@@ -105708,10 +105789,10 @@ async function getVersion2() {
105708
105789
  }
105709
105790
  async function getCommit2() {
105710
105791
  if (true) {
105711
- return "3de1ba2";
105792
+ return "fdadb6d";
105712
105793
  }
105713
105794
  return "dev";
105714
105795
  }
105715
105796
  main();
105716
105797
 
105717
- //# debugId=B438EB8A747E943564756E2164756E21
105798
+ //# debugId=E4248FFA7E75804564756E2164756E21