fumadocs-core 16.15.17 → 16.15.18

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.
@@ -0,0 +1,20 @@
1
+ import { n as SearchClient } from "../../client-BcR4jyFl.js";
2
+ import { Meilisearch } from "meilisearch";
3
+ //#region src/search/client/meilisearch.d.ts
4
+ export interface MeilisearchOptions {
5
+ /**
6
+ * Meilisearch client with a search API key
7
+ */
8
+ client: Meilisearch;
9
+ indexName: string;
10
+ /**
11
+ * Filter results with specific tag(s).
12
+ */
13
+ tag?: string | string[];
14
+ /**
15
+ * Filter results by locale.
16
+ */
17
+ locale?: string;
18
+ }
19
+ export declare function meilisearchClient(options: MeilisearchOptions): SearchClient;
20
+ //#endregion
@@ -0,0 +1,50 @@
1
+ import { createContentHighlighter } from "../index.js";
2
+ //#region src/search/client/meilisearch.ts
3
+ function meilisearchClient(options) {
4
+ const { client, indexName, tag, locale } = options;
5
+ return {
6
+ deps: [
7
+ client,
8
+ indexName,
9
+ tag,
10
+ locale
11
+ ],
12
+ async search(query) {
13
+ if (query.trim().length === 0) return [];
14
+ const filter = [];
15
+ if (locale) filter.push(`locale = ${JSON.stringify(locale)}`);
16
+ for (const item of typeof tag === "string" ? [tag] : tag ?? []) filter.push(`tag = ${JSON.stringify(item)}`);
17
+ const { hits } = await client.index(indexName).search(query, {
18
+ filter,
19
+ limit: 20
20
+ });
21
+ const highlighter = createContentHighlighter(query);
22
+ const groups = /* @__PURE__ */ new Map();
23
+ for (const hit of hits) {
24
+ let group = groups.get(hit.url);
25
+ if (!group) {
26
+ group = [{
27
+ id: hit.url,
28
+ type: "page",
29
+ content: highlighter.highlightMarkdown(hit.title),
30
+ breadcrumbs: hit.breadcrumbs,
31
+ url: hit.url
32
+ }];
33
+ groups.set(hit.url, group);
34
+ }
35
+ if (hit.type === "page") continue;
36
+ group.push({
37
+ id: hit.id.toString(),
38
+ type: hit.type,
39
+ content: highlighter.highlightMarkdown(hit.content),
40
+ url: hit.heading ? `${hit.url}#${hit.heading}` : hit.url
41
+ });
42
+ }
43
+ const results = [];
44
+ for (const group of groups.values()) results.push(...group);
45
+ return results;
46
+ }
47
+ };
48
+ }
49
+ //#endregion
50
+ export { meilisearchClient };
@@ -0,0 +1,50 @@
1
+ import { t as Awaitable } from "../types-D89QoQR-.js";
2
+ import { i as StructuredData } from "../remark-structure-CnHwvNZr.js";
3
+ import { S as LoaderOutput, b as LoaderConfig } from "../index-CBtz3H2e.js";
4
+ import { Meilisearch } from "meilisearch";
5
+ //#region src/search/meilisearch.d.ts
6
+ export interface DocumentRecord {
7
+ title: string;
8
+ description?: string;
9
+ breadcrumbs?: string[];
10
+ /**
11
+ * URL to the page
12
+ */
13
+ url: string;
14
+ structured: StructuredData;
15
+ /**
16
+ * Tag(s) to filter results
17
+ */
18
+ tag?: string | string[];
19
+ locale?: string;
20
+ }
21
+ /**
22
+ * Document in Meilisearch, for the title, headings and paragraphs of a page
23
+ */
24
+ export interface MeilisearchDocument extends Omit<DocumentRecord, 'description' | 'structured'> {
25
+ id: number;
26
+ type: 'page' | 'heading' | 'text';
27
+ /**
28
+ * ID of the heading it belongs to
29
+ */
30
+ heading?: string;
31
+ content: string;
32
+ }
33
+ /**
34
+ * Build the search documents of every page in a source.
35
+ */
36
+ export declare function toDocuments<C extends LoaderConfig>(source: LoaderOutput<C> | (() => Awaitable<LoaderOutput<C>>), options?: {
37
+ /** Tag to filter results by. */
38
+ tag?: (page: C['page']) => string | string[];
39
+ }): Promise<DocumentRecord[]>;
40
+ export interface SyncOptions {
41
+ indexName: string;
42
+ documents: DocumentRecord[];
43
+ }
44
+ /**
45
+ * Configure the index and replace its documents, existing documents stay searchable until the new ones are indexed.
46
+ *
47
+ * @param client - Meilisearch client with an admin API key
48
+ */
49
+ export declare function sync(client: Meilisearch, options: SyncOptions): Promise<void>;
50
+ //#endregion
@@ -0,0 +1,55 @@
1
+ import { n as buildDocuments, t as buildBreadcrumbs } from "../build-index-BD-VRKOW.js";
2
+ //#region src/search/meilisearch.ts
3
+ /**
4
+ * Build the search documents of every page in a source.
5
+ */
6
+ async function toDocuments(source, options = {}) {
7
+ const loader = typeof source === "function" ? await source() : source;
8
+ return buildDocuments(loader, (index, page) => ({
9
+ title: index.title,
10
+ description: index.description,
11
+ breadcrumbs: buildBreadcrumbs(loader, page),
12
+ url: index.url,
13
+ structured: index.structuredData,
14
+ tag: options.tag?.(page),
15
+ locale: page.locale
16
+ }));
17
+ }
18
+ /**
19
+ * Configure the index and replace its documents, existing documents stay searchable until the new ones are indexed.
20
+ *
21
+ * @param client - Meilisearch client with an admin API key
22
+ */
23
+ async function sync(client, options) {
24
+ const index = client.index(options.indexName);
25
+ const documents = [];
26
+ for (const { description, structured, ...page } of options.documents) {
27
+ const add = (type, content, heading) => documents.push({
28
+ ...page,
29
+ id: documents.length,
30
+ type,
31
+ content,
32
+ heading
33
+ });
34
+ add("page", page.title);
35
+ if (description && !structured.contents.some((item) => item.content === description)) add("text", description);
36
+ for (const heading of structured.headings) add("heading", heading.content, heading.id);
37
+ for (const item of structured.contents) add("text", item.content, item.heading);
38
+ }
39
+ await run(index.updateSettings({
40
+ searchableAttributes: ["content"],
41
+ filterableAttributes: [
42
+ "id",
43
+ "tag",
44
+ "locale"
45
+ ]
46
+ }));
47
+ await run(index.addDocuments(documents, { primaryKey: "id" }));
48
+ await run(index.deleteDocuments({ filter: `id >= ${documents.length}` }));
49
+ }
50
+ async function run(task) {
51
+ const { status, error } = await task.waitTask({ timeout: 0 });
52
+ if (status !== "succeeded") throw new Error(error ? error.message : `Meilisearch task ${status}`, { cause: error });
53
+ }
54
+ //#endregion
55
+ export { sync, toDocuments };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "16.15.17",
3
+ "version": "16.15.18",
4
4
  "description": "The React.js library for building a documentation website",
