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:
committed by
Patrik Oldsberg
parent
88ed7f5926
commit
11aaaa496a
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const featureDiscoveryServiceFactory: ServiceFactoryCompat<
|
||||
FeatureDiscoveryService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ import { UserInfoService } from '@backstage/backend-plugin-api';
|
||||
export const authServiceFactory: ServiceFactoryCompat<
|
||||
AuthService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -80,6 +81,7 @@ export interface Backend {
|
||||
export const cacheServiceFactory: ServiceFactoryCompat<
|
||||
CacheService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -113,6 +115,7 @@ export interface CreateSpecializedBackendOptions {
|
||||
export const databaseServiceFactory: ServiceFactoryCompat<
|
||||
DatabaseService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -135,6 +138,7 @@ export type DefaultRootHttpRouterOptions = DefaultRootHttpRouterOptions_2;
|
||||
export const discoveryServiceFactory: ServiceFactoryCompat<
|
||||
DiscoveryService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -161,6 +165,7 @@ export class HostDiscovery implements DiscoveryService {
|
||||
export const httpAuthServiceFactory: ServiceFactoryCompat<
|
||||
HttpAuthService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -168,6 +173,7 @@ export const httpAuthServiceFactory: ServiceFactoryCompat<
|
||||
export const httpRouterServiceFactory: ServiceFactoryCompat<
|
||||
HttpRouterService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -191,6 +197,7 @@ export type IdentityFactoryOptions = {
|
||||
export const identityServiceFactory: ServiceFactoryCompat<
|
||||
IdentityService,
|
||||
'plugin',
|
||||
true,
|
||||
IdentityFactoryOptions
|
||||
>;
|
||||
|
||||
@@ -203,6 +210,7 @@ export type LifecycleMiddlewareOptions = LifecycleMiddlewareOptions_2;
|
||||
export const lifecycleServiceFactory: ServiceFactoryCompat<
|
||||
LifecycleService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -220,6 +228,7 @@ export function loadBackendConfig(options: {
|
||||
export const loggerServiceFactory: ServiceFactoryCompat<
|
||||
LoggerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -248,6 +257,7 @@ export type MiddlewareFactoryOptions = MiddlewareFactoryOptions_2;
|
||||
export const permissionsServiceFactory: ServiceFactoryCompat<
|
||||
PermissionsService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -278,6 +288,7 @@ export interface RootConfigFactoryOptions {
|
||||
export const rootConfigServiceFactory: ServiceFactoryCompat<
|
||||
RootConfigService,
|
||||
'root',
|
||||
true,
|
||||
RootConfigFactoryOptions
|
||||
>;
|
||||
|
||||
@@ -294,13 +305,14 @@ export type RootHttpRouterFactoryOptions = RootHttpRouterFactoryOptions_2;
|
||||
// @public @deprecated (undocumented)
|
||||
export const rootHttpRouterServiceFactory: ((
|
||||
options?: RootHttpRouterFactoryOptions_2 | undefined,
|
||||
) => ServiceFactory<RootHttpRouterService, 'root'>) &
|
||||
ServiceFactory<RootHttpRouterService, 'root'>;
|
||||
) => ServiceFactory<RootHttpRouterService, 'root', true>) &
|
||||
ServiceFactory<RootHttpRouterService, 'root', true>;
|
||||
|
||||
// @public @deprecated
|
||||
export const rootLifecycleServiceFactory: ServiceFactoryCompat<
|
||||
RootLifecycleService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -308,6 +320,7 @@ export const rootLifecycleServiceFactory: ServiceFactoryCompat<
|
||||
export const rootLoggerServiceFactory: ServiceFactoryCompat<
|
||||
RootLoggerService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -315,6 +328,7 @@ export const rootLoggerServiceFactory: ServiceFactoryCompat<
|
||||
export const schedulerServiceFactory: ServiceFactoryCompat<
|
||||
SchedulerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -322,6 +336,7 @@ export const schedulerServiceFactory: ServiceFactoryCompat<
|
||||
export const tokenManagerServiceFactory: ServiceFactoryCompat<
|
||||
TokenManagerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -329,6 +344,7 @@ export const tokenManagerServiceFactory: ServiceFactoryCompat<
|
||||
export const urlReaderServiceFactory: ServiceFactoryCompat<
|
||||
UrlReaderService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -336,6 +352,7 @@ export const urlReaderServiceFactory: ServiceFactoryCompat<
|
||||
export const userInfoServiceFactory: ServiceFactoryCompat<
|
||||
UserInfoService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -58,12 +58,24 @@ function createPluginMetadataServiceFactory(pluginId: string) {
|
||||
|
||||
export class ServiceRegistry {
|
||||
static create(factories: Array<ServiceFactory>): ServiceRegistry {
|
||||
const registry = new ServiceRegistry(factories);
|
||||
const factoryMap = new Map<string, InternalServiceFactory[]>();
|
||||
for (const factory of factories) {
|
||||
if (factory.service.singleton) {
|
||||
factoryMap.set(factory.service.id, [toInternalServiceFactory(factory)]);
|
||||
} else {
|
||||
const existing = factoryMap.get(factory.service.id) ?? [];
|
||||
factoryMap.set(
|
||||
factory.service.id,
|
||||
existing.concat(toInternalServiceFactory(factory)),
|
||||
);
|
||||
}
|
||||
}
|
||||
const registry = new ServiceRegistry(factoryMap);
|
||||
registry.checkForCircularDeps();
|
||||
return registry;
|
||||
}
|
||||
|
||||
readonly #providedFactories: Map<string, InternalServiceFactory>;
|
||||
readonly #providedFactories: Map<string, InternalServiceFactory[]>;
|
||||
readonly #loadedDefaultFactories: Map<
|
||||
Function,
|
||||
Promise<InternalServiceFactory>
|
||||
@@ -82,10 +94,8 @@ export class ServiceRegistry {
|
||||
readonly #addedFactoryIds = new Set<string>();
|
||||
readonly #instantiatedFactories = new Set<string>();
|
||||
|
||||
private constructor(factories: Array<ServiceFactory>) {
|
||||
this.#providedFactories = new Map(
|
||||
factories.map(sf => [sf.service.id, toInternalServiceFactory(sf)]),
|
||||
);
|
||||
private constructor(factories: Map<string, InternalServiceFactory[]>) {
|
||||
this.#providedFactories = factories;
|
||||
this.#loadedDefaultFactories = new Map();
|
||||
this.#implementations = new Map();
|
||||
}
|
||||
@@ -93,17 +103,17 @@ export class ServiceRegistry {
|
||||
#resolveFactory(
|
||||
ref: ServiceRef<unknown>,
|
||||
pluginId: string,
|
||||
): Promise<InternalServiceFactory> | undefined {
|
||||
): Promise<InternalServiceFactory[]> | undefined {
|
||||
// Special case handling of the plugin metadata service, generating a custom factory for it each time
|
||||
if (ref.id === coreServices.pluginMetadata.id) {
|
||||
return Promise.resolve(
|
||||
return Promise.resolve([
|
||||
toInternalServiceFactory(createPluginMetadataServiceFactory(pluginId)),
|
||||
);
|
||||
]);
|
||||
}
|
||||
|
||||
let resolvedFactory:
|
||||
| Promise<InternalServiceFactory>
|
||||
| InternalServiceFactory
|
||||
| Promise<InternalServiceFactory[]>
|
||||
| InternalServiceFactory[]
|
||||
| undefined = this.#providedFactories.get(ref.id);
|
||||
const { __defaultFactory: defaultFactory } = ref as InternalServiceRef;
|
||||
if (!resolvedFactory && !defaultFactory) {
|
||||
@@ -120,15 +130,18 @@ export class ServiceRegistry {
|
||||
);
|
||||
this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory);
|
||||
}
|
||||
resolvedFactory = loadedFactory.catch(error => {
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${
|
||||
ref.id
|
||||
}' because the default factory loader threw an error, ${stringifyError(
|
||||
error,
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
resolvedFactory = loadedFactory.then(
|
||||
factory => [factory],
|
||||
error => {
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${
|
||||
ref.id
|
||||
}' because the default factory loader threw an error, ${stringifyError(
|
||||
error,
|
||||
)}`,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve(resolvedFactory);
|
||||
@@ -142,6 +155,9 @@ export class ServiceRegistry {
|
||||
if (this.#providedFactories.get(ref.id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ref.singleton) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(ref as InternalServiceRef).__defaultFactory;
|
||||
});
|
||||
@@ -156,13 +172,13 @@ export class ServiceRegistry {
|
||||
|
||||
checkForCircularDeps(): void {
|
||||
const graph = DependencyGraph.fromIterable(
|
||||
Array.from(this.#providedFactories).map(
|
||||
([serviceId, serviceFactory]) => ({
|
||||
value: serviceId,
|
||||
provides: [serviceId],
|
||||
consumes: Object.values(serviceFactory.deps).map(d => d.id),
|
||||
}),
|
||||
),
|
||||
Array.from(this.#providedFactories).map(([serviceId, factories]) => ({
|
||||
value: serviceId,
|
||||
provides: [serviceId],
|
||||
consumes: factories.flatMap(factory =>
|
||||
Object.values(factory.deps).map(d => d.id),
|
||||
),
|
||||
})),
|
||||
);
|
||||
const circularDependencies = Array.from(graph.detectCircularDependencies());
|
||||
|
||||
@@ -183,27 +199,36 @@ export class ServiceRegistry {
|
||||
);
|
||||
}
|
||||
|
||||
if (this.#addedFactoryIds.has(factoryId)) {
|
||||
throw new Error(
|
||||
`Duplicate service implementations provided for ${factoryId}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.#instantiatedFactories.has(factoryId)) {
|
||||
throw new Error(
|
||||
`Unable to set service factory with id ${factoryId}, service has already been instantiated`,
|
||||
);
|
||||
}
|
||||
|
||||
this.#addedFactoryIds.add(factoryId);
|
||||
this.#providedFactories.set(factoryId, toInternalServiceFactory(factory));
|
||||
if (factory.service.singleton) {
|
||||
if (this.#addedFactoryIds.has(factoryId)) {
|
||||
throw new Error(
|
||||
`Duplicate service implementations provided for ${factoryId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.#addedFactoryIds.add(factoryId);
|
||||
this.#providedFactories.set(factoryId, [
|
||||
toInternalServiceFactory(factory),
|
||||
]);
|
||||
} else {
|
||||
const newFactories = (
|
||||
this.#providedFactories.get(factoryId) ?? []
|
||||
).concat(toInternalServiceFactory(factory));
|
||||
this.#providedFactories.set(factoryId, newFactories);
|
||||
}
|
||||
}
|
||||
|
||||
async initializeEagerServicesWithScope(
|
||||
scope: 'root' | 'plugin',
|
||||
pluginId: string = 'root',
|
||||
) {
|
||||
for (const factory of this.#providedFactories.values()) {
|
||||
for (const [factory] of this.#providedFactories.values()) {
|
||||
if (factory.service.scope === scope) {
|
||||
// Root-scoped services are eager by default, plugin-scoped are lazy by default
|
||||
if (scope === 'root' && factory.initialization !== 'lazy') {
|
||||
@@ -215,88 +240,112 @@ export class ServiceRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
get<T>(ref: ServiceRef<T>, pluginId: string): Promise<T> | undefined {
|
||||
get<T, TSingleton extends boolean>(
|
||||
ref: ServiceRef<T, 'plugin' | 'root', TSingleton>,
|
||||
pluginId: string,
|
||||
): Promise<TSingleton extends true ? T : T[]> | undefined {
|
||||
this.#instantiatedFactories.add(ref.id);
|
||||
|
||||
return this.#resolveFactory(ref, pluginId)?.then(factory => {
|
||||
if (factory.service.scope === 'root') {
|
||||
let existing = this.#rootServiceImplementations.get(factory);
|
||||
if (!existing) {
|
||||
this.#checkForMissingDeps(factory, pluginId);
|
||||
const rootDeps = new Array<Promise<[name: string, impl: unknown]>>();
|
||||
const resolvedFactory = this.#resolveFactory(ref, pluginId);
|
||||
|
||||
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
||||
if (serviceRef.scope !== 'root') {
|
||||
throw new Error(
|
||||
`Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`,
|
||||
);
|
||||
if (!resolvedFactory) {
|
||||
return ref.singleton
|
||||
? undefined
|
||||
: (Promise.resolve([]) as
|
||||
| Promise<TSingleton extends true ? T : T[]>
|
||||
| undefined);
|
||||
}
|
||||
|
||||
return resolvedFactory
|
||||
.then(factories => {
|
||||
return Promise.all(
|
||||
factories.map(factory => {
|
||||
if (factory.service.scope === 'root') {
|
||||
let existing = this.#rootServiceImplementations.get(factory);
|
||||
if (!existing) {
|
||||
this.#checkForMissingDeps(factory, pluginId);
|
||||
const rootDeps = new Array<
|
||||
Promise<[name: string, impl: unknown]>
|
||||
>();
|
||||
|
||||
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
||||
if (serviceRef.scope !== 'root') {
|
||||
throw new Error(
|
||||
`Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`,
|
||||
);
|
||||
}
|
||||
const target = this.get(serviceRef, pluginId)!;
|
||||
rootDeps.push(target.then(impl => [name, impl]));
|
||||
}
|
||||
|
||||
existing = Promise.all(rootDeps).then(entries =>
|
||||
factory.factory(Object.fromEntries(entries), undefined),
|
||||
);
|
||||
this.#rootServiceImplementations.set(factory, existing);
|
||||
}
|
||||
return existing as Promise<T>;
|
||||
}
|
||||
const target = this.get(serviceRef, pluginId)!;
|
||||
rootDeps.push(target.then(impl => [name, impl]));
|
||||
}
|
||||
|
||||
existing = Promise.all(rootDeps).then(entries =>
|
||||
factory.factory(Object.fromEntries(entries), undefined),
|
||||
);
|
||||
this.#rootServiceImplementations.set(factory, existing);
|
||||
}
|
||||
return existing as Promise<T>;
|
||||
}
|
||||
let implementation = this.#implementations.get(factory);
|
||||
if (!implementation) {
|
||||
this.#checkForMissingDeps(factory, pluginId);
|
||||
const rootDeps = new Array<
|
||||
Promise<[name: string, impl: unknown]>
|
||||
>();
|
||||
|
||||
let implementation = this.#implementations.get(factory);
|
||||
if (!implementation) {
|
||||
this.#checkForMissingDeps(factory, pluginId);
|
||||
const rootDeps = new Array<Promise<[name: string, impl: unknown]>>();
|
||||
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
||||
if (serviceRef.scope === 'root') {
|
||||
const target = this.get(serviceRef, pluginId)!;
|
||||
rootDeps.push(target.then(impl => [name, impl]));
|
||||
}
|
||||
}
|
||||
|
||||
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
||||
if (serviceRef.scope === 'root') {
|
||||
const target = this.get(serviceRef, pluginId)!;
|
||||
rootDeps.push(target.then(impl => [name, impl]));
|
||||
}
|
||||
}
|
||||
implementation = {
|
||||
context: Promise.all(rootDeps)
|
||||
.then(entries =>
|
||||
factory.createRootContext?.(Object.fromEntries(entries)),
|
||||
)
|
||||
.catch(error => {
|
||||
const cause = stringifyError(error);
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`,
|
||||
);
|
||||
}),
|
||||
byPlugin: new Map(),
|
||||
};
|
||||
|
||||
implementation = {
|
||||
context: Promise.all(rootDeps)
|
||||
.then(entries =>
|
||||
factory.createRootContext?.(Object.fromEntries(entries)),
|
||||
)
|
||||
.catch(error => {
|
||||
const cause = stringifyError(error);
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`,
|
||||
);
|
||||
}),
|
||||
byPlugin: new Map(),
|
||||
};
|
||||
this.#implementations.set(factory, implementation);
|
||||
}
|
||||
|
||||
this.#implementations.set(factory, implementation);
|
||||
}
|
||||
let result = implementation.byPlugin.get(pluginId) as Promise<any>;
|
||||
if (!result) {
|
||||
const allDeps = new Array<
|
||||
Promise<[name: string, impl: unknown]>
|
||||
>();
|
||||
|
||||
let result = implementation.byPlugin.get(pluginId) as Promise<any>;
|
||||
if (!result) {
|
||||
const allDeps = new Array<Promise<[name: string, impl: unknown]>>();
|
||||
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
||||
const target = this.get(serviceRef, pluginId)!;
|
||||
allDeps.push(target.then(impl => [name, impl]));
|
||||
}
|
||||
|
||||
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
||||
const target = this.get(serviceRef, pluginId)!;
|
||||
allDeps.push(target.then(impl => [name, impl]));
|
||||
}
|
||||
|
||||
result = implementation.context
|
||||
.then(context =>
|
||||
Promise.all(allDeps).then(entries =>
|
||||
factory.factory(Object.fromEntries(entries), context),
|
||||
),
|
||||
)
|
||||
.catch(error => {
|
||||
const cause = stringifyError(error);
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`,
|
||||
);
|
||||
});
|
||||
implementation.byPlugin.set(pluginId, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
result = implementation.context
|
||||
.then(context =>
|
||||
Promise.all(allDeps).then(entries =>
|
||||
factory.factory(Object.fromEntries(entries), context),
|
||||
),
|
||||
)
|
||||
.catch(error => {
|
||||
const cause = stringifyError(error);
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`,
|
||||
);
|
||||
});
|
||||
implementation.byPlugin.set(pluginId, result);
|
||||
}
|
||||
return result;
|
||||
}),
|
||||
);
|
||||
})
|
||||
.then(results => (ref.singleton ? results[0] : results));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const authServiceFactory: ServiceFactoryCompat<
|
||||
AuthService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ export type CacheManagerOptions = {
|
||||
export const cacheServiceFactory: ServiceFactoryCompat<
|
||||
CacheService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ export type DatabaseManagerOptions = {
|
||||
export const databaseServiceFactory: ServiceFactoryCompat<
|
||||
DatabaseService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const discoveryServiceFactory: ServiceFactoryCompat<
|
||||
DiscoveryService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const httpAuthServiceFactory: ServiceFactoryCompat<
|
||||
HttpAuthService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export function createLifecycleMiddleware(
|
||||
export const httpRouterServiceFactory: ServiceFactoryCompat<
|
||||
HttpRouterService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const lifecycleServiceFactory: ServiceFactoryCompat<
|
||||
LifecycleService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const loggerServiceFactory: ServiceFactoryCompat<
|
||||
LoggerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const permissionsServiceFactory: ServiceFactoryCompat<
|
||||
PermissionsService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ export interface RootConfigFactoryOptions {
|
||||
// @public (undocumented)
|
||||
export const rootConfigServiceFactory: ((
|
||||
options?: RootConfigFactoryOptions,
|
||||
) => ServiceFactory<RootConfigService, 'root'>) &
|
||||
ServiceFactory<RootConfigService, 'root'>;
|
||||
) => ServiceFactory<RootConfigService, 'root', true>) &
|
||||
ServiceFactory<RootConfigService, 'root', true>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const rootHealthServiceFactory: ServiceFactoryCompat<
|
||||
RootHealthService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -143,8 +143,8 @@ export type RootHttpRouterFactoryOptions = {
|
||||
// @public (undocumented)
|
||||
export const rootHttpRouterServiceFactory: ((
|
||||
options?: RootHttpRouterFactoryOptions,
|
||||
) => ServiceFactory<RootHttpRouterService, 'root'>) &
|
||||
ServiceFactory<RootHttpRouterService, 'root'>;
|
||||
) => ServiceFactory<RootHttpRouterService, 'root', true>) &
|
||||
ServiceFactory<RootHttpRouterService, 'root', true>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
|
||||
export const rootLifecycleServiceFactory: ServiceFactoryCompat<
|
||||
RootLifecycleService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { transport } from 'winston';
|
||||
export const rootLoggerServiceFactory: ServiceFactoryCompat<
|
||||
RootLoggerService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export class DefaultSchedulerService {
|
||||
export const schedulerServiceFactory: ServiceFactoryCompat<
|
||||
SchedulerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -429,6 +429,7 @@ export class UrlReaders {
|
||||
export const urlReaderServiceFactory: ServiceFactoryCompat<
|
||||
UrlReaderService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { UserInfoService } from '@backstage/backend-plugin-api';
|
||||
export const userInfoServiceFactory: ServiceFactoryCompat<
|
||||
UserInfoService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
|
||||
@@ -14,12 +14,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReaderFactory } from './lib';
|
||||
import { UrlReaders } from './lib/UrlReaders';
|
||||
import {
|
||||
coreServices,
|
||||
createServiceFactory,
|
||||
createServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* @public
|
||||
* A non-singleton reference to URL Reader factory services.
|
||||
*
|
||||
* @example
|
||||
* Creating a service factory implementation for a Custom URL Reader.
|
||||
* ```ts
|
||||
* createServiceFactory({
|
||||
* service: urlReaderProviderFactoriesServiceRef,
|
||||
* deps: {},
|
||||
* async factory() {
|
||||
* return CustomUrlReader.factory;
|
||||
* },
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export const urlReaderProviderFactoriesServiceRef =
|
||||
createServiceRef<ReaderFactory>({
|
||||
id: 'core.urlReader.factories',
|
||||
scope: 'plugin',
|
||||
singleton: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* Reading content from external systems.
|
||||
*
|
||||
@@ -34,11 +59,13 @@ export const urlReaderServiceFactory = createServiceFactory({
|
||||
deps: {
|
||||
config: coreServices.rootConfig,
|
||||
logger: coreServices.logger,
|
||||
factories: urlReaderProviderFactoriesServiceRef,
|
||||
},
|
||||
async factory({ config, logger }) {
|
||||
async factory({ config, logger, factories }) {
|
||||
return UrlReaders.default({
|
||||
config,
|
||||
logger,
|
||||
factories,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -117,6 +117,7 @@ export interface DynamicPluginsFactoryOptions {
|
||||
export const dynamicPluginsFeatureDiscoveryServiceFactory: ServiceFactoryCompat<
|
||||
FeatureDiscoveryService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -127,6 +128,7 @@ export const dynamicPluginsFrontendSchemas: BackendFeatureCompat;
|
||||
export const dynamicPluginsRootLoggerServiceFactory: ServiceFactoryCompat<
|
||||
RootLoggerService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -147,6 +149,7 @@ export interface DynamicPluginsSchemasService {
|
||||
export const dynamicPluginsSchemasServiceFactory: ServiceFactoryCompat<
|
||||
DynamicPluginsSchemasService,
|
||||
'root',
|
||||
true,
|
||||
DynamicPluginsSchemasOptions
|
||||
>;
|
||||
|
||||
@@ -154,13 +157,15 @@ export const dynamicPluginsSchemasServiceFactory: ServiceFactoryCompat<
|
||||
export const dynamicPluginsServiceFactory: ServiceFactoryCompat<
|
||||
DynamicPluginProvider,
|
||||
'root',
|
||||
true,
|
||||
DynamicPluginsFactoryOptions
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const dynamicPluginsServiceRef: ServiceRef<
|
||||
DynamicPluginProvider,
|
||||
'root'
|
||||
'root',
|
||||
true
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -17,7 +17,8 @@ export interface FeatureDiscoveryService {
|
||||
// @alpha
|
||||
export const featureDiscoveryServiceRef: ServiceRef<
|
||||
FeatureDiscoveryService,
|
||||
'root'
|
||||
'root',
|
||||
true
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace auth {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<AuthService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<AuthService, 'plugin', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<AuthService> | undefined,
|
||||
@@ -165,7 +165,7 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace cache {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<CacheService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<CacheService, 'plugin', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<CacheService> | undefined,
|
||||
@@ -174,7 +174,7 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace database {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<DatabaseService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<DatabaseService, 'plugin', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<DatabaseService> | undefined,
|
||||
@@ -185,7 +185,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace discovery {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<DiscoveryService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
DiscoveryService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<DiscoveryService> | undefined,
|
||||
@@ -194,7 +199,7 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace events {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<EventsService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<EventsService, 'plugin', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<EventsService> | undefined,
|
||||
@@ -208,8 +213,8 @@ export namespace mockServices {
|
||||
export namespace httpAuth {
|
||||
const factory: ((options?: {
|
||||
defaultCredentials?: BackstageCredentials;
|
||||
}) => ServiceFactory<HttpAuthService, 'plugin'>) &
|
||||
ServiceFactory<HttpAuthService, 'plugin'>;
|
||||
}) => ServiceFactory<HttpAuthService, 'plugin', true>) &
|
||||
ServiceFactory<HttpAuthService, 'plugin', true>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<HttpAuthService> | undefined,
|
||||
@@ -218,7 +223,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace httpRouter {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<HttpRouterService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
HttpRouterService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<HttpRouterService> | undefined,
|
||||
@@ -229,7 +239,7 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace identity {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<IdentityService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<IdentityService, 'plugin', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<IdentityService> | undefined,
|
||||
@@ -238,7 +248,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace lifecycle {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<LifecycleService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
LifecycleService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<LifecycleService> | undefined,
|
||||
@@ -247,7 +262,7 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace logger {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<LoggerService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<LoggerService, 'plugin', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<LoggerService> | undefined,
|
||||
@@ -256,7 +271,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace permissions {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<PermissionsService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
PermissionsService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<PermissionsService> | undefined,
|
||||
@@ -271,15 +291,15 @@ export namespace mockServices {
|
||||
data?: JsonObject;
|
||||
};
|
||||
const // (undocumented)
|
||||
factory: ServiceFactory<RootConfigService, 'root'> &
|
||||
factory: ServiceFactory<RootConfigService, 'root', boolean> &
|
||||
((
|
||||
options?: Options | undefined,
|
||||
) => ServiceFactory<RootConfigService, 'root'>);
|
||||
) => ServiceFactory<RootConfigService, 'root', boolean>);
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace rootHealth {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<RootHealthService, 'root', undefined>;
|
||||
factory: ServiceFactoryCompat<RootHealthService, 'root', true, undefined>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<RootHealthService> | undefined,
|
||||
@@ -290,8 +310,8 @@ export namespace mockServices {
|
||||
const // (undocumented)
|
||||
factory: ((
|
||||
options?: RootHttpRouterFactoryOptions | undefined,
|
||||
) => ServiceFactory<RootHttpRouterService, 'root'>) &
|
||||
ServiceFactory<RootHttpRouterService, 'root'>;
|
||||
) => ServiceFactory<RootHttpRouterService, 'root', true>) &
|
||||
ServiceFactory<RootHttpRouterService, 'root', true>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<RootHttpRouterService> | undefined,
|
||||
@@ -300,7 +320,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace rootLifecycle {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<RootLifecycleService, 'root', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
RootLifecycleService,
|
||||
'root',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<RootLifecycleService> | undefined,
|
||||
@@ -315,10 +340,10 @@ export namespace mockServices {
|
||||
level?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
||||
};
|
||||
const // (undocumented)
|
||||
factory: ServiceFactory<LoggerService, 'root'> &
|
||||
factory: ServiceFactory<LoggerService, 'root', boolean> &
|
||||
((
|
||||
options?: Options | undefined,
|
||||
) => ServiceFactory<LoggerService, 'root'>);
|
||||
) => ServiceFactory<LoggerService, 'root', boolean>);
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<RootLoggerService> | undefined,
|
||||
@@ -327,7 +352,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace scheduler {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<SchedulerService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
SchedulerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<SchedulerService> | undefined,
|
||||
@@ -338,7 +368,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace tokenManager {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<TokenManagerService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
TokenManagerService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<TokenManagerService> | undefined,
|
||||
@@ -347,7 +382,12 @@ export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace urlReader {
|
||||
const // (undocumented)
|
||||
factory: ServiceFactoryCompat<UrlReaderService, 'plugin', undefined>;
|
||||
factory: ServiceFactoryCompat<
|
||||
UrlReaderService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<UrlReaderService> | undefined,
|
||||
@@ -358,7 +398,12 @@ export namespace mockServices {
|
||||
): UserInfoService;
|
||||
// (undocumented)
|
||||
export namespace userInfo {
|
||||
const factory: ServiceFactoryCompat<UserInfoService, 'plugin', undefined>;
|
||||
const factory: ServiceFactoryCompat<
|
||||
UserInfoService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<UserInfoService> | undefined,
|
||||
@@ -374,22 +419,34 @@ export function registerMswTestHooks(worker: {
|
||||
}): void;
|
||||
|
||||
// @public
|
||||
export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
static from<TService, TScope extends 'root' | 'plugin'>(
|
||||
subject: ServiceFactory<TService, TScope>,
|
||||
export class ServiceFactoryTester<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
TSingleton extends boolean = true,
|
||||
> {
|
||||
static from<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
TSingleton extends boolean = true,
|
||||
>(
|
||||
subject: ServiceFactory<TService, TScope, TSingleton>,
|
||||
options?: ServiceFactoryTesterOptions,
|
||||
): ServiceFactoryTester<TService, TScope>;
|
||||
): ServiceFactoryTester<TService, TScope, TSingleton>;
|
||||
// @deprecated
|
||||
get(
|
||||
...args: 'root' extends TScope ? [] : [pluginId?: string]
|
||||
): Promise<TService>;
|
||||
getService<TGetService, TGetScope extends 'root' | 'plugin'>(
|
||||
service: ServiceRef<TGetService, TGetScope>,
|
||||
): Promise<TSingleton extends true ? TService : TService[]>;
|
||||
getService<
|
||||
TGetService,
|
||||
TGetScope extends 'root' | 'plugin',
|
||||
TGetSingleton extends boolean,
|
||||
>(
|
||||
service: ServiceRef<TGetService, TGetScope, TGetSingleton>,
|
||||
...args: 'root' extends TGetScope ? [] : [pluginId?: string]
|
||||
): Promise<TGetService>;
|
||||
): Promise<TGetSingleton extends true ? TGetService : TGetService[]>;
|
||||
getSubject(
|
||||
...args: 'root' extends TScope ? [] : [pluginId?: string]
|
||||
): Promise<TService>;
|
||||
): Promise<TSingleton extends true ? TService : TService[]>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -43,8 +43,12 @@ export interface ServiceFactoryTesterOptions {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
readonly #subject: ServiceRef<TService, TScope>;
|
||||
export class ServiceFactoryTester<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
TSingleton extends boolean = true,
|
||||
> {
|
||||
readonly #subject: ServiceRef<TService, TScope, TSingleton>;
|
||||
readonly #registry: ServiceRegistry;
|
||||
|
||||
/**
|
||||
@@ -54,10 +58,14 @@ export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
* @param options - Additional options
|
||||
* @returns A new tester instance for the provided subject.
|
||||
*/
|
||||
static from<TService, TScope extends 'root' | 'plugin'>(
|
||||
subject: ServiceFactory<TService, TScope>,
|
||||
static from<
|
||||
TService,
|
||||
TScope extends 'root' | 'plugin',
|
||||
TSingleton extends boolean = true,
|
||||
>(
|
||||
subject: ServiceFactory<TService, TScope, TSingleton>,
|
||||
options?: ServiceFactoryTesterOptions,
|
||||
) {
|
||||
): ServiceFactoryTester<TService, TScope, TSingleton> {
|
||||
const registry = ServiceRegistry.create([
|
||||
...defaultServiceFactories,
|
||||
...(options?.dependencies ?? []),
|
||||
@@ -67,7 +75,7 @@ export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
}
|
||||
|
||||
private constructor(
|
||||
subject: ServiceRef<TService, TScope>,
|
||||
subject: ServiceRef<TService, TScope, TSingleton>,
|
||||
registry: ServiceRegistry,
|
||||
) {
|
||||
this.#subject = subject;
|
||||
@@ -81,7 +89,7 @@ export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
*/
|
||||
async get(
|
||||
...args: 'root' extends TScope ? [] : [pluginId?: string]
|
||||
): Promise<TService> {
|
||||
): Promise<TSingleton extends true ? TService : TService[]> {
|
||||
return this.getSubject(...args);
|
||||
}
|
||||
|
||||
@@ -97,9 +105,10 @@ export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
*/
|
||||
async getSubject(
|
||||
...args: 'root' extends TScope ? [] : [pluginId?: string]
|
||||
): Promise<TService> {
|
||||
): Promise<TSingleton extends true ? TService : TService[]> {
|
||||
const [pluginId] = args;
|
||||
return this.#registry.get(this.#subject, pluginId ?? 'test')!;
|
||||
const instance = this.#registry.get(this.#subject, pluginId ?? 'test')!;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,10 +118,14 @@ export class ServiceFactoryTester<TService, TScope extends 'root' | 'plugin'> {
|
||||
*
|
||||
* A plugin ID can optionally be provided for plugin scoped services, otherwise the plugin ID 'test' is used.
|
||||
*/
|
||||
async getService<TGetService, TGetScope extends 'root' | 'plugin'>(
|
||||
service: ServiceRef<TGetService, TGetScope>,
|
||||
async getService<
|
||||
TGetService,
|
||||
TGetScope extends 'root' | 'plugin',
|
||||
TGetSingleton extends boolean,
|
||||
>(
|
||||
service: ServiceRef<TGetService, TGetScope, TGetSingleton>,
|
||||
...args: 'root' extends TGetScope ? [] : [pluginId?: string]
|
||||
): Promise<TGetService> {
|
||||
): Promise<TGetSingleton extends true ? TGetService : TGetService[]> {
|
||||
const [pluginId] = args;
|
||||
const instance = await this.#registry.get(service, pluginId ?? 'test');
|
||||
if (instance === undefined) {
|
||||
|
||||
@@ -88,7 +88,7 @@ export interface CatalogProcessingExtensionPoint {
|
||||
export const catalogProcessingExtensionPoint: ExtensionPoint<CatalogProcessingExtensionPoint>;
|
||||
|
||||
// @alpha
|
||||
export const catalogServiceRef: ServiceRef<CatalogApi, 'plugin'>;
|
||||
export const catalogServiceRef: ServiceRef<CatalogApi, 'plugin', true>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -66,11 +66,12 @@ export type EventsServiceEventHandler = (params: EventParams) => Promise<void>;
|
||||
export const eventsServiceFactory: ServiceFactoryCompat<
|
||||
EventsService,
|
||||
'plugin',
|
||||
true,
|
||||
undefined
|
||||
>;
|
||||
|
||||
// @public
|
||||
export const eventsServiceRef: ServiceRef<EventsService, 'plugin'>;
|
||||
export const eventsServiceRef: ServiceRef<EventsService, 'plugin', true>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type EventsServiceSubscribeOptions = {
|
||||
|
||||
@@ -65,7 +65,11 @@ export interface NotificationService {
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const notificationService: ServiceRef<NotificationService, 'plugin'>;
|
||||
export const notificationService: ServiceRef<
|
||||
NotificationService,
|
||||
'plugin',
|
||||
true
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type NotificationServiceOptions = {
|
||||
|
||||
@@ -46,7 +46,11 @@ export type SearchIndexServiceInitOptions = {
|
||||
};
|
||||
|
||||
// @alpha
|
||||
export const searchIndexServiceRef: ServiceRef<SearchIndexService, 'plugin'>;
|
||||
export const searchIndexServiceRef: ServiceRef<
|
||||
SearchIndexService,
|
||||
'plugin',
|
||||
true
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -37,7 +37,7 @@ export type SignalPayload<TMessage extends JsonObject = JsonObject> = {
|
||||
export interface SignalService extends SignalsService {}
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export const signalService: ServiceRef<SignalsService, 'plugin'>;
|
||||
export const signalService: ServiceRef<SignalsService, 'plugin', true>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SignalsService {
|
||||
@@ -52,7 +52,7 @@ export type SignalsServiceOptions = {
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const signalsServiceRef: ServiceRef<SignalsService, 'plugin'>;
|
||||
export const signalsServiceRef: ServiceRef<SignalsService, 'plugin', true>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user