fumadocs-core 16.14.5 → 16.15.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.
@@ -47,8 +47,10 @@ async function searchAdvanced(db, query, tag = [], { mode = "fulltext", ...overr
47
47
  if (query.length > 0) params.term = query;
48
48
  const highlighter = createContentHighlighter(query);
49
49
  const result = await search(db, params);
50
+ const limit = typeof params.limit === "number" ? params.limit : Infinity;
50
51
  const list = [];
51
52
  for (const item of result.groups ?? []) {
53
+ if (list.length >= limit) break;
52
54
  const pageId = item.values[0];
53
55
  const page = getByID(db, pageId);
54
56
  if (!page) continue;
@@ -60,6 +62,7 @@ async function searchAdvanced(db, query, tag = [], { mode = "fulltext", ...overr
60
62
  url: page.url
61
63
  });
62
64
  for (const hit of item.result) {
65
+ if (list.length >= limit) break;
63
66
  if (hit.document.type === "page") continue;
64
67
  list.push({
65
68
  id: hit.document.id.toString(),
@@ -70,7 +73,6 @@ async function searchAdvanced(db, query, tag = [], { mode = "fulltext", ...overr
70
73
  });
71
74
  }
72
75
  }
73
- if (typeof params.limit === "number" && list.length > params.limit) return list.slice(0, params.limit);
74
76
  return list;
75
77
  }
76
78
  //#endregion
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as applyDefaultThemes } from "../utils-D2T58c9w.js";
2
+ import { t as applyDefaultThemes } from "../utils-Cgs-6U-z.js";
3
3
  import { useShiki as useShiki$1 } from "./shiki/react.js";
4
4
  import { defaultShikiFactory } from "./shiki/full.js";
5
5
  //#region src/highlight/client.ts
@@ -1,4 +1,4 @@
1
- import { a as loadMissingTheme, i as loadMissingLanguage, t as applyDefaultThemes } from "../utils-D2T58c9w.js";
1
+ import { a as loadMissingTheme, i as loadMissingLanguage, t as applyDefaultThemes } from "../utils-Cgs-6U-z.js";
2
2
  import { highlightHast as highlightHast$1 } from "./shiki/index.js";
3
3
  import { defaultShikiFactory, wasmShikiFactory } from "./shiki/full.js";
4
4
  import * as JsxRuntime from "react/jsx-runtime";
@@ -1,10 +1,14 @@
1
- import { a as loadMissingTheme, r as getRequiredThemes } from "../../utils-D2T58c9w.js";
1
+ import { a as loadMissingTheme, r as getRequiredThemes } from "../../utils-Cgs-6U-z.js";
2
2
  //#region src/highlight/shiki/index.ts
3
3
  function createShikiFactory(config) {
4
4
  let instance;
5
5
  return {
6
6
  init(options) {
7
- return instance = config.init(options);
7
+ const created = config.init(options);
8
+ if (created instanceof Promise) created.catch(() => {
9
+ if (instance === created) instance = void 0;
10
+ });
11
+ return instance = created;
8
12
  },
9
13
  getOrInit() {
10
14
  return instance ?? this.init();
@@ -14,8 +18,9 @@ function createShikiFactory(config) {
14
18
  async function highlightHast(highlighter, code, options) {
15
19
  const { fallbackLanguage = "text", ...resolved } = options;
16
20
  const { isSpecialLang } = await import("shiki/core");
17
- if (!isSpecialLang(resolved.lang) && !(resolved.lang in highlighter.getBundledLanguages()) && !highlighter.getLoadedLanguages().includes(resolved.lang)) resolved.lang = fallbackLanguage;
18
- await Promise.all([loadMissingTheme(highlighter, getRequiredThemes(resolved)), highlighter.loadLanguage(resolved.lang)]);
21
+ const loaded = highlighter.getLoadedLanguages();
22
+ if (!isSpecialLang(resolved.lang) && !(resolved.lang in highlighter.getBundledLanguages()) && !loaded.includes(resolved.lang)) resolved.lang = fallbackLanguage;
23
+ await Promise.all([loadMissingTheme(highlighter, getRequiredThemes(resolved)), !isSpecialLang(resolved.lang) && !loaded.includes(resolved.lang) && highlighter.loadLanguage(resolved.lang)]);
19
24
  return highlighter.codeToHast(code, resolved);
20
25
  }
21
26
  //#endregion
@@ -265,11 +265,13 @@ interface LoaderOutput<Config extends LoaderConfig = LoaderConfig> {
265
265
  serializePageTree: (tree: Root) => Promise<SerializedPageTree>;
266
266
  }
267
267
  declare function createGetUrl(baseUrl: string, i18n?: I18nConfig): ResolvedLoaderConfig['url'];
268
+ /** content loader API for static content sources */
268
269
  declare function loader<I extends ResolvedInput, I18n extends I18nConfig | undefined = undefined>(source: I, options: LoaderOptions<NoInfer<GenerateStorage<I>>, I18n>): LoaderOutput<{
269
270
  meta: GenerateMeta<I>;
270
271
  page: GeneratePage<I>;
271
272
  i18n: I18n;
272
273
  }>;
274
+ /** content loader API for static content sources */
273
275
  declare function loader<I extends ResolvedInput, I18n extends I18nConfig | undefined = undefined>(options: LoaderOptions<NoInfer<GenerateStorage<I>>, I18n> & {
274
276
  source: I;
275
277
  }): LoaderOutput<{
@@ -305,20 +307,20 @@ type InferPageType<Utils extends LoaderOutput<any>> = Utils['$inferPage'];
305
307
  type InferMetaType<Utils extends LoaderOutput<any>> = Utils['$inferMeta'];
306
308
  //#endregion
307
309
  //#region src/source/dynamic.d.ts
308
- type Input = SourceUnion | Record<string, SourceUnion>;
309
310
  interface DynamicLoaderConfig extends LoaderConfig {
310
311
  source: string | undefined;
311
312
  }
312
313
  interface DynamicLoader<Config extends DynamicLoaderConfig = DynamicLoaderConfig> {
313
314
  get: () => Promise<LoaderOutput<Config>>;
314
- /** update & re-compute dynamic sources */
315
+ /** invalidate & re-compute dynamic sources immediately */
315
316
  revalidate: (source?: Config['source']) => Promise<void>;
316
317
  /** remove computed cache of dynamic sources */
317
318
  invalidate: (source?: Config['source']) => void;
318
319
  get $inferPage(): Config['page'];
319
320
  get $inferMeta(): Config['meta'];
320
321
  }
321
- declare function dynamicLoader<I extends Input, I18n extends I18nConfig | undefined = undefined>(input: I, options: LoaderOptions<NoInfer<GenerateStorage<I>>, I18n>): DynamicLoader<{
322
+ /** content loader API for static & dynamic content sources, with in-memory cache. */
323
+ declare function dynamicLoader<I extends SourceUnion | Record<string, SourceUnion>, I18n extends I18nConfig | undefined = undefined>(input: I, options: LoaderOptions<NoInfer<GenerateStorage<I>>, I18n>): DynamicLoader<{
322
324
  i18n: I18n;
323
325
  meta: NoInfer<GenerateMeta<I>>;
324
326
  page: NoInfer<GeneratePage<I>>;
@@ -333,10 +335,37 @@ type SourceUnion<Config extends SourceConfig = SourceConfig> = StaticSource<Conf
333
335
  type Source<Config extends SourceConfig = SourceConfig> = StaticSource<Config>;
334
336
  interface StaticSource<Config extends SourceConfig = SourceConfig> {
335
337
  files: VirtualFile<Config>[];
338
+ /**
339
+ * called when the source is attached to a new static loader, before loader output is accessible.
340
+ **/
341
+ configureStatic?: (opts: {
342
+ loader: LoaderOutput;
343
+ source?: string;
344
+ }) => void;
336
345
  }
346
+ /** one dynamic source object can only be used by one dynamic loader */
337
347
  interface DynamicSource<Config extends SourceConfig = SourceConfig> {
348
+ /**
349
+ * - `memory`: the dynamic loader's in-memory cache handles caching.
350
+ * - `custom`: the source handles caching itself. When the newer result of `files()` is (shallowly) different from the previous result, the source is considered revalidated, and all associated properties will be re-computed.
351
+ *
352
+ * @default 'memory'
353
+ **/
354
+ cache?: 'memory' | 'custom';
338
355
  files: () => Awaitable<VirtualFile<Config>[]>;
339
- configure?: (loader: DynamicLoader) => void;
356
+ configure?: (loader: DynamicLoader, opts: {
357
+ source?: string;
358
+ }) => void;
359
+ /**
360
+ * called when the source is attached to a new static loader, before loader output is accessible.
361
+ *
362
+ * it can be called multiple times, when the parent dynamic loader creates a different static loader.
363
+ **/
364
+ configureStatic?: (opts: {
365
+ loader: LoaderOutput;
366
+ source?: string;
367
+ }) => void;
368
+ invalidate?: () => void;
340
369
  }
341
370
  type SourceConfig = {
342
371
  pageData: PageData;
@@ -12,7 +12,7 @@ var FileSystem = class {
12
12
  this.files = /* @__PURE__ */ new Map();
13
13
  this.folders = /* @__PURE__ */ new Map();
14
14
  if (inherit) {
15
- for (const [k, v] of inherit.folders) this.folders.set(k, v);
15
+ for (const [k, v] of inherit.folders) this.folders.set(k, [...v]);
16
16
  for (const [k, v] of inherit.files) this.files.set(k, v);
17
17
  } else this.folders.set("", []);
18
18
  }
@@ -601,6 +601,7 @@ function createPageIndexer({ url }) {
601
601
  const pages = /* @__PURE__ */ new Map();
602
602
  const pathToMeta = /* @__PURE__ */ new Map();
603
603
  const pathToPage = /* @__PURE__ */ new Map();
604
+ const urlToPage = /* @__PURE__ */ new Map();
604
605
  return {
605
606
  scan(storage, lang) {
606
607
  for (const filePath of storage.getFiles()) {
@@ -627,11 +628,15 @@ function createPageIndexer({ url }) {
627
628
  };
628
629
  pathToPage.set(path, page);
629
630
  pages.set(prefix + page.slugs.join("/"), page);
631
+ urlToPage.set(prefix + page.url, page);
630
632
  }
631
633
  },
632
634
  getPage(path, lang = "") {
633
635
  return pathToPage.get(`${lang}.${path}`);
634
636
  },
637
+ getPageByUrl(url, lang = "") {
638
+ return urlToPage.get(`${lang}.${url}`);
639
+ },
635
640
  getMeta(path, lang = "") {
636
641
  return pathToMeta.get(`${lang}.${path}`);
637
642
  },
@@ -687,7 +692,7 @@ function loader(...args) {
687
692
  return pageTrees = out;
688
693
  }
689
694
  }
690
- return {
695
+ const out = {
691
696
  _i18n: i18n,
692
697
  get pageTree() {
693
698
  return getPageTrees();
@@ -705,7 +710,7 @@ function loader(...args) {
705
710
  } catch {}
706
711
  const path = joinPath(dir, decoded);
707
712
  target = indexer.getPage(path, language);
708
- } else target = this.getPages(language).find((item) => item.url === value);
713
+ } else target = indexer.getPageByUrl(value, language);
709
714
  if (target) return {
710
715
  page: target,
711
716
  hash
@@ -775,6 +780,12 @@ function loader(...args) {
775
780
  };
776
781
  }
777
782
  };
783
+ if (isStaticSource(loaderConfig.input)) loaderConfig.input.configureStatic?.({ loader: out });
784
+ else for (const [k, v] of Object.entries(loaderConfig.input)) v.configureStatic?.({
785
+ loader: out,
786
+ source: k
787
+ });
788
+ return out;
778
789
  }
779
790
  function resolveConfig(input, { slugs, baseSlugs, icon, plugins = [], baseUrl, url, ...base }) {
780
791
  let config = {
@@ -1,7 +1,7 @@
1
1
  import { remarkHeading } from "./remark-heading.js";
2
2
  import { generateCodeBlockTabs, parseCodeBlockAttributes } from "./codeblock-utils.js";
3
3
  import { remarkGfm } from "./remark-gfm.js";
4
- import { r as transformerTab } from "../rehype-code.core-CWlREGfK.js";
4
+ import { r as transformerTab } from "../rehype-code.core-BUwNuchP.js";
5
5
  import { transformerIcon } from "./transformer-icon.js";
6
6
  import { rehypeCode, rehypeCodeDefaultOptions } from "./rehype-code.js";
7
7
  import { remarkImage } from "./remark-image.js";
@@ -1,3 +1,3 @@
1
- import { n as rehypeCodeDefaultOptions, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-CWlREGfK.js";
1
+ import { n as rehypeCodeDefaultOptions, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-BUwNuchP.js";
2
2
  import { transformerIcon } from "./transformer-icon.js";
3
3
  export { createRehypeCode, rehypeCodeDefaultOptions, transformerIcon, transformerTab };
@@ -1,5 +1,5 @@
1
1
  import { defaultShikiFactory, wasmShikiFactory } from "../highlight/shiki/full.js";
2
- import { n as rehypeCodeDefaultOptions$1, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-CWlREGfK.js";
2
+ import { n as rehypeCodeDefaultOptions$1, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-BUwNuchP.js";
3
3
  import { transformerIcon } from "./transformer-icon.js";
4
4
  //#region src/mdx-plugins/rehype-code.ts
5
5
  const rehypeCodeDefaultOptions = {
@@ -1,5 +1,5 @@
1
1
  import { n as flattenNodeHast } from "./utils-Yx0IL9eW.js";
2
- import { n as defaultThemes, r as getRequiredThemes } from "./utils-D2T58c9w.js";
2
+ import { n as defaultThemes, r as getRequiredThemes } from "./utils-Cgs-6U-z.js";
3
3
  import { parseCodeBlockAttributes } from "./mdx-plugins/codeblock-utils.js";
4
4
  import { transformerIcon } from "./mdx-plugins/transformer-icon.js";
5
5
  import { visit } from "unist-util-visit";
@@ -43,13 +43,9 @@ function algoliaClient(options) {
43
43
  filters: tag ? `tag:${tag}` : void 0
44
44
  }] });
45
45
  const highlighter = createContentHighlighter(query);
46
- return groupResults(result.results[0].hits).flatMap((hit) => {
47
- if (hit.type === "page") return {
48
- ...hit,
49
- content: highlighter.highlightMarkdown(hit.content)
50
- };
51
- return [];
52
- });
46
+ const results = groupResults(result.results[0].hits);
47
+ for (const item of results) item.content = highlighter.highlightMarkdown(item.content);
48
+ return results;
53
49
  }
54
50
  };
55
51
  }
@@ -1,5 +1,5 @@
1
1
  import { n as join, t as BASE_PATH } from "../../url-BVHvi3_K.js";
2
- import { n as searchSimple, t as searchAdvanced } from "../../advanced-B0__lVW5.js";
2
+ import { n as searchSimple, t as searchAdvanced } from "../../advanced-Ct13khZr.js";
3
3
  import { create, load } from "zbsearch";
4
4
  //#region src/search/client/orama-static.ts
5
5
  const cache = /* @__PURE__ */ new Map();
@@ -1,8 +1,8 @@
1
1
  import { t as Awaitable } from "../types-D89QoQR-.js";
2
2
  import { n as I18nConfig } from "../index-DydiXvgS.js";
3
3
  import "../index-BM36H-xw.js";
4
- import { m as SharedIndex, n as SearchAPI, t as QueryOptions } from "../server-BYa_JUH1.js";
5
- import { x as LoaderOutput, y as LoaderConfig } from "../index-BNgjXvXj2.js";
4
+ import { m as SharedIndex, n as SearchAPI, t as QueryOptions } from "../server-ugF9hnpc.js";
5
+ import { x as LoaderOutput, y as LoaderConfig } from "../index-C8oBtRaX2.js";
6
6
  import { DocumentData, DocumentOptions } from "flexsearch";
7
7
  //#region src/search/server/build-doc.d.ts
8
8
  interface SharedDocument {
@@ -1,5 +1,5 @@
1
1
  import { r as SortedResult } from "../index-BM36H-xw.js";
2
- import { n as SearchAPI } from "../server-BYa_JUH1.js";
2
+ import { n as SearchAPI } from "../server-ugF9hnpc.js";
3
3
  import Mixedbread from "@mixedbread/sdk";
4
4
  import { StoreSearchResponse } from "@mixedbread/sdk/resources/stores";
5
5
  //#region src/search/mixedbread.d.ts
@@ -1,2 +1,2 @@
1
- import { a as AdvancedOptions, c as SimpleOptions, d as createSearchAPI, f as initAdvancedSearch, i as AdvancedIndex, l as createFromSource, n as SearchAPI, o as ExportedData, p as initSimpleSearch, r as SearchServer, s as Index, t as QueryOptions, u as createI18nSearchAPI } from "../server-BYa_JUH1.js";
1
+ import { a as AdvancedOptions, c as SimpleOptions, d as createSearchAPI, f as initAdvancedSearch, i as AdvancedIndex, l as createFromSource, n as SearchAPI, o as ExportedData, p as initSimpleSearch, r as SearchServer, s as Index, t as QueryOptions, u as createI18nSearchAPI } from "../server-ugF9hnpc.js";
2
2
  export { AdvancedIndex, AdvancedOptions, ExportedData, Index, QueryOptions, SearchAPI, SearchServer, SimpleOptions, createFromSource, createI18nSearchAPI, createSearchAPI, initAdvancedSearch, initSimpleSearch };
@@ -1,7 +1,7 @@
1
1
  import { n as defaultReadOptions, t as createEndpoint } from "../endpoint-MyoBU5IC.js";
2
2
  import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-SC7P37WG.js";
3
- import { n as searchSimple, t as searchAdvanced } from "../advanced-B0__lVW5.js";
4
- import { create, insertMultiple, save } from "zbsearch";
3
+ import { n as searchSimple, t as searchAdvanced } from "../advanced-Ct13khZr.js";
4
+ import { create, insertMultipleAsync, save } from "zbsearch";
5
5
  //#region src/search/zbsearch/create-db.ts
6
6
  const simpleSchema = {
7
7
  url: "string",
@@ -36,7 +36,7 @@ async function createDB({ indexes, tokenizer, language = DefaultLanguage, search
36
36
  }
37
37
  });
38
38
  const mapTo = buildDocuments(items);
39
- await insertMultiple(db, mapTo);
39
+ await insertMultipleAsync(db, mapTo);
40
40
  return db;
41
41
  }
42
42
  async function createDBSimple({ indexes, tokenizer, language = DefaultLanguage, search: _, localeFilter: __, ...rest }) {
@@ -51,7 +51,7 @@ async function createDBSimple({ indexes, tokenizer, language = DefaultLanguage,
51
51
  tokenizer: resolvedTokenizer
52
52
  }
53
53
  });
54
- await insertMultiple(db, items.map((page) => ({
54
+ await insertMultipleAsync(db, items.map((page) => ({
55
55
  title: page.title,
56
56
  description: page.description,
57
57
  breadcrumbs: page.breadcrumbs,
@@ -207,8 +207,12 @@ function createFromSource(loader, options = {}) {
207
207
  const l = typeof loader === "function" ? await loader() : loader;
208
208
  let server = cache.get(l);
209
209
  if (!server) {
210
- server = initServer(l);
211
- cache.set(l, server);
210
+ const promise = initServer(l);
211
+ promise.catch(() => {
212
+ if (cache.get(l) === promise) cache.delete(l);
213
+ });
214
+ cache.set(l, promise);
215
+ server = promise;
212
216
  }
213
217
  return await server;
214
218
  }
@@ -2,7 +2,7 @@ import { t as Awaitable } from "./types-D89QoQR-.js";
2
2
  import { i as StructuredData } from "./remark-structure-CnHwvNZr.js";
3
3
  import { n as I18nConfig } from "./index-DydiXvgS.js";
4
4
  import { r as SortedResult } from "./index-BM36H-xw.js";
5
- import { x as LoaderOutput, y as LoaderConfig } from "./index-BNgjXvXj2.js";
5
+ import { x as LoaderOutput, y as LoaderConfig } from "./index-C8oBtRaX2.js";
6
6
  import { Language, RawData, SearchParams, TypedDocument, ZBSearch, create } from "zbsearch";
7
7
  //#region src/search/zbsearch/create-db.d.ts
8
8
  type SimpleDocument = TypedDocument<ZBSearch<typeof simpleSchema>>;
@@ -1,2 +1,2 @@
1
- import { g as dynamicLoader, h as DynamicLoaderConfig, m as DynamicLoader } from "../index-BNgjXvXj2.js";
1
+ import { g as dynamicLoader, h as DynamicLoaderConfig, m as DynamicLoader } from "../index-C8oBtRaX2.js";
2
2
  export { DynamicLoader, DynamicLoaderConfig, dynamicLoader };
@@ -1,31 +1,32 @@
1
- import { i as isStaticSource, n as loader, r as isDynamicSource } from "../loader-9mGcCnIF.js";
1
+ import { t as isEqualShallow } from "../is-equal-LdLqRs0o.js";
2
+ import { i as isStaticSource, n as loader, r as isDynamicSource } from "../loader-BfwY7fPX.js";
2
3
  import { cache } from "react";
3
4
  //#region src/source/dynamic.ts
5
+ /** content loader API for static & dynamic content sources, with in-memory cache. */
4
6
  function dynamicLoader(input, options) {
5
7
  let loaderCacheKey;
6
8
  let loaderCache;
7
- const sourceCache = /* @__PURE__ */ new Map();
8
- function configureSources() {
9
- if (isStaticSource(input)) return;
10
- if (isDynamicSource(input)) {
11
- input.configure?.(dynamicLoader);
12
- return;
13
- }
14
- for (const v of Object.values(input)) if (isDynamicSource(v)) v.configure?.(dynamicLoader);
15
- }
16
- async function resolveSources(skipCache = false) {
17
- if (isStaticSource(input) || isDynamicSource(input)) return resolveSource(input, skipCache);
18
- const entries = await Promise.all(Object.entries(input).map(async ([k, v]) => [k, await resolveSource(v, skipCache)]));
9
+ const memoryCache = /* @__PURE__ */ new Map();
10
+ async function resolveSources() {
11
+ if (isStaticSource(input) || isDynamicSource(input)) return resolveSource(input);
12
+ const entries = await Promise.all(Object.entries(input).map(async ([k, v]) => [k, await resolveSource(v)]));
19
13
  return Object.fromEntries(entries);
20
14
  }
21
- function resolveSource(v, skipCache = false) {
15
+ function resolveSource(v) {
22
16
  if (isStaticSource(v)) return v;
23
- let resolved = skipCache ? void 0 : sourceCache.get(v);
24
- if (resolved) return resolved;
25
- const files = v.files();
26
- if ("then" in files) resolved = files.then((res) => ({ files: res }));
27
- else resolved = { files };
28
- sourceCache.set(v, resolved);
17
+ const cache = v.cache ?? "memory";
18
+ if (cache === "memory") {
19
+ const cached = memoryCache.get(v);
20
+ if (cached) return cached;
21
+ }
22
+ const resolved = Promise.resolve(v.files()).then((res) => ({
23
+ files: res,
24
+ configureStatic: v.configureStatic
25
+ })).catch((e) => {
26
+ if (cache === "memory" && memoryCache.get(v) === resolved) memoryCache.delete(v);
27
+ throw e;
28
+ });
29
+ if (cache === "memory") memoryCache.set(v, resolved);
29
30
  return resolved;
30
31
  }
31
32
  const dynamicLoader = {
@@ -39,27 +40,34 @@ function dynamicLoader(input, options) {
39
40
  $inferPage: void 0,
40
41
  $inferMeta: void 0,
41
42
  async revalidate(name) {
42
- if (name === void 0) await resolveSources(true);
43
- else if (!isStaticSource(input) && !isDynamicSource(input)) await resolveSource(input[name], true);
43
+ dynamicLoader.invalidate(name);
44
+ if (name === void 0) await resolveSources();
45
+ else if (!isStaticSource(input) && !isDynamicSource(input)) await resolveSource(input[name]);
44
46
  },
45
47
  invalidate(name) {
46
- if (name === void 0) sourceCache.clear();
47
- else if (!isStaticSource(input) && !isDynamicSource(input)) {
48
- const s = input[name];
49
- if (isDynamicSource(s)) sourceCache.delete(s);
48
+ if (isStaticSource(input)) return;
49
+ if (name === void 0) {
50
+ memoryCache.clear();
51
+ if (isDynamicSource(input)) input.invalidate?.();
52
+ else for (const v of Object.values(input)) if (isDynamicSource(v)) v.invalidate?.();
53
+ return;
50
54
  }
55
+ if (isDynamicSource(input)) return;
56
+ const s = input[name];
57
+ if (!isDynamicSource(s)) return;
58
+ memoryCache.delete(s);
59
+ s.invalidate?.();
51
60
  }
52
61
  };
53
- configureSources();
62
+ if (isDynamicSource(input)) input.configure?.(dynamicLoader, {});
63
+ else if (!isStaticSource(input)) {
64
+ for (const [k, v] of Object.entries(input)) if (isDynamicSource(v)) v.configure?.(dynamicLoader, { source: k });
65
+ }
54
66
  return dynamicLoader;
55
67
  }
56
68
  function isEqual(a, b) {
57
- if (isStaticSource(a) && isStaticSource(b)) return a === b;
58
- if (!isStaticSource(a) && !isStaticSource(b)) {
59
- const aKeys = Object.keys(a);
60
- const bKeys = Object.keys(b);
61
- return aKeys.length === bKeys.length && aKeys.every((k) => a[k] === b[k]);
62
- }
69
+ if (isStaticSource(a) && isStaticSource(b)) return isEqualShallow(a.files, b.files);
70
+ if (!isStaticSource(a) && !isStaticSource(b)) return Object.keys(b).every((k) => isEqualShallow(a[k].files, b[k].files));
63
71
  return false;
64
72
  }
65
73
  //#endregion
@@ -1,2 +1,2 @@
1
- import { B as ContentStorageMetaFile, C as LoaderPluginOption, D as createGetUrl, E as ResolvedLoaderConfig, F as PageTreeBuilder, H as FileSystem, I as PageTreeBuilderContext, L as PageTreeOptions, M as getSlugs, O as loader, R as PageTreeTransformer, S as LoaderPlugin, T as Page, V as ContentStoragePageFile, _ as InferMetaType, a as MetaData, b as LoaderOptions, c as SourceUnion, d as multiple, f as source, i as DynamicSource, k as types_d_exports, l as StaticSource, n as llms, o as PageData, p as update, r as path_d_exports, s as Source, t as LLMsConfig, u as VirtualFile, v as InferPageType, w as Meta, x as LoaderOutput, y as LoaderConfig, z as ContentStorage } from "../index-BNgjXvXj2.js";
1
+ import { B as ContentStorageMetaFile, C as LoaderPluginOption, D as createGetUrl, E as ResolvedLoaderConfig, F as PageTreeBuilder, H as FileSystem, I as PageTreeBuilderContext, L as PageTreeOptions, M as getSlugs, O as loader, R as PageTreeTransformer, S as LoaderPlugin, T as Page, V as ContentStoragePageFile, _ as InferMetaType, a as MetaData, b as LoaderOptions, c as SourceUnion, d as multiple, f as source, i as DynamicSource, k as types_d_exports, l as StaticSource, n as llms, o as PageData, p as update, r as path_d_exports, s as Source, t as LLMsConfig, u as VirtualFile, v as InferPageType, w as Meta, x as LoaderOutput, y as LoaderConfig, z as ContentStorage } from "../index-C8oBtRaX2.js";
2
2
  export { type ContentStorage, type ContentStorageMetaFile, type ContentStoragePageFile, type DynamicSource, FileSystem, InferMetaType, InferPageType, LLMsConfig, LoaderConfig, LoaderOptions, LoaderOutput, LoaderPlugin, LoaderPluginOption, Meta, type MetaData, Page, type PageData, type PageTreeBuilder, type PageTreeBuilderContext, type PageTreeOptions, type PageTreeTransformer, path_d_exports as PathUtils, ResolvedLoaderConfig, type Source, type SourceUnion, type StaticSource, type VirtualFile, type types_d_exports as _Internal, createGetUrl, getSlugs, llms, loader, multiple, source, update };
@@ -1,5 +1,5 @@
1
1
  import { o as path_exports } from "../path-1H5VzYiT.js";
2
- import { a as multiple, c as FileSystem, n as loader, o as source, s as update, t as createGetUrl } from "../loader-9mGcCnIF.js";
2
+ import { a as multiple, c as FileSystem, n as loader, o as source, s as update, t as createGetUrl } from "../loader-BfwY7fPX.js";
3
3
  import { getSlugs } from "./plugins/slugs.js";
4
4
  import { llms } from "./llms.js";
5
5
  export { FileSystem, path_exports as PathUtils, createGetUrl, getSlugs, llms, loader, multiple, source, update };
@@ -1,2 +1,2 @@
1
- import { n as llms, t as LLMsConfig } from "../index-BNgjXvXj2.js";
1
+ import { n as llms, t as LLMsConfig } from "../index-C8oBtRaX2.js";
2
2
  export { LLMsConfig, llms };
@@ -1,4 +1,4 @@
1
- import { S as LoaderPlugin } from "../../index-BNgjXvXj2.js";
1
+ import { S as LoaderPlugin } from "../../index-C8oBtRaX2.js";
2
2
  import { icons } from "lucide-react";
3
3
  //#region src/source/plugins/lucide-icons.d.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { A as SlugFn, M as getSlugs, N as slugsFromData, P as slugsPlugin, j as SlugsPluginOptions } from "../../index-BNgjXvXj2.js";
1
+ import { A as SlugFn, M as getSlugs, N as slugsFromData, P as slugsPlugin, j as SlugsPluginOptions } from "../../index-C8oBtRaX2.js";
2
2
  export { SlugFn, SlugsPluginOptions, getSlugs, slugsFromData, slugsPlugin };
@@ -1,5 +1,5 @@
1
1
  import { a as Separator$1, n as Item$1, t as Folder$1 } from "../../definitions-D8-KI7Uy.js";
2
- import { S as LoaderPlugin } from "../../index-BNgjXvXj2.js";
2
+ import { S as LoaderPlugin } from "../../index-C8oBtRaX2.js";
3
3
  import { ReactNode } from "react";
4
4
  //#region src/source/plugins/status-badges.d.ts
5
5
  interface Item extends Item$1 {
@@ -1,27 +1,19 @@
1
1
  //#region src/highlight/utils.ts
2
2
  async function loadMissingTheme(highlighter, themes) {
3
3
  const bundled = highlighter.getBundledThemes();
4
+ const loaded = highlighter.getLoadedThemes();
4
5
  const missingThemes = themes.filter((theme) => {
5
- if (typeof theme === "string" && !(theme in bundled)) return false;
6
- try {
7
- highlighter.getTheme(theme);
8
- return false;
9
- } catch {
10
- return true;
11
- }
6
+ if (typeof theme === "string") return theme in bundled && !loaded.includes(theme);
7
+ return theme.name === void 0 || !loaded.includes(theme.name);
12
8
  });
13
9
  if (missingThemes.length > 0) await highlighter.loadTheme(...missingThemes);
14
10
  }
15
11
  async function loadMissingLanguage(highlighter, langs) {
16
12
  const bundled = highlighter.getBundledLanguages();
13
+ const loaded = highlighter.getLoadedLanguages();
17
14
  const missingLangs = langs.filter((lang) => {
18
- if (typeof lang === "string" && !(lang in bundled)) return false;
19
- try {
20
- highlighter.getLanguage(lang);
21
- return false;
22
- } catch {
23
- return true;
24
- }
15
+ if (typeof lang === "string") return lang in bundled && !loaded.includes(lang);
16
+ return !loaded.includes(lang.name);
25
17
  });
26
18
  if (missingLangs.length > 0) await highlighter.loadLanguage(...missingLangs);
27
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "16.14.5",
3
+ "version": "16.15.0",
4
4
  "description": "The React.js library for building a documentation website",
5
5
  "keywords": [
6
6
  "Docs",