@backstage/plugin-search-backend-module-elasticsearch 1.8.8-next.2 → 2.0.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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # @backstage/plugin-search-backend-module-elasticsearch
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 3753c36: **BREAKING**: Upgraded the Elasticsearch client to version 8, requiring at least version 8.19 - the only 8.x release line still under support, [following the end of life of Elasticsearch 7.x and earlier 8.x lines](https://endoflife.date/elasticsearch). Elasticsearch 7.x clusters are no longer supported.
8
+
9
+ If you use the `elastic` provider or connect to a plain Elasticsearch node, make sure your cluster is running Elasticsearch 8.19 or later before upgrading. The `aws` and `opensearch` providers keep using the OpenSearch client and are unaffected. Existing TLS settings continue to work without any configuration changes.
10
+
11
+ The methods of the `ElasticSearchClientWrapper` now return a normalized response that exposes `body`, `statusCode`, `headers` and `warnings` for both providers, instead of the client specific response types. Code that relies on the raw client types or reads the `meta` property of a response needs to be adjusted.
12
+
13
+ ### Patch Changes
14
+
15
+ - fe6ace6: Added optional `accountId` config to `search.elasticsearch` for resolving account-specific AWS credentials, enabling support for `webIdentityTokenFile` and `accountDefaults` when using AWS OpenSearch.
16
+ - b11c9b4: Fixed a bug where an empty document type list could result in querying all indices instead of returning empty results.
17
+ - Updated dependencies
18
+ - @backstage/plugin-search-backend-node@1.4.8
19
+ - @backstage/config@1.3.9
20
+ - @backstage/backend-plugin-api@1.10.1
21
+ - @backstage/integration-aws-node@0.2.2
22
+ - @backstage/plugin-search-common@1.2.25
23
+
3
24
  ## 1.8.8-next.2
4
25
 
5
26
  ### Patch Changes
@@ -62,7 +62,7 @@
62
62
  "description": "Delimiter string used to concatenate fragments. Defaults to \" ... \"."
63
63
  }
64
64
  },
65
- "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/highlighting.html"
65
+ "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/8.19/highlighting.html"
66
66
  },
67
67
  "queryOptions": {
68
68
  "type": "object",
@@ -113,7 +113,7 @@
113
113
  "template": {
114
114
  "type": "object",
115
115
  "additionalProperties": {},
116
- "description": "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"
116
+ "description": "See available properties of template https://www.elastic.co/guide/en/elasticsearch/reference/8.19/indices-put-template.html#put-index-template-api-request-body"
117
117
  }
118
118
  },
119
119
  "required": [
@@ -202,7 +202,7 @@
202
202
  "description": "Delimiter string used to concatenate fragments. Defaults to \" ... \"."
203
203
  }
204
204
  },
205
- "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/highlighting.html"
205
+ "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/8.19/highlighting.html"
206
206
  },
207
207
  "queryOptions": {
208
208
  "type": "object",
@@ -253,7 +253,7 @@
253
253
  "template": {
254
254
  "type": "object",
255
255
  "additionalProperties": {},
256
- "description": "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"
256
+ "description": "See available properties of template https://www.elastic.co/guide/en/elasticsearch/reference/8.19/indices-put-template.html#put-index-template-api-request-body"
257
257
  }
258
258
  },
259
259
  "required": [
@@ -369,7 +369,7 @@
369
369
  "description": "Delimiter string used to concatenate fragments. Defaults to \" ... \"."
370
370
  }
371
371
  },
372
- "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/highlighting.html"
372
+ "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/8.19/highlighting.html"
373
373
  },
374
374
  "queryOptions": {
375
375
  "type": "object",
@@ -420,7 +420,7 @@
420
420
  "template": {
421
421
  "type": "object",
422
422
  "additionalProperties": {},
423
- "description": "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"
423
+ "description": "See available properties of template https://www.elastic.co/guide/en/elasticsearch/reference/8.19/indices-put-template.html#put-index-template-api-request-body"
424
424
  }
425
425
  },
426
426
  "required": [
@@ -538,7 +538,7 @@
538
538
  "description": "Delimiter string used to concatenate fragments. Defaults to \" ... \"."
539
539
  }
540
540
  },
541
- "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/highlighting.html"
541
+ "description": "Options for configuring highlight settings See https://www.elastic.co/guide/en/elasticsearch/reference/8.19/highlighting.html"
542
542
  },
543
543
  "queryOptions": {
544
544
  "type": "object",
@@ -589,7 +589,7 @@
589
589
  "template": {
590
590
  "type": "object",
591
591
  "additionalProperties": {},
592
- "description": "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"
592
+ "description": "See available properties of template https://www.elastic.co/guide/en/elasticsearch/reference/8.19/indices-put-template.html#put-index-template-api-request-body"
593
593
  }
594
594
  },
