@ox-content/vite-plugin 2.6.0 → 2.8.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.
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { n as transformMermaidStatic, r as importNapiModule, t as mermaidClientScript } from "./mermaid.mjs";
2
2
  import { n as resetTabGroupCounter, r as transformTabs, t as generateTabsCSS } from "./tabs2.mjs";
3
3
  import { n as transformYouTube, t as extractVideoId } from "./youtube2.mjs";
4
- import { i as transformGitHub, n as fetchRepoData, r as prefetchGitHubRepos, t as collectGitHubRepos } from "./github2.mjs";
5
- import { i as transformOgp, n as fetchOgpData, r as prefetchOgpData, t as collectOgpUrls } from "./ogp2.mjs";
4
+ import { a as transformGitHub, i as prefetchGitHubRepos, n as fetchRepoData, t as collectGitHubRepos } from "./github2.mjs";
5
+ import { a as transformOgp, i as prefetchOgpData, n as fetchOgpData, t as collectOgpUrls } from "./ogp2.mjs";
6
6
  import { createRequire } from "node:module";
7
7
  import * as path$2 from "path";
8
8
  import path from "path";
@@ -9397,6 +9397,7 @@ function resolveTheme(config) {
9397
9397
  header: merged.header ?? defaultTheme.header,
9398
9398
  footer: merged.footer ?? defaultTheme.footer,
9399
9399
  socialLinks: merged.socialLinks ?? defaultTheme.socialLinks,
9400
+ sidebar: merged.sidebar ?? [],
9400
9401
  embed: merged.embed ?? {},
9401
9402
  css: merged.css ?? "",
9402
9403
  js: merged.js ?? ""
@@ -9406,6 +9407,7 @@ function resolveTheme(config) {
9406
9407
  * Converts resolved theme to the format expected by Rust NAPI.
9407
9408
  */
9408
9409
  function themeToNapi(theme) {
9410
+ const socialLinks = socialLinksToNapi(theme.socialLinks);
9409
9411
  return {
9410
9412
  colors: theme.colors.primary ? {
9411
9413
  primary: theme.colors.primary,
@@ -9451,16 +9453,30 @@ function themeToNapi(theme) {
9451
9453
  message: theme.footer.message,
9452
9454
  copyright: theme.footer.copyright
9453
9455
  } : void 0,
9454
- socialLinks: theme.socialLinks.github || theme.socialLinks.twitter || theme.socialLinks.discord ? {
9455
- github: theme.socialLinks.github,
9456
- twitter: theme.socialLinks.twitter,
9457
- discord: theme.socialLinks.discord
9458
- } : void 0,
9456
+ socialLinks,
9459
9457
  embed: Object.keys(theme.embed).length > 0 ? theme.embed : void 0,
9460
9458
  css: theme.css || void 0,
9461
9459
  js: theme.js || void 0
9462
9460
  };
9463
9461
  }
9462
+ function socialLinksToNapi(links) {
9463
+ if (Array.isArray(links)) {
9464
+ const items = links.map((item) => {
9465
+ return {
9466
+ icon: typeof item.icon === "string" ? item.icon : void 0,
9467
+ iconSvg: typeof item.icon === "object" ? item.icon.svg : void 0,
9468
+ link: item.link,
9469
+ ariaLabel: item.ariaLabel
9470
+ };
9471
+ });
9472
+ return items.length > 0 ? { links: items } : void 0;
9473
+ }
9474
+ return links.github || links.twitter || links.discord ? {
9475
+ github: links.github,
9476
+ twitter: links.twitter,
9477
+ discord: links.discord
9478
+ } : void 0;
9479
+ }
9464
9480
  //#endregion
9465
9481
  //#region src/ssg.ts
9466
9482
  /**
@@ -10816,7 +10832,8 @@ function resolveSsgOptions(ssg) {
10816
10832
  extension: ".html",
10817
10833
  clean: false,
10818
10834
  bare: false,
10819
- generateOgImage: false
10835
+ generateOgImage: false,
10836
+ lastUpdated: false
10820
10837
  };
10821
10838
  if (ssg === true || ssg === void 0) return {
10822
10839
  enabled: true,
@@ -10824,6 +10841,7 @@ function resolveSsgOptions(ssg) {
10824
10841
  clean: false,
10825
10842
  bare: false,
10826
10843
  generateOgImage: false,
10844
+ lastUpdated: false,
10827
10845
  theme: resolveTheme(void 0)
10828
10846
  };
10829
10847
  return {
@@ -10834,6 +10852,7 @@ function resolveSsgOptions(ssg) {
10834
10852
  siteName: ssg.siteName,
10835
10853
  ogImage: ssg.ogImage,
10836
10854
  generateOgImage: ssg.generateOgImage ?? false,
10855
+ lastUpdated: ssg.lastUpdated ?? false,
10837
10856
  siteUrl: ssg.siteUrl,
10838
10857
  theme: resolveTheme(ssg.theme)
10839
10858
  };
@@ -10880,20 +10899,24 @@ function generateBareHtmlPage(content, title) {
10880
10899
  /**
10881
10900
  * Generates HTML page with navigation using Rust NAPI bindings.
10882
10901
  */
10883
- async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, theme) {
10902
+ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, theme, locale, availableLocales) {
10884
10903
  const mod = await importNapiModule();
10885
10904
  const tocForRust = pageData.toc.map((entry) => ({
10886
10905
  depth: entry.depth,
10887
10906
  text: entry.text,
10888
10907
  slug: entry.slug
10889
10908
  }));
10909
+ const toRustNavItem = (item) => ({
10910
+ title: item.title,
10911
+ path: item.path,
10912
+ href: item.href,
10913
+ children: item.children?.map(toRustNavItem),
10914
+ collapsed: item.collapsed
10915
+ });
10890
10916
  const navGroupsForRust = navGroups.map((group) => ({
10891
10917
  title: group.title,
10892
- items: group.items.map((item) => ({
10893
- title: item.title,
10894
- path: item.path,
10895
- href: item.href
10896
- }))
10918
+ collapsed: group.collapsed,
10919
+ items: group.items.map(toRustNavItem)
10897
10920
  }));
10898
10921
  const themeForRust = theme ? themeToNapi(theme) : void 0;
10899
10922
  const entryPageForRust = pageData.entryPage ? {
@@ -10932,13 +10955,20 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
10932
10955
  description: pageData.description,
10933
10956
  content: pageData.content,
10934
10957
  toc: tocForRust,
10958
+ lastUpdated: pageData.lastUpdated,
10935
10959
  path: pageData.path,
10936
10960
  entryPage: entryPageForRust
10937
10961
  }, navGroupsForRust, {
10938
10962
  siteName,
10939
10963
  base,
10940
10964
  ogImage,
10941
- theme: themeForRust
10965
+ theme: themeForRust,
10966
+ locale,
10967
+ availableLocales: availableLocales?.map((l) => ({
10968
+ code: l.code,
10969
+ name: l.name,
10970
+ dir: l.dir ?? "ltr"
10971
+ }))
10942
10972
  });
10943
10973
  }
10944
10974
  const SSG_STYLE_BLOCK_RE = /[ \t]*<!-- ox-content:styles:start -->\s*<style>([\s\S]*?)<\/style>\s*<!-- ox-content:styles:end -->/;
@@ -11113,6 +11143,11 @@ function getHref(inputPath, srcDir, base, extension) {
11113
11143
  if (urlPath === "/" || urlPath === "") return `${base}index${extension}`;
11114
11144
  return `${base}${urlPath}/index${extension}`;
11115
11145
  }
11146
+ function getPageLocale(urlPath, i18n) {
11147
+ if (!i18n) return void 0;
11148
+ const firstSegment = urlPath.split("/").filter(Boolean)[0];
11149
+ return i18n.locales.some((l) => l.code === firstSegment) ? firstSegment : i18n.defaultLocale;
11150
+ }
11116
11151
  /**
11117
11152
  * Gets the OG image output path for a given markdown file.
11118
11153
  */
@@ -11219,6 +11254,63 @@ function buildNavItems(markdownFiles, srcDir, base, extension) {
11219
11254
  });
