fumadocs-core 16.12.1 → 16.14.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.
@@ -1,8 +1,8 @@
1
1
  import { createContentHighlighter } from "./search/index.js";
2
2
  import { t as removeUndefined } from "./remove-undefined-CzMSKybq.js";
3
- import { getByID, search } from "@orama/orama";
4
- //#region src/search/orama/search/simple.ts
5
- async function searchSimple(db, query, params = {}) {
3
+ import { getByID, search } from "zbsearch";
4
+ //#region src/search/zbsearch/search/simple.ts
5
+ async function searchSimple(db, query, params = {}, locale) {
6
6
  const highlighter = createContentHighlighter(query);
7
7
  return (await search(db, {
8
8
  term: query,
@@ -11,7 +11,11 @@ async function searchSimple(db, query, params = {}) {
11
11
  boost: {
12
12
  title: 2,
13
13
  ..."boost" in params ? params.boost : void 0
14
- }
14
+ },
15
+ where: removeUndefined({
16
+ locale: locale ? { eq: locale } : void 0,
17
+ ...params.where
18
+ })
15
19
  })).hits.map((hit) => ({
16
20
  type: "page",
17
21
  content: highlighter.highlightMarkdown(hit.document.title),
@@ -21,8 +25,8 @@ async function searchSimple(db, query, params = {}) {
21
25
  }));
22
26
  }
23
27
  //#endregion
24
- //#region src/search/orama/search/advanced.ts
25
- async function searchAdvanced(db, query, tag = [], { mode = "fulltext", ...override } = {}) {
28
+ //#region src/search/zbsearch/search/advanced.ts
29
+ async function searchAdvanced(db, query, tag = [], { mode = "fulltext", ...override } = {}, locale) {
26
30
  if (typeof tag === "string") tag = [tag];
27
31
  const params = {
28
32
  limit: 60,
@@ -30,6 +34,7 @@ async function searchAdvanced(db, query, tag = [], { mode = "fulltext", ...overr
30
34
  ...override,
31
35
  where: removeUndefined({
32
36
  tags: tag.length > 0 ? { containsAll: tag } : void 0,
37
+ locale: locale ? { eq: locale } : void 0,
33
38
  ...override.where
34
39
  }),
35
40
  groupBy: {
@@ -47,7 +47,8 @@ function buildDocuments(indexes) {
47
47
  content: page.title,
48
48
  breadcrumbs: page.breadcrumbs,
49
49
  tags,
50
- url: page.url
50
+ url: page.url,
51
+ locale: page.locale
51
52
  });
52
53
  const nextId = () => `${page.id}-${id++}`;
53
54
  if (page.description) docs.push({
@@ -56,7 +57,8 @@ function buildDocuments(indexes) {
56
57
  tags,
57
58
  type: "text",
58
59
  url: page.url,
59
- content: page.description
60
+ content: page.description,
61
+ locale: page.locale
60
62
  });
61
63
  for (const heading of data.headings) docs.push({
62
64
  id: nextId(),
@@ -64,7 +66,8 @@ function buildDocuments(indexes) {
64
66
  type: "heading",
65
67
  tags,
66
68
  url: `${page.url}#${heading.id}`,
67
- content: heading.content
69
+ content: heading.content,
70
+ locale: page.locale
68
71
  });
69
72
  for (const content of data.contents) docs.push({
70
73
  id: nextId(),
@@ -72,7 +75,8 @@ function buildDocuments(indexes) {
72
75
  tags,
73
76
  type: "text",
74
77
  url: content.heading ? `${page.url}#${content.heading}` : page.url,
75
- content: content.content
78
+ content: content.content,
79
+ locale: page.locale
76
80
  });
77
81
  }
78
82
  return docs;
@@ -2,7 +2,7 @@ import { t as Awaitable } from "./types-D89QoQR-.js";
2
2
  import { t as BaseIndex } from "./algolia-C0E5qQhM.js";
3
3
  import { r as SortedResult } from "./index-BM36H-xw.js";
4
4
  import { DependencyList } from "react";
5
- import { AnyOrama, Orama, SearchParams } from "@orama/orama";
5
+ import { AnyZBSearch, SearchParams } from "zbsearch";
6
6
  import { LiteClient, SearchResponse } from "algoliasearch/lite";
7
7
  import { OramaCloud, OramaCloudSearchParams } from "@orama/core";
8
8
  import { ClientSearchParams, OramaClient } from "@oramacloud/client";
@@ -35,21 +35,34 @@ interface StaticOptions {
35
35
  * @defaultValue '/api/search'
36
36
  */
37
37
  from?: string;
38
- initOrama?: (locale?: string) => AnyOrama | Promise<AnyOrama>;
38
+ /**
39
+ * Customize how the search database is initialized (advanced).
40
+ *
41
+ * For legacy per-locale exports, it is called once per locale.
42
+ */
43
+ initDB?: (locale?: string) => AnyZBSearch | Promise<AnyZBSearch>;
44
+ /**
45
+ * @deprecated Renamed to `initDB`, note that the search engine is now ZBSearch.
46
+ */
47
+ initOrama?: (locale?: string) => AnyZBSearch | Promise<AnyZBSearch>;
39
48
  /**
40
49
  * Filter results with specific tag(s).
41
50
  */
42
51
  tag?: string | string[];
43
52
  /**
44
- * Filter by locale (unsupported at the moment)
53
+ * Filter by locale (for i18n)
45
54
  */
46
55
  locale?: string;
47
56
  /**
48
57
  * extra options for search
49
58
  */
50
- search?: Partial<SearchParams<Orama<unknown>>>;
59
+ search?: Partial<SearchParams<AnyZBSearch>>;
51
60
  }
52
- declare function oramaStaticClient(options?: StaticOptions): SearchClient;
61
+ declare function staticClient(options?: StaticOptions): SearchClient;
62
+ /**
63
+ * @deprecated Renamed to `staticClient`, note that the search engine is now ZBSearch.
64
+ */
65
+ declare const oramaStaticClient: typeof staticClient;
53
66
  //#endregion
54
67
  //#region src/search/client/algolia.d.ts
55
68
  interface AlgoliaOptions {
@@ -174,7 +187,7 @@ type ClientPreset = ({
174
187
  type: 'fetch';
175
188
  } & FetchOptions) | ({
176
189
  /**
177
- * @deprecated Pass `client: oramaStaticClient(...)` instead.
190
+ * @deprecated Pass `client: staticClient(...)` instead.
178
191
  */
179
192
  type: 'static';
180
193
  } & StaticOptions) | ({
@@ -231,4 +244,4 @@ declare function useDocsSearch(clientOptions: ClientPreset & {
231
244
  allowEmpty?: boolean;
232
245
  }, customDeps?: DependencyList): UseDocsSearch;
233
246
  //#endregion
234
- export { FetchOptions as _, flexsearchStaticClient as a, mixedbreadClient as c, OramaCloudOptions as d, oramaCloudClient as f, oramaStaticClient as g, StaticOptions as h, FlexsearchStaticOptions as i, OramaCloudLegacyOptions as l, algoliaClient as m, SearchClient as n, MixedbreadOptions as o, AlgoliaOptions as p, useDocsSearch as r, SearchMetadata as s, ClientPreset as t, oramaCloudLegacyClient as u, fetchClient as v };
247
+ export { staticClient as _, flexsearchStaticClient as a, mixedbreadClient as c, OramaCloudOptions as d, oramaCloudClient as f, oramaStaticClient as g, StaticOptions as h, FlexsearchStaticOptions as i, OramaCloudLegacyOptions as l, algoliaClient as m, SearchClient as n, MixedbreadOptions as o, AlgoliaOptions as p, useDocsSearch as r, SearchMetadata as s, ClientPreset as t, oramaCloudLegacyClient as u, FetchOptions as v, fetchClient as y };
@@ -1,4 +1,4 @@
1
- import { t as getNegotiator } from "../negotiation-D7x4zl2m.js";
1
+ import { t as getNegotiator } from "../negotiation-Bdf_-s58.js";
2
2
  import { NextResponse } from "next/server.js";
3
3
  //#region ../../node_modules/.pnpm/@formatjs+fast-memoize@3.1.7/node_modules/@formatjs/fast-memoize/index.js
4
4
  function memoize(fn, options) {
@@ -1,2 +1,2 @@
1
- import { n as isMarkdownPreferred, r as rewritePath, t as getNegotiator } from "../negotiation-D7x4zl2m.js";
1
+ import { n as isMarkdownPreferred, r as rewritePath, t as getNegotiator } from "../negotiation-Bdf_-s58.js";
2
2
  export { getNegotiator, isMarkdownPreferred, rewritePath };
@@ -1008,14 +1008,47 @@ function rewritePath(source, destination) {
1008
1008
  return compiler(result.params);
1009
1009
  } };
1010
1010
  }
1011
+ /**
1012
+ * Parse an `Accept` header into its media types and quality values.
1013
+ *
1014
+ * Media types the client didn't rank explicitly default to `q=1`.
1015
+ */
1016
+ function parseAccept(header) {
1017
+ const entries = [];
1018
+ for (const section of header.split(",")) {
1019
+ const [rawMediaType, ...params] = section.split(";");
1020
+ const mediaType = rawMediaType.trim().toLowerCase();
1021
+ if (mediaType.length === 0) continue;
1022
+ let quality = 1;
1023
+ for (const param of params) {
1024
+ const separator = param.indexOf("=");
1025
+ if (separator === -1 || param.slice(0, separator).trim().toLowerCase() !== "q") continue;
1026
+ const parsed = Number.parseFloat(param.slice(separator + 1));
1027
+ if (!Number.isNaN(parsed)) quality = parsed;
1028
+ }
1029
+ entries.push({
1030
+ mediaType,
1031
+ quality
1032
+ });
1033
+ }
1034
+ return entries;
1035
+ }
1011
1036
  function isMarkdownPreferred(request, options) {
1012
1037
  const { markdownMediaTypes = [
1013
1038
  "text/plain",
1014
1039
  "text/markdown",
1015
1040
  "text/x-markdown"
1016
1041
  ] } = options ?? {};
1017
- const mediaTypes = getNegotiator(request).mediaTypes();
1018
- return markdownMediaTypes.some((type) => mediaTypes.includes(type));
1042
+ const accept = request.headers.get("accept");
1043
+ if (!accept) return false;
1044
+ let markdown = 0;
1045
+ let html = 0;
1046
+ for (const { mediaType, quality } of parseAccept(accept)) {
1047
+ if (quality <= 0) continue;
1048
+ if (markdownMediaTypes.includes(mediaType)) markdown = Math.max(markdown, quality);
1049
+ else if (mediaType === "text/html" || mediaType === "text/*" || mediaType === "*/*") html = Math.max(html, quality);
1050
+ }
1051
+ return markdown > 0 && markdown >= html;
1019
1052
  }
1020
1053
  //#endregion
1021
1054
  export { isMarkdownPreferred as n, rewritePath as r, getNegotiator as t };
@@ -1,2 +1,2 @@
1
- import { m as algoliaClient, p as AlgoliaOptions } from "../../client-CFte63Ws.js";
1
+ import { m as algoliaClient, p as AlgoliaOptions } from "../../client-DURack0W.js";
2
2
  export { AlgoliaOptions, algoliaClient };
@@ -1,2 +1,2 @@
1
- import { _ as FetchOptions, v as fetchClient } from "../../client-CFte63Ws.js";
1
+ import { v as FetchOptions, y as fetchClient } from "../../client-DURack0W.js";
2
2
  export { FetchOptions, fetchClient };
@@ -1,2 +1,2 @@
1
- import { a as flexsearchStaticClient, i as FlexsearchStaticOptions } from "../../client-CFte63Ws.js";
1
+ import { a as flexsearchStaticClient, i as FlexsearchStaticOptions } from "../../client-DURack0W.js";
2
2
  export { FlexsearchStaticOptions, flexsearchStaticClient };
@@ -1,2 +1,2 @@
1
- import { c as mixedbreadClient, o as MixedbreadOptions, s as SearchMetadata } from "../../client-CFte63Ws.js";
1
+ import { c as mixedbreadClient, o as MixedbreadOptions, s as SearchMetadata } from "../../client-DURack0W.js";
2
2
  export { MixedbreadOptions, SearchMetadata, mixedbreadClient };
@@ -1,2 +1,2 @@
1
- import { l as OramaCloudLegacyOptions, u as oramaCloudLegacyClient } from "../../client-CFte63Ws.js";
1
+ import { l as OramaCloudLegacyOptions, u as oramaCloudLegacyClient } from "../../client-DURack0W.js";
2
2
  export { OramaCloudLegacyOptions, oramaCloudLegacyClient };
@@ -1,2 +1,2 @@
1
- import { d as OramaCloudOptions, f as oramaCloudClient } from "../../client-CFte63Ws.js";
1
+ import { d as OramaCloudOptions, f as oramaCloudClient } from "../../client-DURack0W.js";
2
2
  export { OramaCloudOptions, oramaCloudClient };
@@ -1,2 +1,2 @@
1
- import { g as oramaStaticClient, h as StaticOptions } from "../../client-CFte63Ws.js";
2
- export { StaticOptions, oramaStaticClient };
1
+ import { _ as staticClient, g as oramaStaticClient, h as StaticOptions } from "../../client-DURack0W.js";
2
+ export { StaticOptions, oramaStaticClient, staticClient };
@@ -1,58 +1,75 @@
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-BnqbPavQ.js";
3
- import { create, load } from "@orama/orama";
2
+ import { n as searchSimple, t as searchAdvanced } from "../../advanced-B0__lVW5.js";
3
+ import { create, load } from "zbsearch";
4
4
  //#region src/search/client/orama-static.ts
5
5
  const cache = /* @__PURE__ */ new Map();
6
- async function loadDB(from, initOrama = (locale) => create({
7
- schema: { _: "string" },
8
- language: locale
9
- })) {
6
+ async function loadDB(from, initDB = () => create({ schema: { _: "string" } })) {
10
7
  const res = await fetch(from);
11
8
  if (!res.ok) throw new Error(`failed to fetch exported search indexes from ${from}, make sure the search database is exported and available for client.`);
12
9
  const data = await res.json();
13
- const dbs = /* @__PURE__ */ new Map();
14
- if (data.type === "i18n") await Promise.all(Object.entries(data.data).map(async ([k, v]) => {
15
- const db = await initOrama(k);
16
- load(db, v);
17
- dbs.set(k, {
18
- type: v.type,
19
- db
20
- });
21
- }));
22
- else {
23
- const db = await initOrama();
24
- load(db, data);
25
- dbs.set("", {
26
- type: data.type,
27
- db
28
- });
10
+ const map = /* @__PURE__ */ new Map();
11
+ if (data.type === "i18n") {
12
+ await Promise.all(Object.entries(data.data).map(async ([k, v]) => {
13
+ const db = await initDB(k);
14
+ load(db, v);
15
+ map.set(k, {
16
+ type: v.type,
17
+ db
18
+ });
19
+ }));
20
+ return {
21
+ map,
22
+ unified: false,
23
+ i18n: true
24
+ };
29
25
  }
30
- return dbs;
26
+ const db = await initDB();
27
+ load(db, data);
28
+ map.set("", {
29
+ type: data.type,
30
+ db
31
+ });
32
+ return {
33
+ map,
34
+ unified: true,
35
+ i18n: data.i18n === true
36
+ };
31
37
  }
32
- function getDBCached({ from = join(BASE_PATH, "/api/search"), initOrama }) {
38
+ function getDBCached({ from = join(BASE_PATH, "/api/search"), initDB, initOrama }) {
33
39
  const cacheKey = from;
34
40
  const cached = cache.get(cacheKey);
35
41
  if (cached) return cached;
36
- const result = loadDB(from, initOrama);
42
+ const result = loadDB(from, initDB ?? initOrama);
37
43
  cache.set(cacheKey, result);
38
44
  return result;
39
45
  }
40
- function oramaStaticClient(options = {}) {
46
+ function staticClient(options = {}) {
41
47
  const { tag, locale, search } = options;
42
48
  return {
43
49
  deps: [tag, locale],
44
50
  async search(query) {
45
- const dbs = await getDBCached(options);
46
- let db = dbs.get(locale ?? "");
47
- if (!db) {
48
- console.warn(`failed to find search data for "${locale}", available: ${Array.from(dbs.keys())}.`);
49
- db = dbs.values().next().value;
51
+ const { map, unified, i18n } = await getDBCached(options);
52
+ let db;
53
+ let filterLocale;
54
+ if (unified) {
55
+ db = map.get("");
56
+ if (i18n) filterLocale = locale;
57
+ } else {
58
+ db = map.get(locale ?? "");
59
+ if (!db) {
60
+ console.warn(`failed to find search data for "${locale}", available: ${Array.from(map.keys())}.`);
61
+ db = map.values().next().value;
62
+ }
50
63
  }
51
64
  if (!db) return [];
52
- if (db.type === "simple") return searchSimple(db, query, search);
53
- return searchAdvanced(db.db, query, tag, search);
65
+ if (db.type === "simple") return searchSimple(db.db, query, search, filterLocale);
66
+ return searchAdvanced(db.db, query, tag, search, filterLocale);
54
67
  }
55
68
  };
56
69
  }
70
+ /**
71
+ * @deprecated Renamed to `staticClient`, note that the search engine is now ZBSearch.
72
+ */
73
+ const oramaStaticClient = staticClient;
57
74
  //#endregion
58
- export { oramaStaticClient };
75
+ export { oramaStaticClient, staticClient };
@@ -1,2 +1,2 @@
1
- import { _ as FetchOptions, d as OramaCloudOptions, h as StaticOptions, n as SearchClient, p as AlgoliaOptions, r as useDocsSearch, t as ClientPreset } from "../client-CFte63Ws.js";
1
+ import { d as OramaCloudOptions, h as StaticOptions, n as SearchClient, p as AlgoliaOptions, r as useDocsSearch, t as ClientPreset, v as FetchOptions } from "../client-DURack0W.js";
2
2
  export { type AlgoliaOptions, ClientPreset, type FetchOptions, type OramaCloudOptions, SearchClient, type StaticOptions, useDocsSearch };
@@ -45,7 +45,7 @@ function useDocsSearch(clientOptions, customDeps) {
45
45
  client = import("./client/mixedbread.js").then((mod) => mod.mixedbreadClient(clientRest));
46
46
  break;
47
47
  case "static":
48
- client = import("./client/orama-static.js").then((mod) => mod.oramaStaticClient(clientRest));
48
+ client = import("./client/orama-static.js").then((mod) => mod.staticClient(clientRest));
49
49
  break;
50
50
  default: throw new Error("unknown search client");
51
51
  }
@@ -1,7 +1,7 @@
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-gfoj6dyH.js";
4
+ import { m as SharedIndex, n as SearchAPI, t as QueryOptions } from "../server-Bu44vTPO.js";
5
5
  import { x as LoaderOutput, y as LoaderConfig } from "../index-sdv2T3z92.js";
6
6
  import { DocumentData, DocumentOptions } from "flexsearch";
7
7
  //#region src/search/server/build-doc.d.ts
@@ -13,6 +13,7 @@ interface SharedDocument {
13
13
  breadcrumbs?: string[];
14
14
  tags: string[];
15
15
  url: string;
16
+ locale?: string;
16
17
  }
17
18
  //#endregion
18
19
  //#region src/search/flexsearch/utils.d.ts
@@ -1,5 +1,5 @@
1
1
  import { t as createEndpoint } from "../endpoint-MyoBU5IC.js";
2
- import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-CTQdPLc0.js";
2
+ import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-C3YHxNoA.js";
3
3
  import { n as search, t as createDocument } from "../utils-Bvy3V-fv.js";
4
4
  import Search from "flexsearch";
5
5
  //#region src/search/flexsearch.ts
@@ -1,5 +1,5 @@
1
1
  import { r as SortedResult } from "../index-BM36H-xw.js";
2
- import { n as SearchAPI } from "../server-gfoj6dyH.js";
2
+ import { n as SearchAPI } from "../server-Bu44vTPO.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-gfoj6dyH.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-Bu44vTPO.js";
2
2
  export { AdvancedIndex, AdvancedOptions, ExportedData, Index, QueryOptions, SearchAPI, SearchServer, SimpleOptions, createFromSource, createI18nSearchAPI, createSearchAPI, initAdvancedSearch, initSimpleSearch };
@@ -1,50 +1,16 @@
1
1
  import { n as defaultReadOptions, t as createEndpoint } from "../endpoint-MyoBU5IC.js";
2
- import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-CTQdPLc0.js";
3
- import { n as searchSimple, t as searchAdvanced } from "../advanced-BnqbPavQ.js";
4
- import { create, insertMultiple, save } from "@orama/orama";
5
- //#region src/search/orama/_stemmers.ts
6
- const STEMMERS = {
7
- arabic: "ar",
8
- armenian: "am",
9
- bulgarian: "bg",
10
- czech: "cz",
11
- danish: "dk",
12
- dutch: "nl",
13
- english: "en",
14
- finnish: "fi",
15
- french: "fr",
16
- german: "de",
17
- greek: "gr",
18
- hungarian: "hu",
19
- indian: "in",
20
- indonesian: "id",
21
- irish: "ie",
22
- italian: "it",
23
- lithuanian: "lt",
24
- nepali: "np",
25
- norwegian: "no",
26
- portuguese: "pt",
27
- romanian: "ro",
28
- russian: "ru",
29
- serbian: "rs",
30
- slovenian: "ru",
31
- spanish: "es",
32
- swedish: "se",
33
- tamil: "ta",
34
- turkish: "tr",
35
- ukrainian: "uk",
36
- vietnamese: "vi",
37
- sanskrit: "sk"
38
- };
39
- //#endregion
40
- //#region src/search/orama/create-db.ts
2
+ import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-C3YHxNoA.js";
3
+ import { n as searchSimple, t as searchAdvanced } from "../advanced-B0__lVW5.js";
4
+ import { create, insertMultiple, save } from "zbsearch";
5
+ //#region src/search/zbsearch/create-db.ts
41
6
  const simpleSchema = {
42
7
  url: "string",
43
8
  title: "string",
44
9
  breadcrumbs: "string[]",
45
10
  description: "string",
46
11
  content: "string",
47
- keywords: "string"
12
+ keywords: "string",
13
+ locale: "enum"
48
14
  };
49
15
  const advancedSchema = {
50
16
  content: "string",
@@ -53,12 +19,14 @@ const advancedSchema = {
53
19
  breadcrumbs: "string[]",
54
20
  tags: "enum[]",
55
21
  url: "string",
22
+ locale: "enum",
56
23
  embeddings: "vector[512]"
57
24
  };
58
- async function createDB({ indexes, tokenizer, search: _, ...rest }) {
25
+ async function createDB({ indexes, tokenizer, language = "multilingual", search: _, localeFilter: __, ...rest }) {
59
26
  const items = typeof indexes === "function" ? await indexes() : indexes;
60
27
  const db = create({
61
28
  schema: advancedSchema,
29
+ language,
62
30
  ...rest,
63
31
  components: {
64
32
  ...rest.components,
@@ -68,10 +36,11 @@ async function createDB({ indexes, tokenizer, search: _, ...rest }) {
68
36
  await insertMultiple(db, buildDocuments(items));
69
37
  return db;
70
38
  }
71
- async function createDBSimple({ indexes, tokenizer, ...rest }) {
39
+ async function createDBSimple({ indexes, tokenizer, language = "multilingual", search: _, localeFilter: __, ...rest }) {
72
40
  const items = typeof indexes === "function" ? await indexes() : indexes;
73
41
  const db = create({
74
42
  schema: simpleSchema,
43
+ language,
75
44
  ...rest,
76
45
  components: {
77
46
  ...rest.components,
@@ -84,28 +53,30 @@ async function createDBSimple({ indexes, tokenizer, ...rest }) {
84
53
  breadcrumbs: page.breadcrumbs,
85
54
  url: page.url,
86
55
  content: page.content,
87
- keywords: page.keywords
56
+ keywords: page.keywords,
57
+ locale: page.locale
88
58
  })));
89
59
  return db;
90
60
  }
91
61
  //#endregion
92
- //#region src/search/orama/create-server.ts
62
+ //#region src/search/zbsearch/create-server.ts
93
63
  function initSimpleSearch(options) {
94
64
  const doc = createDBSimple(options);
95
65
  return {
96
66
  async export() {
97
67
  return {
98
68
  type: "simple",
69
+ ...options.localeFilter ? { i18n: true } : null,
99
70
  ...save(await doc)
100
71
  };
101
72
  },
102
73
  async search(query, searchOptions = {}) {
103
74
  const db = await doc;
104
- const { limit } = searchOptions;
75
+ const { limit, locale } = searchOptions;
105
76
  return searchSimple(db, query, {
106
77
  limit,
107
78
  ...options.search
108
- });
79
+ }, options.localeFilter && locale ? locale : void 0);
109
80
  }
110
81
  };
111
82
  }
@@ -115,18 +86,19 @@ function initAdvancedSearch(options) {
115
86
  async export() {
116
87
  return {
117
88
  type: "advanced",
89
+ ...options.localeFilter ? { i18n: true } : null,
118
90
  ...save(await get)
119
91
  };
120
92
  },
121
93
  async search(query, searchOptions = {}) {
122
94
  const db = await get;
123
- const { limit, tag, mode } = searchOptions;
95
+ const { limit, tag, mode, locale } = searchOptions;
124
96
  return searchAdvanced(db, query, tag, {
125
97
  ...options.search,
126
98
  limit,
127
99
  mode: mode === "vector" ? "vector" : "fulltext"
128
- }).catch((err) => {
129
- if (mode === "vector") throw new Error("failed to search, make sure you have installed `@orama/plugin-embeddings` according to their docs.", { cause: err });
100
+ }, options.localeFilter && locale ? locale : void 0).catch((err) => {
101
+ if (mode === "vector") throw new Error("failed to search, make sure your indexes include `embeddings` and a plugin/proxy is configured to vectorize search terms.", { cause: err });
130
102
  throw err;
131
103
  });
132
104
  }
@@ -135,17 +107,35 @@ function initAdvancedSearch(options) {
135
107
  function createSearchAPI(...args) {
136
108
  return toAPI(args[0] === "simple" ? initSimpleSearch(args[1]) : initAdvancedSearch(args[1]));
137
109
  }
138
- function getTokenizer(locale) {
139
- return { language: Object.keys(STEMMERS).find((lang) => STEMMERS[lang] === locale) ?? locale };
140
- }
141
110
  function createI18nSearchAPI(...[type, options]) {
111
+ if (options.localeMap) return createI18nSearchAPILegacy(type, options);
112
+ const server = type === "simple" ? initSimpleSearch({
113
+ ...options,
114
+ language: "multilingual",
115
+ localeFilter: true
116
+ }) : initAdvancedSearch({
117
+ ...options,
118
+ language: "multilingual",
119
+ localeFilter: true
120
+ });
121
+ return toAPI({
122
+ export: server.export,
123
+ async search(query, searchOptions) {
124
+ return server.search(query, {
125
+ ...searchOptions,
126
+ locale: searchOptions?.locale ?? options.i18n.defaultLanguage
127
+ });
128
+ }
129
+ });
130
+ }
131
+ function createI18nSearchAPILegacy(type, options) {
142
132
  async function initSearchServers() {
143
133
  const map = /* @__PURE__ */ new Map();
144
134
  if (options.i18n.languages.length === 0) return map;
145
135
  const indexes = typeof options.indexes === "function" ? await options.indexes() : options.indexes;
146
136
  for (const locale of options.i18n.languages) {
147
137
  const localeIndexes = indexes.filter((index) => index.locale === locale);
148
- const mapped = options.localeMap?.[locale] ?? getTokenizer(locale);
138
+ const mapped = options.localeMap?.[locale] ?? "multilingual";
149
139
  if (type === "simple") map.set(locale, typeof mapped === "object" ? initSimpleSearch({
150
140
  ...options,
151
141
  ...mapped,
@@ -3,9 +3,9 @@ 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
5
  import { x as LoaderOutput, y as LoaderConfig } from "./index-sdv2T3z92.js";
6
- import { Language, Orama, RawData, SearchParams, TypedDocument, create } from "@orama/orama";
7
- //#region src/search/orama/create-db.d.ts
8
- type SimpleDocument = TypedDocument<Orama<typeof simpleSchema>>;
6
+ import { Language, RawData, SearchParams, TypedDocument, ZBSearch, create } from "zbsearch";
7
+ //#region src/search/zbsearch/create-db.d.ts
8
+ type SimpleDocument = TypedDocument<ZBSearch<typeof simpleSchema>>;
9
9
  declare const simpleSchema: {
10
10
  readonly url: "string";
11
11
  readonly title: "string";
@@ -13,8 +13,9 @@ declare const simpleSchema: {
13
13
  readonly description: "string";
14
14
  readonly content: "string";
15
15
  readonly keywords: "string";
16
+ readonly locale: "enum";
16
17
  };
17
- type AdvancedDocument = TypedDocument<Orama<typeof advancedSchema>>;
18
+ type AdvancedDocument = TypedDocument<ZBSearch<typeof advancedSchema>>;
18
19
  declare const advancedSchema: {
19
20
  readonly content: "string";
20
21
  readonly page_id: "string";
@@ -22,6 +23,7 @@ declare const advancedSchema: {
22
23
  readonly breadcrumbs: "string[]";
23
24
  readonly tags: "enum[]";
24
25
  readonly url: "string";
26
+ readonly locale: "enum";
25
27
  readonly embeddings: "vector[512]";
26
28
  };
27
29
  //#endregion
@@ -31,6 +33,10 @@ interface SharedIndex {
31
33
  title: string;
32
34
  description?: string;
33
35
  breadcrumbs?: string[];
36
+ /**
37
+ * Locale of content (for i18n)
38
+ */
39
+ locale?: string;
34
40
  /**
35
41
  * Required if tag filter is enabled
36
42
  */
@@ -42,13 +48,24 @@ interface SharedIndex {
42
48
  url: string;
43
49
  }
44
50
  //#endregion
45
- //#region src/search/orama/create-server.d.ts
46
- type OramaInput = Parameters<typeof create>[0];
47
- interface SharedOptions extends Pick<OramaInput, 'sort' | 'components' | 'plugins'> {
51
+ //#region src/search/zbsearch/create-server.d.ts
52
+ type CreateInput = Parameters<typeof create>[0];
53
+ interface SharedOptions extends Pick<CreateInput, 'sort' | 'components' | 'plugins'> {
54
+ /**
55
+ * Tokenizer language.
56
+ *
57
+ * @defaultValue 'multilingual' - works with every language, zero config needed.
58
+ */
48
59
  language?: string;
49
- tokenizer?: Required<OramaInput>['components']['tokenizer'];
60
+ tokenizer?: Required<CreateInput>['components']['tokenizer'];
61
+ /**
62
+ * Filter search results by the `locale` query option, requires indexes to include a `locale` property.
63
+ *
64
+ * Enabled automatically by i18n search servers.
65
+ */
66
+ localeFilter?: boolean;
50
67
  }
51
- interface OramaQueryOptions extends QueryOptions {
68
+ interface EngineQueryOptions extends QueryOptions {
52
69
  mode?: 'full' | 'vector';
53
70
  }
54
71
  /**
@@ -60,14 +77,14 @@ interface SimpleOptions extends SharedOptions {
60
77
  /**
61
78
  * Customize search options on server
62
79
  */
63
- search?: Partial<SearchParams<Orama<typeof simpleSchema>, SimpleDocument>>;
80
+ search?: Partial<SearchParams<ZBSearch<typeof simpleSchema>, SimpleDocument>>;
64
81
  }
65
82
  interface AdvancedOptions extends SharedOptions {
66
83
  indexes: AdvancedIndex[] | Dynamic<AdvancedIndex>;
67
84
  /**
68
85
  * Customize search options on server
69
86
  */
70
- search?: Partial<SearchParams<Orama<typeof advancedSchema>, AdvancedDocument>>;
87
+ search?: Partial<SearchParams<ZBSearch<typeof advancedSchema>, AdvancedDocument>>;
71
88
  }
72
89
  interface Index {
73
90
  title: string;
@@ -76,24 +93,29 @@ interface Index {
76
93
  content: string;
77
94
  url: string;
78
95
  keywords?: string;
96
+ locale?: string;
79
97
  }
80
98
  type ExportedData = (RawData & {
81
99
  type: 'simple' | 'advanced';
100
+ i18n?: boolean;
82
101
  }) | {
83
102
  type: 'i18n';
84
103
  data: Record<string, RawData & {
85
104
  type: 'simple' | 'advanced';
86
105
  }>;
87
106
  };
88
- declare function initSimpleSearch(options: SimpleOptions): SearchServer<OramaQueryOptions>;
107
+ declare function initSimpleSearch(options: SimpleOptions): SearchServer<EngineQueryOptions>;
89
108
  type AdvancedIndex = SharedIndex;
90
- declare function initAdvancedSearch(options: AdvancedOptions): SearchServer<OramaQueryOptions>;
91
- declare function createSearchAPI(type: 'simple', options: SimpleOptions): SearchAPI<OramaQueryOptions>;
92
- declare function createSearchAPI(type: 'advanced', options: AdvancedOptions): SearchAPI<OramaQueryOptions>;
109
+ declare function initAdvancedSearch(options: AdvancedOptions): SearchServer<EngineQueryOptions>;
110
+ declare function createSearchAPI(type: 'simple', options: SimpleOptions): SearchAPI<EngineQueryOptions>;
111
+ declare function createSearchAPI(type: 'advanced', options: AdvancedOptions): SearchAPI<EngineQueryOptions>;
93
112
  type I18nOptions<O extends SimpleOptions | AdvancedOptions, Idx> = Omit<O, 'language' | 'indexes'> & {
94
113
  i18n: I18nConfig;
95
114
  /**
96
- * Map locale name from i18n config to Orama compatible `language` or options
115
+ * Map locale name from i18n config to a compatible `language` or options.
116
+ *
117
+ * @deprecated No longer needed - the default `multilingual` tokenizer supports every language with zero config.
118
+ * When specified, a separate database is created for each locale (legacy behaviour).
97
119
  */
98
120
  localeMap?: Record<string, Language | Partial<O> | undefined>;
99
121
  indexes: WithLocale<Idx>[] | Dynamic<WithLocale<Idx>>;
@@ -103,16 +125,19 @@ type I18nAdvancedOptions = I18nOptions<AdvancedOptions, AdvancedIndex>;
103
125
  type WithLocale<T> = T & {
104
126
  locale: string;
105
127
  };
106
- declare function createI18nSearchAPI(type: 'simple', options: I18nSimpleOptions): SearchAPI<OramaQueryOptions>;
107
- declare function createI18nSearchAPI(type: 'advanced', options: I18nAdvancedOptions): SearchAPI<OramaQueryOptions>;
128
+ declare function createI18nSearchAPI(type: 'simple', options: I18nSimpleOptions): SearchAPI<EngineQueryOptions>;
129
+ declare function createI18nSearchAPI(type: 'advanced', options: I18nAdvancedOptions): SearchAPI<EngineQueryOptions>;
108
130
  interface Options<C extends LoaderConfig> extends Omit<AdvancedOptions, 'indexes'> {
131
+ /**
132
+ * @deprecated No longer needed - the default `multilingual` tokenizer supports every language with zero config.
133
+ */
109
134
  localeMap?: { [K in C['i18n'] extends I18nConfig<infer Languages> ? Languages : string]?: Partial<AdvancedOptions> | Language; };
110
135
  buildIndex?: (page: C['page']) => Awaitable<AdvancedIndex>;
111
136
  }
112
137
  /**
113
138
  * create server from loader, if passed as function, the server will re-index all records once a different instance of loader is returned.
114
139
  */
115
- declare function createFromSource<C extends LoaderConfig = LoaderConfig>(loader: LoaderOutput<C> | (() => Awaitable<LoaderOutput<C>>), options?: Options<C>): SearchAPI<OramaQueryOptions>;
140
+ declare function createFromSource<C extends LoaderConfig = LoaderConfig>(loader: LoaderOutput<C> | (() => Awaitable<LoaderOutput<C>>), options?: Options<C>): SearchAPI<EngineQueryOptions>;
116
141
  //#endregion
117
142
  //#region src/search/server/types.d.ts
118
143
  interface QueryOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "16.12.1",
3
+ "version": "16.14.0",
4
4
  "description": "The React.js library for building a documentation website",
5
5
  "keywords": [
6
6
  "Docs",
@@ -103,14 +103,13 @@
103
103
  "access": "public"
104
104
  },
105
105
  "dependencies": {
106
- "@orama/orama": "^3.1.18",
107
106
  "estree-util-value-to-estree": "^3.5.0",
108
107
  "github-slugger": "^2.0.0",
109
108
  "hast-util-to-estree": "^3.1.3",
110
109
  "hast-util-to-jsx-runtime": "^2.3.6",
111
110
  "mdast-util-mdx": "^3.0.0",
112
111
  "mdast-util-to-markdown": "^2.1.2",
113
- "npm-to-yarn": "3.1.0",
112
+ "npm-to-yarn": "3.2.0",
114
113
  "remark": "^15.0.1",
115
114
  "remark-gfm": "^4.0.1",
116
115
  "remark-rehype": "^11.1.2",
@@ -120,7 +119,8 @@
120
119
  "unified": "^11.0.5",
121
120
  "unist-util-visit": "^5.1.0",
122
121
  "vfile": "^6.0.3",
123
- "yaml": "^2.9.0"
122
+ "yaml": "^2.9.0",
123
+ "zbsearch": "^3.3.4"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@formatjs/intl-localematcher": "^0.8.13",
@@ -134,23 +134,23 @@
134
134
  "@types/hast": "^3.0.5",
135
135
  "@types/mdast": "^4.0.4",
136
136
  "@types/negotiator": "^0.6.4",
137
- "@types/node": "26.1.1",
137
+ "@types/node": "26.1.2",
138
138
  "@types/react": "^19.2.17",
139
139
  "@types/react-dom": "^19.2.3",
140
140
  "algoliasearch": "5.56.0",
141
141
  "flexsearch": "^0.8.212",
142
142
  "image-size": "^2.0.2",
143
- "lucide-react": "^1.25.0",
143
+ "lucide-react": "^1.27.0",
144
144
  "negotiator": "^1.0.0",
145
- "next": "16.2.11",
145
+ "next": "16.2.12",
146
146
  "path-to-regexp": "^8.4.2",
147
147
  "react-router": "^8.3.0",
148
148
  "remark-directive": "^4.0.0",
149
149
  "remark-mdx": "^3.1.1",
150
150
  "remove-markdown": "^0.6.4",
151
- "tsdown": "0.22.13",
151
+ "tsdown": "0.22.14",
152
152
  "typescript": "^6.0.3",
153
- "waku": "1.0.0-beta.7",
153
+ "waku": "1.0.0-beta.8",
154
154
  "zod": "4.4.3",
155
155
  "tsconfig": "0.0.0"
156
156
  },