595
595
  "required": [
@@ -41,32 +41,9 @@ function createOpenSearchAuthTransport(authProvider) {
41
41
  }
42
42
  function createElasticSearchAuthTransport(authProvider) {
43
43
  class AuthTransport extends elasticsearch.Transport {
44
- request(params, options, callback) {
45
- if (typeof options === "function") {
46
- const cb = options;
47
- authProvider.getAuthHeaders().then((authHeaders) => {
48
- const mergedOptions = {
49
- headers: authHeaders
50
- };
51
- return super.request(params, mergedOptions, cb);
52
- }).catch(cb);
53
- return { abort: () => {
54
- } };
55
- }
56
- if (callback !== void 0) {
57
- authProvider.getAuthHeaders().then((authHeaders) => {
58
- const mergedOptions = {
59
- ...options,
60
- headers: {
61
- ...options?.headers,
62
- ...authHeaders
63
- }
64
- };
65
- return super.request(params, mergedOptions, callback);
66
- }).catch(callback);
67
- return { abort: () => {
68
- } };
69
- }
44
+ // The Elasticsearch v8 client only supports the promise-based transport
45
+ // signature, so there is no callback variant to handle here.
46
+ request(params, options) {
70
47
  const result = authProvider.getAuthHeaders().then((authHeaders) => {
71
48
  const mergedOptions = {
72
49
  ...options,
@@ -1 +1 @@
1
- {"version":3,"file":"ElasticSearchAuthTransport.cjs.js","sources":["../../src/engines/ElasticSearchAuthTransport.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Transport as OpenSearchTransport } from '@opensearch-project/opensearch';\nimport { Transport as ElasticSearchTransport } from '@elastic/elasticsearch';\nimport { ElasticSearchAuthProvider } from '../auth';\nimport { ElasticSearchTransportConstructor } from './ElasticSearchClientOptions';\n\n/**\n * Creates a custom OpenSearch Transport class that injects authentication headers\n * from the provided auth provider before each request.\n *\n * @param authProvider - The authentication provider to use for getting headers\n * @returns A Transport class constructor that can be used with the OpenSearch client\n *\n * @internal\n */\nexport function createOpenSearchAuthTransport(\n authProvider: ElasticSearchAuthProvider,\n): ElasticSearchTransportConstructor {\n class AuthTransport extends OpenSearchTransport {\n request(\n params: any,\n optionsOrCallback: any = {},\n maybeCallback?: any,\n ): any {\n // options is optional, so if it's a function, it's the callback\n const isOptionsCallback = typeof optionsOrCallback === 'function';\n const options = isOptionsCallback ? {} : optionsOrCallback;\n const callback = isOptionsCallback ? optionsOrCallback : maybeCallback;\n\n // If callback style, wrap it to inject headers\n if (callback !== undefined) {\n authProvider\n .getAuthHeaders()\n .then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions, callback);\n })\n .catch(callback);\n\n // Return an abort-able object similar to the AWS transport\n return {\n abort: () => {},\n };\n }\n\n // Promise style\n return authProvider.getAuthHeaders().then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions);\n });\n }\n }\n\n return AuthTransport as unknown as ElasticSearchTransportConstructor;\n}\n\n/**\n * Creates a custom Elasticsearch Transport class that injects authentication headers\n * from the provided auth provider before each request.\n *\n * @param authProvider - The authentication provider to use for getting headers\n * @returns A Transport class constructor that can be used with the Elasticsearch client\n *\n * @internal\n */\nexport function createElasticSearchAuthTransport(\n authProvider: ElasticSearchAuthProvider,\n): ElasticSearchTransportConstructor {\n class AuthTransport extends ElasticSearchTransport {\n request(params: any, options?: any, callback?: any): any {\n // Handle overloaded signatures\n if (typeof options === 'function') {\n // Callback style without options\n const cb = options;\n authProvider\n .getAuthHeaders()\n .then(authHeaders => {\n const mergedOptions = {\n headers: authHeaders,\n };\n return super.request(params, mergedOptions, cb);\n })\n .catch(cb);\n\n return { abort: () => {} };\n }\n\n if (callback !== undefined) {\n // Callback style with options\n authProvider\n .getAuthHeaders()\n .then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options?.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions, callback);\n })\n .catch(callback);\n\n return { abort: () => {} };\n }\n\n // Promise style\n const result = authProvider.getAuthHeaders().then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options?.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions);\n });\n\n // Add abort method to match TransportRequestPromise interface\n (result as any).abort = () => {};\n return result;\n }\n }\n\n return AuthTransport as unknown as ElasticSearchTransportConstructor;\n}\n"],"names":["OpenSearchTransport","ElasticSearchTransport"],"mappings":"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"}
1
+ {"version":3,"file":"ElasticSearchAuthTransport.cjs.js","sources":["../../src/engines/ElasticSearchAuthTransport.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Transport as OpenSearchTransport } from '@opensearch-project/opensearch';\nimport { Transport as ElasticSearchTransport } from '@elastic/elasticsearch';\nimport { ElasticSearchAuthProvider } from '../auth';\nimport { ElasticSearchTransportConstructor } from './ElasticSearchClientOptions';\n\n/**\n * Creates a custom OpenSearch Transport class that injects authentication headers\n * from the provided auth provider before each request.\n *\n * @param authProvider - The authentication provider to use for getting headers\n * @returns A Transport class constructor that can be used with the OpenSearch client\n *\n * @internal\n */\nexport function createOpenSearchAuthTransport(\n authProvider: ElasticSearchAuthProvider,\n): ElasticSearchTransportConstructor {\n class AuthTransport extends OpenSearchTransport {\n request(\n params: any,\n optionsOrCallback: any = {},\n maybeCallback?: any,\n ): any {\n // options is optional, so if it's a function, it's the callback\n const isOptionsCallback = typeof optionsOrCallback === 'function';\n const options = isOptionsCallback ? {} : optionsOrCallback;\n const callback = isOptionsCallback ? optionsOrCallback : maybeCallback;\n\n // If callback style, wrap it to inject headers\n if (callback !== undefined) {\n authProvider\n .getAuthHeaders()\n .then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions, callback);\n })\n .catch(callback);\n\n // Return an abort-able object similar to the AWS transport\n return {\n abort: () => {},\n };\n }\n\n // Promise style\n return authProvider.getAuthHeaders().then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions);\n });\n }\n }\n\n return AuthTransport as unknown as ElasticSearchTransportConstructor;\n}\n\n/**\n * Creates a custom Elasticsearch Transport class that injects authentication headers\n * from the provided auth provider before each request.\n *\n * @param authProvider - The authentication provider to use for getting headers\n * @returns A Transport class constructor that can be used with the Elasticsearch client\n *\n * @internal\n */\nexport function createElasticSearchAuthTransport(\n authProvider: ElasticSearchAuthProvider,\n): ElasticSearchTransportConstructor {\n class AuthTransport extends ElasticSearchTransport {\n // The Elasticsearch v8 client only supports the promise-based transport\n // signature, so there is no callback variant to handle here.\n request(params: any, options?: any): any {\n const result = authProvider.getAuthHeaders().then(authHeaders => {\n const mergedOptions = {\n ...options,\n headers: {\n ...options?.headers,\n ...authHeaders,\n },\n };\n return super.request(params, mergedOptions);\n });\n\n // Add abort method to match TransportRequestPromise interface\n (result as any).abort = () => {};\n return result;\n }\n }\n\n return AuthTransport as unknown as ElasticSearchTransportConstructor;\n}\n"],"names":["OpenSearchTransport","ElasticSearchTransport"],"mappings":";;;;;AA8BO,SAAS,8BACd,YAAA,EACmC;AAAA,EACnC,MAAM,sBAAsBA,oBAAA,CAAoB;AAAA,IAC9C,OAAA,CACE,MAAA,EACA,iBAAA,GAAyB,IACzB,aAAA,EACK;AAEL,MAAA,MAAM,iBAAA,GAAoB,OAAO,iBAAA,KAAsB,UAAA;AACvD,MAAA,MAAM,OAAA,GAAU,iBAAA,GAAoB,EAAC,GAAI,iBAAA;AACzC,MAAA,MAAM,QAAA,GAAW,oBAAoB,iBAAA,GAAoB,aAAA;AAGzD,MAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,QAAA,YAAA,CACG,cAAA,EAAe,CACf,IAAA,CAAK,CAAA,WAAA,KAAe;AACnB,UAAA,MAAM,aAAA,GAAgB;AAAA,YACpB,GAAG,OAAA;AAAA,YACH,OAAA,EAAS;AAAA,cACP,GAAG,OAAA,CAAQ,OAAA;AAAA,cACX,GAAG;AAAA;AACL,WACF;AACA,UAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,MAAA,EAAQ,aAAA,EAAe,QAAQ,CAAA;AAAA,QACtD,CAAC,CAAA,CACA,KAAA,CAAM,QAAQ,CAAA;AAGjB,QAAA,OAAO;AAAA,UACL,OAAO,MAAM;AAAA,UAAC;AAAA,SAChB;AAAA,MACF;AAGA,MAAA,OAAO,YAAA,CAAa,cAAA,EAAe,CAAE,IAAA,CAAK,CAAA,WAAA,KAAe;AACvD,QAAA,MAAM,aAAA,GAAgB;AAAA,UACpB,GAAG,OAAA;AAAA,UACH,OAAA,EAAS;AAAA,YACP,GAAG,OAAA,CAAQ,OAAA;AAAA,YACX,GAAG;AAAA;AACL,SACF;AACA,QAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,MAAA,EAAQ,aAAa,CAAA;AAAA,MAC5C,CAAC,CAAA;AAAA,IACH;AAAA;AAGF,EAAA,OAAO,aAAA;AACT;AAWO,SAAS,iCACd,YAAA,EACmC;AAAA,EACnC,MAAM,sBAAsBC,uBAAA,CAAuB;AAAA;AAAA;AAAA,IAGjD,OAAA,CAAQ,QAAa,OAAA,EAAoB;AACvC,MAAA,MAAM,MAAA,GAAS,YAAA,CAAa,cAAA,EAAe,CAAE,KAAK,CAAA,WAAA,KAAe;AAC/D,QAAA,MAAM,aAAA,GAAgB;AAAA,UACpB,GAAG,OAAA;AAAA,UACH,OAAA,EAAS;AAAA,YACP,GAAG,OAAA,EAAS,OAAA;AAAA,YACZ,GAAG;AAAA;AACL,SACF;AACA,QAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,MAAA,EAAQ,aAAa,CAAA;AAAA,MAC5C,CAAC,CAAA;AAGD,MAAC,MAAA,CAAe,QAAQ,MAAM;AAAA,MAAC,CAAA;AAC/B,MAAA,OAAO,MAAA;AAAA,IACT;AAAA;AAGF,EAAA,OAAO,aAAA;AACT;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ElasticSearchClientOptions.cjs.js","sources":["../../src/engines/ElasticSearchClientOptions.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { ConnectionOptions as TLSConnectionOptions } from 'node:tls';\n\n/**\n * Typeguard to differentiate ElasticSearch client options which are compatible\n * with OpenSearch vs. ElasticSearch clients. Useful when calling the\n * {@link ElasticSearchSearchEngine.newClient} method.\n *\n * @public\n */\nexport const isOpenSearchCompatible = (\n opts: ElasticSearchClientOptions,\n): opts is OpenSearchElasticSearchClientOptions => {\n return ['aws', 'opensearch'].includes(opts?.provider ?? '');\n};\n\n/**\n * Options used to configure the `@elastic/elasticsearch` client or the\n * `@opensearch-project/opensearch` client, depending on the given config. It\n * will be passed as an argument to the\n * {@link ElasticSearchSearchEngine.newClient} method.\n *\n * @public\n */\nexport type ElasticSearchClientOptions =\n | ElasticSearchElasticSearchClientOptions\n | OpenSearchElasticSearchClientOptions;\n\n/**\n * Options used to configure the `@opensearch-project/opensearch` client.\n *\n * They are drawn from the `ClientOptions` class of `@opensearch-project/opensearch`,\n * but are maintained separately so that this interface is not coupled to it.\n *\n * @public\n */\nexport interface OpenSearchElasticSearchClientOptions\n extends BaseElasticSearchClientOptions {\n provider?: 'aws' | 'opensearch';\n region?: string;\n service?: 'es' | 'aoss';\n auth?: OpenSearchAuth;\n connection?: OpenSearchConnectionConstructor;\n node?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[];\n nodes?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[];\n}\n\n/**\n * Options used to configure the `@elastic/elasticsearch` client.\n *\n * They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`,\n * but are maintained separately so that this interface is not coupled to it.\n *\n * @public\n */\nexport interface ElasticSearchElasticSearchClientOptions\n extends BaseElasticSearchClientOptions {\n provider?: 'elastic';\n auth?: ElasticSearchAuth;\n Connection?: ElasticSearchConnectionConstructor;\n node?:\n | string\n | string[]\n | ElasticSearchNodeOptions\n | ElasticSearchNodeOptions[];\n nodes?:\n | string\n | string[]\n | ElasticSearchNodeOptions\n | ElasticSearchNodeOptions[];\n cloud?: {\n id: string;\n username?: string;\n password?: string;\n };\n}\n\n/**\n * Base client options that are shared across `@opensearch-project/opensearch`\n * and `@elastic/elasticsearch` clients.\n *\n * @public\n */\nexport interface BaseElasticSearchClientOptions {\n Transport?: ElasticSearchTransportConstructor;\n maxRetries?: number;\n requestTimeout?: number;\n pingTimeout?: number;\n sniffInterval?: number | boolean;\n sniffOnStart?: boolean;\n sniffEndpoint?: string;\n sniffOnConnectionFault?: boolean;\n resurrectStrategy?: 'ping' | 'optimistic' | 'none';\n suggestCompression?: boolean;\n compression?: 'gzip';\n ssl?: TLSConnectionOptions;\n agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false;\n nodeFilter?: (connection: any) => boolean;\n nodeSelector?: ((connections: any[]) => any) | string;\n headers?: Record<string, any>;\n opaqueIdPrefix?: string;\n name?: string | symbol;\n proxy?: string | URL;\n enableMetaHeader?: boolean;\n disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor';\n}\n\n/**\n * @public\n */\nexport type OpenSearchAuth = {\n username: string;\n password: string;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchAuth =\n | OpenSearchAuth\n | {\n apiKey:\n | string\n | {\n id: string;\n api_key: string;\n };\n };\n\n/**\n * @public\n */\nexport interface ElasticSearchNodeOptions {\n url: URL;\n id?: string;\n agent?: ElasticSearchAgentOptions;\n ssl?: TLSConnectionOptions;\n headers?: Record<string, any>;\n roles?: {\n master: boolean;\n data: boolean;\n ingest: boolean;\n ml: boolean;\n };\n}\n\n/**\n * @public\n */\nexport interface OpenSearchNodeOptions {\n url: URL;\n id?: string;\n agent?: ElasticSearchAgentOptions;\n ssl?: TLSConnectionOptions;\n headers?: Record<string, any>;\n roles?: {\n master: boolean;\n data: boolean;\n ingest: boolean;\n };\n}\n\n/**\n * @public\n */\nexport interface ElasticSearchAgentOptions {\n keepAlive?: boolean;\n keepAliveMsecs?: number;\n maxSockets?: number;\n maxFreeSockets?: number;\n}\n\n/**\n * @public\n */\nexport interface ElasticSearchConnectionConstructor {\n new (opts?: any): any;\n statuses: {\n ALIVE: string;\n DEAD: string;\n };\n roles: {\n MASTER: string;\n DATA: string;\n INGEST: string;\n ML: string;\n };\n}\n\n/**\n * @public\n */\nexport interface OpenSearchConnectionConstructor {\n new (opts?: any): any;\n statuses: {\n ALIVE: string;\n DEAD: string;\n };\n roles: {\n MASTER: string;\n DATA: string;\n INGEST: string;\n };\n}\n\n/**\n * @public\n */\nexport interface ElasticSearchTransportConstructor {\n new (opts?: any): any;\n sniffReasons: {\n SNIFF_ON_START: string;\n SNIFF_INTERVAL: string;\n SNIFF_ON_CONNECTION_FAULT: string;\n DEFAULT: string;\n };\n}\n\n// todo(iamEAP) implement canary types to ensure we remain compatible through upgrades.\n"],"names":[],"mappings":";;AAwBO,MAAM,sBAAA,GAAyB,CACpC,IAAA,KACiD;AACjD,EAAA,OAAO,CAAC,KAAA,EAAO,YAAY,EAAE,QAAA,CAAS,IAAA,EAAM,YAAY,EAAE,CAAA;AAC5D;;;;"}
1
+ {"version":3,"file":"ElasticSearchClientOptions.cjs.js","sources":["../../src/engines/ElasticSearchClientOptions.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { ConnectionOptions as TLSConnectionOptions } from 'node:tls';\n\n/**\n * Typeguard to differentiate ElasticSearch client options which are compatible\n * with OpenSearch vs. ElasticSearch clients. Useful when calling the\n * {@link ElasticSearchSearchEngine.newClient} method.\n *\n * @public\n */\nexport const isOpenSearchCompatible = (\n opts: ElasticSearchClientOptions,\n): opts is OpenSearchElasticSearchClientOptions => {\n return ['aws', 'opensearch'].includes(opts?.provider ?? '');\n};\n\n/**\n * Options used to configure the `@elastic/elasticsearch` client or the\n * `@opensearch-project/opensearch` client, depending on the given config. It\n * will be passed as an argument to the\n * {@link ElasticSearchSearchEngine.newClient} method.\n *\n * @public\n */\nexport type ElasticSearchClientOptions =\n | ElasticSearchElasticSearchClientOptions\n | OpenSearchElasticSearchClientOptions;\n\n/**\n * Options used to configure the `@opensearch-project/opensearch` client.\n *\n * They are drawn from the `ClientOptions` class of `@opensearch-project/opensearch`,\n * but are maintained separately so that this interface is not coupled to it.\n *\n * @public\n */\nexport interface OpenSearchElasticSearchClientOptions\n extends BaseElasticSearchClientOptions {\n provider?: 'aws' | 'opensearch';\n region?: string;\n service?: 'es' | 'aoss';\n auth?: OpenSearchAuth;\n connection?: OpenSearchConnectionConstructor;\n node?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[];\n nodes?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[];\n}\n\n/**\n * Options used to configure the `@elastic/elasticsearch` client.\n *\n * They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`,\n * but are maintained separately so that this interface is not coupled to it.\n *\n * @public\n */\nexport interface ElasticSearchElasticSearchClientOptions\n extends BaseElasticSearchClientOptions {\n provider?: 'elastic';\n auth?: ElasticSearchAuth;\n Connection?: ElasticSearchConnectionConstructor;\n node?:\n | string\n | string[]\n | ElasticSearchNodeOptions\n | ElasticSearchNodeOptions[];\n nodes?:\n | string\n | string[]\n | ElasticSearchNodeOptions\n | ElasticSearchNodeOptions[];\n cloud?: {\n id: string;\n username?: string;\n password?: string;\n };\n}\n\n/**\n * Base client options that are shared across `@opensearch-project/opensearch`\n * and `@elastic/elasticsearch` clients.\n *\n * @public\n */\nexport interface BaseElasticSearchClientOptions {\n Transport?: ElasticSearchTransportConstructor;\n maxRetries?: number;\n requestTimeout?: number;\n pingTimeout?: number;\n sniffInterval?: number | boolean;\n sniffOnStart?: boolean;\n sniffEndpoint?: string;\n sniffOnConnectionFault?: boolean;\n resurrectStrategy?: 'ping' | 'optimistic' | 'none';\n suggestCompression?: boolean;\n compression?: 'gzip';\n ssl?: TLSConnectionOptions;\n agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false;\n nodeFilter?: (connection: any) => boolean;\n nodeSelector?: ((connections: any[]) => any) | string;\n headers?: Record<string, any>;\n opaqueIdPrefix?: string;\n name?: string | symbol;\n proxy?: string | URL;\n enableMetaHeader?: boolean;\n disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor';\n}\n\n/**\n * @public\n */\nexport type OpenSearchAuth = {\n username: string;\n password: string;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchAuth =\n | OpenSearchAuth\n | {\n apiKey:\n | string\n | {\n id: string;\n api_key: string;\n };\n };\n\n/**\n * @public\n */\nexport interface ElasticSearchNodeOptions {\n url: URL;\n id?: string;\n agent?: ElasticSearchAgentOptions;\n ssl?: TLSConnectionOptions;\n headers?: Record<string, any>;\n roles?: {\n master: boolean;\n data: boolean;\n ingest: boolean;\n ml: boolean;\n };\n}\n\n/**\n * @public\n */\nexport interface OpenSearchNodeOptions {\n url: URL;\n id?: string;\n agent?: ElasticSearchAgentOptions;\n ssl?: TLSConnectionOptions;\n headers?: Record<string, any>;\n roles?: {\n master: boolean;\n data: boolean;\n ingest: boolean;\n };\n}\n\n/**\n * @public\n */\nexport interface ElasticSearchAgentOptions {\n keepAlive?: boolean;\n keepAliveMsecs?: number;\n maxSockets?: number;\n maxFreeSockets?: number;\n}\n\n/**\n * @public\n */\nexport interface ElasticSearchConnectionConstructor {\n new (opts?: any): any;\n statuses: {\n ALIVE: string;\n DEAD: string;\n };\n // The Elasticsearch v8 client exposes connection roles as an instance\n // property rather than a static, so this is optional for compatibility.\n roles?: {\n MASTER: string;\n DATA: string;\n INGEST: string;\n ML: string;\n };\n}\n\n/**\n * @public\n */\nexport interface OpenSearchConnectionConstructor {\n new (opts?: any): any;\n statuses: {\n ALIVE: string;\n DEAD: string;\n };\n roles: {\n MASTER: string;\n DATA: string;\n INGEST: string;\n };\n}\n\n/**\n * @public\n */\nexport interface ElasticSearchTransportConstructor {\n new (opts?: any): any;\n sniffReasons: {\n SNIFF_ON_START: string;\n SNIFF_INTERVAL: string;\n SNIFF_ON_CONNECTION_FAULT: string;\n DEFAULT: string;\n };\n}\n\n// todo(iamEAP) implement canary types to ensure we remain compatible through upgrades.\n"],"names":[],"mappings":";;AAwBO,MAAM,sBAAA,GAAyB,CACpC,IAAA,KACiD;AACjD,EAAA,OAAO,CAAC,KAAA,EAAO,YAAY,EAAE,QAAA,CAAS,IAAA,EAAM,YAAY,EAAE,CAAA;AAC5D;;;;"}
@@ -4,6 +4,13 @@ var elasticsearch = require('@elastic/elasticsearch');
4
4
  var opensearch = require('@opensearch-project/opensearch');
5
5
  var ElasticSearchClientOptions = require('./ElasticSearchClientOptions.cjs.js');
6
6
 
7
+ function toElasticSearchClientOptions(options) {
8
+ const { ssl, ...rest } = options;
9
+ return {
10
+ ...rest,
11
+ ...ssl ? { tls: ssl } : {}
12
+ };
13
+ }
7
14
  class ElasticSearchClientWrapper {
8
15
  elasticSearchClient;
9
16
  openSearchClient;
@@ -18,7 +25,9 @@ class ElasticSearchClientWrapper {
18
25
  });
19
26
  }
20
27
  return new ElasticSearchClientWrapper({
21
- elasticSearchClient: new elasticsearch.Client(options)
28
+ elasticSearchClient: new elasticsearch.Client(
29
+ toElasticSearchClientOptions(options)
30
+ )
22
31
  });
23
32
  }
24
33
  search(options) {
@@ -33,10 +42,13 @@ class ElasticSearchClientWrapper {
33
42
  });
34
43
  }
35
44
  if (this.elasticSearchClient) {
36
- return this.elasticSearchClient.search({
37
- ...options,
38
- ...searchOptions
39
- });
45
+ return this.elasticSearchClient.search(
46
+ {
47
+ ...options,
48
+ ...searchOptions
49
+ },
50
+ { meta: true }
51
+ );
40
52
  }
41
53
  throw new Error("No client defined");
42
54
  }
@@ -54,7 +66,9 @@ class ElasticSearchClientWrapper {
54
66
  return this.openSearchClient.indices.putIndexTemplate(template);
55
67
  }
56
68
  if (this.elasticSearchClient) {
57
- return this.elasticSearchClient.indices.putIndexTemplate(template);
69
+ return this.elasticSearchClient.indices.putIndexTemplate(template, {
70
+ meta: true
71
+ });
58
72
  }
59
73
  throw new Error("No client defined");
60
74
  }
@@ -63,7 +77,7 @@ class ElasticSearchClientWrapper {
63
77
  return this.openSearchClient.indices.get(options);
64
78
  }
65
79
  if (this.elasticSearchClient) {
66
- return this.elasticSearchClient.indices.get(options);
80
+ return this.elasticSearchClient.indices.get(options, { meta: true });
67
81
  }
68
82
  throw new Error("No client defined");
69
83
  }
@@ -72,7 +86,7 @@ class ElasticSearchClientWrapper {
72
86
  return this.openSearchClient.indices.exists(options);
73
87
  }
74
88
  if (this.elasticSearchClient) {
75
- return this.elasticSearchClient.indices.exists(options);
89
+ return this.elasticSearchClient.indices.exists(options, { meta: true });
76
90
  }
77
91
  throw new Error("No client defined");
78
92
  }
@@ -81,7 +95,7 @@ class ElasticSearchClientWrapper {
81
95
  return this.openSearchClient.indices.delete(options);
82
96
  }
83
97
  if (this.elasticSearchClient) {
84
- return this.elasticSearchClient.indices.delete(options);
98
+ return this.elasticSearchClient.indices.delete(options, { meta: true });
85
99
  }
86
100
  throw new Error("No client defined");
87
101
  }
