diff --git a/plugins/search-backend-module-elasticsearch/alpha-api-report.md b/plugins/search-backend-module-elasticsearch/alpha-api-report.md new file mode 100644 index 0000000000..acdd14e781 --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/alpha-api-report.md @@ -0,0 +1,61 @@ +## API Report File for "@backstage/plugin-search-backend-module-elasticsearch" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { SearchQuery } from '@backstage/plugin-search-common'; + +// @public +export type ElasticSearchConcreteQuery = { + documentTypes?: string[]; + elasticSearchQuery: Object; + pageSize: number; +}; + +// @public +export type ElasticSearchCustomIndexTemplate = { + name: string; + body: ElasticSearchCustomIndexTemplateBody; +}; + +// @public +export type ElasticSearchCustomIndexTemplateBody = { + index_patterns: string[]; + composed_of?: string[]; + template?: Record; +}; + +// @alpha +export const elasticSearchEngineModule: ( + options?: ElasticsearchEngineModuleOptions | undefined, +) => BackendFeature; + +// @alpha +export type ElasticsearchEngineModuleOptions = { + translator?: ElasticSearchQueryTranslator; + indexTemplate?: ElasticSearchCustomIndexTemplate; +}; + +// @public (undocumented) +export type ElasticSearchHighlightConfig = { + fragmentDelimiter: string; + fragmentSize: number; + numFragments: number; + preTag: string; + postTag: string; +}; + +// @public +export type ElasticSearchQueryTranslator = ( + query: SearchQuery, + options?: ElasticSearchQueryTranslatorOptions, +) => ElasticSearchConcreteQuery; + +// @public +export type ElasticSearchQueryTranslatorOptions = { + highlightOptions?: ElasticSearchHighlightConfig; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-elasticsearch/src/alpha.ts b/plugins/search-backend-module-elasticsearch/src/alpha.ts index ad83919ee4..8e75c9f603 100644 --- a/plugins/search-backend-module-elasticsearch/src/alpha.ts +++ b/plugins/search-backend-module-elasticsearch/src/alpha.ts @@ -20,18 +20,30 @@ import { } from '@backstage/backend-plugin-api'; import { loggerToWinstonLogger } from '@backstage/backend-common'; import { + ElasticSearchHighlightConfig, + ElasticSearchQueryTranslatorOptions, + ElasticSearchConcreteQuery, ElasticSearchCustomIndexTemplate, + ElasticSearchCustomIndexTemplateBody, ElasticSearchQueryTranslator, ElasticSearchSearchEngine, } from './engines'; -export type ElasticSearchEngineModuleOptions = { +/** + * @alpha + * Options for {@link elasticSearchEngineModule}. + */ +export type ElasticsearchEngineModuleOptions = { translator?: ElasticSearchQueryTranslator; indexTemplate?: ElasticSearchCustomIndexTemplate; }; +/** + * @alpha + * Search backend module for the Elasticsearch engine. + */ export const elasticSearchEngineModule = createBackendModule( - (options?: ElasticSearchEngineModuleOptions) => ({ + (options?: ElasticsearchEngineModuleOptions) => ({ moduleId: 'elasticSearchEngineModule', pluginId: 'search', register(env) { @@ -46,7 +58,7 @@ export const elasticSearchEngineModule = createBackendModule( logger: loggerToWinstonLogger(logger), config: config, }); - searchEngineRegistry.setSearchEngine(searchEngine); + // set custom translator if available if (options?.translator) { searchEngine.setTranslator(options.translator); @@ -56,8 +68,19 @@ export const elasticSearchEngineModule = createBackendModule( if (options?.indexTemplate) { searchEngine.setIndexTemplate(options.indexTemplate); } + + searchEngineRegistry.setSearchEngine(searchEngine); }, }); }, }), ); + +export type { + ElasticSearchCustomIndexTemplate, + ElasticSearchCustomIndexTemplateBody, + ElasticSearchQueryTranslator, + ElasticSearchQueryTranslatorOptions, + ElasticSearchHighlightConfig, + ElasticSearchConcreteQuery, +}; diff --git a/plugins/search-backend-module-pg/alpha-api-report.md b/plugins/search-backend-module-pg/alpha-api-report.md new file mode 100644 index 0000000000..01a83bace4 --- /dev/null +++ b/plugins/search-backend-module-pg/alpha-api-report.md @@ -0,0 +1,12 @@ +## API Report File for "@backstage/plugin-search-backend-module-pg" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// @alpha +export const pgSearchEngineModule: () => BackendFeature; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-pg/src/alpha.ts b/plugins/search-backend-module-pg/src/alpha.ts index bd12b4f118..80ce31adf6 100644 --- a/plugins/search-backend-module-pg/src/alpha.ts +++ b/plugins/search-backend-module-pg/src/alpha.ts @@ -20,6 +20,10 @@ import { import { searchEngineRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; import { PgSearchEngine } from './PgSearchEngine'; +/** + * @alpha + * Search backend module for the Postgres engine. + */ export const pgSearchEngineModule = createBackendModule({ moduleId: 'pgSearchEngineModule', pluginId: 'search', diff --git a/plugins/search-backend-node/alpha-api-report.md b/plugins/search-backend-node/alpha-api-report.md new file mode 100644 index 0000000000..f53f86b709 --- /dev/null +++ b/plugins/search-backend-node/alpha-api-report.md @@ -0,0 +1,62 @@ +## API Report File for "@backstage/plugin-search-backend-node" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; +import { DocumentDecoratorFactory } from '@backstage/plugin-search-common'; +import { DocumentTypeInfo } from '@backstage/plugin-search-common'; +import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { SearchEngine } from '@backstage/plugin-search-common'; +import { ServiceRef } from '@backstage/backend-plugin-api'; +import { TaskRunner } from '@backstage/backend-tasks'; + +// @alpha +export type IndexServiceBuildOptions = { + searchEngine: SearchEngine; + collators: RegisterCollatorParameters[]; + decorators: RegisterDecoratorParameters[]; +}; + +// @public +export interface RegisterCollatorParameters { + factory: DocumentCollatorFactory; + schedule: TaskRunner; +} + +// @public +export interface RegisterDecoratorParameters { + factory: DocumentDecoratorFactory; +} + +// @alpha +export interface SearchEngineRegistryExtensionPoint { + // (undocumented) + setSearchEngine(searchEngine: SearchEngine): void; +} + +// @alpha +export const searchEngineRegistryExtensionPoint: ExtensionPoint; + +// @alpha +export interface SearchIndexRegistryExtensionPoint { + // (undocumented) + addCollator(options: RegisterCollatorParameters): void; + // (undocumented) + addDecorator(options: RegisterDecoratorParameters): void; +} + +// @alpha +export const searchIndexRegistryExtensionPoint: ExtensionPoint; + +// @alpha +export interface SearchIndexService { + getDocumentTypes(): Record; + start(options: IndexServiceBuildOptions): Promise; +} + +// @alpha +export const searchIndexService: ServiceRef; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-node/src/alpha.ts b/plugins/search-backend-node/src/alpha.ts index b2ca6570e1..22c6508b15 100644 --- a/plugins/search-backend-node/src/alpha.ts +++ b/plugins/search-backend-node/src/alpha.ts @@ -34,43 +34,70 @@ import { } from './types'; import { IndexBuilder } from './IndexBuilder'; -import { Scheduler } from './Scheduler'; -export interface SearchIndexBuilderService { - build(options: IndexBuilderServiceBuildOptions): Promise<{ - scheduler: Scheduler; - }>; +/** + * @alpha + * Options for build method on {@link SearchIndexService}. + */ +export type IndexServiceBuildOptions = { + searchEngine: SearchEngine; + collators: RegisterCollatorParameters[]; + decorators: RegisterDecoratorParameters[]; +}; + +/** + * @alpha + * Interface for implementation of index service. + */ +export interface SearchIndexService { + /** + * Starts indexing process + */ + start(options: IndexServiceBuildOptions): Promise; + /** + * Returns an index types list. + */ getDocumentTypes(): Record; } +/** + * @alpha + * Interface for search index registry extension point. + */ export interface SearchIndexRegistryExtensionPoint { addCollator(options: RegisterCollatorParameters): void; addDecorator(options: RegisterDecoratorParameters): void; } +/** + * @alpha + * Interface for search engine registry extension point. + */ export interface SearchEngineRegistryExtensionPoint { setSearchEngine(searchEngine: SearchEngine): void; } -type DefaultSearchIndexBuilderServiceOptions = { +type DefaultSearchIndexServiceOptions = { logger: Logger; }; -class DefaultSearchIndexBuilderService implements SearchIndexBuilderService { +/** + * @alpha + * Reponsible for register the indexing task and start the schedule. + */ +class DefaultSearchIndexService implements SearchIndexService { private logger: Logger; private indexBuilder: IndexBuilder | null = null; - private constructor(options: DefaultSearchIndexBuilderServiceOptions) { + private constructor(options: DefaultSearchIndexServiceOptions) { this.logger = options.logger; } - static fromConfig(options: DefaultSearchIndexBuilderServiceOptions) { - return new DefaultSearchIndexBuilderService(options); + static fromConfig(options: DefaultSearchIndexServiceOptions) { + return new DefaultSearchIndexService(options); } - build( - options: IndexBuilderServiceBuildOptions, - ): Promise<{ scheduler: Scheduler }> { + async start(options: IndexServiceBuildOptions): Promise { this.indexBuilder = new IndexBuilder({ logger: this.logger, searchEngine: options.searchEngine, @@ -84,7 +111,8 @@ class DefaultSearchIndexBuilderService implements SearchIndexBuilderService { this.indexBuilder?.addDecorator(decorator), ); - return this.indexBuilder?.build(); + const { scheduler } = await this.indexBuilder?.build(); + scheduler.start(); } getDocumentTypes(): Record { @@ -92,35 +120,48 @@ class DefaultSearchIndexBuilderService implements SearchIndexBuilderService { } } -export const searchIndexBuilderService = - createServiceRef({ - id: 'search.index.builder', - defaultFactory: async service => - createServiceFactory({ - service, - deps: { - logger: coreServices.logger, - }, - factory({ logger }) { - return DefaultSearchIndexBuilderService.fromConfig({ - logger: loggerToWinstonLogger(logger), - }); - }, - }), - }); +/** + * @alpha + * Service that builds a search index. + */ +export const searchIndexServiceRef = createServiceRef({ + id: 'search.index.service', + defaultFactory: async service => + createServiceFactory({ + service, + deps: { + logger: coreServices.logger, + }, + factory({ logger }) { + return DefaultSearchIndexService.fromConfig({ + logger: loggerToWinstonLogger(logger), + }); + }, + }), +}); +/** + * @alpha + * Extension point for register a search engine. + */ export const searchEngineRegistryExtensionPoint = createExtensionPoint({ id: 'search.engine.registry', }); +/** + * @alpha + * Extension point for registering collators and decorators + */ export const searchIndexRegistryExtensionPoint = createExtensionPoint({ id: 'search.index.registry', }); -export type IndexBuilderServiceBuildOptions = { - searchEngine: SearchEngine; - collators: RegisterCollatorParameters[]; - decorators: RegisterDecoratorParameters[]; -}; +/** + * @alpha + */ +export type { + RegisterCollatorParameters, + RegisterDecoratorParameters, +} from './types'; diff --git a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts index 57fe123ede..b69b5ea863 100644 --- a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts +++ b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts @@ -26,12 +26,6 @@ import lunr from 'lunr'; import { v4 as uuid } from 'uuid'; import { Logger } from 'winston'; import { LunrSearchEngineIndexer } from './LunrSearchEngineIndexer'; -import { - coreServices, - createBackendModule, -} from '@backstage/backend-plugin-api'; -import { searchEngineRegistryExtensionPoint } from '../alpha'; -import { loggerToWinstonLogger } from '@backstage/backend-common'; /** * Type of translated query for the Lunr Search Engine. @@ -340,21 +334,3 @@ export function parseHighlightFields({ }), ); } - -export const lunrSearchEngineModule = createBackendModule({ - moduleId: 'lunrSearchEngineModule', - pluginId: 'search', - register(env) { - env.registerInit({ - deps: { - searchEngineRegistry: searchEngineRegistryExtensionPoint, - logger: coreServices.logger, - }, - async init({ searchEngineRegistry, logger }) { - searchEngineRegistry.setSearchEngine( - new LunrSearchEngine({ logger: loggerToWinstonLogger(logger) }), - ); - }, - }); - }, -}); diff --git a/plugins/search-backend-node/src/engines/index.ts b/plugins/search-backend-node/src/engines/index.ts index 59aa4a24b0..0d710eadc2 100644 --- a/plugins/search-backend-node/src/engines/index.ts +++ b/plugins/search-backend-node/src/engines/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { LunrSearchEngine, lunrSearchEngineModule } from './LunrSearchEngine'; +export { LunrSearchEngine } from './LunrSearchEngine'; export type { ConcreteLunrQuery, LunrQueryTranslator, diff --git a/plugins/search-backend-node/src/index.ts b/plugins/search-backend-node/src/index.ts index 140c0a22f8..a188509c1c 100644 --- a/plugins/search-backend-node/src/index.ts +++ b/plugins/search-backend-node/src/index.ts @@ -23,7 +23,7 @@ export { IndexBuilder } from './IndexBuilder'; export { Scheduler } from './Scheduler'; export * from './collators'; -export { LunrSearchEngine, lunrSearchEngineModule } from './engines'; +export { LunrSearchEngine } from './engines'; export type { ConcreteLunrQuery, LunrQueryTranslator, diff --git a/plugins/search-backend/alpha-api-report.md b/plugins/search-backend/alpha-api-report.md new file mode 100644 index 0000000000..6ee94a0e29 --- /dev/null +++ b/plugins/search-backend/alpha-api-report.md @@ -0,0 +1,12 @@ +## API Report File for "@backstage/plugin-search-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// @alpha +export const searchPlugin: () => BackendFeature; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend/src/alpha.ts b/plugins/search-backend/src/alpha.ts index e35b33188b..0c14852875 100644 --- a/plugins/search-backend/src/alpha.ts +++ b/plugins/search-backend/src/alpha.ts @@ -14,4 +14,117 @@ * limitations under the License. */ -export { searchPlugin } from './plugin'; +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + RegisterCollatorParameters, + RegisterDecoratorParameters, + LunrSearchEngine, +} from '@backstage/plugin-search-backend-node'; +import { + searchIndexServiceRef, + searchIndexRegistryExtensionPoint, + SearchIndexRegistryExtensionPoint, + SearchEngineRegistryExtensionPoint, + searchEngineRegistryExtensionPoint, +} from '@backstage/plugin-search-backend-node/alpha'; + +import { createRouter } from './service/router'; +import { SearchEngine } from '@backstage/plugin-search-common'; + +class SearchIndexRegistry implements SearchIndexRegistryExtensionPoint { + private collators: RegisterCollatorParameters[] = []; + private decorators: RegisterDecoratorParameters[] = []; + + public addCollator(options: RegisterCollatorParameters): void { + this.collators.push(options); + } + + public addDecorator(options: RegisterDecoratorParameters): void { + this.decorators.push(options); + } + + public getCollators(): RegisterCollatorParameters[] { + return this.collators; + } + + public getDecorators(): RegisterDecoratorParameters[] { + return this.decorators; + } +} + +class SearchEngineRegistry implements SearchEngineRegistryExtensionPoint { + private searchEngine: SearchEngine | null = null; + + public setSearchEngine(searchEngine: SearchEngine): void { + if (this.searchEngine) { + throw new Error('Multiple Search engines is not supported at this time'); + } + this.searchEngine = searchEngine; + } + + public getSearchEngine(): SearchEngine | null { + return this.searchEngine; + } +} + +/** + * The Search plugin is responsible for starting search indexing processes and return search results. + * @alpha + */ +export const searchPlugin = createBackendPlugin({ + pluginId: 'search', + register(env) { + const searchIndexRegistry = new SearchIndexRegistry(); + env.registerExtensionPoint( + searchIndexRegistryExtensionPoint, + searchIndexRegistry, + ); + + const searchEngineRegistry = new SearchEngineRegistry(); + env.registerExtensionPoint( + searchEngineRegistryExtensionPoint, + searchEngineRegistry, + ); + + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.config, + permissions: coreServices.permissions, + http: coreServices.httpRouter, + searchIndexService: searchIndexServiceRef, + }, + async init({ config, logger, permissions, http, searchIndexService }) { + let searchEngine = searchEngineRegistry.getSearchEngine(); + if (!searchEngine) { + searchEngine = new LunrSearchEngine({ + logger: loggerToWinstonLogger(logger), + }); + } + + const collators = searchIndexRegistry.getCollators(); + const decorators = searchIndexRegistry.getDecorators(); + + await searchIndexService.start({ + searchEngine, + collators, + decorators, + }); + + const router = await createRouter({ + config, + permissions, + logger: loggerToWinstonLogger(logger), + engine: searchEngine, + types: searchIndexService.getDocumentTypes(), + }); + + http.use(router); + }, + }); + }, +}); diff --git a/plugins/search-backend/src/plugin.ts b/plugins/search-backend/src/plugin.ts deleted file mode 100644 index 7c01ddc607..0000000000 --- a/plugins/search-backend/src/plugin.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - coreServices, - createBackendPlugin, -} from '@backstage/backend-plugin-api'; -import { loggerToWinstonLogger } from '@backstage/backend-common'; -import { - RegisterCollatorParameters, - RegisterDecoratorParameters, - LunrSearchEngine, -} from '@backstage/plugin-search-backend-node'; -import { - searchIndexBuilderService, - searchIndexRegistryExtensionPoint, - SearchIndexRegistryExtensionPoint, - SearchEngineRegistryExtensionPoint, - searchEngineRegistryExtensionPoint, -} from '@backstage/plugin-search-backend-node/alpha'; - -import { createRouter } from './service/router'; -import { SearchEngine } from '@backstage/plugin-search-common'; - -class SearchIndexRegistry implements SearchIndexRegistryExtensionPoint { - private collators: RegisterCollatorParameters[] = []; - private decorators: RegisterDecoratorParameters[] = []; - - public addCollator(options: RegisterCollatorParameters): void { - this.collators.push(options); - } - - public addDecorator(options: RegisterDecoratorParameters): void { - this.decorators.push(options); - } - - public getCollators(): RegisterCollatorParameters[] { - return this.collators; - } - - public getDecorators(): RegisterDecoratorParameters[] { - return this.decorators; - } -} - -class SearchEngineRegistry implements SearchEngineRegistryExtensionPoint { - private searchEngine: SearchEngine | null = null; - - public setSearchEngine(searchEngine: SearchEngine): void { - if (this.searchEngine) { - throw new Error('Multiple Search engines is not supported at this time'); - } - this.searchEngine = searchEngine; - } - - public getSearchEngine(): SearchEngine | null { - return this.searchEngine; - } -} - -export const searchPlugin = createBackendPlugin({ - pluginId: 'search', - register(env) { - const searchIndexRegistry = new SearchIndexRegistry(); - env.registerExtensionPoint( - searchIndexRegistryExtensionPoint, - searchIndexRegistry, - ); - - const searchEngineRegistry = new SearchEngineRegistry(); - env.registerExtensionPoint( - searchEngineRegistryExtensionPoint, - searchEngineRegistry, - ); - - env.registerInit({ - deps: { - logger: coreServices.logger, - config: coreServices.config, - permissions: coreServices.permissions, - http: coreServices.httpRouter, - searchIndexBuilder: searchIndexBuilderService, - }, - async init({ config, logger, permissions, http, searchIndexBuilder }) { - let searchEngine = searchEngineRegistry.getSearchEngine(); - if (!searchEngine) { - searchEngine = new LunrSearchEngine({ - logger: loggerToWinstonLogger(logger), - }); - } - - const collators = searchIndexRegistry.getCollators(); - const decorators = searchIndexRegistry.getDecorators(); - - const { scheduler } = await searchIndexBuilder.build({ - searchEngine, - collators, - decorators, - }); - scheduler.start(); - - const router = await createRouter({ - config, - permissions, - logger: loggerToWinstonLogger(logger), - engine: searchEngine, - types: searchIndexBuilder.getDocumentTypes(), - }); - - http.use(router); - }, - }); - }, -});