diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index cf27f4dff9..2f3a11b7e0 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -40,8 +40,8 @@ import { DependencyGraph } from '../lib/DependencyGraph'; import { ServiceRegistry } from './ServiceRegistry'; import { createInitializationLogger } from './createInitializationLogger'; import { deepFreeze, unwrapFeature } from './helpers'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import type { InstanceMetadataServicePluginInfo } from '../../../backend-plugin-api/src/services/definitions/InstanceMetadataService'; +import type { RootInstanceMetadataServicePluginInfo } from '@backstage/backend-plugin-api'; +import { instanceMetadataServiceRef } from '@backstage/backend-plugin-api/alpha'; export interface BackendRegisterInit { consumes: Set; @@ -99,31 +99,30 @@ const instanceRegistry = new (class InstanceRegistry { }; })(); -function createInstanceMetadataServiceFactory( +function createRootInstanceMetadataServiceFactory( registrations: InternalBackendRegistrations[], ) { - const installedPlugins: { - [pluginId: string]: InstanceMetadataServicePluginInfo; - } = {}; + const installedPlugins: Map = + new Map(); for (const registration of registrations) { if (registration.featureType === 'registrations') { for (const feature of registration.getRegistrations()) { if (feature.type === 'plugin') { - if (!installedPlugins[feature.pluginId]) { - installedPlugins[feature.pluginId] = { + if (!installedPlugins.get(feature.pluginId)) { + installedPlugins.set(feature.pluginId, { pluginId: feature.pluginId, modules: [], - }; + }); } } else if (feature.type === 'module') { - if (!installedPlugins[feature.pluginId]) { - installedPlugins[feature.pluginId] = { + if (!installedPlugins.get(feature.pluginId)) { + installedPlugins.set(feature.pluginId, { pluginId: feature.pluginId, modules: [], - }; + }); } ( - installedPlugins[feature.pluginId].modules as Array<{ + installedPlugins.get(feature.pluginId)!.modules as Array<{ moduleId: string; }> ).push({ @@ -134,11 +133,9 @@ function createInstanceMetadataServiceFactory( } } return createServiceFactory({ - service: coreServices.instanceMetadata, - deps: { - logger: coreServices.rootLogger, - }, - factory: async ({ logger }) => { + service: coreServices.rootInstanceMetadata, + deps: {}, + factory: async () => { const readonlyInstalledPlugins = deepFreeze( Object.values(installedPlugins), ); @@ -146,18 +143,29 @@ function createInstanceMetadataServiceFactory( getInstalledPlugins: () => Promise.resolve(readonlyInstalledPlugins), }; - const plugins = await instanceMetadata.getInstalledPlugins(); - - logger.info( - `Installed plugins on this instance: ${plugins - .map(p => p.pluginId) - .join(', ')}`, - ); return instanceMetadata; }, }); } +function createDeprecatedInstanceMetadataServiceFactory() { + return createServiceFactory({ + service: instanceMetadataServiceRef, + deps: { + instanceMetadata: coreServices.rootInstanceMetadata, + }, + factory: async ({ instanceMetadata }) => { + const plugins = await instanceMetadata.getInstalledPlugins(); + const service = { + getInstalledFeatures: () => + plugins.map(e => ({ type: 'plugin' as const, pluginId: e.pluginId })), + }; + + return service; + }, + }); +} + export class BackendInitializer { #startPromise?: Promise; #stopPromise?: Promise; @@ -259,8 +267,9 @@ export class BackendInitializer { await this.#applyBackendFeatureLoaders(this.#registeredFeatureLoaders); this.#serviceRegistry.add( - createInstanceMetadataServiceFactory(this.#registrations), + createRootInstanceMetadataServiceFactory(this.#registrations), ); + this.#serviceRegistry.add(createDeprecatedInstanceMetadataServiceFactory()); // This makes sure that any uncaught errors or unhandled rejections are // caught and logged, rather than terminating the process. We register these diff --git a/packages/backend-plugin-api/src/alpha/InstanceMetadataService.ts b/packages/backend-plugin-api/src/alpha/InstanceMetadataService.ts new file mode 100644 index 0000000000..a82a261d9d --- /dev/null +++ b/packages/backend-plugin-api/src/alpha/InstanceMetadataService.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @alpha */ +export type BackendFeatureMeta = + | { + type: 'plugin'; + pluginId: string; + } + | { + type: 'module'; + pluginId: string; + moduleId: string; + }; + +/** @alpha */ +export interface InstanceMetadataService { + getInstalledFeatures: () => BackendFeatureMeta[]; +} diff --git a/packages/backend-plugin-api/src/alpha/index.ts b/packages/backend-plugin-api/src/alpha/index.ts index b1edd68adc..5bb69eb4e2 100644 --- a/packages/backend-plugin-api/src/alpha/index.ts +++ b/packages/backend-plugin-api/src/alpha/index.ts @@ -14,6 +14,11 @@ * limitations under the License. */ +export type { + BackendFeatureMeta, + InstanceMetadataService, +} from './InstanceMetadataService'; + export type { ActionsRegistryService, ActionsRegistryActionOptions, @@ -22,4 +27,8 @@ export type { export type { ActionsService, ActionsServiceAction } from './ActionsService'; -export { actionsRegistryServiceRef, actionsServiceRef } from './refs'; +export { + actionsRegistryServiceRef, + actionsServiceRef, + instanceMetadataServiceRef, +} from './refs'; diff --git a/packages/backend-plugin-api/src/alpha/refs.ts b/packages/backend-plugin-api/src/alpha/refs.ts index cfbb215615..81996679f7 100644 --- a/packages/backend-plugin-api/src/alpha/refs.ts +++ b/packages/backend-plugin-api/src/alpha/refs.ts @@ -16,6 +16,15 @@ import { createServiceRef } from '@backstage/backend-plugin-api'; +/** + * @alpha + */ +export const instanceMetadataServiceRef = createServiceRef< + import('./InstanceMetadataService').InstanceMetadataService +>({ + id: 'core.instanceMetadata', +}); + /** * Service for calling distributed actions * diff --git a/packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts b/packages/backend-plugin-api/src/services/definitions/RootInstanceMetadataService.ts similarity index 82% rename from packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts rename to packages/backend-plugin-api/src/services/definitions/RootInstanceMetadataService.ts index 49c4dfe765..c324fed331 100644 --- a/packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootInstanceMetadataService.ts @@ -15,7 +15,7 @@ */ /** @public */ -export interface InstanceMetadataServicePluginInfo { +export interface RootInstanceMetadataServicePluginInfo { readonly pluginId: string; readonly modules: ReadonlyArray<{ moduleId: string; @@ -23,8 +23,8 @@ export interface InstanceMetadataServicePluginInfo { } /** @public */ -export interface InstanceMetadataService { +export interface RootInstanceMetadataService { getInstalledPlugins: () => Promise< - ReadonlyArray + ReadonlyArray >; } diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index b8f4494f74..62f2f848fc 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -283,9 +283,9 @@ export namespace coreServices { * * @public */ - export const instanceMetadata = createServiceRef< - import('./InstanceMetadataService').InstanceMetadataService + export const rootInstanceMetadata = createServiceRef< + import('./RootInstanceMetadataService').RootInstanceMetadataService >({ - id: 'core.instanceMetadata', + id: 'core.rootInstanceMetadata', }); } diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 111bd86ba9..6bcee4b043 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -86,7 +86,7 @@ export type { } from './UrlReaderService'; export type { BackstageUserInfo, UserInfoService } from './UserInfoService'; export type { - InstanceMetadataService, - InstanceMetadataServicePluginInfo, -} from './InstanceMetadataService'; + RootInstanceMetadataService, + RootInstanceMetadataServicePluginInfo, +} from './RootInstanceMetadataService'; export { coreServices } from './coreServices';