@@ -97,10 +111,13 @@ class ElasticSearchClientWrapper {
97
111
  });
98
112
  }
99
113
  if (this.elasticSearchClient) {
100
- return this.elasticSearchClient.cat.aliases({
101
- format: "json",
102
- name: aliases
103
- });
114
+ return this.elasticSearchClient.cat.aliases(
115
+ {
116
+ format: "json",
117
+ name: aliases
118
+ },
119
+ { meta: true }
120
+ );
104
121
  }
105
122
  throw new Error("No client defined");
106
123
  }
@@ -109,7 +126,7 @@ class ElasticSearchClientWrapper {
109
126
  return this.openSearchClient.indices.create(options);
110
127
  }
111
128
  if (this.elasticSearchClient) {
112
- return this.elasticSearchClient.indices.create(options);
129
+ return this.elasticSearchClient.indices.create(options, { meta: true });
113
130
  }
114
131
  throw new Error("No client defined");
115
132
  }
@@ -123,11 +140,14 @@ class ElasticSearchClientWrapper {
123
140
  });
124
141
  }
125
142
  if (this.elasticSearchClient) {
126
- return this.elasticSearchClient.indices.updateAliases({
127
- body: {
128
- actions: filteredActions
129
- }
130
- });
143
+ return this.elasticSearchClient.indices.updateAliases(
144
+ {
145
+ body: {
146
+ actions: filteredActions
147
+ }
148
+ },
149
+ { meta: true }
150
+ );
131
151
  }
132
152
  throw new Error("No client defined");