5
5
  "keywords": [
6
6
  "Docs",
@@ -75,11 +75,13 @@
75
75
  "./search/client/algolia": "./dist/search/client/algolia.js",
76
76
  "./search/client/fetch": "./dist/search/client/fetch.js",
77
77
  "./search/client/flexsearch-static": "./dist/search/client/flexsearch-static.js",
78
+ "./search/client/meilisearch": "./dist/search/client/meilisearch.js",
78
79
  "./search/client/mixedbread": "./dist/search/client/mixedbread.js",
79
80
  "./search/client/orama-cloud": "./dist/search/client/orama-cloud.js",
80
81
  "./search/client/orama-cloud-legacy": "./dist/search/client/orama-cloud-legacy.js",
81
82
  "./search/client/orama-static": "./dist/search/client/orama-static.js",
82
83
  "./search/flexsearch": "./dist/search/flexsearch.js",
84
+ "./search/meilisearch": "./dist/search/meilisearch.js",
83
85
  "./search/mixedbread": "./dist/search/mixedbread.js",
84
86
  "./search/orama-cloud": "./dist/search/orama-cloud.js",
85
87
  "./search/orama-cloud-legacy": "./dist/search/orama-cloud-legacy.js",
@@ -148,6 +150,7 @@
148
150
  "algoliasearch": "5.59.0",
149
151
  "flexsearch": "^0.8.212",
150
152
  "lucide-react": "^1.47.0",
153
+ "meilisearch": "0.62.0",
151
154
  "next": "16.3.5",
152
155
  "path-to-regexp": "^8.4.2",
153
156
  "react-router": "^8.4.0",
@@ -174,6 +177,7 @@
174
177
  "algoliasearch": "5.x.x",
175
178
  "flexsearch": "*",
176
179
  "lucide-react": "*",
180
+ "meilisearch": ">=0.50.0 <1.0.0",
177
181
  "next": "16.x.x",
178
182
  "react": "^19.2.0",
179
183
  "react-dom": "^19.2.0",
@@ -215,6 +219,9 @@
215
219
  "algoliasearch": {
216
220
  "optional": true
217
221
  },
222
+ "meilisearch": {
223
+ "optional": true
224
+ },
218
225
  "next": {
219
226
  "optional": true
220
227
  },