11220
11255
  return result;
11221
11256
  }
11257
+ function isSafeSidebarLink(link) {
11258
+ const trimmed = link.trim();
11259
+ if (trimmed.startsWith("//")) return false;
11260
+ return !/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || /^(https?:|mailto:)/i.test(trimmed);
11261
+ }
11262
+ function sidebarPath(link) {
11263
+ if (!link || !isSafeSidebarLink(link)) return "";
11264
+ if (/^(https?:|mailto:|#)/i.test(link.trim())) return "";
11265
+ const bare = link.trim().split("#", 1)[0].split("?", 1)[0].replace(/^\/+/, "").replace(/\/$/, "").replace(/\.(md|markdown)$/i, "");
11266
+ if (!bare || bare === "index") return "/";
11267
+ return bare.replace(/\/index$/, "");
11268
+ }
11269
+ function sidebarHref(link, base, extension) {
11270
+ if (!link) return "#";
11271
+ const trimmed = link.trim();
11272
+ if (!isSafeSidebarLink(trimmed)) return "#";
11273
+ if (/^(https?:|mailto:|#)/i.test(trimmed)) return trimmed;
11274
+ const hash = trimmed.includes("#") ? `#${trimmed.split("#").slice(1).join("#")}` : "";
11275
+ const withoutExt = trimmed.split("#", 1)[0].replace(/^\/+/, "").replace(/\/$/, "").replace(/\.(md|markdown)$/i, "");
11276
+ return `${base}${!withoutExt || withoutExt === "index" ? "index" : `${withoutExt.replace(/\/index$/, "")}/index`}${extension}${hash}`;
11277
+ }
11278
+ /**
11279
+ * Builds navigation items from an explicit theme sidebar tree.
11280
+ */
11281
+ function buildThemeNavItems(sidebar, base, extension) {
11282
+ const toNavItem = (item) => {
11283
+ const navItem = {
11284
+ title: item.text ?? item.link ?? "Untitled",
11285
+ path: sidebarPath(item.link),
11286
+ href: sidebarHref(item.link, base, extension)
11287
+ };
11288
+ if (item.items?.length) navItem.children = item.items.map(toNavItem);
11289
+ if (item.collapsed !== void 0) navItem.collapsed = item.collapsed;
11290
+ return navItem;
11291
+ };
11292
+ const groups = [];
11293
+ let looseItems = [];
11294
+ const flushLooseItems = () => {
11295
+ if (looseItems.length > 0) {
11296
+ groups.push({
11297
+ title: "Guide",
11298
+ items: looseItems
11299
+ });
11300
+ looseItems = [];
11301
+ }
11302
+ };
11303
+ for (const item of sidebar) if (item.items?.length && !item.link) {
11304
+ flushLooseItems();
11305
+ groups.push({
11306
+ title: item.text ?? "Guide",
11307
+ items: item.items.map(toNavItem),
11308
+ collapsed: item.collapsed
11309
+ });
11310
+ } else looseItems.push(toNavItem(item));
11311
+ flushLooseItems();
11312
+ return groups;
11313
+ }
11222
11314
  /**
11223
11315
  * Builds all markdown files to static HTML.
11224
11316
  */
@@ -11241,7 +11333,7 @@ async function buildSsg(options, root) {
11241
11333
  });
11242
11334
  } catch {}
11243
11335
  const markdownFiles = await collectMarkdownFiles$1(srcDir);
11244
- const navItems = buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension);
11336
+ const navItems = ssgOptions.theme?.sidebar.length ? buildThemeNavItems(ssgOptions.theme.sidebar, base, ssgOptions.extension) : buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension);
11245
11337
  let siteName = ssgOptions.siteName ?? "Documentation";
