@easyops-cn/docusaurus-search-local 0.52.2 → 0.53.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.
- package/CHANGELOG.md +16 -0
- package/dist/client/client/theme/SearchBar/SearchBar.jsx +41 -30
- package/dist/client/client/theme/SearchBar/SearchBar.module.css +28 -1
- package/dist/client/client/theme/SearchBar/SuggestionTemplate.js +10 -1
- package/dist/client/client/theme/SearchBar/icons.js +1 -0
- package/dist/client/shared/interfaces.js +1 -0
- package/dist/server/server/utils/generate.js +2 -1
- package/dist/server/server/utils/validateOptions.js +1 -0
- package/dist/server/shared/interfaces.js +1 -0
- package/dist/types/declarations.d.ts +43 -0
- package/dist/types/index.d.ts +5 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.53.0](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.52.3...v0.53.0) (2026-02-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* support Ask AI ([8a5d29e](https://github.com/easyops-cn/docusaurus-search-local/commit/8a5d29e2e5b3b1cb534b1bbf13075f6824307d2e))
|
|
11
|
+
* support Ask AI ([3b2e339](https://github.com/easyops-cn/docusaurus-search-local/commit/3b2e339a04ac9347e73fe39d63237ffa3e63242a))
|
|
12
|
+
|
|
13
|
+
## [0.52.3](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.52.2...v0.52.3) (2026-01-29)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* replace useDocsPreferredVersion with useActiveVersion ([7e72ef4](https://github.com/easyops-cn/docusaurus-search-local/commit/7e72ef42c8605f4f4147b2227decc9865ac41afd))
|
|
19
|
+
* replace useDocsPreferredVersion with useActiveVersion ([15ba30d](https://github.com/easyops-cn/docusaurus-search-local/commit/15ba30d8c4aab85984be337f227b3ab166daa93e))
|
|
20
|
+
|
|
5
21
|
## [0.52.2](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.52.1...v0.52.2) (2025-12-01)
|
|
6
22
|
|
|
7
23
|
|
|
@@ -4,12 +4,14 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
|
|
4
4
|
import useIsBrowser from "@docusaurus/useIsBrowser";
|
|
5
5
|
import { useHistory, useLocation } from "@docusaurus/router";
|
|
6
6
|
import { translate } from "@docusaurus/Translate";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { useActivePlugin, useActiveVersion, } from "@docusaurus/plugin-content-docs/client";
|
|
8
|
+
import { AskAIWidget } from "open-ask-ai";
|
|
9
|
+
import "open-ask-ai/styles.css";
|
|
9
10
|
import { fetchIndexesByWorker, searchByWorker } from "../searchByWorker";
|
|
10
11
|
import { SuggestionTemplate } from "./SuggestionTemplate";
|
|
11
12
|
import { EmptyTemplate } from "./EmptyTemplate";
|
|
12
|
-
import {
|
|
13
|
+
import { SearchDocumentType } from "../../../shared/interfaces";
|
|
14
|
+
import { Mark, searchBarShortcut, searchBarShortcutHint, searchBarShortcutKeymap, searchBarPosition, docsPluginIdForPreferredVersion, searchContextByPaths, hideSearchBarWithNoSearchContext, useAllContextsWithNoSearchContext, askAi, } from "../../utils/proxiedGenerated";
|
|
13
15
|
import LoadingRing from "../LoadingRing/LoadingRing";
|
|
14
16
|
import { normalizeContextByPath } from "../../utils/normalizeContextByPath";
|
|
15
17
|
import { searchResultLimits } from "../../utils/proxiedGeneratedConstants";
|
|
@@ -36,29 +38,9 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
36
38
|
// It returns undefined for non-docs pages
|
|
37
39
|
const activePlugin = useActivePlugin();
|
|
38
40
|
let versionUrl = baseUrl;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// It seems that we can not get the correct id for non-docs pages.
|
|
43
|
-
try {
|
|
44
|
-
// The try-catch is a hack because useDocsPreferredVersion just throws an
|
|
45
|
-
// exception when versions are not used.
|
|
46
|
-
// The same hack is used in SearchPage.tsx
|
|
47
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
48
|
-
const { preferredVersion } = useDocsPreferredVersion(activePlugin?.pluginId ?? docsPluginIdForPreferredVersion);
|
|
49
|
-
if (preferredVersion && !preferredVersion.isLast) {
|
|
50
|
-
versionUrl = preferredVersion.path + "/";
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch (e) {
|
|
54
|
-
if (indexDocs) {
|
|
55
|
-
if (e instanceof ReactContextError) {
|
|
56
|
-
/* ignore, happens when website doesn't use versions */
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
throw e;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
41
|
+
const activeVersion = useActiveVersion(activePlugin?.pluginId ?? docsPluginIdForPreferredVersion);
|
|
42
|
+
if (activeVersion && !activeVersion.isLast) {
|
|
43
|
+
versionUrl = activeVersion.path + "/";
|
|
62
44
|
}
|
|
63
45
|
const history = useHistory();
|
|
64
46
|
const location = useLocation();
|
|
@@ -70,6 +52,7 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
70
52
|
const [inputChanged, setInputChanged] = useState(false);
|
|
71
53
|
const [inputValue, setInputValue] = useState("");
|
|
72
54
|
const search = useRef(null);
|
|
55
|
+
const askAIWidgetRef = useRef(null);
|
|
73
56
|
const prevSearchContext = useRef("");
|
|
74
57
|
const [searchContext, setSearchContext] = useState("");
|
|
75
58
|
const prevVersionUrl = useRef(baseUrl);
|
|
@@ -197,7 +180,25 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
197
180
|
{
|
|
198
181
|
source: async (input, callback) => {
|
|
199
182
|
const result = await searchByWorker(versionUrl, searchContext, input, searchResultLimits);
|
|
200
|
-
|
|
183
|
+
if (input && askAi) {
|
|
184
|
+
callback([
|
|
185
|
+
{
|
|
186
|
+
document: {
|
|
187
|
+
i: -1,
|
|
188
|
+
t: "",
|
|
189
|
+
u: "",
|
|
190
|
+
},
|
|
191
|
+
type: SearchDocumentType.AskAI,
|
|
192
|
+
page: undefined,
|
|
193
|
+
metadata: {},
|
|
194
|
+
tokens: [input],
|
|
195
|
+
},
|
|
196
|
+
...result,
|
|
197
|
+
]);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
callback(result);
|
|
201
|
+
}
|
|
201
202
|
},
|
|
202
203
|
templates: {
|
|
203
204
|
suggestion: SuggestionTemplate,
|
|
@@ -216,8 +217,12 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
216
217
|
},
|
|
217
218
|
},
|
|
218
219
|
])
|
|
219
|
-
.on("autocomplete:selected", function (event, { document: { u, h }, tokens }) {
|
|
220
|
+
.on("autocomplete:selected", function (event, { document: { u, h }, type, tokens }) {
|
|
220
221
|
searchBarRef.current?.blur();
|
|
222
|
+
if (type === SearchDocumentType.AskAI && askAi) {
|
|
223
|
+
askAIWidgetRef.current?.openWithNewSession(tokens.join(""));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
221
226
|
let url = u;
|
|
222
227
|
if (Mark && tokens.length > 0) {
|
|
223
228
|
const params = new URLSearchParams();
|
|
@@ -354,13 +359,19 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
354
359
|
message: "Search",
|
|
355
360
|
description: "The ARIA label and placeholder for search button",
|
|
356
361
|
})} aria-label="Search" className={`navbar__search-input ${styles.searchInput}`} onMouseEnter={onInputMouseEnter} onFocus={onInputFocus} onBlur={onInputBlur} onChange={onInputChange} ref={searchBarRef} value={inputValue}/>
|
|
362
|
+
{askAi && (<AskAIWidget ref={askAIWidgetRef} {...askAi}>
|
|
363
|
+
<span hidden></span>
|
|
364
|
+
</AskAIWidget>)}
|
|
357
365
|
<LoadingRing className={styles.searchBarLoadingRing}/>
|
|
358
366
|
{searchBarShortcut &&
|
|
359
367
|
searchBarShortcutHint &&
|
|
360
368
|
(inputValue !== "" ? (<button className={styles.searchClearButton} onClick={onClearSearch}>
|
|
361
369
|
✕
|
|
362
|
-
</button>) : (isBrowser &&
|
|
363
|
-
|
|
370
|
+
</button>) : (isBrowser &&
|
|
371
|
+
searchBarShortcutKeymap && (<div className={styles.searchHintContainer}>
|
|
372
|
+
{getKeymapHints(searchBarShortcutKeymap, isMac).map((hint, index) => (<kbd key={index} className={styles.searchHint}>
|
|
373
|
+
{hint}
|
|
374
|
+
</kbd>))}
|
|
364
375
|
</div>)))}
|
|
365
376
|
</div>);
|
|
366
377
|
}
|
|
@@ -17,10 +17,37 @@
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.searchInput:focus {
|
|
20
|
-
outline: 2px solid
|
|
20
|
+
outline: 2px solid
|
|
21
|
+
var(--search-local-input-active-border-color, var(--ifm-color-primary));
|
|
21
22
|
outline-offset: 0px;
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
html[data-theme="dark"] div:global(.ask-ai),
|
|
26
|
+
div:global(.ask-ai) {
|
|
27
|
+
--ask-ai-primary: var(--ifm-color-primary);
|
|
28
|
+
--ask-ai-primary-hover: var(--ifm-color-primary-light);
|
|
29
|
+
--ask-ai-foreground: var(--ifm-color-content);
|
|
30
|
+
--ask-ai-border: var(--ifm-color-emphasis-300);
|
|
31
|
+
--ask-ai-error: var(--ifm-color-danger);
|
|
32
|
+
--ask-ai-button-bg: var(--ifm-color-emphasis-200);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:global(.ask-ai) {
|
|
36
|
+
--ask-ai-background: var(--search-local-modal-background, #f5f6f7);
|
|
37
|
+
--ask-ai-muted: var(--search-local-muted-color, #969faf);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
html[data-theme="dark"] :global(.ask-ai) {
|
|
41
|
+
--ask-ai-background: var(
|
|
42
|
+
--search-local-modal-background,
|
|
43
|
+
var(--ifm-background-color)
|
|
44
|
+
);
|
|
45
|
+
--ask-ai-muted: var(
|
|
46
|
+
--search-local-muted-color,
|
|
47
|
+
var(--ifm-color-secondary-darkest)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
24
51
|
@media not (max-width: 996px) {
|
|
25
52
|
.searchBar.searchBarLeft .dropdownMenu {
|
|
26
53
|
left: 0 !important;
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { SearchDocumentType, } from "../../../shared/interfaces";
|
|
2
2
|
import { concatDocumentPath } from "../../utils/concatDocumentPath";
|
|
3
|
+
import { escapeHtml } from "../../utils/escapeHtml";
|
|
3
4
|
import { getStemmedPositions } from "../../utils/getStemmedPositions";
|
|
4
5
|
import { highlight } from "../../utils/highlight";
|
|
5
6
|
import { highlightStemmed } from "../../utils/highlightStemmed";
|
|
6
7
|
import { explicitSearchResultPath } from "../../utils/proxiedGenerated";
|
|
7
|
-
import { iconAction, iconContent, iconHeading, iconTitle, iconTreeInter, iconTreeLast, } from "./icons";
|
|
8
|
+
import { iconAction, iconAskAI, iconContent, iconHeading, iconTitle, iconTreeInter, iconTreeLast, } from "./icons";
|
|
8
9
|
import styles from "./SearchBar.module.css";
|
|
9
10
|
export function SuggestionTemplate({ document, type, page, metadata, tokens, isInterOfTree, isLastOfTree, }) {
|
|
11
|
+
if (type === SearchDocumentType.AskAI) {
|
|
12
|
+
return [
|
|
13
|
+
`<span class="${styles.hitIcon}">${iconAskAI}</span>`,
|
|
14
|
+
`<span class="${styles.hitWrapper}">`,
|
|
15
|
+
`<span class="${styles.hitTitle}">Ask AI: <mark>${escapeHtml(tokens.join(" "))}</mark></span>`,
|
|
16
|
+
`</span>`,
|
|
17
|
+
].join("");
|
|
18
|
+
}
|
|
10
19
|
const isTitle = type === SearchDocumentType.Title;
|
|
11
20
|
const isKeywords = type === SearchDocumentType.Keywords;
|
|
12
21
|
const isTitleRelated = isTitle || isKeywords;
|
|
@@ -5,3 +5,4 @@ export const iconAction = '<svg width="20" height="20" viewBox="0 0 20 20"><g st
|
|
|
5
5
|
export const iconNoResults = '<svg width="40" height="40" viewBox="0 0 20 20" fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"></path></svg>';
|
|
6
6
|
export const iconTreeInter = '<svg viewBox="0 0 24 54"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6v42M20 27H8.3"></path></g></svg>';
|
|
7
7
|
export const iconTreeLast = '<svg viewBox="0 0 24 54"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6v21M20 27H8.3"></path></g></svg>';
|
|
8
|
+
export const iconAskAI = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sparkles-icon lucide-sparkles"><path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/></svg>';
|
|
@@ -5,4 +5,5 @@ export var SearchDocumentType;
|
|
|
5
5
|
SearchDocumentType[SearchDocumentType["Description"] = 2] = "Description";
|
|
6
6
|
SearchDocumentType[SearchDocumentType["Keywords"] = 3] = "Keywords";
|
|
7
7
|
SearchDocumentType[SearchDocumentType["Content"] = 4] = "Content";
|
|
8
|
+
SearchDocumentType[SearchDocumentType["AskAI"] = 5] = "AskAI";
|
|
8
9
|
})(SearchDocumentType || (SearchDocumentType = {}));
|
|
@@ -6,7 +6,7 @@ const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
|
6
6
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
7
|
const getIndexHash_1 = require("./getIndexHash");
|
|
8
8
|
function generate(config, dir) {
|
|
9
|
-
const { language, removeDefaultStopWordFilter, removeDefaultStemmer, highlightSearchTermsOnTargetPage, searchResultLimits, searchResultContextMaxLength, explicitSearchResultPath, searchBarShortcut, searchBarShortcutHint, searchBarShortcutKeymap, searchBarPosition, docsPluginIdForPreferredVersion, indexDocs, searchContextByPaths, hideSearchBarWithNoSearchContext, useAllContextsWithNoSearchContext, fuzzyMatchingDistance, } = config;
|
|
9
|
+
const { language, removeDefaultStopWordFilter, removeDefaultStemmer, highlightSearchTermsOnTargetPage, searchResultLimits, searchResultContextMaxLength, explicitSearchResultPath, searchBarShortcut, searchBarShortcutHint, searchBarShortcutKeymap, searchBarPosition, docsPluginIdForPreferredVersion, indexDocs, searchContextByPaths, hideSearchBarWithNoSearchContext, useAllContextsWithNoSearchContext, fuzzyMatchingDistance, askAi, } = config;
|
|
10
10
|
const indexHash = (0, getIndexHash_1.getIndexHash)(config);
|
|
11
11
|
const contents = [];
|
|
12
12
|
contents.push(`export const removeDefaultStemmer = ${JSON.stringify(removeDefaultStemmer)};`);
|
|
@@ -41,6 +41,7 @@ function generate(config, dir) {
|
|
|
41
41
|
: null)};`);
|
|
42
42
|
contents.push(`export const hideSearchBarWithNoSearchContext = ${JSON.stringify(!!hideSearchBarWithNoSearchContext)};`);
|
|
43
43
|
contents.push(`export const useAllContextsWithNoSearchContext = ${JSON.stringify(!!useAllContextsWithNoSearchContext)};`);
|
|
44
|
+
contents.push(`export const askAi = ${JSON.stringify(askAi !== null && askAi !== void 0 ? askAi : null)};`);
|
|
44
45
|
fs_1.default.writeFileSync(path_1.default.join(dir, "generated.js"), contents.join("\n"));
|
|
45
46
|
const constantContents = [
|
|
46
47
|
`import lunr from ${JSON.stringify(require.resolve("lunr"))};`,
|
|
@@ -40,6 +40,7 @@ const schema = utils_validation_1.Joi.object({
|
|
|
40
40
|
useAllContextsWithNoSearchContext: utils_validation_1.Joi.boolean().default(false),
|
|
41
41
|
forceIgnoreNoIndex: utils_validation_1.Joi.boolean().default(false),
|
|
42
42
|
fuzzyMatchingDistance: utils_validation_1.Joi.number().default(1),
|
|
43
|
+
askAi: utils_validation_1.Joi.object().optional(),
|
|
43
44
|
});
|
|
44
45
|
function validateOptions({ options, validate, }) {
|
|
45
46
|
return validate(schema, options || {});
|
|
@@ -8,4 +8,5 @@ var SearchDocumentType;
|
|
|
8
8
|
SearchDocumentType[SearchDocumentType["Description"] = 2] = "Description";
|
|
9
9
|
SearchDocumentType[SearchDocumentType["Keywords"] = 3] = "Keywords";
|
|
10
10
|
SearchDocumentType[SearchDocumentType["Content"] = 4] = "Content";
|
|
11
|
+
SearchDocumentType[SearchDocumentType["AskAI"] = 5] = "AskAI";
|
|
11
12
|
})(SearchDocumentType || (exports.SearchDocumentType = SearchDocumentType = {}));
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare module "ai" {
|
|
2
|
+
interface UIMessage {
|
|
3
|
+
}
|
|
4
|
+
interface UIMessageChunk {
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
declare module "@easyops-cn/autocomplete.js" {
|
|
8
|
+
const noConflict: () => void;
|
|
9
|
+
}
|
|
10
|
+
declare module "*/generated.js" {
|
|
11
|
+
const removeDefaultStemmer: string[];
|
|
12
|
+
class Mark {
|
|
13
|
+
constructor(root: HTMLElement);
|
|
14
|
+
mark: (terms: string[], options?: Record<string, unknown>) => void;
|
|
15
|
+
unmark: () => void;
|
|
16
|
+
}
|
|
17
|
+
const searchResultContextMaxLength: number;
|
|
18
|
+
const explicitSearchResultPath: boolean;
|
|
19
|
+
const searchBarShortcut: boolean;
|
|
20
|
+
const searchBarShortcutHint: boolean;
|
|
21
|
+
const searchBarShortcutKeymap: string;
|
|
22
|
+
const searchBarPosition: "left" | "right";
|
|
23
|
+
const docsPluginIdForPreferredVersion: string;
|
|
24
|
+
const indexDocs: boolean;
|
|
25
|
+
const searchContextByPaths: (string | {
|
|
26
|
+
label: string | Record<string, string>;
|
|
27
|
+
path: string;
|
|
28
|
+
})[];
|
|
29
|
+
const hideSearchBarWithNoSearchContext: boolean;
|
|
30
|
+
const useAllContextsWithNoSearchContext: boolean;
|
|
31
|
+
const forceIgnoreNoIndex: boolean;
|
|
32
|
+
const askAi: import("open-ask-ai").AskAIWidgetProps;
|
|
33
|
+
}
|
|
34
|
+
declare module "*/generated-constants.js" {
|
|
35
|
+
const removeDefaultStopWordFilter: string[];
|
|
36
|
+
const language: string[];
|
|
37
|
+
const searchIndexUrl: string;
|
|
38
|
+
const searchResultLimits: number;
|
|
39
|
+
const fuzzyMatchingDistance: number;
|
|
40
|
+
const __setLanguage: (value: string[]) => void;
|
|
41
|
+
const __setRemoveDefaultStopWordFilter: (value: string[]) => void;
|
|
42
|
+
}
|
|
43
|
+
declare module "@docusaurus/Head";
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AskAIWidgetProps } from "open-ask-ai";
|
|
1
2
|
export interface PluginOptions {
|
|
2
3
|
/**
|
|
3
4
|
* Whether to index docs.
|
|
@@ -193,4 +194,8 @@ export interface PluginOptions {
|
|
|
193
194
|
* @default 1
|
|
194
195
|
*/
|
|
195
196
|
fuzzyMatchingDistance?: number;
|
|
197
|
+
/**
|
|
198
|
+
* Configuration for Ask AI widget integration. When not set, the Ask AI feature will be disabled.
|
|
199
|
+
*/
|
|
200
|
+
askAi?: AskAIWidgetProps;
|
|
196
201
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easyops-cn/docusaurus-search-local",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "An offline/local search plugin for Docusaurus v3",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"lunr": "^2.3.9",
|
|
47
47
|
"lunr-languages": "^1.4.0",
|
|
48
48
|
"mark.js": "^8.11.1",
|
|
49
|
+
"open-ask-ai": "^0.7.3",
|
|
49
50
|
"tslib": "^2.4.0"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|