133
153
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ElasticSearchClientWrapper.cjs.js","sources":["../../src/engines/ElasticSearchClientWrapper.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Client as ElasticSearchClient } from '@elastic/elasticsearch';\nimport { Client as OpenSearchClient } from '@opensearch-project/opensearch';\nimport { Readable } from 'node:stream';\nimport {\n ElasticSearchClientOptions,\n isOpenSearchCompatible,\n} from './ElasticSearchClientOptions';\nimport { ElasticSearchCustomIndexTemplate } from './types';\n\n/**\n * @public\n */\nexport type ElasticSearchAliasAction =\n | {\n remove: { index: any; alias: any };\n add?: undefined;\n }\n | {\n add: { indices: any; alias: any; index?: undefined };\n remove?: undefined;\n }\n | {\n add: { index: any; alias: any; indices?: undefined };\n remove?: undefined;\n }\n | undefined;\n\n/**\n * @public\n */\nexport type ElasticSearchIndexAction = {\n index: {\n _index: string;\n [key: string]: any;\n };\n};\n\n/**\n * A wrapper class that exposes logical methods that are conditionally fired\n * against either a configured Elasticsearch client or a configured Opensearch\n * client.\n *\n * This is necessary because, despite its intention to be API-compatible, the\n * opensearch client does not support API key-based authentication. This is\n * also the sanest way to accomplish this while making typescript happy.\n *\n * In the future, if the differences between implementations become\n * unmaintainably divergent, we should split out the Opensearch and\n * Elasticsearch search engine implementations.\n *\n * @public\n */\nexport class ElasticSearchClientWrapper {\n private readonly elasticSearchClient: ElasticSearchClient | undefined;\n private readonly openSearchClient: OpenSearchClient | undefined;\n\n private constructor(options: {\n openSearchClient?: OpenSearchClient;\n elasticSearchClient?: ElasticSearchClient;\n }) {\n this.openSearchClient = options.openSearchClient;\n this.elasticSearchClient = options.elasticSearchClient;\n }\n\n static fromClientOptions(options: ElasticSearchClientOptions) {\n if (isOpenSearchCompatible(options)) {\n return new ElasticSearchClientWrapper({\n openSearchClient: new OpenSearchClient(options),\n });\n }\n\n return new ElasticSearchClientWrapper({\n elasticSearchClient: new ElasticSearchClient(options),\n });\n }\n\n search(options: { index: string | string[]; body: Object }) {\n const searchOptions = {\n ignore_unavailable: true,\n allow_no_indices: true,\n };\n\n if (this.openSearchClient) {\n return this.openSearchClient.search({\n ...options,\n ...searchOptions,\n });\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.search({\n ...options,\n ...searchOptions,\n });\n }\n\n throw new Error('No client defined');\n }\n\n bulk(bulkOptions: {\n datasource: Readable;\n onDocument: (doc: any) => ElasticSearchIndexAction;\n refreshOnCompletion?: string | boolean;\n }) {\n if (this.openSearchClient) {\n return this.openSearchClient.helpers.bulk(bulkOptions);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.helpers.bulk(bulkOptions);\n }\n\n throw new Error('No client defined');\n }\n\n putIndexTemplate(template: ElasticSearchCustomIndexTemplate) {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.putIndexTemplate(template);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.putIndexTemplate(template);\n }\n\n throw new Error('No client defined');\n }\n\n listIndices(options: { index: string }) {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.get(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.get(options);\n }\n\n throw new Error('No client defined');\n }\n\n indexExists(options: { index: string | string[] }) {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.exists(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.exists(options);\n }\n\n throw new Error('No client defined');\n }\n\n deleteIndex(options: { index: string | string[] }) {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.delete(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.delete(options);\n }\n\n throw new Error('No client defined');\n }\n\n /**\n * @deprecated unused by the ElasticSearch Engine, will be removed in the future\n */\n getAliases(options: { aliases: string[] }) {\n const { aliases } = options;\n\n if (this.openSearchClient) {\n return this.openSearchClient.cat.aliases({\n format: 'json',\n name: aliases,\n });\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.cat.aliases({\n format: 'json',\n name: aliases,\n });\n }\n\n throw new Error('No client defined');\n }\n\n createIndex(options: { index: string }) {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.create(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.create(options);\n }\n\n throw new Error('No client defined');\n }\n\n updateAliases(options: { actions: ElasticSearchAliasAction[] }) {\n const filteredActions = options.actions.filter(Boolean);\n\n if (this.openSearchClient) {\n return this.openSearchClient.indices.updateAliases({\n body: {\n actions: filteredActions,\n },\n });\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.updateAliases({\n body: {\n actions: filteredActions,\n },\n });\n }\n\n throw new Error('No client defined');\n }\n}\n"],"names":["isOpenSearchCompatible","OpenSearchClient","ElasticSearchClient"],"mappings":"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"}
1
+ {"version":3,"file":"ElasticSearchClientWrapper.cjs.js","sources":["../../src/engines/ElasticSearchClientWrapper.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Client as ElasticSearchClient,\n ClientOptions as ElasticSearchClientLibOptions,\n} from '@elastic/elasticsearch';\nimport { Client as OpenSearchClient } from '@opensearch-project/opensearch';\nimport { Readable } from 'node:stream';\nimport {\n ElasticSearchClientOptions,\n isOpenSearchCompatible,\n} from './ElasticSearchClientOptions';\nimport { ElasticSearchCustomIndexTemplate } from './types';\n\n/**\n * @public\n */\nexport type ElasticSearchAliasAction =\n | {\n remove: { index: any; alias: any };\n add?: undefined;\n }\n | {\n add: { indices: any; alias: any; index?: undefined };\n remove?: undefined;\n }\n | {\n add: { index: any; alias: any; indices?: undefined };\n remove?: undefined;\n }\n | undefined;\n\n/**\n * @public\n */\nexport type ElasticSearchIndexAction = {\n index: {\n _index: string;\n [key: string]: any;\n };\n};\n\n/**\n * The normalized response shape returned by the wrapped client methods.\n *\n * Both the Elasticsearch and Opensearch clients expose the response payload\n * under a `body` property together with the HTTP status code, the response\n * headers and any deprecation warnings, so consumers can read these regardless\n * of the configured provider. The client specific `meta` envelope is not part\n * of this type because its shape differs between the two clients.\n *\n * @public\n */\nexport type ElasticSearchClientResponse<TBody = any> = {\n body: TBody;\n headers: Record<string, any> | null;\n statusCode: number | null;\n warnings: string[] | null;\n};\n\n/**\n * The promise returned by the wrapped client methods.\n *\n * The Opensearch client returns a promise that additionally exposes an\n * `abort` method, whereas the Elasticsearch v8 client returns a plain\n * promise, so `abort` is only present when the Opensearch client is\n * configured.\n *\n * @public\n */\nexport type ElasticSearchClientResponsePromise<TBody = any> = Promise<\n ElasticSearchClientResponse<TBody>\n> & {\n abort?: () => void;\n};\n\n/**\n * Adapts the provider-agnostic client options to the shape expected by the\n * `@elastic/elasticsearch` v8 client.\n *\n * The v8 client reads TLS configuration from a `tls` property; the `ssl`\n * property used by the Opensearch client (and by earlier Elasticsearch client\n * versions) is no longer recognized. Map it across so that TLS settings keep\n * being honored.\n */\nfunction toElasticSearchClientOptions(\n options: ElasticSearchClientOptions,\n): ElasticSearchClientLibOptions {\n const { ssl, ...rest } = options;\n return {\n ...rest,\n ...(ssl ? { tls: ssl } : {}),\n } as ElasticSearchClientLibOptions;\n}\n\n/**\n * A wrapper class that exposes logical methods that are conditionally fired\n * against either a configured Elasticsearch client or a configured Opensearch\n * client.\n *\n * This is necessary because, despite its intention to be API-compatible, the\n * opensearch client does not support API key-based authentication. This is\n * also the sanest way to accomplish this while making typescript happy.\n *\n * In the future, if the differences between implementations become\n * unmaintainably divergent, we should split out the Opensearch and\n * Elasticsearch search engine implementations.\n *\n * The Elasticsearch client calls below pass `{ meta: true }`. As of v8 the\n * `@elastic/elasticsearch` client returns the response body directly, whereas\n * the Opensearch client (forked from the v7 Elasticsearch client) still wraps\n * it in `{ body, statusCode, headers, ... }`. Requesting the meta envelope\n * keeps both clients returning the same shape, so consumers can continue to\n * read `response.body` regardless of the configured provider.\n *\n * @public\n */\nexport class ElasticSearchClientWrapper {\n private readonly elasticSearchClient: ElasticSearchClient | undefined;\n private readonly openSearchClient: OpenSearchClient | undefined;\n\n private constructor(options: {\n openSearchClient?: OpenSearchClient;\n elasticSearchClient?: ElasticSearchClient;\n }) {\n this.openSearchClient = options.openSearchClient;\n this.elasticSearchClient = options.elasticSearchClient;\n }\n\n static fromClientOptions(options: ElasticSearchClientOptions) {\n if (isOpenSearchCompatible(options)) {\n return new ElasticSearchClientWrapper({\n openSearchClient: new OpenSearchClient(options),\n });\n }\n\n return new ElasticSearchClientWrapper({\n elasticSearchClient: new ElasticSearchClient(\n toElasticSearchClientOptions(options),\n ),\n });\n }\n\n search(options: {\n index: string | string[];\n body: Object;\n }): ElasticSearchClientResponsePromise {\n const searchOptions = {\n ignore_unavailable: true,\n allow_no_indices: true,\n };\n\n if (this.openSearchClient) {\n return this.openSearchClient.search({\n ...options,\n ...searchOptions,\n });\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.search(\n {\n ...options,\n ...searchOptions,\n },\n { meta: true },\n );\n }\n\n throw new Error('No client defined');\n }\n\n bulk(bulkOptions: {\n datasource: Readable;\n onDocument: (doc: any) => ElasticSearchIndexAction;\n refreshOnCompletion?: string | boolean;\n }) {\n if (this.openSearchClient) {\n return this.openSearchClient.helpers.bulk(bulkOptions);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.helpers.bulk(bulkOptions);\n }\n\n throw new Error('No client defined');\n }\n\n putIndexTemplate(\n template: ElasticSearchCustomIndexTemplate,\n ): ElasticSearchClientResponsePromise {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.putIndexTemplate(template);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.putIndexTemplate(template, {\n meta: true,\n });\n }\n\n throw new Error('No client defined');\n }\n\n listIndices(options: { index: string }): ElasticSearchClientResponsePromise {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.get(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.get(options, { meta: true });\n }\n\n throw new Error('No client defined');\n }\n\n indexExists(options: {\n index: string | string[];\n }): ElasticSearchClientResponsePromise<boolean> {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.exists(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.exists(options, { meta: true });\n }\n\n throw new Error('No client defined');\n }\n\n deleteIndex(options: {\n index: string | string[];\n }): ElasticSearchClientResponsePromise {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.delete(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.delete(options, { meta: true });\n }\n\n throw new Error('No client defined');\n }\n\n /**\n * @deprecated unused by the ElasticSearch Engine, will be removed in the future\n */\n getAliases(options: {\n aliases: string[];\n }): ElasticSearchClientResponsePromise {\n const { aliases } = options;\n\n if (this.openSearchClient) {\n return this.openSearchClient.cat.aliases({\n format: 'json',\n name: aliases,\n });\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.cat.aliases(\n {\n format: 'json',\n name: aliases,\n },\n { meta: true },\n );\n }\n\n throw new Error('No client defined');\n }\n\n createIndex(options: { index: string }): ElasticSearchClientResponsePromise {\n if (this.openSearchClient) {\n return this.openSearchClient.indices.create(options);\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.create(options, { meta: true });\n }\n\n throw new Error('No client defined');\n }\n\n updateAliases(options: {\n actions: ElasticSearchAliasAction[];\n }): ElasticSearchClientResponsePromise {\n const filteredActions = options.actions.filter(Boolean);\n\n if (this.openSearchClient) {\n return this.openSearchClient.indices.updateAliases({\n body: {\n actions: filteredActions,\n },\n });\n }\n\n if (this.elasticSearchClient) {\n return this.elasticSearchClient.indices.updateAliases(\n {\n body: {\n actions: filteredActions as any[],\n },\n },\n { meta: true },\n );\n }\n\n throw new Error('No client defined');\n }\n}\n"],"names":["isOpenSearchCompatible","OpenSearchClient","ElasticSearchClient"],"mappings":"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"}
@@ -58,9 +58,13 @@ class ElasticSearchSearchEngine {
58
58
  authProvider
59
59
  } = options;
60
60
  const credentialProvider = integrationAwsNode.DefaultAwsCredentialsManager.fromConfig(config);
61
+ const esConfig = config.getConfig("search.elasticsearch");
62
+ const awsAccountId = esConfig.getOptionalString("accountId");
61
63
  const clientOptions = await this.createElasticSearchClientOptions(
62
- await credentialProvider?.getCredentialProvider(),
63
- config.getConfig("search.elasticsearch"),
64
+ await credentialProvider?.getCredentialProvider(
65
+ awsAccountId ? { accountId: awsAccountId } : void 0
66
+ ),
67
+ esConfig,
64
68
  authProvider
65
69
  );
