@backstage/plugin-search-backend-module-elasticsearch 0.1.4-next.0 → 0.1.4-next.1
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 +11 -0
- package/config.d.ts +18 -0
- package/dist/index.cjs.js +37 -10
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +29 -4
- package/package.json +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @backstage/plugin-search-backend-module-elasticsearch
|
|
2
2
|
|
|
3
|
+
## 0.1.4-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 71d3432710: Search Engines will now index documents in batches of 1000 instead of 100 (under the hood). This may result in your Backstage backend consuming slightly more memory during index runs, but should dramatically improve indexing performance for large document sets.
|
|
8
|
+
- 3a74e203a8: Support generating highlighted matched terms in search result data
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/config@1.0.1-next.0
|
|
11
|
+
- @backstage/plugin-search-backend-node@0.6.1-next.1
|
|
12
|
+
- @backstage/plugin-search-common@0.3.4-next.0
|
|
13
|
+
|
|
3
14
|
## 0.1.4-next.0
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/config.d.ts
CHANGED
|
@@ -21,6 +21,24 @@ export interface Config {
|
|
|
21
21
|
* Options for ElasticSearch
|
|
22
22
|
*/
|
|
23
23
|
elasticsearch?: {
|
|
24
|
+
/**
|
|
25
|
+
* Options for configuring highlight settings
|
|
26
|
+
* See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/highlighting.html
|
|
27
|
+
*/
|
|
28
|
+
highlightOptions?: {
|
|
29
|
+
/**
|
|
30
|
+
* The size of the highlighted fragment in characters. Defaults to 1000.
|
|
31
|
+
*/
|
|
32
|
+
fragmentSize?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Number of result fragments to extract. Fragments will be concatenated with `fragmentDelimiter`. Defaults to 1.
|
|
35
|
+
*/
|
|
36
|
+
numFragments?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Delimiter string used to concatenate fragments. Defaults to " ... ".
|
|
39
|
+
*/
|
|
40
|
+
fragmentDelimiter?: string;
|
|
41
|
+
};
|
|
24
42
|
/** Miscellaneous options for the client */
|
|
25
43
|
clientOptions?: {
|
|
26
44
|
ssl?: {
|
package/dist/index.cjs.js
CHANGED
|
@@ -6,6 +6,7 @@ var awsEsConnection = require('@acuris/aws-es-connection');
|
|
|
6
6
|
var elasticsearch = require('@elastic/elasticsearch');
|
|
7
7
|
var esb = require('elastic-builder');
|
|
8
8
|
var lodash = require('lodash');
|
|
9
|
+
var uuid = require('uuid');
|
|
9
10
|
var pluginSearchBackendNode = require('@backstage/plugin-search-backend-node');
|
|
10
11
|
var stream = require('stream');
|
|
11
12
|
|
|
@@ -20,7 +21,7 @@ function duration(startTimestamp) {
|
|
|
20
21
|
}
|
|
21
22
|
class ElasticSearchSearchEngineIndexer extends pluginSearchBackendNode.BatchSearchEngineIndexer {
|
|
22
23
|
constructor(options) {
|
|
23
|
-
super({ batchSize:
|
|
24
|
+
super({ batchSize: 1e3 });
|
|
24
25
|
this.received = 0;
|
|
25
26
|
this.processed = 0;
|
|
26
27
|
this.removableIndices = [];
|
|
@@ -121,13 +122,22 @@ function isBlank(str) {
|
|
|
121
122
|
return lodash.isEmpty(str) && !lodash.isNumber(str) || lodash.isNaN(str);
|
|
122
123
|
}
|
|
123
124
|
class ElasticSearchSearchEngine {
|
|
124
|
-
constructor(elasticSearchClientOptions, aliasPostfix, indexPrefix, logger) {
|
|
125
|
+
constructor(elasticSearchClientOptions, aliasPostfix, indexPrefix, logger, highlightOptions) {
|
|
125
126
|
this.elasticSearchClientOptions = elasticSearchClientOptions;
|
|
126
127
|
this.aliasPostfix = aliasPostfix;
|
|
127
128
|
this.indexPrefix = indexPrefix;
|
|
128
129
|
this.logger = logger;
|
|
129
130
|
this.indexSeparator = "-index__";
|
|
130
131
|
this.elasticSearchClient = this.newClient((options) => new elasticsearch.Client(options));
|
|
132
|
+
const uuidTag = uuid.v4();
|
|
133
|
+
this.highlightOptions = {
|
|
134
|
+
preTag: `<${uuidTag}>`,
|
|
135
|
+
postTag: `</${uuidTag}>`,
|
|
136
|
+
fragmentSize: 1e3,
|
|
137
|
+
numFragments: 1,
|
|
138
|
+
fragmentDelimiter: " ... ",
|
|
139
|
+
...highlightOptions
|
|
140
|
+
};
|
|
131
141
|
}
|
|
132
142
|
static async fromConfig({
|
|
133
143
|
logger,
|
|
@@ -143,12 +153,12 @@ class ElasticSearchSearchEngine {
|
|
|
143
153
|
} else {
|
|
144
154
|
logger.info("Initializing ElasticSearch search engine.");
|
|
145
155
|
}
|
|
146
|
-
return new ElasticSearchSearchEngine(options, aliasPostfix, indexPrefix, logger);
|
|
156
|
+
return new ElasticSearchSearchEngine(options, aliasPostfix, indexPrefix, logger, config.getOptional("search.elasticsearch.highlightOptions"));
|
|
147
157
|
}
|
|
148
158
|
newClient(create) {
|
|
149
159
|
return create(this.elasticSearchClientOptions);
|
|
150
160
|
}
|
|
151
|
-
translator(query) {
|
|
161
|
+
translator(query, options) {
|
|
152
162
|
const { term, filters = {}, types, pageCursor } = query;
|
|
153
163
|
const filter = Object.entries(filters).filter(([_, value]) => Boolean(value)).map(([key, value]) => {
|
|
154
164
|
if (["string", "number", "boolean"].includes(typeof value)) {
|
|
@@ -163,8 +173,12 @@ class ElasticSearchSearchEngine {
|
|
|
163
173
|
const esbQuery = isBlank(term) ? esb__default["default"].matchAllQuery() : esb__default["default"].multiMatchQuery(["*"], term).fuzziness("auto").minimumShouldMatch(1);
|
|
164
174
|
const pageSize = 25;
|
|
165
175
|
const { page } = decodePageCursor(pageCursor);
|
|
176
|
+
let esbRequestBodySearch = esb__default["default"].requestBodySearch().query(esb__default["default"].boolQuery().filter(filter).must([esbQuery])).from(page * pageSize).size(pageSize);
|
|
177
|
+
if (options == null ? void 0 : options.highlightOptions) {
|
|
178
|
+
esbRequestBodySearch = esbRequestBodySearch.highlight(esb__default["default"].highlight("*").numberOfFragments(options.highlightOptions.numFragments).fragmentSize(options.highlightOptions.fragmentSize).preTags(options.highlightOptions.preTag).postTags(options.highlightOptions.postTag));
|
|
179
|
+
}
|
|
166
180
|
return {
|
|
167
|
-
elasticSearchQuery:
|
|
181
|
+
elasticSearchQuery: esbRequestBodySearch.toJSON(),
|
|
168
182
|
documentTypes: types,
|
|
169
183
|
pageSize
|
|
170
184
|
};
|
|
@@ -202,7 +216,7 @@ class ElasticSearchSearchEngine {
|
|
|
202
216
|
return indexer;
|
|
203
217
|
}
|
|
204
218
|
async query(query) {
|
|
205
|
-
const { elasticSearchQuery, documentTypes, pageSize } = this.translator(query);
|
|
219
|
+
const { elasticSearchQuery, documentTypes, pageSize } = this.translator(query, { highlightOptions: this.highlightOptions });
|
|
206
220
|
const queryIndices = documentTypes ? documentTypes.map((it) => this.constructSearchAlias(it)) : this.constructSearchAlias("*");
|
|
207
221
|
try {
|
|
208
222
|
const result = await this.elasticSearchClient.search({
|
|
@@ -215,10 +229,23 @@ class ElasticSearchSearchEngine {
|
|
|
215
229
|
const nextPageCursor = hasNextPage ? encodePageCursor({ page: page + 1 }) : void 0;
|
|
216
230
|
const previousPageCursor = hasPreviousPage ? encodePageCursor({ page: page - 1 }) : void 0;
|
|
217
231
|
return {
|
|
218
|
-
results: result.body.hits.hits.map((d) =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
232
|
+
results: result.body.hits.hits.map((d) => {
|
|
233
|
+
const resultItem = {
|
|
234
|
+
type: this.getTypeFromIndex(d._index),
|
|
235
|
+
document: d._source
|
|
236
|
+
};
|
|
237
|
+
if (d.highlight) {
|
|
238
|
+
resultItem.highlight = {
|
|
239
|
+
preTag: this.highlightOptions.preTag,
|
|
240
|
+
postTag: this.highlightOptions.postTag,
|
|
241
|
+
fields: Object.fromEntries(Object.entries(d.highlight).map(([field, fragments]) => [
|
|
242
|
+
field,
|
|
243
|
+
fragments.join(this.highlightOptions.fragmentDelimiter)
|
|
244
|
+
]))
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return resultItem;
|
|
248
|
+
}),
|
|
222
249
|
nextPageCursor,
|
|
223
250
|
previousPageCursor
|
|
224
251
|
};
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/engines/ElasticSearchSearchEngineIndexer.ts","../src/engines/ElasticSearchSearchEngine.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node';\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { Client } from '@elastic/elasticsearch';\nimport { Readable } from 'stream';\nimport { Logger } from 'winston';\n\nexport type ElasticSearchSearchEngineIndexerOptions = {\n type: string;\n indexPrefix: string;\n indexSeparator: string;\n alias: string;\n logger: Logger;\n elasticSearchClient: Client;\n};\n\nfunction duration(startTimestamp: [number, number]): string {\n const delta = process.hrtime(startTimestamp);\n const seconds = delta[0] + delta[1] / 1e9;\n return `${seconds.toFixed(1)}s`;\n}\n\nexport class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer {\n private received: number = 0;\n private processed: number = 0;\n private removableIndices: string[] = [];\n\n private readonly startTimestamp: [number, number];\n private readonly type: string;\n public readonly indexName: string;\n private readonly indexPrefix: string;\n private readonly indexSeparator: string;\n private readonly alias: string;\n private readonly removableAlias: string;\n private readonly logger: Logger;\n private readonly sourceStream: Readable;\n private readonly elasticSearchClient: Client;\n private bulkResult: Promise<any>;\n\n constructor(options: ElasticSearchSearchEngineIndexerOptions) {\n super({ batchSize: 100 });\n this.logger = options.logger;\n this.startTimestamp = process.hrtime();\n this.type = options.type;\n this.indexPrefix = options.indexPrefix;\n this.indexSeparator = options.indexSeparator;\n this.indexName = this.constructIndexName(`${Date.now()}`);\n this.alias = options.alias;\n this.removableAlias = `${this.alias}_removable`;\n this.elasticSearchClient = options.elasticSearchClient;\n\n // The ES client bulk helper supports stream-based indexing, but we have to\n // supply the stream directly to it at instantiation-time. We can't supply\n // this class itself, so instead, we create this inline stream instead.\n this.sourceStream = new Readable({ objectMode: true });\n this.sourceStream._read = () => {};\n\n // eslint-disable-next-line consistent-this\n const that = this;\n\n // Keep a reference to the ES Bulk helper so that we can know when all\n // documents have been successfully written to ES.\n this.bulkResult = this.elasticSearchClient.helpers.bulk({\n datasource: this.sourceStream,\n onDocument() {\n that.processed++;\n return {\n index: { _index: that.indexName },\n };\n },\n refreshOnCompletion: that.indexName,\n });\n }\n\n async initialize(): Promise<void> {\n this.logger.info(`Started indexing documents for index ${this.type}`);\n\n const aliases = await this.elasticSearchClient.cat.aliases({\n format: 'json',\n name: [this.alias, this.removableAlias],\n });\n\n this.removableIndices = [\n ...new Set(aliases.body.map((r: Record<string, any>) => r.index)),\n ] as string[];\n\n await this.elasticSearchClient.indices.create({\n index: this.indexName,\n });\n }\n\n async index(documents: IndexableDocument[]): Promise<void> {\n await this.isReady();\n documents.forEach(document => {\n this.received++;\n this.sourceStream.push(document);\n });\n }\n\n async finalize(): Promise<void> {\n // Wait for all documents to be processed.\n await this.isReady();\n\n // Close off the underlying stream connected to ES, indicating that no more\n // documents will be written.\n this.sourceStream.push(null);\n\n // Wait for the bulk helper to finish processing.\n const result = await this.bulkResult;\n\n // Rotate main alias upon completion. Apply permanent secondary alias so\n // stale indices can be referenced for deletion in case initial attempt\n // fails. Allow errors to bubble up so that we can clean up the created index.\n this.logger.info(\n `Indexing completed for index ${this.type} in ${duration(\n this.startTimestamp,\n )}`,\n result,\n );\n await this.elasticSearchClient.indices.updateAliases({\n body: {\n actions: [\n {\n remove: { index: this.constructIndexName('*'), alias: this.alias },\n },\n this.removableIndices.length\n ? {\n add: {\n indices: this.removableIndices,\n alias: this.removableAlias,\n },\n }\n : undefined,\n {\n add: { index: this.indexName, alias: this.alias },\n },\n ].filter(Boolean),\n },\n });\n\n // If any indices are removable, remove them. Do not bubble up this error,\n // as doing so would delete the now aliased index. Log instead.\n if (this.removableIndices.length) {\n this.logger.info('Removing stale search indices', this.removableIndices);\n try {\n await this.elasticSearchClient.indices.delete({\n index: this.removableIndices,\n });\n } catch (e) {\n this.logger.warn(`Failed to remove stale search indices: ${e}`);\n }\n }\n }\n\n /**\n * Ensures that the number of documents sent over the wire to ES matches the\n * number of documents this stream has received so far. This helps manage\n * backpressure in other parts of the indexing pipeline.\n */\n private isReady(): Promise<void> {\n return new Promise(resolve => {\n const interval = setInterval(() => {\n if (this.received === this.processed) {\n clearInterval(interval);\n resolve();\n }\n }, 50);\n });\n }\n\n private constructIndexName(postFix: string) {\n return `${this.indexPrefix}${this.type}${this.indexSeparator}${postFix}`;\n }\n}\n","/*\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 awsGetCredentials,\n createAWSConnection,\n} from '@acuris/aws-es-connection';\nimport { Config } from '@backstage/config';\nimport {\n IndexableDocument,\n IndexableResultSet,\n SearchEngine,\n SearchQuery,\n} from '@backstage/plugin-search-common';\nimport { Client } from '@elastic/elasticsearch';\nimport esb from 'elastic-builder';\nimport { isEmpty, isNaN as nan, isNumber } from 'lodash';\nimport { Logger } from 'winston';\nimport type { ElasticSearchClientOptions } from './ElasticSearchClientOptions';\nimport { ElasticSearchSearchEngineIndexer } from './ElasticSearchSearchEngineIndexer';\n\nexport type { ElasticSearchClientOptions };\n\nexport type ConcreteElasticSearchQuery = {\n documentTypes?: string[];\n elasticSearchQuery: Object;\n pageSize: number;\n};\n\ntype ElasticSearchQueryTranslator = (\n query: SearchQuery,\n) => ConcreteElasticSearchQuery;\n\ntype ElasticSearchOptions = {\n logger: Logger;\n config: Config;\n aliasPostfix?: string;\n indexPrefix?: string;\n};\n\ntype ElasticSearchResult = {\n _index: string;\n _type: string;\n _score: number;\n _source: IndexableDocument;\n};\n\nfunction isBlank(str: string) {\n return (isEmpty(str) && !isNumber(str)) || nan(str);\n}\n\n/**\n * @public\n */\nexport class ElasticSearchSearchEngine implements SearchEngine {\n private readonly elasticSearchClient: Client;\n\n constructor(\n private readonly elasticSearchClientOptions: ElasticSearchClientOptions,\n private readonly aliasPostfix: string,\n private readonly indexPrefix: string,\n private readonly logger: Logger,\n ) {\n this.elasticSearchClient = this.newClient(options => new Client(options));\n }\n\n static async fromConfig({\n logger,\n config,\n aliasPostfix = `search`,\n indexPrefix = ``,\n }: ElasticSearchOptions) {\n const options = await createElasticSearchClientOptions(\n config.getConfig('search.elasticsearch'),\n );\n if (options.provider === 'elastic') {\n logger.info('Initializing Elastic.co ElasticSearch search engine.');\n } else if (options.provider === 'aws') {\n logger.info('Initializing AWS ElasticSearch search engine.');\n } else {\n logger.info('Initializing ElasticSearch search engine.');\n }\n\n return new ElasticSearchSearchEngine(\n options,\n aliasPostfix,\n indexPrefix,\n logger,\n );\n }\n\n /**\n * Create a custom search client from the derived elastic search\n * configuration. This need not be the same client that the engine uses\n * internally.\n */\n newClient<T>(create: (options: ElasticSearchClientOptions) => T): T {\n return create(this.elasticSearchClientOptions);\n }\n\n protected translator(query: SearchQuery): ConcreteElasticSearchQuery {\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 return esb.matchQuery(key, 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(\n '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 const esbQuery = isBlank(term)\n ? esb.matchAllQuery()\n : esb\n .multiMatchQuery(['*'], term)\n .fuzziness('auto')\n .minimumShouldMatch(1);\n const pageSize = 25;\n const { page } = decodePageCursor(pageCursor);\n\n return {\n elasticSearchQuery: esb\n .requestBodySearch()\n .query(esb.boolQuery().filter(filter).must([esbQuery]))\n .from(page * pageSize)\n .size(pageSize)\n .toJSON(),\n documentTypes: types,\n pageSize,\n };\n }\n\n setTranslator(translator: ElasticSearchQueryTranslator) {\n this.translator = translator;\n }\n\n async getIndexer(type: string) {\n const alias = this.constructSearchAlias(type);\n const indexer = new ElasticSearchSearchEngineIndexer({\n type,\n indexPrefix: this.indexPrefix,\n indexSeparator: this.indexSeparator,\n alias,\n elasticSearchClient: this.elasticSearchClient,\n logger: this.logger,\n });\n\n // Attempt cleanup upon failure.\n indexer.on('error', async e => {\n this.logger.error(`Failed to index documents for type ${type}`, e);\n try {\n const response = await this.elasticSearchClient.indices.exists({\n index: indexer.indexName,\n });\n const indexCreated = response.body;\n if (indexCreated) {\n this.logger.info(`Removing created index ${indexer.indexName}`);\n await this.elasticSearchClient.indices.delete({\n index: indexer.indexName,\n });\n }\n } catch (error) {\n this.logger.error(`Unable to clean up elastic index: ${error}`);\n }\n });\n\n return indexer;\n }\n\n async query(query: SearchQuery): Promise<IndexableResultSet> {\n const { elasticSearchQuery, documentTypes, pageSize } =\n this.translator(query);\n const queryIndices = documentTypes\n ? documentTypes.map(it => this.constructSearchAlias(it))\n : this.constructSearchAlias('*');\n try {\n const result = await this.elasticSearchClient.search({\n index: queryIndices,\n body: elasticSearchQuery,\n });\n const { page } = decodePageCursor(query.pageCursor);\n const hasNextPage = result.body.hits.total.value > page * 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((d: ElasticSearchResult) => ({\n type: this.getTypeFromIndex(d._index),\n document: d._source,\n })),\n nextPageCursor,\n previousPageCursor,\n };\n } catch (e) {\n this.logger.error(\n `Failed to query documents for indices ${queryIndices}`,\n e,\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\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\nasync function createElasticSearchClientOptions(\n config?: Config,\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 = config.getConfig('auth');\n return {\n provider: 'elastic',\n cloud: {\n id: config.getString('cloudId'),\n },\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n if (config.getOptionalString('provider') === 'aws') {\n const awsCredentials = await awsGetCredentials();\n const AWSConnection = createAWSConnection(awsCredentials);\n return {\n provider: 'aws',\n node: config.getString('node'),\n ...AWSConnection,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n const authConfig = 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,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n}\n"],"names":["BatchSearchEngineIndexer","Readable","isEmpty","isNumber","nan","Client","esb","awsGetCredentials","createAWSConnection"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/engines/ElasticSearchSearchEngineIndexer.ts","../src/engines/ElasticSearchSearchEngine.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node';\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { Client } from '@elastic/elasticsearch';\nimport { Readable } from 'stream';\nimport { Logger } from 'winston';\n\nexport type ElasticSearchSearchEngineIndexerOptions = {\n type: string;\n indexPrefix: string;\n indexSeparator: string;\n alias: string;\n logger: Logger;\n elasticSearchClient: Client;\n};\n\nfunction duration(startTimestamp: [number, number]): string {\n const delta = process.hrtime(startTimestamp);\n const seconds = delta[0] + delta[1] / 1e9;\n return `${seconds.toFixed(1)}s`;\n}\n\nexport class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer {\n private received: number = 0;\n private processed: number = 0;\n private removableIndices: string[] = [];\n\n private readonly startTimestamp: [number, number];\n private readonly type: string;\n public readonly indexName: string;\n private readonly indexPrefix: string;\n private readonly indexSeparator: string;\n private readonly alias: string;\n private readonly removableAlias: string;\n private readonly logger: Logger;\n private readonly sourceStream: Readable;\n private readonly elasticSearchClient: Client;\n private bulkResult: Promise<any>;\n\n constructor(options: ElasticSearchSearchEngineIndexerOptions) {\n super({ batchSize: 1000 });\n this.logger = options.logger;\n this.startTimestamp = process.hrtime();\n this.type = options.type;\n this.indexPrefix = options.indexPrefix;\n this.indexSeparator = options.indexSeparator;\n this.indexName = this.constructIndexName(`${Date.now()}`);\n this.alias = options.alias;\n this.removableAlias = `${this.alias}_removable`;\n this.elasticSearchClient = options.elasticSearchClient;\n\n // The ES client bulk helper supports stream-based indexing, but we have to\n // supply the stream directly to it at instantiation-time. We can't supply\n // this class itself, so instead, we create this inline stream instead.\n this.sourceStream = new Readable({ objectMode: true });\n this.sourceStream._read = () => {};\n\n // eslint-disable-next-line consistent-this\n const that = this;\n\n // Keep a reference to the ES Bulk helper so that we can know when all\n // documents have been successfully written to ES.\n this.bulkResult = this.elasticSearchClient.helpers.bulk({\n datasource: this.sourceStream,\n onDocument() {\n that.processed++;\n return {\n index: { _index: that.indexName },\n };\n },\n refreshOnCompletion: that.indexName,\n });\n }\n\n async initialize(): Promise<void> {\n this.logger.info(`Started indexing documents for index ${this.type}`);\n\n const aliases = await this.elasticSearchClient.cat.aliases({\n format: 'json',\n name: [this.alias, this.removableAlias],\n });\n\n this.removableIndices = [\n ...new Set(aliases.body.map((r: Record<string, any>) => r.index)),\n ] as string[];\n\n await this.elasticSearchClient.indices.create({\n index: this.indexName,\n });\n }\n\n async index(documents: IndexableDocument[]): Promise<void> {\n await this.isReady();\n documents.forEach(document => {\n this.received++;\n this.sourceStream.push(document);\n });\n }\n\n async finalize(): Promise<void> {\n // Wait for all documents to be processed.\n await this.isReady();\n\n // Close off the underlying stream connected to ES, indicating that no more\n // documents will be written.\n this.sourceStream.push(null);\n\n // Wait for the bulk helper to finish processing.\n const result = await this.bulkResult;\n\n // Rotate main alias upon completion. Apply permanent secondary alias so\n // stale indices can be referenced for deletion in case initial attempt\n // fails. Allow errors to bubble up so that we can clean up the created index.\n this.logger.info(\n `Indexing completed for index ${this.type} in ${duration(\n this.startTimestamp,\n )}`,\n result,\n );\n await this.elasticSearchClient.indices.updateAliases({\n body: {\n actions: [\n {\n remove: { index: this.constructIndexName('*'), alias: this.alias },\n },\n this.removableIndices.length\n ? {\n add: {\n indices: this.removableIndices,\n alias: this.removableAlias,\n },\n }\n : undefined,\n {\n add: { index: this.indexName, alias: this.alias },\n },\n ].filter(Boolean),\n },\n });\n\n // If any indices are removable, remove them. Do not bubble up this error,\n // as doing so would delete the now aliased index. Log instead.\n if (this.removableIndices.length) {\n this.logger.info('Removing stale search indices', this.removableIndices);\n try {\n await this.elasticSearchClient.indices.delete({\n index: this.removableIndices,\n });\n } catch (e) {\n this.logger.warn(`Failed to remove stale search indices: ${e}`);\n }\n }\n }\n\n /**\n * Ensures that the number of documents sent over the wire to ES matches the\n * number of documents this stream has received so far. This helps manage\n * backpressure in other parts of the indexing pipeline.\n */\n private isReady(): Promise<void> {\n return new Promise(resolve => {\n const interval = setInterval(() => {\n if (this.received === this.processed) {\n clearInterval(interval);\n resolve();\n }\n }, 50);\n });\n }\n\n private constructIndexName(postFix: string) {\n return `${this.indexPrefix}${this.type}${this.indexSeparator}${postFix}`;\n }\n}\n","/*\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 awsGetCredentials,\n createAWSConnection,\n} from '@acuris/aws-es-connection';\nimport { Config } from '@backstage/config';\nimport {\n IndexableDocument,\n IndexableResult,\n IndexableResultSet,\n SearchEngine,\n SearchQuery,\n} from '@backstage/plugin-search-common';\nimport { Client } from '@elastic/elasticsearch';\nimport esb from 'elastic-builder';\nimport { isEmpty, isNaN as nan, isNumber } from 'lodash';\nimport { v4 as uuid } from 'uuid';\nimport { Logger } from 'winston';\nimport type { ElasticSearchClientOptions } from './ElasticSearchClientOptions';\nimport { ElasticSearchSearchEngineIndexer } from './ElasticSearchSearchEngineIndexer';\n\nexport type { ElasticSearchClientOptions };\n\nexport type ConcreteElasticSearchQuery = {\n documentTypes?: string[];\n elasticSearchQuery: Object;\n pageSize: number;\n};\n\n/**\n * @public\n */\nexport type ElasticSearchQueryTranslatorOptions = {\n highlightOptions?: ElasticSearchHighlightConfig;\n};\n\ntype ElasticSearchQueryTranslator = (\n query: SearchQuery,\n options?: ElasticSearchQueryTranslatorOptions,\n) => ConcreteElasticSearchQuery;\n\ntype ElasticSearchOptions = {\n logger: Logger;\n config: Config;\n aliasPostfix?: string;\n indexPrefix?: string;\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 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\n/**\n * @public\n */\nexport class ElasticSearchSearchEngine implements SearchEngine {\n private readonly elasticSearchClient: Client;\n private readonly highlightOptions: ElasticSearchHighlightConfig;\n\n constructor(\n private readonly elasticSearchClientOptions: ElasticSearchClientOptions,\n private readonly aliasPostfix: string,\n private readonly indexPrefix: string,\n private readonly logger: Logger,\n highlightOptions?: ElasticSearchHighlightOptions,\n ) {\n this.elasticSearchClient = this.newClient(options => new Client(options));\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 }\n\n static async fromConfig({\n logger,\n config,\n aliasPostfix = `search`,\n indexPrefix = ``,\n }: ElasticSearchOptions) {\n const options = await createElasticSearchClientOptions(\n config.getConfig('search.elasticsearch'),\n );\n if (options.provider === 'elastic') {\n logger.info('Initializing Elastic.co ElasticSearch search engine.');\n } else if (options.provider === 'aws') {\n logger.info('Initializing AWS ElasticSearch search engine.');\n } else {\n logger.info('Initializing ElasticSearch search engine.');\n }\n\n return new ElasticSearchSearchEngine(\n options,\n aliasPostfix,\n indexPrefix,\n logger,\n config.getOptional<ElasticSearchHighlightOptions>(\n 'search.elasticsearch.highlightOptions',\n ),\n );\n }\n\n /**\n * Create a custom search client from the derived elastic search\n * configuration. This need not be the same client that the engine uses\n * internally.\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 ): ConcreteElasticSearchQuery {\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 return esb.matchQuery(key, 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(\n '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 const esbQuery = isBlank(term)\n ? esb.matchAllQuery()\n : esb\n .multiMatchQuery(['*'], term)\n .fuzziness('auto')\n .minimumShouldMatch(1);\n const pageSize = 25;\n const { page } = decodePageCursor(pageCursor);\n\n let esbRequestBodySearch = esb\n .requestBodySearch()\n .query(esb.boolQuery().filter(filter).must([esbQuery]))\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 getIndexer(type: string) {\n const alias = this.constructSearchAlias(type);\n const indexer = new ElasticSearchSearchEngineIndexer({\n type,\n indexPrefix: this.indexPrefix,\n indexSeparator: this.indexSeparator,\n alias,\n elasticSearchClient: this.elasticSearchClient,\n logger: this.logger,\n });\n\n // Attempt cleanup upon failure.\n indexer.on('error', async e => {\n this.logger.error(`Failed to index documents for type ${type}`, e);\n try {\n const response = await this.elasticSearchClient.indices.exists({\n index: indexer.indexName,\n });\n const indexCreated = response.body;\n if (indexCreated) {\n this.logger.info(`Removing created index ${indexer.indexName}`);\n await this.elasticSearchClient.indices.delete({\n index: indexer.indexName,\n });\n }\n } catch (error) {\n this.logger.error(`Unable to clean up elastic index: ${error}`);\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 { highlightOptions: this.highlightOptions },\n );\n const queryIndices = documentTypes\n ? documentTypes.map(it => this.constructSearchAlias(it))\n : this.constructSearchAlias('*');\n try {\n const result = await this.elasticSearchClient.search({\n index: queryIndices,\n body: elasticSearchQuery,\n });\n const { page } = decodePageCursor(query.pageCursor);\n const hasNextPage = result.body.hits.total.value > page * 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((d: ElasticSearchResult) => {\n const resultItem: IndexableResult = {\n type: this.getTypeFromIndex(d._index),\n document: d._source,\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 nextPageCursor,\n previousPageCursor,\n };\n } catch (e) {\n this.logger.error(\n `Failed to query documents for indices ${queryIndices}`,\n e,\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\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\nasync function createElasticSearchClientOptions(\n config?: Config,\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 = config.getConfig('auth');\n return {\n provider: 'elastic',\n cloud: {\n id: config.getString('cloudId'),\n },\n auth: {\n username: authConfig.getString('username'),\n password: authConfig.getString('password'),\n },\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n if (config.getOptionalString('provider') === 'aws') {\n const awsCredentials = await awsGetCredentials();\n const AWSConnection = createAWSConnection(awsCredentials);\n return {\n provider: 'aws',\n node: config.getString('node'),\n ...AWSConnection,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n }\n const authConfig = 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,\n ...(sslConfig\n ? {\n ssl: {\n rejectUnauthorized:\n sslConfig?.getOptionalBoolean('rejectUnauthorized'),\n },\n }\n : {}),\n };\n}\n"],"names":["BatchSearchEngineIndexer","Readable","isEmpty","isNumber","nan","Client","uuid","esb","awsGetCredentials","createAWSConnection"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -139,13 +139,37 @@ declare type ConcreteElasticSearchQuery = {
|
|
|
139
139
|
elasticSearchQuery: Object;
|
|
140
140
|
pageSize: number;
|
|
141
141
|
};
|
|
142
|
-
|
|
142
|
+
/**
|
|
143
|
+
* @public
|
|
144
|
+
*/
|
|
145
|
+
declare type ElasticSearchQueryTranslatorOptions = {
|
|
146
|
+
highlightOptions?: ElasticSearchHighlightConfig;
|
|
147
|
+
};
|
|
148
|
+
declare type ElasticSearchQueryTranslator = (query: SearchQuery, options?: ElasticSearchQueryTranslatorOptions) => ConcreteElasticSearchQuery;
|
|
143
149
|
declare type ElasticSearchOptions = {
|
|
144
150
|
logger: Logger;
|
|
145
151
|
config: Config;
|
|
146
152
|
aliasPostfix?: string;
|
|
147
153
|
indexPrefix?: string;
|
|
148
154
|
};
|
|
155
|
+
/**
|
|
156
|
+
* @public
|
|
157
|
+
*/
|
|
158
|
+
declare type ElasticSearchHighlightOptions = {
|
|
159
|
+
fragmentDelimiter?: string;
|
|
160
|
+
fragmentSize?: number;
|
|
161
|
+
numFragments?: number;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* @public
|
|
165
|
+
*/
|
|
166
|
+
declare type ElasticSearchHighlightConfig = {
|
|
167
|
+
fragmentDelimiter: string;
|
|
168
|
+
fragmentSize: number;
|
|
169
|
+
numFragments: number;
|
|
170
|
+
preTag: string;
|
|
171
|
+
postTag: string;
|
|
172
|
+
};
|
|
149
173
|
/**
|
|
150
174
|
* @public
|
|
151
175
|
*/
|
|
@@ -155,7 +179,8 @@ declare class ElasticSearchSearchEngine implements SearchEngine {
|
|
|
155
179
|
private readonly indexPrefix;
|
|
156
180
|
private readonly logger;
|
|
157
181
|
private readonly elasticSearchClient;
|
|
158
|
-
|
|
182
|
+
private readonly highlightOptions;
|
|
183
|
+
constructor(elasticSearchClientOptions: ElasticSearchClientOptions, aliasPostfix: string, indexPrefix: string, logger: Logger, highlightOptions?: ElasticSearchHighlightOptions);
|
|
159
184
|
static fromConfig({ logger, config, aliasPostfix, indexPrefix, }: ElasticSearchOptions): Promise<ElasticSearchSearchEngine>;
|
|
160
185
|
/**
|
|
161
186
|
* Create a custom search client from the derived elastic search
|
|
@@ -163,7 +188,7 @@ declare class ElasticSearchSearchEngine implements SearchEngine {
|
|
|
163
188
|
* internally.
|
|
164
189
|
*/
|
|
165
190
|
newClient<T>(create: (options: ElasticSearchClientOptions) => T): T;
|
|
166
|
-
protected translator(query: SearchQuery): ConcreteElasticSearchQuery;
|
|
191
|
+
protected translator(query: SearchQuery, options?: ElasticSearchQueryTranslatorOptions): ConcreteElasticSearchQuery;
|
|
167
192
|
setTranslator(translator: ElasticSearchQueryTranslator): void;
|
|
168
193
|
getIndexer(type: string): Promise<ElasticSearchSearchEngineIndexer>;
|
|
169
194
|
query(query: SearchQuery): Promise<IndexableResultSet>;
|
|
@@ -172,4 +197,4 @@ declare class ElasticSearchSearchEngine implements SearchEngine {
|
|
|
172
197
|
private constructSearchAlias;
|
|
173
198
|
}
|
|
174
199
|
|
|
175
|
-
export { ElasticSearchClientOptions, ElasticSearchSearchEngine, ElasticSearchSearchEngineIndexer, ElasticSearchSearchEngineIndexerOptions };
|
|
200
|
+
export { ElasticSearchClientOptions, ElasticSearchHighlightConfig, ElasticSearchHighlightOptions, ElasticSearchQueryTranslatorOptions, ElasticSearchSearchEngine, ElasticSearchSearchEngineIndexer, ElasticSearchSearchEngineIndexerOptions };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-search-backend-module-elasticsearch",
|
|
3
3
|
"description": "A module for the search backend that implements search using ElasticSearch",
|
|
4
|
-
"version": "0.1.4-next.
|
|
4
|
+
"version": "0.1.4-next.1",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -24,18 +24,19 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@acuris/aws-es-connection": "^2.2.0",
|
|
27
|
-
"@backstage/config": "^1.0.0",
|
|
28
|
-
"@backstage/plugin-search-backend-node": "^0.6.1-next.
|
|
29
|
-
"@backstage/plugin-search-common": "^0.3.
|
|
27
|
+
"@backstage/config": "^1.0.1-next.0",
|
|
28
|
+
"@backstage/plugin-search-backend-node": "^0.6.1-next.1",
|
|
29
|
+
"@backstage/plugin-search-common": "^0.3.4-next.0",
|
|
30
30
|
"@elastic/elasticsearch": "7.13.0",
|
|
31
31
|
"aws-sdk": "^2.948.0",
|
|
32
32
|
"elastic-builder": "^2.16.0",
|
|
33
33
|
"lodash": "^4.17.21",
|
|
34
|
+
"uuid": "^8.3.2",
|
|
34
35
|
"winston": "^3.2.1"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
|
-
"@backstage/backend-common": "^0.13.3-next.
|
|
38
|
-
"@backstage/cli": "^0.17.1-next.
|
|
38
|
+
"@backstage/backend-common": "^0.13.3-next.2",
|
|
39
|
+
"@backstage/cli": "^0.17.1-next.2",
|
|
39
40
|
"@elastic/elasticsearch-mock": "^1.0.0"
|
|
40
41
|
},
|
|
41
42
|
"files": [
|
|
@@ -43,5 +44,5 @@
|
|
|
43
44
|
"config.d.ts"
|
|
44
45
|
],
|
|
45
46
|
"configSchema": "config.d.ts",
|
|
46
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "cfbf5762d7d91eee18999306b21d63840400ee29"
|
|
47
48
|
}
|