Merge pull request #25593 from backstage/mob/nbs10-service-modules
[NBS 1.0] Enabling multiple service implementations
This commit is contained in:
@@ -17,7 +17,8 @@ export interface FeatureDiscoveryService {
|
||||
// @alpha
|
||||
export const featureDiscoveryServiceRef: ServiceRef<
|
||||
FeatureDiscoveryService,
|
||||
'root'
|
||||
'root',
|
||||
'singleton'
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
@@ -189,28 +189,32 @@ export type CacheServiceSetOptions = {
|
||||
|
||||
// @public
|
||||
export namespace coreServices {
|
||||
const auth: ServiceRef<AuthService, 'plugin'>;
|
||||
const userInfo: ServiceRef<UserInfoService, 'plugin'>;
|
||||
const cache: ServiceRef<CacheService, 'plugin'>;
|
||||
const rootConfig: ServiceRef<RootConfigService, 'root'>;
|
||||
const database: ServiceRef<DatabaseService, 'plugin'>;
|
||||
const discovery: ServiceRef<DiscoveryService, 'plugin'>;
|
||||
const rootHealth: ServiceRef<RootHealthService, 'root'>;
|
||||
const httpAuth: ServiceRef<HttpAuthService, 'plugin'>;
|
||||
const httpRouter: ServiceRef<HttpRouterService, 'plugin'>;
|
||||
const lifecycle: ServiceRef<LifecycleService, 'plugin'>;
|
||||
const logger: ServiceRef<LoggerService, 'plugin'>;
|
||||
const permissions: ServiceRef<PermissionsService, 'plugin'>;
|
||||
const pluginMetadata: ServiceRef<PluginMetadataService, 'plugin'>;
|
||||
const rootHttpRouter: ServiceRef<RootHttpRouterService, 'root'>;
|
||||
const rootLifecycle: ServiceRef<RootLifecycleService, 'root'>;
|
||||
const rootLogger: ServiceRef<RootLoggerService, 'root'>;
|
||||
const scheduler: ServiceRef<SchedulerService, 'plugin'>;
|
||||
const auth: ServiceRef<AuthService, 'plugin', 'singleton'>;
|
||||
const userInfo: ServiceRef<UserInfoService, 'plugin', 'singleton'>;
|
||||
const cache: ServiceRef<CacheService, 'plugin', 'singleton'>;
|
||||
const rootConfig: ServiceRef<RootConfigService, 'root', 'singleton'>;
|
||||
const database: ServiceRef<DatabaseService, 'plugin', 'singleton'>;
|
||||
const discovery: ServiceRef<DiscoveryService, 'plugin', 'singleton'>;
|
||||
const rootHealth: ServiceRef<RootHealthService, 'root', 'singleton'>;
|
||||
const httpAuth: ServiceRef<HttpAuthService, 'plugin', 'singleton'>;
|
||||
const httpRouter: ServiceRef<HttpRouterService, 'plugin', 'singleton'>;
|
||||
const lifecycle: ServiceRef<LifecycleService, 'plugin', 'singleton'>;
|
||||
const logger: ServiceRef<LoggerService, 'plugin', 'singleton'>;
|
||||
const permissions: ServiceRef<PermissionsService, 'plugin', 'singleton'>;
|
||||
const pluginMetadata: ServiceRef<
|
||||
PluginMetadataService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
const rootHttpRouter: ServiceRef<RootHttpRouterService, 'root', 'singleton'>;
|
||||
const rootLifecycle: ServiceRef<RootLifecycleService, 'root', 'singleton'>;
|
||||
const rootLogger: ServiceRef<RootLoggerService, 'root', 'singleton'>;
|
||||
const scheduler: ServiceRef<SchedulerService, 'plugin', 'singleton'>;
|
||||
const // @deprecated
|
||||
tokenManager: ServiceRef<TokenManagerService, 'plugin'>;
|
||||
const urlReader: ServiceRef<UrlReaderService, 'plugin'>;
|
||||
tokenManager: ServiceRef<TokenManagerService, 'plugin', 'singleton'>;
|
||||
const urlReader: ServiceRef<UrlReaderService, 'plugin', 'singleton'>;
|
||||
const // @deprecated
|
||||
identity: ServiceRef<IdentityService, 'plugin'>;
|
||||
identity: ServiceRef<IdentityService, 'plugin', 'singleton'>;
|
||||
}
|
||||
|
||||
// @public
|
||||
@@ -292,18 +296,20 @@ export interface CreateExtensionPointOptions {
|
||||
// @public
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown, 'root'>;
|
||||
},
|
||||
TOpts extends object | undefined = undefined,
|
||||
>(
|
||||
options: RootServiceFactoryOptions<TService, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root'>;
|
||||
options: RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root', TInstances>;
|
||||
|
||||
// @public @deprecated
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown, 'root'>;
|
||||
@@ -312,12 +318,13 @@ export function createServiceFactory<
|
||||
>(
|
||||
options: (
|
||||
options?: TOpts,
|
||||
) => RootServiceFactoryOptions<TService, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root', TOpts>;
|
||||
) => RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root', TInstances, TOpts>;
|
||||
|
||||
// @public
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown>;
|
||||
@@ -325,12 +332,19 @@ export function createServiceFactory<
|
||||
TContext = undefined,
|
||||
TOpts extends object | undefined = undefined,
|
||||
>(
|
||||
options: PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'plugin'>;
|
||||
options: PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
>,
|
||||
): ServiceFactoryCompat<TService, 'plugin', TInstances>;
|
||||
|
||||
// @public @deprecated
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown>;
|
||||
@@ -340,18 +354,34 @@ export function createServiceFactory<
|
||||
>(
|
||||
options: (
|
||||
options?: TOpts,
|
||||
) => PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'plugin', TOpts>;
|
||||
) => PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
>,
|
||||
): ServiceFactoryCompat<TService, 'plugin', TInstances, TOpts>;
|
||||
|
||||
// @public
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'plugin'>,
|
||||
): ServiceRef<TService, 'plugin'>;
|
||||
options: ServiceRefOptions<TService, 'plugin', 'singleton'>,
|
||||
): ServiceRef<TService, 'plugin', 'singleton'>;
|
||||
|
||||
// @public
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'root'>,
|
||||
): ServiceRef<TService, 'root'>;
|
||||
options: ServiceRefOptions<TService, 'root', 'singleton'>,
|
||||
): ServiceRef<TService, 'root', 'singleton'>;
|
||||
|
||||
// @public
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'plugin', 'multiton'>,
|
||||
): ServiceRef<TService, 'plugin', 'multiton'>;
|
||||
|
||||
// @public
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'root', 'multiton'>,
|
||||
): ServiceRef<TService, 'root', 'multiton'>;
|
||||
|
||||
// @public
|
||||
export interface DatabaseService {
|
||||
@@ -488,16 +518,18 @@ export interface PluginMetadataService {
|
||||
// @public @deprecated (undocumented)
|
||||
export type PluginServiceFactoryConfig<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TContext,
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown>;
|
||||
},
|
||||
> = PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>;
|
||||
> = PluginServiceFactoryOptions<TService, TInstances, TContext, TImpl, TDeps>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TContext,
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
@@ -517,7 +549,7 @@ export interface PluginServiceFactoryOptions<
|
||||
): TImpl | Promise<TImpl>;
|
||||
initialization?: 'always' | 'lazy';
|
||||
// (undocumented)
|
||||
service: ServiceRef<TService, 'plugin'>;
|
||||
service: ServiceRef<TService, 'plugin', TInstances>;
|
||||
}
|
||||
|
||||
// @public
|
||||
@@ -579,15 +611,17 @@ export interface RootLoggerService extends LoggerService {}
|
||||
// @public @deprecated (undocumented)
|
||||
export type RootServiceFactoryConfig<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown>;
|
||||
},
|
||||
> = RootServiceFactoryOptions<TService, TImpl, TDeps>;
|
||||
> = RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RootServiceFactoryOptions<
|
||||
TService,
|
||||
TService, // TODO(Rugvip): Can we forward the entire service ref type here instead of forwarding each type arg once the callback form is gone?
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends {
|
||||
[name in string]: ServiceRef<unknown>;
|
||||
@@ -599,7 +633,7 @@ export interface RootServiceFactoryOptions<
|
||||
factory(deps: ServiceRefsToInstances<TDeps, 'root'>): TImpl | Promise<TImpl>;
|
||||
initialization?: 'always' | 'lazy';
|
||||
// (undocumented)
|
||||
service: ServiceRef<TService, 'root'>;
|
||||
service: ServiceRef<TService, 'root', TInstances>;
|
||||
}
|
||||
|
||||
// @public
|
||||
@@ -690,21 +724,23 @@ export type SearchResponseFile = UrlReaderServiceSearchResponseFile;
|
||||
export interface ServiceFactory<
|
||||
TService = unknown,
|
||||
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
> extends BackendFeature {
|
||||
// (undocumented)
|
||||
service: ServiceRef<TService, TScope>;
|
||||
service: ServiceRef<TService, TScope, TInstances>;
|
||||
}
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export interface ServiceFactoryCompat<
|
||||
TService = unknown,
|
||||
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
TOpts extends object | undefined = undefined,
|
||||
> extends ServiceFactory<TService, TScope> {
|
||||
> extends ServiceFactory<TService, TScope, TInstances> {
|
||||
// @deprecated (undocumented)
|
||||
(
|
||||
...options: undefined extends TOpts ? [] : [options?: TOpts]
|
||||
): ServiceFactory<TService, TScope>;
|
||||
): ServiceFactory<TService, TScope, TInstances>;
|
||||
}
|
||||
|
||||
// @public @deprecated
|
||||
@@ -714,9 +750,11 @@ export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory);
|
||||
export type ServiceRef<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin' = 'root' | 'plugin',
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
> = {
|
||||
id: string;
|
||||
scope: TScope;
|
||||
multiton?: TInstances extends 'multiton' ? true : false;
|
||||
T: TService;
|
||||
$$type: '@backstage/ServiceRef';
|
||||
};
|
||||
@@ -725,10 +763,15 @@ export type ServiceRef<
|
||||
export type ServiceRefConfig<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
> = ServiceRefOptions<TService, TScope>;
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
> = ServiceRefOptions<TService, TScope, TInstances>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ServiceRefOptions<TService, TScope extends 'root' | 'plugin'> {
|
||||
export interface ServiceRefOptions<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
> {
|
||||
// (undocumented)
|
||||
defaultFactory?(
|
||||
service: ServiceRef<TService, TScope>,
|
||||
@@ -740,6 +783,8 @@ export interface ServiceRefOptions<TService, TScope extends 'root' | 'plugin'> {
|
||||
// (undocumented)
|
||||
id: string;
|
||||
// (undocumented)
|
||||
multiton?: TInstances extends 'multiton' ? true : false;
|
||||
// (undocumented)
|
||||
scope?: TScope;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ import {
|
||||
export type ServiceRefConfig<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
> = ServiceRefOptions<TService, TScope>;
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
> = ServiceRefOptions<TService, TScope, TInstances>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -36,9 +37,10 @@ export type ServiceRefConfig<
|
||||
*/
|
||||
export type RootServiceFactoryConfig<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
> = RootServiceFactoryOptions<TService, TImpl, TDeps>;
|
||||
> = RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -46,7 +48,8 @@ export type RootServiceFactoryConfig<
|
||||
*/
|
||||
export type PluginServiceFactoryConfig<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TContext,
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
> = PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>;
|
||||
> = PluginServiceFactoryOptions<TService, TInstances, TContext, TImpl, TDeps>;
|
||||
|
||||
@@ -332,6 +332,24 @@ describe('createServiceFactory', () => {
|
||||
metaFactory();
|
||||
});
|
||||
|
||||
it('should support old service refs without a multiton field', () => {
|
||||
const oldPluginDep = pluginDep as Omit<typeof pluginDep, 'multiton'>; // Old refs don't have a multiton field
|
||||
const metaFactory = createServiceFactory({
|
||||
service: ref,
|
||||
deps: {
|
||||
plugin: oldPluginDep,
|
||||
},
|
||||
async factory({ plugin }) {
|
||||
const plugin1: boolean = plugin;
|
||||
// @ts-expect-error
|
||||
const plugin2: number = plugin;
|
||||
unused(plugin1, plugin2);
|
||||
return 'x';
|
||||
},
|
||||
});
|
||||
expect(metaFactory).toEqual(expect.any(Function));
|
||||
});
|
||||
|
||||
it('should only allow objects as options', () => {
|
||||
// @ts-expect-error
|
||||
const metaFactory = createServiceFactory((_opts: string) => ({
|
||||
|
||||
@@ -24,6 +24,7 @@ import { BackendFeature } from '../../types';
|
||||
export type ServiceRef<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin' = 'root' | 'plugin',
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
> = {
|
||||
id: string;
|
||||
|
||||
@@ -38,6 +39,8 @@ export type ServiceRef<
|
||||
*/
|
||||
scope: TScope;
|
||||
|
||||
multiton?: TInstances extends 'multiton' ? true : false;
|
||||
|
||||
/**
|
||||
* Utility for getting the type of the service, using `typeof serviceRef.T`.
|
||||
* Attempting to actually read this value will result in an exception.
|
||||
@@ -51,8 +54,9 @@ export type ServiceRef<
|
||||
export interface ServiceFactory<
|
||||
TService = unknown,
|
||||
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
> extends BackendFeature {
|
||||
service: ServiceRef<TService, TScope>;
|
||||
service: ServiceRef<TService, TScope, TInstances>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,21 +66,23 @@ export interface ServiceFactory<
|
||||
export interface ServiceFactoryCompat<
|
||||
TService = unknown,
|
||||
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
TOpts extends object | undefined = undefined,
|
||||
> extends ServiceFactory<TService, TScope> {
|
||||
> extends ServiceFactory<TService, TScope, TInstances> {
|
||||
/**
|
||||
* @deprecated Callable service factories will be removed in a future release, please re-implement the service factory using the available APIs instead. If no options are being passed, you can simply remove the trailing `()`.
|
||||
*/
|
||||
(
|
||||
...options: undefined extends TOpts ? [] : [options?: TOpts]
|
||||
): ServiceFactory<TService, TScope>;
|
||||
): ServiceFactory<TService, TScope, TInstances>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface InternalServiceFactory<
|
||||
TService = unknown,
|
||||
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
|
||||
> extends ServiceFactory<TService, TScope> {
|
||||
TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton',
|
||||
> extends ServiceFactory<TService, TScope, TInstances> {
|
||||
version: 'v1';
|
||||
featureType: 'service';
|
||||
initialization?: 'always' | 'lazy';
|
||||
@@ -97,9 +103,14 @@ export interface InternalServiceFactory<
|
||||
export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory);
|
||||
|
||||
/** @public */
|
||||
export interface ServiceRefOptions<TService, TScope extends 'root' | 'plugin'> {
|
||||
export interface ServiceRefOptions<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
> {
|
||||
id: string;
|
||||
scope?: TScope;
|
||||
multiton?: TInstances extends 'multiton' ? true : false;
|
||||
defaultFactory?(
|
||||
service: ServiceRef<TService, TScope>,
|
||||
): Promise<ServiceFactory>;
|
||||
@@ -117,8 +128,8 @@ export interface ServiceRefOptions<TService, TScope extends 'root' | 'plugin'> {
|
||||
* @public
|
||||
*/
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'plugin'>,
|
||||
): ServiceRef<TService, 'plugin'>;
|
||||
options: ServiceRefOptions<TService, 'plugin', 'singleton'>,
|
||||
): ServiceRef<TService, 'plugin', 'singleton'>;
|
||||
|
||||
/**
|
||||
* Creates a new service definition. This overload is used to create root scoped services.
|
||||
@@ -126,16 +137,37 @@ export function createServiceRef<TService>(
|
||||
* @public
|
||||
*/
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'root'>,
|
||||
): ServiceRef<TService, 'root'>;
|
||||
options: ServiceRefOptions<TService, 'root', 'singleton'>,
|
||||
): ServiceRef<TService, 'root', 'singleton'>;
|
||||
|
||||
/**
|
||||
* Creates a new service definition. This overload is used to create plugin scoped services.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, any>,
|
||||
): ServiceRef<TService, any> {
|
||||
const { id, scope = 'plugin', defaultFactory } = options;
|
||||
options: ServiceRefOptions<TService, 'plugin', 'multiton'>,
|
||||
): ServiceRef<TService, 'plugin', 'multiton'>;
|
||||
|
||||
/**
|
||||
* Creates a new service definition. This overload is used to create root scoped services.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createServiceRef<TService>(
|
||||
options: ServiceRefOptions<TService, 'root', 'multiton'>,
|
||||
): ServiceRef<TService, 'root', 'multiton'>;
|
||||
export function createServiceRef<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
>(
|
||||
options: ServiceRefOptions<TService, any, TInstances>,
|
||||
): ServiceRef<TService, any, TInstances> {
|
||||
const { id, scope = 'plugin', multiton = false, defaultFactory } = options;
|
||||
return {
|
||||
id,
|
||||
scope,
|
||||
multiton,
|
||||
get T(): TService {
|
||||
throw new Error(`tried to read ServiceRef.T of ${this}`);
|
||||
},
|
||||
@@ -144,7 +176,7 @@ export function createServiceRef<TService>(
|
||||
},
|
||||
$$type: '@backstage/ServiceRef',
|
||||
__defaultFactory: defaultFactory,
|
||||
} as ServiceRef<TService, typeof scope> & {
|
||||
} as ServiceRef<TService, typeof scope, TInstances> & {
|
||||
__defaultFactory?: (
|
||||
service: ServiceRef<TService>,
|
||||
) => Promise<ServiceFactory<TService> | (() => ServiceFactory<TService>)>;
|
||||
@@ -156,12 +188,17 @@ type ServiceRefsToInstances<
|
||||
T extends { [key in string]: ServiceRef<unknown> },
|
||||
TScope extends 'root' | 'plugin' = 'root' | 'plugin',
|
||||
> = {
|
||||
[key in keyof T as T[key]['scope'] extends TScope ? key : never]: T[key]['T'];
|
||||
[key in keyof T as T[key]['scope'] extends TScope
|
||||
? key
|
||||
: never]: T[key]['multiton'] extends true | undefined
|
||||
? Array<T[key]['T']>
|
||||
: T[key]['T'];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface RootServiceFactoryOptions<
|
||||
TService,
|
||||
TService, // TODO(Rugvip): Can we forward the entire service ref type here instead of forwarding each type arg once the callback form is gone?
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
> {
|
||||
@@ -176,7 +213,7 @@ export interface RootServiceFactoryOptions<
|
||||
* Service factories for root scoped services use `always` as the default, while plugin scoped services use `lazy`.
|
||||
*/
|
||||
initialization?: 'always' | 'lazy';
|
||||
service: ServiceRef<TService, 'root'>;
|
||||
service: ServiceRef<TService, 'root', TInstances>;
|
||||
deps: TDeps;
|
||||
factory(deps: ServiceRefsToInstances<TDeps, 'root'>): TImpl | Promise<TImpl>;
|
||||
}
|
||||
@@ -184,6 +221,7 @@ export interface RootServiceFactoryOptions<
|
||||
/** @public */
|
||||
export interface PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TContext,
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
@@ -199,7 +237,7 @@ export interface PluginServiceFactoryOptions<
|
||||
* Service factories for root scoped services use `always` as the default, while plugin scoped services use `lazy`.
|
||||
*/
|
||||
initialization?: 'always' | 'lazy';
|
||||
service: ServiceRef<TService, 'plugin'>;
|
||||
service: ServiceRef<TService, 'plugin', TInstances>;
|
||||
deps: TDeps;
|
||||
createRootContext?(
|
||||
deps: ServiceRefsToInstances<TDeps, 'root'>,
|
||||
@@ -218,12 +256,13 @@ export interface PluginServiceFactoryOptions<
|
||||
*/
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown, 'root'> },
|
||||
TOpts extends object | undefined = undefined,
|
||||
>(
|
||||
options: RootServiceFactoryOptions<TService, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root'>;
|
||||
options: RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root', TInstances>;
|
||||
/**
|
||||
* Creates a root scoped service factory with optional options.
|
||||
*
|
||||
@@ -236,14 +275,15 @@ export function createServiceFactory<
|
||||
*/
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown, 'root'> },
|
||||
TOpts extends object | undefined = undefined,
|
||||
>(
|
||||
options: (
|
||||
options?: TOpts,
|
||||
) => RootServiceFactoryOptions<TService, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root', TOpts>;
|
||||
) => RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'root', TInstances, TOpts>;
|
||||
/**
|
||||
* Creates a plugin scoped service factory without options.
|
||||
*
|
||||
@@ -252,13 +292,20 @@ export function createServiceFactory<
|
||||
*/
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
TContext = undefined,
|
||||
TOpts extends object | undefined = undefined,
|
||||
>(
|
||||
options: PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'plugin'>;
|
||||
options: PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
>,
|
||||
): ServiceFactoryCompat<TService, 'plugin', TInstances>;
|
||||
/**
|
||||
* Creates a plugin scoped service factory with optional options.
|
||||
*
|
||||
@@ -271,6 +318,7 @@ export function createServiceFactory<
|
||||
*/
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
TContext = undefined,
|
||||
@@ -278,25 +326,51 @@ export function createServiceFactory<
|
||||
>(
|
||||
options: (
|
||||
options?: TOpts,
|
||||
) => PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
|
||||
): ServiceFactoryCompat<TService, 'plugin', TOpts>;
|
||||
) => PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
>,
|
||||
): ServiceFactoryCompat<TService, 'plugin', TInstances, TOpts>;
|
||||
export function createServiceFactory<
|
||||
TService,
|
||||
TInstances extends 'singleton' | 'multiton',
|
||||
TImpl extends TService,
|
||||
TDeps extends { [name in string]: ServiceRef<unknown> },
|
||||
TContext,
|
||||
TOpts extends object | undefined = undefined,
|
||||
>(
|
||||
options:
|
||||
| RootServiceFactoryOptions<TService, TImpl, TDeps>
|
||||
| PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>
|
||||
| ((options: TOpts) => RootServiceFactoryOptions<TService, TImpl, TDeps>)
|
||||
| RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>
|
||||
| PluginServiceFactoryOptions<TService, TInstances, TContext, TImpl, TDeps>
|
||||
| ((
|
||||
options: TOpts,
|
||||
) => PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>)
|
||||
| (() => RootServiceFactoryOptions<TService, TImpl, TDeps>)
|
||||
| (() => PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>),
|
||||
): ServiceFactoryCompat<TService, 'root' | 'plugin', TOpts> {
|
||||
) => RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>)
|
||||
| ((
|
||||
options: TOpts,
|
||||
) => PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
>)
|
||||
| (() => RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>)
|
||||
| (() => PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
>),
|
||||
): ServiceFactoryCompat<
|
||||
TService,
|
||||
'root' | 'plugin',
|
||||
'singleton' | 'multiton',
|
||||
TOpts
|
||||
> {
|
||||
const configCallback =
|
||||
typeof options === 'function' ? options : () => options;
|
||||
const factory = (
|
||||
@@ -304,7 +378,12 @@ export function createServiceFactory<
|
||||
): InternalServiceFactory<TService, 'plugin' | 'root'> => {
|
||||
const anyConf = configCallback(o!);
|
||||
if (anyConf.service.scope === 'root') {
|
||||
const c = anyConf as RootServiceFactoryOptions<TService, TImpl, TDeps>;
|
||||
const c = anyConf as RootServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TImpl,
|
||||
TDeps
|
||||
>;
|
||||
return {
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
@@ -312,11 +391,13 @@ export function createServiceFactory<
|
||||
service: c.service,
|
||||
initialization: c.initialization,
|
||||
deps: c.deps,
|
||||
factory: async (deps: TDeps) => c.factory(deps),
|
||||
factory: async (deps: ServiceRefsToInstances<TDeps, 'root'>) =>
|
||||
c.factory(deps),
|
||||
};
|
||||
}
|
||||
const c = anyConf as PluginServiceFactoryOptions<
|
||||
TService,
|
||||
TInstances,
|
||||
TContext,
|
||||
TImpl,
|
||||
TDeps
|
||||
@@ -329,12 +410,14 @@ export function createServiceFactory<
|
||||
initialization: c.initialization,
|
||||
...('createRootContext' in c
|
||||
? {
|
||||
createRootContext: async (deps: TDeps) =>
|
||||
c?.createRootContext?.(deps),
|
||||
createRootContext: async (
|
||||
deps: ServiceRefsToInstances<TDeps, 'root'>,
|
||||
) => c?.createRootContext?.(deps),
|
||||
}
|
||||
: {}),
|
||||
deps: c.deps,
|
||||
factory: async (deps: TDeps, ctx: TContext) => c.factory(deps, ctx),
|
||||
factory: async (deps: ServiceRefsToInstances<TDeps>, ctx: TContext) =>
|
||||
c.factory(deps, ctx),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user