66
70
  if (clientOptions.provider === "elastic") {
@@ -1 +1 @@
1
- {"version":3,"file":"ElasticSearchSearchEngine.cjs.js","sources":["../../src/engines/ElasticSearchSearchEngine.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n IndexableDocument,\n IndexableResult,\n IndexableResultSet,\n SearchQuery,\n} from '@backstage/plugin-search-common';\nimport { SearchEngine } from '@backstage/plugin-search-backend-node';\nimport { isEmpty, isNumber, isNaN as nan } from 'lodash';\n\nimport { AwsSigv4Signer } from '@opensearch-project/opensearch/aws';\nimport { RequestSigner } from 'aws4';\nimport { Config } from '@backstage/config';\nimport {\n ElasticSearchClientOptions,\n OpenSearchElasticSearchClientOptions,\n} from './ElasticSearchClientOptions';\nimport { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper';\nimport { ElasticSearchCustomIndexTemplate } from './types';\nimport { ElasticSearchSearchEngineIndexer } from './ElasticSearchSearchEngineIndexer';\nimport { MissingIndexError } from '@backstage/plugin-search-backend-node';\nimport esb from 'elastic-builder';\nimport { randomUUID as uuid } from 'node:crypto';\nimport {\n AwsCredentialProvider,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ElasticSearchAuthProvider } from '../auth';\nimport {\n createOpenSearchAuthTransport,\n createElasticSearchAuthTransport,\n} from './ElasticSearchAuthTransport';\n\nexport type { ElasticSearchClientOptions };\n\n/**\n * Search query that the elasticsearch engine understands.\n * @public\n */\nexport type ElasticSearchConcreteQuery = {\n documentTypes?: string[];\n elasticSearchQuery: Object;\n pageSize: number;\n};\n\n/**\n * Options available for the Elasticsearch specific query translator.\n * @public\n */\nexport type ElasticSearchQueryTranslatorOptions = {\n highlightOptions?: ElasticSearchHighlightConfig;\n queryOptions?: ElasticSearchQueryConfig;\n};\n\n/**\n * Elasticsearch specific query translator.\n * @public\n */\nexport type ElasticSearchQueryTranslator = (\n query: SearchQuery,\n options?: ElasticSearchQueryTranslatorOptions,\n) => ElasticSearchConcreteQuery;\n\n/**\n * Options for instantiate ElasticSearchSearchEngine\n * @public\n */\nexport type ElasticSearchOptions = {\n logger: LoggerService;\n config: Config;\n aliasPostfix?: string;\n indexPrefix?: string;\n translator?: ElasticSearchQueryTranslator;\n /**\n * An optional authentication provider for dynamic authentication.\n *\n * @remarks\n *\n * When provided, this auth provider will be used to inject authentication\n * headers into each request to Elasticsearch/OpenSearch. This is useful\n * for scenarios requiring dynamic tokens (e.g., bearer tokens with rotation).\n *\n * The auth provider takes precedence over static authentication configured\n * in app-config.yaml.\n */\n authProvider?: ElasticSearchAuthProvider;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchHighlightOptions = {\n fragmentDelimiter?: string;\n fragmentSize?: number;\n numFragments?: number;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchQueryConfig = {\n fuzziness?: string | number;\n prefixLength?: number;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchHighlightConfig = {\n fragmentDelimiter: string;\n fragmentSize: number;\n numFragments: number;\n preTag: string;\n postTag: string;\n};\n\ntype ElasticSearchResult = {\n _index: string;\n _type: string;\n _score: number;\n _source: IndexableDocument;\n highlight?: {\n [field: string]: string[];\n };\n};\n\nfunction isBlank(str: string) {\n return (isEmpty(str) && !isNumber(str)) || nan(str);\n}\n\nconst DEFAULT_INDEXER_BATCH_SIZE = 1000;\n\n/**\n * @public\n */\nexport class ElasticSearchSearchEngine implements SearchEngine {\n private readonly elasticSearchClientWrapper: ElasticSearchClientWrapper;\n private readonly highlightOptions: ElasticSearchHighlightConfig;\n private readonly queryOptions?: ElasticSearchQueryConfig;\n\n private readonly elasticSearchClientOptions: ElasticSearchClientOptions;\n private readonly aliasPostfix: string;\n private readonly indexPrefix: string;\n private readonly logger: LoggerService;\n private readonly batchSize: number;\n private readonly batchKeyField?: string;\n\n constructor(\n elasticSearchClientOptions: ElasticSearchClientOptions,\n aliasPostfix: string,\n indexPrefix: string,\n logger: LoggerService,\n batchSize: number,\n batchKeyField?: string,\n highlightOptions?: ElasticSearchHighlightOptions,\n queryOptions?: ElasticSearchQueryConfig,\n ) {\n this.elasticSearchClientOptions = elasticSearchClientOptions;\n this.aliasPostfix = aliasPostfix;\n this.indexPrefix = indexPrefix;\n this.logger = logger;\n this.batchSize = batchSize;\n this.batchKeyField = batchKeyField;\n this.elasticSearchClientWrapper =\n ElasticSearchClientWrapper.fromClientOptions(elasticSearchClientOptions);\n const uuidTag = uuid();\n this.highlightOptions = {\n preTag: `<${uuidTag}>`,\n postTag: `</${uuidTag}>`,\n fragmentSize: 1000,\n numFragments: 1,\n fragmentDelimiter: ' ... ',\n ...highlightOptions,\n };\n this.queryOptions = queryOptions;\n }\n\n static async fromConfig(options: ElasticSearchOptions) {\n const {\n logger,\n config,\n aliasPostfix = `search`,\n indexPrefix = ``,\n translator,\n authProvider,\n } = options;\n const credentialProvider = DefaultAwsCredentialsManager.fromConfig(config);\n const clientOptions = await this.createElasticSearchClientOptions(\n await credentialProvider?.getCredentialProvider(),\n config.getConfig('search.elasticsearch'),\n authProvider,\n );\n if (clientOptions.provider === 'elastic') {\n logger.info('Initializing Elastic.co ElasticSearch search engine.');\n } else if (clientOptions.provider === 'aws') {\n logger.info('Initializing AWS OpenSearch search engine.');\n } else if (clientOptions.provider === 'opensearch') {\n logger.info('Initializing OpenSearch search engine.');\n } else {\n logger.info('Initializing ElasticSearch search engine.');\n }\n\n const engine = new ElasticSearchSearchEngine(\n clientOptions,\n aliasPostfix,\n indexPrefix,\n logger,\n config.getOptionalNumber('search.elasticsearch.batchSize') ??\n DEFAULT_INDEXER_BATCH_SIZE,\n config.getOptionalString('search.elasticsearch.batchKeyField'),\n config.getOptional<ElasticSearchHighlightOptions>(\n 'search.elasticsearch.highlightOptions',\n ),\n config.getOptional<ElasticSearchQueryConfig>(\n 'search.elasticsearch.queryOptions',\n ),\n );\n\n for (const indexTemplate of this.readIndexTemplateConfig(\n config.getConfig('search.elasticsearch'),\n )) {\n await engine.setIndexTemplate(indexTemplate);\n }\n\n if (translator) {\n await engine.setTranslator(translator);\n }\n\n return engine;\n }\n\n /**\n * Create a custom search client from the derived search client configuration.\n * This need not be the same client that the engine uses internally.\n *\n * @example Instantiate an instance of an Elasticsearch client.\n *\n * ```ts\n * import { isOpenSearchCompatible } from '@backstage/plugin-search-backend-module-elasticsearch';\n * import { Client } from '@elastic/elasticsearch';\n *\n * const client = searchEngine.newClient<Client>(options => {\n * // This type guard ensures options are compatible with either OpenSearch\n * // or Elasticsearch client constructors.\n * if (!isOpenSearchCompatible(options)) {\n * return new Client(options);\n * }\n * throw new Error('Incompatible options provided');\n * });\n * ```\n */\n newClient<T>(create: (options: ElasticSearchClientOptions) => T): T {\n return create(this.elasticSearchClientOptions);\n }\n\n protected translator(\n query: SearchQuery,\n options?: ElasticSearchQueryTranslatorOptions,\n ): ElasticSearchConcreteQuery {\n const { term, filters = {}, types, pageCursor } = query;\n\n const filter = Object.entries(filters)\n .filter(([_, value]) => Boolean(value))\n .map(([key, value]: [key: string, value: any]) => {\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n // Use exact matching for string datatype fields\n const keyword = typeof value === 'string' ? `${key}.keyword` : key;\n return esb.matchQuery(keyword, value.toString());\n }\n if (Array.isArray(value)) {\n return esb\n .boolQuery()\n .should(value.map(it => esb.matchQuery(key, it.toString())));\n }\n this.logger.error('Failed to query, unrecognized filter type', {\n key,\n value,\n });\n throw new Error(\n 'Failed to add filters to query. Unrecognized filter type',\n );\n });\n\n const esbQueries = [];\n // https://regex101.com/r/Lr0MqS/1\n const phraseTerms = term.match(/\"[^\"]*\"/g);\n\n if (isBlank(term)) {\n const esbQuery = esb.matchAllQuery();\n esbQueries.push(esbQuery);\n } else if (phraseTerms && phraseTerms.length > 0) {\n let restTerm = term;\n for (const phraseTerm of phraseTerms) {\n restTerm = restTerm.replace(phraseTerm, '');\n const esbPhraseQuery = esb\n .multiMatchQuery(['*'], phraseTerm.replace(/\"/g, ''))\n .type('phrase');\n esbQueries.push(esbPhraseQuery);\n }\n if (restTerm?.length > 0) {\n const esbRestQuery = esb\n .multiMatchQuery(['*'], restTerm.trim())\n .fuzziness(options?.queryOptions?.fuzziness ?? 'auto')\n .prefixLength(options?.queryOptions?.prefixLength ?? 0);\n esbQueries.push(esbRestQuery);\n }\n } else {\n const esbQuery = esb\n .multiMatchQuery(['*'], term)\n .fuzziness(options?.queryOptions?.fuzziness ?? 'auto')\n .prefixLength(options?.queryOptions?.prefixLength ?? 0);\n esbQueries.push(esbQuery);\n }\n\n const pageSize = query.pageLimit || 25;\n const { page } = decodePageCursor(pageCursor);\n\n let esbRequestBodySearch = esb\n .requestBodySearch()\n .query(esb.boolQuery().filter(filter).should(esbQueries))\n .from(page * pageSize)\n .size(pageSize);\n\n if (options?.highlightOptions) {\n esbRequestBodySearch = esbRequestBodySearch.highlight(\n esb\n .highlight('*')\n .numberOfFragments(options.highlightOptions.numFragments as number)\n .fragmentSize(options.highlightOptions.fragmentSize as number)\n .preTags(options.highlightOptions.preTag)\n .postTags(options.highlightOptions.postTag),\n );\n }\n\n return {\n elasticSearchQuery: esbRequestBodySearch.toJSON(),\n documentTypes: types,\n pageSize,\n };\n }\n\n setTranslator(translator: ElasticSearchQueryTranslator) {\n this.translator = translator;\n }\n\n async setIndexTemplate(template: ElasticSearchCustomIndexTemplate) {\n try {\n await this.elasticSearchClientWrapper.putIndexTemplate(template);\n this.logger.info('Custom index template set');\n } catch (error) {\n this.logger.error(`Unable to set custom index template: ${error}`);\n }\n }\n\n async getIndexer(type: string) {\n const alias = this.constructSearchAlias(type);\n const indexerLogger = this.logger.child({ documentType: type });\n\n const indexer = new ElasticSearchSearchEngineIndexer({\n type,\n indexPrefix: this.indexPrefix,\n indexSeparator: this.indexSeparator,\n alias,\n elasticSearchClientWrapper: this.elasticSearchClientWrapper,\n logger: indexerLogger,\n batchSize: this.batchSize,\n batchKeyField: this.batchKeyField,\n skipRefresh:\n (\n this\n .elasticSearchClientOptions as OpenSearchElasticSearchClientOptions\n )?.service === 'aoss',\n });\n\n // Attempt cleanup upon failure.\n // todo(@backstage/search-maintainers): Consider introducing a more\n // formal mechanism for handling such errors in BatchSearchEngineIndexer and\n // replacing this handler with it. See: #17291\n indexer.on('error', async e => {\n indexerLogger.error(`Failed to index documents for type ${type}`, e);\n let cleanupError: Error | undefined;\n\n // In some cases, a failure may have occurred before the indexer was able\n // to complete initialization. Try up to 5 times to remove the dangling\n // index.\n await new Promise<void>(async done => {\n const maxAttempts = 5;\n let attempts = 0;\n\n while (attempts < maxAttempts) {\n try {\n await this.elasticSearchClientWrapper.deleteIndex({\n index: indexer.indexName,\n });\n\n attempts = maxAttempts;\n cleanupError = undefined;\n done();\n } catch (err) {\n cleanupError = err;\n }\n\n // Wait 1 second between retries.\n await new Promise(okay => setTimeout(okay, 1000));\n\n attempts++;\n }\n done();\n });\n\n if (cleanupError) {\n indexerLogger.error(\n `Unable to clean up elastic index ${indexer.indexName}: ${cleanupError}`,\n );\n } else {\n indexerLogger.info(\n `Removed partial, failed index ${indexer.indexName}`,\n );\n }\n });\n\n return indexer;\n }\n\n async query(query: SearchQuery): Promise<IndexableResultSet> {\n const { elasticSearchQuery, documentTypes, pageSize } = this.translator(\n query,\n {\n highlightOptions: this.highlightOptions,\n queryOptions: this.queryOptions,\n },\n );\n if (documentTypes && documentTypes.length === 0) {\n return {\n results: [],\n nextPageCursor: undefined,\n previousPageCursor: undefined,\n numberOfResults: undefined,\n };\n }\n const queryIndices = documentTypes\n ? documentTypes.map(it => this.constructSearchAlias(it))\n : this.constructSearchAlias('*');\n try {\n const result = await this.elasticSearchClientWrapper.search({\n index: queryIndices,\n body: elasticSearchQuery,\n });\n const { page } = decodePageCursor(query.pageCursor);\n const hasNextPage = result.body.hits.total.value > (page + 1) * pageSize;\n const hasPreviousPage = page > 0;\n const nextPageCursor = hasNextPage\n ? encodePageCursor({ page: page + 1 })\n : undefined;\n const previousPageCursor = hasPreviousPage\n ? encodePageCursor({ page: page - 1 })\n : undefined;\n\n return {\n results: result.body.hits.hits.map(\n (d: ElasticSearchResult, index: number) => {\n const resultItem: IndexableResult = {\n type: this.getTypeFromIndex(d._index),\n document: d._source,\n rank: pageSize * page + index + 1,\n };\n\n if (d.highlight) {\n resultItem.highlight = {\n preTag: this.highlightOptions.preTag as string,\n postTag: this.highlightOptions.postTag as string,\n fields: Object.fromEntries(\n Object.entries(d.highlight).map(([field, fragments]) => [\n field,\n fragments.join(this.highlightOptions.fragmentDelimiter),\n ]),\n ),\n };\n }\n\n return resultItem;\n },\n ),\n nextPageCursor,\n previousPageCursor,\n numberOfResults: result.body.hits.total.value,\n };\n } catch (error) {\n if (error.meta?.body?.error?.type === 'index_not_found_exception') {\n throw new MissingIndexError(\n `Missing index for ${queryIndices}. This means there are no documents to search through.`,\n error,\n );\n }\n this.logger.error(\n `Failed to query documents for indices ${queryIndices}`,\n error,\n );\n return Promise.reject({ results: [] });\n }\n }\n\n private readonly indexSeparator = '-index__';\n\n private getTypeFromIndex(index: string) {\n return index\n .substring(this.indexPrefix.length)\n .split(this.indexSeparator)[0];\n }\n\n private constructSearchAlias(type: string) {\n const postFix = this.aliasPostfix ? `__${this.aliasPostfix}` : '';\n return `${this.indexPrefix}${type}${postFix}`;\n }\n\n private static async createElasticSearchClientOptions(\n credentialProvider: AwsCredentialProvider,\n config?: Config,\n authProvider?: ElasticSearchAuthProvider,\n ): Promise<ElasticSearchClientOptions> {\n if (!config) {\n throw new Error('No elastic search config found');\n }\n const clientOptionsConfig = config.getOptionalConfig('clientOptions');\n const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl');\n\n if (config.getOptionalString('provider') === 'elastic') {\n const authConfig = authProvider ? undefined : config.getConfig('auth');\n return {\n provider: 'elastic',\n cloud: {\n id: config.getString('cloudId'),\n },\n // When using authProvider, we inject auth via custom Transport, not static auth\n ...(authConfig\n ? {\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n }\n : {}),\n ...(authProvider\n ? {\n Transport: createElasticSearchAuthTransport(authProvider),\n }\n : {}),\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n if (config.getOptionalString('provider') === 'aws') {\n // AWS provider uses SigV4 signing; authProvider is not applicable here\n if (authProvider) {\n throw new Error(\n 'Custom auth provider is not supported with AWS provider. AWS uses SigV4 signing.',\n );\n }\n const requestSigner = new RequestSigner(config.getString('node'));\n const service =\n config.getOptionalString('service') ?? requestSigner.service;\n if (service !== 'es' && service !== 'aoss')\n throw new Error(`Unrecognized service type: ${service}`);\n return {\n provider: 'aws',\n node: config.getString('node'),\n region: config.getOptionalString('region'),\n service,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n ...AwsSigv4Signer({\n region: config.getOptionalString('region') ?? requestSigner.region, // for backwards compatibility\n service: service,\n getCredentials: async () =>\n await credentialProvider.sdkCredentialProvider(),\n }),\n };\n }\n if (config.getOptionalString('provider') === 'opensearch') {\n const authConfig = authProvider\n ? undefined\n : config.getOptionalConfig('auth');\n return {\n provider: 'opensearch',\n node: config.getString('node'),\n // When using authProvider, we inject auth via custom Transport, not static auth\n ...(authConfig\n ? {\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n }\n : {}),\n ...(authProvider\n ? {\n Transport: createOpenSearchAuthTransport(authProvider),\n }\n : {}),\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n // Default provider (standard Elasticsearch)\n const authConfig = authProvider\n ? undefined\n : config.getOptionalConfig('auth');\n const auth =\n authConfig &&\n (authConfig.has('apiKey')\n ? {\n apiKey: authConfig.getString('apiKey'),\n }\n : {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n });\n return {\n node: config.getString('node'),\n ...(auth ? { auth } : {}),\n ...(authProvider\n ? {\n Transport: createElasticSearchAuthTransport(authProvider),\n }\n : {}),\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n\n private static readIndexTemplateConfig(\n config: Config,\n ): ElasticSearchCustomIndexTemplate[] {\n return (\n config.getOptionalConfigArray('indexTemplates')?.map(templateConfig => {\n const bodyConfig = templateConfig.getConfig('body');\n return {\n name: templateConfig.getString('name'),\n body: {\n index_patterns: bodyConfig.getStringArray('index_patterns'),\n composed_of: bodyConfig.getOptionalStringArray('composed_of'),\n template: bodyConfig.getOptionalConfig('template')?.get(),\n },\n };\n }) ?? []\n );\n }\n}\n\n/**\n * @public\n */\nexport function decodePageCursor(pageCursor?: string): { page: number } {\n if (!pageCursor) {\n return { page: 0 };\n }\n\n return {\n page: Number(Buffer.from(pageCursor, 'base64').toString('utf-8')),\n };\n}\n\nexport function encodePageCursor({ page }: { page: number }): string {\n return Buffer.from(`${page}`, 'utf-8').toString('base64');\n}\n"],"names":["isEmpty","isNumber","nan","ElasticSearchClientWrapper","uuid","DefaultAwsCredentialsManager","esb","ElasticSearchSearchEngineIndexer","MissingIndexError","authConfig","createElasticSearchAuthTransport","RequestSigner","AwsSigv4Signer","createOpenSearchAuthTransport"],"mappings":"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"}
1
+ {"version":3,"file":"ElasticSearchSearchEngine.cjs.js","sources":["../../src/engines/ElasticSearchSearchEngine.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n IndexableDocument,\n IndexableResult,\n IndexableResultSet,\n SearchQuery,\n} from '@backstage/plugin-search-common';\nimport { SearchEngine } from '@backstage/plugin-search-backend-node';\nimport { isEmpty, isNumber, isNaN as nan } from 'lodash';\n\nimport { AwsSigv4Signer } from '@opensearch-project/opensearch/aws';\nimport { RequestSigner } from 'aws4';\nimport { Config } from '@backstage/config';\nimport {\n ElasticSearchClientOptions,\n OpenSearchElasticSearchClientOptions,\n} from './ElasticSearchClientOptions';\nimport { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper';\nimport { ElasticSearchCustomIndexTemplate } from './types';\nimport { ElasticSearchSearchEngineIndexer } from './ElasticSearchSearchEngineIndexer';\nimport { MissingIndexError } from '@backstage/plugin-search-backend-node';\nimport esb from 'elastic-builder';\nimport { randomUUID as uuid } from 'node:crypto';\nimport {\n AwsCredentialProvider,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ElasticSearchAuthProvider } from '../auth';\nimport {\n createOpenSearchAuthTransport,\n createElasticSearchAuthTransport,\n} from './ElasticSearchAuthTransport';\n\nexport type { ElasticSearchClientOptions };\n\n/**\n * Search query that the elasticsearch engine understands.\n * @public\n */\nexport type ElasticSearchConcreteQuery = {\n documentTypes?: string[];\n elasticSearchQuery: Object;\n pageSize: number;\n};\n\n/**\n * Options available for the Elasticsearch specific query translator.\n * @public\n */\nexport type ElasticSearchQueryTranslatorOptions = {\n highlightOptions?: ElasticSearchHighlightConfig;\n queryOptions?: ElasticSearchQueryConfig;\n};\n\n/**\n * Elasticsearch specific query translator.\n * @public\n */\nexport type ElasticSearchQueryTranslator = (\n query: SearchQuery,\n options?: ElasticSearchQueryTranslatorOptions,\n) => ElasticSearchConcreteQuery;\n\n/**\n * Options for instantiate ElasticSearchSearchEngine\n * @public\n */\nexport type ElasticSearchOptions = {\n logger: LoggerService;\n config: Config;\n aliasPostfix?: string;\n indexPrefix?: string;\n translator?: ElasticSearchQueryTranslator;\n /**\n * An optional authentication provider for dynamic authentication.\n *\n * @remarks\n *\n * When provided, this auth provider will be used to inject authentication\n * headers into each request to Elasticsearch/OpenSearch. This is useful\n * for scenarios requiring dynamic tokens (e.g., bearer tokens with rotation).\n *\n * The auth provider takes precedence over static authentication configured\n * in app-config.yaml.\n */\n authProvider?: ElasticSearchAuthProvider;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchHighlightOptions = {\n fragmentDelimiter?: string;\n fragmentSize?: number;\n numFragments?: number;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchQueryConfig = {\n fuzziness?: string | number;\n prefixLength?: number;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchHighlightConfig = {\n fragmentDelimiter: string;\n fragmentSize: number;\n numFragments: number;\n preTag: string;\n postTag: string;\n};\n\ntype ElasticSearchResult = {\n _index: string;\n _type: string;\n _score: number;\n _source: IndexableDocument;\n highlight?: {\n [field: string]: string[];\n };\n};\n\nfunction isBlank(str: string) {\n return (isEmpty(str) && !isNumber(str)) || nan(str);\n}\n\nconst DEFAULT_INDEXER_BATCH_SIZE = 1000;\n\n/**\n * @public\n */\nexport class ElasticSearchSearchEngine implements SearchEngine {\n private readonly elasticSearchClientWrapper: ElasticSearchClientWrapper;\n private readonly highlightOptions: ElasticSearchHighlightConfig;\n private readonly queryOptions?: ElasticSearchQueryConfig;\n\n private readonly elasticSearchClientOptions: ElasticSearchClientOptions;\n private readonly aliasPostfix: string;\n private readonly indexPrefix: string;\n private readonly logger: LoggerService;\n private readonly batchSize: number;\n private readonly batchKeyField?: string;\n\n constructor(\n elasticSearchClientOptions: ElasticSearchClientOptions,\n aliasPostfix: string,\n indexPrefix: string,\n logger: LoggerService,\n batchSize: number,\n batchKeyField?: string,\n highlightOptions?: ElasticSearchHighlightOptions,\n queryOptions?: ElasticSearchQueryConfig,\n ) {\n this.elasticSearchClientOptions = elasticSearchClientOptions;\n this.aliasPostfix = aliasPostfix;\n this.indexPrefix = indexPrefix;\n this.logger = logger;\n this.batchSize = batchSize;\n this.batchKeyField = batchKeyField;\n this.elasticSearchClientWrapper =\n ElasticSearchClientWrapper.fromClientOptions(elasticSearchClientOptions);\n const uuidTag = uuid();\n this.highlightOptions = {\n preTag: `<${uuidTag}>`,\n postTag: `</${uuidTag}>`,\n fragmentSize: 1000,\n numFragments: 1,\n fragmentDelimiter: ' ... ',\n ...highlightOptions,\n };\n this.queryOptions = queryOptions;\n }\n\n static async fromConfig(options: ElasticSearchOptions) {\n const {\n logger,\n config,\n aliasPostfix = `search`,\n indexPrefix = ``,\n translator,\n authProvider,\n } = options;\n const credentialProvider = DefaultAwsCredentialsManager.fromConfig(config);\n const esConfig = config.getConfig('search.elasticsearch');\n const awsAccountId = esConfig.getOptionalString('accountId');\n const clientOptions = await this.createElasticSearchClientOptions(\n await credentialProvider?.getCredentialProvider(\n awsAccountId ? { accountId: awsAccountId } : undefined,\n ),\n esConfig,\n authProvider,\n );\n if (clientOptions.provider === 'elastic') {\n logger.info('Initializing Elastic.co ElasticSearch search engine.');\n } else if (clientOptions.provider === 'aws') {\n logger.info('Initializing AWS OpenSearch search engine.');\n } else if (clientOptions.provider === 'opensearch') {\n logger.info('Initializing OpenSearch search engine.');\n } else {\n logger.info('Initializing ElasticSearch search engine.');\n }\n\n const engine = new ElasticSearchSearchEngine(\n clientOptions,\n aliasPostfix,\n indexPrefix,\n logger,\n config.getOptionalNumber('search.elasticsearch.batchSize') ??\n DEFAULT_INDEXER_BATCH_SIZE,\n config.getOptionalString('search.elasticsearch.batchKeyField'),\n config.getOptional<ElasticSearchHighlightOptions>(\n 'search.elasticsearch.highlightOptions',\n ),\n config.getOptional<ElasticSearchQueryConfig>(\n 'search.elasticsearch.queryOptions',\n ),\n );\n\n for (const indexTemplate of this.readIndexTemplateConfig(\n config.getConfig('search.elasticsearch'),\n )) {\n await engine.setIndexTemplate(indexTemplate);\n }\n\n if (translator) {\n await engine.setTranslator(translator);\n }\n\n return engine;\n }\n\n /**\n * Create a custom search client from the derived search client configuration.\n * This need not be the same client that the engine uses internally.\n *\n * @example Instantiate an instance of an Elasticsearch client.\n *\n * ```ts\n * import { isOpenSearchCompatible } from '@backstage/plugin-search-backend-module-elasticsearch';\n * import { Client } from '@elastic/elasticsearch';\n *\n * const client = searchEngine.newClient<Client>(options => {\n * // This type guard ensures options are compatible with either OpenSearch\n * // or Elasticsearch client constructors.\n * if (!isOpenSearchCompatible(options)) {\n * return new Client(options);\n * }\n * throw new Error('Incompatible options provided');\n * });\n * ```\n */\n newClient<T>(create: (options: ElasticSearchClientOptions) => T): T {\n return create(this.elasticSearchClientOptions);\n }\n\n protected translator(\n query: SearchQuery,\n options?: ElasticSearchQueryTranslatorOptions,\n ): ElasticSearchConcreteQuery {\n const { term, filters = {}, types, pageCursor } = query;\n\n const filter = Object.entries(filters)\n .filter(([_, value]) => Boolean(value))\n .map(([key, value]: [key: string, value: any]) => {\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n // Use exact matching for string datatype fields\n const keyword = typeof value === 'string' ? `${key}.keyword` : key;\n return esb.matchQuery(keyword, value.toString());\n }\n if (Array.isArray(value)) {\n return esb\n .boolQuery()\n .should(value.map(it => esb.matchQuery(key, it.toString())));\n }\n this.logger.error('Failed to query, unrecognized filter type', {\n key,\n value,\n });\n throw new Error(\n 'Failed to add filters to query. Unrecognized filter type',\n );\n });\n\n const esbQueries = [];\n // https://regex101.com/r/Lr0MqS/1\n const phraseTerms = term.match(/\"[^\"]*\"/g);\n\n if (isBlank(term)) {\n const esbQuery = esb.matchAllQuery();\n esbQueries.push(esbQuery);\n } else if (phraseTerms && phraseTerms.length > 0) {\n let restTerm = term;\n for (const phraseTerm of phraseTerms) {\n restTerm = restTerm.replace(phraseTerm, '');\n const esbPhraseQuery = esb\n .multiMatchQuery(['*'], phraseTerm.replace(/\"/g, ''))\n .type('phrase');\n esbQueries.push(esbPhraseQuery);\n }\n if (restTerm?.length > 0) {\n const esbRestQuery = esb\n .multiMatchQuery(['*'], restTerm.trim())\n .fuzziness(options?.queryOptions?.fuzziness ?? 'auto')\n .prefixLength(options?.queryOptions?.prefixLength ?? 0);\n esbQueries.push(esbRestQuery);\n }\n } else {\n const esbQuery = esb\n .multiMatchQuery(['*'], term)\n .fuzziness(options?.queryOptions?.fuzziness ?? 'auto')\n .prefixLength(options?.queryOptions?.prefixLength ?? 0);\n esbQueries.push(esbQuery);\n }\n\n const pageSize = query.pageLimit || 25;\n const { page } = decodePageCursor(pageCursor);\n\n let esbRequestBodySearch = esb\n .requestBodySearch()\n .query(esb.boolQuery().filter(filter).should(esbQueries))\n .from(page * pageSize)\n .size(pageSize);\n\n if (options?.highlightOptions) {\n esbRequestBodySearch = esbRequestBodySearch.highlight(\n esb\n .highlight('*')\n .numberOfFragments(options.highlightOptions.numFragments as number)\n .fragmentSize(options.highlightOptions.fragmentSize as number)\n .preTags(options.highlightOptions.preTag)\n .postTags(options.highlightOptions.postTag),\n );\n }\n\n return {\n elasticSearchQuery: esbRequestBodySearch.toJSON(),\n documentTypes: types,\n pageSize,\n };\n }\n\n setTranslator(translator: ElasticSearchQueryTranslator) {\n this.translator = translator;\n }\n\n async setIndexTemplate(template: ElasticSearchCustomIndexTemplate) {\n try {\n await this.elasticSearchClientWrapper.putIndexTemplate(template);\n this.logger.info('Custom index template set');\n } catch (error) {\n this.logger.error(`Unable to set custom index template: ${error}`);\n }\n }\n\n async getIndexer(type: string) {\n const alias = this.constructSearchAlias(type);\n const indexerLogger = this.logger.child({ documentType: type });\n\n const indexer = new ElasticSearchSearchEngineIndexer({\n type,\n indexPrefix: this.indexPrefix,\n indexSeparator: this.indexSeparator,\n alias,\n elasticSearchClientWrapper: this.elasticSearchClientWrapper,\n logger: indexerLogger,\n batchSize: this.batchSize,\n batchKeyField: this.batchKeyField,\n skipRefresh:\n (\n this\n .elasticSearchClientOptions as OpenSearchElasticSearchClientOptions\n )?.service === 'aoss',\n });\n\n // Attempt cleanup upon failure.\n // todo(@backstage/search-maintainers): Consider introducing a more\n // formal mechanism for handling such errors in BatchSearchEngineIndexer and\n // replacing this handler with it. See: #17291\n indexer.on('error', async e => {\n indexerLogger.error(`Failed to index documents for type ${type}`, e);\n let cleanupError: Error | undefined;\n\n // In some cases, a failure may have occurred before the indexer was able\n // to complete initialization. Try up to 5 times to remove the dangling\n // index.\n await new Promise<void>(async done => {\n const maxAttempts = 5;\n let attempts = 0;\n\n while (attempts < maxAttempts) {\n try {\n await this.elasticSearchClientWrapper.deleteIndex({\n index: indexer.indexName,\n });\n\n attempts = maxAttempts;\n cleanupError = undefined;\n done();\n } catch (err) {\n cleanupError = err;\n }\n\n // Wait 1 second between retries.\n await new Promise(okay => setTimeout(okay, 1000));\n\n attempts++;\n }\n done();\n });\n\n if (cleanupError) {\n indexerLogger.error(\n `Unable to clean up elastic index ${indexer.indexName}: ${cleanupError}`,\n );\n } else {\n indexerLogger.info(\n `Removed partial, failed index ${indexer.indexName}`,\n );\n }\n });\n\n return indexer;\n }\n\n async query(query: SearchQuery): Promise<IndexableResultSet> {\n const { elasticSearchQuery, documentTypes, pageSize } = this.translator(\n query,\n {\n highlightOptions: this.highlightOptions,\n queryOptions: this.queryOptions,\n },\n );\n if (documentTypes && documentTypes.length === 0) {\n return {\n results: [],\n nextPageCursor: undefined,\n previousPageCursor: undefined,\n numberOfResults: undefined,\n };\n }\n const queryIndices = documentTypes\n ? documentTypes.map(it => this.constructSearchAlias(it))\n : this.constructSearchAlias('*');\n try {\n const result = await this.elasticSearchClientWrapper.search({\n index: queryIndices,\n body: elasticSearchQuery,\n });\n const { page } = decodePageCursor(query.pageCursor);\n const hasNextPage = result.body.hits.total.value > (page + 1) * pageSize;\n const hasPreviousPage = page > 0;\n const nextPageCursor = hasNextPage\n ? encodePageCursor({ page: page + 1 })\n : undefined;\n const previousPageCursor = hasPreviousPage\n ? encodePageCursor({ page: page - 1 })\n : undefined;\n\n return {\n results: result.body.hits.hits.map(\n (d: ElasticSearchResult, index: number) => {\n const resultItem: IndexableResult = {\n type: this.getTypeFromIndex(d._index),\n document: d._source,\n rank: pageSize * page + index + 1,\n };\n\n if (d.highlight) {\n resultItem.highlight = {\n preTag: this.highlightOptions.preTag as string,\n postTag: this.highlightOptions.postTag as string,\n fields: Object.fromEntries(\n Object.entries(d.highlight).map(([field, fragments]) => [\n field,\n fragments.join(this.highlightOptions.fragmentDelimiter),\n ]),\n ),\n };\n }\n\n return resultItem;\n },\n ),\n nextPageCursor,\n previousPageCursor,\n numberOfResults: result.body.hits.total.value,\n };\n } catch (error) {\n if (error.meta?.body?.error?.type === 'index_not_found_exception') {\n throw new MissingIndexError(\n `Missing index for ${queryIndices}. This means there are no documents to search through.`,\n error,\n );\n }\n this.logger.error(\n `Failed to query documents for indices ${queryIndices}`,\n error,\n );\n return Promise.reject({ results: [] });\n }\n }\n\n private readonly indexSeparator = '-index__';\n\n private getTypeFromIndex(index: string) {\n return index\n .substring(this.indexPrefix.length)\n .split(this.indexSeparator)[0];\n }\n\n private constructSearchAlias(type: string) {\n const postFix = this.aliasPostfix ? `__${this.aliasPostfix}` : '';\n return `${this.indexPrefix}${type}${postFix}`;\n }\n\n private static async createElasticSearchClientOptions(\n credentialProvider: AwsCredentialProvider,\n config?: Config,\n authProvider?: ElasticSearchAuthProvider,\n ): Promise<ElasticSearchClientOptions> {\n if (!config) {\n throw new Error('No elastic search config found');\n }\n const clientOptionsConfig = config.getOptionalConfig('clientOptions');\n const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl');\n\n if (config.getOptionalString('provider') === 'elastic') {\n const authConfig = authProvider ? undefined : config.getConfig('auth');\n return {\n provider: 'elastic',\n cloud: {\n id: config.getString('cloudId'),\n },\n // When using authProvider, we inject auth via custom Transport, not static auth\n ...(authConfig\n ? {\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n }\n : {}),\n ...(authProvider\n ? {\n Transport: createElasticSearchAuthTransport(authProvider),\n }\n : {}),\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n if (config.getOptionalString('provider') === 'aws') {\n // AWS provider uses SigV4 signing; authProvider is not applicable here\n if (authProvider) {\n throw new Error(\n 'Custom auth provider is not supported with AWS provider. AWS uses SigV4 signing.',\n );\n }\n const requestSigner = new RequestSigner(config.getString('node'));\n const service =\n config.getOptionalString('service') ?? requestSigner.service;\n if (service !== 'es' && service !== 'aoss')\n throw new Error(`Unrecognized service type: ${service}`);\n return {\n provider: 'aws',\n node: config.getString('node'),\n region: config.getOptionalString('region'),\n service,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n ...AwsSigv4Signer({\n region: config.getOptionalString('region') ?? requestSigner.region, // for backwards compatibility\n service: service,\n getCredentials: async () =>\n await credentialProvider.sdkCredentialProvider(),\n }),\n };\n }\n if (config.getOptionalString('provider') === 'opensearch') {\n const authConfig = authProvider\n ? undefined\n : config.getOptionalConfig('auth');\n return {\n provider: 'opensearch',\n node: config.getString('node'),\n // When using authProvider, we inject auth via custom Transport, not static auth\n ...(authConfig\n ? {\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n }\n : {}),\n ...(authProvider\n ? {\n Transport: createOpenSearchAuthTransport(authProvider),\n }\n : {}),\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n // Default provider (standard Elasticsearch)\n const authConfig = authProvider\n ? undefined\n : config.getOptionalConfig('auth');\n const auth =\n authConfig &&\n (authConfig.has('apiKey')\n ? {\n apiKey: authConfig.getString('apiKey'),\n }\n : {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n });\n return {\n node: config.getString('node'),\n ...(auth ? { auth } : {}),\n ...(authProvider\n ? {\n Transport: createElasticSearchAuthTransport(authProvider),\n }\n : {}),\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n\n private static readIndexTemplateConfig(\n config: Config,\n ): ElasticSearchCustomIndexTemplate[] {\n return (\n config.getOptionalConfigArray('indexTemplates')?.map(templateConfig => {\n const bodyConfig = templateConfig.getConfig('body');\n return {\n name: templateConfig.getString('name'),\n body: {\n index_patterns: bodyConfig.getStringArray('index_patterns'),\n composed_of: bodyConfig.getOptionalStringArray('composed_of'),\n template: bodyConfig.getOptionalConfig('template')?.get(),\n },\n };\n }) ?? []\n );\n }\n}\n\n/**\n * @public\n */\nexport function decodePageCursor(pageCursor?: string): { page: number } {\n if (!pageCursor) {\n return { page: 0 };\n }\n\n return {\n page: Number(Buffer.from(pageCursor, 'base64').toString('utf-8')),\n };\n}\n\nexport function encodePageCursor({ page }: { page: number }): string {\n return Buffer.from(`${page}`, 'utf-8').toString('base64');\n}\n"],"names":["isEmpty","isNumber","nan","ElasticSearchClientWrapper","uuid","DefaultAwsCredentialsManager","esb","ElasticSearchSearchEngineIndexer","MissingIndexError","authConfig","createElasticSearchAuthTransport","RequestSigner","AwsSigv4Signer","createOpenSearchAuthTransport"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,11 +4,7 @@ import { IndexableDocument, SearchQuery, IndexableResultSet } from '@backstage/p
4
4
  import { BatchSearchEngineIndexer, SearchEngine } from '@backstage/plugin-search-backend-node';
5
5
  import { Config } from '@backstage/config';
6
6
  import { ConnectionOptions } from 'node:tls';
7
- import * as _elastic_elasticsearch_lib_Helpers from '@elastic/elasticsearch/lib/Helpers';
8
- import * as _elastic_elasticsearch_lib_Transport from '@elastic/elasticsearch/lib/Transport';
9
- import * as _elastic_elasticsearch from '@elastic/elasticsearch';
10
- import * as _opensearch_project_opensearch_lib_Transport_js from '@opensearch-project/opensearch/lib/Transport.js';
11
- import * as _opensearch_project_opensearch from '@opensearch-project/opensearch';
7
+ import * as _opensearch_project_opensearch_lib_Helpers_js from '@opensearch-project/opensearch/lib/Helpers.js';
12
8
  import { Readable } from 'node:stream';
13
9
 
14
10
  /**
@@ -159,7 +155,7 @@ interface ElasticSearchConnectionConstructor {
159
155
  ALIVE: string;
160
156
  DEAD: string;
161
157
  };
162
- roles: {
158
+ roles?: {
163
159
  MASTER: string;
164
160
  DATA: string;
165
161
  INGEST: string;
@@ -219,7 +215,7 @@ type ElasticSearchCustomIndexTemplateBody = {
219
215
  composed_of?: string[];
220
216
  /**
221
217
  * See available properties of template
222
- * https://www.elastic.co/guide/en/elasticsearch/reference/7.15/indices-put-template.html#put-index-template-api-request-body
218
+ * https://www.elastic.co/guide/en/elasticsearch/reference/8.19/indices-put-template.html#put-index-template-api-request-body
223
219
  */
224
220
  template?: Record<string, any>;
225
221
  };
@@ -257,6 +253,36 @@ type ElasticSearchIndexAction = {
257
253
  [key: string]: any;
258
254
  };
259
255
  };
256
+ /**
257
+ * The normalized response shape returned by the wrapped client methods.
258
+ *
259
+ * Both the Elasticsearch and Opensearch clients expose the response payload
260
+ * under a `body` property together with the HTTP status code, the response
261
+ * headers and any deprecation warnings, so consumers can read these regardless
262
+ * of the configured provider. The client specific `meta` envelope is not part
263
+ * of this type because its shape differs between the two clients.
264
+ *
265
+ * @public
266
+ */
267
+ type ElasticSearchClientResponse<TBody = any> = {
268
+ body: TBody;
269
+ headers: Record<string, any> | null;
270
+ statusCode: number | null;
271
+ warnings: string[] | null;
272
+ };
273
+ /**
274
+ * The promise returned by the wrapped client methods.
275
+ *
276
+ * The Opensearch client returns a promise that additionally exposes an
277
+ * `abort` method, whereas the Elasticsearch v8 client returns a plain
278
+ * promise, so `abort` is only present when the Opensearch client is
279
+ * configured.
280
+ *
281
+ * @public
282
+ */
283
+ type ElasticSearchClientResponsePromise<TBody = any> = Promise<ElasticSearchClientResponse<TBody>> & {
284
+ abort?: () => void;
285
+ };
260
286
  /**
261
287
  * A wrapper class that exposes logical methods that are conditionally fired
262
288
  * against either a configured Elasticsearch client or a configured Opensearch
@@ -270,6 +296,13 @@ type ElasticSearchIndexAction = {
270
296
  * unmaintainably divergent, we should split out the Opensearch and
271
297
  * Elasticsearch search engine implementations.
272
298
  *
299
+ * The Elasticsearch client calls below pass `{ meta: true }`. As of v8 the
300
+ * `@elastic/elasticsearch` client returns the response body directly, whereas
301
+ * the Opensearch client (forked from the v7 Elasticsearch client) still wraps
302
+ * it in `{ body, statusCode, headers, ... }`. Requesting the meta envelope
303
+ * keeps both clients returning the same shape, so consumers can continue to
304
+ * read `response.body` regardless of the configured provider.
305
+ *
273
306
  * @public
274
307
  */
275
308
  declare class ElasticSearchClientWrapper {
@@ -280,34 +313,34 @@ declare class ElasticSearchClientWrapper {
280
313
  search(options: {
281
314
  index: string | string[];
282
315
  body: Object;
283
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
316
+ }): ElasticSearchClientResponsePromise;
284
317
  bulk(bulkOptions: {
285
318
  datasource: Readable;
286
319
  onDocument: (doc: any) => ElasticSearchIndexAction;
287
320
  refreshOnCompletion?: string | boolean;
288
- }): _elastic_elasticsearch_lib_Helpers.BulkHelper<_elastic_elasticsearch_lib_Helpers.BulkStats>;
289
- putIndexTemplate(template: ElasticSearchCustomIndexTemplate): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
321
+ }): _opensearch_project_opensearch_lib_Helpers_js.BulkHelper<_opensearch_project_opensearch_lib_Helpers_js.BulkStats>;
322
+ putIndexTemplate(template: ElasticSearchCustomIndexTemplate): ElasticSearchClientResponsePromise;
290
323
  listIndices(options: {
291
324
  index: string;
292
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
325
+ }): ElasticSearchClientResponsePromise;
293
326
  indexExists(options: {
294
327
  index: string | string[];
295
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<boolean, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<boolean, unknown>>;
328
+ }): ElasticSearchClientResponsePromise<boolean>;
296
329
  deleteIndex(options: {
297
330
  index: string | string[];
298
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
331
+ }): ElasticSearchClientResponsePromise;
299
332
  /**
300
333
  * @deprecated unused by the ElasticSearch Engine, will be removed in the future
301
334
  */
302
335
  getAliases(options: {
303
336
  aliases: string[];
304
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
337
+ }): ElasticSearchClientResponsePromise;
305
338
  createIndex(options: {
306
339
  index: string;
307
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
340
+ }): ElasticSearchClientResponsePromise;
308
341
  updateAliases(options: {
309
342
  actions: ElasticSearchAliasAction[];
310
- }): _opensearch_project_opensearch_lib_Transport_js.TransportRequestPromise<_opensearch_project_opensearch.ApiResponse<Record<string, any>, unknown>> | _elastic_elasticsearch_lib_Transport.TransportRequestPromise<_elastic_elasticsearch.ApiResponse<Record<string, any>, unknown>>;
343
+ }): ElasticSearchClientResponsePromise;
311
344
  }
