@backstage/plugin-catalog-backend 1.7.0-next.1 → 1.7.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
+ ## 1.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f75bf76330: Implemented server side ordering in the entities endpoint
8
+
9
+ ### Patch Changes
10
+
11
+ - e23f13a573: Enable the `by-refs` endpoint to receive `fields` through the POST body as well as through query parameters.
12
+ - f23eef3aa2: Updated dependency `better-sqlite3` to `^8.0.0`.
13
+ - d136793ff0: Fixed an issue where internal references in the catalog would stick around for longer than expected, causing entities to not be deleted or orphaned as expected.
14
+ - 8e06f3cf00: Switched imports of `loggerToWinstonLogger` to `@backstage/backend-common`.
15
+ - Updated dependencies
16
+ - @backstage/backend-plugin-api@0.3.0
17
+ - @backstage/backend-common@0.18.0
18
+ - @backstage/catalog-model@1.1.5
19
+ - @backstage/plugin-scaffolder-common@1.2.4
20
+ - @backstage/catalog-client@1.3.0
21
+ - @backstage/plugin-catalog-node@1.3.1
22
+ - @backstage/config@1.0.6
23
+ - @backstage/errors@1.1.4
24
+ - @backstage/integration@1.4.2
25
+ - @backstage/types@1.0.2
26
+ - @backstage/plugin-catalog-common@1.0.10
27
+ - @backstage/plugin-permission-common@0.7.3
28
+ - @backstage/plugin-permission-node@0.7.3
29
+ - @backstage/plugin-search-common@1.2.1
30
+
31
+ ## 1.7.0-next.2
32
+
33
+ ### Patch Changes
34
+
35
+ - e23f13a573: Enable the `by-refs` endpoint to receive `fields` through the POST body as well as through query parameters.
36
+ - f23eef3aa2: Updated dependency `better-sqlite3` to `^8.0.0`.
37
+ - 8e06f3cf00: Switched imports of `loggerToWinstonLogger` to `@backstage/backend-common`.
38
+ - Updated dependencies
39
+ - @backstage/backend-plugin-api@0.3.0-next.1
40
+ - @backstage/backend-common@0.18.0-next.1
41
+ - @backstage/catalog-client@1.3.0-next.2
42
+ - @backstage/plugin-catalog-node@1.3.1-next.2
43
+ - @backstage/plugin-permission-node@0.7.3-next.1
44
+ - @backstage/catalog-model@1.1.5-next.1
45
+ - @backstage/config@1.0.6-next.0
46
+ - @backstage/errors@1.1.4
47
+ - @backstage/integration@1.4.2-next.0
48
+ - @backstage/types@1.0.2
49
+ - @backstage/plugin-catalog-common@1.0.10-next.1
50
+ - @backstage/plugin-permission-common@0.7.3-next.0
51
+ - @backstage/plugin-scaffolder-common@1.2.4-next.1
52
+ - @backstage/plugin-search-common@1.2.1-next.0
53
+
3
54
  ## 1.7.0-next.1
4
55
 
5
56
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend",
3
- "version": "1.7.0-next.1",
3
+ "version": "1.7.0",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -390,7 +390,7 @@ export declare type CatalogPermissionRule<TParams extends PermissionRuleParams =
390
390
  * Catalog plugin
391
391
  * @alpha
392
392
  */
393
- export declare const catalogPlugin: (options?: undefined) => BackendFeature;
393
+ export declare const catalogPlugin: () => BackendFeature;
394
394
 
