From 19ea360fd59ee70693569f47d5996a500152a689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Mon, 13 Oct 2025 18:57:09 +0200 Subject: [PATCH] fix(theme-search-algolia): Fix Algolia AskAI validation logic (#11468) --- .../src/__tests__/validateThemeConfig.test.ts | 38 ++++++++++++++----- .../src/theme-search-algolia.d.ts | 6 ++- .../src/validateThemeConfig.ts | 12 ++++-- website/docusaurus.config.ts | 8 ++-- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts index b41f5bb73b..31b1fe01da 100644 --- a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts @@ -229,10 +229,33 @@ describe('validateThemeConfig', () => { ...DEFAULT_CONFIG, ...algolia, askAi: { - indexName: 'index', - apiKey: 'apiKey', - appId: 'BH4D9OD16A', assistantId: 'my-assistant-id', + indexName: algolia.indexName, + apiKey: algolia.apiKey, + appId: algolia.appId, + }, + }, + }); + }); + + it('accepts minimal object format', () => { + const algolia: AlgoliaInput = { + appId: 'BH4D9OD16A', + indexName: 'index', + apiKey: 'apiKey', + askAi: { + assistantId: 'my-assistant-id', + }, + }; + expect(testValidateThemeConfig(algolia)).toEqual({ + algolia: { + ...DEFAULT_CONFIG, + ...algolia, + askAi: { + assistantId: 'my-assistant-id', + indexName: algolia.indexName, + apiKey: algolia.apiKey, + appId: algolia.appId, }, }, }); @@ -273,21 +296,18 @@ describe('validateThemeConfig', () => { ); }); - it('rejects object missing required fields', () => { + it('rejects empty askAi', () => { const algolia: AlgoliaInput = { appId: 'BH4D9OD16A', indexName: 'index', apiKey: 'apiKey', // @ts-expect-error: expected type error: missing mandatory fields - askAi: { - assistantId: 'my-assistant-id', - // Missing indexName, apiKey, appId - }, + askAi: {}, }; expect(() => testValidateThemeConfig(algolia), ).toThrowErrorMatchingInlineSnapshot( - `""algolia.askAi.indexName" is required"`, + `""algolia.askAi.assistantId" is required"`, ); }); diff --git a/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts b/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts index 076a93eab3..7e01aca0e8 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts +++ b/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts @@ -11,7 +11,7 @@ declare module '@docsearch/react/useDocSearchKeyboardEvents'; declare module '@docsearch/react/version'; declare module '@docusaurus/theme-search-algolia' { - import type {DeepPartial, Overwrite} from 'utility-types'; + import type {DeepPartial, Overwrite, Optional} from 'utility-types'; import type {DocSearchProps} from '@docsearch/react'; import type {FacetFilters} from 'algoliasearch/lite'; @@ -70,7 +70,9 @@ declare module '@docusaurus/theme-search-algolia' { apiKey: ThemeConfigAlgolia['apiKey']; indexName: ThemeConfigAlgolia['indexName']; // askAi also accepts a shorter string form - askAi?: string | AskAiConfig; + askAi?: + | string + | Optional; } >; }; diff --git a/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts b/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts index 6f623e3032..8b5d71980a 100644 --- a/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts @@ -67,10 +67,11 @@ export const Schema = Joi.object({ Joi.string(), // Full configuration object Joi.object({ - indexName: Joi.string().required(), - apiKey: Joi.string().required(), - appId: Joi.string().required(), assistantId: Joi.string().required(), + // Optional Ask AI configuration + indexName: Joi.string().optional(), + apiKey: Joi.string().optional(), + appId: Joi.string().optional(), searchParameters: Joi.object({ facetFilters: FacetFiltersSchema.optional(), }).optional(), @@ -102,6 +103,10 @@ export const Schema = Joi.object({ } satisfies ThemeConfigAlgolia['askAi']; } + // Fill in missing fields with the top-level Algolia config + askAiInput.indexName = askAiInput.indexName ?? algolia.indexName; + askAiInput.apiKey = askAiInput.apiKey ?? algolia.apiKey; + askAiInput.appId = askAiInput.appId ?? algolia.appId; if ( askAiInput.searchParameters?.facetFilters === undefined && algoliaFacetFilters @@ -109,6 +114,7 @@ export const Schema = Joi.object({ askAiInput.searchParameters = askAiInput.searchParameters ?? {}; askAiInput.searchParameters.facetFilters = algoliaFacetFilters; } + return askAiInput; }, ) diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index c5c3d3fc80..befe96bfe9 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -662,9 +662,11 @@ export default async function createConfigAsync() { // eslint-disable-next-line @typescript-eslint/no-var-requires,global-require ...(require('@docsearch/react').version.startsWith('4.') ? { - // cSpell:ignore IMYF - askAi: 'RgIMYFUmTfrN', - // indexName: 'docusaurus-markdown', + askAi: { + // cSpell:ignore IMYF + assistantId: 'RgIMYFUmTfrN', + indexName: 'docusaurus-markdown', + }, } : {}),