312
345
 
313
346
  /**
@@ -595,4 +628,4 @@ declare const elasticsearchTranslatorExtensionPoint: _backstage_backend_plugin_a
595
628
  declare const _default: _backstage_backend_plugin_api.BackendFeature;
596
629
 
597
630
  export { ElasticSearchClientWrapper, ElasticSearchSearchEngine, ElasticSearchSearchEngineIndexer, decodePageCursor as decodeElasticSearchPageCursor, _default as default, elasticsearchAuthExtensionPoint, elasticsearchTranslatorExtensionPoint, isOpenSearchCompatible };
598
- 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 };
631
+ export type { BaseElasticSearchClientOptions, ElasticSearchAgentOptions, ElasticSearchAliasAction, ElasticSearchAuth, ElasticSearchAuthExtensionPoint, ElasticSearchAuthProvider, ElasticSearchClientOptions, ElasticSearchClientResponse, ElasticSearchClientResponsePromise, ElasticSearchConcreteQuery, ElasticSearchConnectionConstructor, ElasticSearchCustomIndexTemplate, ElasticSearchCustomIndexTemplateBody, ElasticSearchElasticSearchClientOptions, ElasticSearchHighlightConfig, ElasticSearchHighlightOptions, ElasticSearchIndexAction, ElasticSearchNodeOptions, ElasticSearchOptions, ElasticSearchQueryConfig, ElasticSearchQueryTranslator, ElasticSearchQueryTranslatorExtensionPoint, ElasticSearchQueryTranslatorOptions, ElasticSearchSearchEngineIndexerOptions, ElasticSearchTransportConstructor, OpenSearchAuth, OpenSearchConnectionConstructor, OpenSearchElasticSearchClientOptions, OpenSearchNodeOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-search-backend-module-elasticsearch",
3
- "version": "1.8.8-next.2",
3
+ "version": "2.0.0",
4
4
  "description": "A module for the search backend that implements search using ElasticSearch",
5
5
  "backstage": {
6
6
  "role": "backend-plugin-module",
@@ -62,21 +62,21 @@
62
62
  "test": "backstage-cli package test"
63
63
  },
64
64
  "dependencies": {
65
- "@backstage/backend-plugin-api": "1.10.1-next.1",
66
- "@backstage/config": "1.3.9-next.0",
67
- "@backstage/integration-aws-node": "0.2.2-next.0",
68
- "@backstage/plugin-search-backend-node": "1.4.8-next.1",
69
- "@backstage/plugin-search-common": "1.2.25-next.0",
70
- "@elastic/elasticsearch": "^7.13.0",
65
+ "@backstage/backend-plugin-api": "^1.10.1",
66
+ "@backstage/config": "^1.3.9",
67
+ "@backstage/integration-aws-node": "^0.2.2",
68
+ "@backstage/plugin-search-backend-node": "^1.4.8",
69
+ "@backstage/plugin-search-common": "^1.2.25",
70
+ "@elastic/elasticsearch": "^8.19.0",
71
71
  "@opensearch-project/opensearch": "^2.2.1",
72
72
  "aws4": "^1.12.0",
73
73
  "elastic-builder": "^2.16.0",
74
74
  "lodash": "^4.17.21"
75
75
  },
76
76
  "devDependencies": {
77
- "@backstage/backend-test-utils": "1.11.7-next.1",
78
- "@backstage/cli": "0.36.6-next.1",
79
- "@elastic/elasticsearch-mock": "^1.0.0",
77
+ "@backstage/backend-test-utils": "^1.11.7",
78
+ "@backstage/cli": "^0.36.6",
79
+ "@elastic/elasticsearch-mock": "^2.0.0",
80
80
  "@short.io/opensearch-mock": "^0.4.0",
81
81
  "@types/aws4": "^1.5.1"
82
82
  },