@backstage/plugin-catalog-backend 3.0.0-next.0 → 3.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,56 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 3.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 5127ebe: **BREAKING**: The default `catalog.stitchingStrategy` has been switched to `{ mode: 'deferred' }`.
8
+ - d675d96: **BREAKING**: The relations compatibility mode is no longer enabled by default, and the `disableRelationsCompatiblity` flag has been removed. To re-enable relations compatibility, the new `enableRelationsCompatibility` flag can be used instead.
9
+ - 2339363: **BREAKING:** The experimental `catalog.useUrlReadersSearch` configuration flag (introduced in v1.36) has been removed.
10
+
11
+ The `UrlReaderProcessor` now always uses the `search` method of `UrlReaders`. Built-in `UrlReaderService` implementations have been updated accordingly.
12
+ If you use custom `UrlReaderService` implementations, you need to adapt their `search` method to correctly handle both specific URLs and potential
13
+ search patterns (see changes on built-in readers [in the original PR](https://github.com/backstage/backstage/pull/28379/files#diff-68b0452f173ee54bdd40f7b5e047a9cb8bb59200425622c212c217b76dac1d1b)).
14
+
15
+ Previous behavior was to call the `search` method only if the parsed Git URL's filename contained a wildcard and use `readUrl` otherwise. Each `UrlReaderService` must implement this logic in the `search` method instead.
16
+
17
+ This allows each `UrlReaderService` implementation to check whether it's a search URL (that contains a wildcard pattern) or not using logic that is specific to each provider.
18
+
19
+ - 687bfc8: **BREAKING**: The default `catalog.orphanStrategy` has been switched to `'delete'`.
20
+ - 5de7a9d: **BREAKING**: The default `catalog.orphanProviderStrategy` has been switched to `'delete'`.
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies
25
+ - @backstage/config@1.3.3
26
+ - @backstage/plugin-permission-common@0.9.1
27
+ - @backstage/plugin-permission-node@0.10.2
28
+ - @backstage/catalog-model@1.7.5
29
+ - @backstage/catalog-client@1.10.2
30
+ - @backstage/integration@1.17.1
31
+ - @backstage/backend-openapi-utils@0.5.5
32
+ - @backstage/backend-plugin-api@1.4.1
33
+ - @backstage/plugin-catalog-common@1.1.5
34
+ - @backstage/plugin-catalog-node@1.17.2
35
+ - @backstage/plugin-events-node@0.4.13
36
+
37
+ ## 3.0.0-next.1
38
+
39
+ ### Patch Changes
40
+
41
+ - Updated dependencies
42
+ - @backstage/config@1.3.3-next.0
43
+ - @backstage/plugin-permission-common@0.9.1-next.0
44
+ - @backstage/plugin-permission-node@0.10.2-next.0
45
+ - @backstage/catalog-model@1.7.5-next.0
46
+ - @backstage/catalog-client@1.10.2-next.0
47
+ - @backstage/integration@1.17.1-next.1
48
+ - @backstage/backend-plugin-api@1.4.1-next.0
49
+ - @backstage/plugin-catalog-common@1.1.5-next.0
50
+ - @backstage/plugin-catalog-node@1.17.2-next.0
51
+ - @backstage/backend-openapi-utils@0.5.5-next.0
52
+ - @backstage/plugin-events-node@0.4.13-next.0
53
+
3
54
  ## 3.0.0-next.0
4
55
 
5
56
  ### Major Changes
package/config.d.ts CHANGED
@@ -139,14 +139,14 @@ export interface Config {
139
139
  }>;
140
140
 
141
141
  /**
142
- * Disables the compatibility layer for relations in returned entities that
142
+ * Enables the compatibility layer for relations in returned entities that
143
143
  * ensures that all relations objects have both `target` and `targetRef`.
144
144
  *
145
- * Enabling this option significantly reduces the memory usage of the
146
- * catalog, and slightly increases performance, but may break consumers that
145
+ * Enabling this option significantly increases the memory usage of the
146
+ * catalog, and slightly reduces performance, but may avoid breaking consumers that
147
147
  * rely on the existence of `target` in the relations objects.
148
148
  */
149
- disableRelationsCompatibility?: boolean;
149
+ enableRelationsCompatibility?: boolean;
150
150
 
151
151
  /**
152
152
  * Disables the default backstage processors.
@@ -160,19 +160,19 @@ export interface Config {
160
160
  /**
161
161
  * The strategy to use for entities that are orphaned, i.e. no longer have
162
162
  * any other entities or providers referencing them. The default value is
163
- * "keep".
163
+ * "delete".
164
164
  */
165
165
  orphanStrategy?: 'keep' | 'delete';
166
166
 
167
167
  /**
168
168
  * The strategy to use for entities that are referenced by providers that are orphaned,
169
169
  * i.e. entities with no providers currently configured in the catalog. The default value is
170
- * "keep".
170
+ * "delete".
171
171
  */
172
172
  orphanProviderStrategy?: 'keep' | 'delete';
173
173
 
174
174
  /**
175
- * The strategy to use when stitching together the final entities.
175
+ * The strategy to use when stitching together the final entities. The default mode is "deferred".
176
176
  */
177
177
  stitchingStrategy?:
178
178
  | {
@@ -237,7 +237,7 @@ class DefaultCatalogProcessingEngine {
237
237
  });
238
238
  }
239
239
  startOrphanCleanup() {
240
- const orphanStrategy = this.config.getOptionalString("catalog.orphanStrategy") ?? "keep";
240
+ const orphanStrategy = this.config.getOptionalString("catalog.orphanStrategy") ?? "delete";
241
241
  if (orphanStrategy !== "delete") {
242
242
  return () => {
243
243
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultCatalogProcessingEngine.cjs.js","sources":["../../src/processing/DefaultCatalogProcessingEngine.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 ANNOTATION_LOCATION,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { assertError, serializeError, stringifyError } from '@backstage/errors';\nimport { Hash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\nimport { Knex } from 'knex';\nimport { metrics, trace } from '@opentelemetry/api';\nimport { ProcessingDatabase, RefreshStateItem } from '../database/types';\nimport { createCounterMetric, createSummaryMetric } from '../util/metrics';\nimport { CatalogProcessingOrchestrator, EntityProcessingResult } from './types';\nimport { Stitcher, stitchingStrategyFromConfig } from '../stitching/types';\nimport { startTaskPipeline } from './TaskPipeline';\nimport { Config } from '@backstage/config';\nimport {\n addEntityAttributes,\n TRACER_ID,\n withActiveSpan,\n} from '../util/opentelemetry';\nimport { deleteOrphanedEntities } from '../database/operations/util/deleteOrphanedEntities';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { CATALOG_ERRORS_TOPIC } from '../constants';\nimport { LoggerService, SchedulerService } from '@backstage/backend-plugin-api';\n\nconst CACHE_TTL = 5;\n\nconst tracer = trace.getTracer(TRACER_ID);\n\nexport type ProgressTracker = ReturnType<typeof progressTracker>;\n\n// NOTE(freben): Perhaps surprisingly, this class does not implement the\n// CatalogProcessingEngine type. That type is externally visible and its name is\n// the way it is for historic reasons. This class has no particular reason to\n// implement that precise interface; nowadays there are several different\n// engines \"hiding\" behind the CatalogProcessingEngine interface, of which this\n// is just one.\nexport class DefaultCatalogProcessingEngine {\n private readonly config: Config;\n private readonly scheduler?: SchedulerService;\n private readonly logger: LoggerService;\n private readonly knex: Knex;\n private readonly processingDatabase: ProcessingDatabase;\n private readonly orchestrator: CatalogProcessingOrchestrator;\n private readonly stitcher: Stitcher;\n private readonly createHash: () => Hash;\n private readonly pollingIntervalMs: number;\n private readonly orphanCleanupIntervalMs: number;\n private readonly onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private readonly tracker: ProgressTracker;\n private readonly eventBroker?: EventBroker | EventsService;\n\n private stopFunc?: () => void;\n\n constructor(options: {\n config: Config;\n scheduler?: SchedulerService;\n logger: LoggerService;\n knex: Knex;\n processingDatabase: ProcessingDatabase;\n orchestrator: CatalogProcessingOrchestrator;\n stitcher: Stitcher;\n createHash: () => Hash;\n pollingIntervalMs?: number;\n orphanCleanupIntervalMs?: number;\n onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n tracker?: ProgressTracker;\n eventBroker?: EventBroker | EventsService;\n }) {\n this.config = options.config;\n this.scheduler = options.scheduler;\n this.logger = options.logger;\n this.knex = options.knex;\n this.processingDatabase = options.processingDatabase;\n this.orchestrator = options.orchestrator;\n this.stitcher = options.stitcher;\n this.createHash = options.createHash;\n this.pollingIntervalMs = options.pollingIntervalMs ?? 1_000;\n this.orphanCleanupIntervalMs = options.orphanCleanupIntervalMs ?? 30_000;\n this.onProcessingError = options.onProcessingError;\n this.tracker = options.tracker ?? progressTracker();\n this.eventBroker = options.eventBroker;\n\n this.stopFunc = undefined;\n }\n\n async start() {\n if (this.stopFunc) {\n throw new Error('Processing engine is already started');\n }\n\n const stopPipeline = this.startPipeline();\n const stopCleanup = this.startOrphanCleanup();\n\n this.stopFunc = () => {\n stopPipeline();\n stopCleanup();\n };\n }\n\n async stop() {\n if (this.stopFunc) {\n this.stopFunc();\n this.stopFunc = undefined;\n }\n }\n\n private startPipeline(): () => void {\n return startTaskPipeline<RefreshStateItem>({\n lowWatermark: 5,\n highWatermark: 10,\n pollingIntervalMs: this.pollingIntervalMs,\n loadTasks: async count => {\n try {\n const { items } =\n await this.processingDatabase.getProcessableEntities(this.knex, {\n processBatchSize: count,\n });\n return items;\n } catch (error) {\n this.logger.warn('Failed to load processing items', error);\n return [];\n }\n },\n processTask: async item => {\n await withActiveSpan(tracer, 'ProcessingRun', async span => {\n const track = this.tracker.processStart(item, this.logger);\n addEntityAttributes(span, item.unprocessedEntity);\n\n try {\n const {\n id,\n state,\n unprocessedEntity,\n entityRef,\n locationKey,\n resultHash: previousResultHash,\n } = item;\n const result = await this.orchestrator.process({\n entity: unprocessedEntity,\n state,\n });\n\n track.markProcessorsCompleted(result);\n\n if (result.ok) {\n const { ttl: _, ...stateWithoutTtl } = state ?? {};\n if (\n stableStringify(stateWithoutTtl) !==\n stableStringify(result.state)\n ) {\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: {\n ttl: CACHE_TTL,\n ...result.state,\n },\n });\n });\n }\n } else {\n const maybeTtl = state?.ttl;\n const ttl = Number.isInteger(maybeTtl) ? (maybeTtl as number) : 0;\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: ttl > 0 ? { ...state, ttl: ttl - 1 } : {},\n });\n });\n }\n\n const location =\n unprocessedEntity?.metadata?.annotations?.[ANNOTATION_LOCATION];\n if (result.errors.length) {\n this.eventBroker?.publish({\n topic: CATALOG_ERRORS_TOPIC,\n eventPayload: {\n entity: entityRef,\n location,\n errors: result.errors,\n },\n });\n }\n const errorsString = JSON.stringify(\n result.errors.map(e => serializeError(e)),\n );\n\n let hashBuilder = this.createHash().update(errorsString);\n\n if (result.ok) {\n const { entityRefs: parents } =\n await this.processingDatabase.transaction(tx =>\n this.processingDatabase.listParents(tx, {\n entityRefs: [\n entityRef,\n ...result.deferredEntities.map(e =>\n stringifyEntityRef(e.entity),\n ),\n ],\n }),\n );\n\n hashBuilder = hashBuilder\n .update(stableStringify({ ...result.completedEntity }))\n .update(stableStringify([...result.deferredEntities]))\n .update(stableStringify([...result.relations]))\n .update(stableStringify([...result.refreshKeys]))\n .update(stableStringify([...parents]));\n }\n\n const resultHash = hashBuilder.digest('hex');\n if (resultHash === previousResultHash) {\n // If nothing changed in our produced outputs, we cannot have any\n // significant effect on our surroundings; therefore, we just abort\n // without any updates / stitching.\n track.markSuccessfulWithNoChanges();\n return;\n }\n\n // If the result was marked as not OK, it signals that some part of the\n // processing pipeline threw an exception. This can happen both as part of\n // non-catastrophic things such as due to validation errors, as well as if\n // something fatal happens inside the processing for other reasons. In any\n // case, this means we can't trust that anything in the output is okay. So\n // just store the errors and trigger a stich so that they become visible to\n // the outside.\n if (!result.ok) {\n // notify the error listener if the entity can not be processed.\n Promise.resolve(undefined)\n .then(() =>\n this.onProcessingError?.({\n unprocessedEntity,\n errors: result.errors,\n }),\n )\n .catch(error => {\n this.logger.debug(\n `Processing error listener threw an exception, ${stringifyError(\n error,\n )}`,\n );\n });\n\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateProcessedEntityErrors(tx, {\n id,\n errors: errorsString,\n resultHash,\n });\n });\n\n await this.stitcher.stitch({\n entityRefs: [stringifyEntityRef(unprocessedEntity)],\n });\n\n track.markSuccessfulWithErrors();\n return;\n }\n\n result.completedEntity.metadata.uid = id;\n let oldRelationSources: Map<string, string>;\n await this.processingDatabase.transaction(async tx => {\n const { previous } =\n await this.processingDatabase.updateProcessedEntity(tx, {\n id,\n processedEntity: result.completedEntity,\n resultHash,\n errors: errorsString,\n relations: result.relations,\n deferredEntities: result.deferredEntities,\n locationKey,\n refreshKeys: result.refreshKeys,\n });\n oldRelationSources = new Map(\n previous.relations.map(r => [\n `${r.source_entity_ref}:${r.type}->${r.target_entity_ref}`,\n r.source_entity_ref,\n ]),\n );\n });\n\n const newRelationSources = new Map<string, string>(\n result.relations.map(relation => {\n const sourceEntityRef = stringifyEntityRef(relation.source);\n const targetEntityRef = stringifyEntityRef(relation.target);\n return [\n `${sourceEntityRef}:${relation.type}->${targetEntityRef}`,\n sourceEntityRef,\n ];\n }),\n );\n\n const setOfThingsToStitch = new Set<string>([\n stringifyEntityRef(result.completedEntity),\n ]);\n newRelationSources.forEach((sourceEntityRef, uniqueKey) => {\n if (!oldRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n oldRelationSources!.forEach((sourceEntityRef, uniqueKey) => {\n if (!newRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n\n await this.stitcher.stitch({\n entityRefs: setOfThingsToStitch,\n });\n\n track.markSuccessfulWithChanges();\n } catch (error) {\n assertError(error);\n track.markFailed(error);\n }\n });\n },\n });\n }\n\n private startOrphanCleanup(): () => void {\n const orphanStrategy =\n this.config.getOptionalString('catalog.orphanStrategy') ?? 'keep';\n if (orphanStrategy !== 'delete') {\n return () => {};\n }\n\n const stitchingStrategy = stitchingStrategyFromConfig(this.config);\n\n const runOnce = async () => {\n try {\n const n = await deleteOrphanedEntities({\n knex: this.knex,\n strategy: stitchingStrategy,\n });\n if (n > 0) {\n this.logger.info(`Deleted ${n} orphaned entities`);\n }\n } catch (error) {\n this.logger.warn(`Failed to delete orphaned entities`, error);\n }\n };\n\n if (this.scheduler) {\n const abortController = new AbortController();\n\n this.scheduler.scheduleTask({\n id: 'catalog_orphan_cleanup',\n frequency: { milliseconds: this.orphanCleanupIntervalMs },\n timeout: { milliseconds: this.orphanCleanupIntervalMs * 0.8 },\n fn: runOnce,\n signal: abortController.signal,\n });\n\n return () => {\n abortController.abort();\n };\n }\n\n const intervalKey = setInterval(runOnce, this.orphanCleanupIntervalMs);\n return () => {\n clearInterval(intervalKey);\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction progressTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promProcessedEntities = createCounterMetric({\n name: 'catalog_processed_entities_count',\n help: 'Amount of entities processed, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingDuration = createSummaryMetric({\n name: 'catalog_processing_duration_seconds',\n help: 'Time spent executing the full processing flow, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessorsDuration = createSummaryMetric({\n name: 'catalog_processors_duration_seconds',\n help: 'Time spent executing catalog processors, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingQueueDelay = createSummaryMetric({\n name: 'catalog_processing_queue_delay_seconds',\n help: 'The amount of delay between being scheduled for processing, and the start of actually being processed, DEPRECATED, use OpenTelemetry metrics instead',\n });\n\n const meter = metrics.getMeter('default');\n const processedEntities = meter.createCounter(\n 'catalog.processed.entities.count',\n { description: 'Amount of entities processed' },\n );\n\n const processingDuration = meter.createHistogram(\n 'catalog.processing.duration',\n {\n description: 'Time spent executing the full processing flow',\n unit: 'seconds',\n },\n );\n\n const processorsDuration = meter.createHistogram(\n 'catalog.processors.duration',\n {\n description: 'Time spent executing catalog processors',\n unit: 'seconds',\n },\n );\n\n const processingQueueDelay = meter.createHistogram(\n 'catalog.processing.queue.delay',\n {\n description:\n 'The amount of delay between being scheduled for processing, and the start of actually being processed',\n unit: 'seconds',\n },\n );\n\n function processStart(item: RefreshStateItem, logger: LoggerService) {\n const startTime = process.hrtime();\n const endOverallTimer = promProcessingDuration.startTimer();\n const endProcessorsTimer = promProcessorsDuration.startTimer();\n\n logger.debug(`Processing ${item.entityRef}`);\n\n if (item.nextUpdateAt) {\n const seconds = -item.nextUpdateAt.diffNow().as('seconds');\n promProcessingQueueDelay.observe(seconds);\n processingQueueDelay.record(seconds);\n }\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n function markProcessorsCompleted(result: EntityProcessingResult) {\n endProcessorsTimer({ result: result.ok ? 'ok' : 'failed' });\n processorsDuration.record(endTime(), {\n result: result.ok ? 'ok' : 'failed',\n });\n }\n\n function markSuccessfulWithNoChanges() {\n endOverallTimer({ result: 'unchanged' });\n promProcessedEntities.inc({ result: 'unchanged' }, 1);\n\n processingDuration.record(endTime(), { result: 'unchanged' });\n processedEntities.add(1, { result: 'unchanged' });\n }\n\n function markSuccessfulWithErrors() {\n endOverallTimer({ result: 'errors' });\n promProcessedEntities.inc({ result: 'errors' }, 1);\n\n processingDuration.record(endTime(), { result: 'errors' });\n processedEntities.add(1, { result: 'errors' });\n }\n\n function markSuccessfulWithChanges() {\n endOverallTimer({ result: 'changed' });\n promProcessedEntities.inc({ result: 'changed' }, 1);\n\n processingDuration.record(endTime(), { result: 'changed' });\n processedEntities.add(1, { result: 'changed' });\n }\n\n function markFailed(error: Error) {\n promProcessedEntities.inc({ result: 'failed' }, 1);\n processedEntities.add(1, { result: 'failed' });\n logger.warn(`Processing of ${item.entityRef} failed`, error);\n }\n\n return {\n markProcessorsCompleted,\n markSuccessfulWithNoChanges,\n markSuccessfulWithErrors,\n markSuccessfulWithChanges,\n markFailed,\n };\n }\n\n return { processStart };\n}\n"],"names":["trace","TRACER_ID","startTaskPipeline","withActiveSpan","addEntityAttributes","stableStringify","ANNOTATION_LOCATION","CATALOG_ERRORS_TOPIC","serializeError","stringifyEntityRef","stringifyError","assertError","stitchingStrategyFromConfig","deleteOrphanedEntities","createCounterMetric","createSummaryMetric","metrics"],"mappings":"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"}
1
+ {"version":3,"file":"DefaultCatalogProcessingEngine.cjs.js","sources":["../../src/processing/DefaultCatalogProcessingEngine.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 ANNOTATION_LOCATION,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { assertError, serializeError, stringifyError } from '@backstage/errors';\nimport { Hash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\nimport { Knex } from 'knex';\nimport { metrics, trace } from '@opentelemetry/api';\nimport { ProcessingDatabase, RefreshStateItem } from '../database/types';\nimport { createCounterMetric, createSummaryMetric } from '../util/metrics';\nimport { CatalogProcessingOrchestrator, EntityProcessingResult } from './types';\nimport { Stitcher, stitchingStrategyFromConfig } from '../stitching/types';\nimport { startTaskPipeline } from './TaskPipeline';\nimport { Config } from '@backstage/config';\nimport {\n addEntityAttributes,\n TRACER_ID,\n withActiveSpan,\n} from '../util/opentelemetry';\nimport { deleteOrphanedEntities } from '../database/operations/util/deleteOrphanedEntities';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { CATALOG_ERRORS_TOPIC } from '../constants';\nimport { LoggerService, SchedulerService } from '@backstage/backend-plugin-api';\n\nconst CACHE_TTL = 5;\n\nconst tracer = trace.getTracer(TRACER_ID);\n\nexport type ProgressTracker = ReturnType<typeof progressTracker>;\n\n// NOTE(freben): Perhaps surprisingly, this class does not implement the\n// CatalogProcessingEngine type. That type is externally visible and its name is\n// the way it is for historic reasons. This class has no particular reason to\n// implement that precise interface; nowadays there are several different\n// engines \"hiding\" behind the CatalogProcessingEngine interface, of which this\n// is just one.\nexport class DefaultCatalogProcessingEngine {\n private readonly config: Config;\n private readonly scheduler?: SchedulerService;\n private readonly logger: LoggerService;\n private readonly knex: Knex;\n private readonly processingDatabase: ProcessingDatabase;\n private readonly orchestrator: CatalogProcessingOrchestrator;\n private readonly stitcher: Stitcher;\n private readonly createHash: () => Hash;\n private readonly pollingIntervalMs: number;\n private readonly orphanCleanupIntervalMs: number;\n private readonly onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private readonly tracker: ProgressTracker;\n private readonly eventBroker?: EventBroker | EventsService;\n\n private stopFunc?: () => void;\n\n constructor(options: {\n config: Config;\n scheduler?: SchedulerService;\n logger: LoggerService;\n knex: Knex;\n processingDatabase: ProcessingDatabase;\n orchestrator: CatalogProcessingOrchestrator;\n stitcher: Stitcher;\n createHash: () => Hash;\n pollingIntervalMs?: number;\n orphanCleanupIntervalMs?: number;\n onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n tracker?: ProgressTracker;\n eventBroker?: EventBroker | EventsService;\n }) {\n this.config = options.config;\n this.scheduler = options.scheduler;\n this.logger = options.logger;\n this.knex = options.knex;\n this.processingDatabase = options.processingDatabase;\n this.orchestrator = options.orchestrator;\n this.stitcher = options.stitcher;\n this.createHash = options.createHash;\n this.pollingIntervalMs = options.pollingIntervalMs ?? 1_000;\n this.orphanCleanupIntervalMs = options.orphanCleanupIntervalMs ?? 30_000;\n this.onProcessingError = options.onProcessingError;\n this.tracker = options.tracker ?? progressTracker();\n this.eventBroker = options.eventBroker;\n\n this.stopFunc = undefined;\n }\n\n async start() {\n if (this.stopFunc) {\n throw new Error('Processing engine is already started');\n }\n\n const stopPipeline = this.startPipeline();\n const stopCleanup = this.startOrphanCleanup();\n\n this.stopFunc = () => {\n stopPipeline();\n stopCleanup();\n };\n }\n\n async stop() {\n if (this.stopFunc) {\n this.stopFunc();\n this.stopFunc = undefined;\n }\n }\n\n private startPipeline(): () => void {\n return startTaskPipeline<RefreshStateItem>({\n lowWatermark: 5,\n highWatermark: 10,\n pollingIntervalMs: this.pollingIntervalMs,\n loadTasks: async count => {\n try {\n const { items } =\n await this.processingDatabase.getProcessableEntities(this.knex, {\n processBatchSize: count,\n });\n return items;\n } catch (error) {\n this.logger.warn('Failed to load processing items', error);\n return [];\n }\n },\n processTask: async item => {\n await withActiveSpan(tracer, 'ProcessingRun', async span => {\n const track = this.tracker.processStart(item, this.logger);\n addEntityAttributes(span, item.unprocessedEntity);\n\n try {\n const {\n id,\n state,\n unprocessedEntity,\n entityRef,\n locationKey,\n resultHash: previousResultHash,\n } = item;\n const result = await this.orchestrator.process({\n entity: unprocessedEntity,\n state,\n });\n\n track.markProcessorsCompleted(result);\n\n if (result.ok) {\n const { ttl: _, ...stateWithoutTtl } = state ?? {};\n if (\n stableStringify(stateWithoutTtl) !==\n stableStringify(result.state)\n ) {\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: {\n ttl: CACHE_TTL,\n ...result.state,\n },\n });\n });\n }\n } else {\n const maybeTtl = state?.ttl;\n const ttl = Number.isInteger(maybeTtl) ? (maybeTtl as number) : 0;\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: ttl > 0 ? { ...state, ttl: ttl - 1 } : {},\n });\n });\n }\n\n const location =\n unprocessedEntity?.metadata?.annotations?.[ANNOTATION_LOCATION];\n if (result.errors.length) {\n this.eventBroker?.publish({\n topic: CATALOG_ERRORS_TOPIC,\n eventPayload: {\n entity: entityRef,\n location,\n errors: result.errors,\n },\n });\n }\n const errorsString = JSON.stringify(\n result.errors.map(e => serializeError(e)),\n );\n\n let hashBuilder = this.createHash().update(errorsString);\n\n if (result.ok) {\n const { entityRefs: parents } =\n await this.processingDatabase.transaction(tx =>\n this.processingDatabase.listParents(tx, {\n entityRefs: [\n entityRef,\n ...result.deferredEntities.map(e =>\n stringifyEntityRef(e.entity),\n ),\n ],\n }),\n );\n\n hashBuilder = hashBuilder\n .update(stableStringify({ ...result.completedEntity }))\n .update(stableStringify([...result.deferredEntities]))\n .update(stableStringify([...result.relations]))\n .update(stableStringify([...result.refreshKeys]))\n .update(stableStringify([...parents]));\n }\n\n const resultHash = hashBuilder.digest('hex');\n if (resultHash === previousResultHash) {\n // If nothing changed in our produced outputs, we cannot have any\n // significant effect on our surroundings; therefore, we just abort\n // without any updates / stitching.\n track.markSuccessfulWithNoChanges();\n return;\n }\n\n // If the result was marked as not OK, it signals that some part of the\n // processing pipeline threw an exception. This can happen both as part of\n // non-catastrophic things such as due to validation errors, as well as if\n // something fatal happens inside the processing for other reasons. In any\n // case, this means we can't trust that anything in the output is okay. So\n // just store the errors and trigger a stich so that they become visible to\n // the outside.\n if (!result.ok) {\n // notify the error listener if the entity can not be processed.\n Promise.resolve(undefined)\n .then(() =>\n this.onProcessingError?.({\n unprocessedEntity,\n errors: result.errors,\n }),\n )\n .catch(error => {\n this.logger.debug(\n `Processing error listener threw an exception, ${stringifyError(\n error,\n )}`,\n );\n });\n\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateProcessedEntityErrors(tx, {\n id,\n errors: errorsString,\n resultHash,\n });\n });\n\n await this.stitcher.stitch({\n entityRefs: [stringifyEntityRef(unprocessedEntity)],\n });\n\n track.markSuccessfulWithErrors();\n return;\n }\n\n result.completedEntity.metadata.uid = id;\n let oldRelationSources: Map<string, string>;\n await this.processingDatabase.transaction(async tx => {\n const { previous } =\n await this.processingDatabase.updateProcessedEntity(tx, {\n id,\n processedEntity: result.completedEntity,\n resultHash,\n errors: errorsString,\n relations: result.relations,\n deferredEntities: result.deferredEntities,\n locationKey,\n refreshKeys: result.refreshKeys,\n });\n oldRelationSources = new Map(\n previous.relations.map(r => [\n `${r.source_entity_ref}:${r.type}->${r.target_entity_ref}`,\n r.source_entity_ref,\n ]),\n );\n });\n\n const newRelationSources = new Map<string, string>(\n result.relations.map(relation => {\n const sourceEntityRef = stringifyEntityRef(relation.source);\n const targetEntityRef = stringifyEntityRef(relation.target);\n return [\n `${sourceEntityRef}:${relation.type}->${targetEntityRef}`,\n sourceEntityRef,\n ];\n }),\n );\n\n const setOfThingsToStitch = new Set<string>([\n stringifyEntityRef(result.completedEntity),\n ]);\n newRelationSources.forEach((sourceEntityRef, uniqueKey) => {\n if (!oldRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n oldRelationSources!.forEach((sourceEntityRef, uniqueKey) => {\n if (!newRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n\n await this.stitcher.stitch({\n entityRefs: setOfThingsToStitch,\n });\n\n track.markSuccessfulWithChanges();\n } catch (error) {\n assertError(error);\n track.markFailed(error);\n }\n });\n },\n });\n }\n\n private startOrphanCleanup(): () => void {\n const orphanStrategy =\n this.config.getOptionalString('catalog.orphanStrategy') ?? 'delete';\n if (orphanStrategy !== 'delete') {\n return () => {};\n }\n\n const stitchingStrategy = stitchingStrategyFromConfig(this.config);\n\n const runOnce = async () => {\n try {\n const n = await deleteOrphanedEntities({\n knex: this.knex,\n strategy: stitchingStrategy,\n });\n if (n > 0) {\n this.logger.info(`Deleted ${n} orphaned entities`);\n }\n } catch (error) {\n this.logger.warn(`Failed to delete orphaned entities`, error);\n }\n };\n\n if (this.scheduler) {\n const abortController = new AbortController();\n\n this.scheduler.scheduleTask({\n id: 'catalog_orphan_cleanup',\n frequency: { milliseconds: this.orphanCleanupIntervalMs },\n timeout: { milliseconds: this.orphanCleanupIntervalMs * 0.8 },\n fn: runOnce,\n signal: abortController.signal,\n });\n\n return () => {\n abortController.abort();\n };\n }\n\n const intervalKey = setInterval(runOnce, this.orphanCleanupIntervalMs);\n return () => {\n clearInterval(intervalKey);\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction progressTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promProcessedEntities = createCounterMetric({\n name: 'catalog_processed_entities_count',\n help: 'Amount of entities processed, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingDuration = createSummaryMetric({\n name: 'catalog_processing_duration_seconds',\n help: 'Time spent executing the full processing flow, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessorsDuration = createSummaryMetric({\n name: 'catalog_processors_duration_seconds',\n help: 'Time spent executing catalog processors, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingQueueDelay = createSummaryMetric({\n name: 'catalog_processing_queue_delay_seconds',\n help: 'The amount of delay between being scheduled for processing, and the start of actually being processed, DEPRECATED, use OpenTelemetry metrics instead',\n });\n\n const meter = metrics.getMeter('default');\n const processedEntities = meter.createCounter(\n 'catalog.processed.entities.count',\n { description: 'Amount of entities processed' },\n );\n\n const processingDuration = meter.createHistogram(\n 'catalog.processing.duration',\n {\n description: 'Time spent executing the full processing flow',\n unit: 'seconds',\n },\n );\n\n const processorsDuration = meter.createHistogram(\n 'catalog.processors.duration',\n {\n description: 'Time spent executing catalog processors',\n unit: 'seconds',\n },\n );\n\n const processingQueueDelay = meter.createHistogram(\n 'catalog.processing.queue.delay',\n {\n description:\n 'The amount of delay between being scheduled for processing, and the start of actually being processed',\n unit: 'seconds',\n },\n );\n\n function processStart(item: RefreshStateItem, logger: LoggerService) {\n const startTime = process.hrtime();\n const endOverallTimer = promProcessingDuration.startTimer();\n const endProcessorsTimer = promProcessorsDuration.startTimer();\n\n logger.debug(`Processing ${item.entityRef}`);\n\n if (item.nextUpdateAt) {\n const seconds = -item.nextUpdateAt.diffNow().as('seconds');\n promProcessingQueueDelay.observe(seconds);\n processingQueueDelay.record(seconds);\n }\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n function markProcessorsCompleted(result: EntityProcessingResult) {\n endProcessorsTimer({ result: result.ok ? 'ok' : 'failed' });\n processorsDuration.record(endTime(), {\n result: result.ok ? 'ok' : 'failed',\n });\n }\n\n function markSuccessfulWithNoChanges() {\n endOverallTimer({ result: 'unchanged' });\n promProcessedEntities.inc({ result: 'unchanged' }, 1);\n\n processingDuration.record(endTime(), { result: 'unchanged' });\n processedEntities.add(1, { result: 'unchanged' });\n }\n\n function markSuccessfulWithErrors() {\n endOverallTimer({ result: 'errors' });\n promProcessedEntities.inc({ result: 'errors' }, 1);\n\n processingDuration.record(endTime(), { result: 'errors' });\n processedEntities.add(1, { result: 'errors' });\n }\n\n function markSuccessfulWithChanges() {\n endOverallTimer({ result: 'changed' });\n promProcessedEntities.inc({ result: 'changed' }, 1);\n\n processingDuration.record(endTime(), { result: 'changed' });\n processedEntities.add(1, { result: 'changed' });\n }\n\n function markFailed(error: Error) {\n promProcessedEntities.inc({ result: 'failed' }, 1);\n processedEntities.add(1, { result: 'failed' });\n logger.warn(`Processing of ${item.entityRef} failed`, error);\n }\n\n return {\n markProcessorsCompleted,\n markSuccessfulWithNoChanges,\n markSuccessfulWithErrors,\n markSuccessfulWithChanges,\n markFailed,\n };\n }\n\n return { processStart };\n}\n"],"names":["trace","TRACER_ID","startTaskPipeline","withActiveSpan","addEntityAttributes","stableStringify","ANNOTATION_LOCATION","CATALOG_ERRORS_TOPIC","serializeError","stringifyEntityRef","stringifyError","assertError","stitchingStrategyFromConfig","deleteOrphanedEntities","createCounterMetric","createSummaryMetric","metrics"],"mappings":";;;;;;;;;;;;;;;;;AA0CA,MAAM,SAAY,GAAA,CAAA;AAElB,MAAM,MAAA,GAASA,SAAM,CAAA,SAAA,CAAUC,uBAAS,CAAA;AAUjC,MAAM,8BAA+B,CAAA;AAAA,EACzB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,kBAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA;AAAA,EACA,uBAAA;AAAA,EACA,iBAAA;AAAA,EAIA,OAAA;AAAA,EACA,WAAA;AAAA,EAET,QAAA;AAAA,EAER,YAAY,OAiBT,EAAA;AACD,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,YAAY,OAAQ,CAAA,SAAA;AACzB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,OAAO,OAAQ,CAAA,IAAA;AACpB,IAAA,IAAA,CAAK,qBAAqB,OAAQ,CAAA,kBAAA;AAClC,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAC5B,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA;AACxB,IAAA,IAAA,CAAK,aAAa,OAAQ,CAAA,UAAA;AAC1B,IAAK,IAAA,CAAA,iBAAA,GAAoB,QAAQ,iBAAqB,IAAA,GAAA;AACtD,IAAK,IAAA,CAAA,uBAAA,GAA0B,QAAQ,uBAA2B,IAAA,GAAA;AAClE,IAAA,IAAA,CAAK,oBAAoB,OAAQ,CAAA,iBAAA;AACjC,IAAK,IAAA,CAAA,OAAA,GAAU,OAAQ,CAAA,OAAA,IAAW,eAAgB,EAAA;AAClD,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA;AAE3B,IAAA,IAAA,CAAK,QAAW,GAAA,KAAA,CAAA;AAAA;AAClB,EAEA,MAAM,KAAQ,GAAA;AACZ,IAAA,IAAI,KAAK,QAAU,EAAA;AACjB,MAAM,MAAA,IAAI,MAAM,sCAAsC,CAAA;AAAA;AAGxD,IAAM,MAAA,YAAA,GAAe,KAAK,aAAc,EAAA;AACxC,IAAM,MAAA,WAAA,GAAc,KAAK,kBAAmB,EAAA;AAE5C,IAAA,IAAA,CAAK,WAAW,MAAM;AACpB,MAAa,YAAA,EAAA;AACb,MAAY,WAAA,EAAA;AAAA,KACd;AAAA;AACF,EAEA,MAAM,IAAO,GAAA;AACX,IAAA,IAAI,KAAK,QAAU,EAAA;AACjB,MAAA,IAAA,CAAK,QAAS,EAAA;AACd,MAAA,IAAA,CAAK,QAAW,GAAA,KAAA,CAAA;AAAA;AAClB;AACF,EAEQ,aAA4B,GAAA;AAClC,IAAA,OAAOC,8BAAoC,CAAA;AAAA,MACzC,YAAc,EAAA,CAAA;AAAA,MACd,aAAe,EAAA,EAAA;AAAA,MACf,mBAAmB,IAAK,CAAA,iBAAA;AAAA,MACxB,SAAA,EAAW,OAAM,KAAS,KAAA;AACxB,QAAI,IAAA;AACF,UAAM,MAAA,EAAE,OACN,GAAA,MAAM,KAAK,kBAAmB,CAAA,sBAAA,CAAuB,KAAK,IAAM,EAAA;AAAA,YAC9D,gBAAkB,EAAA;AAAA,WACnB,CAAA;AACH,UAAO,OAAA,KAAA;AAAA,iBACA,KAAO,EAAA;AACd,UAAK,IAAA,CAAA,MAAA,CAAO,IAAK,CAAA,iCAAA,EAAmC,KAAK,CAAA;AACzD,UAAA,OAAO,EAAC;AAAA;AACV,OACF;AAAA,MACA,WAAA,EAAa,OAAM,IAAQ,KAAA;AACzB,QAAA,MAAMC,4BAAe,CAAA,MAAA,EAAQ,eAAiB,EAAA,OAAM,IAAQ,KAAA;AAC1D,UAAA,MAAM,QAAQ,IAAK,CAAA,OAAA,CAAQ,YAAa,CAAA,IAAA,EAAM,KAAK,MAAM,CAAA;AACzD,UAAoBC,iCAAA,CAAA,IAAA,EAAM,KAAK,iBAAiB,CAAA;AAEhD,UAAI,IAAA;AACF,YAAM,MAAA;AAAA,cACJ,EAAA;AAAA,cACA,KAAA;AAAA,cACA,iBAAA;AAAA,cACA,SAAA;AAAA,cACA,WAAA;AAAA,cACA,UAAY,EAAA;AAAA,aACV,GAAA,IAAA;AACJ,YAAA,MAAM,MAAS,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,OAAQ,CAAA;AAAA,cAC7C,MAAQ,EAAA,iBAAA;AAAA,cACR;AAAA,aACD,CAAA;AAED,YAAA,KAAA,CAAM,wBAAwB,MAAM,CAAA;AAEpC,YAAA,IAAI,OAAO,EAAI,EAAA;AACb,cAAA,MAAM,EAAE,GAAK,EAAA,CAAA,EAAG,GAAG,eAAgB,EAAA,GAAI,SAAS,EAAC;AACjD,cAAA,IACEC,iCAAgB,eAAe,CAAA,KAC/BA,gCAAgB,CAAA,MAAA,CAAO,KAAK,CAC5B,EAAA;AACA,gBAAA,MAAM,IAAK,CAAA,kBAAA,CAAmB,WAAY,CAAA,OAAM,EAAM,KAAA;AACpD,kBAAM,MAAA,IAAA,CAAK,kBAAmB,CAAA,iBAAA,CAAkB,EAAI,EAAA;AAAA,oBAClD,EAAA;AAAA,oBACA,KAAO,EAAA;AAAA,sBACL,GAAK,EAAA,SAAA;AAAA,sBACL,GAAG,MAAO,CAAA;AAAA;AACZ,mBACD,CAAA;AAAA,iBACF,CAAA;AAAA;AACH,aACK,MAAA;AACL,cAAA,MAAM,WAAW,KAAO,EAAA,GAAA;AACxB,cAAA,MAAM,GAAM,GAAA,MAAA,CAAO,SAAU,CAAA,QAAQ,IAAK,QAAsB,GAAA,CAAA;AAChE,cAAA,MAAM,IAAK,CAAA,kBAAA,CAAmB,WAAY,CAAA,OAAM,EAAM,KAAA;AACpD,gBAAM,MAAA,IAAA,CAAK,kBAAmB,CAAA,iBAAA,CAAkB,EAAI,EAAA;AAAA,kBAClD,EAAA;AAAA,kBACA,KAAA,EAAO,GAAM,GAAA,CAAA,GAAI,EAAE,GAAG,OAAO,GAAK,EAAA,GAAA,GAAM,CAAE,EAAA,GAAI;AAAC,iBAChD,CAAA;AAAA,eACF,CAAA;AAAA;AAGH,YAAA,MAAM,QACJ,GAAA,iBAAA,EAAmB,QAAU,EAAA,WAAA,GAAcC,gCAAmB,CAAA;AAChE,YAAI,IAAA,MAAA,CAAO,OAAO,MAAQ,EAAA;AACxB,cAAA,IAAA,CAAK,aAAa,OAAQ,CAAA;AAAA,gBACxB,KAAO,EAAAC,8BAAA;AAAA,gBACP,YAAc,EAAA;AAAA,kBACZ,MAAQ,EAAA,SAAA;AAAA,kBACR,QAAA;AAAA,kBACA,QAAQ,MAAO,CAAA;AAAA;AACjB,eACD,CAAA;AAAA;AAEH,YAAA,MAAM,eAAe,IAAK,CAAA,SAAA;AAAA,cACxB,OAAO,MAAO,CAAA,GAAA,CAAI,CAAK,CAAA,KAAAC,qBAAA,CAAe,CAAC,CAAC;AAAA,aAC1C;AAEA,YAAA,IAAI,WAAc,GAAA,IAAA,CAAK,UAAW,EAAA,CAAE,OAAO,YAAY,CAAA;AAEvD,YAAA,IAAI,OAAO,EAAI,EAAA;AACb,cAAA,MAAM,EAAE,UAAY,EAAA,OAAA,EAClB,GAAA,MAAM,KAAK,kBAAmB,CAAA,WAAA;AAAA,gBAAY,CACxC,EAAA,KAAA,IAAA,CAAK,kBAAmB,CAAA,WAAA,CAAY,EAAI,EAAA;AAAA,kBACtC,UAAY,EAAA;AAAA,oBACV,SAAA;AAAA,oBACA,GAAG,OAAO,gBAAiB,CAAA,GAAA;AAAA,sBAAI,CAAA,CAAA,KAC7BC,+BAAmB,CAAA,CAAA,CAAE,MAAM;AAAA;AAC7B;AACF,iBACD;AAAA,eACH;AAEF,cAAA,WAAA,GAAc,YACX,MAAO,CAAAJ,gCAAA,CAAgB,EAAE,GAAG,MAAA,CAAO,iBAAiB,CAAC,EACrD,MAAO,CAAAA,gCAAA,CAAgB,CAAC,GAAG,MAAA,CAAO,gBAAgB,CAAC,CAAC,EACpD,MAAO,CAAAA,gCAAA,CAAgB,CAAC,GAAG,MAAA,CAAO,SAAS,CAAC,CAAC,EAC7C,MAAO,CAAAA,gCAAA,CAAgB,CAAC,GAAG,MAAA,CAAO,WAAW,CAAC,CAAC,EAC/C,MAAO,CAAAA,gCAAA,CAAgB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAA;AAAA;AAGzC,YAAM,MAAA,UAAA,GAAa,WAAY,CAAA,MAAA,CAAO,KAAK,CAAA;AAC3C,YAAA,IAAI,eAAe,kBAAoB,EAAA;AAIrC,cAAA,KAAA,CAAM,2BAA4B,EAAA;AAClC,cAAA;AAAA;AAUF,YAAI,IAAA,CAAC,OAAO,EAAI,EAAA;AAEd,cAAQ,OAAA,CAAA,OAAA,CAAQ,MAAS,CACtB,CAAA,IAAA;AAAA,gBAAK,MACJ,KAAK,iBAAoB,GAAA;AAAA,kBACvB,iBAAA;AAAA,kBACA,QAAQ,MAAO,CAAA;AAAA,iBAChB;AAAA,eACH,CACC,MAAM,CAAS,KAAA,KAAA;AACd,gBAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,kBACV,CAAiD,8CAAA,EAAAK,qBAAA;AAAA,oBAC/C;AAAA,mBACD,CAAA;AAAA,iBACH;AAAA,eACD,CAAA;AAEH,cAAA,MAAM,IAAK,CAAA,kBAAA,CAAmB,WAAY,CAAA,OAAM,EAAM,KAAA;AACpD,gBAAM,MAAA,IAAA,CAAK,kBAAmB,CAAA,2BAAA,CAA4B,EAAI,EAAA;AAAA,kBAC5D,EAAA;AAAA,kBACA,MAAQ,EAAA,YAAA;AAAA,kBACR;AAAA,iBACD,CAAA;AAAA,eACF,CAAA;AAED,cAAM,MAAA,IAAA,CAAK,SAAS,MAAO,CAAA;AAAA,gBACzB,UAAY,EAAA,CAACD,+BAAmB,CAAA,iBAAiB,CAAC;AAAA,eACnD,CAAA;AAED,cAAA,KAAA,CAAM,wBAAyB,EAAA;AAC/B,cAAA;AAAA;AAGF,YAAO,MAAA,CAAA,eAAA,CAAgB,SAAS,GAAM,GAAA,EAAA;AACtC,YAAI,IAAA,kBAAA;AACJ,YAAA,MAAM,IAAK,CAAA,kBAAA,CAAmB,WAAY,CAAA,OAAM,EAAM,KAAA;AACpD,cAAA,MAAM,EAAE,QAAS,EAAA,GACf,MAAM,IAAK,CAAA,kBAAA,CAAmB,sBAAsB,EAAI,EAAA;AAAA,gBACtD,EAAA;AAAA,gBACA,iBAAiB,MAAO,CAAA,eAAA;AAAA,gBACxB,UAAA;AAAA,gBACA,MAAQ,EAAA,YAAA;AAAA,gBACR,WAAW,MAAO,CAAA,SAAA;AAAA,gBAClB,kBAAkB,MAAO,CAAA,gBAAA;AAAA,gBACzB,WAAA;AAAA,gBACA,aAAa,MAAO,CAAA;AAAA,eACrB,CAAA;AACH,cAAA,kBAAA,GAAqB,IAAI,GAAA;AAAA,gBACvB,QAAA,CAAS,SAAU,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA;AAAA,kBAC1B,CAAA,EAAG,EAAE,iBAAiB,CAAA,CAAA,EAAI,EAAE,IAAI,CAAA,EAAA,EAAK,EAAE,iBAAiB,CAAA,CAAA;AAAA,kBACxD,CAAE,CAAA;AAAA,iBACH;AAAA,eACH;AAAA,aACD,CAAA;AAED,YAAA,MAAM,qBAAqB,IAAI,GAAA;AAAA,cAC7B,MAAA,CAAO,SAAU,CAAA,GAAA,CAAI,CAAY,QAAA,KAAA;AAC/B,gBAAM,MAAA,eAAA,GAAkBA,+BAAmB,CAAA,QAAA,CAAS,MAAM,CAAA;AAC1D,gBAAM,MAAA,eAAA,GAAkBA,+BAAmB,CAAA,QAAA,CAAS,MAAM,CAAA;AAC1D,gBAAO,OAAA;AAAA,kBACL,GAAG,eAAe,CAAA,CAAA,EAAI,QAAS,CAAA,IAAI,KAAK,eAAe,CAAA,CAAA;AAAA,kBACvD;AAAA,iBACF;AAAA,eACD;AAAA,aACH;AAEA,YAAM,MAAA,mBAAA,uBAA0B,GAAY,CAAA;AAAA,cAC1CA,+BAAA,CAAmB,OAAO,eAAe;AAAA,aAC1C,CAAA;AACD,YAAmB,kBAAA,CAAA,OAAA,CAAQ,CAAC,eAAA,EAAiB,SAAc,KAAA;AACzD,cAAA,IAAI,CAAC,kBAAA,CAAmB,GAAI,CAAA,SAAS,CAAG,EAAA;AACtC,gBAAA,mBAAA,CAAoB,IAAI,eAAe,CAAA;AAAA;AACzC,aACD,CAAA;AACD,YAAoB,kBAAA,CAAA,OAAA,CAAQ,CAAC,eAAA,EAAiB,SAAc,KAAA;AAC1D,cAAA,IAAI,CAAC,kBAAA,CAAmB,GAAI,CAAA,SAAS,CAAG,EAAA;AACtC,gBAAA,mBAAA,CAAoB,IAAI,eAAe,CAAA;AAAA;AACzC,aACD,CAAA;AAED,YAAM,MAAA,IAAA,CAAK,SAAS,MAAO,CAAA;AAAA,cACzB,UAAY,EAAA;AAAA,aACb,CAAA;AAED,YAAA,KAAA,CAAM,yBAA0B,EAAA;AAAA,mBACzB,KAAO,EAAA;AACd,YAAAE,kBAAA,CAAY,KAAK,CAAA;AACjB,YAAA,KAAA,CAAM,WAAW,KAAK,CAAA;AAAA;AACxB,SACD,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AACH,EAEQ,kBAAiC,GAAA;AACvC,IAAA,MAAM,cACJ,GAAA,IAAA,CAAK,MAAO,CAAA,iBAAA,CAAkB,wBAAwB,CAAK,IAAA,QAAA;AAC7D,IAAA,IAAI,mBAAmB,QAAU,EAAA;AAC/B,MAAA,OAAO,MAAM;AAAA,OAAC;AAAA;AAGhB,IAAM,MAAA,iBAAA,GAAoBC,iCAA4B,CAAA,IAAA,CAAK,MAAM,CAAA;AAEjE,IAAA,MAAM,UAAU,YAAY;AAC1B,MAAI,IAAA;AACF,QAAM,MAAA,CAAA,GAAI,MAAMC,6CAAuB,CAAA;AAAA,UACrC,MAAM,IAAK,CAAA,IAAA;AAAA,UACX,QAAU,EAAA;AAAA,SACX,CAAA;AACD,QAAA,IAAI,IAAI,CAAG,EAAA;AACT,UAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAW,QAAA,EAAA,CAAC,CAAoB,kBAAA,CAAA,CAAA;AAAA;AACnD,eACO,KAAO,EAAA;AACd,QAAK,IAAA,CAAA,MAAA,CAAO,IAAK,CAAA,CAAA,kCAAA,CAAA,EAAsC,KAAK,CAAA;AAAA;AAC9D,KACF;AAEA,IAAA,IAAI,KAAK,SAAW,EAAA;AAClB,MAAM,MAAA,eAAA,GAAkB,IAAI,eAAgB,EAAA;AAE5C,MAAA,IAAA,CAAK,UAAU,YAAa,CAAA;AAAA,QAC1B,EAAI,EAAA,wBAAA;AAAA,QACJ,SAAW,EAAA,EAAE,YAAc,EAAA,IAAA,CAAK,uBAAwB,EAAA;AAAA,QACxD,OAAS,EAAA,EAAE,YAAc,EAAA,IAAA,CAAK,0BAA0B,GAAI,EAAA;AAAA,QAC5D,EAAI,EAAA,OAAA;AAAA,QACJ,QAAQ,eAAgB,CAAA;AAAA,OACzB,CAAA;AAED,MAAA,OAAO,MAAM;AACX,QAAA,eAAA,CAAgB,KAAM,EAAA;AAAA,OACxB;AAAA;AAGF,IAAA,MAAM,WAAc,GAAA,WAAA,CAAY,OAAS,EAAA,IAAA,CAAK,uBAAuB,CAAA;AACrE,IAAA,OAAO,MAAM;AACX,MAAA,aAAA,CAAc,WAAW,CAAA;AAAA,KAC3B;AAAA;AAEJ;AAGA,SAAS,eAAkB,GAAA;AAEzB,EAAA,MAAM,wBAAwBC,2BAAoB,CAAA;AAAA,IAChD,IAAM,EAAA,kCAAA;AAAA,IACN,IAAM,EAAA,6EAAA;AAAA,IACN,UAAA,EAAY,CAAC,QAAQ;AAAA,GACtB,CAAA;AACD,EAAA,MAAM,yBAAyBC,2BAAoB,CAAA;AAAA,IACjD,IAAM,EAAA,qCAAA;AAAA,IACN,IAAM,EAAA,8FAAA;AAAA,IACN,UAAA,EAAY,CAAC,QAAQ;AAAA,GACtB,CAAA;AACD,EAAA,MAAM,yBAAyBA,2BAAoB,CAAA;AAAA,IACjD,IAAM,EAAA,qCAAA;AAAA,IACN,IAAM,EAAA,wFAAA;AAAA,IACN,UAAA,EAAY,CAAC,QAAQ;AAAA,GACtB,CAAA;AACD,EAAA,MAAM,2BAA2BA,2BAAoB,CAAA;AAAA,IACnD,IAAM,EAAA,wCAAA;AAAA,IACN,IAAM,EAAA;AAAA,GACP,CAAA;AAED,EAAM,MAAA,KAAA,GAAQC,WAAQ,CAAA,QAAA,CAAS,SAAS,CAAA;AACxC,EAAA,MAAM,oBAAoB,KAAM,CAAA,aAAA;AAAA,IAC9B,kCAAA;AAAA,IACA,EAAE,aAAa,8BAA+B;AAAA,GAChD;AAEA,EAAA,MAAM,qBAAqB,KAAM,CAAA,eAAA;AAAA,IAC/B,6BAAA;AAAA,IACA;AAAA,MACE,WAAa,EAAA,+CAAA;AAAA,MACb,IAAM,EAAA;AAAA;AACR,GACF;AAEA,EAAA,MAAM,qBAAqB,KAAM,CAAA,eAAA;AAAA,IAC/B,6BAAA;AAAA,IACA;AAAA,MACE,WAAa,EAAA,yCAAA;AAAA,MACb,IAAM,EAAA;AAAA;AACR,GACF;AAEA,EAAA,MAAM,uBAAuB,KAAM,CAAA,eAAA;AAAA,IACjC,gCAAA;AAAA,IACA;AAAA,MACE,WACE,EAAA,uGAAA;AAAA,MACF,IAAM,EAAA;AAAA;AACR,GACF;AAEA,EAAS,SAAA,YAAA,CAAa,MAAwB,MAAuB,EAAA;AACnE,IAAM,MAAA,SAAA,GAAY,QAAQ,MAAO,EAAA;AACjC,IAAM,MAAA,eAAA,GAAkB,uBAAuB,UAAW,EAAA;AAC1D,IAAM,MAAA,kBAAA,GAAqB,uBAAuB,UAAW,EAAA;AAE7D,IAAA,MAAA,CAAO,KAAM,CAAA,CAAA,WAAA,EAAc,IAAK,CAAA,SAAS,CAAE,CAAA,CAAA;AAE3C,IAAA,IAAI,KAAK,YAAc,EAAA;AACrB,MAAA,MAAM,UAAU,CAAC,IAAA,CAAK,aAAa,OAAQ,EAAA,CAAE,GAAG,SAAS,CAAA;AACzD,MAAA,wBAAA,CAAyB,QAAQ,OAAO,CAAA;AACxC,MAAA,oBAAA,CAAqB,OAAO,OAAO,CAAA;AAAA;AAGrC,IAAA,SAAS,OAAU,GAAA;AACjB,MAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,MAAA,CAAO,SAAS,CAAA;AACtC,MAAA,OAAO,KAAM,CAAA,CAAC,CAAI,GAAA,KAAA,CAAM,CAAC,CAAI,GAAA,GAAA;AAAA;AAG/B,IAAA,SAAS,wBAAwB,MAAgC,EAAA;AAC/D,MAAA,kBAAA,CAAmB,EAAE,MAAQ,EAAA,MAAA,CAAO,EAAK,GAAA,IAAA,GAAO,UAAU,CAAA;AAC1D,MAAmB,kBAAA,CAAA,MAAA,CAAO,SAAW,EAAA;AAAA,QACnC,MAAA,EAAQ,MAAO,CAAA,EAAA,GAAK,IAAO,GAAA;AAAA,OAC5B,CAAA;AAAA;AAGH,IAAA,SAAS,2BAA8B,GAAA;AACrC,MAAgB,eAAA,CAAA,EAAE,MAAQ,EAAA,WAAA,EAAa,CAAA;AACvC,MAAA,qBAAA,CAAsB,GAAI,CAAA,EAAE,MAAQ,EAAA,WAAA,IAAe,CAAC,CAAA;AAEpD,MAAA,kBAAA,CAAmB,OAAO,OAAQ,EAAA,EAAG,EAAE,MAAA,EAAQ,aAAa,CAAA;AAC5D,MAAA,iBAAA,CAAkB,GAAI,CAAA,CAAA,EAAG,EAAE,MAAA,EAAQ,aAAa,CAAA;AAAA;AAGlD,IAAA,SAAS,wBAA2B,GAAA;AAClC,MAAgB,eAAA,CAAA,EAAE,MAAQ,EAAA,QAAA,EAAU,CAAA;AACpC,MAAA,qBAAA,CAAsB,GAAI,CAAA,EAAE,MAAQ,EAAA,QAAA,IAAY,CAAC,CAAA;AAEjD,MAAA,kBAAA,CAAmB,OAAO,OAAQ,EAAA,EAAG,EAAE,MAAA,EAAQ,UAAU,CAAA;AACzD,MAAA,iBAAA,CAAkB,GAAI,CAAA,CAAA,EAAG,EAAE,MAAA,EAAQ,UAAU,CAAA;AAAA;AAG/C,IAAA,SAAS,yBAA4B,GAAA;AACnC,MAAgB,eAAA,CAAA,EAAE,MAAQ,EAAA,SAAA,EAAW,CAAA;AACrC,MAAA,qBAAA,CAAsB,GAAI,CAAA,EAAE,MAAQ,EAAA,SAAA,IAAa,CAAC,CAAA;AAElD,MAAA,kBAAA,CAAmB,OAAO,OAAQ,EAAA,EAAG,EAAE,MAAA,EAAQ,WAAW,CAAA;AAC1D,MAAA,iBAAA,CAAkB,GAAI,CAAA,CAAA,EAAG,EAAE,MAAA,EAAQ,WAAW,CAAA;AAAA;AAGhD,IAAA,SAAS,WAAW,KAAc,EAAA;AAChC,MAAA,qBAAA,CAAsB,GAAI,CAAA,EAAE,MAAQ,EAAA,QAAA,IAAY,CAAC,CAAA;AACjD,MAAA,iBAAA,CAAkB,GAAI,CAAA,CAAA,EAAG,EAAE,MAAA,EAAQ,UAAU,CAAA;AAC7C,MAAA,MAAA,CAAO,IAAK,CAAA,CAAA,cAAA,EAAiB,IAAK,CAAA,SAAS,WAAW,KAAK,CAAA;AAAA;AAG7D,IAAO,OAAA;AAAA,MACL,uBAAA;AAAA,MACA,2BAAA;AAAA,MACA,wBAAA;AAAA,MACA,yBAAA;AAAA,MACA;AAAA,KACF;AAAA;AAGF,EAAA,OAAO,EAAE,YAAa,EAAA;AACxB;;;;"}
@@ -317,8 +317,8 @@ class CatalogBuilder {
317
317
  auth,
318
318
  httpAuth
319
319
  } = this.env;
320
- const disableRelationsCompatibility = config.getOptionalBoolean(
321
- "catalog.disableRelationsCompatibility"
320
+ const enableRelationsCompatibility = Boolean(
321
+ config.getOptionalBoolean("catalog.enableRelationsCompatibility")
322
322
  );
323
323
  const policy = this.buildEntityPolicy();
324
324
  const processors = this.buildProcessors();
@@ -352,7 +352,7 @@ class CatalogBuilder {
352
352
  database: dbClient,
353
353
  logger,
354
354
  stitcher,
355
- disableRelationsCompatibility
355
+ enableRelationsCompatibility
356
356
  });
357
357
  let permissionsService;
358
358
  if ("authorizeConditional" in permissions) {
@@ -452,9 +452,9 @@ class CatalogBuilder {
452
452
  httpAuth,
453
453
  permissionsService,
454
454
  auditor,
455
- disableRelationsCompatibility
455
+ enableRelationsCompatibility
456
456
  });
457
- if (config.getOptionalString("catalog.orphanProviderStrategy") === "delete") {
457
+ if (config.getOptionalString("catalog.orphanProviderStrategy") !== "keep") {
458
458
  await evictEntitiesFromOrphanedProviders.evictEntitiesFromOrphanedProviders({
459
459
  db: providerDatabase,
460
460
  providers: entityProviders,
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogBuilder.cjs.js","sources":["../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 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 DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n SchemaValidEntityPolicy,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash from 'lodash';\n\nimport {\n AuditorService,\n AuthService,\n DatabaseService,\n HttpAuthService,\n LoggerService,\n PermissionsRegistryService,\n PermissionsService,\n RootConfigService,\n SchedulerService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntityProvider,\n LocationAnalyzer,\n PlaceholderResolver,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport {\n Permission,\n PermissionAuthorizer,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n} from '@backstage/plugin-permission-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport { CatalogProcessingEngine } from '../processing/types';\nimport {\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing/refresh';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport { evictEntitiesFromOrphanedProviders } from '../processing/evictEntitiesFromOrphanedProviders';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../processors';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../processors/PlaceholderProcessor';\nimport { ConfigLocationEntityProvider } from '../providers/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../providers/DefaultLocationStore';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { defaultEntityDataParser } from '../util/parse';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { AuthorizedLocationAnalyzer } from './AuthorizedLocationAnalyzer';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { createRouter } from './createRouter';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { entitiesResponseToObjects } from './response';\nimport {\n catalogEntityPermissionResourceRef,\n CatalogPermissionRuleInput,\n} from '@backstage/plugin-catalog-node/alpha';\n\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: DatabaseService;\n config: RootConfigService;\n reader: UrlReaderService;\n permissions: PermissionsService | PermissionAuthorizer;\n permissionsRegistry?: PermissionsRegistryService;\n scheduler?: SchedulerService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n auditor?: AuditorService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record<string, PlaceholderResolver>;\n private fieldFormatValidators: Partial<Validators>;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array<EntityPolicy | Array<EntityPolicy>>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial<Validators>): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array<ScmLocationAnalyzer | Array<ScmLocationAnalyzer>>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array<Permission | Array<Permission>>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n permissionsRegistry,\n auditor,\n auth,\n httpAuth,\n } = this.env;\n\n const disableRelationsCompatibility = config.getOptionalBoolean(\n 'catalog.disableRelationsCompatibility',\n );\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n disableRelationsCompatibility,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n permissionsRegistry\n ? createConditionTransformer(\n permissionsRegistry.getPermissionRuleset(\n catalogEntityPermissionResourceRef,\n ),\n )\n : createConditionTransformer(this.permissionRules),\n );\n\n const getResources = async (resourceRefs: string[]) => {\n const { items } = await unauthorizedEntitiesCatalog.entitiesBatch({\n credentials: await auth.getOwnServiceCredentials(),\n entityRefs: resourceRefs,\n });\n\n return entitiesResponseToObjects(items).map(e => e || undefined);\n };\n\n let permissionIntegrationRouter:\n | ReturnType<typeof createPermissionIntegrationRouter>\n | undefined;\n if (permissionsRegistry) {\n permissionsRegistry.addResourceType({\n resourceRef: catalogEntityPermissionResourceRef,\n getResources,\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n } else {\n permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources,\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n }\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new AuthorizedLocationAnalyzer(\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers),\n permissionsService,\n );\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n permissionsService,\n auditor,\n disableRelationsCompatibility,\n });\n\n if (\n config.getOptionalString('catalog.orphanProviderStrategy') === 'delete'\n ) {\n await evictEntitiesFromOrphanedProviders({\n db: providerDatabase,\n providers: entityProviders,\n logger,\n });\n }\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record<string, PlaceholderResolver> = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n const disableDefaultProcessors = config.getOptionalBoolean(\n 'catalog.disableDefaultProcessors',\n );\n\n // Add default processors if:\n // - processors have NOT been explicitly replaced\n // - and default processors are NOT disabled via config\n if (!this.processorsReplace && !disableDefaultProcessors) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n if (!Boolean(config.get('catalog.processingInterval'))) {\n return () => {\n throw new Error(\n 'catalog.processingInterval is set to false, processing is disabled.',\n );\n };\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["catalogPermissions","catalogPermissionRules","createRandomProcessingInterval","lodash","ScmIntegrations","FileReaderProcessor","UrlReaderProcessor","AnnotateLocationEntityProcessor","defaultEntityDataParser","applyDatabaseMigrations","DefaultStitcher","DefaultProcessingDatabase","DefaultProviderDatabase","DefaultCatalogDatabase","DefaultCatalogRulesEnforcer","DefaultEntitiesCatalog","toPermissionEvaluator","DefaultCatalogProcessingOrchestrator","AuthorizedEntitiesCatalog","createConditionTransformer","catalogEntityPermissionResourceRef","entitiesResponseToObjects","createPermissionIntegrationRouter","RESOURCE_TYPE_CATALOG_ENTITY","DefaultLocationStore","ConfigLocationEntityProvider","DefaultCatalogProcessingEngine","createHash","AuthorizedLocationAnalyzer","RepoLocationAnalyzer","AuthorizedLocationService","DefaultLocationService","AuthorizedRefreshService","DefaultRefreshService","createRouter","evictEntitiesFromOrphanedProviders","connectEntityProviders","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","jsonPlaceholderResolver","yamlPlaceholderResolver","textPlaceholderResolver","PlaceholderProcessor","BuiltinKindsEntityProcessor","config","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
1
+ {"version":3,"file":"CatalogBuilder.cjs.js","sources":["../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 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 DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n SchemaValidEntityPolicy,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash from 'lodash';\n\nimport {\n AuditorService,\n AuthService,\n DatabaseService,\n HttpAuthService,\n LoggerService,\n PermissionsRegistryService,\n PermissionsService,\n RootConfigService,\n SchedulerService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntityProvider,\n LocationAnalyzer,\n PlaceholderResolver,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport {\n Permission,\n PermissionAuthorizer,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n} from '@backstage/plugin-permission-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport { CatalogProcessingEngine } from '../processing/types';\nimport {\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing/refresh';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport { evictEntitiesFromOrphanedProviders } from '../processing/evictEntitiesFromOrphanedProviders';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../processors';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../processors/PlaceholderProcessor';\nimport { ConfigLocationEntityProvider } from '../providers/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../providers/DefaultLocationStore';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { defaultEntityDataParser } from '../util/parse';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { AuthorizedLocationAnalyzer } from './AuthorizedLocationAnalyzer';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { createRouter } from './createRouter';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { entitiesResponseToObjects } from './response';\nimport {\n catalogEntityPermissionResourceRef,\n CatalogPermissionRuleInput,\n} from '@backstage/plugin-catalog-node/alpha';\n\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: DatabaseService;\n config: RootConfigService;\n reader: UrlReaderService;\n permissions: PermissionsService | PermissionAuthorizer;\n permissionsRegistry?: PermissionsRegistryService;\n scheduler?: SchedulerService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n auditor?: AuditorService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record<string, PlaceholderResolver>;\n private fieldFormatValidators: Partial<Validators>;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array<EntityPolicy | Array<EntityPolicy>>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial<Validators>): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array<ScmLocationAnalyzer | Array<ScmLocationAnalyzer>>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array<Permission | Array<Permission>>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n permissionsRegistry,\n auditor,\n auth,\n httpAuth,\n } = this.env;\n\n const enableRelationsCompatibility = Boolean(\n config.getOptionalBoolean('catalog.enableRelationsCompatibility'),\n );\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n enableRelationsCompatibility,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n permissionsRegistry\n ? createConditionTransformer(\n permissionsRegistry.getPermissionRuleset(\n catalogEntityPermissionResourceRef,\n ),\n )\n : createConditionTransformer(this.permissionRules),\n );\n\n const getResources = async (resourceRefs: string[]) => {\n const { items } = await unauthorizedEntitiesCatalog.entitiesBatch({\n credentials: await auth.getOwnServiceCredentials(),\n entityRefs: resourceRefs,\n });\n\n return entitiesResponseToObjects(items).map(e => e || undefined);\n };\n\n let permissionIntegrationRouter:\n | ReturnType<typeof createPermissionIntegrationRouter>\n | undefined;\n if (permissionsRegistry) {\n permissionsRegistry.addResourceType({\n resourceRef: catalogEntityPermissionResourceRef,\n getResources,\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n } else {\n permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources,\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n }\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new AuthorizedLocationAnalyzer(\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers),\n permissionsService,\n );\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n permissionsService,\n auditor,\n enableRelationsCompatibility,\n });\n\n if (config.getOptionalString('catalog.orphanProviderStrategy') !== 'keep') {\n await evictEntitiesFromOrphanedProviders({\n db: providerDatabase,\n providers: entityProviders,\n logger,\n });\n }\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record<string, PlaceholderResolver> = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n const disableDefaultProcessors = config.getOptionalBoolean(\n 'catalog.disableDefaultProcessors',\n );\n\n // Add default processors if:\n // - processors have NOT been explicitly replaced\n // - and default processors are NOT disabled via config\n if (!this.processorsReplace && !disableDefaultProcessors) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n if (!Boolean(config.get('catalog.processingInterval'))) {\n return () => {\n throw new Error(\n 'catalog.processingInterval is set to false, processing is disabled.',\n );\n };\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["catalogPermissions","catalogPermissionRules","createRandomProcessingInterval","lodash","ScmIntegrations","FileReaderProcessor","UrlReaderProcessor","AnnotateLocationEntityProcessor","defaultEntityDataParser","applyDatabaseMigrations","DefaultStitcher","DefaultProcessingDatabase","DefaultProviderDatabase","DefaultCatalogDatabase","DefaultCatalogRulesEnforcer","DefaultEntitiesCatalog","toPermissionEvaluator","DefaultCatalogProcessingOrchestrator","AuthorizedEntitiesCatalog","createConditionTransformer","catalogEntityPermissionResourceRef","entitiesResponseToObjects","createPermissionIntegrationRouter","RESOURCE_TYPE_CATALOG_ENTITY","DefaultLocationStore","ConfigLocationEntityProvider","DefaultCatalogProcessingEngine","createHash","AuthorizedLocationAnalyzer","RepoLocationAnalyzer","AuthorizedLocationService","DefaultLocationService","AuthorizedRefreshService","DefaultRefreshService","createRouter","evictEntitiesFromOrphanedProviders","connectEntityProviders","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","jsonPlaceholderResolver","yamlPlaceholderResolver","textPlaceholderResolver","PlaceholderProcessor","BuiltinKindsEntityProcessor","config","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
@@ -48,13 +48,13 @@ class DefaultEntitiesCatalog {
48
48
  database;
49
49
  logger;
50
50
  stitcher;
51
- disableRelationsCompatibility;
51
+ enableRelationsCompatibility;
52
52
  constructor(options) {
53
53
  this.database = options.database;
54
54
  this.logger = options.logger;
55
55
  this.stitcher = options.stitcher;
56
- this.disableRelationsCompatibility = Boolean(
57
- options.disableRelationsCompatibility
56
+ this.enableRelationsCompatibility = Boolean(
57
+ options.enableRelationsCompatibility
58
58
  );
59
59
  }
60
60
  async entities(request) {
@@ -119,13 +119,13 @@ class DefaultEntitiesCatalog {
119
119
  return {
120
120
  entities: process.processRawEntitiesResult(
121
121
  rows.map((r) => r.final_entity),
122
- this.disableRelationsCompatibility ? request?.fields : (e) => {
122
+ this.enableRelationsCompatibility ? (e) => {
123
123
  util.expandLegacyCompoundRelationsInEntity(e);
124
124
  if (request?.fields) {
125
125
  return request.fields(e);
126
126
  }
127
127
  return e;
128
- }
128
+ } : request?.fields
129
129
  ),
130
130
  pageInfo
131
131
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultEntitiesCatalog.cjs.js","sources":["../../src/service/DefaultEntitiesCatalog.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { chunk as lodashChunk, isEqual } from 'lodash';\nimport { z } from 'zod';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n EntityOrder,\n EntityPagination,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport {\n DbFinalEntitiesRow,\n DbPageInfo,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n DbSearchRow,\n} from '../database/tables';\nimport { Stitcher } from '../stitching/types';\n\nimport {\n expandLegacyCompoundRelationsInEntity,\n isQueryEntitiesCursorRequest,\n isQueryEntitiesInitialRequest,\n} from './util';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { applyEntityFilterToQuery } from './request/applyEntityFilterToQuery';\nimport { processRawEntitiesResult } from './response';\n\nconst DEFAULT_LIMIT = 200;\n\nfunction parsePagination(input?: EntityPagination): EntityPagination {\n if (!input) {\n return {};\n }\n\n let { limit, offset } = input;\n\n if (input.after === undefined) {\n return { limit, offset };\n }\n\n let cursor;\n try {\n const json = Buffer.from(input.after, 'base64').toString('utf8');\n cursor = JSON.parse(json);\n } catch {\n throw new InputError('Malformed after cursor, could not be parsed');\n }\n\n if (cursor.limit !== undefined) {\n if (!Number.isInteger(cursor.limit)) {\n throw new InputError('Malformed after cursor, limit was not an number');\n }\n limit = cursor.limit;\n }\n\n if (cursor.offset !== undefined) {\n if (!Number.isInteger(cursor.offset)) {\n throw new InputError('Malformed after cursor, offset was not a number');\n }\n offset = cursor.offset;\n }\n\n return { limit, offset };\n}\n\nfunction stringifyPagination(\n input: Required<Omit<EntityPagination, 'after'>>,\n): string {\n const { limit, offset } = input;\n const json = JSON.stringify({ limit, offset });\n const base64 = Buffer.from(json, 'utf8').toString('base64');\n return base64;\n}\n\nexport class DefaultEntitiesCatalog implements EntitiesCatalog {\n private readonly database: Knex;\n private readonly logger: LoggerService;\n private readonly stitcher: Stitcher;\n private readonly disableRelationsCompatibility: boolean;\n\n constructor(options: {\n database: Knex;\n logger: LoggerService;\n stitcher: Stitcher;\n disableRelationsCompatibility?: boolean;\n }) {\n this.database = options.database;\n this.logger = options.logger;\n this.stitcher = options.stitcher;\n this.disableRelationsCompatibility = Boolean(\n options.disableRelationsCompatibility,\n );\n }\n\n async entities(request?: EntitiesRequest): Promise<EntitiesResponse> {\n const db = this.database;\n const { limit, offset } = parsePagination(request?.pagination);\n\n let entitiesQuery =\n db<DbFinalEntitiesRow>('final_entities').select('final_entities.*');\n\n request?.order?.forEach(({ field }, index) => {\n const alias = `order_${index}`;\n entitiesQuery = entitiesQuery.leftOuterJoin(\n { [alias]: 'search' },\n function search(inner) {\n inner\n .on(`${alias}.entity_id`, 'final_entities.entity_id')\n .andOn(`${alias}.key`, db.raw('?', [field]));\n },\n );\n });\n\n entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity');\n\n if (request?.filter) {\n entitiesQuery = applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: entitiesQuery,\n onEntityIdField: 'final_entities.entity_id',\n knex: db,\n });\n }\n\n request?.order?.forEach(({ order }, index) => {\n if (db.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order, nulls: 'last' },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order: undefined, nulls: 'last' },\n { column: `order_${index}.value`, order },\n ]);\n }\n });\n\n if (!request?.order) {\n entitiesQuery = entitiesQuery.orderBy('final_entities.entity_ref', 'asc'); // default sort\n } else {\n entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort\n }\n\n if (limit !== undefined) {\n entitiesQuery = entitiesQuery.limit(limit + 1);\n }\n if (offset !== undefined) {\n entitiesQuery = entitiesQuery.offset(offset);\n }\n\n let rows = await entitiesQuery;\n let pageInfo: DbPageInfo;\n if (limit === undefined || rows.length <= limit) {\n pageInfo = { hasNextPage: false };\n } else {\n rows = rows.slice(0, -1);\n pageInfo = {\n hasNextPage: true,\n endCursor: stringifyPagination({\n limit,\n offset: (offset ?? 0) + limit,\n }),\n };\n }\n\n return {\n entities: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n this.disableRelationsCompatibility\n ? request?.fields\n : e => {\n expandLegacyCompoundRelationsInEntity(e);\n if (request?.fields) {\n return request.fields(e);\n }\n return e;\n },\n ),\n pageInfo,\n };\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise<EntitiesBatchResponse> {\n const lookup = new Map<string, string>();\n\n for (const chunk of lodashChunk(request.entityRefs, 200)) {\n let query = this.database<DbFinalEntitiesRow>('final_entities')\n .select({\n entityRef: 'final_entities.entity_ref',\n entity: 'final_entities.final_entity',\n })\n .whereIn('final_entities.entity_ref', chunk);\n\n if (request?.filter) {\n query = applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: query,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n for (const row of await query) {\n lookup.set(row.entityRef, row.entity ? row.entity : null);\n }\n }\n\n const items = request.entityRefs.map(ref => lookup.get(ref) ?? null);\n\n return { items: processRawEntitiesResult(items, request.fields) };\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise<QueryEntitiesResponse> {\n const limit = request.limit ?? DEFAULT_LIMIT;\n\n const cursor: Omit<Cursor, 'orderFieldValues'> & {\n orderFieldValues?: (string | null)[];\n skipTotalItems: boolean;\n } = {\n orderFields: [],\n isPrevious: false,\n ...parseCursorFromRequest(request),\n };\n\n // For performance reasons we invoke the count query only on the first\n // request. The result is then embedded into the cursor for subsequent\n // requests. Threfore this can be undefined here, but will then get\n // populated further down.\n const shouldComputeTotalItems =\n cursor.totalItems === undefined && !cursor.skipTotalItems;\n const isFetchingBackwards = cursor.isPrevious;\n\n if (cursor.orderFields.length > 1) {\n this.logger.warn(`Only one sort field is supported, ignoring the rest`);\n }\n\n const sortField = cursor.orderFields.at(0);\n\n // The first part of the query builder is a subquery that applies all of the\n // filtering.\n const dbQuery = this.database.with(\n 'filtered',\n ['entity_id', 'final_entity', ...(sortField ? ['value'] : [])],\n inner => {\n inner\n .from<DbFinalEntitiesRow>('final_entities')\n .whereNotNull('final_entity');\n\n if (sortField) {\n inner\n .distinct()\n .leftOuterJoin('search', qb =>\n qb\n .on('search.entity_id', 'final_entities.entity_id')\n .andOnVal('search.key', sortField.field),\n )\n .select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n value: 'search.value',\n });\n } else {\n inner.select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n });\n }\n\n // Add regular filters, if given\n if (cursor.filter) {\n applyEntityFilterToQuery({\n filter: cursor.filter,\n targetQuery: inner,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n // Add full text search filters, if given\n const normalizedFullTextFilterTerm =\n cursor.fullTextFilter?.term?.trim();\n const textFilterFields = cursor.fullTextFilter?.fields ?? [\n sortField?.field || 'metadata.uid',\n ];\n if (normalizedFullTextFilterTerm) {\n if (\n textFilterFields.length === 1 &&\n textFilterFields[0] === sortField?.field\n ) {\n // If there is one item, apply the like query to the top level query which is already\n // filtered based on the singular sortField.\n inner.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n } else {\n const matchQuery = this.database<DbSearchRow>('search')\n .select('search.entity_id')\n // textFilterFields must be lowercased to match searchable keys in database, i.e. spec.profile.displayName -> spec.profile.displayname\n .whereIn(\n 'search.key',\n textFilterFields.map(field => field.toLocaleLowerCase('en-US')),\n )\n .andWhere(function keyFilter() {\n this.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase(\n 'en-US',\n )}%`,\n );\n });\n inner.andWhere('final_entities.entity_id', 'in', matchQuery);\n }\n }\n },\n );\n\n // Only pay the cost of counting the number of items if needed\n if (shouldComputeTotalItems) {\n // Note the intentional cross join here. The filtered_count dataset is\n // always exactly one row, so it won't grow the result unnecessarily. But\n // it's also important that there IS at least one row, because even if the\n // filtered dataset is empty, we still want to know the total number of\n // items.\n dbQuery\n .with('filtered_count', ['count'], inner =>\n inner.from('filtered').count('*', { as: 'count' }),\n )\n .fromRaw('filtered_count, filtered')\n .select('count', 'filtered.*');\n } else {\n dbQuery.from('filtered').select('*');\n }\n\n const isOrderingDescending = sortField?.order === 'desc';\n\n // Move forward (or backward) in the set to the correct cursor position\n if (cursor.orderFieldValues) {\n if (cursor.orderFieldValues.length === 2) {\n // The first will be the sortField value, the second the entity_id\n const [first, second] = cursor.orderFieldValues;\n dbQuery.andWhere(function nested() {\n this.where(\n 'filtered.value',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n first,\n )\n .orWhere('filtered.value', '=', first)\n .andWhere(\n 'filtered.entity_id',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n second,\n );\n });\n } else if (cursor.orderFieldValues.length === 1) {\n // This will be the entity_id\n const [first] = cursor.orderFieldValues;\n dbQuery.andWhere('entity_id', isFetchingBackwards ? '<' : '>', first);\n }\n }\n\n // Add the ordering\n let order = sortField?.order ?? 'asc';\n if (isFetchingBackwards) {\n order = invertOrder(order);\n }\n if (this.database.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order,\n nulls: 'last',\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order: undefined,\n nulls: 'last',\n },\n {\n column: 'filtered.value',\n order,\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n }\n\n // Apply a manually set initial offset\n if (\n isQueryEntitiesInitialRequest(request) &&\n request.offset !== undefined\n ) {\n dbQuery.offset(request.offset);\n }\n // fetch an extra item to check if there are more items.\n dbQuery.limit(isFetchingBackwards ? limit : limit + 1);\n\n const rows = shouldComputeTotalItems || limit > 0 ? await dbQuery : [];\n\n let totalItems: number;\n if (cursor.totalItems !== undefined) {\n totalItems = cursor.totalItems;\n } else if (cursor.skipTotalItems) {\n totalItems = 0;\n } else if (rows.length) {\n totalItems = Number(rows[0].count);\n } else {\n totalItems = 0;\n }\n\n if (isFetchingBackwards) {\n rows.reverse();\n }\n const hasMoreResults =\n limit > 0 && (isFetchingBackwards || rows.length > limit);\n\n // discard the extra item only when fetching forward.\n if (rows.length > limit) {\n rows.length -= 1;\n }\n\n const isInitialRequest = cursor.firstSortFieldValues === undefined;\n\n const firstRow = rows[0];\n const lastRow = rows[rows.length - 1];\n\n const firstSortFieldValues =\n cursor.firstSortFieldValues || sortFieldsFromRow(firstRow, sortField);\n\n const nextCursor: Cursor | undefined = hasMoreResults\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(lastRow, sortField),\n firstSortFieldValues,\n isPrevious: false,\n totalItems,\n }\n : undefined;\n\n const prevCursor: Cursor | undefined =\n !isInitialRequest &&\n rows.length > 0 &&\n !isEqual(\n sortFieldsFromRow(firstRow, sortField),\n cursor.firstSortFieldValues,\n )\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(firstRow, sortField),\n firstSortFieldValues: cursor.firstSortFieldValues,\n isPrevious: true,\n totalItems,\n }\n : undefined;\n\n return {\n items: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n request.fields,\n ),\n pageInfo: {\n ...(!!prevCursor && { prevCursor }),\n ...(!!nextCursor && { nextCursor }),\n },\n totalItems,\n };\n }\n\n async removeEntityByUid(uid: string): Promise<void> {\n const dbConfig = this.database.client.config;\n\n // Clear the hashed state of the immediate parents of the deleted entity.\n // This makes sure that when they get reprocessed, their output is written\n // down again. The reason for wanting to do this, is that if the user\n // deletes entities that ARE still emitted by the parent, the parent\n // processing will still generate the same output hash as always, which\n // means it'll never try to write down the children again (it assumes that\n // they already exist). This means that without the code below, the database\n // never \"heals\" from accidental deletes.\n if (dbConfig.client.includes('mysql')) {\n // MySQL doesn't support the syntax we need to do this in a single query,\n // http://dev.mysql.com/doc/refman/5.6/en/update.html\n const results = await this.database<DbRefreshStateRow>('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n await this.database<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn(\n 'entity_id',\n results.map(key => key.entity_id),\n );\n } else {\n await this.database<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n }\n\n // Stitch the entities that the deleted one had relations to. If we do not\n // do this, the entities in the other end of the relations will still look\n // like they have a relation to the entity that was deleted, despite not\n // having any corresponding rows in the relations table.\n const relationPeers = await this.database\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateReferencesRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.target_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.target_entity_ref' })\n .union(other =>\n other\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateReferencesRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.source_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.source_entity_ref' }),\n );\n\n await this.database<DbRefreshStateRow>('refresh_state')\n .where('entity_id', uid)\n .delete();\n\n await this.stitcher.stitch({\n entityRefs: new Set(relationPeers.map(p => p.ref)),\n });\n }\n\n async entityAncestry(rootRef: string): Promise<EntityAncestryResponse> {\n const [rootRow] = await this.database<DbFinalEntitiesRow>('final_entities')\n .where('final_entities.entity_ref', '=', rootRef)\n .select({\n entityJson: 'final_entities.final_entity',\n });\n\n if (!rootRow) {\n throw new NotFoundError(`No such entity ${rootRef}`);\n }\n\n const rootEntity = JSON.parse(rootRow.entityJson) as Entity;\n const seenEntityRefs = new Set<string>();\n const todo = new Array<Entity>();\n const items = new Array<{ entity: Entity; parentEntityRefs: string[] }>();\n\n for (\n let current: Entity | undefined = rootEntity;\n current;\n current = todo.pop()\n ) {\n const currentRef = stringifyEntityRef(current);\n seenEntityRefs.add(currentRef);\n\n const parentRows = await this.database<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n )\n .innerJoin<DbFinalEntitiesRow>('final_entities', {\n 'refresh_state_references.source_entity_ref':\n 'final_entities.entity_ref',\n })\n .where('refresh_state_references.target_entity_ref', '=', currentRef)\n .select({\n parentEntityRef: 'final_entities.entity_ref',\n parentEntityJson: 'final_entities.final_entity',\n });\n\n const parentRefs: string[] = [];\n for (const { parentEntityRef, parentEntityJson } of parentRows) {\n parentRefs.push(parentEntityRef);\n if (!seenEntityRefs.has(parentEntityRef)) {\n seenEntityRefs.add(parentEntityRef);\n todo.push(JSON.parse(parentEntityJson));\n }\n }\n\n items.push({\n entity: current,\n parentEntityRefs: parentRefs,\n });\n }\n\n return {\n rootEntityRef: stringifyEntityRef(rootEntity),\n items,\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {\n const query = this.database<DbSearchRow>('search')\n .whereIn(\n 'search.key',\n request.facets.map(f => f.toLocaleLowerCase('en-US')),\n )\n .whereNotNull('search.original_value')\n .select({\n facet: 'search.key',\n value: 'search.original_value',\n count: this.database.raw('count(*)'),\n })\n .groupBy(['search.key', 'search.original_value']);\n\n if (request.filter) {\n applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: query,\n onEntityIdField: 'search.entity_id',\n knex: this.database,\n });\n }\n\n const rows = await query;\n\n const facets: EntityFacetsResponse['facets'] = {};\n for (const facet of request.facets) {\n const facetLowercase = facet.toLocaleLowerCase('en-US');\n facets[facet] = rows\n .filter(row => row.facet === facetLowercase)\n .map(row => ({\n value: String(row.value),\n count: Number(row.count),\n }));\n }\n\n return { facets };\n }\n}\n\nconst entityFilterParser: z.ZodSchema<EntityFilter> = z.lazy(() =>\n z\n .object({\n key: z.string(),\n values: z.array(z.string()).optional(),\n })\n .or(z.object({ not: entityFilterParser }))\n .or(z.object({ anyOf: z.array(entityFilterParser) }))\n .or(z.object({ allOf: z.array(entityFilterParser) })),\n);\n\nexport const cursorParser: z.ZodSchema<Cursor> = z.object({\n orderFields: z.array(\n z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),\n ),\n orderFieldValues: z.array(z.string().or(z.null())),\n filter: entityFilterParser.optional(),\n isPrevious: z.boolean(),\n query: z.string().optional(),\n firstSortFieldValues: z.array(z.string().or(z.null())).optional(),\n totalItems: z.number().optional(),\n});\n\nfunction parseCursorFromRequest(\n request?: QueryEntitiesRequest,\n): Partial<Cursor> & { skipTotalItems: boolean } {\n if (isQueryEntitiesInitialRequest(request)) {\n const {\n filter,\n orderFields: sortFields = [],\n fullTextFilter,\n skipTotalItems = false,\n } = request;\n return { filter, orderFields: sortFields, fullTextFilter, skipTotalItems };\n }\n if (isQueryEntitiesCursorRequest(request)) {\n return {\n ...request.cursor,\n // Doesn't matter here\n skipTotalItems: false,\n };\n }\n return {\n skipTotalItems: false,\n };\n}\n\nfunction invertOrder(order: EntityOrder['order']) {\n return order === 'asc' ? 'desc' : 'asc';\n}\n\nfunction sortFieldsFromRow(\n row: DbSearchRow & DbFinalEntitiesRow,\n sortField?: EntityOrder | undefined,\n) {\n return sortField ? [row?.value, row?.entity_id] : [row?.entity_id];\n}\n"],"names":["InputError","applyEntityFilterToQuery","processRawEntitiesResult","expandLegacyCompoundRelationsInEntity","lodashChunk","isQueryEntitiesInitialRequest","isEqual","NotFoundError","stringifyEntityRef","z","isQueryEntitiesCursorRequest"],"mappings":"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"}
1
+ {"version":3,"file":"DefaultEntitiesCatalog.cjs.js","sources":["../../src/service/DefaultEntitiesCatalog.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { chunk as lodashChunk, isEqual } from 'lodash';\nimport { z } from 'zod';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n EntityOrder,\n EntityPagination,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport {\n DbFinalEntitiesRow,\n DbPageInfo,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n DbSearchRow,\n} from '../database/tables';\nimport { Stitcher } from '../stitching/types';\n\nimport {\n expandLegacyCompoundRelationsInEntity,\n isQueryEntitiesCursorRequest,\n isQueryEntitiesInitialRequest,\n} from './util';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { applyEntityFilterToQuery } from './request/applyEntityFilterToQuery';\nimport { processRawEntitiesResult } from './response';\n\nconst DEFAULT_LIMIT = 200;\n\nfunction parsePagination(input?: EntityPagination): EntityPagination {\n if (!input) {\n return {};\n }\n\n let { limit, offset } = input;\n\n if (input.after === undefined) {\n return { limit, offset };\n }\n\n let cursor;\n try {\n const json = Buffer.from(input.after, 'base64').toString('utf8');\n cursor = JSON.parse(json);\n } catch {\n throw new InputError('Malformed after cursor, could not be parsed');\n }\n\n if (cursor.limit !== undefined) {\n if (!Number.isInteger(cursor.limit)) {\n throw new InputError('Malformed after cursor, limit was not an number');\n }\n limit = cursor.limit;\n }\n\n if (cursor.offset !== undefined) {\n if (!Number.isInteger(cursor.offset)) {\n throw new InputError('Malformed after cursor, offset was not a number');\n }\n offset = cursor.offset;\n }\n\n return { limit, offset };\n}\n\nfunction stringifyPagination(\n input: Required<Omit<EntityPagination, 'after'>>,\n): string {\n const { limit, offset } = input;\n const json = JSON.stringify({ limit, offset });\n const base64 = Buffer.from(json, 'utf8').toString('base64');\n return base64;\n}\n\nexport class DefaultEntitiesCatalog implements EntitiesCatalog {\n private readonly database: Knex;\n private readonly logger: LoggerService;\n private readonly stitcher: Stitcher;\n private readonly enableRelationsCompatibility: boolean;\n\n constructor(options: {\n database: Knex;\n logger: LoggerService;\n stitcher: Stitcher;\n enableRelationsCompatibility?: boolean;\n }) {\n this.database = options.database;\n this.logger = options.logger;\n this.stitcher = options.stitcher;\n this.enableRelationsCompatibility = Boolean(\n options.enableRelationsCompatibility,\n );\n }\n\n async entities(request?: EntitiesRequest): Promise<EntitiesResponse> {\n const db = this.database;\n const { limit, offset } = parsePagination(request?.pagination);\n\n let entitiesQuery =\n db<DbFinalEntitiesRow>('final_entities').select('final_entities.*');\n\n request?.order?.forEach(({ field }, index) => {\n const alias = `order_${index}`;\n entitiesQuery = entitiesQuery.leftOuterJoin(\n { [alias]: 'search' },\n function search(inner) {\n inner\n .on(`${alias}.entity_id`, 'final_entities.entity_id')\n .andOn(`${alias}.key`, db.raw('?', [field]));\n },\n );\n });\n\n entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity');\n\n if (request?.filter) {\n entitiesQuery = applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: entitiesQuery,\n onEntityIdField: 'final_entities.entity_id',\n knex: db,\n });\n }\n\n request?.order?.forEach(({ order }, index) => {\n if (db.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order, nulls: 'last' },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order: undefined, nulls: 'last' },\n { column: `order_${index}.value`, order },\n ]);\n }\n });\n\n if (!request?.order) {\n entitiesQuery = entitiesQuery.orderBy('final_entities.entity_ref', 'asc'); // default sort\n } else {\n entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort\n }\n\n if (limit !== undefined) {\n entitiesQuery = entitiesQuery.limit(limit + 1);\n }\n if (offset !== undefined) {\n entitiesQuery = entitiesQuery.offset(offset);\n }\n\n let rows = await entitiesQuery;\n let pageInfo: DbPageInfo;\n if (limit === undefined || rows.length <= limit) {\n pageInfo = { hasNextPage: false };\n } else {\n rows = rows.slice(0, -1);\n pageInfo = {\n hasNextPage: true,\n endCursor: stringifyPagination({\n limit,\n offset: (offset ?? 0) + limit,\n }),\n };\n }\n\n return {\n entities: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n this.enableRelationsCompatibility\n ? e => {\n expandLegacyCompoundRelationsInEntity(e);\n if (request?.fields) {\n return request.fields(e);\n }\n return e;\n }\n : request?.fields,\n ),\n pageInfo,\n };\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise<EntitiesBatchResponse> {\n const lookup = new Map<string, string>();\n\n for (const chunk of lodashChunk(request.entityRefs, 200)) {\n let query = this.database<DbFinalEntitiesRow>('final_entities')\n .select({\n entityRef: 'final_entities.entity_ref',\n entity: 'final_entities.final_entity',\n })\n .whereIn('final_entities.entity_ref', chunk);\n\n if (request?.filter) {\n query = applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: query,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n for (const row of await query) {\n lookup.set(row.entityRef, row.entity ? row.entity : null);\n }\n }\n\n const items = request.entityRefs.map(ref => lookup.get(ref) ?? null);\n\n return { items: processRawEntitiesResult(items, request.fields) };\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise<QueryEntitiesResponse> {\n const limit = request.limit ?? DEFAULT_LIMIT;\n\n const cursor: Omit<Cursor, 'orderFieldValues'> & {\n orderFieldValues?: (string | null)[];\n skipTotalItems: boolean;\n } = {\n orderFields: [],\n isPrevious: false,\n ...parseCursorFromRequest(request),\n };\n\n // For performance reasons we invoke the count query only on the first\n // request. The result is then embedded into the cursor for subsequent\n // requests. Threfore this can be undefined here, but will then get\n // populated further down.\n const shouldComputeTotalItems =\n cursor.totalItems === undefined && !cursor.skipTotalItems;\n const isFetchingBackwards = cursor.isPrevious;\n\n if (cursor.orderFields.length > 1) {\n this.logger.warn(`Only one sort field is supported, ignoring the rest`);\n }\n\n const sortField = cursor.orderFields.at(0);\n\n // The first part of the query builder is a subquery that applies all of the\n // filtering.\n const dbQuery = this.database.with(\n 'filtered',\n ['entity_id', 'final_entity', ...(sortField ? ['value'] : [])],\n inner => {\n inner\n .from<DbFinalEntitiesRow>('final_entities')\n .whereNotNull('final_entity');\n\n if (sortField) {\n inner\n .distinct()\n .leftOuterJoin('search', qb =>\n qb\n .on('search.entity_id', 'final_entities.entity_id')\n .andOnVal('search.key', sortField.field),\n )\n .select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n value: 'search.value',\n });\n } else {\n inner.select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n });\n }\n\n // Add regular filters, if given\n if (cursor.filter) {\n applyEntityFilterToQuery({\n filter: cursor.filter,\n targetQuery: inner,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n // Add full text search filters, if given\n const normalizedFullTextFilterTerm =\n cursor.fullTextFilter?.term?.trim();\n const textFilterFields = cursor.fullTextFilter?.fields ?? [\n sortField?.field || 'metadata.uid',\n ];\n if (normalizedFullTextFilterTerm) {\n if (\n textFilterFields.length === 1 &&\n textFilterFields[0] === sortField?.field\n ) {\n // If there is one item, apply the like query to the top level query which is already\n // filtered based on the singular sortField.\n inner.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n } else {\n const matchQuery = this.database<DbSearchRow>('search')\n .select('search.entity_id')\n // textFilterFields must be lowercased to match searchable keys in database, i.e. spec.profile.displayName -> spec.profile.displayname\n .whereIn(\n 'search.key',\n textFilterFields.map(field => field.toLocaleLowerCase('en-US')),\n )\n .andWhere(function keyFilter() {\n this.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase(\n 'en-US',\n )}%`,\n );\n });\n inner.andWhere('final_entities.entity_id', 'in', matchQuery);\n }\n }\n },\n );\n\n // Only pay the cost of counting the number of items if needed\n if (shouldComputeTotalItems) {\n // Note the intentional cross join here. The filtered_count dataset is\n // always exactly one row, so it won't grow the result unnecessarily. But\n // it's also important that there IS at least one row, because even if the\n // filtered dataset is empty, we still want to know the total number of\n // items.\n dbQuery\n .with('filtered_count', ['count'], inner =>\n inner.from('filtered').count('*', { as: 'count' }),\n )\n .fromRaw('filtered_count, filtered')\n .select('count', 'filtered.*');\n } else {\n dbQuery.from('filtered').select('*');\n }\n\n const isOrderingDescending = sortField?.order === 'desc';\n\n // Move forward (or backward) in the set to the correct cursor position\n if (cursor.orderFieldValues) {\n if (cursor.orderFieldValues.length === 2) {\n // The first will be the sortField value, the second the entity_id\n const [first, second] = cursor.orderFieldValues;\n dbQuery.andWhere(function nested() {\n this.where(\n 'filtered.value',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n first,\n )\n .orWhere('filtered.value', '=', first)\n .andWhere(\n 'filtered.entity_id',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n second,\n );\n });\n } else if (cursor.orderFieldValues.length === 1) {\n // This will be the entity_id\n const [first] = cursor.orderFieldValues;\n dbQuery.andWhere('entity_id', isFetchingBackwards ? '<' : '>', first);\n }\n }\n\n // Add the ordering\n let order = sortField?.order ?? 'asc';\n if (isFetchingBackwards) {\n order = invertOrder(order);\n }\n if (this.database.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order,\n nulls: 'last',\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order: undefined,\n nulls: 'last',\n },\n {\n column: 'filtered.value',\n order,\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n }\n\n // Apply a manually set initial offset\n if (\n isQueryEntitiesInitialRequest(request) &&\n request.offset !== undefined\n ) {\n dbQuery.offset(request.offset);\n }\n // fetch an extra item to check if there are more items.\n dbQuery.limit(isFetchingBackwards ? limit : limit + 1);\n\n const rows = shouldComputeTotalItems || limit > 0 ? await dbQuery : [];\n\n let totalItems: number;\n if (cursor.totalItems !== undefined) {\n totalItems = cursor.totalItems;\n } else if (cursor.skipTotalItems) {\n totalItems = 0;\n } else if (rows.length) {\n totalItems = Number(rows[0].count);\n } else {\n totalItems = 0;\n }\n\n if (isFetchingBackwards) {\n rows.reverse();\n }\n const hasMoreResults =\n limit > 0 && (isFetchingBackwards || rows.length > limit);\n\n // discard the extra item only when fetching forward.\n if (rows.length > limit) {\n rows.length -= 1;\n }\n\n const isInitialRequest = cursor.firstSortFieldValues === undefined;\n\n const firstRow = rows[0];\n const lastRow = rows[rows.length - 1];\n\n const firstSortFieldValues =\n cursor.firstSortFieldValues || sortFieldsFromRow(firstRow, sortField);\n\n const nextCursor: Cursor | undefined = hasMoreResults\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(lastRow, sortField),\n firstSortFieldValues,\n isPrevious: false,\n totalItems,\n }\n : undefined;\n\n const prevCursor: Cursor | undefined =\n !isInitialRequest &&\n rows.length > 0 &&\n !isEqual(\n sortFieldsFromRow(firstRow, sortField),\n cursor.firstSortFieldValues,\n )\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(firstRow, sortField),\n firstSortFieldValues: cursor.firstSortFieldValues,\n isPrevious: true,\n totalItems,\n }\n : undefined;\n\n return {\n items: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n request.fields,\n ),\n pageInfo: {\n ...(!!prevCursor && { prevCursor }),\n ...(!!nextCursor && { nextCursor }),\n },\n totalItems,\n };\n }\n\n async removeEntityByUid(uid: string): Promise<void> {\n const dbConfig = this.database.client.config;\n\n // Clear the hashed state of the immediate parents of the deleted entity.\n // This makes sure that when they get reprocessed, their output is written\n // down again. The reason for wanting to do this, is that if the user\n // deletes entities that ARE still emitted by the parent, the parent\n // processing will still generate the same output hash as always, which\n // means it'll never try to write down the children again (it assumes that\n // they already exist). This means that without the code below, the database\n // never \"heals\" from accidental deletes.\n if (dbConfig.client.includes('mysql')) {\n // MySQL doesn't support the syntax we need to do this in a single query,\n // http://dev.mysql.com/doc/refman/5.6/en/update.html\n const results = await this.database<DbRefreshStateRow>('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n await this.database<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn(\n 'entity_id',\n results.map(key => key.entity_id),\n );\n } else {\n await this.database<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n }\n\n // Stitch the entities that the deleted one had relations to. If we do not\n // do this, the entities in the other end of the relations will still look\n // like they have a relation to the entity that was deleted, despite not\n // having any corresponding rows in the relations table.\n const relationPeers = await this.database\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateReferencesRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.target_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.target_entity_ref' })\n .union(other =>\n other\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateReferencesRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.source_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.source_entity_ref' }),\n );\n\n await this.database<DbRefreshStateRow>('refresh_state')\n .where('entity_id', uid)\n .delete();\n\n await this.stitcher.stitch({\n entityRefs: new Set(relationPeers.map(p => p.ref)),\n });\n }\n\n async entityAncestry(rootRef: string): Promise<EntityAncestryResponse> {\n const [rootRow] = await this.database<DbFinalEntitiesRow>('final_entities')\n .where('final_entities.entity_ref', '=', rootRef)\n .select({\n entityJson: 'final_entities.final_entity',\n });\n\n if (!rootRow) {\n throw new NotFoundError(`No such entity ${rootRef}`);\n }\n\n const rootEntity = JSON.parse(rootRow.entityJson) as Entity;\n const seenEntityRefs = new Set<string>();\n const todo = new Array<Entity>();\n const items = new Array<{ entity: Entity; parentEntityRefs: string[] }>();\n\n for (\n let current: Entity | undefined = rootEntity;\n current;\n current = todo.pop()\n ) {\n const currentRef = stringifyEntityRef(current);\n seenEntityRefs.add(currentRef);\n\n const parentRows = await this.database<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n )\n .innerJoin<DbFinalEntitiesRow>('final_entities', {\n 'refresh_state_references.source_entity_ref':\n 'final_entities.entity_ref',\n })\n .where('refresh_state_references.target_entity_ref', '=', currentRef)\n .select({\n parentEntityRef: 'final_entities.entity_ref',\n parentEntityJson: 'final_entities.final_entity',\n });\n\n const parentRefs: string[] = [];\n for (const { parentEntityRef, parentEntityJson } of parentRows) {\n parentRefs.push(parentEntityRef);\n if (!seenEntityRefs.has(parentEntityRef)) {\n seenEntityRefs.add(parentEntityRef);\n todo.push(JSON.parse(parentEntityJson));\n }\n }\n\n items.push({\n entity: current,\n parentEntityRefs: parentRefs,\n });\n }\n\n return {\n rootEntityRef: stringifyEntityRef(rootEntity),\n items,\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {\n const query = this.database<DbSearchRow>('search')\n .whereIn(\n 'search.key',\n request.facets.map(f => f.toLocaleLowerCase('en-US')),\n )\n .whereNotNull('search.original_value')\n .select({\n facet: 'search.key',\n value: 'search.original_value',\n count: this.database.raw('count(*)'),\n })\n .groupBy(['search.key', 'search.original_value']);\n\n if (request.filter) {\n applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: query,\n onEntityIdField: 'search.entity_id',\n knex: this.database,\n });\n }\n\n const rows = await query;\n\n const facets: EntityFacetsResponse['facets'] = {};\n for (const facet of request.facets) {\n const facetLowercase = facet.toLocaleLowerCase('en-US');\n facets[facet] = rows\n .filter(row => row.facet === facetLowercase)\n .map(row => ({\n value: String(row.value),\n count: Number(row.count),\n }));\n }\n\n return { facets };\n }\n}\n\nconst entityFilterParser: z.ZodSchema<EntityFilter> = z.lazy(() =>\n z\n .object({\n key: z.string(),\n values: z.array(z.string()).optional(),\n })\n .or(z.object({ not: entityFilterParser }))\n .or(z.object({ anyOf: z.array(entityFilterParser) }))\n .or(z.object({ allOf: z.array(entityFilterParser) })),\n);\n\nexport const cursorParser: z.ZodSchema<Cursor> = z.object({\n orderFields: z.array(\n z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),\n ),\n orderFieldValues: z.array(z.string().or(z.null())),\n filter: entityFilterParser.optional(),\n isPrevious: z.boolean(),\n query: z.string().optional(),\n firstSortFieldValues: z.array(z.string().or(z.null())).optional(),\n totalItems: z.number().optional(),\n});\n\nfunction parseCursorFromRequest(\n request?: QueryEntitiesRequest,\n): Partial<Cursor> & { skipTotalItems: boolean } {\n if (isQueryEntitiesInitialRequest(request)) {\n const {\n filter,\n orderFields: sortFields = [],\n fullTextFilter,\n skipTotalItems = false,\n } = request;\n return { filter, orderFields: sortFields, fullTextFilter, skipTotalItems };\n }\n if (isQueryEntitiesCursorRequest(request)) {\n return {\n ...request.cursor,\n // Doesn't matter here\n skipTotalItems: false,\n };\n }\n return {\n skipTotalItems: false,\n };\n}\n\nfunction invertOrder(order: EntityOrder['order']) {\n return order === 'asc' ? 'desc' : 'asc';\n}\n\nfunction sortFieldsFromRow(\n row: DbSearchRow & DbFinalEntitiesRow,\n sortField?: EntityOrder | undefined,\n) {\n return sortField ? [row?.value, row?.entity_id] : [row?.entity_id];\n}\n"],"names":["InputError","applyEntityFilterToQuery","processRawEntitiesResult","expandLegacyCompoundRelationsInEntity","lodashChunk","isQueryEntitiesInitialRequest","isEqual","NotFoundError","stringifyEntityRef","z","isQueryEntitiesCursorRequest"],"mappings":";;;;;;;;;;AAwDA,MAAM,aAAgB,GAAA,GAAA;AAEtB,SAAS,gBAAgB,KAA4C,EAAA;AACnE,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAA,OAAO,EAAC;AAAA;AAGV,EAAI,IAAA,EAAE,KAAO,EAAA,MAAA,EAAW,GAAA,KAAA;AAExB,EAAI,IAAA,KAAA,CAAM,UAAU,KAAW,CAAA,EAAA;AAC7B,IAAO,OAAA,EAAE,OAAO,MAAO,EAAA;AAAA;AAGzB,EAAI,IAAA,MAAA;AACJ,EAAI,IAAA;AACF,IAAM,MAAA,IAAA,GAAO,OAAO,IAAK,CAAA,KAAA,CAAM,OAAO,QAAQ,CAAA,CAAE,SAAS,MAAM,CAAA;AAC/D,IAAS,MAAA,GAAA,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,GAClB,CAAA,MAAA;AACN,IAAM,MAAA,IAAIA,kBAAW,6CAA6C,CAAA;AAAA;AAGpE,EAAI,IAAA,MAAA,CAAO,UAAU,KAAW,CAAA,EAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,CAAO,SAAU,CAAA,MAAA,CAAO,KAAK,CAAG,EAAA;AACnC,MAAM,MAAA,IAAIA,kBAAW,iDAAiD,CAAA;AAAA;AAExE,IAAA,KAAA,GAAQ,MAAO,CAAA,KAAA;AAAA;AAGjB,EAAI,IAAA,MAAA,CAAO,WAAW,KAAW,CAAA,EAAA;AAC/B,IAAA,IAAI,CAAC,MAAA,CAAO,SAAU,CAAA,MAAA,CAAO,MAAM,CAAG,EAAA;AACpC,MAAM,MAAA,IAAIA,kBAAW,iDAAiD,CAAA;AAAA;AAExE,IAAA,MAAA,GAAS,MAAO,CAAA,MAAA;AAAA;AAGlB,EAAO,OAAA,EAAE,OAAO,MAAO,EAAA;AACzB;AAEA,SAAS,oBACP,KACQ,EAAA;AACR,EAAM,MAAA,EAAE,KAAO,EAAA,MAAA,EAAW,GAAA,KAAA;AAC1B,EAAA,MAAM,OAAO,IAAK,CAAA,SAAA,CAAU,EAAE,KAAA,EAAO,QAAQ,CAAA;AAC7C,EAAA,MAAM,SAAS,MAAO,CAAA,IAAA,CAAK,MAAM,MAAM,CAAA,CAAE,SAAS,QAAQ,CAAA;AAC1D,EAAO,OAAA,MAAA;AACT;AAEO,MAAM,sBAAkD,CAAA;AAAA,EAC5C,QAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,4BAAA;AAAA,EAEjB,YAAY,OAKT,EAAA;AACD,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA;AACxB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA;AACxB,IAAA,IAAA,CAAK,4BAA+B,GAAA,OAAA;AAAA,MAClC,OAAQ,CAAA;AAAA,KACV;AAAA;AACF,EAEA,MAAM,SAAS,OAAsD,EAAA;AACnE,IAAA,MAAM,KAAK,IAAK,CAAA,QAAA;AAChB,IAAA,MAAM,EAAE,KAAO,EAAA,MAAA,EAAW,GAAA,eAAA,CAAgB,SAAS,UAAU,CAAA;AAE7D,IAAA,IAAI,aACF,GAAA,EAAA,CAAuB,gBAAgB,CAAA,CAAE,OAAO,kBAAkB,CAAA;AAEpE,IAAA,OAAA,EAAS,OAAO,OAAQ,CAAA,CAAC,EAAE,KAAA,IAAS,KAAU,KAAA;AAC5C,MAAM,MAAA,KAAA,GAAQ,SAAS,KAAK,CAAA,CAAA;AAC5B,MAAA,aAAA,GAAgB,aAAc,CAAA,aAAA;AAAA,QAC5B,EAAE,CAAC,KAAK,GAAG,QAAS,EAAA;AAAA,QACpB,SAAS,OAAO,KAAO,EAAA;AACrB,UAAA,KAAA,CACG,GAAG,CAAG,EAAA,KAAK,CAAc,UAAA,CAAA,EAAA,0BAA0B,EACnD,KAAM,CAAA,CAAA,EAAG,KAAK,CAAA,IAAA,CAAA,EAAQ,GAAG,GAAI,CAAA,GAAA,EAAK,CAAC,KAAK,CAAC,CAAC,CAAA;AAAA;AAC/C,OACF;AAAA,KACD,CAAA;AAED,IAAgB,aAAA,GAAA,aAAA,CAAc,aAAa,6BAA6B,CAAA;AAExE,IAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,MAAA,aAAA,GAAgBC,iDAAyB,CAAA;AAAA,QACvC,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,WAAa,EAAA,aAAA;AAAA,QACb,eAAiB,EAAA,0BAAA;AAAA,QACjB,IAAM,EAAA;AAAA,OACP,CAAA;AAAA;AAGH,IAAA,OAAA,EAAS,OAAO,OAAQ,CAAA,CAAC,EAAE,KAAA,IAAS,KAAU,KAAA;AAC5C,MAAA,IAAI,EAAG,CAAA,MAAA,CAAO,MAAO,CAAA,MAAA,KAAW,IAAM,EAAA;AAEpC,QAAA,aAAA,GAAgB,cAAc,OAAQ,CAAA;AAAA,UACpC,EAAE,MAAQ,EAAA,CAAA,MAAA,EAAS,KAAK,CAAU,MAAA,CAAA,EAAA,KAAA,EAAO,OAAO,MAAO;AAAA,SACxD,CAAA;AAAA,OACI,MAAA;AAIL,QAAA,aAAA,GAAgB,cAAc,OAAQ,CAAA;AAAA,UACpC,EAAE,QAAQ,CAAS,MAAA,EAAA,KAAK,UAAU,KAAO,EAAA,KAAA,CAAA,EAAW,OAAO,MAAO,EAAA;AAAA,UAClE,EAAE,MAAA,EAAQ,CAAS,MAAA,EAAA,KAAK,UAAU,KAAM;AAAA,SACzC,CAAA;AAAA;AACH,KACD,CAAA;AAED,IAAI,IAAA,CAAC,SAAS,KAAO,EAAA;AACnB,MAAgB,aAAA,GAAA,aAAA,CAAc,OAAQ,CAAA,2BAAA,EAA6B,KAAK,CAAA;AAAA,KACnE,MAAA;AACL,MAAc,aAAA,CAAA,OAAA,CAAQ,4BAA4B,KAAK,CAAA;AAAA;AAGzD,IAAA,IAAI,UAAU,KAAW,CAAA,EAAA;AACvB,MAAgB,aAAA,GAAA,aAAA,CAAc,KAAM,CAAA,KAAA,GAAQ,CAAC,CAAA;AAAA;AAE/C,IAAA,IAAI,WAAW,KAAW,CAAA,EAAA;AACxB,MAAgB,aAAA,GAAA,aAAA,CAAc,OAAO,MAAM,CAAA;AAAA;AAG7C,IAAA,IAAI,OAAO,MAAM,aAAA;AACjB,IAAI,IAAA,QAAA;AACJ,IAAA,IAAI,KAAU,KAAA,KAAA,CAAA,IAAa,IAAK,CAAA,MAAA,IAAU,KAAO,EAAA;AAC/C,MAAW,QAAA,GAAA,EAAE,aAAa,KAAM,EAAA;AAAA,KAC3B,MAAA;AACL,MAAO,IAAA,GAAA,IAAA,CAAK,KAAM,CAAA,CAAA,EAAG,CAAE,CAAA,CAAA;AACvB,MAAW,QAAA,GAAA;AAAA,QACT,WAAa,EAAA,IAAA;AAAA,QACb,WAAW,mBAAoB,CAAA;AAAA,UAC7B,KAAA;AAAA,UACA,MAAA,EAAA,CAAS,UAAU,CAAK,IAAA;AAAA,SACzB;AAAA,OACH;AAAA;AAGF,IAAO,OAAA;AAAA,MACL,QAAU,EAAAC,gCAAA;AAAA,QACR,IAAK,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,YAAa,CAAA;AAAA,QAC7B,IAAA,CAAK,+BACD,CAAK,CAAA,KAAA;AACH,UAAAC,0CAAA,CAAsC,CAAC,CAAA;AACvC,UAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,YAAO,OAAA,OAAA,CAAQ,OAAO,CAAC,CAAA;AAAA;AAEzB,UAAO,OAAA,CAAA;AAAA,YAET,OAAS,EAAA;AAAA,OACf;AAAA,MACA;AAAA,KACF;AAAA;AACF,EAEA,MAAM,cACJ,OACgC,EAAA;AAChC,IAAM,MAAA,MAAA,uBAAa,GAAoB,EAAA;AAEvC,IAAA,KAAA,MAAW,KAAS,IAAAC,YAAA,CAAY,OAAQ,CAAA,UAAA,EAAY,GAAG,CAAG,EAAA;AACxD,MAAA,IAAI,KAAQ,GAAA,IAAA,CAAK,QAA6B,CAAA,gBAAgB,EAC3D,MAAO,CAAA;AAAA,QACN,SAAW,EAAA,2BAAA;AAAA,QACX,MAAQ,EAAA;AAAA,OACT,CAAA,CACA,OAAQ,CAAA,2BAAA,EAA6B,KAAK,CAAA;AAE7C,MAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,QAAA,KAAA,GAAQH,iDAAyB,CAAA;AAAA,UAC/B,QAAQ,OAAQ,CAAA,MAAA;AAAA,UAChB,WAAa,EAAA,KAAA;AAAA,UACb,eAAiB,EAAA,0BAAA;AAAA,UACjB,MAAM,IAAK,CAAA;AAAA,SACZ,CAAA;AAAA;AAGH,MAAW,KAAA,MAAA,GAAA,IAAO,MAAM,KAAO,EAAA;AAC7B,QAAA,MAAA,CAAO,IAAI,GAAI,CAAA,SAAA,EAAW,IAAI,MAAS,GAAA,GAAA,CAAI,SAAS,IAAI,CAAA;AAAA;AAC1D;AAGF,IAAM,MAAA,KAAA,GAAQ,QAAQ,UAAW,CAAA,GAAA,CAAI,SAAO,MAAO,CAAA,GAAA,CAAI,GAAG,CAAA,IAAK,IAAI,CAAA;AAEnE,IAAA,OAAO,EAAE,KAAO,EAAAC,gCAAA,CAAyB,KAAO,EAAA,OAAA,CAAQ,MAAM,CAAE,EAAA;AAAA;AAClE,EAEA,MAAM,cACJ,OACgC,EAAA;AAChC,IAAM,MAAA,KAAA,GAAQ,QAAQ,KAAS,IAAA,aAAA;AAE/B,IAAA,MAAM,MAGF,GAAA;AAAA,MACF,aAAa,EAAC;AAAA,MACd,UAAY,EAAA,KAAA;AAAA,MACZ,GAAG,uBAAuB,OAAO;AAAA,KACnC;AAMA,IAAA,MAAM,uBACJ,GAAA,MAAA,CAAO,UAAe,KAAA,KAAA,CAAA,IAAa,CAAC,MAAO,CAAA,cAAA;AAC7C,IAAA,MAAM,sBAAsB,MAAO,CAAA,UAAA;AAEnC,IAAI,IAAA,MAAA,CAAO,WAAY,CAAA,MAAA,GAAS,CAAG,EAAA;AACjC,MAAK,IAAA,CAAA,MAAA,CAAO,KAAK,CAAqD,mDAAA,CAAA,CAAA;AAAA;AAGxE,IAAA,MAAM,SAAY,GAAA,MAAA,CAAO,WAAY,CAAA,EAAA,CAAG,CAAC,CAAA;AAIzC,IAAM,MAAA,OAAA,GAAU,KAAK,QAAS,CAAA,IAAA;AAAA,MAC5B,UAAA;AAAA,MACA,CAAC,aAAa,cAAgB,EAAA,GAAI,YAAY,CAAC,OAAO,CAAI,GAAA,EAAG,CAAA;AAAA,MAC7D,CAAS,KAAA,KAAA;AACP,QAAA,KAAA,CACG,IAAyB,CAAA,gBAAgB,CACzC,CAAA,YAAA,CAAa,cAAc,CAAA;AAE9B,QAAA,IAAI,SAAW,EAAA;AACb,UAAA,KAAA,CACG,UACA,CAAA,aAAA;AAAA,YAAc,QAAA;AAAA,YAAU,CAAA,EAAA,KACvB,GACG,EAAG,CAAA,kBAAA,EAAoB,0BAA0B,CACjD,CAAA,QAAA,CAAS,YAAc,EAAA,SAAA,CAAU,KAAK;AAAA,YAE1C,MAAO,CAAA;AAAA,YACN,SAAW,EAAA,0BAAA;AAAA,YACX,YAAc,EAAA,6BAAA;AAAA,YACd,KAAO,EAAA;AAAA,WACR,CAAA;AAAA,SACE,MAAA;AACL,UAAA,KAAA,CAAM,MAAO,CAAA;AAAA,YACX,SAAW,EAAA,0BAAA;AAAA,YACX,YAAc,EAAA;AAAA,WACf,CAAA;AAAA;AAIH,QAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,UAAyBD,iDAAA,CAAA;AAAA,YACvB,QAAQ,MAAO,CAAA,MAAA;AAAA,YACf,WAAa,EAAA,KAAA;AAAA,YACb,eAAiB,EAAA,0BAAA;AAAA,YACjB,MAAM,IAAK,CAAA;AAAA,WACZ,CAAA;AAAA;AAIH,QAAA,MAAM,4BACJ,GAAA,MAAA,CAAO,cAAgB,EAAA,IAAA,EAAM,IAAK,EAAA;AACpC,QAAM,MAAA,gBAAA,GAAmB,MAAO,CAAA,cAAA,EAAgB,MAAU,IAAA;AAAA,UACxD,WAAW,KAAS,IAAA;AAAA,SACtB;AACA,QAAA,IAAI,4BAA8B,EAAA;AAChC,UAAA,IACE,iBAAiB,MAAW,KAAA,CAAA,IAC5B,iBAAiB,CAAC,CAAA,KAAM,WAAW,KACnC,EAAA;AAGA,YAAM,KAAA,CAAA,WAAA;AAAA,cACJ,qBAAA;AAAA,cACA,CAAI,CAAA,EAAA,4BAAA,CAA6B,iBAAkB,CAAA,OAAO,CAAC,CAAA,CAAA;AAAA,aAC7D;AAAA,WACK,MAAA;AACL,YAAA,MAAM,aAAa,IAAK,CAAA,QAAA,CAAsB,QAAQ,CACnD,CAAA,MAAA,CAAO,kBAAkB,CAEzB,CAAA,OAAA;AAAA,cACC,YAAA;AAAA,cACA,iBAAiB,GAAI,CAAA,CAAA,KAAA,KAAS,KAAM,CAAA,iBAAA,CAAkB,OAAO,CAAC;AAAA,aAChE,CACC,QAAS,CAAA,SAAS,SAAY,GAAA;AAC7B,cAAK,IAAA,CAAA,WAAA;AAAA,gBACH,qBAAA;AAAA,gBACA,IAAI,4BAA6B,CAAA,iBAAA;AAAA,kBAC/B;AAAA,iBACD,CAAA,CAAA;AAAA,eACH;AAAA,aACD,CAAA;AACH,YAAM,KAAA,CAAA,QAAA,CAAS,0BAA4B,EAAA,IAAA,EAAM,UAAU,CAAA;AAAA;AAC7D;AACF;AACF,KACF;AAGA,IAAA,IAAI,uBAAyB,EAAA;AAM3B,MACG,OAAA,CAAA,IAAA;AAAA,QAAK,gBAAA;AAAA,QAAkB,CAAC,OAAO,CAAA;AAAA,QAAG,CAAA,KAAA,KACjC,KAAM,CAAA,IAAA,CAAK,UAAU,CAAA,CAAE,MAAM,GAAK,EAAA,EAAE,EAAI,EAAA,OAAA,EAAS;AAAA,QAElD,OAAQ,CAAA,0BAA0B,CAClC,CAAA,MAAA,CAAO,SAAS,YAAY,CAAA;AAAA,KAC1B,MAAA;AACL,MAAA,OAAA,CAAQ,IAAK,CAAA,UAAU,CAAE,CAAA,MAAA,CAAO,GAAG,CAAA;AAAA;AAGrC,IAAM,MAAA,oBAAA,GAAuB,WAAW,KAAU,KAAA,MAAA;AAGlD,IAAA,IAAI,OAAO,gBAAkB,EAAA;AAC3B,MAAI,IAAA,MAAA,CAAO,gBAAiB,CAAA,MAAA,KAAW,CAAG,EAAA;AAExC,QAAA,MAAM,CAAC,KAAA,EAAO,MAAM,CAAA,GAAI,MAAO,CAAA,gBAAA;AAC/B,QAAQ,OAAA,CAAA,QAAA,CAAS,SAAS,MAAS,GAAA;AACjC,UAAK,IAAA,CAAA,KAAA;AAAA,YACH,gBAAA;AAAA,YACA,mBAAA,KAAwB,uBAAuB,GAAM,GAAA,GAAA;AAAA,YACrD;AAAA,WAEC,CAAA,OAAA,CAAQ,gBAAkB,EAAA,GAAA,EAAK,KAAK,CACpC,CAAA,QAAA;AAAA,YACC,oBAAA;AAAA,YACA,mBAAA,KAAwB,uBAAuB,GAAM,GAAA,GAAA;AAAA,YACrD;AAAA,WACF;AAAA,SACH,CAAA;AAAA,OACQ,MAAA,IAAA,MAAA,CAAO,gBAAiB,CAAA,MAAA,KAAW,CAAG,EAAA;AAE/C,QAAM,MAAA,CAAC,KAAK,CAAA,GAAI,MAAO,CAAA,gBAAA;AACvB,QAAA,OAAA,CAAQ,QAAS,CAAA,WAAA,EAAa,mBAAsB,GAAA,GAAA,GAAM,KAAK,KAAK,CAAA;AAAA;AACtE;AAIF,IAAI,IAAA,KAAA,GAAQ,WAAW,KAAS,IAAA,KAAA;AAChC,IAAA,IAAI,mBAAqB,EAAA;AACvB,MAAA,KAAA,GAAQ,YAAY,KAAK,CAAA;AAAA;AAE3B,IAAA,IAAI,IAAK,CAAA,QAAA,CAAS,MAAO,CAAA,MAAA,CAAO,WAAW,IAAM,EAAA;AAE/C,MAAA,OAAA,CAAQ,OAAQ,CAAA;AAAA,QACd,GAAI,SACA,GAAA;AAAA,UACE;AAAA,YACE,MAAQ,EAAA,gBAAA;AAAA,YACR,KAAA;AAAA,YACA,KAAO,EAAA;AAAA;AACT,YAEF,EAAC;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,oBAAA;AAAA,UACR;AAAA;AACF,OACD,CAAA;AAAA,KACI,MAAA;AAIL,MAAA,OAAA,CAAQ,OAAQ,CAAA;AAAA,QACd,GAAI,SACA,GAAA;AAAA,UACE;AAAA,YACE,MAAQ,EAAA,gBAAA;AAAA,YACR,KAAO,EAAA,KAAA,CAAA;AAAA,YACP,KAAO,EAAA;AAAA,WACT;AAAA,UACA;AAAA,YACE,MAAQ,EAAA,gBAAA;AAAA,YACR;AAAA;AACF,YAEF,EAAC;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,oBAAA;AAAA,UACR;AAAA;AACF,OACD,CAAA;AAAA;AAIH,IAAA,IACEI,kCAA8B,CAAA,OAAO,CACrC,IAAA,OAAA,CAAQ,WAAW,KACnB,CAAA,EAAA;AACA,MAAQ,OAAA,CAAA,MAAA,CAAO,QAAQ,MAAM,CAAA;AAAA;AAG/B,IAAA,OAAA,CAAQ,KAAM,CAAA,mBAAA,GAAsB,KAAQ,GAAA,KAAA,GAAQ,CAAC,CAAA;AAErD,IAAA,MAAM,OAAO,uBAA2B,IAAA,KAAA,GAAQ,CAAI,GAAA,MAAM,UAAU,EAAC;AAErE,IAAI,IAAA,UAAA;AACJ,IAAI,IAAA,MAAA,CAAO,eAAe,KAAW,CAAA,EAAA;AACnC,MAAA,UAAA,GAAa,MAAO,CAAA,UAAA;AAAA,KACtB,MAAA,IAAW,OAAO,cAAgB,EAAA;AAChC,MAAa,UAAA,GAAA,CAAA;AAAA,KACf,MAAA,IAAW,KAAK,MAAQ,EAAA;AACtB,MAAA,UAAA,GAAa,MAAO,CAAA,IAAA,CAAK,CAAC,CAAA,CAAE,KAAK,CAAA;AAAA,KAC5B,MAAA;AACL,MAAa,UAAA,GAAA,CAAA;AAAA;AAGf,IAAA,IAAI,mBAAqB,EAAA;AACvB,MAAA,IAAA,CAAK,OAAQ,EAAA;AAAA;AAEf,IAAA,MAAM,cACJ,GAAA,KAAA,GAAQ,CAAM,KAAA,mBAAA,IAAuB,KAAK,MAAS,GAAA,KAAA,CAAA;AAGrD,IAAI,IAAA,IAAA,CAAK,SAAS,KAAO,EAAA;AACvB,MAAA,IAAA,CAAK,MAAU,IAAA,CAAA;AAAA;AAGjB,IAAM,MAAA,gBAAA,GAAmB,OAAO,oBAAyB,KAAA,KAAA,CAAA;AAEzD,IAAM,MAAA,QAAA,GAAW,KAAK,CAAC,CAAA;AACvB,IAAA,MAAM,OAAU,GAAA,IAAA,CAAK,IAAK,CAAA,MAAA,GAAS,CAAC,CAAA;AAEpC,IAAA,MAAM,oBACJ,GAAA,MAAA,CAAO,oBAAwB,IAAA,iBAAA,CAAkB,UAAU,SAAS,CAAA;AAEtE,IAAA,MAAM,aAAiC,cACnC,GAAA;AAAA,MACE,GAAG,MAAA;AAAA,MACH,gBAAA,EAAkB,iBAAkB,CAAA,OAAA,EAAS,SAAS,CAAA;AAAA,MACtD,oBAAA;AAAA,MACA,UAAY,EAAA,KAAA;AAAA,MACZ;AAAA,KAEF,GAAA,KAAA,CAAA;AAEJ,IAAA,MAAM,aACJ,CAAC,gBAAA,IACD,IAAK,CAAA,MAAA,GAAS,KACd,CAACC,cAAA;AAAA,MACC,iBAAA,CAAkB,UAAU,SAAS,CAAA;AAAA,MACrC,MAAO,CAAA;AAAA,KAEL,GAAA;AAAA,MACE,GAAG,MAAA;AAAA,MACH,gBAAA,EAAkB,iBAAkB,CAAA,QAAA,EAAU,SAAS,CAAA;AAAA,MACvD,sBAAsB,MAAO,CAAA,oBAAA;AAAA,MAC7B,UAAY,EAAA,IAAA;AAAA,MACZ;AAAA,KAEF,GAAA,KAAA,CAAA;AAEN,IAAO,OAAA;AAAA,MACL,KAAO,EAAAJ,gCAAA;AAAA,QACL,IAAK,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,YAAa,CAAA;AAAA,QAC7B,OAAQ,CAAA;AAAA,OACV;AAAA,MACA,QAAU,EAAA;AAAA,QACR,GAAI,CAAC,CAAC,UAAA,IAAc,EAAE,UAAW,EAAA;AAAA,QACjC,GAAI,CAAC,CAAC,UAAA,IAAc,EAAE,UAAW;AAAA,OACnC;AAAA,MACA;AAAA,KACF;AAAA;AACF,EAEA,MAAM,kBAAkB,GAA4B,EAAA;AAClD,IAAM,MAAA,QAAA,GAAW,IAAK,CAAA,QAAA,CAAS,MAAO,CAAA,MAAA;AAUtC,IAAA,IAAI,QAAS,CAAA,MAAA,CAAO,QAAS,CAAA,OAAO,CAAG,EAAA;AAGrC,MAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,QAAA,CAA4B,eAAe,CAAA,CACnE,MAAO,CAAA,WAAW,CAClB,CAAA,OAAA,CAAQ,YAAc,EAAA,SAAS,QAAQ,OAAS,EAAA;AAC/C,QAAO,OAAA,OAAA,CACJ,IAAwB,CAAA,eAAe,CACvC,CAAA,SAAA;AAAA,UACC,0BAAA;AAAA,UACA;AAAA,YACE,4CACE,EAAA;AAAA;AACJ,UAED,KAAM,CAAA,yBAAA,EAA2B,KAAK,GAAG,CAAA,CACzC,OAAO,4CAA4C,CAAA;AAAA,OACvD,CAAA;AACH,MAAA,MAAM,IAAK,CAAA,QAAA,CAA4B,eAAe,CAAA,CACnD,MAAO,CAAA;AAAA,QACN,WAAa,EAAA,mBAAA;AAAA,QACb,cAAgB,EAAA,IAAA,CAAK,QAAS,CAAA,EAAA,CAAG,GAAI;AAAA,OACtC,CACA,CAAA,OAAA;AAAA,QACC,WAAA;AAAA,QACA,OAAQ,CAAA,GAAA,CAAI,CAAO,GAAA,KAAA,GAAA,CAAI,SAAS;AAAA,OAClC;AAAA,KACG,MAAA;AACL,MAAA,MAAM,IAAK,CAAA,QAAA,CAA4B,eAAe,CAAA,CACnD,MAAO,CAAA;AAAA,QACN,WAAa,EAAA,mBAAA;AAAA,QACb,cAAgB,EAAA,IAAA,CAAK,QAAS,CAAA,EAAA,CAAG,GAAI;AAAA,OACtC,CACA,CAAA,OAAA,CAAQ,YAAc,EAAA,SAAS,QAAQ,OAAS,EAAA;AAC/C,QAAO,OAAA,OAAA,CACJ,IAAwB,CAAA,eAAe,CACvC,CAAA,SAAA;AAAA,UACC,0BAAA;AAAA,UACA;AAAA,YACE,4CACE,EAAA;AAAA;AACJ,UAED,KAAM,CAAA,yBAAA,EAA2B,KAAK,GAAG,CAAA,CACzC,OAAO,4CAA4C,CAAA;AAAA,OACvD,CAAA;AAAA;AAOL,IAAM,MAAA,aAAA,GAAgB,MAAM,IAAK,CAAA,QAAA,CAC9B,KAAqB,WAAW,CAAA,CAChC,UAAuC,eAAiB,EAAA;AAAA,MACvD,0BAA4B,EAAA;AAAA,KAC7B,CACA,CAAA,KAAA,CAAM,iCAAmC,EAAA,GAAA,EAAK,GAAG,CACjD,CAAA,QAAA,CAAS,yBAA2B,EAAA,IAAA,EAAM,GAAG,CAC7C,CAAA,MAAA,CAAO,EAAE,GAAK,EAAA,6BAAA,EAA+B,CAC7C,CAAA,KAAA;AAAA,MAAM,WACL,KACG,CAAA,IAAA,CAAqB,WAAW,CAAA,CAChC,UAAuC,eAAiB,EAAA;AAAA,QACvD,0BAA4B,EAAA;AAAA,OAC7B,CACA,CAAA,KAAA,CAAM,iCAAmC,EAAA,GAAA,EAAK,GAAG,CACjD,CAAA,QAAA,CAAS,yBAA2B,EAAA,IAAA,EAAM,GAAG,CAC7C,CAAA,MAAA,CAAO,EAAE,GAAA,EAAK,+BAA+B;AAAA,KAClD;AAEF,IAAM,MAAA,IAAA,CAAK,SAA4B,eAAe,CAAA,CACnD,MAAM,WAAa,EAAA,GAAG,EACtB,MAAO,EAAA;AAEV,IAAM,MAAA,IAAA,CAAK,SAAS,MAAO,CAAA;AAAA,MACzB,UAAA,EAAY,IAAI,GAAI,CAAA,aAAA,CAAc,IAAI,CAAK,CAAA,KAAA,CAAA,CAAE,GAAG,CAAC;AAAA,KAClD,CAAA;AAAA;AACH,EAEA,MAAM,eAAe,OAAkD,EAAA;AACrE,IAAA,MAAM,CAAC,OAAO,CAAI,GAAA,MAAM,IAAK,CAAA,QAAA,CAA6B,gBAAgB,CAAA,CACvE,KAAM,CAAA,2BAAA,EAA6B,GAAK,EAAA,OAAO,EAC/C,MAAO,CAAA;AAAA,MACN,UAAY,EAAA;AAAA,KACb,CAAA;AAEH,IAAA,IAAI,CAAC,OAAS,EAAA;AACZ,MAAA,MAAM,IAAIK,oBAAA,CAAc,CAAkB,eAAA,EAAA,OAAO,CAAE,CAAA,CAAA;AAAA;AAGrD,IAAA,MAAM,UAAa,GAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,UAAU,CAAA;AAChD,IAAM,MAAA,cAAA,uBAAqB,GAAY,EAAA;AACvC,IAAM,MAAA,IAAA,GAAO,IAAI,KAAc,EAAA;AAC/B,IAAM,MAAA,KAAA,GAAQ,IAAI,KAAsD,EAAA;AAExE,IAAA,KAAA,IACM,UAA8B,UAClC,EAAA,OAAA,EACA,OAAU,GAAA,IAAA,CAAK,KACf,EAAA;AACA,MAAM,MAAA,UAAA,GAAaC,gCAAmB,OAAO,CAAA;AAC7C,MAAA,cAAA,CAAe,IAAI,UAAU,CAAA;AAE7B,MAAM,MAAA,UAAA,GAAa,MAAM,IAAK,CAAA,QAAA;AAAA,QAC5B;AAAA,OACF,CACG,UAA8B,gBAAkB,EAAA;AAAA,QAC/C,4CACE,EAAA;AAAA,OACH,CACA,CAAA,KAAA,CAAM,8CAA8C,GAAK,EAAA,UAAU,EACnE,MAAO,CAAA;AAAA,QACN,eAAiB,EAAA,2BAAA;AAAA,QACjB,gBAAkB,EAAA;AAAA,OACnB,CAAA;AAEH,MAAA,MAAM,aAAuB,EAAC;AAC9B,MAAA,KAAA,MAAW,EAAE,eAAA,EAAiB,gBAAiB,EAAA,IAAK,UAAY,EAAA;AAC9D,QAAA,UAAA,CAAW,KAAK,eAAe,CAAA;AAC/B,QAAA,IAAI,CAAC,cAAA,CAAe,GAAI,CAAA,eAAe,CAAG,EAAA;AACxC,UAAA,cAAA,CAAe,IAAI,eAAe,CAAA;AAClC,UAAA,IAAA,CAAK,IAAK,CAAA,IAAA,CAAK,KAAM,CAAA,gBAAgB,CAAC,CAAA;AAAA;AACxC;AAGF,MAAA,KAAA,CAAM,IAAK,CAAA;AAAA,QACT,MAAQ,EAAA,OAAA;AAAA,QACR,gBAAkB,EAAA;AAAA,OACnB,CAAA;AAAA;AAGH,IAAO,OAAA;AAAA,MACL,aAAA,EAAeA,gCAAmB,UAAU,CAAA;AAAA,MAC5C;AAAA,KACF;AAAA;AACF,EAEA,MAAM,OAAO,OAA6D,EAAA;AACxE,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,QAAsB,CAAA,QAAQ,CAC9C,CAAA,OAAA;AAAA,MACC,YAAA;AAAA,MACA,QAAQ,MAAO,CAAA,GAAA,CAAI,OAAK,CAAE,CAAA,iBAAA,CAAkB,OAAO,CAAC;AAAA,KAErD,CAAA,YAAA,CAAa,uBAAuB,CAAA,CACpC,MAAO,CAAA;AAAA,MACN,KAAO,EAAA,YAAA;AAAA,MACP,KAAO,EAAA,uBAAA;AAAA,MACP,KAAO,EAAA,IAAA,CAAK,QAAS,CAAA,GAAA,CAAI,UAAU;AAAA,KACpC,CACA,CAAA,OAAA,CAAQ,CAAC,YAAA,EAAc,uBAAuB,CAAC,CAAA;AAElD,IAAA,IAAI,QAAQ,MAAQ,EAAA;AAClB,MAAyBP,iDAAA,CAAA;AAAA,QACvB,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,WAAa,EAAA,KAAA;AAAA,QACb,eAAiB,EAAA,kBAAA;AAAA,QACjB,MAAM,IAAK,CAAA;AAAA,OACZ,CAAA;AAAA;AAGH,IAAA,MAAM,OAAO,MAAM,KAAA;AAEnB,IAAA,MAAM,SAAyC,EAAC;AAChD,IAAW,KAAA,MAAA,KAAA,IAAS,QAAQ,MAAQ,EAAA;AAClC,MAAM,MAAA,cAAA,GAAiB,KAAM,CAAA,iBAAA,CAAkB,OAAO,CAAA;AACtD,MAAO,MAAA,CAAA,KAAK,CAAI,GAAA,IAAA,CACb,MAAO,CAAA,CAAA,GAAA,KAAO,IAAI,KAAU,KAAA,cAAc,CAC1C,CAAA,GAAA,CAAI,CAAQ,GAAA,MAAA;AAAA,QACX,KAAA,EAAO,MAAO,CAAA,GAAA,CAAI,KAAK,CAAA;AAAA,QACvB,KAAA,EAAO,MAAO,CAAA,GAAA,CAAI,KAAK;AAAA,OACvB,CAAA,CAAA;AAAA;AAGN,IAAA,OAAO,EAAE,MAAO,EAAA;AAAA;AAEpB;AAEA,MAAM,qBAAgDQ,KAAE,CAAA,IAAA;AAAA,EAAK,MAC3DA,MACG,MAAO,CAAA;AAAA,IACN,GAAA,EAAKA,MAAE,MAAO,EAAA;AAAA,IACd,QAAQA,KAAE,CAAA,KAAA,CAAMA,MAAE,MAAO,EAAC,EAAE,QAAS;AAAA,GACtC,CAAA,CACA,EAAG,CAAAA,KAAA,CAAE,OAAO,EAAE,GAAA,EAAK,kBAAmB,EAAC,CAAC,CAAA,CACxC,EAAG,CAAAA,KAAA,CAAE,OAAO,EAAE,KAAA,EAAOA,KAAE,CAAA,KAAA,CAAM,kBAAkB,CAAA,EAAG,CAAC,EACnD,EAAG,CAAAA,KAAA,CAAE,MAAO,CAAA,EAAE,OAAOA,KAAE,CAAA,KAAA,CAAM,kBAAkB,CAAA,EAAG,CAAC;AACxD,CAAA;AAEiDA,MAAE,MAAO,CAAA;AAAA,EACxD,aAAaA,KAAE,CAAA,KAAA;AAAA,IACbA,KAAE,CAAA,MAAA,CAAO,EAAE,KAAA,EAAOA,MAAE,MAAO,EAAA,EAAG,KAAO,EAAAA,KAAA,CAAE,KAAK,CAAC,KAAA,EAAO,MAAM,CAAC,GAAG;AAAA,GAChE;AAAA,EACA,gBAAA,EAAkBA,KAAE,CAAA,KAAA,CAAMA,KAAE,CAAA,MAAA,GAAS,EAAG,CAAAA,KAAA,CAAE,IAAK,EAAC,CAAC,CAAA;AAAA,EACjD,MAAA,EAAQ,mBAAmB,QAAS,EAAA;AAAA,EACpC,UAAA,EAAYA,MAAE,OAAQ,EAAA;AAAA,EACtB,KAAO,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,QAAS,EAAA;AAAA,EAC3B,oBAAsB,EAAAA,KAAA,CAAE,KAAM,CAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,EAAG,CAAAA,KAAA,CAAE,IAAK,EAAC,CAAC,CAAA,CAAE,QAAS,EAAA;AAAA,EAChE,UAAY,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,QAAS;AAClC,CAAC;AAED,SAAS,uBACP,OAC+C,EAAA;AAC/C,EAAI,IAAAJ,kCAAA,CAA8B,OAAO,CAAG,EAAA;AAC1C,IAAM,MAAA;AAAA,MACJ,MAAA;AAAA,MACA,WAAA,EAAa,aAAa,EAAC;AAAA,MAC3B,cAAA;AAAA,MACA,cAAiB,GAAA;AAAA,KACf,GAAA,OAAA;AACJ,IAAA,OAAO,EAAE,MAAA,EAAQ,WAAa,EAAA,UAAA,EAAY,gBAAgB,cAAe,EAAA;AAAA;AAE3E,EAAI,IAAAK,iCAAA,CAA6B,OAAO,CAAG,EAAA;AACzC,IAAO,OAAA;AAAA,MACL,GAAG,OAAQ,CAAA,MAAA;AAAA;AAAA,MAEX,cAAgB,EAAA;AAAA,KAClB;AAAA;AAEF,EAAO,OAAA;AAAA,IACL,cAAgB,EAAA;AAAA,GAClB;AACF;AAEA,SAAS,YAAY,KAA6B,EAAA;AAChD,EAAO,OAAA,KAAA,KAAU,QAAQ,MAAS,GAAA,KAAA;AACpC;AAEA,SAAS,iBAAA,CACP,KACA,SACA,EAAA;AACA,EAAO,OAAA,SAAA,GAAY,CAAC,GAAK,EAAA,KAAA,EAAO,KAAK,SAAS,CAAA,GAAI,CAAC,GAAA,EAAK,SAAS,CAAA;AACnE;;;;"}
@@ -44,7 +44,7 @@ async function createRouter(options) {
44
44
  auth,
45
45
  httpAuth,
46
46
  auditor,
47
- disableRelationsCompatibility = false
47
+ enableRelationsCompatibility = false
48
48
  } = options;
49
49
  const readonlyEnabled = config.getOptionalBoolean("catalog.readonly") || false;
50
50
  if (readonlyEnabled) {
@@ -95,7 +95,7 @@ async function createRouter(options) {
95
95
  const order = parseEntityOrderParams.parseEntityOrderParams(req.query);
96
96
  const pagination = parseEntityPaginationParams.parseEntityPaginationParams(req.query);
97
97
  const credentials = await httpAuth.credentials(req);
98
- if (pagination || disableRelationsCompatibility !== true) {
98
+ if (pagination || enableRelationsCompatibility === true) {
99
99
  const { entities, pageInfo } = await entitiesCatalog.entities({
100
100
  filter,
101
101
  fields,
@@ -116,7 +116,7 @@ async function createRouter(options) {
116
116
  await write.writeEntitiesResponse({
117
117
  res,
118
118
  items: entities,
119
- alwaysUseObjectMode: !disableRelationsCompatibility
119
+ alwaysUseObjectMode: enableRelationsCompatibility
120
120
  });
121
121
  return;
122
122
  }
@@ -189,7 +189,7 @@ async function createRouter(options) {
189
189
  await write.writeEntitiesResponse({
190
190
  res,
191
191
  items,
192
- alwaysUseObjectMode: !disableRelationsCompatibility,
192
+ alwaysUseObjectMode: enableRelationsCompatibility,
193
193
  responseWrapper: (entities) => ({
194
194
  items: entities,
195
195
  ...meta
@@ -350,7 +350,7 @@ async function createRouter(options) {
350
350
  await write.writeEntitiesResponse({
351
351
  res,
352
352
  items,
353
- alwaysUseObjectMode: !disableRelationsCompatibility,
353
+ alwaysUseObjectMode: enableRelationsCompatibility,
354
354
  responseWrapper: (entities) => ({
355
355
  items: entities
356
356
  })
@@ -1 +1 @@
1
- {"version":3,"file":"createRouter.cjs.js","sources":["../../src/service/createRouter.ts"],"sourcesContent":["/*\n * Copyright 2020 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 AuditorService,\n AuthService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError, serializeError } from '@backstage/errors';\nimport { LocationAnalyzer } from '@backstage/plugin-catalog-node';\nimport express from 'express';\nimport yn from 'yn';\nimport { z } from 'zod';\nimport { Cursor, EntitiesCatalog } from '../catalog/types';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { validateEntityEnvelope } from '../processing/util';\nimport { createOpenApiRouter } from '../schema/openapi';\nimport { AuthorizedValidationService } from './AuthorizedValidationService';\nimport {\n basicEntityFilter,\n entitiesBatchRequest,\n parseEntityFilterParams,\n parseEntityTransformParams,\n parseQueryEntitiesParams,\n} from './request';\nimport { parseEntityFacetParams } from './request/parseEntityFacetParams';\nimport { parseEntityOrderParams } from './request/parseEntityOrderParams';\nimport { parseEntityPaginationParams } from './request/parseEntityPaginationParams';\nimport {\n createEntityArrayJsonStream,\n writeEntitiesResponse,\n writeSingleEntityResponse,\n} from './response';\nimport { LocationService, RefreshService } from './types';\nimport {\n disallowReadonlyMode,\n encodeCursor,\n locationInput,\n validateRequestBody,\n} from './util';\n\n/**\n * Options used by {@link createRouter}.\n */\nexport interface RouterOptions {\n entitiesCatalog?: EntitiesCatalog;\n locationAnalyzer?: LocationAnalyzer;\n locationService: LocationService;\n orchestrator?: CatalogProcessingOrchestrator;\n refreshService?: RefreshService;\n scheduler?: SchedulerService;\n logger: LoggerService;\n config: Config;\n permissionIntegrationRouter?: express.Router;\n auth: AuthService;\n httpAuth: HttpAuthService;\n permissionsService: PermissionsService;\n // TODO: Require AuditorService once `backend-legacy` is removed\n auditor?: AuditorService;\n disableRelationsCompatibility?: boolean;\n}\n\n/**\n * Creates a catalog router.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = await createOpenApiRouter({\n validatorOptions: {\n // We want the spec to be up to date with the expected value, but the return type needs\n // to be controlled by the router implementation not the request validator.\n ignorePaths: /^\\/validate-entity\\/?$/,\n },\n });\n const {\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n config,\n logger,\n permissionIntegrationRouter,\n permissionsService,\n auth,\n httpAuth,\n auditor,\n disableRelationsCompatibility = false,\n } = options;\n\n const readonlyEnabled =\n config.getOptionalBoolean('catalog.readonly') || false;\n if (readonlyEnabled) {\n logger.info('Catalog is running in readonly mode');\n }\n\n if (refreshService) {\n // TODO: Potentially find a way to track the ancestor that gets refreshed to refresh this entity (as well as the child of that ancestor?)\n router.post('/refresh', async (req, res) => {\n const { authorizationToken, ...restBody } = req.body;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-mutate',\n severityLevel: 'medium',\n meta: {\n queryType: 'refresh',\n entityRef: restBody.entityRef,\n },\n request: req,\n });\n\n try {\n const credentials = authorizationToken\n ? await auth.authenticate(authorizationToken)\n : await httpAuth.credentials(req);\n\n await refreshService.refresh({\n ...restBody,\n credentials,\n });\n\n await auditorEvent?.success();\n res.status(200).end();\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n });\n }\n\n if (permissionIntegrationRouter) {\n router.use(permissionIntegrationRouter);\n }\n\n if (entitiesCatalog) {\n router\n .get('/entities', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'all',\n query: req.query,\n },\n });\n\n try {\n const filter = parseEntityFilterParams(req.query);\n const fields = parseEntityTransformParams(req.query);\n const order = parseEntityOrderParams(req.query);\n const pagination = parseEntityPaginationParams(req.query);\n const credentials = await httpAuth.credentials(req);\n\n // When pagination parameters are passed in, use the legacy slow path\n // that loads all entities into memory\n\n if (pagination || disableRelationsCompatibility !== true) {\n const { entities, pageInfo } = await entitiesCatalog.entities({\n filter,\n fields,\n order,\n pagination,\n credentials,\n });\n\n // Add a Link header to the next page\n if (pageInfo.hasNextPage) {\n const url = new URL(`http://ignored${req.url}`);\n url.searchParams.delete('offset');\n url.searchParams.set('after', pageInfo.endCursor);\n res.setHeader(\n 'link',\n `<${url.pathname}${url.search}>; rel=\"next\"`,\n );\n }\n\n await auditorEvent?.success();\n\n await writeEntitiesResponse({\n res,\n items: entities,\n alwaysUseObjectMode: !disableRelationsCompatibility,\n });\n return;\n }\n\n const responseStream = createEntityArrayJsonStream(res);\n const limit = 10000;\n let cursor: Cursor | undefined;\n\n try {\n let currentWrite: Promise<boolean> | undefined = undefined;\n do {\n const result = await entitiesCatalog.queryEntities(\n !cursor\n ? {\n credentials,\n fields,\n limit,\n filter,\n orderFields: order,\n skipTotalItems: true,\n }\n : { credentials, fields, limit, cursor },\n );\n\n // Wait for previous write to complete\n if (await currentWrite) {\n return; // Client closed connection\n }\n\n if (result.items.entities.length) {\n currentWrite = responseStream.send(result.items);\n }\n\n cursor = result.pageInfo?.nextCursor;\n } while (cursor);\n\n // Wait for last write to complete\n await currentWrite;\n\n await auditorEvent?.success();\n\n responseStream.complete();\n } finally {\n responseStream.close();\n }\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entities/by-query', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-query',\n },\n });\n\n try {\n const { items, pageInfo, totalItems } =\n await entitiesCatalog.queryEntities({\n limit: req.query.limit,\n offset: req.query.offset,\n ...parseQueryEntitiesParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n const meta = {\n totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n };\n\n await auditorEvent?.success({\n // Let's not log out the entities since this can make the log very big\n meta,\n });\n\n await writeEntitiesResponse({\n res,\n items,\n alwaysUseObjectMode: !disableRelationsCompatibility,\n responseWrapper: entities => ({\n items: entities,\n ...meta,\n }),\n });\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-uid',\n uid: uid,\n },\n });\n\n try {\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n\n writeSingleEntityResponse(res, entities, `No entity with uid ${uid}`);\n\n await auditorEvent?.success({\n meta: {\n // stringify to entity refs\n entities: entities.entities.reduce((arr, element) => {\n if (!element) {\n return arr;\n }\n\n if (typeof element === 'string') {\n arr.push(element);\n return arr;\n }\n\n arr.push(stringifyEntityRef(element));\n return arr;\n }, [] as string[]),\n },\n });\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .delete('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-mutate',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'delete',\n uid: uid,\n },\n });\n\n try {\n await entitiesCatalog.removeEntityByUid(uid, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(204).end();\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-name',\n entityRef: entityRef,\n },\n });\n\n try {\n const { items } = await entitiesCatalog.entitiesBatch({\n entityRefs: [stringifyEntityRef({ kind, namespace, name })],\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n writeSingleEntityResponse(\n res,\n items,\n `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`,\n );\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get(\n '/entities/by-name/:kind/:namespace/:name/ancestry',\n async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n actionType: 'ancestry',\n entityRef: entityRef,\n },\n });\n\n try {\n const response = await entitiesCatalog.entityAncestry(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success({\n meta: {\n rootEntityRef: response.rootEntityRef,\n ancestry: response.items.map(ancestryLink => {\n return {\n entityRef: stringifyEntityRef(ancestryLink.entity),\n parentEntityRefs: ancestryLink.parentEntityRefs,\n };\n }),\n },\n });\n\n res.status(200).json(response);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n },\n )\n .post('/entities/by-refs', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-refs',\n },\n });\n\n try {\n const request = entitiesBatchRequest(req);\n const { items } = await entitiesCatalog.entitiesBatch({\n entityRefs: request.entityRefs,\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query, request.fields),\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success({\n meta: {\n ...request,\n },\n });\n\n await writeEntitiesResponse({\n res,\n items,\n alwaysUseObjectMode: !disableRelationsCompatibility,\n responseWrapper: entities => ({\n items: entities,\n }),\n });\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entity-facets', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-facets',\n request: req,\n });\n\n try {\n const response = await entitiesCatalog.facets({\n filter: parseEntityFilterParams(req.query),\n facets: parseEntityFacetParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(200).json(response);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n if (locationService) {\n router\n .post('/locations', async (req, res) => {\n const location = await validateRequestBody(req, locationInput);\n const dryRun = yn(req.query.dryRun, { default: false });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-mutate',\n severityLevel: dryRun ? 'low' : 'medium',\n request: req,\n meta: {\n actionType: 'create',\n location: location,\n isDryRun: dryRun,\n },\n });\n\n try {\n // when in dryRun addLocation is effectively a read operation so we don't\n // need to disallow readonly\n if (!dryRun) {\n disallowReadonlyMode(readonlyEnabled);\n }\n\n const output = await locationService.createLocation(\n location,\n dryRun,\n {\n credentials: await httpAuth.credentials(req),\n },\n );\n\n await auditorEvent?.success({\n meta: {\n location: output.location,\n },\n });\n\n res.status(201).json(output);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n meta: {\n location: location,\n isDryRun: dryRun,\n },\n });\n throw err;\n }\n })\n .get('/locations', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-fetch',\n request: req,\n meta: {\n queryType: 'all',\n },\n });\n\n try {\n const locations = await locationService.listLocations({\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(200).json(locations.map(l => ({ data: l })));\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n\n .get('/locations/:id', async (req, res) => {\n const { id } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-fetch',\n request: req,\n meta: {\n queryType: 'by-id',\n id: id,\n },\n });\n\n try {\n const output = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success({\n meta: {\n output: output,\n },\n });\n\n res.status(200).json(output);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .delete('/locations/:id', async (req, res) => {\n const { id } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-mutate',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'delete',\n id: id,\n },\n });\n\n disallowReadonlyMode(readonlyEnabled);\n\n try {\n await locationService.deleteLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(204).end();\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/locations/by-entity/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const locationRef = `${kind}:${namespace}/${name}`;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-fetch',\n request: req,\n meta: {\n queryType: 'by-entity',\n locationRef: locationRef,\n },\n });\n\n try {\n const output = await locationService.getLocationByEntity(\n { kind, namespace, name },\n { credentials: await httpAuth.credentials(req) },\n );\n\n await auditorEvent?.success({\n meta: {\n output: output,\n },\n });\n\n res.status(200).json(output);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n if (locationAnalyzer) {\n router.post('/analyze-location', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-analyze',\n request: req,\n });\n\n try {\n const body = await validateRequestBody(\n req,\n z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n }),\n );\n const schema = z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n });\n const credentials = await httpAuth.credentials(req);\n const parsedBody = schema.parse(body);\n try {\n const output = await locationAnalyzer.analyzeLocation(\n parsedBody,\n credentials,\n );\n\n await auditorEvent?.success({\n meta: {\n output: output,\n },\n });\n\n res.status(200).json(output);\n } catch (err) {\n if (\n // Catch errors from parse-url library.\n err.name === 'Error' &&\n 'subject_url' in err\n ) {\n throw new InputError('The given location.target is not a URL');\n }\n throw err;\n }\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n if (orchestrator) {\n router.post('/validate-entity', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-validate',\n request: req,\n });\n\n try {\n const bodySchema = z.object({\n entity: z.unknown(),\n location: z.string(),\n });\n\n let body: z.infer<typeof bodySchema>;\n let entity: Entity;\n let location: { type: string; target: string };\n try {\n body = await validateRequestBody(req, bodySchema);\n entity = validateEntityEnvelope(body.entity);\n location = parseLocationRef(body.location);\n if (location.type !== 'url')\n throw new TypeError(\n `Invalid location ref ${body.location}, only 'url:<target>' is supported, e.g. url:https://host/path`,\n );\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n\n return res.status(400).json({\n errors: [serializeError(err)],\n });\n }\n\n const credentials = await httpAuth.credentials(req);\n const authorizedValidationService = new AuthorizedValidationService(\n orchestrator,\n permissionsService,\n );\n const processingResult = await authorizedValidationService.process(\n {\n entity: {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n [ANNOTATION_LOCATION]: body.location,\n [ANNOTATION_ORIGIN_LOCATION]: body.location,\n ...entity.metadata.annotations,\n },\n },\n },\n },\n credentials,\n );\n\n if (!processingResult.ok) {\n const errors = processingResult.errors.map(e => serializeError(e));\n\n await auditorEvent?.fail({\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n error: (AggregateError as any)(errors, 'Could not validate entity'),\n });\n\n res.status(400).json({\n errors,\n });\n }\n\n await auditorEvent?.success();\n\n return res.status(200).end();\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n return router;\n}\n"],"names":["router","createOpenApiRouter","parseEntityFilterParams","parseEntityTransformParams","parseEntityOrderParams","parseEntityPaginationParams","writeEntitiesResponse","createEntityArrayJsonStream","parseQueryEntitiesParams","encodeCursor","basicEntityFilter","writeSingleEntityResponse","stringifyEntityRef","entitiesBatchRequest","parseEntityFacetParams","validateRequestBody","locationInput","yn","disallowReadonlyMode","z","InputError","validateEntityEnvelope","parseLocationRef","serializeError","AuthorizedValidationService","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","errors"],"mappings":"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"}
1
+ {"version":3,"file":"createRouter.cjs.js","sources":["../../src/service/createRouter.ts"],"sourcesContent":["/*\n * Copyright 2020 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 AuditorService,\n AuthService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError, serializeError } from '@backstage/errors';\nimport { LocationAnalyzer } from '@backstage/plugin-catalog-node';\nimport express from 'express';\nimport yn from 'yn';\nimport { z } from 'zod';\nimport { Cursor, EntitiesCatalog } from '../catalog/types';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { validateEntityEnvelope } from '../processing/util';\nimport { createOpenApiRouter } from '../schema/openapi';\nimport { AuthorizedValidationService } from './AuthorizedValidationService';\nimport {\n basicEntityFilter,\n entitiesBatchRequest,\n parseEntityFilterParams,\n parseEntityTransformParams,\n parseQueryEntitiesParams,\n} from './request';\nimport { parseEntityFacetParams } from './request/parseEntityFacetParams';\nimport { parseEntityOrderParams } from './request/parseEntityOrderParams';\nimport { parseEntityPaginationParams } from './request/parseEntityPaginationParams';\nimport {\n createEntityArrayJsonStream,\n writeEntitiesResponse,\n writeSingleEntityResponse,\n} from './response';\nimport { LocationService, RefreshService } from './types';\nimport {\n disallowReadonlyMode,\n encodeCursor,\n locationInput,\n validateRequestBody,\n} from './util';\n\n/**\n * Options used by {@link createRouter}.\n */\nexport interface RouterOptions {\n entitiesCatalog?: EntitiesCatalog;\n locationAnalyzer?: LocationAnalyzer;\n locationService: LocationService;\n orchestrator?: CatalogProcessingOrchestrator;\n refreshService?: RefreshService;\n scheduler?: SchedulerService;\n logger: LoggerService;\n config: Config;\n permissionIntegrationRouter?: express.Router;\n auth: AuthService;\n httpAuth: HttpAuthService;\n permissionsService: PermissionsService;\n // TODO: Require AuditorService once `backend-legacy` is removed\n auditor?: AuditorService;\n enableRelationsCompatibility?: boolean;\n}\n\n/**\n * Creates a catalog router.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = await createOpenApiRouter({\n validatorOptions: {\n // We want the spec to be up to date with the expected value, but the return type needs\n // to be controlled by the router implementation not the request validator.\n ignorePaths: /^\\/validate-entity\\/?$/,\n },\n });\n const {\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n config,\n logger,\n permissionIntegrationRouter,\n permissionsService,\n auth,\n httpAuth,\n auditor,\n enableRelationsCompatibility = false,\n } = options;\n\n const readonlyEnabled =\n config.getOptionalBoolean('catalog.readonly') || false;\n if (readonlyEnabled) {\n logger.info('Catalog is running in readonly mode');\n }\n\n if (refreshService) {\n // TODO: Potentially find a way to track the ancestor that gets refreshed to refresh this entity (as well as the child of that ancestor?)\n router.post('/refresh', async (req, res) => {\n const { authorizationToken, ...restBody } = req.body;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-mutate',\n severityLevel: 'medium',\n meta: {\n queryType: 'refresh',\n entityRef: restBody.entityRef,\n },\n request: req,\n });\n\n try {\n const credentials = authorizationToken\n ? await auth.authenticate(authorizationToken)\n : await httpAuth.credentials(req);\n\n await refreshService.refresh({\n ...restBody,\n credentials,\n });\n\n await auditorEvent?.success();\n res.status(200).end();\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n });\n }\n\n if (permissionIntegrationRouter) {\n router.use(permissionIntegrationRouter);\n }\n\n if (entitiesCatalog) {\n router\n .get('/entities', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'all',\n query: req.query,\n },\n });\n\n try {\n const filter = parseEntityFilterParams(req.query);\n const fields = parseEntityTransformParams(req.query);\n const order = parseEntityOrderParams(req.query);\n const pagination = parseEntityPaginationParams(req.query);\n const credentials = await httpAuth.credentials(req);\n\n // When pagination parameters are passed in, use the legacy slow path\n // that loads all entities into memory\n\n if (pagination || enableRelationsCompatibility === true) {\n const { entities, pageInfo } = await entitiesCatalog.entities({\n filter,\n fields,\n order,\n pagination,\n credentials,\n });\n\n // Add a Link header to the next page\n if (pageInfo.hasNextPage) {\n const url = new URL(`http://ignored${req.url}`);\n url.searchParams.delete('offset');\n url.searchParams.set('after', pageInfo.endCursor);\n res.setHeader(\n 'link',\n `<${url.pathname}${url.search}>; rel=\"next\"`,\n );\n }\n\n await auditorEvent?.success();\n\n await writeEntitiesResponse({\n res,\n items: entities,\n alwaysUseObjectMode: enableRelationsCompatibility,\n });\n return;\n }\n\n const responseStream = createEntityArrayJsonStream(res);\n const limit = 10000;\n let cursor: Cursor | undefined;\n\n try {\n let currentWrite: Promise<boolean> | undefined = undefined;\n do {\n const result = await entitiesCatalog.queryEntities(\n !cursor\n ? {\n credentials,\n fields,\n limit,\n filter,\n orderFields: order,\n skipTotalItems: true,\n }\n : { credentials, fields, limit, cursor },\n );\n\n // Wait for previous write to complete\n if (await currentWrite) {\n return; // Client closed connection\n }\n\n if (result.items.entities.length) {\n currentWrite = responseStream.send(result.items);\n }\n\n cursor = result.pageInfo?.nextCursor;\n } while (cursor);\n\n // Wait for last write to complete\n await currentWrite;\n\n await auditorEvent?.success();\n\n responseStream.complete();\n } finally {\n responseStream.close();\n }\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entities/by-query', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-query',\n },\n });\n\n try {\n const { items, pageInfo, totalItems } =\n await entitiesCatalog.queryEntities({\n limit: req.query.limit,\n offset: req.query.offset,\n ...parseQueryEntitiesParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n const meta = {\n totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n };\n\n await auditorEvent?.success({\n // Let's not log out the entities since this can make the log very big\n meta,\n });\n\n await writeEntitiesResponse({\n res,\n items,\n alwaysUseObjectMode: enableRelationsCompatibility,\n responseWrapper: entities => ({\n items: entities,\n ...meta,\n }),\n });\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-uid',\n uid: uid,\n },\n });\n\n try {\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n\n writeSingleEntityResponse(res, entities, `No entity with uid ${uid}`);\n\n await auditorEvent?.success({\n meta: {\n // stringify to entity refs\n entities: entities.entities.reduce((arr, element) => {\n if (!element) {\n return arr;\n }\n\n if (typeof element === 'string') {\n arr.push(element);\n return arr;\n }\n\n arr.push(stringifyEntityRef(element));\n return arr;\n }, [] as string[]),\n },\n });\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .delete('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-mutate',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'delete',\n uid: uid,\n },\n });\n\n try {\n await entitiesCatalog.removeEntityByUid(uid, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(204).end();\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-name',\n entityRef: entityRef,\n },\n });\n\n try {\n const { items } = await entitiesCatalog.entitiesBatch({\n entityRefs: [stringifyEntityRef({ kind, namespace, name })],\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n writeSingleEntityResponse(\n res,\n items,\n `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`,\n );\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get(\n '/entities/by-name/:kind/:namespace/:name/ancestry',\n async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n actionType: 'ancestry',\n entityRef: entityRef,\n },\n });\n\n try {\n const response = await entitiesCatalog.entityAncestry(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success({\n meta: {\n rootEntityRef: response.rootEntityRef,\n ancestry: response.items.map(ancestryLink => {\n return {\n entityRef: stringifyEntityRef(ancestryLink.entity),\n parentEntityRefs: ancestryLink.parentEntityRefs,\n };\n }),\n },\n });\n\n res.status(200).json(response);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n },\n )\n .post('/entities/by-refs', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-fetch',\n request: req,\n meta: {\n queryType: 'by-refs',\n },\n });\n\n try {\n const request = entitiesBatchRequest(req);\n const { items } = await entitiesCatalog.entitiesBatch({\n entityRefs: request.entityRefs,\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query, request.fields),\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success({\n meta: {\n ...request,\n },\n });\n\n await writeEntitiesResponse({\n res,\n items,\n alwaysUseObjectMode: enableRelationsCompatibility,\n responseWrapper: entities => ({\n items: entities,\n }),\n });\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/entity-facets', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-facets',\n request: req,\n });\n\n try {\n const response = await entitiesCatalog.facets({\n filter: parseEntityFilterParams(req.query),\n facets: parseEntityFacetParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(200).json(response);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n if (locationService) {\n router\n .post('/locations', async (req, res) => {\n const location = await validateRequestBody(req, locationInput);\n const dryRun = yn(req.query.dryRun, { default: false });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-mutate',\n severityLevel: dryRun ? 'low' : 'medium',\n request: req,\n meta: {\n actionType: 'create',\n location: location,\n isDryRun: dryRun,\n },\n });\n\n try {\n // when in dryRun addLocation is effectively a read operation so we don't\n // need to disallow readonly\n if (!dryRun) {\n disallowReadonlyMode(readonlyEnabled);\n }\n\n const output = await locationService.createLocation(\n location,\n dryRun,\n {\n credentials: await httpAuth.credentials(req),\n },\n );\n\n await auditorEvent?.success({\n meta: {\n location: output.location,\n },\n });\n\n res.status(201).json(output);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n meta: {\n location: location,\n isDryRun: dryRun,\n },\n });\n throw err;\n }\n })\n .get('/locations', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-fetch',\n request: req,\n meta: {\n queryType: 'all',\n },\n });\n\n try {\n const locations = await locationService.listLocations({\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(200).json(locations.map(l => ({ data: l })));\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n\n .get('/locations/:id', async (req, res) => {\n const { id } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-fetch',\n request: req,\n meta: {\n queryType: 'by-id',\n id: id,\n },\n });\n\n try {\n const output = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success({\n meta: {\n output: output,\n },\n });\n\n res.status(200).json(output);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .delete('/locations/:id', async (req, res) => {\n const { id } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-mutate',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'delete',\n id: id,\n },\n });\n\n disallowReadonlyMode(readonlyEnabled);\n\n try {\n await locationService.deleteLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n\n await auditorEvent?.success();\n\n res.status(204).end();\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n })\n .get('/locations/by-entity/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const locationRef = `${kind}:${namespace}/${name}`;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-fetch',\n request: req,\n meta: {\n queryType: 'by-entity',\n locationRef: locationRef,\n },\n });\n\n try {\n const output = await locationService.getLocationByEntity(\n { kind, namespace, name },\n { credentials: await httpAuth.credentials(req) },\n );\n\n await auditorEvent?.success({\n meta: {\n output: output,\n },\n });\n\n res.status(200).json(output);\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n if (locationAnalyzer) {\n router.post('/analyze-location', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'location-analyze',\n request: req,\n });\n\n try {\n const body = await validateRequestBody(\n req,\n z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n }),\n );\n const schema = z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n });\n const credentials = await httpAuth.credentials(req);\n const parsedBody = schema.parse(body);\n try {\n const output = await locationAnalyzer.analyzeLocation(\n parsedBody,\n credentials,\n );\n\n await auditorEvent?.success({\n meta: {\n output: output,\n },\n });\n\n res.status(200).json(output);\n } catch (err) {\n if (\n // Catch errors from parse-url library.\n err.name === 'Error' &&\n 'subject_url' in err\n ) {\n throw new InputError('The given location.target is not a URL');\n }\n throw err;\n }\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n if (orchestrator) {\n router.post('/validate-entity', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'entity-validate',\n request: req,\n });\n\n try {\n const bodySchema = z.object({\n entity: z.unknown(),\n location: z.string(),\n });\n\n let body: z.infer<typeof bodySchema>;\n let entity: Entity;\n let location: { type: string; target: string };\n try {\n body = await validateRequestBody(req, bodySchema);\n entity = validateEntityEnvelope(body.entity);\n location = parseLocationRef(body.location);\n if (location.type !== 'url')\n throw new TypeError(\n `Invalid location ref ${body.location}, only 'url:<target>' is supported, e.g. url:https://host/path`,\n );\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n\n return res.status(400).json({\n errors: [serializeError(err)],\n });\n }\n\n const credentials = await httpAuth.credentials(req);\n const authorizedValidationService = new AuthorizedValidationService(\n orchestrator,\n permissionsService,\n );\n const processingResult = await authorizedValidationService.process(\n {\n entity: {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n [ANNOTATION_LOCATION]: body.location,\n [ANNOTATION_ORIGIN_LOCATION]: body.location,\n ...entity.metadata.annotations,\n },\n },\n },\n },\n credentials,\n );\n\n if (!processingResult.ok) {\n const errors = processingResult.errors.map(e => serializeError(e));\n\n await auditorEvent?.fail({\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n error: (AggregateError as any)(errors, 'Could not validate entity'),\n });\n\n res.status(400).json({\n errors,\n });\n }\n\n await auditorEvent?.success();\n\n return res.status(200).end();\n } catch (err) {\n await auditorEvent?.fail({\n error: err,\n });\n throw err;\n }\n });\n }\n\n return router;\n}\n"],"names":["router","createOpenApiRouter","parseEntityFilterParams","parseEntityTransformParams","parseEntityOrderParams","parseEntityPaginationParams","writeEntitiesResponse","createEntityArrayJsonStream","parseQueryEntitiesParams","encodeCursor","basicEntityFilter","writeSingleEntityResponse","stringifyEntityRef","entitiesBatchRequest","parseEntityFacetParams","validateRequestBody","locationInput","yn","disallowReadonlyMode","z","InputError","validateEntityEnvelope","parseLocationRef","serializeError","AuthorizedValidationService","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","errors"],"mappings":"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"}
@@ -6,11 +6,11 @@ function stitchingStrategyFromConfig(config$1) {
6
6
  const strategyMode = config$1.getOptionalString(
7
7
  "catalog.stitchingStrategy.mode"
8
8
  );
9
- if (strategyMode === void 0 || strategyMode === "immediate") {
9
+ if (strategyMode === "immediate") {
10
10
  return {
11
11
  mode: "immediate"
12
12
  };
13
- } else if (strategyMode === "deferred") {
13
+ } else if (strategyMode === void 0 || strategyMode === "deferred") {
14
14
  const pollingIntervalKey = "catalog.stitchingStrategy.pollingInterval";
15
15
  const stitchTimeoutKey = "catalog.stitchingStrategy.stitchTimeout";
16
16
  const pollingInterval = config$1.has(pollingIntervalKey) ? config.readDurationFromConfig(config$1, { key: pollingIntervalKey }) : { seconds: 1 };
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs.js","sources":["../../src/stitching/types.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport interface Stitcher {\n stitch(options: {\n entityRefs?: Iterable<string>;\n entityIds?: Iterable<string>;\n }): Promise<void>;\n}\n\n/**\n * The strategies supported by the stitching process, in terms of when to\n * perform stitching.\n *\n * @remarks\n *\n * In immediate mode, stitching happens \"in-band\" (blocking) immediately when\n * each processing task finishes. When set to `'deferred'`, stitching is instead\n * deferred to happen on a separate asynchronous worker queue just like\n * processing.\n *\n * Deferred stitching should make performance smoother when ingesting large\n * amounts of entities, and reduce p99 processing times and repeated\n * over-stitching of hot spot entities when fan-out/fan-in in terms of relations\n * is very large. It does however also come with some performance cost due to\n * the queuing with how much wall-clock time some types of task take.\n */\nexport type StitchingStrategy =\n | {\n mode: 'immediate';\n }\n | {\n mode: 'deferred';\n pollingInterval: HumanDuration;\n stitchTimeout: HumanDuration;\n };\n\nexport function stitchingStrategyFromConfig(config: Config): StitchingStrategy {\n const strategyMode = config.getOptionalString(\n 'catalog.stitchingStrategy.mode',\n );\n\n if (strategyMode === undefined || strategyMode === 'immediate') {\n return {\n mode: 'immediate',\n };\n } else if (strategyMode === 'deferred') {\n const pollingIntervalKey = 'catalog.stitchingStrategy.pollingInterval';\n const stitchTimeoutKey = 'catalog.stitchingStrategy.stitchTimeout';\n\n const pollingInterval = config.has(pollingIntervalKey)\n ? readDurationFromConfig(config, { key: pollingIntervalKey })\n : { seconds: 1 };\n const stitchTimeout = config.has(stitchTimeoutKey)\n ? readDurationFromConfig(config, { key: stitchTimeoutKey })\n : { seconds: 60 };\n\n return {\n mode: 'deferred',\n pollingInterval: pollingInterval,\n stitchTimeout: stitchTimeout,\n };\n }\n\n throw new Error(\n `Invalid stitching strategy mode '${strategyMode}', expected one of 'immediate' or 'deferred'`,\n );\n}\n"],"names":["config","readDurationFromConfig"],"mappings":";;;;AA0DO,SAAS,4BAA4BA,QAAmC,EAAA;AAC7E,EAAA,MAAM,eAAeA,QAAO,CAAA,iBAAA;AAAA,IAC1B;AAAA,GACF;AAEA,EAAI,IAAA,YAAA,KAAiB,KAAa,CAAA,IAAA,YAAA,KAAiB,WAAa,EAAA;AAC9D,IAAO,OAAA;AAAA,MACL,IAAM,EAAA;AAAA,KACR;AAAA,GACF,MAAA,IAAW,iBAAiB,UAAY,EAAA;AACtC,IAAA,MAAM,kBAAqB,GAAA,2CAAA;AAC3B,IAAA,MAAM,gBAAmB,GAAA,yCAAA;AAEzB,IAAA,MAAM,eAAkB,GAAAA,QAAA,CAAO,GAAI,CAAA,kBAAkB,IACjDC,6BAAuB,CAAAD,QAAA,EAAQ,EAAE,GAAA,EAAK,kBAAmB,EAAC,CAC1D,GAAA,EAAE,SAAS,CAAE,EAAA;AACjB,IAAA,MAAM,aAAgB,GAAAA,QAAA,CAAO,GAAI,CAAA,gBAAgB,IAC7CC,6BAAuB,CAAAD,QAAA,EAAQ,EAAE,GAAA,EAAK,gBAAiB,EAAC,CACxD,GAAA,EAAE,SAAS,EAAG,EAAA;AAElB,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,UAAA;AAAA,MACN,eAAA;AAAA,MACA;AAAA,KACF;AAAA;AAGF,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,oCAAoC,YAAY,CAAA,4CAAA;AAAA,GAClD;AACF;;;;"}
1
+ {"version":3,"file":"types.cjs.js","sources":["../../src/stitching/types.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport interface Stitcher {\n stitch(options: {\n entityRefs?: Iterable<string>;\n entityIds?: Iterable<string>;\n }): Promise<void>;\n}\n\n/**\n * The strategies supported by the stitching process, in terms of when to\n * perform stitching.\n *\n * @remarks\n *\n * In immediate mode, stitching happens \"in-band\" (blocking) immediately when\n * each processing task finishes. When set to `'deferred'`, stitching is instead\n * deferred to happen on a separate asynchronous worker queue just like\n * processing.\n *\n * Deferred stitching should make performance smoother when ingesting large\n * amounts of entities, and reduce p99 processing times and repeated\n * over-stitching of hot spot entities when fan-out/fan-in in terms of relations\n * is very large. It does however also come with some performance cost due to\n * the queuing with how much wall-clock time some types of task take.\n */\nexport type StitchingStrategy =\n | {\n mode: 'immediate';\n }\n | {\n mode: 'deferred';\n pollingInterval: HumanDuration;\n stitchTimeout: HumanDuration;\n };\n\nexport function stitchingStrategyFromConfig(config: Config): StitchingStrategy {\n const strategyMode = config.getOptionalString(\n 'catalog.stitchingStrategy.mode',\n );\n\n if (strategyMode === 'immediate') {\n return {\n mode: 'immediate',\n };\n } else if (strategyMode === undefined || strategyMode === 'deferred') {\n const pollingIntervalKey = 'catalog.stitchingStrategy.pollingInterval';\n const stitchTimeoutKey = 'catalog.stitchingStrategy.stitchTimeout';\n\n const pollingInterval = config.has(pollingIntervalKey)\n ? readDurationFromConfig(config, { key: pollingIntervalKey })\n : { seconds: 1 };\n const stitchTimeout = config.has(stitchTimeoutKey)\n ? readDurationFromConfig(config, { key: stitchTimeoutKey })\n : { seconds: 60 };\n\n return {\n mode: 'deferred',\n pollingInterval: pollingInterval,\n stitchTimeout: stitchTimeout,\n };\n }\n\n throw new Error(\n `Invalid stitching strategy mode '${strategyMode}', expected one of 'immediate' or 'deferred'`,\n );\n}\n"],"names":["config","readDurationFromConfig"],"mappings":";;;;AA0DO,SAAS,4BAA4BA,QAAmC,EAAA;AAC7E,EAAA,MAAM,eAAeA,QAAO,CAAA,iBAAA;AAAA,IAC1B;AAAA,GACF;AAEA,EAAA,IAAI,iBAAiB,WAAa,EAAA;AAChC,IAAO,OAAA;AAAA,MACL,IAAM,EAAA;AAAA,KACR;AAAA,GACS,MAAA,IAAA,YAAA,KAAiB,KAAa,CAAA,IAAA,YAAA,KAAiB,UAAY,EAAA;AACpE,IAAA,MAAM,kBAAqB,GAAA,2CAAA;AAC3B,IAAA,MAAM,gBAAmB,GAAA,yCAAA;AAEzB,IAAA,MAAM,eAAkB,GAAAA,QAAA,CAAO,GAAI,CAAA,kBAAkB,IACjDC,6BAAuB,CAAAD,QAAA,EAAQ,EAAE,GAAA,EAAK,kBAAmB,EAAC,CAC1D,GAAA,EAAE,SAAS,CAAE,EAAA;AACjB,IAAA,MAAM,aAAgB,GAAAA,QAAA,CAAO,GAAI,CAAA,gBAAgB,IAC7CC,6BAAuB,CAAAD,QAAA,EAAQ,EAAE,GAAA,EAAK,gBAAiB,EAAC,CACxD,GAAA,EAAE,SAAS,EAAG,EAAA;AAElB,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,UAAA;AAAA,MACN,eAAA;AAAA,MACA;AAAA,KACF;AAAA;AAGF,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,oCAAoC,YAAY,CAAA,4CAAA;AAAA,GAClD;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend",
3
- "version": "3.0.0-next.0",
3
+ "version": "3.0.0",
4
4
  "description": "The Backstage backend plugin that provides the Backstage catalog",
5
5
  "backstage": {
6
6
  "role": "backend-plugin",
@@ -73,19 +73,19 @@
73
73
  "test": "backstage-cli package test"
74
74
  },
75
75
  "dependencies": {
76
- "@backstage/backend-openapi-utils": "0.5.4",
77
- "@backstage/backend-plugin-api": "1.4.0",
78
- "@backstage/catalog-client": "1.10.1",
79
- "@backstage/catalog-model": "1.7.4",
80
- "@backstage/config": "1.3.2",
81
- "@backstage/errors": "1.2.7",
82
- "@backstage/integration": "1.17.1-next.0",
83
- "@backstage/plugin-catalog-common": "1.1.4",
84
- "@backstage/plugin-catalog-node": "1.17.1",
85
- "@backstage/plugin-events-node": "0.4.12",
86
- "@backstage/plugin-permission-common": "0.9.0",
87
- "@backstage/plugin-permission-node": "0.10.1",
88
- "@backstage/types": "1.2.1",
76
+ "@backstage/backend-openapi-utils": "^0.5.5",
77
+ "@backstage/backend-plugin-api": "^1.4.1",
78
+ "@backstage/catalog-client": "^1.10.2",
79
+ "@backstage/catalog-model": "^1.7.5",
80
+ "@backstage/config": "^1.3.3",
81
+ "@backstage/errors": "^1.2.7",
82
+ "@backstage/integration": "^1.17.1",
83
+ "@backstage/plugin-catalog-common": "^1.1.5",
84
+ "@backstage/plugin-catalog-node": "^1.17.2",
85
+ "@backstage/plugin-events-node": "^0.4.13",
86
+ "@backstage/plugin-permission-common": "^0.9.1",
87
+ "@backstage/plugin-permission-node": "^0.10.2",
88
+ "@backstage/types": "^1.2.1",
89
89
  "@opentelemetry/api": "^1.9.0",
90
90
  "codeowners-utils": "^1.0.2",
91
91
  "core-js": "^3.6.5",
@@ -106,11 +106,11 @@
106
106
  "zod": "^3.22.4"
107
107
  },
108
108
  "devDependencies": {
109
- "@backstage/backend-defaults": "0.11.1-next.0",
110
- "@backstage/backend-test-utils": "1.7.0-next.0",
111
- "@backstage/cli": "0.33.1-next.0",
112
- "@backstage/plugin-permission-common": "0.9.0",
113
- "@backstage/repo-tools": "0.15.0-next.0",
109
+ "@backstage/backend-defaults": "^0.11.1",
110
+ "@backstage/backend-test-utils": "^1.7.0",
111
+ "@backstage/cli": "^0.33.1",
112
+ "@backstage/plugin-permission-common": "^0.9.1",
113
+ "@backstage/repo-tools": "^0.15.0",
114
114
  "@types/core-js": "^2.5.4",
115
115
  "@types/express": "^4.17.6",
116
116
  "@types/git-url-parse": "^9.0.0",