remove service compat too

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2024-08-15 16:46:19 +02:00
parent d425fc4dfd
commit 9080f57970
57 changed files with 381 additions and 946 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-dynamic-feature-service': minor
---
**BREAKING**: `dynamicPluginsServiceFactory` is no longer callable as a function. If you need to provide options to make a custom factory, use `dynamicPluginsSchemasServiceFactoryWithOptions` instead.
+23 -24
View File
@@ -1,38 +1,37 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
'@backstage/plugin-catalog-backend-module-bitbucket-server': patch
'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch
'@backstage/plugin-events-backend-module-bitbucket-cloud': patch
'@backstage/plugin-search-backend-module-elasticsearch': patch
'@backstage/backend-common': patch
'@backstage/backend-dynamic-feature-service': patch
'@backstage/plugin-catalog-backend-module-puppetdb': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-search-backend-module-techdocs': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-catalog-backend-module-aws': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch
'@backstage/plugin-catalog-backend-module-bitbucket-server': patch
'@backstage/plugin-catalog-backend-module-gerrit': patch
'@backstage/plugin-catalog-backend-module-github': patch
'@backstage/plugin-catalog-backend-module-gitlab': patch
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-catalog-backend-module-puppetdb': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-events-backend-module-aws-sqs': patch
'@backstage/plugin-search-backend-module-catalog': patch
'@backstage/plugin-search-backend-module-explore': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-events-backend-module-azure': patch
'@backstage/plugin-events-backend-module-bitbucket-cloud': patch
'@backstage/plugin-events-backend-module-gerrit': patch
'@backstage/plugin-events-backend-module-github': patch
'@backstage/plugin-events-backend-module-gitlab': patch
'@backstage/plugin-events-backend-module-azure': patch
'@backstage/plugin-catalog-backend-module-aws': patch
'@backstage/plugin-search-backend-module-pg': patch
'@backstage/plugin-user-settings-backend': patch
'@backstage/plugin-events-backend': patch
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-permission-backend': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/backend-app-api': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/backend-common': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-events-backend': patch
'@backstage/plugin-search-backend': patch
'@backstage/plugin-proxy-backend': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-search-backend-module-catalog': patch
'@backstage/plugin-search-backend-module-elasticsearch': patch
'@backstage/plugin-search-backend-module-explore': patch
'@backstage/plugin-search-backend-module-pg': patch
'@backstage/plugin-search-backend-module-techdocs': patch
'@backstage/plugin-search-backend': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-user-settings-backend': patch
---
Modules and plugins are now `BackendFeature`, not a function that returns a feature.
Modules, plugins, and services are now `BackendFeature`, not a function that returns a feature.
+28 -21
View File
@@ -1,56 +1,63 @@
---
'@backstage/backend-app-api': minor
'@backstage/backend-common': minor
'@backstage/backend-defaults': minor
'@backstage/backend-plugin-api': minor
'@backstage/backend-test-utils': minor
'@backstage/plugin-auth-backend-module-atlassian-provider': minor
'@backstage/plugin-auth-backend-module-cloudflare-access-provider': minor
'@backstage/plugin-auth-backend-module-azure-easyauth-provider': minor
'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': minor
'@backstage/plugin-auth-backend-module-vmware-cloud-provider': minor
'@backstage/plugin-auth-backend-module-bitbucket-provider': minor
'@backstage/plugin-auth-backend-module-microsoft-provider': minor
'@backstage/plugin-auth-backend-module-onelogin-provider': minor
'@backstage/plugin-auth-backend-module-pinniped-provider': minor
'@backstage/plugin-auth-backend-module-aws-alb-provider': minor
'@backstage/plugin-auth-backend-module-azure-easyauth-provider': minor
'@backstage/plugin-auth-backend-module-bitbucket-provider': minor
'@backstage/plugin-auth-backend-module-cloudflare-access-provider': minor
'@backstage/plugin-auth-backend-module-gcp-iap-provider': minor
'@backstage/plugin-auth-backend-module-github-provider': minor
'@backstage/plugin-auth-backend-module-gitlab-provider': minor
'@backstage/plugin-auth-backend-module-google-provider': minor
'@backstage/plugin-auth-backend-module-oauth2-provider': minor
'@backstage/plugin-auth-backend-module-guest-provider': minor
'@backstage/plugin-auth-backend-module-microsoft-provider': minor
'@backstage/plugin-auth-backend-module-oauth2-provider': minor
'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': minor
'@backstage/plugin-auth-backend-module-oidc-provider': minor
'@backstage/plugin-auth-backend-module-okta-provider': minor
'@backstage/plugin-auth-backend-module-onelogin-provider': minor
'@backstage/plugin-auth-backend-module-pinniped-provider': minor
'@backstage/plugin-auth-backend-module-vmware-cloud-provider': minor
'@backstage/plugin-auth-backend': minor
'@backstage/plugin-catalog-backend-module-openapi': minor
'@backstage/plugin-catalog-backend-module-backstage-openapi': minor
'@backstage/plugin-catalog-backend-module-gcp': minor
'@backstage/plugin-catalog-backend-module-github-org': minor
'@backstage/plugin-catalog-backend-module-gitlab-org': minor
'@backstage/plugin-catalog-backend-module-ldap': minor
'@backstage/plugin-catalog-backend-module-logs': minor
'@backstage/plugin-catalog-backend-module-backstage-openapi': minor
'@backstage/plugin-catalog-backend-module-openapi': minor
'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': minor
'@backstage/plugin-catalog-backend-module-unprocessed': minor
'@backstage/plugin-devtools-backend': minor
'@backstage/plugin-events-node': minor
'@backstage/plugin-notifications-backend-module-email': minor
'@backstage/plugin-notifications-backend': minor
'@backstage/plugin-permission-backend-module-allow-all-policy': minor
'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': minor
'@backstage/plugin-scaffolder-backend-module-bitbucket-server': minor
'@backstage/plugin-scaffolder-backend-module-azure': minor
'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': minor
'@backstage/plugin-scaffolder-backend-module-notifications': minor
'@backstage/plugin-scaffolder-backend-module-cookiecutter': minor
'@backstage/plugin-scaffolder-backend-module-bitbucket-server': minor
'@backstage/plugin-scaffolder-backend-module-bitbucket': minor
'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': minor
'@backstage/plugin-scaffolder-backend-module-cookiecutter': minor
'@backstage/plugin-scaffolder-backend-module-gcp': minor
'@backstage/plugin-scaffolder-backend-module-gerrit': minor
'@backstage/plugin-scaffolder-backend-module-gitea': minor
'@backstage/plugin-scaffolder-backend-module-github': minor
'@backstage/plugin-scaffolder-backend-module-gitlab': minor
'@backstage/plugin-scaffolder-backend-module-notifications': minor
'@backstage/plugin-scaffolder-backend-module-rails': minor
'@backstage/plugin-scaffolder-backend-module-sentry': minor
'@backstage/plugin-scaffolder-backend-module-yeoman': minor
'@backstage/plugin-scaffolder-backend-module-azure': minor
'@backstage/plugin-scaffolder-backend-module-gitea': minor
'@backstage/plugin-scaffolder-backend-module-rails': minor
'@backstage/plugin-scaffolder-backend-module-gcp': minor
'@backstage/plugin-search-backend-module-stack-overflow-collator': minor
'@backstage/plugin-signals-backend': minor
---
**BREAKING**: The return values from `createBackendPlugin` and `createBackendModule` are now simply `BackendFeature`, instead of the previously deprecated form of a function that returns a feature.
**BREAKING**: The return values from `createBackendPlugin`, `createBackendModule`, and `createServiceFactory` are now simply `BackendFeature` and `ServiceFactory`, instead of the previously deprecated form of a function that returns them. For this reason, `createServiceFactory` also no longer accepts the callback form where you provide direct options to the service. This also affects all `coreServices.*` service refs.
This may in particular affect tests; if you were effectively doing `createBackendModule({...})()` (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your `packages/backend/src/index.ts` too, where you add plugins and modules.
This may in particular affect tests; if you were effectively doing `createBackendModule({...})()` (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your `packages/backend/src/index.ts` too, where you add plugins, modules, and services. If you were using `createServiceFactory` with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the `IdentityFactoryOptions` and `RootConfigFactoryOptions` types were removed, and can no longer be used to tweak those services. The identity service was also deprecated some time ago, and you will want to [migrate to the new auth system](https://backstage.io/docs/tutorials/auth-service-migration) if you still rely on it.
+3 -4
View File
@@ -4,14 +4,13 @@
```ts
import { FeatureDiscoveryService } from '@backstage/backend-plugin-api/alpha';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @alpha (undocumented)
export const featureDiscoveryServiceFactory: ServiceFactoryCompat<
export const featureDiscoveryServiceFactory: ServiceFactory<
FeatureDiscoveryService,
'root',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
+4 -13
View File
@@ -6,7 +6,6 @@
import { BackendFeature } from '@backstage/backend-plugin-api';
import { IdentityService } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { TokenManagerService } from '@backstage/backend-plugin-api';
// @public (undocumented)
@@ -36,25 +35,17 @@ export interface CreateSpecializedBackendOptions {
defaultServiceFactories: ServiceFactory[];
}
// @public @deprecated
export type IdentityFactoryOptions = {
issuer?: string;
algorithms?: string[];
};
// @public @deprecated (undocumented)
export const identityServiceFactory: ServiceFactoryCompat<
export const identityServiceFactory: ServiceFactory<
IdentityService,
'plugin',
'singleton',
IdentityFactoryOptions
'singleton'
>;
// @public @deprecated (undocumented)
export const tokenManagerServiceFactory: ServiceFactoryCompat<
export const tokenManagerServiceFactory: ServiceFactory<
TokenManagerService,
'plugin',
'singleton',
undefined
'singleton'
>;
```
@@ -147,7 +147,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: { backend: { packages: 'all' } },
}),
@@ -166,7 +166,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: {
backend: {
@@ -195,7 +195,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: {
backend: {
@@ -220,7 +220,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: {
backend: {
@@ -245,7 +245,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: {
backend: {
@@ -270,7 +270,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: {
backend: {
@@ -300,7 +300,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: { backend: { packages: {} } },
}),
@@ -316,7 +316,7 @@ describe('featureDiscoveryServiceFactory', () => {
await startTestBackend({
features: [
mock.factory,
featureDiscoveryServiceFactory(),
featureDiscoveryServiceFactory,
mockServices.rootConfig.factory({
data: { backend: {} },
}),
@@ -21,33 +21,15 @@ import {
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
/**
* An identity client options object which allows extra configurations
*
* @public
* @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead
*/
export type IdentityFactoryOptions = {
issuer?: string;
/**
* JWS "alg" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.
* More info on supported algorithms: https://github.com/panva/jose
*/
algorithms?: string[];
};
/**
* @public
* @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead
*/
export const identityServiceFactory = createServiceFactory(
(options?: IdentityFactoryOptions) => ({
service: coreServices.identity,
deps: {
discovery: coreServices.discovery,
},
async factory({ discovery }) {
return DefaultIdentityClient.create({ discovery, ...options });
},
}),
);
export const identityServiceFactory = createServiceFactory({
service: coreServices.identity,
deps: {
discovery: coreServices.discovery,
},
async factory({ discovery }) {
return DefaultIdentityClient.create({ discovery });
},
});
@@ -15,4 +15,3 @@
*/
export { identityServiceFactory } from './identityServiceFactory';
export type { IdentityFactoryOptions } from './identityServiceFactory';
@@ -39,14 +39,14 @@ class MockLogger {
}
const baseFactories = [
lifecycleServiceFactory(),
rootLifecycleServiceFactory(),
lifecycleServiceFactory,
rootLifecycleServiceFactory,
createServiceFactory({
service: coreServices.rootLogger,
deps: {},
factory: () => new MockLogger(),
})(),
loggerServiceFactory(),
}),
loggerServiceFactory,
];
const testPlugin = createBackendPlugin({
@@ -84,18 +84,18 @@ describe('BackendInitializer', () => {
initialization: 'always',
deps: {},
factory: factory1,
})(),
}),
createServiceFactory({
service: ref2,
deps: {},
factory: factory2,
})(),
}),
createServiceFactory({
service: ref3,
initialization: 'lazy',
deps: {},
factory: factory3,
})(),
}),
];
const init = new BackendInitializer(services);
@@ -249,18 +249,18 @@ describe('BackendInitializer', () => {
initialization: 'always',
deps: {},
factory: factory1,
})(),
}),
createServiceFactory({
service: ref2,
deps: {},
factory: factory2,
})(),
}),
createServiceFactory({
service: ref3,
initialization: 'lazy',
deps: {},
factory: factory3,
})(),
}),
];
const init = new BackendInitializer(services);
@@ -505,12 +505,12 @@ describe('BackendInitializer', () => {
const extA = createExtensionPoint<string>({ id: 'a' });
const extB = createExtensionPoint<string>({ id: 'b' });
const init = new BackendInitializer([
rootLifecycleServiceFactory(),
rootLifecycleServiceFactory,
createServiceFactory({
service: coreServices.rootLogger,
deps: {},
factory: () => new MockLogger(),
})(),
}),
]);
init.add(testPlugin);
init.add(
@@ -95,7 +95,7 @@ describe('ServiceRegistry', () => {
});
it('should return an implementation for a registered ref', async () => {
const registry = ServiceRegistry.create([sf1()]);
const registry = ServiceRegistry.create([sf1]);
await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 1 });
await expect(registry.get(ref1, 'scaffolder')).resolves.toEqual({ x: 1 });
expect(await registry.get(ref1, 'catalog')).toBe(
@@ -110,7 +110,7 @@ describe('ServiceRegistry', () => {
});
it('should handle multiple factories with different serviceRefs', async () => {
const registry = ServiceRegistry.create([sf1(), sf2()]);
const registry = ServiceRegistry.create([sf1, sf2]);
await expect(registry.get(ref1, 'catalog')).resolves.toEqual({
x: 1,
@@ -124,15 +124,15 @@ describe('ServiceRegistry', () => {
});
it('should not be possible for root scoped services to depend on plugin scoped services', async () => {
// @ts-expect-error
const factory = createServiceFactory({
// @ts-expect-error
service: ref2,
deps: { pluginDep: ref1 },
async factory() {
return { x: 2 };
},
});
const registry = ServiceRegistry.create([factory(), sf1()]);
const registry = ServiceRegistry.create([factory, sf1]);
await expect(registry.get(ref2, 'catalog')).rejects.toThrow(
"Failed to instantiate 'root' scoped service '2' because it depends on 'plugin' scoped service '1'.",
);
@@ -146,7 +146,7 @@ describe('ServiceRegistry', () => {
return { x: rootDep.x };
},
});
const registry = ServiceRegistry.create([factory(), sf2()]);
const registry = ServiceRegistry.create([factory, sf2]);
await expect(registry.get(ref1, 'catalog')).resolves.toEqual({
x: 2,
});
@@ -161,7 +161,7 @@ describe('ServiceRegistry', () => {
return { x: rootDep.x };
},
});
const registry = ServiceRegistry.create([factory(), sf2()]);
const registry = ServiceRegistry.create([factory, sf2]);
await expect(registry.get(ref, 'catalog')).resolves.toEqual({
x: 2,
});
@@ -176,41 +176,41 @@ describe('ServiceRegistry', () => {
return { pluginId: meta.getId() };
},
});
const registry = ServiceRegistry.create([factory()]);
const registry = ServiceRegistry.create([factory]);
await expect(registry.get(ref, 'catalog')).resolves.toEqual({
pluginId: 'catalog',
});
});
it('should use the last factory for each ref', async () => {
const registry = ServiceRegistry.create([sf2(), sf2b()]);
const registry = ServiceRegistry.create([sf2, sf2b]);
await expect(registry.get(ref2, 'catalog')).resolves.toEqual({
x: 22,
});
});
it('should use added service factories for each ref', async () => {
const registry = ServiceRegistry.create([sf2()]);
registry.add(sf2b());
const registry = ServiceRegistry.create([sf2]);
registry.add(sf2b);
await expect(registry.get(ref2, 'catalog')).resolves.toEqual({
x: 22,
});
});
it('should not allow factories to be added after instantiation', async () => {
const registry = ServiceRegistry.create([sf2()]);
const registry = ServiceRegistry.create([sf2]);
await expect(registry.get(ref2, 'catalog')).resolves.toEqual({
x: 2,
});
expect(() => registry.add(sf2b())).toThrow(
expect(() => registry.add(sf2b)).toThrow(
'Unable to set service factory with id 2, service has already been instantiated',
);
});
it('should not allow the same factory to be added twice', async () => {
const registry = ServiceRegistry.create([sf2()]);
registry.add(sf2b());
expect(() => registry.add(sf2b())).toThrow(
const registry = ServiceRegistry.create([sf2]);
registry.add(sf2b);
expect(() => registry.add(sf2b)).toThrow(
'Duplicate service implementations provided for 2',
);
});
@@ -223,7 +223,7 @@ describe('ServiceRegistry', () => {
});
it('should not use the defaultFactory from the ref if provided to the registry', async () => {
const registry = ServiceRegistry.create([sf1()]);
const registry = ServiceRegistry.create([sf1]);
await expect(registry.get(refDefault1, 'catalog')).resolves.toEqual({
x: 1,
});
@@ -279,7 +279,7 @@ describe('ServiceRegistry', () => {
factory,
});
const registry = ServiceRegistry.create([myFactory()]);
const registry = ServiceRegistry.create([myFactory]);
await Promise.all([
registry.get(ref1, 'catalog')!,
@@ -301,7 +301,7 @@ describe('ServiceRegistry', () => {
factory,
});
const registry = ServiceRegistry.create([myFactory()]);
const registry = ServiceRegistry.create([myFactory]);
await Promise.all([
registry.get(ref1, 'catalog')!,
@@ -323,7 +323,7 @@ describe('ServiceRegistry', () => {
},
});
const registry = ServiceRegistry.create([myFactory()]);
const registry = ServiceRegistry.create([myFactory]);
await expect(registry.get(ref1, 'catalog')).rejects.toThrow(
"Failed to instantiate service '1' for 'catalog' because the following dependent services are missing: '2'",
@@ -350,7 +350,7 @@ describe('ServiceRegistry', () => {
},
});
const registry = ServiceRegistry.create([factoryA(), factoryB()]);
const registry = ServiceRegistry.create([factoryA, factoryB]);
await expect(registry.get(refA, 'catalog')).rejects.toThrow(
"Failed to instantiate service 'a' for 'catalog' because the factory function threw an error, Error: Failed to instantiate service 'b' for 'catalog' because the following dependent services are missing: 'c', 'd'",
@@ -374,7 +374,7 @@ describe('ServiceRegistry', () => {
factory: async ({ a }) => a,
});
expect(() => ServiceRegistry.create([factoryA(), factoryB()])).toThrow(
expect(() => ServiceRegistry.create([factoryA, factoryB])).toThrow(
`Circular dependencies detected:
'a' -> 'b' -> 'a'`,
);
@@ -411,12 +411,7 @@ describe('ServiceRegistry', () => {
});
expect(() =>
ServiceRegistry.create([
factoryA(),
factoryB(),
factoryC(),
factoryD(),
]),
ServiceRegistry.create([factoryA, factoryB, factoryC, factoryD]),
).toThrow(
`Circular dependencies detected:
'a' -> 'b' -> 'a'
@@ -448,7 +443,7 @@ describe('ServiceRegistry', () => {
});
expect(() =>
ServiceRegistry.create([factoryA(), factoryB(), factoryC()]),
ServiceRegistry.create([factoryA, factoryB, factoryC]),
).toThrow(
`Circular dependencies detected:
'a' -> 'b' -> 'c' -> 'a'`,
@@ -486,12 +481,7 @@ describe('ServiceRegistry', () => {
});
expect(() =>
ServiceRegistry.create([
factoryA(),
factoryB(),
factoryC(),
factoryD(),
]),
ServiceRegistry.create([factoryA, factoryB, factoryC, factoryD]),
).toThrow(
`Circular dependencies detected:
'a' -> 'b' -> 'c' -> 'a'`,
@@ -522,7 +512,7 @@ describe('ServiceRegistry', () => {
});
expect(() =>
ServiceRegistry.create([factoryA(), factoryB(), factoryC()]),
ServiceRegistry.create([factoryA, factoryB, factoryC]),
).toThrow(
`Circular dependencies detected:
'a' -> 'c' -> 'a'`,
@@ -553,7 +543,7 @@ describe('ServiceRegistry', () => {
});
expect(() =>
ServiceRegistry.create([factoryA(), factoryB(), factoryC()]),
ServiceRegistry.create([factoryA, factoryB, factoryC]),
).toThrow(
`Circular dependencies detected:
'b' -> 'c' -> 'b'`,
@@ -573,7 +563,7 @@ describe('ServiceRegistry', () => {
},
});
const registry = ServiceRegistry.create([myFactory()]);
const registry = ServiceRegistry.create([myFactory]);
await expect(registry.get(ref1, 'catalog')).rejects.toThrow(
"Failed to instantiate service '1' because createRootContext threw an error, Error: top-level error",
@@ -589,7 +579,7 @@ describe('ServiceRegistry', () => {
},
});
const registry = ServiceRegistry.create([myFactory()]);
const registry = ServiceRegistry.create([myFactory]);
await expect(registry.get(ref1, 'catalog')).rejects.toThrow(
"Failed to instantiate service '1' for 'catalog' because the factory function threw an error, Error: error in plugin",
+3 -3
View File
@@ -9,7 +9,7 @@
import { AppConfig } from '@backstage/config';
import { AuthCallback } from 'isomorphic-git';
import { AuthService } from '@backstage/backend-plugin-api';
import { BackendFeatureCompat } from '@backstage/backend-plugin-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
import { CacheService } from '@backstage/backend-plugin-api';
import { CacheServiceOptions } from '@backstage/backend-plugin-api';
import { CacheServiceSetOptions } from '@backstage/backend-plugin-api';
@@ -348,7 +348,7 @@ export const legacyPlugin: (
>
>;
}>,
) => BackendFeatureCompat;
) => BackendFeature;
// Warning: (ae-forgotten-export) The symbol "LegacyRootDatabaseService_2" needs to be exported by the entry point index.d.ts
//
@@ -386,7 +386,7 @@ export function makeLegacyPlugin<
createRouterImport: Promise<{
default: LegacyCreateRouter<TransformedEnv<TEnv, TEnvTransforms>>;
}>,
) => BackendFeatureCompat;
) => BackendFeature;
// @public @deprecated
export function notFoundHandler(): RequestHandler;
+3 -4
View File
@@ -4,14 +4,13 @@
```ts
import { AuthService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const authServiceFactory: ServiceFactoryCompat<
export const authServiceFactory: ServiceFactory<
AuthService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -7,7 +7,7 @@ import { CacheService } from '@backstage/backend-plugin-api';
import { CacheServiceOptions } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
import { LoggerService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export class CacheManager {
@@ -25,11 +25,10 @@ export type CacheManagerOptions = {
};
// @public
export const cacheServiceFactory: ServiceFactoryCompat<
export const cacheServiceFactory: ServiceFactory<
CacheService,
'plugin',
'singleton',
undefined
'singleton'
>;
// @public (undocumented)
@@ -8,7 +8,7 @@ import { DatabaseService } from '@backstage/backend-plugin-api';
import { LifecycleService } from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { PluginMetadataService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export class DatabaseManager implements LegacyRootDatabaseService {
@@ -32,11 +32,10 @@ export type DatabaseManagerOptions = {
};
// @public
export const databaseServiceFactory: ServiceFactoryCompat<
export const databaseServiceFactory: ServiceFactory<
DatabaseService,
'plugin',
'singleton',
undefined
'singleton'
>;
// @public @deprecated
@@ -5,14 +5,13 @@
```ts
import { Config } from '@backstage/config';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const discoveryServiceFactory: ServiceFactoryCompat<
export const discoveryServiceFactory: ServiceFactory<
DiscoveryService,
'plugin',
'singleton',
undefined
'singleton'
>;
// @public
@@ -4,14 +4,13 @@
```ts
import { HttpAuthService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const httpAuthServiceFactory: ServiceFactoryCompat<
export const httpAuthServiceFactory: ServiceFactory<
HttpAuthService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -7,7 +7,7 @@ import { HttpRouterService } from '@backstage/backend-plugin-api';
import { HumanDuration } from '@backstage/types';
import { LifecycleService } from '@backstage/backend-plugin-api';
import { RequestHandler } from 'express';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export function createLifecycleMiddleware(
@@ -15,11 +15,10 @@ export function createLifecycleMiddleware(
): RequestHandler;
// @public
export const httpRouterServiceFactory: ServiceFactoryCompat<
export const httpRouterServiceFactory: ServiceFactory<
HttpRouterService,
'plugin',
'singleton',
undefined
'singleton'
>;
// @public
@@ -4,14 +4,13 @@
```ts
import { LifecycleService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const lifecycleServiceFactory: ServiceFactoryCompat<
export const lifecycleServiceFactory: ServiceFactory<
LifecycleService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -4,14 +4,13 @@
```ts
import { LoggerService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const loggerServiceFactory: ServiceFactoryCompat<
export const loggerServiceFactory: ServiceFactory<
LoggerService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -4,14 +4,13 @@
```ts
import { PermissionsService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const permissionsServiceFactory: ServiceFactoryCompat<
export const permissionsServiceFactory: ServiceFactory<
PermissionsService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -4,14 +4,13 @@
```ts
import { RootHealthService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public (undocumented)
export const rootHealthServiceFactory: ServiceFactoryCompat<
export const rootHealthServiceFactory: ServiceFactory<
RootHealthService,
'root',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -4,14 +4,13 @@
```ts
import { RootLifecycleService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export const rootLifecycleServiceFactory: ServiceFactoryCompat<
export const rootLifecycleServiceFactory: ServiceFactory<
RootLifecycleService,
'root',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -7,15 +7,14 @@ import { Format } from 'logform';
import { JsonObject } from '@backstage/types';
import { LoggerService } from '@backstage/backend-plugin-api';
import { RootLoggerService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { transport } from 'winston';
// @public
export const rootLoggerServiceFactory: ServiceFactoryCompat<
export const rootLoggerServiceFactory: ServiceFactory<
RootLoggerService,
'root',
'singleton',
undefined
'singleton'
>;
// @public
@@ -6,7 +6,7 @@
import { DatabaseService } from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { SchedulerService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public
export class DefaultSchedulerService {
@@ -18,11 +18,10 @@ export class DefaultSchedulerService {
}
// @public
export const schedulerServiceFactory: ServiceFactoryCompat<
export const schedulerServiceFactory: ServiceFactory<
SchedulerService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -21,7 +21,7 @@ import { GitLabIntegration } from '@backstage/integration';
import { HarnessIntegration } from '@backstage/integration';
import { LoggerService } from '@backstage/backend-plugin-api';
import { Readable } from 'stream';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
import { UrlReaderService } from '@backstage/backend-plugin-api';
import { UrlReaderServiceReadTreeOptions } from '@backstage/backend-plugin-api';
@@ -434,11 +434,10 @@ export class UrlReaders {
}
// @public
export const urlReaderServiceFactory: ServiceFactoryCompat<
export const urlReaderServiceFactory: ServiceFactory<
UrlReaderService,
'plugin',
'singleton',
undefined
'singleton'
>;
// @public
@@ -3,15 +3,14 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { UserInfoService } from '@backstage/backend-plugin-api';
// @public
export const userInfoServiceFactory: ServiceFactoryCompat<
export const userInfoServiceFactory: ServiceFactory<
UserInfoService,
'plugin',
'singleton',
undefined
'singleton'
>;
// (No @packageDocumentation comment for this package)
@@ -36,7 +36,7 @@ const server = setupServer();
// TODO: Ship discovery mock service in the service factory tester
const mockDeps = [
discoveryServiceFactory(),
discoveryServiceFactory,
tokenManagerServiceFactory,
mockServices.rootConfig.factory({
data: {
@@ -110,7 +110,7 @@ describe('httpRouterFactory', () => {
});
const defaultServices = [
httpRouterServiceFactory(),
httpRouterServiceFactory,
mockServices.httpAuth.factory({
defaultCredentials: mockCredentials.none(),
}),
@@ -60,7 +60,7 @@ export const rootConfigServiceFactoryWithOptions = (
console.log(`Loading config from ${source}`);
return await ConfigSources.toConfig(source);
},
})();
});
/**
* @public
@@ -123,7 +123,7 @@ const rootHttpRouterServiceFactoryWithOptions = (
return router;
},
})();
});
/** @public */
export const rootHttpRouterServiceFactory = Object.assign(
@@ -20,7 +20,7 @@ import { schedulerServiceFactory } from './schedulerServiceFactory';
describe('schedulerFactory', () => {
it('creates sidecar database features', async () => {
const tester = ServiceFactoryTester.from(schedulerServiceFactory());
const tester = ServiceFactoryTester.from(schedulerServiceFactory);
const scheduler = await tester.getSubject();
await scheduler.scheduleTask({
@@ -4,6 +4,7 @@
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { BackendFeatureCompat } from '@backstage/backend-plugin-api';
import { BackstagePackageJson } from '@backstage/cli-node';
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
import { Config } from '@backstage/config';
@@ -121,7 +122,7 @@ export const dynamicPluginsFeatureDiscoveryServiceFactory: ServiceFactoryCompat<
>;
// @public (undocumented)
export const dynamicPluginsFrontendSchemas: BackendFeature;
export const dynamicPluginsFrontendSchemas: BackendFeatureCompat;
// @public (undocumented)
export const dynamicPluginsRootLoggerServiceFactory: ServiceFactoryCompat<
@@ -34,6 +34,7 @@ export {
DynamicPluginManager,
dynamicPluginsFeatureDiscoveryServiceFactory,
dynamicPluginsServiceFactory,
dynamicPluginsServiceFactoryWithOptions,
dynamicPluginsServiceRef,
} from './plugin-manager';
@@ -16,7 +16,7 @@
import {
DynamicPluginManager,
dynamicPluginsServiceFactory,
dynamicPluginsServiceFactoryWithOptions,
} from './plugin-manager';
import {
BackendFeature,
@@ -637,7 +637,7 @@ describe('backend-dynamic-feature-service', () => {
const backend = createSpecializedBackend({
defaultServiceFactories: [
rootLifecycleServiceFactory(),
rootLifecycleServiceFactory,
createServiceFactory({
service: coreServices.rootConfig,
deps: {},
@@ -670,7 +670,7 @@ describe('backend-dynamic-feature-service', () => {
return rootLogger;
},
}),
dynamicPluginsServiceFactory({
dynamicPluginsServiceFactoryWithOptions({
moduleLoader: _ => mockedModuleLoader,
}),
],
@@ -232,8 +232,10 @@ export interface DynamicPluginsFactoryOptions {
/**
* @public
*/
export const dynamicPluginsServiceFactory = createServiceFactory(
(options?: DynamicPluginsFactoryOptions) => ({
export const dynamicPluginsServiceFactoryWithOptions = (
options?: DynamicPluginsFactoryOptions,
) =>
createServiceFactory({
service: dynamicPluginsServiceRef,
deps: {
config: coreServices.rootConfig,
@@ -247,8 +249,13 @@ export const dynamicPluginsServiceFactory = createServiceFactory(
moduleLoader: options?.moduleLoader?.(logger),
});
},
}),
);
});
/**
* @public
*/
export const dynamicPluginsServiceFactory =
dynamicPluginsServiceFactoryWithOptions();
class DynamicPluginsEnabledFeatureDiscoveryService
implements FeatureDiscoveryService
@@ -16,6 +16,7 @@
export {
dynamicPluginsSchemasServiceFactory,
dynamicPluginsSchemasServiceFactoryWithOptions,
type DynamicPluginsSchemasService,
type DynamicPluginsSchemasOptions,
} from './schemas';
@@ -71,8 +71,10 @@ export interface DynamicPluginsSchemasOptions {
/**
* @public
*/
export const dynamicPluginsSchemasServiceFactory = createServiceFactory(
(options?: DynamicPluginsSchemasOptions) => ({
export const dynamicPluginsSchemasServiceFactoryWithOptions = (
options?: DynamicPluginsSchemasOptions,
) =>
createServiceFactory({
service: dynamicPluginsSchemasServiceRef,
deps: {
config: coreServices.rootConfig,
@@ -137,8 +139,13 @@ export const dynamicPluginsSchemasServiceFactory = createServiceFactory(
},
};
},
}),
);
});
/**
* @public
*/
export const dynamicPluginsSchemasServiceFactory =
dynamicPluginsSchemasServiceFactoryWithOptions();
/** @internal */
async function gatherDynamicPluginsSchemas(
+2 -58
View File
@@ -291,25 +291,9 @@ export function createServiceFactory<
TDeps extends {
[name in string]: ServiceRef<unknown, 'root'>;
},
TOpts extends object | undefined = undefined,
>(
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'>;
},
TOpts extends object | undefined = undefined,
>(
options: (
options?: TOpts,
) => RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TInstances, TOpts>;
): ServiceFactory<TService, 'root', TInstances>;
// @public
export function createServiceFactory<
@@ -320,7 +304,6 @@ export function createServiceFactory<
[name in string]: ServiceRef<unknown>;
},
TContext = undefined,
TOpts extends object | undefined = undefined,
>(
options: PluginServiceFactoryOptions<
TService,
@@ -329,29 +312,7 @@ export function createServiceFactory<
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>;
},
TContext = undefined,
TOpts extends object | undefined = undefined,
>(
options: (
options?: TOpts,
) => PluginServiceFactoryOptions<
TService,
TInstances,
TContext,
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TInstances, TOpts>;
): ServiceFactory<TService, 'plugin', TInstances>;
// @public
export function createServiceRef<TService>(
@@ -671,19 +632,6 @@ export interface ServiceFactory<
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, TInstances> {
// @deprecated (undocumented)
(
...options: undefined extends TOpts ? [] : [options?: TOpts]
): ServiceFactory<TService, TScope, TInstances>;
}
// @public @deprecated
export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory);
@@ -710,10 +658,6 @@ export interface ServiceRefOptions<
defaultFactory?(
service: ServiceRef<TService, TScope>,
): Promise<ServiceFactory>;
// @deprecated (undocumented)
defaultFactory?(
service: ServiceRef<TService, TScope>,
): Promise<() => ServiceFactory>;
// (undocumented)
id: string;
// (undocumented)
@@ -21,6 +21,5 @@ export type {
PluginServiceFactoryOptions,
RootServiceFactoryOptions,
ServiceFactoryOrFunction,
ServiceFactoryCompat,
} from './types';
export { createServiceRef, createServiceFactory } from './types';
@@ -23,15 +23,11 @@ import {
const ref = createServiceRef<string>({ id: 'x' });
const rootDep = createServiceRef<number>({ id: 'y', scope: 'root' });
const pluginDep = createServiceRef<boolean>({ id: 'z' });
interface TestOptions {
x: number;
}
function unused(..._any: any[]) {}
describe('createServiceFactory', () => {
it('should create a sync factory', () => {
const metaFactory = createServiceFactory({
it('should create a plugin scoped factory', () => {
const factory = createServiceFactory({
service: ref,
deps: {},
createRootContext() {},
@@ -39,52 +35,26 @@ describe('createServiceFactory', () => {
return 'x';
},
});
expect(metaFactory).toEqual(expect.any(Function));
expect(metaFactory().$$type).toBe('@backstage/BackendFeature');
expect((metaFactory() as InternalServiceFactory).featureType).toBe(
'service',
);
expect(metaFactory().service).toBe(ref);
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
// @ts-expect-error
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
expect(factory.$$type).toBe('@backstage/BackendFeature');
expect((factory as InternalServiceFactory).featureType).toBe('service');
expect(factory.service).toBe(ref);
});
it('should create a sync root factory', () => {
const metaFactory = createServiceFactory({
it('should create a root scoped factory', () => {
const factory = createServiceFactory({
service: rootDep,
deps: {},
factory(_deps) {
return 0;
},
});
expect(metaFactory).toEqual(expect.any(Function));
expect(metaFactory().service).toBe(rootDep);
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
// @ts-expect-error
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
expect(factory.$$type).toBe('@backstage/BackendFeature');
expect((factory as InternalServiceFactory).featureType).toBe('service');
expect(factory.service).toBe(rootDep);
});
it('should create a factory', () => {
const metaFactory = createServiceFactory({
it('should create a plugin scoped factory with a root context', () => {
const factory = createServiceFactory({
service: ref,
deps: {},
async createRootContext() {},
@@ -92,85 +62,13 @@ describe('createServiceFactory', () => {
return 'x';
},
});
expect(metaFactory).toEqual(expect.any(Function));
expect(metaFactory().service).toBe(ref);
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
// @ts-expect-error
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
});
it('should create a factory with options', () => {
const metaFactory = createServiceFactory((_opts?: { x: number }) => ({
service: ref,
deps: {},
async createRootContext() {},
async factory() {
return 'x';
},
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory({ x: 1, y: 2 });
// @ts-expect-error
metaFactory(null);
metaFactory(undefined);
metaFactory();
});
it('should not be allowed to require options', () => {
// @ts-expect-error
const metaFactory = createServiceFactory((_opts: { x: number }) => ({
service: ref,
deps: {},
async createRootContext() {},
async factory() {
return 'x';
},
}));
expect(metaFactory).toEqual(expect.any(Function));
});
it('should create a factory with options as interface', () => {
const metaFactory = createServiceFactory((_opts?: TestOptions) => ({
service: ref,
deps: {},
async createRootContext() {},
async factory() {
return 'x';
},
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory({ x: 1, y: 2 });
// @ts-expect-error
metaFactory(null);
metaFactory(undefined);
metaFactory();
expect(factory.$$type).toBe('@backstage/BackendFeature');
expect((factory as InternalServiceFactory).featureType).toBe('service');
expect(factory.service).toBe(ref);
});
it('should create root scoped factory with dependencies', () => {
const metaFactory = createServiceFactory({
const factory = createServiceFactory({
service: createServiceRef({ id: 'foo', scope: 'root' }),
deps: {
root: rootDep,
@@ -183,48 +81,11 @@ describe('createServiceFactory', () => {
return 0;
},
});
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory({});
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
expect(factory.$$type).toBe('@backstage/BackendFeature');
});
it('should create root scoped factory with dependencies and options', () => {
const metaFactory = createServiceFactory((_options?: TestOptions) => ({
service: createServiceRef({ id: 'foo', scope: 'root' }),
deps: {
root: rootDep,
},
async factory({ root }) {
const root1: number = root;
// @ts-expect-error
const root2: string = root;
unused(root1, root2);
return 0;
},
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory({ x: 1, y: 2 });
// @ts-expect-error
metaFactory(null);
metaFactory(undefined);
metaFactory();
});
it('should create factory with dependencies', () => {
const metaFactory = createServiceFactory({
it('should create a plugin scoped factory with dependencies', () => {
const factory = createServiceFactory({
service: createServiceRef({ id: 'derp' }),
deps: {
root: rootDep,
@@ -251,19 +112,11 @@ describe('createServiceFactory', () => {
return 'x';
},
});
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory({});
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
expect(factory.$$type).toBe('@backstage/BackendFeature');
});
it('should create factory with dependencies with optional derpFactory', () => {
const metaFactory = createServiceFactory({
const factory = createServiceFactory({
service: createServiceRef({ id: 'derp' }),
deps: {
root: rootDep,
@@ -280,61 +133,12 @@ describe('createServiceFactory', () => {
return 'x';
},
});
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory({});
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
});
it('should create factory with options and dependencies', () => {
const metaFactory = createServiceFactory((_opts?: TestOptions) => ({
service: ref,
deps: {
root: rootDep,
plugin: pluginDep,
},
async createRootContext({ root }) {
const root1: number = root;
// @ts-expect-error
const root2: string = root;
unused(root1, root2);
return { root };
},
async factory({ plugin }, { root }) {
const root1: number = root;
// @ts-expect-error
const root2: string = root;
const plugin3: boolean = plugin;
// @ts-expect-error
const plugin4: number = plugin;
unused(root1, root2, plugin3, plugin4);
return 'x';
},
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory({ x: 1, y: 2 });
// @ts-expect-error
metaFactory(null);
metaFactory(undefined);
metaFactory();
expect(factory.$$type).toBe('@backstage/BackendFeature');
});
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({
const factory = createServiceFactory({
service: ref,
deps: {
plugin: oldPluginDep,
@@ -347,82 +151,6 @@ describe('createServiceFactory', () => {
return 'x';
},
});
expect(metaFactory).toEqual(expect.any(Function));
});
it('should only allow objects as options', () => {
// @ts-expect-error
const metaFactory = createServiceFactory((_opts: string) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
createServiceFactory((_opts: number) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: symbol) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: bigint) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: 'string') => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: Array) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: Map) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: Set) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
// @ts-expect-error
createServiceFactory((_opts: null) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
expect(factory.$$type).toBe('@backstage/BackendFeature');
});
});
@@ -59,24 +59,6 @@ export interface ServiceFactory<
service: ServiceRef<TService, TScope, TInstances>;
}
/**
* @public
* @deprecated This type exists only as a helper for old code that relied on `createServiceFactory` to return `() => ServiceFactory` instead of `ServiceFactory`. You should remove the `()` parentheses at the end of your usages. This type will be removed in a future release.
*/
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, 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, TInstances>;
}
/** @internal */
export interface InternalServiceFactory<
TService = unknown,
@@ -114,12 +96,6 @@ export interface ServiceRefOptions<
defaultFactory?(
service: ServiceRef<TService, TScope>,
): Promise<ServiceFactory>;
/**
* @deprecated The defaultFactory must return a plain `ServiceFactory` object, support for returning a function will be removed.
*/
defaultFactory?(
service: ServiceRef<TService, TScope>,
): Promise<() => ServiceFactory>;
}
/**
@@ -179,7 +155,7 @@ export function createServiceRef<
} as ServiceRef<TService, typeof scope, TInstances> & {
__defaultFactory?: (
service: ServiceRef<TService>,
) => Promise<ServiceFactory<TService> | (() => ServiceFactory<TService>)>;
) => Promise<ServiceFactory<TService>>;
};
}
@@ -259,31 +235,9 @@ export function createServiceFactory<
TInstances extends 'singleton' | 'multiton',
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown, 'root'> },
TOpts extends object | undefined = undefined,
>(
options: RootServiceFactoryOptions<TService, TInstances, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TInstances>;
/**
* Creates a root scoped service factory with optional options.
*
* @deprecated The ability to define options for service factories is deprecated
* and will be removed. Please use the non-callback form of createServiceFactory
* and provide an API that allows for a simple re-implementation of the service
* factory instead.
* @public
* @param options - The service factory configuration.
*/
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, TInstances, TImpl, TDeps>,
): ServiceFactoryCompat<TService, 'root', TInstances, TOpts>;
): ServiceFactory<TService, 'root', TInstances>;
/**
* Creates a plugin scoped service factory without options.
*
@@ -296,7 +250,6 @@ export function createServiceFactory<
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
TContext = undefined,
TOpts extends object | undefined = undefined,
>(
options: PluginServiceFactoryOptions<
TService,
@@ -305,100 +258,22 @@ export function createServiceFactory<
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TInstances>;
/**
* Creates a plugin scoped service factory with optional options.
*
* @deprecated The ability to define options for service factories is deprecated
* and will be removed. Please use the non-callback form of createServiceFactory
* and provide an API that allows for a simple re-implementation of the service
* factory instead.
* @public
* @param options - The service factory configuration.
*/
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: (
options?: TOpts,
) => PluginServiceFactoryOptions<
TService,
TInstances,
TContext,
TImpl,
TDeps
>,
): ServiceFactoryCompat<TService, 'plugin', TInstances, TOpts>;
): ServiceFactory<TService, 'plugin', TInstances>;
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, TInstances, TImpl, TDeps>
| PluginServiceFactoryOptions<TService, TInstances, TContext, TImpl, TDeps>
| ((
options: 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 = (
o?: TOpts,
): InternalServiceFactory<TService, 'plugin' | 'root'> => {
const anyConf = configCallback(o!);
if (anyConf.service.scope === 'root') {
const c = anyConf as RootServiceFactoryOptions<
TService,
TInstances,
TImpl,
TDeps
>;
return {
$$type: '@backstage/BackendFeature',
version: 'v1',
featureType: 'service',
service: c.service,
initialization: c.initialization,
deps: c.deps,
factory: async (deps: ServiceRefsToInstances<TDeps, 'root'>) =>
c.factory(deps),
};
}
const c = anyConf as PluginServiceFactoryOptions<
| PluginServiceFactoryOptions<TService, TInstances, TContext, TImpl, TDeps>,
): ServiceFactory<TService, 'root' | 'plugin', 'singleton' | 'multiton'> {
if (options.service.scope === 'root') {
const c = options as RootServiceFactoryOptions<
TService,
TInstances,
TContext,
TImpl,
TDeps
>;
@@ -408,23 +283,33 @@ export function createServiceFactory<
featureType: 'service',
service: c.service,
initialization: c.initialization,
...('createRootContext' in c
? {
createRootContext: async (
deps: ServiceRefsToInstances<TDeps, 'root'>,
) => c?.createRootContext?.(deps),
}
: {}),
deps: c.deps,
factory: async (deps: ServiceRefsToInstances<TDeps>, ctx: TContext) =>
c.factory(deps, ctx),
};
};
// This constructs the `ServiceFactoryCompat` type, which is both a plain
// factory object as well as a function that can be called to construct a
// factory, potentially with options. In the future only the plain factory
// form will be supported, but for now we need to allow callers to call the
// factory too.
return Object.assign(factory, factory(undefined as TOpts));
deps: options.deps,
factory: async (deps: ServiceRefsToInstances<TDeps, 'root'>) =>
c.factory(deps),
} as InternalServiceFactory<TService, 'root', TInstances>;
}
const c = options as PluginServiceFactoryOptions<
TService,
TInstances,
TContext,
TImpl,
TDeps
>;
return {
$$type: '@backstage/BackendFeature',
version: 'v1',
featureType: 'service',
service: c.service,
initialization: c.initialization,
...('createRootContext' in options
? {
createRootContext: async (
deps: ServiceRefsToInstances<TDeps, 'root'>,
) => c?.createRootContext?.(deps),
}
: {}),
deps: options.deps,
factory: async (deps: ServiceRefsToInstances<TDeps>, ctx: TContext) =>
c.factory(deps, ctx),
} as InternalServiceFactory<TService, 'plugin', TInstances>;
}
+25 -117
View File
@@ -38,7 +38,6 @@ import { RootLifecycleService } from '@backstage/backend-plugin-api';
import { RootLoggerService } from '@backstage/backend-plugin-api';
import { SchedulerService } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
import { TokenManagerService } from '@backstage/backend-plugin-api';
import { UrlReaderService } from '@backstage/backend-plugin-api';
@@ -150,12 +149,7 @@ export namespace mockServices {
// (undocumented)
export namespace auth {
const // (undocumented)
factory: ServiceFactoryCompat<
AuthService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<AuthService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<AuthService> | undefined,
@@ -164,12 +158,7 @@ export namespace mockServices {
// (undocumented)
export namespace cache {
const // (undocumented)
factory: ServiceFactoryCompat<
CacheService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<CacheService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<CacheService> | undefined,
@@ -178,12 +167,7 @@ export namespace mockServices {
// (undocumented)
export namespace database {
const // (undocumented)
factory: ServiceFactoryCompat<
DatabaseService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<DatabaseService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<DatabaseService> | undefined,
@@ -194,12 +178,7 @@ export namespace mockServices {
// (undocumented)
export namespace discovery {
const // (undocumented)
factory: ServiceFactoryCompat<
DiscoveryService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<DiscoveryService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<DiscoveryService> | undefined,
@@ -208,12 +187,7 @@ export namespace mockServices {
// (undocumented)
export namespace events {
const // (undocumented)
factory: ServiceFactoryCompat<
EventsService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<EventsService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<EventsService> | undefined,
@@ -225,10 +199,9 @@ export namespace mockServices {
}): HttpAuthService;
// (undocumented)
export namespace httpAuth {
const factory: ((options?: {
const factory: (options?: {
defaultCredentials?: BackstageCredentials;
}) => ServiceFactory<HttpAuthService, 'plugin', 'singleton'>) &
ServiceFactory<HttpAuthService, 'plugin', 'singleton'>;
}) => ServiceFactory<HttpAuthService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<HttpAuthService> | undefined,
@@ -237,12 +210,7 @@ export namespace mockServices {
// (undocumented)
export namespace httpRouter {
const // (undocumented)
factory: ServiceFactoryCompat<
HttpRouterService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<HttpRouterService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<HttpRouterService> | undefined,
@@ -253,12 +221,7 @@ export namespace mockServices {
// (undocumented)
export namespace identity {
const // (undocumented)
factory: ServiceFactoryCompat<
IdentityService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<IdentityService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<IdentityService> | undefined,
@@ -267,12 +230,7 @@ export namespace mockServices {
// (undocumented)
export namespace lifecycle {
const // (undocumented)
factory: ServiceFactoryCompat<
LifecycleService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<LifecycleService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<LifecycleService> | undefined,
@@ -281,12 +239,7 @@ export namespace mockServices {
// (undocumented)
export namespace logger {
const // (undocumented)
factory: ServiceFactoryCompat<
LoggerService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<LoggerService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<LoggerService> | undefined,
@@ -295,12 +248,7 @@ export namespace mockServices {
// (undocumented)
export namespace permissions {
const // (undocumented)
factory: ServiceFactoryCompat<
PermissionsService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<PermissionsService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<PermissionsService> | undefined,
@@ -315,28 +263,14 @@ export namespace mockServices {
data?: JsonObject;
};
const // (undocumented)
factory: ServiceFactory<
RootConfigService,
'root',
'singleton' | 'multiton'
> &
((
options?: Options | undefined,
) => ServiceFactory<
RootConfigService,
'root',
'singleton' | 'multiton'
>);
factory: (
options?: Options | undefined,
) => ServiceFactory<RootConfigService, 'root', 'singleton' | 'multiton'>;
}
// (undocumented)
export namespace rootHealth {
const // (undocumented)
factory: ServiceFactoryCompat<
RootHealthService,
'root',
'singleton',
undefined
>;
factory: () => ServiceFactory<RootHealthService, 'root', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<RootHealthService> | undefined,
@@ -345,7 +279,7 @@ export namespace mockServices {
// (undocumented)
export namespace rootHttpRouter {
const // (undocumented)
factory: ((
factory: () => ((
options?: RootHttpRouterFactoryOptions | undefined,
) => ServiceFactory<RootHttpRouterService, 'root', 'singleton'>) &
ServiceFactory<RootHttpRouterService, 'root', 'singleton'>;
@@ -357,12 +291,7 @@ export namespace mockServices {
// (undocumented)
export namespace rootLifecycle {
const // (undocumented)
factory: ServiceFactoryCompat<
RootLifecycleService,
'root',
'singleton',
undefined
>;
factory: () => ServiceFactory<RootLifecycleService, 'root', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<RootLifecycleService> | undefined,
@@ -377,10 +306,9 @@ export namespace mockServices {
level?: 'none' | 'error' | 'warn' | 'info' | 'debug';
};
const // (undocumented)
factory: ServiceFactory<LoggerService, 'root', 'singleton' | 'multiton'> &
((
options?: Options | undefined,
) => ServiceFactory<LoggerService, 'root', 'singleton' | 'multiton'>);
factory: (
options?: Options | undefined,
) => ServiceFactory<LoggerService, 'root', 'singleton' | 'multiton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<RootLoggerService> | undefined,
@@ -389,12 +317,7 @@ export namespace mockServices {
// (undocumented)
export namespace scheduler {
const // (undocumented)
factory: ServiceFactoryCompat<
SchedulerService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<SchedulerService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<SchedulerService> | undefined,
@@ -405,12 +328,7 @@ export namespace mockServices {
// (undocumented)
export namespace tokenManager {
const // (undocumented)
factory: ServiceFactoryCompat<
TokenManagerService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<TokenManagerService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<TokenManagerService> | undefined,
@@ -419,12 +337,7 @@ export namespace mockServices {
// (undocumented)
export namespace urlReader {
const // (undocumented)
factory: ServiceFactoryCompat<
UrlReaderService,
'plugin',
'singleton',
undefined
>;
factory: () => ServiceFactory<UrlReaderService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<UrlReaderService> | undefined,
@@ -435,12 +348,7 @@ export namespace mockServices {
): UserInfoService;
// (undocumented)
export namespace userInfo {
const factory: ServiceFactoryCompat<
UserInfoService,
'plugin',
'singleton',
undefined
>;
const factory: () => ServiceFactory<UserInfoService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<UserInfoService> | undefined,
@@ -77,8 +77,7 @@ function simpleFactoryWithOptions<
>(
ref: ServiceRef<TService, TScope>,
factory: (...options: TOptions) => TService,
): ServiceFactory<TService, TScope> &
((...options: TOptions) => ServiceFactory<TService, TScope>) {
): (...options: TOptions) => ServiceFactory<TService, TScope> {
const factoryWithOptions = (...options: TOptions) =>
createServiceFactory({
service: ref as ServiceRef<TService, any>,
@@ -86,7 +85,7 @@ function simpleFactoryWithOptions<
async factory() {
return factory(...options);
},
})();
});
return Object.assign(
factoryWithOptions,
factoryWithOptions(...([undefined] as unknown as TOptions)),
@@ -126,7 +125,7 @@ function simpleMock<TService>(
service: ref,
deps: {},
factory: () => mock,
})(),
}),
}) as ServiceMock<TService>;
};
}
@@ -181,11 +180,12 @@ export namespace mockServices {
};
}
export namespace tokenManager {
export const factory = createServiceFactory({
service: coreServices.tokenManager,
deps: {},
factory: () => tokenManager(),
});
export const factory = () =>
createServiceFactory({
service: coreServices.tokenManager,
deps: {},
factory: () => tokenManager(),
});
export const mock = simpleMock(coreServices.tokenManager, () => ({
authenticate: jest.fn(),
getToken: jest.fn(),
@@ -196,11 +196,12 @@ export namespace mockServices {
return new MockIdentityService();
}
export namespace identity {
export const factory = createServiceFactory({
service: coreServices.identity,
deps: {},
factory: () => identity(),
});
export const factory = () =>
createServiceFactory({
service: coreServices.identity,
deps: {},
factory: () => identity(),
});
export const mock = simpleMock(coreServices.identity, () => ({
getIdentity: jest.fn(),
}));
@@ -216,24 +217,25 @@ export namespace mockServices {
});
}
export namespace auth {
export const factory = createServiceFactory({
service: coreServices.auth,
deps: {
plugin: coreServices.pluginMetadata,
config: coreServices.rootConfig,
},
factory({ plugin, config }) {
const disableDefaultAuthPolicy = Boolean(
config.getOptionalBoolean(
'backend.auth.dangerouslyDisableDefaultAuthPolicy',
),
);
return new MockAuthService({
pluginId: plugin.getId(),
disableDefaultAuthPolicy,
});
},
});
export const factory = () =>
createServiceFactory({
service: coreServices.auth,
deps: {
plugin: coreServices.pluginMetadata,
config: coreServices.rootConfig,
},
factory({ plugin, config }) {
const disableDefaultAuthPolicy = Boolean(
config.getOptionalBoolean(
'backend.auth.dangerouslyDisableDefaultAuthPolicy',
),
);
return new MockAuthService({
pluginId: plugin.getId(),
disableDefaultAuthPolicy,
});
},
});
export const mock = simpleMock(coreServices.auth, () => ({
authenticate: jest.fn(),
getNoneCredentials: jest.fn(),
@@ -257,7 +259,7 @@ export namespace mockServices {
);
}
export namespace discovery {
export const factory = discoveryServiceFactory;
export const factory = () => discoveryServiceFactory;
export const mock = simpleMock(coreServices.discovery, () => ({
getBaseUrl: jest.fn(),
getExternalBaseUrl: jest.fn(),
@@ -288,7 +290,14 @@ export namespace mockServices {
);
}
export namespace httpAuth {
const factoryWithOptions = (options?: {
/**
* Creates a mock service factory for the `HttpAuthService`.
*
* By default all requests without credentials are treated as requests from
* the default mock user principal. This behavior can be configured with the
* `defaultCredentials` option.
*/
export const factory = (options?: {
defaultCredentials?: BackstageCredentials;
}) =>
createServiceFactory({
@@ -299,18 +308,7 @@ export namespace mockServices {
plugin.getId(),
options?.defaultCredentials ?? mockCredentials.user(),
),
})();
/**
* Creates a mock service factory for the `HttpAuthService`.
*
* By default all requests without credentials are treated as requests from
* the default mock user principal. This behavior can be configured with the
* `defaultCredentials` option.
*/
export const factory = Object.assign(
factoryWithOptions,
factoryWithOptions(),
);
});
export const mock = simpleMock(coreServices.httpAuth, () => ({
credentials: jest.fn(),
issueUserCookie: jest.fn(),
@@ -336,13 +334,14 @@ export namespace mockServices {
* By default it extracts the user's entity ref from a user principal and
* returns that as the only ownership entity ref.
*/
export const factory = createServiceFactory({
service: coreServices.userInfo,
deps: {},
factory() {
return new MockUserInfoService();
},
});
export const factory = () =>
createServiceFactory({
service: coreServices.userInfo,
deps: {},
factory() {
return new MockUserInfoService();
},
});
export const mock = simpleMock(coreServices.userInfo, () => ({
getUserInfo: jest.fn(),
}));
@@ -352,7 +351,7 @@ export namespace mockServices {
// some may need a bit more refactoring for it to be simpler to
// re-implement functioning mock versions here.
export namespace cache {
export const factory = cacheServiceFactory;
export const factory = () => cacheServiceFactory;
export const mock = simpleMock(coreServices.cache, () => ({
delete: jest.fn(),
get: jest.fn(),
@@ -362,14 +361,14 @@ export namespace mockServices {
}
export namespace database {
export const factory = databaseServiceFactory;
export const factory = () => databaseServiceFactory;
export const mock = simpleMock(coreServices.database, () => ({
getClient: jest.fn(),
}));
}
export namespace rootHealth {
export const factory = rootHealthServiceFactory;
export const factory = () => rootHealthServiceFactory;
export const mock = simpleMock(coreServices.rootHealth, () => ({
getLiveness: jest.fn(),
getReadiness: jest.fn(),
@@ -377,7 +376,7 @@ export namespace mockServices {
}
export namespace httpRouter {
export const factory = httpRouterServiceFactory;
export const factory = () => httpRouterServiceFactory;
export const mock = simpleMock(coreServices.httpRouter, () => ({
use: jest.fn(),
addAuthPolicy: jest.fn(),
@@ -385,14 +384,14 @@ export namespace mockServices {
}
export namespace rootHttpRouter {
export const factory = rootHttpRouterServiceFactory;
export const factory = () => rootHttpRouterServiceFactory;
export const mock = simpleMock(coreServices.rootHttpRouter, () => ({
use: jest.fn(),
}));
}
export namespace lifecycle {
export const factory = lifecycleServiceFactory;
export const factory = () => lifecycleServiceFactory;
export const mock = simpleMock(coreServices.lifecycle, () => ({
addShutdownHook: jest.fn(),
addStartupHook: jest.fn(),
@@ -400,15 +399,14 @@ export namespace mockServices {
}
export namespace logger {
export const factory = loggerServiceFactory;
export const factory = () => loggerServiceFactory;
export const mock = simpleMock(coreServices.logger, () =>
createLoggerMock(),
);
}
export namespace permissions {
export const factory = permissionsServiceFactory;
export const factory = () => permissionsServiceFactory;
export const mock = simpleMock(coreServices.permissions, () => ({
authorize: jest.fn(),
authorizeConditional: jest.fn(),
@@ -416,7 +414,7 @@ export namespace mockServices {
}
export namespace rootLifecycle {
export const factory = rootLifecycleServiceFactory;
export const factory = () => rootLifecycleServiceFactory;
export const mock = simpleMock(coreServices.rootLifecycle, () => ({
addShutdownHook: jest.fn(),
addStartupHook: jest.fn(),
@@ -424,7 +422,7 @@ export namespace mockServices {
}
export namespace scheduler {
export const factory = schedulerServiceFactory;
export const factory = () => schedulerServiceFactory;
export const mock = simpleMock(coreServices.scheduler, () => ({
createScheduledTaskRunner: jest.fn(),
getScheduledTasks: jest.fn(),
@@ -434,7 +432,7 @@ export namespace mockServices {
}
export namespace urlReader {
export const factory = urlReaderServiceFactory;
export const factory = () => urlReaderServiceFactory;
export const mock = simpleMock(coreServices.urlReader, () => ({
readTree: jest.fn(),
readUrl: jest.fn(),
@@ -443,7 +441,7 @@ export namespace mockServices {
}
export namespace events {
export const factory = eventsServiceFactory;
export const factory = () => eventsServiceFactory;
export const mock = simpleMock(eventsServiceRef, () => ({
publish: jest.fn(),
subscribe: jest.fn(),
@@ -93,7 +93,7 @@ describe('ServiceFactoryTester', () => {
deps: { root: rootServiceRef, plugin: pluginServiceRef },
factory: async ({ root, plugin }) => `${root}, ${plugin}`,
}),
{ dependencies: [rootFactory, pluginFactory()] },
{ dependencies: [rootFactory, pluginFactory] },
);
await expect(tester.getSubject('x')).resolves.toBe('root, x-plugin');
@@ -106,7 +106,7 @@ describe('ServiceFactoryTester', () => {
deps: { shared: sharedPluginServiceRef, plugin: pluginServiceRef },
factory: async ({ shared, plugin }) => `${shared}, ${plugin}`,
}),
{ dependencies: [sharedPluginFactory(), pluginFactory] },
{ dependencies: [sharedPluginFactory, pluginFactory] },
);
await expect(tester.getSubject('x')).resolves.toBe('x-1-plugin, x-plugin');
@@ -71,34 +71,34 @@ describe('TestBackend', () => {
features: [
// @ts-expect-error
[extensionPoint1, { a: 'a' }],
createServiceFactory(() => ({
createServiceFactory({
service: serviceRef,
deps: {},
// @ts-expect-error
factory: async () => ({ a: 'a' }),
})),
createServiceFactory(() => ({
}),
createServiceFactory({
service: serviceRef,
deps: {},
factory: async () => ({ a: 'a', b: 'b' }),
})),
createServiceFactory(() => ({
}),
createServiceFactory({
service: serviceRef,
deps: {},
// @ts-expect-error
factory: async () => ({ c: 'c' }),
})),
createServiceFactory(() => ({
}),
createServiceFactory({
service: serviceRef,
deps: {},
// @ts-expect-error
factory: async () => ({ a: 'a', c: 'c' }),
})),
createServiceFactory(() => ({
}),
createServiceFactory({
service: serviceRef,
deps: {},
factory: async () => ({ a: 'a', b: 'b', c: 'c' }),
})),
}),
],
extensionPoints: [
// @ts-expect-error
@@ -144,7 +144,7 @@ describe('TestBackend', () => {
});
await startTestBackend({
features: [testModule, sf()],
features: [testModule, sf],
});
expect(testFn).toHaveBeenCalledWith('winning');
@@ -58,7 +58,7 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => {
[catalogProcessingExtensionPoint, catalogExtensionPointImpl],
],
features: [
eventsServiceFactory(),
eventsServiceFactory,
catalogModuleBitbucketCloudEntityProvider,
mockServices.rootConfig.factory({
data: {
@@ -83,7 +83,7 @@ describe('catalogModuleGitlabOrgDiscoveryEntityProvider', () => {
await startTestBackend({
extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]],
features: [
eventsServiceFactory(),
eventsServiceFactory,
catalogModuleGitlabOrgDiscoveryEntityProvider,
mockServices.rootConfig.factory({ data: config }),
mockServices.logger.factory(),
@@ -82,7 +82,7 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => {
await startTestBackend({
extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]],
features: [
eventsServiceFactory(),
eventsServiceFactory,
catalogModuleGitlabDiscoveryEntityProvider,
mockServices.rootConfig.factory({ data: config }),
mockServices.logger.factory(),
@@ -35,7 +35,7 @@ describe('eventsModuleAwsSqsConsumingEventPublisher', () => {
await startTestBackend({
features: [
eventsServiceFactory(),
eventsServiceFactory,
eventsModuleAwsSqsConsumingEventPublisher,
mockServices.rootConfig.factory({
data: {
@@ -32,7 +32,7 @@ describe('eventsModuleAzureDevOpsEventRouter', () => {
});
await startTestBackend({
features: [eventsServiceFactory(), eventsModuleAzureDevOpsEventRouter],
features: [eventsServiceFactory, eventsModuleAzureDevOpsEventRouter],
});
expect(events.subscribed).toHaveLength(1);
@@ -32,7 +32,7 @@ describe('eventsModuleBitbucketCloudEventRouter', () => {
});
await startTestBackend({
features: [eventsServiceFactory(), eventsModuleBitbucketCloudEventRouter],
features: [eventsServiceFactory, eventsModuleBitbucketCloudEventRouter],
});
expect(events.subscribed).toHaveLength(1);
@@ -32,7 +32,7 @@ describe('eventsModuleGerritEventRouter', () => {
});
await startTestBackend({
features: [eventsServiceFactory(), eventsModuleGerritEventRouter],
features: [eventsServiceFactory, eventsModuleGerritEventRouter],
});
expect(events.subscribed).toHaveLength(1);
@@ -32,7 +32,7 @@ describe('eventsModuleGithubEventRouter', () => {
});
await startTestBackend({
features: [eventsServiceFactory(), eventsModuleGithubEventRouter],
features: [eventsServiceFactory, eventsModuleGithubEventRouter],
});
expect(events.subscribed).toHaveLength(1);
@@ -32,7 +32,7 @@ describe('eventsModuleGitlabEventRouter', () => {
});
await startTestBackend({
features: [eventsServiceFactory(), eventsModuleGitlabEventRouter],
features: [eventsServiceFactory, eventsModuleGitlabEventRouter],
});
expect(events.subscribed).toHaveLength(1);
@@ -56,7 +56,7 @@ describe('eventsPlugin', () => {
const { server } = await startTestBackend({
extensionPoints: [],
features: [
eventsServiceFactory(),
eventsServiceFactory,
eventsPlugin,
testModule,
mockServices.logger.factory(),
+3 -4
View File
@@ -4,7 +4,7 @@
```ts
import { LoggerService } from '@backstage/backend-plugin-api';
import { ServiceFactoryCompat } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
// @public
@@ -63,11 +63,10 @@ export interface EventsService {
export type EventsServiceEventHandler = (params: EventParams) => Promise<void>;
// @public (undocumented)
export const eventsServiceFactory: ServiceFactoryCompat<
export const eventsServiceFactory: ServiceFactory<
EventsService,
'plugin',
'singleton',
undefined
'singleton'
>;
// @public
@@ -80,8 +80,8 @@ describe('credentials', () => {
features: [
import('../alpha'),
mockServices.rootConfig.factory({ data: config }),
authServiceFactory(),
httpAuthServiceFactory(),
authServiceFactory,
httpAuthServiceFactory,
],
});