fumadocs-core 15.2.8 → 16.0.3

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 (92) hide show
  1. package/README.md +1 -1
  2. package/dist/algolia-IZEDLPHE.js +58 -0
  3. package/dist/breadcrumb.d.ts +7 -5
  4. package/dist/breadcrumb.js +46 -52
  5. package/dist/builder-feW_xVjc.d.ts +296 -0
  6. package/dist/{chunk-FVY6EZ3N.js → chunk-BBP7MIO4.js} +12 -14
  7. package/dist/{chunk-ORHEEQVY.js → chunk-EMWGTXSW.js} +0 -7
  8. package/dist/chunk-FAEPKD7U.js +20 -0
  9. package/dist/{chunk-NNKVN7WA.js → chunk-H2GMUTQG.js} +4 -2
  10. package/dist/chunk-IZPLHEX4.js +113 -0
  11. package/dist/chunk-OTD7MV33.js +53 -0
  12. package/dist/chunk-PFNP6PEB.js +11 -0
  13. package/dist/{chunk-Y2774T3B.js → chunk-QMATWJ5F.js} +6 -7
  14. package/dist/chunk-U67V476Y.js +35 -0
  15. package/dist/{chunk-BUCUQ3WX.js → chunk-XN2LKXFZ.js} +39 -34
  16. package/dist/{chunk-WFUH5VBX.js → chunk-XOFXGHS4.js} +26 -10
  17. package/dist/chunk-XZSI7AHE.js +67 -0
  18. package/dist/chunk-YVVDKJ2H.js +34 -0
  19. package/dist/chunk-ZMWYLUDP.js +21 -0
  20. package/dist/content/github.d.ts +34 -0
  21. package/dist/content/github.js +43 -0
  22. package/dist/content/index.d.ts +16 -0
  23. package/dist/content/index.js +30 -0
  24. package/dist/{get-toc-Cr2URuiP.d.ts → content/toc.d.ts} +6 -10
  25. package/dist/content/toc.js +21 -0
  26. package/dist/{page-tree-BG3wP0gU.d.ts → definitions-BRsJlZ6m.d.ts} +10 -15
  27. package/dist/dynamic-link.js +3 -3
  28. package/dist/fetch-2XFMBLBA.js +22 -0
  29. package/dist/framework/index.d.ts +1 -1
  30. package/dist/framework/index.js +2 -2
  31. package/dist/framework/next.js +2 -2
  32. package/dist/framework/react-router.js +2 -2
  33. package/dist/framework/tanstack.js +2 -2
  34. package/dist/framework/waku.d.ts +8 -0
  35. package/dist/framework/waku.js +51 -0
  36. package/dist/hide-if-empty.d.ts +18 -0
  37. package/dist/hide-if-empty.js +83 -0
  38. package/dist/highlight/client.d.ts +8 -5
  39. package/dist/highlight/client.js +9 -93
  40. package/dist/highlight/index.d.ts +20 -5
  41. package/dist/highlight/index.js +10 -6
  42. package/dist/i18n/index.d.ts +35 -8
  43. package/dist/i18n/index.js +5 -69
  44. package/dist/i18n/middleware.d.ts +12 -0
  45. package/dist/i18n/middleware.js +63 -0
  46. package/dist/link.js +3 -3
  47. package/dist/mdx-plugins/index.d.ts +124 -18
  48. package/dist/mdx-plugins/index.js +605 -203
  49. package/dist/mixedbread-RAHDVXGJ.js +118 -0
  50. package/dist/negotiation/index.d.ts +19 -0
  51. package/dist/negotiation/index.js +11 -0
  52. package/dist/{orama-cloud-USLSOSXS.js → orama-cloud-WEGQE5A6.js} +37 -27
  53. package/dist/page-tree/index.d.ts +32 -0
  54. package/dist/page-tree/index.js +15 -0
  55. package/dist/remark-code-tab-DmyIyi6m.d.ts +57 -0
  56. package/dist/{remark-structure-FIjTA11P.d.ts → remark-structure-DkCXCzpD.d.ts} +13 -2
  57. package/dist/search/algolia.d.ts +9 -7
  58. package/dist/search/algolia.js +31 -17
  59. package/dist/search/client.d.ts +88 -17
  60. package/dist/search/client.js +71 -50
  61. package/dist/search/index.d.ts +26 -0
  62. package/dist/search/index.js +7 -0
  63. package/dist/search/orama-cloud.d.ts +7 -5
  64. package/dist/search/orama-cloud.js +18 -10
  65. package/dist/search/server.d.ts +33 -25
  66. package/dist/search/server.js +109 -47
  67. package/dist/source/index.d.ts +33 -254
  68. package/dist/source/index.js +532 -353
  69. package/dist/source/plugins/lucide-icons.d.ts +14 -0
  70. package/dist/source/plugins/lucide-icons.js +23 -0
  71. package/dist/static-A2YJ5TXV.js +62 -0
  72. package/dist/toc.d.ts +11 -7
  73. package/dist/toc.js +6 -5
  74. package/dist/utils/use-effect-event.d.ts +4 -3
  75. package/dist/utils/use-effect-event.js +9 -6
  76. package/dist/utils/use-media-query.d.ts +3 -0
  77. package/dist/utils/use-media-query.js +23 -0
  78. package/dist/utils/use-on-change.js +2 -2
  79. package/package.json +92 -40
  80. package/dist/algolia-NTWLS6J3.js +0 -49
  81. package/dist/chunk-KAOEMCTI.js +0 -17
  82. package/dist/chunk-MLKGABMK.js +0 -9
  83. package/dist/chunk-XMCPKVJQ.js +0 -34
  84. package/dist/config-inq6kP6y.d.ts +0 -26
  85. package/dist/fetch-W5EHIBOE.js +0 -21
  86. package/dist/remark-heading-BPCoYwjn.d.ts +0 -31
  87. package/dist/server/index.d.ts +0 -117
  88. package/dist/server/index.js +0 -202
  89. package/dist/sidebar.d.ts +0 -33
  90. package/dist/sidebar.js +0 -89
  91. package/dist/static-VESU2S64.js +0 -61
  92. package/dist/types-Ch8gnVgO.d.ts +0 -8
