fumadocs-core 16.5.3 → 16.6.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 (61) hide show
  1. package/dist/{advanced-BH0syJ-M.js → advanced-ZOIuXvBJ.js} +9 -12
  2. package/dist/{algolia-C7Crg8-5.js → algolia-CfKKhsrI.js} +1 -1
  3. package/dist/breadcrumb.d.ts +1 -1
  4. package/dist/content/md.d.ts +30 -0
  5. package/dist/content/md.js +47 -0
  6. package/dist/content/mdx/preset-bundler.d.ts +2 -2
  7. package/dist/content/mdx/preset-bundler.js +1 -1
  8. package/dist/content/mdx/preset-runtime.d.ts +2 -2
  9. package/dist/content/mdx/preset-runtime.js +1 -1
  10. package/dist/create-endpoint-9PZc4Cmz.js +23 -0
  11. package/dist/{create-i18n-Cv3Cocbs.d.ts → create-i18n-DxSvCSv-.d.ts} +2 -2
  12. package/dist/highlight/config.d.ts +1 -1
  13. package/dist/highlight/core/client.d.ts +1 -1
  14. package/dist/highlight/core/index.d.ts +1 -1
  15. package/dist/highlight/index.d.ts +1 -1
  16. package/dist/mdx-plugins/index.d.ts +3 -3
  17. package/dist/mdx-plugins/index.js +2 -2
  18. package/dist/mdx-plugins/rehype-code.core.d.ts +2 -2
  19. package/dist/mdx-plugins/rehype-code.d.ts +1 -1
  20. package/dist/mdx-plugins/remark-feedback-block.d.ts +1 -1
  21. package/dist/mdx-plugins/remark-feedback-block.js +11 -3
  22. package/dist/mdx-plugins/remark-structure.d.ts +65 -20
  23. package/dist/mdx-plugins/remark-structure.js +96 -50
  24. package/dist/mixedbread-RiA_24CE.js +58 -0
  25. package/dist/{orama-cloud-ByznDyOk.js → orama-cloud-cgTJNLo0.js} +9 -13
  26. package/dist/{orama-cloud-legacy-BbgJnf5f.js → orama-cloud-legacy-Caf8mcU9.js} +5 -9
  27. package/dist/page-tree/index.d.ts +2 -2
  28. package/dist/{path-B77y3W0_.d.ts → path-CDjb5iUO.d.ts} +1 -1
  29. package/dist/{mixedbread-Bx9drx9S.js → remove-markdown-CnXcUR-e.js} +2 -51
  30. package/dist/search/client.d.ts +9 -4
  31. package/dist/search/client.js +6 -6
  32. package/dist/search/index.d.ts +7 -0
  33. package/dist/search/index.js +48 -20
  34. package/dist/search/mixedbread.d.ts +56 -0
  35. package/dist/search/mixedbread.js +79 -0
  36. package/dist/search/orama-cloud-legacy.d.ts +1 -1
  37. package/dist/search/orama-cloud.d.ts +1 -1
  38. package/dist/search/server.d.ts +4 -4
  39. package/dist/search/server.js +4 -24
  40. package/dist/source/client/index.d.ts +2 -2
  41. package/dist/source/index.d.ts +3 -3
  42. package/dist/source/index.js +2 -2
  43. package/dist/source/plugins/lucide-icons.d.ts +3 -3
  44. package/dist/source/plugins/lucide-icons.js +1 -1
  45. package/dist/source/plugins/slugs.d.ts +3 -3
  46. package/dist/source/plugins/slugs.js +1 -1
  47. package/dist/source/plugins/status-badges.d.ts +3 -3
  48. package/dist/{static-DTxK4eHk.js → static-BUXJwBmr.js} +1 -1
  49. package/dist/{utils-IgHyYnrz.d.ts → utils-5HX-8dF3.d.ts} +1 -1
  50. package/package.json +4 -4
  51. package/dist/content/index.d.ts +0 -22
  52. package/dist/content/index.js +0 -23
  53. /package/dist/{definitions-DSNTbAwC.d.ts → definitions-Cw2aM1Af.d.ts} +0 -0
  54. /package/dist/{fetch-HotVeLLF.js → fetch-D_OY-eAB.js} +0 -0
  55. /package/dist/{icon-BcFuYa-b.js → icon-CGDZIqYj.js} +0 -0
  56. /package/dist/{path-D0Bwm6Fs.js → path-CfJghBXy.js} +0 -0
  57. /package/dist/{remove-undefined-CJm9cyrC.js → remove-undefined-B_oBVupY.js} +0 -0
  58. /package/dist/{transformer-icon-D7-6aFzt.d.ts → transformer-icon-C8MUuI2T.d.ts} +0 -0
  59. /package/dist/{types-BSnJn7kF.d.ts → types-Bt4vrwsT.d.ts} +0 -0
  60. /package/dist/{util-C60LmklF.d.ts → util-C7X6g0ql.d.ts} +0 -0
  61. /package/dist/{util-De0ALHOx.js → util-bgCahl6-.js} +0 -0
