feat: start implementing multiple service factories

Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2024-07-08 16:08:04 +02:00
committed by Patrik Oldsberg
parent 88ed7f5926
commit 11aaaa496a
33 changed files with 563 additions and 250 deletions
@@ -17,7 +17,8 @@ export interface FeatureDiscoveryService {
// @alpha
export const featureDiscoveryServiceRef: ServiceRef<
FeatureDiscoveryService,
'root'
'root',
true
>;
// (No @packageDocumentation comment for this package)
+83 -42
View File
@@ -189,28 +189,28 @@ 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', true>;
const userInfo: ServiceRef<UserInfoService, 'plugin', true>;
const cache: ServiceRef<CacheService, 'plugin', true>;
const rootConfig: ServiceRef<RootConfigService, 'root', true>;
const database: ServiceRef<DatabaseService, 'plugin', true>;
const discovery: ServiceRef<DiscoveryService, 'plugin', true>;
const rootHealth: ServiceRef<RootHealthService, 'root', true>;
const httpAuth: ServiceRef<HttpAuthService, 'plugin', true>;
const httpRouter: ServiceRef<HttpRouterService, 'plugin', true>;
const lifecycle: ServiceRef<LifecycleService, 'plugin', true>;
const logger: ServiceRef<LoggerService, 'plugin', true>;
const permissions: ServiceRef<PermissionsService, 'plugin', true>;
const pluginMetadata: ServiceRef<PluginMetadataService, 'plugin', true>;
const rootHttpRouter: ServiceRef<RootHttpRouterService, 'root', true>;
const rootLifecycle: ServiceRef<RootLifecycleService, 'root', true>;
const rootLogger: ServiceRef<RootLoggerService, 'root', true>;
const scheduler: ServiceRef<SchedulerService, 'plugin', true>;
const // @deprecated
tokenManager: ServiceRef<TokenManagerService, 'plugin'>;
const urlReader: ServiceRef<UrlReaderService, 'plugin'>;
tokenManager: ServiceRef<TokenManagerService, 'plugin', true>;
const urlReader: ServiceRef<UrlReaderService, 'plugin', true>;
const // @deprecated
identity: ServiceRef<IdentityService, 'plugin'>;
identity: ServiceRef<IdentityService, 'plugin', true>;
}
// @public
@@ -251,18 +251,20 @@ export interface CreateExtensionPointOptions {
// @public
export function createServiceFactory<
TService,
TSingleton extends boolean,
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, TSingleton, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TSingleton>;
// @public @deprecated
export function createServiceFactory<
TService,
TSingleton extends boolean,
TImpl extends TService,
TDeps extends {
[name in string]: ServiceRef<unknown, 'root'>;
@@ -271,12 +273,13 @@ export function createServiceFactory<
>(
options: (
options?: TOpts,
) => RootServiceFactoryOptions<TService, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TOpts>;
) => RootServiceFactoryOptions<TService, TSingleton, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TSingleton, TOpts>;
// @public
export function createServiceFactory<
TService,
TSingleton extends boolean,
TImpl extends TService,
TDeps extends {
[name in string]: ServiceRef<unknown>;
@@ -284,12 +287,19 @@ export function createServiceFactory<
TContext = undefined,
TOpts extends object | undefined = undefined,
>(
options: PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'plugin'>;
options: PluginServiceFactoryOptions<
TService,
TSingleton,
TContext,
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TSingleton>;
// @public @deprecated
export function createServiceFactory<
TService,
TSingleton extends boolean,
TImpl extends TService,
TDeps extends {
[name in string]: ServiceRef<unknown>;
@@ -299,18 +309,34 @@ export function createServiceFactory<
>(
options: (
options?: TOpts,
) => PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'plugin', TOpts>;
) => PluginServiceFactoryOptions<
TService,
TSingleton,
TContext,
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TSingleton, TOpts>;
// @public
export function createServiceRef<TService>(
options: ServiceRefOptions<TService, 'plugin'>,
): ServiceRef<TService, 'plugin'>;
options: ServiceRefOptions<TService, 'plugin', true>,
): ServiceRef<TService, 'plugin', true>;
// @public
export function createServiceRef<TService>(
options: ServiceRefOptions<TService, 'root'>,
): ServiceRef<TService, 'root'>;
options: ServiceRefOptions<TService, 'root', true>,
): ServiceRef<TService, 'root', true>;
// @public
export function createServiceRef<TService>(
options: ServiceRefOptions<TService, 'plugin', false>,
): ServiceRef<TService, 'plugin', false>;
// @public
export function createServiceRef<TService>(
options: ServiceRefOptions<TService, 'root', false>,
): ServiceRef<TService, 'root', false>;
// @public
export interface DatabaseService {
@@ -447,16 +473,18 @@ export interface PluginMetadataService {
// @public @deprecated (undocumented)
export type PluginServiceFactoryConfig<
TService,
TSingleton extends boolean,
TContext,
TImpl extends TService,
TDeps extends {
[name in string]: ServiceRef<unknown>;
},
> = PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>;
> = PluginServiceFactoryOptions<TService, TSingleton, TContext, TImpl, TDeps>;
// @public (undocumented)
export interface PluginServiceFactoryOptions<
TService,
TSingleton extends boolean,
TContext,
TImpl extends TService,
TDeps extends {
@@ -476,7 +504,7 @@ export interface PluginServiceFactoryOptions<
): TImpl | Promise<TImpl>;
initialization?: 'always' | 'lazy';
// (undocumented)
service: ServiceRef<TService, 'plugin'>;
service: ServiceRef<TService, 'plugin', TSingleton>;
}
// @public
@@ -538,15 +566,17 @@ export interface RootLoggerService extends LoggerService {}
// @public @deprecated (undocumented)
export type RootServiceFactoryConfig<
TService,
TSingleton extends boolean,
TImpl extends TService,
TDeps extends {
[name in string]: ServiceRef<unknown>;
},
> = RootServiceFactoryOptions<TService, TImpl, TDeps>;
> = RootServiceFactoryOptions<TService, TSingleton, 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?
TSingleton extends boolean,
TImpl extends TService,
TDeps extends {
[name in string]: ServiceRef<unknown>;
@@ -558,7 +588,7 @@ export interface RootServiceFactoryOptions<
factory(deps: ServiceRefsToInstances<TDeps, 'root'>): TImpl | Promise<TImpl>;
initialization?: 'always' | 'lazy';
// (undocumented)
service: ServiceRef<TService, 'root'>;
service: ServiceRef<TService, 'root', TSingleton>;
}
// @public
@@ -639,21 +669,23 @@ export type SearchResponseFile = UrlReaderServiceSearchResponseFile;
export interface ServiceFactory<
TService = unknown,
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
TSingleton extends boolean = boolean,
> extends BackendFeature {
// (undocumented)
service: ServiceRef<TService, TScope>;
service: ServiceRef<TService, TScope, TSingleton>;
}
// @public @deprecated (undocumented)
export interface ServiceFactoryCompat<
TService = unknown,
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
TSingleton extends boolean = boolean,
TOpts extends object | undefined = undefined,
> extends ServiceFactory<TService, TScope> {
> extends ServiceFactory<TService, TScope, TSingleton> {
// @deprecated (undocumented)
(
...options: undefined extends TOpts ? [] : [options?: TOpts]
): ServiceFactory<TService, TScope>;
): ServiceFactory<TService, TScope, TSingleton>;
}
// @public @deprecated
@@ -663,9 +695,11 @@ export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory);
export type ServiceRef<
TService,
TScope extends 'root' | 'plugin' = 'root' | 'plugin',
TSingleton extends boolean = boolean,
> = {
id: string;
scope: TScope;
singleton: TSingleton;
T: TService;
$$type: '@backstage/ServiceRef';
};
@@ -674,10 +708,15 @@ export type ServiceRef<
export type ServiceRefConfig<
TService,
TScope extends 'root' | 'plugin',
> = ServiceRefOptions<TService, TScope>;
TSingleton extends boolean,
> = ServiceRefOptions<TService, TScope, TSingleton>;
// @public (undocumented)
export interface ServiceRefOptions<TService, TScope extends 'root' | 'plugin'> {
export interface ServiceRefOptions<
TService,
TScope extends 'root' | 'plugin',
TSingleton extends boolean,
> {
// (undocumented)
defaultFactory?(
service: ServiceRef<TService, TScope>,
@@ -690,6 +729,8 @@ export interface ServiceRefOptions<TService, TScope extends 'root' | 'plugin'> {
id: string;
// (undocumented)
scope?: TScope;
// (undocumented)
singleton?: TSingleton;
}
// @public @deprecated
@@ -28,7 +28,8 @@ import {
export type ServiceRefConfig<
TService,
TScope extends 'root' | 'plugin',
> = ServiceRefOptions<TService, TScope>;
TSingleton extends boolean,
> = ServiceRefOptions<TService, TScope, TSingleton>;
/**
* @public
@@ -36,9 +37,10 @@ export type ServiceRefConfig<
*/
export type RootServiceFactoryConfig<
TService,
TSingleton extends boolean,
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
> = RootServiceFactoryOptions<TService, TImpl, TDeps>;
> = RootServiceFactoryOptions<TService, TSingleton, TImpl, TDeps>;
/**
* @public
@@ -46,7 +48,8 @@ export type RootServiceFactoryConfig<
*/
export type PluginServiceFactoryConfig<
TService,
TSingleton extends boolean,
TContext,
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
> = PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>;
> = PluginServiceFactoryOptions<TService, TSingleton, TContext, TImpl, TDeps>;
@@ -24,6 +24,7 @@ import { BackendFeature } from '../../types';
export type ServiceRef<
TService,
TScope extends 'root' | 'plugin' = 'root' | 'plugin',
TSingleton extends boolean = boolean,
> = {
id: string;
@@ -38,6 +39,8 @@ export type ServiceRef<
*/
scope: TScope;
singleton: TSingleton;
/**
* 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',
TSingleton extends boolean = boolean,
> extends BackendFeature {
service: ServiceRef<TService, TScope>;
service: ServiceRef<TService, TScope, TSingleton>;
}
/**
@@ -62,21 +66,23 @@ export interface ServiceFactory<
export interface ServiceFactoryCompat<
TService = unknown,
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
TSingleton extends boolean = boolean,
TOpts extends object | undefined = undefined,
> extends ServiceFactory<TService, TScope> {
> extends ServiceFactory<TService, TScope, TSingleton> {
/**
* @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, TSingleton>;
}
/** @internal */
export interface InternalServiceFactory<
TService = unknown,
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
> extends ServiceFactory<TService, TScope> {
TSingleton extends boolean = boolean,
> extends ServiceFactory<TService, TScope, TSingleton> {
version: 'v1';
initialization?: 'always' | 'lazy';
deps: { [key in string]: ServiceRef<unknown> };
@@ -96,9 +102,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',
TSingleton extends boolean,
> {
id: string;
scope?: TScope;
singleton?: TSingleton;
defaultFactory?(
service: ServiceRef<TService, TScope>,
): Promise<ServiceFactory>;
@@ -116,8 +127,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', true>,
): ServiceRef<TService, 'plugin', true>;
/**
* Creates a new service definition. This overload is used to create root scoped services.
@@ -125,16 +136,34 @@ export function createServiceRef<TService>(
* @public
*/
export function createServiceRef<TService>(
options: ServiceRefOptions<TService, 'root'>,
): ServiceRef<TService, 'root'>;
options: ServiceRefOptions<TService, 'root', true>,
): ServiceRef<TService, 'root', true>;
/**
* 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', false>,
): ServiceRef<TService, 'plugin', false>;
/**
* Creates a new service definition. This overload is used to create root scoped services.
*
* @public
*/
export function createServiceRef<TService>(
options: ServiceRefOptions<TService, 'root', false>,
): ServiceRef<TService, 'root', false>;
export function createServiceRef<TService, TSingleton extends boolean>(
options: ServiceRefOptions<TService, any, TSingleton>,
): ServiceRef<TService, any, TSingleton> {
const { id, scope = 'plugin', singleton = true, defaultFactory } = options;
return {
id,
scope,
singleton,
get T(): TService {
throw new Error(`tried to read ServiceRef.T of ${this}`);
},
@@ -143,7 +172,7 @@ export function createServiceRef<TService>(
},
$$type: '@backstage/ServiceRef',
__defaultFactory: defaultFactory,
} as ServiceRef<TService, typeof scope> & {
} as ServiceRef<TService, typeof scope, TSingleton> & {
__defaultFactory?: (
service: ServiceRef<TService>,
) => Promise<ServiceFactory<TService> | (() => ServiceFactory<TService>)>;
@@ -155,12 +184,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]['singleton'] extends true
? T[key]['T']
: Array<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?
TSingleton extends boolean,
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
> {
@@ -175,7 +209,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', TSingleton>;
deps: TDeps;
factory(deps: ServiceRefsToInstances<TDeps, 'root'>): TImpl | Promise<TImpl>;
}
@@ -183,6 +217,7 @@ export interface RootServiceFactoryOptions<
/** @public */
export interface PluginServiceFactoryOptions<
TService,
TSingleton extends boolean,
TContext,
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
@@ -198,7 +233,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', TSingleton>;
deps: TDeps;
createRootContext?(
deps: ServiceRefsToInstances<TDeps, 'root'>,
@@ -217,12 +252,13 @@ export interface PluginServiceFactoryOptions<
*/
export function createServiceFactory<
TService,
TSingleton extends boolean,
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, TSingleton, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TSingleton>;
/**
* Creates a root scoped service factory with optional options.
*
@@ -235,14 +271,15 @@ export function createServiceFactory<
*/
export function createServiceFactory<
TService,
TSingleton extends boolean,
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, TSingleton, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TSingleton, TOpts>;
/**
* Creates a plugin scoped service factory without options.
*
@@ -251,13 +288,20 @@ export function createServiceFactory<
*/
export function createServiceFactory<
TService,
TSingleton extends boolean,
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,
TSingleton,
TContext,
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TSingleton>;
/**
* Creates a plugin scoped service factory with optional options.
*
@@ -270,6 +314,7 @@ export function createServiceFactory<
*/
export function createServiceFactory<
TService,
TSingleton extends boolean,
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
TContext = undefined,
@@ -277,25 +322,46 @@ export function createServiceFactory<
>(
options: (
options?: TOpts,
) => PluginServiceFactoryOptions<TService, TContext, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'plugin', TOpts>;
) => PluginServiceFactoryOptions<
TService,
TSingleton,
TContext,
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TSingleton, TOpts>;
export function createServiceFactory<
TService,
TSingleton extends boolean,
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, TSingleton, TImpl, TDeps>
| PluginServiceFactoryOptions<TService, TSingleton, 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, TSingleton, TImpl, TDeps>)
| ((
options: TOpts,
) => PluginServiceFactoryOptions<
TService,
TSingleton,
TContext,
TImpl,
TDeps
>)
| (() => RootServiceFactoryOptions<TService, TSingleton, TImpl, TDeps>)
| (() => PluginServiceFactoryOptions<
TService,
TSingleton,
TContext,
TImpl,
TDeps
>),
): ServiceFactoryCompat<TService, 'root' | 'plugin', boolean, TOpts> {
const configCallback =
typeof options === 'function' ? options : () => options;
const factory = (
@@ -303,18 +369,25 @@ 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,
TSingleton,
TImpl,
TDeps
>;
return {
$$type: '@backstage/BackendFeature',
version: 'v1',
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,
TSingleton,
TContext,
TImpl,
TDeps
@@ -326,12 +399,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),
};
};