395
395
  /**
396
396
  * Represents the engine that drives the processing loops. Some backend
package/dist/index.cjs.js CHANGED
@@ -97,8 +97,11 @@ function normalizeCodeOwner(owner) {
97
97
 
98
98
  const CODEOWNERS = "CODEOWNERS";
99
99
  const scmCodeOwnersPaths = {
100
+ // https://mibexsoftware.atlassian.net/wiki/spaces/CODEOWNERS/pages/222822413/Usage
100
101
  bitbucket: [CODEOWNERS, `.bitbucket/${CODEOWNERS}`],
102
+ // https://docs.gitlab.com/ee/user/project/code_owners.html#how-to-set-up-code-owners
101
103
  gitlab: [CODEOWNERS, `.gitlab/${CODEOWNERS}`, `docs/${CODEOWNERS}`],
104
+ // https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-file-location
102
105
  github: [CODEOWNERS, `.github/${CODEOWNERS}`, `docs/${CODEOWNERS}`]
103
106
  };
104
107
 
@@ -1549,6 +1552,9 @@ async function updateUnprocessedEntity(options) {
1549
1552
  unprocessed_hash: hash,
1550
1553
  location_key: locationKey,
1551
1554
  last_discovery_at: tx.fn.now(),
1555
+ // We only get to this point if a processed entity actually had any changes, or
1556
+ // if an entity provider requested this mutation, meaning that we can safely
1557
+ // bump the deferred entities to the front of the queue for immediate processing.
1552
1558
  next_update_at: tx.fn.now()
1553
1559
  }).where("entity_ref", entityRef).andWhere((inner) => {
1554
1560
  if (!locationKey) {
@@ -1707,6 +1713,7 @@ class DefaultProcessingDatabase {
1707
1713
  result = await fn(tx);
1708
1714
  },
1709
1715
  {
1716
+ // If we explicitly trigger a rollback, don't fail.
1710
1717
  doNotRejectOnRollback: true
1711
1718
  }
1712
1719
  );
@@ -1722,6 +1729,10 @@ class DefaultProcessingDatabase {
1722
1729
  (r) => `${r.source_entity_ref}:${r.target_entity_ref}:${r.type}`
1723
1730
  );
1724
1731
  }
1732
+ /**
1733
+ * Add a set of deferred entities for processing.
1734
+ * The entities will be added at the front of the processing queue.
1735
+ */
1725
1736
  async addUnprocessedEntities(txOpaque, options) {
1726
1737
  const tx = txOpaque;
1727
1738
  const stateReferences = new Array();
@@ -2159,6 +2170,7 @@ class DefaultLocationService {
2159
2170
  const processed = await this.orchestrator.process({
2160
2171
  entity: currentEntity.entity,
2161
2172
  state: {}
2173
+ // we process without the existing cache
2162
2174
  });
2163
2175
  if (processed.ok) {
2164
2176
  if (entities.some(
@@ -2749,6 +2761,8 @@ class DefaultCatalogProcessingOrchestrator {
2749
2761
  };
2750
2762
  }
2751
2763
  }
2764
+ // Pre-process phase, used to populate entities with data that is required
2765
+ // during the main processing step
2752
2766
  async runPreProcessStep(entity, context) {
2753
2767
  let res = entity;
2754
2768
  for (const processor of this.options.processors) {
@@ -2771,6 +2785,9 @@ class DefaultCatalogProcessingOrchestrator {
2771
2785
  }
2772
2786
  return res;
2773
2787
  }
2788
+ /**
2789
+ * Enforce entity policies making sure that entities conform to a general schema
2790
+ */
2774
2791
  async runPolicyStep(entity) {
2775
2792
  let policyEnforcedEntity;
2776
2793
  try {
@@ -2790,6 +2807,9 @@ class DefaultCatalogProcessingOrchestrator {
2790
2807
  }
2791
2808
  return policyEnforcedEntity;
2792
2809
  }
2810
+ /**
2811
+ * Validate the given entity
2812
+ */
2793
2813
  async runValidateStep(entity, context) {
2794
2814
  if (catalogModel.stringifyEntityRef(entity) !== context.entityRef) {
2795
2815
  throw new errors.ConflictError(
@@ -2829,6 +2849,9 @@ class DefaultCatalogProcessingOrchestrator {
2829
2849
  );
2830
2850
  }
2831
2851
  }
2852
+ /**
2853
+ * Backwards compatible processing of location entities
2854
+ */
2832
2855
  async runSpecialLocationStep(entity, context) {
2833
2856
  const { type = context.location.type, presence = "required" } = entity.spec;
2834
2857
  const targets = new Array();
@@ -2888,6 +2911,9 @@ class DefaultCatalogProcessingOrchestrator {
2888
2911
  }
2889
2912
  }
2890
2913
  }
2914
+ /**
2915
+ * Main processing step of the entity
2916
+ */
2891
2917
  async runPostProcessStep(entity, context) {
2892
2918
  let res = entity;
2893
2919
  for (const processor of this.options.processors) {
@@ -3108,7 +3134,10 @@ class Stitcher {
3108
3134
  }));
3109
3135
  }
3110
3136
  }
3111
- entity.relations = relationsResult.filter((row) => row.relationType).map((row) => ({
3137
+ entity.relations = relationsResult.filter(
3138
+ (row) => row.relationType
3139
+ /* exclude null row, if relevant */
3140
+ ).map((row) => ({
3112
3141
  type: row.relationType,
3113
3142
  targetRef: row.relationTarget
3114
3143
  }));
@@ -3147,7 +3176,8 @@ class Stitcher {
3147
3176
  }
3148
3177
 
3149
3178
  const schema = zod.z.object({
3150
- entityRefs: zod.z.array(zod.z.string())
3179
+ entityRefs: zod.z.array(zod.z.string()),
3180
+ fields: zod.z.array(zod.z.string()).optional()
3151
3181
  });
3152
3182
  function entitiesBatchRequest(req) {
3153
3183
  try {
@@ -3274,17 +3304,22 @@ function getPathArrayAndValue(input, field) {
3274
3304
  [[], input]
3275
3305
  );
3276
3306
  }
3277
- function parseEntityTransformParams(params) {
3278
- const fieldsStrings = parseStringsParam(params.fields, "fields");
3279
- if (!fieldsStrings) {
3280
- return void 0;
3281
- }
3282
- const fields = fieldsStrings.map((s) => s.split(",")).flat().map((s) => s.trim()).filter(Boolean);
3307
+ function parseEntityTransformParams(params, extra) {
3308
+ var _a;
3309
+ const queryFields = parseStringsParam(params.fields, "fields");
3310
+ const fields = Array.from(
3311
+ new Set(
3312
+ [...extra != null ? extra : [], ...(_a = queryFields == null ? void 0 : queryFields.map((s) => s.split(","))) != null ? _a : []].flat().map((s) => s.trim()).filter(Boolean)
3313
+ )
3314
+ );
3283
3315
  if (!fields.length) {
3284
3316
  return void 0;
3285
3317
  }
3286
- if (fields.some((f) => f.includes("["))) {
3287
- throw new errors.InputError("invalid fields, array type fields are not supported");
3318
+ const arrayTypeField = fields.find((f) => f.includes("["));
3319
+ if (arrayTypeField) {
3320
+ throw new errors.InputError(
3321
+ `Invalid field "${arrayTypeField}", array type fields are not supported`
3322
+ );
3288
3323
  }
3289
3324
  return (input) => {
3290
3325
  const output = {};
@@ -3454,7 +3489,7 @@ async function createRouter(options) {
3454
3489
  const token = getBearerToken(req.header("authorization"));
3455
3490
  const response = await entitiesCatalog.entitiesBatch({
3456
3491
  entityRefs: request.entityRefs,
3457
- fields: parseEntityTransformParams(req.query),
3492
+ fields: parseEntityTransformParams(req.query, request.fields),
3458
3493
  authorizationToken: token
3459
3494
  });
3460
3495
  res.status(200).json(response);
@@ -3618,6 +3653,44 @@ const _DefaultCatalogRulesEnforcer = class {
3618
3653
  constructor(rules) {
3619
3654
  this.rules = rules;
3620
3655
  }
3656
+ /**
3657
+ * Loads catalog rules from config.
3658
+ *
3659
+ * This reads `catalog.rules` and defaults to the default rules if no value is present.
3660
+ * The value of the config should be a list of config objects, each with a single `allow`
3661
+ * field which in turn is a list of entity kinds to allow.
3662
+ *
3663
+ * If there is no matching rule to allow an ingested entity, it will be rejected by the catalog.
3664
+ *
3665
+ * It also reads in rules from `catalog.locations`, where each location can have a list
3666
+ * of rules for that specific location, specified in a `rules` field.
3667
+ *
3668
+ * For example:
3669
+ *
3670
+ * ```yaml
3671
+ * catalog:
3672
+ * rules:
3673
+ * - allow: [Component, API]
3674
+ * - allow: [Template]
3675
+ * locations:
3676
+ * - type: url
3677
+ * pattern: https://github.com/org/*\/blob/master/template.yaml
3678
+ * - allow: [Location]
3679
+ * locations:
3680
+ * - type: url
3681
+ * pattern: https://github.com/org/repo/blob/master/location.yaml
3682
+ *
3683
+ * locations:
3684
+ * - type: url
3685
+ * target: https://github.com/org/repo/blob/master/users.yaml
3686
+ * rules:
3687
+ * - allow: [User, Group]
3688
+ * - type: url
3689
+ * target: https://github.com/org/repo/blob/master/systems.yaml
3690
+ * rules:
3691
+ * - allow: [System]
3692
+ * ```
3693
+ */
3621
3694
  static fromConfig(config) {
3622
3695
  const rules = new Array();
3623
3696
  if (config.has("catalog.rules")) {
@@ -3660,6 +3733,10 @@ const _DefaultCatalogRulesEnforcer = class {
3660
3733
  }
3661
3734
  return new _DefaultCatalogRulesEnforcer(rules);
3662
3735
  }
3736
+ /**
3737
+ * Checks whether a specific entity/location combination is allowed
3738
+ * according to the configured rules.
3739
+ */
3663
3740
  isAllowed(entity, location) {
3664
3741
  for (const rule of this.rules) {
3665
3742
  if (!this.matchLocation(location, rule.locations)) {
@@ -3704,6 +3781,11 @@ const _DefaultCatalogRulesEnforcer = class {
3704
3781
  }
3705
3782
  };
3706
3783
  let DefaultCatalogRulesEnforcer = _DefaultCatalogRulesEnforcer;
3784
+ /**
3785
+ * Default rules used by the catalog.
3786
+ *
3787
+ * Denies any location from specifying user or group entities.
3788
+ */
3707
3789
  DefaultCatalogRulesEnforcer.defaultRules = [
3708
3790
  {
3709
3791
  allow: ["Component", "API", "Location"].map((kind) => ({ kind }))
@@ -4052,6 +4134,7 @@ class DefaultProviderDatabase {
4052
4134
  result = await fn(tx);
4053
4135
  },
4054
4136
  {
4137
+ // If we explicitly trigger a rollback, don't fail.
4055
4138
  doNotRejectOnRollback: true
4056
4139
  }
4057
4140
  );
@@ -4233,6 +4316,7 @@ class DefaultCatalogDatabase {
4233
4316
  result = await fn(tx);
4234
4317
  },
4235
4318
  {
4319
+ // If we explicitly trigger a rollback, don't fail.
4236
4320
  doNotRejectOnRollback: true
4237
4321
  }
4238
4322
  );
@@ -4302,13 +4386,33 @@ class CatalogBuilder {
4302
4386
  this.permissionRules = Object.values(permissionRules);
4303
4387
  this.allowedLocationType = ["url"];
4304
4388
  }
4389
+ /**
4390
+ * Creates a catalog builder.
4391
+ */
4305
4392
  static create(env) {
4306
4393
  return new CatalogBuilder(env);
4307
4394
  }
4395
+ /**
4396
+ * Adds policies that are used to validate entities between the pre-
4397
+ * processing and post-processing stages. All such policies must pass for the
4398
+ * entity to be considered valid.
4399
+ *
4400
+ * If what you want to do is to replace the rules for what format is allowed
4401
+ * in various core entity fields (such as metadata.name), you may want to use
4402
+ * {@link CatalogBuilder#setFieldFormatValidators} instead.
4403
+ *
4404
+ * @param policies - One or more policies
4405
+ */
4308
4406
  addEntityPolicy(...policies) {
4309
4407
  this.entityPolicies.push(...policies.flat());
4310
4408
  return this;
4311
4409
  }
4410
+ /**
4411
+ * Processing interval determines how often entities should be processed.
4412
+ * Seconds provided will be multiplied by 1.5
4413
+ * The default processing interval is 100-150 seconds.
4414
+ * setting this too low will potentially deplete request quotas to upstream services.
4415
+ */
4312
4416
  setProcessingIntervalSeconds(seconds) {
4313
4417
  this.processingInterval = createRandomProcessingInterval({
4314
4418
  minSeconds: seconds,
@@ -4316,40 +4420,109 @@ class CatalogBuilder {
4316
4420
  });
4317
4421
  return this;
4318
4422
  }
4423
+ /**
4424
+ * Overwrites the default processing interval function used to spread
4425
+ * entity updates in the catalog.
4426
+ */
4319
4427
  setProcessingInterval(processingInterval) {
4320
4428
  this.processingInterval = processingInterval;
4321
4429
  return this;
4322
4430
  }
4431
+ /**
4432
+ * Overwrites the default location analyzer.
4433
+ */
4323
4434
  setLocationAnalyzer(locationAnalyzer) {
4324
4435
  this.locationAnalyzer = locationAnalyzer;
4325
4436
  return this;
4326
4437
  }
4438
+ /**
4439
+ * Sets what policies to use for validation of entities between the pre-
4440
+ * processing and post-processing stages. All such policies must pass for the
4441
+ * entity to be considered valid.
4442
+ *
4443
+ * If what you want to do is to replace the rules for what format is allowed
4444
+ * in various core entity fields (such as metadata.name), you may want to use
4445
+ * {@link CatalogBuilder#setFieldFormatValidators} instead.
4446
+ *
4447
+ * This function replaces the default set of policies; use with care.
4448
+ *
4449
+ * @param policies - One or more policies
4450
+ */
4327
4451
  replaceEntityPolicies(policies) {
4328
4452
  this.entityPolicies = [...policies];
4329
4453
  this.entityPoliciesReplace = true;
4330
4454
  return this;
4331
4455
  }
4456
+ /**
4457
+ * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity
4458
+ * definition files.
4459
+ *
4460
+ * @param key - The key that identifies the placeholder, e.g. "file"
4461
+ * @param resolver - The resolver that gets values for this placeholder
4462
+ */
4332
4463
  setPlaceholderResolver(key, resolver) {
4333
4464
  this.placeholderResolvers[key] = resolver;
4334
4465
  return this;
4335
4466
  }
4467
+ /**
4468
+ * Sets the validator function to use for one or more special fields of an
4469
+ * entity. This is useful if the default rules for formatting of fields are
4470
+ * not sufficient.
4471
+ *
4472
+ * This function has no effect if used together with
4473
+ * {@link CatalogBuilder#replaceEntityPolicies}.
4474
+ *
4475
+ * @param validators - The (subset of) validators to set
4476
+ */
4336
4477
  setFieldFormatValidators(validators) {
4337
4478
  lodash__default["default"].merge(this.fieldFormatValidators, validators);
4338
4479
  return this;
4339
4480
  }
4481
+ /**
4482
+ * Adds or replaces entity providers. These are responsible for bootstrapping
4483
+ * the list of entities out of original data sources. For example, there is
4484
+ * one entity source for the config locations, and one for the database
4485
+ * stored locations. If you ingest entities out of a third party system, you
4486
+ * may want to implement that in terms of an entity provider as well.
4487
+ *
4488
+ * @param providers - One or more entity providers
4489
+ */
4340
4490
  addEntityProvider(...providers) {
4341
4491
  this.entityProviders.push(...providers.flat());
4342
4492
  return this;
4343
4493
  }
4494
+ /**
4495
+ * Adds entity processors. These are responsible for reading, parsing, and
4496
+ * processing entities before they are persisted in the catalog.
4497
+ *
4498
+ * @param processors - One or more processors
4499
+ */
4344
4500
  addProcessor(...processors) {
4345
4501
  this.processors.push(...processors.flat());
4346
4502
  return this;
4347
4503
  }
4504
+ /**
4505
+ * Sets what entity processors to use. These are responsible for reading,
4506
+ * parsing, and processing entities before they are persisted in the catalog.
4507
+ *
4508
+ * This function replaces the default set of processors, consider using with
4509
+ * {@link CatalogBuilder#getDefaultProcessors}; use with care.
4510
+ *
4511
+ * @param processors - One or more processors
4512
+ */
4348
4513
  replaceProcessors(processors) {
4349
4514
  this.processors = [...processors];
4350
4515
  this.processorsReplace = true;
4351
4516
  return this;
4352
4517
  }
4518
+ /**
4519
+ * Returns the default list of entity processors. These are responsible for reading,
4520
+ * parsing, and processing entities before they are persisted in the catalog. Changing
4521
+ * the order of processing can give more control to custom processors.
4522
+ *
4523
+ * Consider using with {@link CatalogBuilder#replaceProcessors}
4524
+ *
4525
+ */
4353
4526
  getDefaultProcessors() {
4354
4527
  const { config, logger, reader } = this.env;
4355
4528
  const integrations = integration.ScmIntegrations.fromConfig(config);
@@ -4360,26 +4533,63 @@ class CatalogBuilder {
4360
4533
  new AnnotateLocationEntityProcessor({ integrations })
4361
4534
  ];
4362
4535
  }
4536
+ /**
4537
+ * Adds Location Analyzers. These are responsible for analyzing
4538
+ * repositories when onboarding them into the catalog, by finding
4539
+ * catalog-info.yaml files and other artifacts that can help automatically
4540
+ * register or create catalog data on the user's behalf.
4541
+ *
4542
+ * @param locationAnalyzers - One or more location analyzers
4543
+ */
4363
4544
  addLocationAnalyzers(...analyzers) {
4364
4545
  this.locationAnalyzers.push(...analyzers.flat());
4365
4546
  return this;
4366
4547
  }
4548
+ /**
4549
+ * Sets up the catalog to use a custom parser for entity data.
4550
+ *
4551
+ * This is the function that gets called immediately after some raw entity
4552
+ * specification data has been read from a remote source, and needs to be
4553
+ * parsed and emitted as structured data.
4554
+ *
4555
+ * @param parser - The custom parser
4556
+ */
4367
4557
  setEntityDataParser(parser) {
4368
4558
  this.parser = parser;
4369
4559
  return this;
4370
4560
  }
4561
+ /**
4562
+ * Adds additional permission rules. Permission rules are used to evaluate
4563
+ * catalog resources against queries. See
4564
+ * {@link @backstage/plugin-permission-node#PermissionRule}.
4565
+ *
4566
+ * @param permissionRules - Additional permission rules
4567
+ * @alpha
4568
+ */
4371
4569
  addPermissionRules(...permissionRules) {
4372
4570
  this.permissionRules.push(...permissionRules.flat());
4373
4571
  return this;
4374
4572
  }
4573
+ /**
4574
+ * Sets up the allowed location types from being registered via the location service.
4575
+ *
4576
+ * @param allowedLocationTypes - the allowed location types
4577
+ */
4375
4578
  setAllowedLocationTypes(allowedLocationTypes) {
4376
4579
  this.allowedLocationType = allowedLocationTypes;
4377
4580
  return this;
4378
4581
  }
4582
+ /**
4583
+ * Enables the legacy behaviour of canceling validation early whenever only a
4584
+ * single processor declares an entity kind to be valid.
4585
+ */
4379
4586
  useLegacySingleProcessorValidation() {
4380
4587
  this.legacySingleProcessorValidation = true;
4381
4588
  return this;
4382
4589
  }
4590
+ /**
4591
+ * Wires up and returns all of the component parts of the catalog
4592
+ */
4383
4593
  async build() {
4384
4594
  var _a, _b;
4385
4595
  const { config, database, logger, permissions } = this.env;
@@ -4542,6 +4752,8 @@ class CatalogBuilder {
4542
4752
  this.checkMissingExternalProcessors(processors);
4543
4753
  return processors;
4544
4754
  }
4755
+ // TODO(Rugvip): These old processors are removed, for a while we'll be throwing
4756
+ // errors here to make sure people know where to move the config
4545
4757
  checkDeprecatedReaderProcessors() {
4546
4758
  const pc = this.env.config.getOptionalConfig("catalog.processors");
4547
4759
  if (pc == null ? void 0 : pc.has("github")) {
@@ -4565,6 +4777,7 @@ class CatalogBuilder {
4565
4777
  );
4566
4778
  }
4567
4779
  }
4780
+ // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure
4568
4781
  checkMissingExternalProcessors(processors) {
4569
4782
  var _a, _b;
4570
4783
  const skipCheckVarName = "BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK";
@@ -4699,7 +4912,7 @@ const catalogPlugin = backendPluginApi.createBackendPlugin({
4699
4912
  httpRouter,
4700
4913
  lifecycle
4701
4914
  }) {
4702
- const winstonLogger = backendPluginApi.loggerToWinstonLogger(logger);
4915
+ const winstonLogger = backendCommon.loggerToWinstonLogger(logger);
4703
4916
  const builder = await CatalogBuilder.create({
4704
4917
  config,
4705
4918
  reader,