import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { IndexableDocument, SearchQuery, IndexableResultSet } from '@backstage/plugin-search-common'; import { BatchSearchEngineIndexer, SearchEngine } from '@backstage/plugin-search-backend-node'; import { Config } from '@backstage/config'; import { ConnectionOptions } from 'node:tls'; import * as _elastic_elasticsearch_lib_Helpers from '@elastic/elasticsearch/lib/Helpers'; import * as _elastic_elasticsearch_lib_Transport from '@elastic/elasticsearch/lib/Transport'; import * as _elastic_elasticsearch from '@elastic/elasticsearch'; import * as _opensearch_project_opensearch_lib_Transport_js from '@opensearch-project/opensearch/lib/Transport.js'; import * as _opensearch_project_opensearch from '@opensearch-project/opensearch'; import { Readable } from 'node:stream'; /** * Typeguard to differentiate ElasticSearch client options which are compatible * with OpenSearch vs. ElasticSearch clients. Useful when calling the * {@link ElasticSearchSearchEngine.newClient} method. * * @public */ declare const isOpenSearchCompatible: (opts: ElasticSearchClientOptions) => opts is OpenSearchElasticSearchClientOptions; /** * Options used to configure the `@elastic/elasticsearch` client or the * `@opensearch-project/opensearch` client, depending on the given config. It * will be passed as an argument to the * {@link ElasticSearchSearchEngine.newClient} method. * * @public */ type ElasticSearchClientOptions = ElasticSearchElasticSearchClientOptions | OpenSearchElasticSearchClientOptions; /** * Options used to configure the `@opensearch-project/opensearch` client. * * They are drawn from the `ClientOptions` class of `@opensearch-project/opensearch`, * but are maintained separately so that this interface is not coupled to it. * * @public */ interface OpenSearchElasticSearchClientOptions extends BaseElasticSearchClientOptions { provider?: 'aws' | 'opensearch'; region?: string; service?: 'es' | 'aoss'; auth?: OpenSearchAuth; connection?: OpenSearchConnectionConstructor; node?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[]; nodes?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[]; } /** * Options used to configure the `@elastic/elasticsearch` client. * * They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`, * but are maintained separately so that this interface is not coupled to it. * * @public */ interface ElasticSearchElasticSearchClientOptions extends BaseElasticSearchClientOptions { provider?: 'elastic'; auth?: ElasticSearchAuth; Connection?: ElasticSearchConnectionConstructor; node?: string | string[] | ElasticSearchNodeOptions | ElasticSearchNodeOptions[]; nodes?: string | string[] | ElasticSearchNodeOptions | ElasticSearchNodeOptions[]; cloud?: { id: string; username?: string; password?: string; }; } /** * Base client options that are shared across `@opensearch-project/opensearch` * and `@elastic/elasticsearch` clients. * * @public */ interface BaseElasticSearchClientOptions { Transport?: ElasticSearchTransportConstructor; maxRetries?: number; requestTimeout?: number; pingTimeout?: number; sniffInterval?: number | boolean; sniffOnStart?: boolean; sniffEndpoint?: string; sniffOnConnectionFault?: boolean; resurrectStrategy?: 'ping' | 'optimistic' | 'none'; suggestCompression?: boolean; compression?: 'gzip'; ssl?: ConnectionOptions; agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false; nodeFilter?: (connection: any) => boolean; nodeSelector?: ((connections: any[]) => any) | string; headers?: Record; opaqueIdPrefix?: string; name?: string | symbol; proxy?: string | URL; enableMetaHeader?: boolean; disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor'; } /** * @public */ type OpenSearchAuth = { username: string; password: string; }; /** * @public */ type ElasticSearchAuth = OpenSearchAuth | { apiKey: string | { id: string; api_key: string; }; }; /** * @public */ interface ElasticSearchNodeOptions { url: URL; id?: string; agent?: ElasticSearchAgentOptions; ssl?: ConnectionOptions; headers?: Record; roles?: { master: boolean; data: boolean; ingest: boolean; ml: boolean; }; } /** * @public */ interface OpenSearchNodeOptions { url: URL; id?: string; agent?: ElasticSearchAgentOptions; ssl?: ConnectionOptions; headers?: Record; roles?: { master: boolean; data: boolean; ingest: boolean; }; } /** * @public */ interface ElasticSearchAgentOptions { keepAlive?: boolean; keepAliveMsecs?: number; maxSockets?: number; maxFreeSockets?: number; } /** * @public */ interface ElasticSearchConnectionConstructor { new (opts?: any): any; statuses: { ALIVE: string; DEAD: string; }; roles: { MASTER: string; DATA: string; INGEST: string; ML: string; }; } /** * @public */ interface OpenSearchConnectionConstructor { new (opts?: any): any; statuses: { ALIVE: string; DEAD: string; }; roles: { MASTER: string; DATA: string; INGEST: string; }; } /** * @public */ interface ElasticSearchTransportConstructor { new (opts?: any): any; sniffReasons: { SNIFF_ON_START: string; SNIFF_INTERVAL: string; SNIFF_ON_CONNECTION_FAULT: string; DEFAULT: string; }; } /** * Elasticsearch specific index template * @public */ type ElasticSearchCustomIndexTemplate = { name: string; body: ElasticSearchCustomIndexTemplateBody; }; /** * Elasticsearch specific index template body * @public */ type ElasticSearchCustomIndexTemplateBody = { /** * Array of wildcard (*) expressions used to match the names of data streams and indices during creation. */ index_patterns: string[]; /** * An ordered list of component template names. * Component templates are merged in the order specified, * meaning that the last component template specified has the highest precedence. */ composed_of?: string[]; /** * See available properties of template * https://www.elastic.co/guide/en/elasticsearch/reference/7.15/indices-put-template.html#put-index-template-api-request-body */ template?: Record; }; /** * @public */ type ElasticSearchAliasAction = { remove: { index: any; alias: any; }; add?: undefined; } | { add: { indices: any; alias: any; index?: undefined; }; remove?: undefined; } | { add: { index: any; alias: any; indices?: undefined; }; remove?: undefined; } | undefined; /** * @public */ type ElasticSearchIndexAction = { index: { _index: string; [key: string]: any; }; }; /** * A wrapper class that exposes logical methods that are conditionally fired * against either a configured Elasticsearch client or a configured Opensearch * client. * * This is necessary because, despite its intention to be API-compatible, the * opensearch client does not support API key-based authentication. This is * also the sanest way to accomplish this while making typescript happy. * * In the future, if the differences between implementations become * unmaintainably divergent, we should split out the Opensearch and * Elasticsearch search engine implementations. * * @public */ declare class ElasticSearchClientWrapper { private readonly elasticSearchClient; private readonly openSearchClient; private constructor(); static fromClientOptions(options: ElasticSearchClientOptions): ElasticSearchClientWrapper; search(options: { index: string | string[]; body: Object; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; bulk(bulkOptions: { datasource: Readable; onDocument: (doc: any) => ElasticSearchIndexAction; refreshOnCompletion?: string | boolean; }): _elastic_elasticsearch_lib_Helpers.BulkHelper<_elastic_elasticsearch_lib_Helpers.BulkStats>; putIndexTemplate(template: ElasticSearchCustomIndexTemplate): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; listIndices(options: { index: string; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; indexExists(options: { index: string | string[]; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse>; deleteIndex(options: { index: string | string[]; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; /** * @deprecated unused by the ElasticSearch Engine, will be removed in the future */ getAliases(options: { aliases: string[]; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; createIndex(options: { index: string; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; updateAliases(options: { actions: ElasticSearchAliasAction[]; }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse, unknown>>; } /** * Options for instantiate ElasticSearchSearchEngineIndexer * @public */ type ElasticSearchSearchEngineIndexerOptions = { type: string; indexPrefix: string; indexSeparator: string; alias: string; logger: LoggerService; elasticSearchClientWrapper: ElasticSearchClientWrapper; batchSize: number; batchKeyField?: string; skipRefresh?: boolean; }; /** * Elasticsearch specific search engine indexer. * @public */ declare class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { private processed; private removableIndices; private readonly startTimestamp; private readonly type; readonly indexName: string; private readonly indexPrefix; private readonly indexSeparator; private readonly alias; private readonly logger; private readonly sourceStream; private readonly elasticSearchClientWrapper; private configuredBatchSize; private bulkResult; private bulkClientError?; constructor(options: ElasticSearchSearchEngineIndexerOptions); initialize(): Promise; index(documents: IndexableDocument[]): Promise; finalize(): Promise; /** * Ensures that the number of documents sent over the wire to ES matches the * number of documents this stream has received so far. This helps manage * backpressure in other parts of the indexing pipeline. */ private isReady; private constructIndexName; } /** * A provider that supplies authentication headers for Elasticsearch/OpenSearch requests. * * @remarks * * This interface allows for dynamic authentication mechanisms such as bearer tokens * that need to be refreshed or rotated. The `getAuthHeaders` method is called before * each request to the Elasticsearch/OpenSearch cluster, allowing for just-in-time * token retrieval and automatic rotation. * * @example * * ```ts * const authProvider: ElasticSearchAuthProvider = { * async getAuthHeaders() { * const token = await myTokenService.getToken(); * return { Authorization: `Bearer ${token}` }; * }, * }; * ``` * * @public */ interface ElasticSearchAuthProvider { /** * Returns authentication headers to be included in requests to Elasticsearch/OpenSearch. * * @remarks * * This method is called before each request, allowing for dynamic token refresh * and rotation. Implementations should handle caching internally if needed to * avoid excessive token generation. * * @returns A promise that resolves to a record of header names and values */ getAuthHeaders(): Promise>; } /** * Extension point for providing custom authentication to the Elasticsearch search engine. * * @remarks * * Use this extension point to provide dynamic authentication mechanisms such as * bearer tokens with automatic rotation. When an auth provider is set, it takes * precedence over any static authentication configured in app-config.yaml. * * @example * * ```ts * import { createBackendModule } from '@backstage/backend-plugin-api'; * import { elasticsearchAuthExtensionPoint } from '@backstage/plugin-search-backend-module-elasticsearch'; * * export default createBackendModule({ * pluginId: 'search', * moduleId: 'elasticsearch-custom-auth', * register(env) { * env.registerInit({ * deps: { * elasticsearchAuth: elasticsearchAuthExtensionPoint, * }, * async init({ elasticsearchAuth }) { * elasticsearchAuth.setAuthProvider({ * async getAuthHeaders() { * const token = await fetchTokenFromIdentityService(); * return { Authorization: `Bearer ${token}` }; * }, * }); * }, * }); * }, * }); * ``` * * @public */ interface ElasticSearchAuthExtensionPoint { /** * Sets the authentication provider for the Elasticsearch search engine. * * @remarks * * This method can only be called once. Subsequent calls will throw an error. * The auth provider takes precedence over static authentication configuration. * * @param provider - The authentication provider to use */ setAuthProvider(provider: ElasticSearchAuthProvider): void; } /** * Extension point used to customize Elasticsearch/OpenSearch authentication. * * @public */ declare const elasticsearchAuthExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint; /** * Search query that the elasticsearch engine understands. * @public */ type ElasticSearchConcreteQuery = { documentTypes?: string[]; elasticSearchQuery: Object; pageSize: number; }; /** * Options available for the Elasticsearch specific query translator. * @public */ type ElasticSearchQueryTranslatorOptions = { highlightOptions?: ElasticSearchHighlightConfig; queryOptions?: ElasticSearchQueryConfig; }; /** * Elasticsearch specific query translator. * @public */ type ElasticSearchQueryTranslator = (query: SearchQuery, options?: ElasticSearchQueryTranslatorOptions) => ElasticSearchConcreteQuery; /** * Options for instantiate ElasticSearchSearchEngine * @public */ type ElasticSearchOptions = { logger: LoggerService; config: Config; aliasPostfix?: string; indexPrefix?: string; translator?: ElasticSearchQueryTranslator; /** * An optional authentication provider for dynamic authentication. * * @remarks * * When provided, this auth provider will be used to inject authentication * headers into each request to Elasticsearch/OpenSearch. This is useful * for scenarios requiring dynamic tokens (e.g., bearer tokens with rotation). * * The auth provider takes precedence over static authentication configured * in app-config.yaml. */ authProvider?: ElasticSearchAuthProvider; }; /** * @public */ type ElasticSearchHighlightOptions = { fragmentDelimiter?: string; fragmentSize?: number; numFragments?: number; }; /** * @public */ type ElasticSearchQueryConfig = { fuzziness?: string | number; prefixLength?: number; }; /** * @public */ type ElasticSearchHighlightConfig = { fragmentDelimiter: string; fragmentSize: number; numFragments: number; preTag: string; postTag: string; }; /** * @public */ declare class ElasticSearchSearchEngine implements SearchEngine { private readonly elasticSearchClientWrapper; private readonly highlightOptions; private readonly queryOptions?; private readonly elasticSearchClientOptions; private readonly aliasPostfix; private readonly indexPrefix; private readonly logger; private readonly batchSize; private readonly batchKeyField?; constructor(elasticSearchClientOptions: ElasticSearchClientOptions, aliasPostfix: string, indexPrefix: string, logger: LoggerService, batchSize: number, batchKeyField?: string, highlightOptions?: ElasticSearchHighlightOptions, queryOptions?: ElasticSearchQueryConfig); static fromConfig(options: ElasticSearchOptions): Promise; /** * Create a custom search client from the derived search client configuration. * This need not be the same client that the engine uses internally. * * @example Instantiate an instance of an Elasticsearch client. * * ```ts * import { isOpenSearchCompatible } from '@backstage/plugin-search-backend-module-elasticsearch'; * import { Client } from '@elastic/elasticsearch'; * * const client = searchEngine.newClient(options => { * // This type guard ensures options are compatible with either OpenSearch * // or Elasticsearch client constructors. * if (!isOpenSearchCompatible(options)) { * return new Client(options); * } * throw new Error('Incompatible options provided'); * }); * ``` */ newClient(create: (options: ElasticSearchClientOptions) => T): T; protected translator(query: SearchQuery, options?: ElasticSearchQueryTranslatorOptions): ElasticSearchConcreteQuery; setTranslator(translator: ElasticSearchQueryTranslator): void; setIndexTemplate(template: ElasticSearchCustomIndexTemplate): Promise; getIndexer(type: string): Promise; query(query: SearchQuery): Promise; private readonly indexSeparator; private getTypeFromIndex; private constructSearchAlias; private static createElasticSearchClientOptions; private static readIndexTemplateConfig; } /** * @public */ declare function decodePageCursor(pageCursor?: string): { page: number; }; /** @public */ interface ElasticSearchQueryTranslatorExtensionPoint { setTranslator(translator: ElasticSearchQueryTranslator): void; } /** * Extension point used to customize the ElasticSearch query translator. * * @public */ declare const elasticsearchTranslatorExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint; /** * Search backend module for the Elasticsearch engine. * * @public */ declare const _default: _backstage_backend_plugin_api.BackendFeature; export { ElasticSearchClientWrapper, ElasticSearchSearchEngine, ElasticSearchSearchEngineIndexer, decodePageCursor as decodeElasticSearchPageCursor, _default as default, elasticsearchAuthExtensionPoint, elasticsearchTranslatorExtensionPoint, isOpenSearchCompatible }; export type { BaseElasticSearchClientOptions, ElasticSearchAgentOptions, ElasticSearchAliasAction, ElasticSearchAuth, ElasticSearchAuthExtensionPoint, ElasticSearchAuthProvider, ElasticSearchClientOptions, ElasticSearchConcreteQuery, ElasticSearchConnectionConstructor, ElasticSearchCustomIndexTemplate, ElasticSearchCustomIndexTemplateBody, ElasticSearchElasticSearchClientOptions, ElasticSearchHighlightConfig, ElasticSearchHighlightOptions, ElasticSearchIndexAction, ElasticSearchNodeOptions, ElasticSearchOptions, ElasticSearchQueryConfig, ElasticSearchQueryTranslator, ElasticSearchQueryTranslatorExtensionPoint, ElasticSearchQueryTranslatorOptions, ElasticSearchSearchEngineIndexerOptions, ElasticSearchTransportConstructor, OpenSearchAuth, OpenSearchConnectionConstructor, OpenSearchElasticSearchClientOptions, OpenSearchNodeOptions };