diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 45b82aac56..e0509aecde 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -26,7 +26,9 @@ import { stringifyError } from '@backstage/errors'; * @internal */ export type InternalServiceRef = ServiceRef & { - __defaultFactory?: (service: ServiceRef) => Promise>; + __defaultFactory?: ( + service: ServiceRef, + ) => Promise | (() => ServiceFactory)>; }; export class ServiceRegistry { @@ -40,8 +42,18 @@ export class ServiceRegistry { } >; - constructor(factories: ServiceFactory[]) { - this.#providedFactories = new Map(factories.map(f => [f.service.id, f])); + constructor( + factories: Array | (() => ServiceFactory)>, + ) { + this.#providedFactories = new Map( + factories.map(f => { + if (typeof f === 'function') { + const cf = f(); + return [cf.service.id, cf]; + } + return [f.service.id, f]; + }), + ); this.#loadedDefaultFactories = new Map(); this.#implementations = new Map(); } @@ -57,9 +69,11 @@ export class ServiceRegistry { if (!factory) { let loadedFactory = this.#loadedDefaultFactories.get(defaultFactory!); if (!loadedFactory) { - loadedFactory = Promise.resolve().then( - () => defaultFactory!(ref) as Promise, - ); + loadedFactory = Promise.resolve() + .then(() => defaultFactory!(ref)) + .then(f => + typeof f === 'function' ? f() : f, + ) as Promise; this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory); } // NOTE: This await is safe as long as #providedFactories is not mutated. diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 55009edbdf..febc6830c7 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -43,7 +43,7 @@ export interface BackendRegisterInit { * @public */ export interface CreateSpecializedBackendOptions { - services: ServiceFactory[]; + services: (ServiceFactory | (() => ServiceFactory))[]; } export type ServiceHolder = { @@ -56,7 +56,9 @@ export type ServiceHolder = { export function createSpecializedBackend( options: CreateSpecializedBackendOptions, ): Backend { - return new BackstageBackend(options.services); + return new BackstageBackend( + options.services.map(s => (typeof s === 'function' ? s() : s)), + ); } /** diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 819a77ea11..5130d6733b 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -47,24 +47,14 @@ export const defaultServiceFactories = [ * @public */ export interface CreateBackendOptions { - services?: ServiceFactory[]; + services?: (ServiceFactory | (() => ServiceFactory))[]; } /** * @public */ export function createBackend(options?: CreateBackendOptions): Backend { - const services = new Map( - defaultServiceFactories.map(sf => [sf.service.id, sf as ServiceFactory]), - ); - - if (options?.services) { - for (const sf of options.services) { - services.set(sf.service.id, sf); - } - } - return createSpecializedBackend({ - services: Array.from(services.values()), + services: [...defaultServiceFactories, ...(options?.services ?? [])], }); } diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 4737c6a0e8..a19c17bb9c 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -41,7 +41,9 @@ export type InternalServiceRef = ServiceRef & { * The default factory that will be used to create service * instances if no other factory is provided. */ - __defaultFactory?: (service: ServiceRef) => Promise>; + __defaultFactory?: ( + service: ServiceRef, + ) => Promise | (() => ServiceFactory)>; }; /** @public */ @@ -67,7 +69,9 @@ export type ServiceFactory = { */ export function createServiceRef(options: { id: string; - defaultFactory?: (service: ServiceRef) => Promise>; + defaultFactory?: ( + service: ServiceRef, + ) => Promise | (() => ServiceFactory)>; }): ServiceRef { const { id, defaultFactory } = options; return { diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 98e979793e..f93b34cdd8 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -32,6 +32,7 @@ export interface TestBackendOptions< ...{ [index in keyof TServices]: | ServiceFactory + | (() => ServiceFactory) | [ServiceRef, Partial]; }, ];