@@ -1,75 +1,96 @@
1
1
  import {
2
2
  useOnChange
3
- } from "../chunk-ORHEEQVY.js";
4
- import "../chunk-MLKGABMK.js";
3
+ } from "../chunk-EMWGTXSW.js";
4
+ import "../chunk-U67V476Y.js";
5
5
 
6
6
  // src/search/client.ts
7
- import { useRef as useRef2, useState as useState2 } from "react";
7
+ import { useRef, useState as useState2 } from "react";
8
8
 
9
9
  // src/utils/use-debounce.ts
10
- import { useRef, useState } from "react";
10
+ import { useEffect, useState } from "react";
11
11
  function useDebounce(value, delayMs = 1e3) {
12
12
  const [debouncedValue, setDebouncedValue] = useState(value);
13
- const timer = useRef(void 0);
14
- if (delayMs === 0) return value;
15
- if (value !== debouncedValue && timer.current?.value !== value) {
16
- if (timer.current) clearTimeout(timer.current.handler);
13
+ useEffect(() => {
14
+ if (delayMs === 0) return;
17
15
  const handler = window.setTimeout(() => {
18
16
  setDebouncedValue(value);
19
17
  }, delayMs);
20
- timer.current = { value, handler };
21
- }
18
+ return () => clearTimeout(handler);
19
+ }, [delayMs, value]);
20
+ if (delayMs === 0) return value;
22
21
  return debouncedValue;
23
22
  }
24
23
 
25
24
  // src/search/client.ts