@@ -1,8 +1,8 @@
1
- import { n as toMdxExport, t as flattenNode } from "../mdast-utils-gJMY143g.js";
1
+ import { n as toMdxExport } from "../mdast-utils-gJMY143g.js";
2
2
  import { remarkHeading } from "./remark-heading.js";
3
3
  import { remark } from "remark";
4
- import remarkGfm from "remark-gfm";
5
4
  import { visit } from "unist-util-visit";
5
+ import remarkGfm from "remark-gfm";
6
6
  import { toMarkdown } from "mdast-util-to-markdown";
7
7
 
8
8
  //#region src/mdx-plugins/remark-structure.ts
@@ -14,12 +14,8 @@ const remarkStructureDefaultOptions = {
14
14
  "tableCell",
15
15
  "mdxJsxFlowElement"
16
16
  ],
17
- allowedMdxAttributes(node) {
18
- switch (node.name) {
19
- case "TypeTable":
20
- case "Callout": return true;
21
- default: return false;
22
- }
17
+ mdxTypes(node) {
18
+ return node.children.length === 0;
23
19
  },
24
20
  exportAs: false
25
21
  };
@@ -28,16 +24,15 @@ const remarkStructureDefaultOptions = {
28
24
  *
29
25
  * By default, the output is stored into VFile (`vfile.data.structuredData`), you can specify `exportAs` to export it.
30
26
  */
31
- function remarkStructure({ types = remarkStructureDefaultOptions.types, stringify, allowedMdxAttributes = remarkStructureDefaultOptions.allowedMdxAttributes, exportAs = remarkStructureDefaultOptions.exportAs } = {}) {
32
- if (Array.isArray(allowedMdxAttributes)) {
33
- const arr = allowedMdxAttributes;
34
- allowedMdxAttributes = (_node, attribute) => attribute.type === "mdxJsxAttribute" && arr.includes(attribute.name);
35
- }
27
+ function remarkStructure({ types = remarkStructureDefaultOptions.types, mdxTypes = remarkStructureDefaultOptions.mdxTypes, stringify: stringifyOptions, allowedMdxAttributes, exportAs = remarkStructureDefaultOptions.exportAs } = {}) {
36
28
  if (Array.isArray(types)) {
37
29
  const arr = types;
38
30
  types = (node) => arr.includes(node.type);
39
31
  }
40
- stringify ??= defaultStringify({ filterMdxAttributes: allowedMdxAttributes });
32
+ const stringify = typeof stringifyOptions === "function" ? stringifyOptions : defaultStringifier({
33
+ filterMdxAttributes: Array.isArray(allowedMdxAttributes) ? (_node, attribute) => attribute.type === "mdxJsxAttribute" && allowedMdxAttributes.includes(attribute.name) : allowedMdxAttributes,
34
+ ...stringifyOptions
35
+ });
41
36
  return (tree, file) => {
42
37
  const data = {
43
38
  contents: [],
@@ -51,31 +46,38 @@ function remarkStructure({ types = remarkStructureDefaultOptions.types, stringif
51
46
  data.contents.push(...frontmatter._openapi.structuredData.contents);
52
47
  }
53
48
  }
49
+ const stringifierCtx = { addContent(...content) {
50
+ for (const item of content) data.contents.push({
51
+ ...item,
52
+ heading: item.heading ?? lastHeading
53
+ });
54
+ } };
54
55
  visit(tree, (element) => {
55
- if (element.type === "root" || !types(element)) return;
56
- if (element.type === "heading") {
57
- element.data ||= {};
58
- element.data.hProperties ||= {};
59
- const id = element.data.hProperties.id;
60
- if (typeof id !== "string") {
61
- console.warn("[remark-structure] hProperties.id is missing in heading node, it is required to generate heading data. You can add remark-heading prior to remark-structure to generate heading IDs.");
56
+ if (!types(element)) return;
57
+ switch (element.type) {
58
+ case "root": return;
59
+ case "mdxJsxFlowElement":
60
+ case "mdxJsxTextElement":
61
+ if (!mdxTypes(element)) return;
62
+ break;
63
+ case "heading": {
64
+ element.data ||= {};
65
+ element.data.hProperties ||= {};
66
+ const id = element.data.hProperties.id;
67
+ if (typeof id !== "string") {
68
+ console.warn("[remark-structure] hProperties.id is missing in heading node, it is required to generate heading data. You can add remark-heading prior to remark-structure to generate heading IDs.");
69
+ return "skip";
70
+ }
71
+ const content = stringify.call(this, element, stringifierCtx).trim();
72
+ if (content.length > 0) data.headings.push({
73
+ id,
74
+ content
75
+ });
76
+ lastHeading = id;
62
77
  return "skip";
63
78
  }
64
- data.headings.push({
65
- id,
66
- content: flattenNode(element).trim()
67
- });
68
- lastHeading = id;
69
- return "skip";
70
- }
71
- if (element.data?._string) {
72
- for (const content of element.data._string) data.contents.push({
73
- heading: lastHeading,
74
- content
75
- });
76
- return "skip";
77
79
  }
78
- const content = stringify.call(this, element).trim();
80
+ const content = stringify.call(this, element, stringifierCtx).trim();
79
81
  if (content.length > 0) data.contents.push({
80
82
  heading: lastHeading,
81
83
  content
@@ -92,37 +94,81 @@ function remarkStructure({ types = remarkStructureDefaultOptions.types, stringif
92
94
  function structure(content, remarkPlugins = [], options = {}) {
93
95
  return remark().use(remarkGfm).use(remarkPlugins).use(remarkHeading).use(remarkStructure, options).processSync(content).data.structuredData;
94
96
  }
95
- function defaultStringify(config = {}) {
96
- const { filterMdxAttributes } = config;
97
- function modHandler(handler) {
98
- return function(node, ...rest) {
99
- if (node.data?._string) return node.data._string.join("\n");
97
+ function defaultStringifier(config = {}) {
98
+ const { filterMdxAttributes, filterElement = (node) => {
99
+ switch (node.type) {
100
+ case "mdxJsxFlowElement":
101
+ case "mdxJsxTextElement":
102
+ switch (node.name) {
103
+ case "File":
104
+ case "TypeTable":
105
+ case "Callout":
106
+ case "Card": return true;
107
+ }
108
+ return "children-only";
109
+ }
110
+ return true;
111
+ } } = config;
112
+ function modHandler(handler, ctx) {
113
+ return function(node, parent, state, info) {
114
+ const { structuredData, _string } = node.data ?? {};
115
+ if (structuredData) ctx.addContent(...structuredData.contents);
116
+ if (_string) return typeof _string === "function" ? _string() : _string;
117
+ const visibility = filterElement(node);
118
+ if (visibility === false) return "";
100
119
  switch (node.type) {
101
120
  case "mdxJsxFlowElement":
102
- case "mdxJsxTextElement": if (filterMdxAttributes) {
121
+ case "mdxJsxTextElement": {
122
+ if (visibility === "children-only") return node.type === "mdxJsxTextElement" ? state.containerPhrasing(node, info) : state.containerFlow(node, info);
123
+ const stringifiedAttributes = [];
124
+ for (const attr of node.attributes) {
125
+ if (attr.type === "mdxJsxExpressionAttribute") continue;
126
+ if (filterMdxAttributes && !filterMdxAttributes(node, attr)) continue;
127
+ const str = typeof attr.value === "string" ? attr.value : attr.value?.value;
128
+ if (!str) continue;
129
+ stringifiedAttributes.push({
130
+ ...attr,
131
+ value: str
132
+ });
133
+ }
103
134
  const temp = node.attributes;
104
- node.attributes = node.attributes.filter((attr) => filterMdxAttributes(node, attr));
105
- const s = handler(node, ...rest);
135
+ node.attributes = stringifiedAttributes;
136
+ const s = handler(node, parent, state, info);
106
137
  node.attributes = temp;
107
138
  return s;
108
139
  }
109
- default: return handler(node, ...rest);
140
+ default:
141
+ if (visibility === "children-only") return "children" in node ? state.containerFlow({
142
+ type: "root",
143
+ children: node.children
144
+ }, info) : "";
145
+ return handler(node, parent, state, info);
110
146
  }
111
147
  };
112
148
  }
113
149
  const handlers = {
114
- ...config.handlers,
150
+ link(node, _, state, info) {
151
+ return state.containerPhrasing(node, info);
152
+ },
153
+ heading(node, _, state, info) {
154
+ return state.containerPhrasing(node, info);
155
+ },
156
+ image() {
157
+ return "";
158
+ },
115
159
  _custom(node, _, state, info) {
116
160
  const handlers = state.handlers;
117
- for (const k in handlers) handlers[k] = modHandler(handlers[k]);
161
+ for (const k in handlers) handlers[k] = modHandler(handlers[k], node.ctx);
118
162
  return state.handle(node.root, void 0, state, info);
119
- }
163
+ },
164
+ ...config.handlers
120
165
  };
121
- return function(root) {
166
+ return function(root, ctx) {
122
167
  const defaultExtensions = this.data("toMarkdownExtensions") ?? [];
123
168
  return toMarkdown({
124
169
  type: "_custom",
125
- root
170
+ root,
171
+ ctx
126
172
  }, {
127
173
  ...this.data("settings"),
128
174
  ...config,
@@ -133,4 +179,4 @@ function defaultStringify(config = {}) {
133
179
  }
134
180
 
135
181
  //#endregion
136
- export { defaultStringify, remarkStructure, remarkStructureDefaultOptions, structure };
182
+ export { defaultStringifier, remarkStructure, remarkStructureDefaultOptions, structure };
@@ -0,0 +1,58 @@
1
+ import { r as __toESM } from "./chunk-CaR5F9JI.js";
2
+ import { t as require_remove_markdown } from "./remove-markdown-CnXcUR-e.js";
3
+ import Slugger from "github-slugger";
4
+
5
+ //#region src/search/client/mixedbread.ts
6
+ var import_remove_markdown = /* @__PURE__ */ __toESM(require_remove_markdown(), 1);
7
+ const slugger = new Slugger();
8
+ function extractHeadingTitle(text) {
9
+ const trimmedText = text.trim();
10
+ if (!trimmedText.startsWith("#")) return "";
11
+ const firstLine = trimmedText.split("\n")[0]?.trim();
12
+ if (firstLine) return (0, import_remove_markdown.default)(firstLine, { useImgAltText: false });
13
+ return "";
14
+ }
15
+ /**
16
+ * @deprecated Use `createMixedbreadSearchAPI` from `fumadocs-core/search/mixedbread` instead.
17
+ * This client-side approach exposes your API key in the browser.
18
+ * The server-side approach keeps the key secure and uses `type: 'fetch'` on the client.
19
+ */
20
+ async function search(query, options) {
21
+ const { client, storeIdentifier, tag } = options;
22
+ if (!query.trim()) return [];
23
+ return (await client.stores.search({
24
+ query,
25
+ store_identifiers: [storeIdentifier],
26
+ top_k: 10,
27
+ filters: {
28
+ key: "generated_metadata.tag",
29
+ operator: "eq",
30
+ value: tag
31
+ },
32
+ search_options: { return_metadata: true }
33
+ })).data.flatMap((item) => {
34
+ const metadata = item.generated_metadata;
35
+ const url = metadata.url || "#";
36
+ const title = metadata.title || "Untitled";
37
+ const chunkResults = [{
38
+ id: `${item.file_id}-${item.chunk_index}-page`,
39
+ type: "page",
40
+ content: title,
41
+ url
42
+ }];
43
+ const headingTitle = item.type === "text" ? extractHeadingTitle(item.text) : "";
44
+ if (headingTitle) {
45
+ slugger.reset();
46
+ chunkResults.push({
47
+ id: `${item.file_id}-${item.chunk_index}-heading`,
48
+ type: "heading",
49
+ content: headingTitle,
50
+ url: `${url}#${slugger.slug(headingTitle)}`
51
+ });
52
+ }
53
+ return chunkResults;
54
+ });
55
+ }
56
+
57
+ //#endregion
58
+ export { search };
@@ -1,5 +1,5 @@
1
1
  import { createContentHighlighter } from "./search/index.js";
2
- import { t as removeUndefined } from "./remove-undefined-CJm9cyrC.js";
2
+ import { t as removeUndefined } from "./remove-undefined-B_oBVupY.js";
3
3
 
4
4
  //#region src/search/client/orama-cloud.ts
5
5
  async function searchDocs(query, options) {
@@ -23,23 +23,22 @@ async function searchDocs(query, options) {
23
23
  list.push({
24
24
  id: hit.id,
25
25
  type: "page",
26
- content: doc.title,
27
- contentWithHighlights: highlighter.highlight(doc.title),
26
+ content: highlighter.highlightMarkdown(doc.title),
28
27
  url: doc.path
29
28
  }, {
30
29
  id: "page" + hit.id,
31
30
  type: "text",
32
- content: doc.content,
33
- contentWithHighlights: highlighter.highlight(doc.content),
31
+ content: highlighter.highlightMarkdown(doc.content),
34
32
  url: doc.path
35
33
  });
36
34
  }
37
35
  return list;
38
36
  }
39
- const params = {
37
+ const result = await client.search({
40
38
  datasources: [],
41
39
  ...extraParams,
42
40
  term: query,
41
+ limit: 10,
43
42
  where: removeUndefined({
44
43
  tag,
45
44
  ...extraParams?.where
@@ -49,8 +48,7 @@ async function searchDocs(query, options) {
49
48
  max_results: 7,
50
49
  ...extraParams?.groupBy
51
50
  }
52
- };
53
- const result = await client.search(params);
51
+ });
54
52
  if (!result || !result.groups) return list;
55
53
  for (const item of result.groups) {
56
54
  let addedHead = false;
@@ -60,23 +58,21 @@ async function searchDocs(query, options) {
60
58
  list.push({
61
59
  id: doc.page_id,
62
60
  type: "page",
63
- content: doc.title,
61
+ content: highlighter.highlightMarkdown(doc.title),
64
62
  breadcrumbs: doc.breadcrumbs,
65
- contentWithHighlights: highlighter.highlight(doc.title),
66
63
  url: doc.url
67
64
  });
68
65
  addedHead = true;
69
66
  }
70
67
  list.push({
71
68
  id: doc.id,
72
- content: doc.content,
73
- contentWithHighlights: highlighter.highlight(doc.content),
69
+ content: highlighter.highlightMarkdown(doc.content),
74
70
  type: doc.content === doc.section ? "heading" : "text",
75
71
  url: doc.section_id ? `${doc.url}#${doc.section_id}` : doc.url
76
72
  });
77
73
  }
78
74
  }
79
- return list;
75
+ return list.length > 80 ? list.slice(0, 80) : list;
80
76
  }
81
77
 
82
78
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { createContentHighlighter } from "./search/index.js";
2
- import { t as removeUndefined } from "./remove-undefined-CJm9cyrC.js";
2
+ import { t as removeUndefined } from "./remove-undefined-B_oBVupY.js";
3
3
 
4
4
  //#region src/search/client/orama-cloud-legacy.ts
5
5
  async function searchDocs(query, options) {
@@ -22,14 +22,12 @@ async function searchDocs(query, options) {
22
22
  list.push({
23
23
  id: hit.id,
24
24
  type: "page",
25
- content: doc.title,
26
- contentWithHighlights: highlighter.highlight(doc.title),
25
+ content: highlighter.highlightMarkdown(doc.title),
27
26
  url: doc.path
28
27
  }, {
29
28
  id: "page" + hit.id,
30
29
  type: "text",
31
- content: doc.content,
32
- contentWithHighlights: highlighter.highlight(doc.content),
30
+ content: highlighter.highlightMarkdown(doc.content),
33
31
  url: doc.path
34
32
  });
35
33
  }
@@ -58,17 +56,15 @@ async function searchDocs(query, options) {
58
56
  list.push({
59
57
  id: doc.page_id,
60
58
  type: "page",
61
- content: doc.title,
59
+ content: highlighter.highlightMarkdown(doc.title),
62
60
  breadcrumbs: doc.breadcrumbs,
63
- contentWithHighlights: highlighter.highlight(doc.title),
64
61
  url: doc.url
65
62
  });
66
63
  addedHead = true;
67
64
  }
68
65
  list.push({
69
66
  id: doc.id,
70
- content: doc.content,
71
- contentWithHighlights: highlighter.highlight(doc.content),
67
+ content: highlighter.highlightMarkdown(doc.content),
72
68
  type: doc.content === doc.section ? "heading" : "text",
73
69
  url: doc.section_id ? `${doc.url}#${doc.section_id}` : doc.url
74
70
  });
@@ -1,3 +1,3 @@
1
- import { a as Separator, i as Root, n as Item, r as Node, t as Folder } from "../definitions-DSNTbAwC.js";
2
- import { a as flattenTree, c as visit, i as findSiblings, n as findParent, o as getPageTreePeers, r as findPath, s as getPageTreeRoots, t as findNeighbour } from "../utils-IgHyYnrz.js";
1
+ import { a as Separator, i as Root, n as Item, r as Node, t as Folder } from "../definitions-Cw2aM1Af.js";
2
+ import { a as flattenTree, c as visit, i as findSiblings, n as findParent, o as getPageTreePeers, r as findPath, s as getPageTreeRoots, t as findNeighbour } from "../utils-5HX-8dF3.js";
3
3
  export { Folder, Item, Node, Root, Separator, findNeighbour, findParent, findPath, findSiblings, flattenTree, getPageTreePeers, getPageTreeRoots, visit };
@@ -1,4 +1,4 @@
1
- import { a as Separator, i as Root, n as Item, r as Node, t as Folder } from "./definitions-DSNTbAwC.js";
1
+ import { a as Separator, i as Root, n as Item, r as Node, t as Folder } from "./definitions-Cw2aM1Af.js";
2
2
  import { I18nConfig } from "./i18n/index.js";
3
3
  import { SlugFn } from "./source/plugins/slugs.js";
4
4
  import { SerializedPageTree } from "./source/client/index.js";
@@ -1,5 +1,4 @@
1
- import { r as __toESM, t as __commonJSMin } from "./chunk-CaR5F9JI.js";
2
- import Slugger from "github-slugger";
1
+ import { t as __commonJSMin } from "./chunk-CaR5F9JI.js";
3
2
 
4
3
  //#region ../../node_modules/.pnpm/remove-markdown@0.6.3/node_modules/remove-markdown/index.js
5
4
  var require_remove_markdown = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -38,52 +37,4 @@ var require_remove_markdown = /* @__PURE__ */ __commonJSMin(((exports, module) =
38
37
  }));
39
38
 
40
39
  //#endregion
41
- //#region src/search/client/mixedbread.ts
42
- var import_remove_markdown = /* @__PURE__ */ __toESM(require_remove_markdown(), 1);
43
- const slugger = new Slugger();
44
- function extractHeadingTitle(text) {
45
- const trimmedText = text.trim();
46
- if (!trimmedText.startsWith("#")) return "";
47
- const firstLine = trimmedText.split("\n")[0]?.trim();
48
- if (firstLine) return (0, import_remove_markdown.default)(firstLine, { useImgAltText: false });
49
- return "";
50
- }
51
- async function search(query, options) {
52
- const { client, storeIdentifier, tag } = options;
53
- if (!query.trim()) return [];
54
- return (await client.stores.search({
55
- query,
56
- store_identifiers: [storeIdentifier],
57
- top_k: 10,
58
- filters: {
59
- key: "generated_metadata.tag",
60
- operator: "eq",
61
- value: tag
62
- },
63
- search_options: { return_metadata: true }
64
- })).data.flatMap((item) => {
65
- const metadata = item.generated_metadata;
66
- const url = metadata.url || "#";
67
- const title = metadata.title || "Untitled";
68
- const chunkResults = [{
69
- id: `${item.file_id}-${item.chunk_index}-page`,
70
- type: "page",
71
- content: title,
72
- url
73
- }];
74
- const headingTitle = item.type === "text" ? extractHeadingTitle(item.text) : "";
75
- if (headingTitle) {
76
- slugger.reset();
77
- chunkResults.push({
78
- id: `${item.file_id}-${item.chunk_index}-heading`,
79
- type: "heading",
80
- content: headingTitle,
81
- url: `${url}#${slugger.slug(headingTitle)}`
82
- });
83
- }
84
- return chunkResults;
85
- });
86
- }
87
-
88
- //#endregion
89
- export { search };
40
+ export { require_remove_markdown as t };
@@ -1,9 +1,9 @@
1
- import "../definitions-DSNTbAwC.js";
2
- import "../utils-IgHyYnrz.js";
1
+ import "../definitions-Cw2aM1Af.js";
2
+ import "../utils-5HX-8dF3.js";
3
3
  import { BaseIndex } from "./algolia.js";
4
4
  import { SortedResult } from "./index.js";
5
- import "../create-i18n-Cv3Cocbs.js";
6
- import "../path-B77y3W0_.js";
5
+ import "../create-i18n-DxSvCSv-.js";
6
+ import "../path-CDjb5iUO.js";
7
7
  import "./server.js";
8
8
  import { DependencyList } from "react";
9
9
  import { AnyOrama } from "@orama/orama";
@@ -104,6 +104,11 @@ interface OramaCloudLegacyOptions {
104
104
  }
105
105
  //#endregion
106
106
  //#region src/search/client/mixedbread.d.ts
107
+ /**
108
+ * @deprecated Use `createMixedbreadSearchAPI` from `fumadocs-core/search/mixedbread` instead.
109
+ * This client-side approach exposes your API key in the browser.
110
+ * The server-side approach keeps the key secure and uses `type: 'fetch'` on the client.
111
+ */
107
112
  interface MixedbreadOptions {
108
113
  /**
109
114
  * The identifier of the store to search in
@@ -54,27 +54,27 @@ function useDocsSearch(clientOptions, deps) {
54
54
  if (debouncedValue.length === 0 && !allowEmpty) return "empty";
55
55
  switch (client.type) {
56
56
  case "fetch": {
57
- const { fetchDocs } = await import("../fetch-HotVeLLF.js");
57
+ const { fetchDocs } = await import("../fetch-D_OY-eAB.js");
58
58
  return fetchDocs(debouncedValue, client);
59
59
  }
60
60
  case "algolia": {
61
- const { searchDocs } = await import("../algolia-C7Crg8-5.js");
61
+ const { searchDocs } = await import("../algolia-CfKKhsrI.js");
62
62
  return searchDocs(debouncedValue, client);
63
63
  }
64
64
  case "orama-cloud": {
65
- const { searchDocs } = await import("../orama-cloud-ByznDyOk.js");
65
+ const { searchDocs } = await import("../orama-cloud-cgTJNLo0.js");
66
66
  return searchDocs(debouncedValue, client);
67
67
  }
68
68
  case "orama-cloud-legacy": {
69
- const { searchDocs } = await import("../orama-cloud-legacy-BbgJnf5f.js");
69
+ const { searchDocs } = await import("../orama-cloud-legacy-Caf8mcU9.js");
70
70
  return searchDocs(debouncedValue, client);
71
71
  }
72
72
  case "mixedbread": {
73
- const { search } = await import("../mixedbread-Bx9drx9S.js");
73
+ const { search } = await import("../mixedbread-RiA_24CE.js");
74
74
  return search(debouncedValue, client);
75
75
  }
76
76
  case "static": {
77
- const { search } = await import("../static-DTxK4eHk.js");
77
+ const { search } = await import("../static-BUXJwBmr.js");
78
78
  return search(debouncedValue, client);
79
79
  }
80
80
  default: throw new Error("unknown search client");
@@ -10,6 +10,9 @@ interface SortedResult<Content = string> {
10
10
  * breadcrumbs to be displayed on UI
11
11
  */
12
12
  breadcrumbs?: Content[];
13
+ /**
14
+ * @deprecated it is now included in `content` as Markdown using `<mark />`.
15
+ */
13
16
  contentWithHighlights?: HighlightedText<Content>[];
14
17
  }
15
18
  type ReactSortedResult = SortedResult<ReactNode>;
@@ -22,6 +25,10 @@ interface HighlightedText<Content = string> {
22
25
  }
23
26
  declare function createContentHighlighter(query: string | RegExp): {
24
27
  highlight(content: string): HighlightedText[];
28
+ /**
29
+ * @param content - Markdown, it assumes the content is already sanitized & safe, no escape is performed.
30
+ */
31
+ highlightMarkdown(content: string): string;
25
32
  };
26
33
  //#endregion
27
34
  export { HighlightedText, ReactSortedResult, SortedResult, createContentHighlighter };
@@ -1,3 +1,6 @@
1
+ import { remark } from "remark";
2
+ import { visit } from "unist-util-visit";
3
+
1
4
  //#region src/search/index.ts
2
5
  function escapeRegExp(input) {
3
6
  return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -11,32 +14,57 @@ function buildRegexFromQuery(q) {
11
14
  return new RegExp(`(${escaped})`, "gi");
12
15
  }
13
16
  function createContentHighlighter(query) {
17
+ let processor = remark();
14
18
  const regex = typeof query === "string" ? buildRegexFromQuery(query) : query;
15
- return { highlight(content) {
16
- if (!regex) return [{
17
- type: "text",
18
- content
19
- }];
20
- const out = [];
21
- let i = 0;
22
- for (const match of content.matchAll(regex)) {
23
- if (i < match.index) out.push({
19
+ if (regex) processor = processor.use(remarkHighlight, regex);
20
+ return {
21
+ highlight(content) {
22
+ if (!regex) return [{
24
23
  type: "text",
25
- content: content.substring(i, match.index)
26
- });
27
- out.push({
24
+ content
25
+ }];
26
+ const out = [];
27
+ let i = 0;
28
+ for (const match of content.matchAll(regex)) {
29
+ if (i < match.index) out.push({
30
+ type: "text",
31
+ content: content.substring(i, match.index)
32
+ });
33
+ out.push({
34
+ type: "text",
35
+ content: match[0],
36
+ styles: { highlight: true }
37
+ });
38
+ i = match.index + match[0].length;
39
+ }
40
+ if (i < content.length) out.push({
28
41
  type: "text",
29
- content: match[0],
30
- styles: { highlight: true }
42
+ content: content.substring(i)
31
43
  });
32
- i = match.index + match[0].length;
44
+ return out;
45
+ },
46
+ highlightMarkdown(content) {
47
+ if (!regex) return content;
48
+ return String(processor.processSync(content).value);
33
49
  }
34
- if (i < content.length) out.push({
35
- type: "text",
36
- content: content.substring(i)
50
+ };
51
+ }
52
+ function remarkHighlight(regex) {
53
+ return (tree) => {
54
+ visit(tree, "text", (node) => {
55
+ let out = "";
56
+ const content = node.value;
57
+ let i = 0;
58
+ for (const match of content.matchAll(regex)) {
59
+ if (i < match.index) out += content.substring(i, match.index);
60
+ out += `<mark>${match[0]}</mark>`;
61
+ i = match.index + match[0].length;
62
+ }
63
+ if (i < content.length) out += content.substring(i);
64
+ node.type = "html";
65
+ node.value = out;
37
66
  });
38
- return out;
39
- } };
67
+ };
40
68
  }
41
69
 
42
70
  //#endregion