11246
11338
  if (!ssgOptions.siteName) try {
11247
11339
  const pkgPath = path$2.join(root, "package.json");
@@ -11253,6 +11345,7 @@ async function buildSsg(options, root) {
11253
11345
  const ogImageUrlMap = /* @__PURE__ */ new Map();
11254
11346
  const shouldGenerateOgImages = (options.ogImage || ssgOptions.generateOgImage) && !ssgOptions.bare;
11255
11347
  const pageResults = [];
11348
+ const napi = ssgOptions.lastUpdated ? await importNapiModule() : void 0;
11256
11349
  for (const inputPath of markdownFiles) try {
11257
11350
  const result = await transformMarkdown(await fs$1.readFile(inputPath, "utf-8"), inputPath, options, {
11258
11351
  convertMdLinks: true,
@@ -11280,6 +11373,7 @@ async function buildSsg(options, root) {
11280
11373
  transformedHtml,
11281
11374
  title,
11282
11375
  description,
11376
+ lastUpdated: napi?.getGitLastUpdated(inputPath, root) ?? void 0,
11283
11377
  frontmatter: result.frontmatter,
11284
11378
  toc: result.toc
11285
11379
  });
@@ -11325,7 +11419,7 @@ async function buildSsg(options, root) {
11325
11419
  ogImageUrlMap.clear();
11326
11420
  }
11327
11421
  for (const pageResult of pageResults) try {
11328
- const { inputPath, transformedHtml, title, description, frontmatter, toc } = pageResult;
11422
+ const { inputPath, transformedHtml, title, description, lastUpdated, frontmatter, toc } = pageResult;
11329
11423
  let pageOgImage = ssgOptions.ogImage;
11330
11424
  if (shouldGenerateOgImages && ogImageUrlMap.has(inputPath)) pageOgImage = ogImageUrlMap.get(inputPath);
11331
11425
  let entryPage;
@@ -11335,16 +11429,20 @@ async function buildSsg(options, root) {
11335
11429
  };
11336
11430
  let html;
11337
11431
  if (ssgOptions.bare) html = generateBareHtmlPage(transformedHtml, title);
11338
- else html = await generateHtmlPage({
11339
- title,
11340
- description,
11341
- content: transformedHtml,
11342
- toc,
11343
- frontmatter,
11344
- path: getUrlPath$1(inputPath, srcDir),
11345
- href: getHref(inputPath, srcDir, base, ssgOptions.extension),
11346
- entryPage
11347
- }, navItems, siteName, base, pageOgImage, ssgOptions.theme);
11432
+ else {
11433
+ const pageData = {
11434
+ title,
11435
+ description,
11436
+ content: transformedHtml,
11437
+ toc,
11438
+ lastUpdated,
11439
+ frontmatter,
11440
+ path: getUrlPath$1(inputPath, srcDir),
11441
+ href: getHref(inputPath, srcDir, base, ssgOptions.extension),
11442
+ entryPage
11443
+ };
11444
+ html = await generateHtmlPage(pageData, navItems, siteName, base, pageOgImage, ssgOptions.theme, getPageLocale(pageData.path, options.i18n), options.i18n ? options.i18n.locales : void 0);
11445
+ }
11348
11446
  const outputPath = getOutputPath(inputPath, srcDir, outDir, ssgOptions.extension);
11349
11447
  generatedPages.push({
11350
11448
  inputPath,
@@ -12344,7 +12442,7 @@ function createI18nPlugin(resolvedOptions) {
12344
12442
  }
12345
12443
  server.middlewares.use((req, _res, next) => {
12346
12444
  if (!req.url) return next();
12347
- const localeMatch = req.url.match(/^\/([a-z]{2}(?:-[a-zA-Z]+)?)(\/|$)/);
12445
+ const localeMatch = req.url.match(/^\/([A-Za-z]{2,3}(?:-[A-Za-z0-9]+)*)(\/|$)/);
12348
12446
  if (localeMatch) {
12349
12447
  const localeCode = localeMatch[1];
12350
12448
  if (i18nOptions.locales.some((l) => l.code === localeCode)) req.__oxLocale = localeCode;
@@ -12392,14 +12490,14 @@ export function t(key, params, locale) {
12392
12490
  }
12393
12491
  if (params) {
12394
12492
  for (const [k, v] of Object.entries(params)) {
12395
- message = message.replace(new RegExp('\\\\{\\\\$' + k + '\\\\}', 'g'), String(v));
12493
+ message = message.split('{$' + k + '}').join(String(v));
12396
12494
  }
12397
12495
  }
12398
12496
  return message;
12399
12497
  }
12400
12498
 
12401
12499
  export function getLocaleFromPath(pathname) {
12402
- const match = pathname.match(/^\\/([a-z]{2}(?:-[a-zA-Z]+)?)(\\//|$)/);
12500
+ const match = pathname.match(new RegExp('^/([A-Za-z]{2,3}(?:-[A-Za-z0-9]+)*)(/|$)'));
12403
12501
  if (match) {
12404
12502
  const code = match[1];
12405
12503
  if (i18nConfig.locales.some(l => l.code === code)) {
@@ -12413,7 +12511,9 @@ export function localePath(pathname, locale) {
12413
12511
  const current = getLocaleFromPath(pathname);
12414
12512
  let clean = pathname;
12415
12513
  if (current !== i18nConfig.defaultLocale || !i18nConfig.hideDefaultLocale) {
12416
- clean = pathname.replace(new RegExp('^/' + current + '(/|$)'), '/');
12514
+ const prefix = '/' + current;
12515
+ if (clean === prefix) clean = '/';
12516
+ else if (clean.startsWith(prefix + '/')) clean = clean.slice(prefix.length);
12417
12517
  }
12418
12518
  if (locale === i18nConfig.defaultLocale && i18nConfig.hideDefaultLocale) {
12419
12519
  return clean || '/';
@@ -12421,8 +12521,95 @@ export function localePath(pathname, locale) {
12421
12521
  return '/' + locale + (clean.startsWith('/') ? clean : '/' + clean);
12422
12522
  }
12423
12523
 
12424
- export default { i18nConfig, dictionaries, t, getLocaleFromPath, localePath };
12425
- `;
12524
+ const formatterCache = new Map();
12525
+
12526
+ function getFormatter(kind, locale, options) {
12527
+ const key = kind + ':' + locale + ':' + JSON.stringify(options || {});
12528
+ if (!formatterCache.has(key)) {
12529
+ formatterCache.set(key, new Intl[kind](locale, options));
12530
+ }
12531
+ return formatterCache.get(key);
12532
+ }
12533
+
12534
+ export function getLocaleMeta(locale) {
12535
+ const code = locale || i18nConfig.defaultLocale;
12536
+ return i18nConfig.locales.find(l => l.code === code) || { code, name: code, dir: 'ltr' };
12537
+ }
12538
+
12539
+ export function formatDate(value, options, locale) {
12540
+ return getFormatter('DateTimeFormat', locale || i18nConfig.defaultLocale, options).format(
12541
+ value instanceof Date ? value : new Date(value),
12542
+ );
12543
+ }
12544
+
12545
+ export function formatDateParts(value, options, locale) {
12546
+ return getFormatter('DateTimeFormat', locale || i18nConfig.defaultLocale, options).formatToParts(
12547
+ value instanceof Date ? value : new Date(value),
12548
+ );
12549
+ }
12550
+
12551
+ export function formatNumber(value, options, locale) {
12552
+ return getFormatter('NumberFormat', locale || i18nConfig.defaultLocale, options).format(value);
12553
+ }
12554
+
12555
+ export function formatNumberParts(value, options, locale) {
12556
+ return getFormatter('NumberFormat', locale || i18nConfig.defaultLocale, options).formatToParts(value);
12557
+ }
12558
+
12559
+ export function formatRelativeTime(value, unit, options, locale) {
12560
+ return getFormatter('RelativeTimeFormat', locale || i18nConfig.defaultLocale, options).format(value, unit);
12561
+ }
12562
+
12563
+ export function formatList(values, options, locale) {
12564
+ return getFormatter('ListFormat', locale || i18nConfig.defaultLocale, options).format(values);
12565
+ }
12566
+
12567
+ export function formatListParts(values, options, locale) {
12568
+ return getFormatter('ListFormat', locale || i18nConfig.defaultLocale, options).formatToParts(values);
12569
+ }
12570
+
12571
+ export function formatDisplayName(value, type, options, locale) {
12572
+ if (!Intl.DisplayNames) return String(value);
12573
+ const displayType = type || 'language';
12574
+ return getFormatter('DisplayNames', locale || i18nConfig.defaultLocale, { type: displayType, ...options }).of(value) || String(value);
12575
+ }
12576
+
12577
+ export function createIntl(locale, defaults = {}) {
12578
+ const meta = getLocaleMeta(locale);
12579
+ const code = meta.code;
12580
+ return {
12581
+ locale: code,
12582
+ meta,
12583
+ dir: meta.dir || 'ltr',
12584
+ date: (value, options) => formatDate(value, { ...defaults.date, ...options }, code),
12585
+ dateParts: (value, options) => formatDateParts(value, { ...defaults.date, ...options }, code),
12586
+ number: (value, options) => formatNumber(value, { ...defaults.number, ...options }, code),
12587
+ numberParts: (value, options) => formatNumberParts(value, { ...defaults.number, ...options }, code),
12588
+ relativeTime: (value, unit, options) => formatRelativeTime(value, unit, { ...defaults.relativeTime, ...options }, code),
12589
+ list: (values, options) => formatList(values, { ...defaults.list, ...options }, code),
12590
+ listParts: (values, options) => formatListParts(values, { ...defaults.list, ...options }, code),
12591
+ displayName: (value, type, options) => formatDisplayName(value, type, { ...defaults.displayName, ...options }, code),
12592
+ };
12593
+ }
12594
+
12595
+ export default {
12596
+ i18nConfig,
12597
+ dictionaries,
12598
+ t,
12599
+ getLocaleFromPath,
12600
+ localePath,
12601
+ getLocaleMeta,
12602
+ createIntl,
12603
+ formatDate,
12604
+ formatDateParts,
12605
+ formatNumber,
12606
+ formatNumberParts,
12607
+ formatRelativeTime,
12608
+ formatList,
12609
+ formatListParts,
12610
+ formatDisplayName,
12611
+ };
12612
+ `;
12426
12613
  }
12427
12614
  /**
12428
12615
  * Flattens a nested object into dot-separated keys.
@@ -13248,6 +13435,7 @@ function renderPage(page, options) {
13248
13435
  description: page.description,
13249
13436
  html: page.html,
13250
13437
  toc: page.toc,
13438
+ lastUpdated: page.lastUpdated,
13251
13439
  path: page.path,
13252
13440
  url: page.url,
13253
13441
  frontmatter: page.frontmatter,
@@ -13262,6 +13450,7 @@ function renderPage(page, options) {
13262
13450
  description: p.description,
13263
13451
  html: p.html,
13264
13452
  toc: p.toc,
13453
+ lastUpdated: p.lastUpdated,
13265
13454
  path: p.path,
13266
13455
  url: p.url,
13267
13456
  frontmatter: p.frontmatter,
@@ -13652,19 +13841,53 @@ function resolveCodeAnnotationsOptions(options) {
13652
13841
  */
13653
13842
  function generateVirtualModule(path, options) {
13654
13843
  if (path === "config") return `export default ${JSON.stringify(options)};`;
13655
- if (path === "runtime") return `
13844
+ if (path === "runtime") {
13845
+ const base = normalizeRuntimeBase(options.base);
13846
+ return `
13847
+ export const base = ${JSON.stringify(base)};
13848
+ export const runtimeConfig = { base };
13849
+
13850
+ export function isExternalUrl(value) {
13851
+ return /^(?:https?:)?\\/\\//i.test(value) || /^(?:mailto|tel):/i.test(value);
13852
+ }
13853
+
13854
+ export function withBase(pathname = "") {
13855
+ const value = String(pathname);
13856
+ if (!value || value === "/") return base;
13857
+ if (value.startsWith("#") || isExternalUrl(value)) return value;
13858
+ return base + (value.startsWith("/") ? value.slice(1) : value);
13859
+ }
13860
+
13861
+ export function withoutBase(pathname = "") {
13862
+ const value = String(pathname);
13863
+ if (base === "/" || value.startsWith("#") || isExternalUrl(value)) return value;
13864
+ const bareBase = base.slice(0, -1);
13865
+ if (value === bareBase) return "/";
13866
+ if (value.startsWith(base)) return "/" + value.slice(base.length);
13867
+ return value;
13868
+ }
13869
+
13656
13870
  export function useMarkdown() {
13657
13871
  return {
13872
+ base,
13873
+ withBase,
13874
+ withoutBase,
13658
13875
  render: (content) => {
13659
- // Client-side rendering if needed
13660
13876
  return content;
13661
13877
  },
13662
13878
  };
13663
13879
  }
13664
13880
  `;
13881
+ }
13665
13882
  return "export default {};";
13666
13883
  }
13884
+ function normalizeRuntimeBase(base) {
13885
+ const trimmed = base.trim();
13886
+ if (!trimmed || trimmed === "/") return "/";
13887
+ const withLeading = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
13888
+ return withLeading.endsWith("/") ? withLeading : `${withLeading}/`;
13889
+ }
13667
13890
  //#endregion
13668
- export { DEFAULT_HTML_TEMPLATE, DefaultTheme, Fragment, buildSearchIndex, buildSsg, clearRenderContext, collectGitHubRepos, collectOgpUrls, createI18nPlugin, createMarkdownEnvironment, createTheme, defaultTheme, defineTheme, each, extractDocs, extractIslandInfo, extractVideoId, fetchOgpData, fetchRepoData, generateFrontmatterTypes, generateHydrationScript, generateMarkdown, generateOgImages, generateTabsCSS, generateTypes, hasIslands, inferType, jsx, jsxs, lintMarkdown, lintMarkdownAsync, lintMarkdownFile, lintMarkdownFiles, mergeThemes, mermaidClientScript, oxContent, prefetchGitHubRepos, prefetchOgpData, raw, renderAllPages, renderPage, renderToString, resolveDocsOptions, resolveI18nOptions, resolveOgImageOptions, resolveSearchOptions, resolveSsgOptions, resolveTheme, setRenderContext, shouldLintMarkdownFile, transformAllPlugins, transformGitHub, transformIslands, transformMarkdown, transformMermaidStatic, transformOgp, transformTabs, transformYouTube, useIsActive, useNav, usePageProps, useRenderContext, useSiteConfig, when, writeDocs, writeSearchIndex };
13891
+ export { DEFAULT_HTML_TEMPLATE, DefaultTheme, Fragment, buildSearchIndex, buildSsg, clearRenderContext, collectGitHubRepos, collectOgpUrls, createI18nPlugin, createMarkdownEnvironment, createTheme, defaultTheme, defineTheme, each, extractDocs, extractIslandInfo, extractVideoId, fetchOgpData, fetchRepoData, generateFrontmatterTypes, generateHydrationScript, generateMarkdown, generateOgImages, generateTabsCSS, generateTypes, generateVirtualModule, hasIslands, inferType, jsx, jsxs, lintMarkdown, lintMarkdownAsync, lintMarkdownFile, lintMarkdownFiles, mergeThemes, mermaidClientScript, oxContent, prefetchGitHubRepos, prefetchOgpData, raw, renderAllPages, renderPage, renderToString, resolveDocsOptions, resolveI18nOptions, resolveOgImageOptions, resolveSearchOptions, resolveSsgOptions, resolveTheme, setRenderContext, shouldLintMarkdownFile, transformAllPlugins, transformGitHub, transformIslands, transformMarkdown, transformMermaidStatic, transformOgp, transformTabs, transformYouTube, useIsActive, useNav, usePageProps, useRenderContext, useSiteConfig, when, writeDocs, writeSearchIndex };
13669
13892
 
13670
13893
  //# sourceMappingURL=index.mjs.map