26
- var staticClient;
27
- function useDocsSearch(client, locale, tag, delayMs = 100, allowEmpty = false, key) {
25
+ function isDifferentDeep(a, b) {
26
+ if (Array.isArray(a) && Array.isArray(b)) {
27
+ return b.length !== a.length || a.some((v, i) => isDifferentDeep(v, b[i]));
28
+ }
29
+ if (typeof a === "object" && a && typeof b === "object" && b) {
30
+ const aKeys = Object.keys(a);
31
+ const bKeys = Object.keys(b);
32
+ return aKeys.length !== bKeys.length || aKeys.some(
33
+ (key) => isDifferentDeep(a[key], b[key])
34
+ );
35
+ }
36
+ return a !== b;
37
+ }
38
+ function useDocsSearch(clientOptions) {
39
+ const { delayMs = 100, allowEmpty = false, ...client } = clientOptions;
28
40
  const [search, setSearch] = useState2("");
29
41
  const [results, setResults] = useState2("empty");
30
42
  const [error, setError] = useState2();
31
43
  const [isLoading, setIsLoading] = useState2(false);
32
44
  const debouncedValue = useDebounce(search, delayMs);
33
- const onStart = useRef2(void 0);
34
- useOnChange(key ?? [client, debouncedValue, locale, tag], () => {
35
- if (onStart.current) {
36
- onStart.current();
37
- onStart.current = void 0;
38
- }
39
- setIsLoading(true);
40
- let interrupt = false;
41
- onStart.current = () => {
42
- interrupt = true;
43
- };
44
- async function run() {
45
- if (debouncedValue.length === 0 && !allowEmpty) return "empty";
46
- if (client.type === "fetch") {
47
- const { fetchDocs } = await import("../fetch-W5EHIBOE.js");
48
- return fetchDocs(debouncedValue, locale, tag, client);
49
- }
50
- if (client.type === "algolia") {
51
- const { index, type: _, ...rest } = client;
52
- const { searchDocs } = await import("../algolia-NTWLS6J3.js");
53
- return searchDocs(index, debouncedValue, tag, rest);
45
+ const onStart = useRef(void 0);
46
+ useOnChange(
47
+ [client, debouncedValue],
48
+ () => {
49
+ if (onStart.current) {
50
+ onStart.current();
51
+ onStart.current = void 0;
54
52
  }
55
- if (client.type === "orama-cloud") {
56
- const { searchDocs } = await import("../orama-cloud-USLSOSXS.js");
57
- return searchDocs(debouncedValue, tag, client);
53
+ setIsLoading(true);
54
+ let interrupt = false;
55
+ onStart.current = () => {
56
+ interrupt = true;
57
+ };
58
+ async function run() {
59
+ if (debouncedValue.length === 0 && !allowEmpty) return "empty";
60
+ if (client.type === "fetch") {
61
+ const { fetchDocs } = await import("../fetch-2XFMBLBA.js");
62
+ return fetchDocs(debouncedValue, client);
63
+ }
64
+ if (client.type === "algolia") {
65
+ const { searchDocs } = await import("../algolia-IZEDLPHE.js");
66
+ return searchDocs(debouncedValue, client);
67
+ }
68
+ if (client.type === "orama-cloud") {
69
+ const { searchDocs } = await import("../orama-cloud-WEGQE5A6.js");
70
+ return searchDocs(debouncedValue, client);
71
+ }
72
+ if (client.type === "static") {
73
+ const { search: search2 } = await import("../static-A2YJ5TXV.js");
74
+ return search2(debouncedValue, client);
75
+ }
76
+ if (client.type === "mixedbread") {
77
+ const { search: search2 } = await import("../mixedbread-RAHDVXGJ.js");
78
+ return search2(debouncedValue, client);
79
+ }
80
+ throw new Error("unknown search client");
58
81
  }
59
- const { createStaticClient } = await import("../static-VESU2S64.js");
60
- if (!staticClient) staticClient = createStaticClient(client);
61
- return staticClient.search(debouncedValue, locale, tag);
62
- }
63
- void run().then((res) => {
64
- if (interrupt) return;
65
- setError(void 0);
66
- setResults(res);
67
- }).catch((err) => {
68
- setError(err);
69
- }).finally(() => {
70
- setIsLoading(false);
71
- });
72
- });
82
+ void run().then((res) => {
83
+ if (interrupt) return;
84
+ setError(void 0);
85
+ setResults(res);
86
+ }).catch((err) => {
87
+ setError(err);
88
+ }).finally(() => {
89
+ setIsLoading(false);
90
+ });
91
+ },
92
+ isDifferentDeep
93
+ );
73
94
  return { search, setSearch, query: { isLoading, data: results, error } };
74
95
  }
75
96
  export {
@@ -0,0 +1,26 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ interface SortedResult<Content = string> {
4
+ id: string;
5
+ url: string;
6
+ type: 'page' | 'heading' | 'text';
7
+ content: Content;
8
+ /**
9
+ * breadcrumbs to be displayed on UI
10
+ */
11
+ breadcrumbs?: Content[];
12
+ contentWithHighlights?: HighlightedText<Content>[];
13
+ }
14
+ type ReactSortedResult = SortedResult<ReactNode>;
15
+ interface HighlightedText<Content = string> {
16
+ type: 'text';
17
+ content: Content;
18
+ styles?: {
19
+ highlight?: boolean;
20
+ };
21
+ }
22
+ declare function createContentHighlighter(query: string | RegExp): {
23
+ highlight(content: string): HighlightedText[];
24
+ };
25
+
26
+ export { type HighlightedText, type ReactSortedResult, type SortedResult, createContentHighlighter };
@@ -0,0 +1,7 @@
1
+ import {
2
+ createContentHighlighter
3
+ } from "../chunk-OTD7MV33.js";
4
+ import "../chunk-U67V476Y.js";
5
+ export {
6
+ createContentHighlighter
7
+ };
@@ -1,6 +1,6 @@
1
- import { CloudManager } from '@oramacloud/client';
2
- import { S as StructuredData } from '../remark-structure-FIjTA11P.js';
3
- import '../remark-heading-BPCoYwjn.js';
1
+ import { S as StructuredData } from '../remark-structure-DkCXCzpD.js';
2
+ import '../remark-code-tab-DmyIyi6m.js';
3
+ import { OramaCloud } from '@orama/core';
4
4
  import 'mdast';
5
5
  import 'unified';
6
6
  import 'mdast-util-mdx-jsx';
@@ -50,6 +50,7 @@ interface OramaDocument {
50
50
  * Data to be added to each section index
51
51
  */
52
52
  extra_data?: object;
53
+ breadcrumbs?: string[];
53
54
  }
54
55
  interface OramaIndex {
55
56
  id: string;
@@ -64,13 +65,14 @@ interface OramaIndex {
64
65
  * Heading content
65
66
  */
66
67
  section?: string;
68
+ breadcrumbs?: string[];
67
69
  /**
68
70
  * Heading (anchor) id
69
71
  */
70
72
  section_id?: string;
71
73
  content: string;
72
74
  }
73
- declare function sync(cloudManager: CloudManager, options: SyncOptions): Promise<void>;
74
- declare function syncI18n(cloudManager: CloudManager, options: I18nSyncOptions): Promise<void>;
75
+ declare function sync(orama: OramaCloud, options: SyncOptions): Promise<void>;
76
+ declare function syncI18n(orama: OramaCloud, options: I18nSyncOptions): Promise<void>;
75
77
 
76
78
  export { type I18nSyncOptions, type OramaDocument, type OramaIndex, type SyncOptions, sync, syncI18n };
@@ -1,18 +1,24 @@
1
- import "../chunk-MLKGABMK.js";
1
+ import "../chunk-U67V476Y.js";
2
2
 
3
3
  // src/search/orama-cloud.ts
4
- async function sync(cloudManager, options) {
4
+ async function sync(orama, options) {
5
5
  const { autoDeploy = true } = options;
6
- const index = cloudManager.index(options.index);
7
- await index.snapshot(options.documents.flatMap(toIndex));
8
- if (autoDeploy) await index.deploy();
6
+ const index = orama.index.set(options.index);
7
+ await index.transaction.open();
8
+ await index.transaction.insertDocuments(
9
+ options.documents.flatMap(toIndex)
10
+ );
11
+ if (autoDeploy) await index.transaction.commit();
9
12
  }
10
- async function syncI18n(cloudManager, options) {
11
- const { autoDeploy = true } = options;
13
+ async function syncI18n(orama, options) {
14
+ const { autoDeploy = true, indexes } = options;
12
15
  const tasks = options.documents.map(async (document) => {
13
- const index = cloudManager.index(options.indexes[document.locale]);
14
- await index.snapshot(document.items.flatMap(toIndex));
15
- if (autoDeploy) await index.deploy();
16
+ const index = orama.index.set(indexes[document.locale]);
17
+ await index.transaction.open();
18
+ await index.transaction.insertDocuments(
19
+ document.items.flatMap(toIndex)
20
+ );
21
+ if (autoDeploy) await index.transaction.commit();
16
22
  });
17
23
  await Promise.all(tasks);
18
24
  }
@@ -25,11 +31,13 @@ function toIndex(page) {
25
31
  id: `${page.id}-${(id++).toString()}`,
26
32
  title: page.title,
27
33
  url: page.url,
34
+ // TODO: explicit declare enums
28
35
  page_id: page.id,
29
36
  tag: page.tag,
30
37
  section,
31
38
  section_id: sectionId,
32
39
  content,
40
+ breadcrumbs: page.breadcrumbs,
33
41
  ...page.extra_data
34
42
  };
35
43
  }
@@ -1,39 +1,50 @@
1
1
  import { TypedDocument, Orama, Language, RawData, create, SearchParams } from '@orama/orama';
2
- import { S as StructuredData } from '../remark-structure-FIjTA11P.js';
3
- import { S as SortedResult } from '../types-Ch8gnVgO.js';
4
- import { I as I18nConfig } from '../config-inq6kP6y.js';
5
- import { LoaderOutput, LoaderConfig, InferPageType } from '../source/index.js';
2
+ import { S as StructuredData } from '../remark-structure-DkCXCzpD.js';
3
+ import { SortedResult } from './index.js';
4
+ export { HighlightedText, ReactSortedResult, createContentHighlighter } from './index.js';
5
+ import { I18nConfig } from '../i18n/index.js';
6
+ import { k as LoaderOutput, f as LoaderConfig, I as InferPageType } from '../builder-feW_xVjc.js';
6
7
  import 'mdast';
7
8
  import 'unified';
8
9
  import 'mdast-util-mdx-jsx';
9
10
  import 'react';
10
- import '../page-tree-BG3wP0gU.js';
11
+ import '../definitions-BRsJlZ6m.js';
11
12
 
12
- type AdvancedDocument = TypedDocument<Orama<typeof advancedSchema>>;
13
- declare const advancedSchema: {
14
- readonly content: "string";
15
- readonly page_id: "string";
16
- readonly type: "string";
17
- readonly keywords: "string";
18
- readonly tag: "string";
19
- readonly url: "string";
20
- };
21
13
  type SimpleDocument = TypedDocument<Orama<typeof simpleSchema>>;
22
14
  declare const simpleSchema: {
23
15
  readonly url: "string";
24
16
  readonly title: "string";
17
+ readonly breadcrumbs: "string[]";
25
18
  readonly description: "string";
26
19
  readonly content: "string";
27
20
  readonly keywords: "string";
28
21
  };
22
+ type AdvancedDocument = TypedDocument<Orama<typeof advancedSchema>>;
23
+ declare const advancedSchema: {
24
+ readonly content: "string";
25
+ readonly page_id: "string";
26
+ readonly type: "string";
27
+ readonly breadcrumbs: "string[]";
28
+ readonly tags: "enum[]";
29
+ readonly url: "string";
30
+ readonly embeddings: "vector[512]";
31
+ };
32
+
33
+ type Awaitable<T> = T | Promise<T>;
34
+ interface Options<S extends LoaderOutput<LoaderConfig>> extends Omit<AdvancedOptions, 'indexes'> {
35
+ localeMap?: {
36
+ [K in S extends LoaderOutput<infer C> ? C['i18n'] extends I18nConfig<infer Languages> ? Languages : string : string]?: Partial<AdvancedOptions> | Language;
37
+ };
38
+ buildIndex?: (page: InferPageType<S>) => Awaitable<AdvancedIndex>;
39
+ }
40
+ declare function createFromSource<S extends LoaderOutput<LoaderConfig>>(source: S, options?: Options<S>): SearchAPI;
29
41
 
30
- type LocaleMap<O> = Record<string, Language | O>;
31
42
  type I18nOptions<O extends SimpleOptions | AdvancedOptions, Idx> = Omit<O, 'language' | 'indexes'> & {
32
43
  i18n: I18nConfig;
33
44
  /**
34
45
  * Map locale name from i18n config to Orama compatible `language` or options
35
46
  */
36
- localeMap?: LocaleMap<Partial<O>>;
47
+ localeMap?: Record<string, Language | Partial<O> | undefined>;
37
48
  indexes: WithLocale<Idx>[] | Dynamic<WithLocale<Idx>>;
38
49
  };
39
50
  type I18nSimpleOptions = I18nOptions<SimpleOptions, Index>;
@@ -43,11 +54,6 @@ type WithLocale<T> = T & {
43
54
  };
44
55
  declare function createI18nSearchAPI<T extends 'simple' | 'advanced'>(type: T, options: T extends 'simple' ? I18nSimpleOptions : I18nAdvancedOptions): SearchAPI;
45
56
 
46
- type Options = Omit<AdvancedOptions, 'language' | 'indexes'> & {
47
- localeMap?: LocaleMap<Partial<AdvancedOptions>>;
48
- };
49
- declare function createFromSource<S extends LoaderOutput<LoaderConfig>>(source: S, pageToIndexFn?: (page: InferPageType<S>) => AdvancedIndex, options?: Options): SearchAPI;
50
-
51
57
  type SearchType = 'simple' | 'advanced';
52
58
  type ExportedData = (RawData & {
53
59
  type: SearchType;
@@ -60,7 +66,8 @@ type ExportedData = (RawData & {
60
66
  interface SearchServer {
61
67
  search: (query: string, options?: {
62
68
  locale?: string;
63
- tag?: string;
69
+ tag?: string | string[];
70
+ mode?: 'vector' | 'full';
64
71
  }) => Promise<SortedResult[]>;
65
72
  /**
66
73
  * Export the database
@@ -103,6 +110,7 @@ declare function createSearchAPI<T extends SearchType>(type: T, options: T exten
103
110
  interface Index {
104
111
  title: string;
105
112
  description?: string;
113
+ breadcrumbs?: string[];
106
114
  content: string;
107
115
  url: string;
108
116
  keywords?: string;
@@ -112,11 +120,11 @@ interface AdvancedIndex {
112
120
  id: string;
113
121
  title: string;
114
122
  description?: string;
115
- keywords?: string;
123
+ breadcrumbs?: string[];
116
124
  /**
117
125
  * Required if tag filter is enabled
118
126
  */
119
- tag?: string;
127
+ tag?: string | string[];
120
128
  /**
121
129
  * preprocess mdx content with `structure`
122
130
  */
@@ -125,4 +133,4 @@ interface AdvancedIndex {
125
133
  }
126
134
  declare function initAdvancedSearch(options: AdvancedOptions): SearchServer;
127
135
 
128
- export { type AdvancedIndex, type AdvancedOptions, type Dynamic, type ExportedData, type Index, type SearchAPI, type SearchServer, type SimpleOptions, createFromSource, createI18nSearchAPI, createSearchAPI, initAdvancedSearch, initSimpleSearch };
136
+ export { type AdvancedIndex, type AdvancedOptions, type Dynamic, type ExportedData, type Index, type SearchAPI, type SearchServer, type SimpleOptions, SortedResult, createFromSource, createI18nSearchAPI, createSearchAPI, initAdvancedSearch, initSimpleSearch };
@@ -1,9 +1,19 @@
1
1
  import {
2
2
  searchAdvanced,
3
3
  searchSimple
4
- } from "../chunk-WFUH5VBX.js";
5
- import "../chunk-KAOEMCTI.js";
6
- import "../chunk-MLKGABMK.js";
4
+ } from "../chunk-XOFXGHS4.js";
5
+ import "../chunk-ZMWYLUDP.js";
6
+ import {
7
+ basename,
8
+ extname
9
+ } from "../chunk-XZSI7AHE.js";
10
+ import {
11
+ createContentHighlighter
12
+ } from "../chunk-OTD7MV33.js";
13
+ import {
14
+ findPath
15
+ } from "../chunk-IZPLHEX4.js";
16
+ import "../chunk-U67V476Y.js";
7
17
 
8
18
  // src/search/server.ts
9
19
  import {
@@ -24,8 +34,9 @@ function createEndpoint(server) {
24
34
  if (!query) return Response.json([]);
25
35
  return Response.json(
26
36
  await search(query, {
27
- tag: url.searchParams.get("tag") ?? void 0,
28
- locale: url.searchParams.get("locale") ?? void 0
37
+ tag: url.searchParams.get("tag")?.split(",") ?? void 0,
38
+ locale: url.searchParams.get("locale") ?? void 0,
39
+ mode: url.searchParams.get("mode") === "vector" ? "vector" : "full"
29
40
  })
30
41
  );
31
42
  }
@@ -37,13 +48,22 @@ import {
37
48
  create,
38
49
  insertMultiple
39
50
  } from "@orama/orama";
51
+ var simpleSchema = {
52
+ url: "string",
53
+ title: "string",
54
+ breadcrumbs: "string[]",
55
+ description: "string",
56
+ content: "string",
57
+ keywords: "string"
58
+ };
40
59
  var advancedSchema = {
41
60
  content: "string",
42
61
  page_id: "string",
43
62
  type: "string",
44
- keywords: "string",
45
- tag: "string",
46
- url: "string"
63
+ breadcrumbs: "string[]",
64
+ tags: "enum[]",
65
+ url: "string",
66
+ embeddings: "vector[512]"
47
67
  };
48
68
  async function createDB({
49
69
  indexes,
@@ -62,6 +82,8 @@ async function createDB({
62
82
  });
63
83
  const mapTo = [];
64
84
  items.forEach((page) => {
85
+ const pageTag = page.tag ?? [];
86
+ const tags = Array.isArray(pageTag) ? pageTag : [pageTag];
65
87
  const data = page.structuredData;
66
88
  let id = 0;
67
89
  mapTo.push({
@@ -69,15 +91,16 @@ async function createDB({
69
91
  page_id: page.id,
70
92
  type: "page",
71
93
  content: page.title,
72
- keywords: page.keywords,
73
- tag: page.tag,
94
+ breadcrumbs: page.breadcrumbs,
95
+ tags,
74
96
  url: page.url
75
97
  });
98
+ const nextId = () => `${page.id}-${id++}`;
76
99
  if (page.description) {
77
100
  mapTo.push({
78
- id: `${page.id}-${(id++).toString()}`,
101
+ id: nextId(),
79
102
  page_id: page.id,
80
- tag: page.tag,
103
+ tags,
81
104
  type: "text",
82
105
  url: page.url,
83
106
  content: page.description
@@ -85,19 +108,19 @@ async function createDB({
85
108
  }
86
109
  for (const heading of data.headings) {
87
110
  mapTo.push({
88
- id: `${page.id}-${(id++).toString()}`,
111
+ id: nextId(),
89
112
  page_id: page.id,
90
113
  type: "heading",
91
- tag: page.tag,
114
+ tags,
92
115
  url: `${page.url}#${heading.id}`,
93
116
  content: heading.content
94
117
  });
95
118
  }
96
119
  for (const content of data.contents) {
97
120
  mapTo.push({
98
- id: `${page.id}-${(id++).toString()}`,
121
+ id: nextId(),
99
122
  page_id: page.id,
100
- tag: page.tag,
123
+ tags,
101
124
  type: "text",
102
125
  url: content.heading ? `${page.url}#${content.heading}` : page.url,
103
126
  content: content.content
@@ -107,13 +130,6 @@ async function createDB({
107
130
  await insertMultiple(db, mapTo);
108
131
  return db;
109
132
  }
110
- var simpleSchema = {
111
- url: "string",
112
- title: "string",
113
- description: "string",
114
- content: "string",
115
- keywords: "string"
116
- };
117
133
  async function createDBSimple({
118
134
  indexes,
119
135
  tokenizer,
@@ -133,6 +149,7 @@ async function createDBSimple({
133
149
  items.map((page) => ({
134
150
  title: page.title,
135
151
  description: page.description,
152
+ breadcrumbs: page.breadcrumbs,
136
153
  url: page.url,
137
154
  content: page.content,
138
155
  keywords: page.keywords
@@ -142,41 +159,71 @@ async function createDBSimple({
142
159
  }
143
160
 
144
161
  // src/search/orama/create-from-source.ts
145
- function pageToIndex(page) {
146
- if (!("structuredData" in page.data)) {
147
- throw new Error(
148
- "Cannot find structured data from page, please define the page to index function."
149
- );
162
+ function defaultBuildIndex(source) {
163
+ function isBreadcrumbItem(item) {
164
+ return typeof item === "string" && item.length > 0;
150
165
  }
151
- const structuredData = page.data.structuredData;
152
- return {
153
- title: page.data.title ?? page.file.name,
154
- description: "description" in page.data ? page.data.description : void 0,
155
- url: page.url,
156
- id: page.url,
157
- structuredData
166
+ return async (page) => {
167
+ let breadcrumbs;
168
+ let structuredData;
169
+ if ("structuredData" in page.data) {
170
+ structuredData = page.data.structuredData;
171
+ } else if ("load" in page.data && typeof page.data.load === "function") {
172
+ structuredData = (await page.data.load()).structuredData;
173
+ }
174
+ if (!structuredData)
175
+ throw new Error(
176
+ "Cannot find structured data from page, please define the page to index function."
177
+ );
178
+ const pageTree = source.getPageTree(page.locale);
179
+ const path = findPath(
180
+ pageTree.children,
181
+ (node) => node.type === "page" && node.url === page.url
182
+ );
183
+ if (path) {
184
+ breadcrumbs = [];
185
+ path.pop();
186
+ if (isBreadcrumbItem(pageTree.name)) {
187
+ breadcrumbs.push(pageTree.name);
188
+ }
189
+ for (const segment of path) {
190
+ if (!isBreadcrumbItem(segment.name)) continue;
191
+ breadcrumbs.push(segment.name);
192
+ }
193
+ }
194
+ return {
195
+ title: page.data.title ?? basename(page.path, extname(page.path)),
196
+ breadcrumbs,
197
+ description: page.data.description,
198
+ url: page.url,
199
+ id: page.url,
200
+ structuredData
201
+ };
158
202
  };
159
203
  }
160
- function createFromSource(source, pageToIndexFn = pageToIndex, options = {}) {
204
+ function createFromSource(source, options = {}) {
205
+ const { buildIndex = defaultBuildIndex(source) } = options;
161
206
  if (source._i18n) {
162
207
  return createI18nSearchAPI("advanced", {
163
208
  ...options,
164
209
  i18n: source._i18n,
165
- indexes: source.getLanguages().flatMap((entry) => {
166
- return entry.pages.map((page) => {
167
- return {
168
- ...pageToIndexFn(page),
210
+ indexes: async () => {
211
+ const indexes = source.getLanguages().flatMap((entry) => {
212
+ return entry.pages.map(async (page) => ({
213
+ ...await buildIndex(page),
169
214
  locale: entry.language
170
- };
215
+ }));
171
216
  });
172
- })
217
+ return Promise.all(indexes);
218
+ }
173
219
  });
174
220
  }
175
221
  return createSearchAPI("advanced", {
176
222
  ...options,
177
- indexes: source.getPages().map((page) => {
178
- return pageToIndexFn(page);
179
- })
223
+ indexes: async () => {
224
+ const indexes = source.getPages().map((page) => buildIndex(page));
225
+ return Promise.all(indexes);
226
+ }
180
227
  });
181
228
  }
182
229
 
@@ -273,7 +320,7 @@ function createI18nSearchAPI(type, options) {
273
320
  return createEndpoint({
274
321
  async export() {
275
322
  const map = await get;
276
- const entries = Object.entries(map).map(async ([k, v]) => [
323
+ const entries = Array.from(map.entries()).map(async ([k, v]) => [
277
324
  k,
278
325
  await v.export()
279
326
  ]);
@@ -325,11 +372,26 @@ function initAdvancedSearch(options) {
325
372
  },
326
373
  async search(query, searchOptions) {
327
374
  const db = await get;
328
- return searchAdvanced(db, query, searchOptions?.tag, options.search);
375
+ const mode = searchOptions?.mode;
376
+ return searchAdvanced(db, query, searchOptions?.tag, {
377
+ ...options.search,
378
+ mode: mode === "vector" ? "vector" : "fulltext"
379
+ }).catch((err) => {
380
+ if (mode === "vector") {
381
+ throw new Error(
382
+ "failed to search, make sure you have installed `@orama/plugin-embeddings` according to their docs.",
383
+ {
384
+ cause: err
385
+ }
386
+ );
387
+ }
388
+ throw err;
389
+ });
329
390
  }
330
391
  };
331
392
  }
332
393
  export {
394
+ createContentHighlighter,
333
395
  createFromSource,
334
396
  createI18nSearchAPI,
335
397
  createSearchAPI,