From f318a3565541627d72aede7c2f8383afe65021fd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Jul 2025 11:38:46 +0200 Subject: [PATCH 01/11] frontend-plugin-api: tests in place for advanced blueprint types Signed-off-by: Patrik Oldsberg --- .../wiring/createExtensionBlueprint.test.tsx | 455 +++++++++++++++++- 1 file changed, 454 insertions(+), 1 deletion(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index 5a44dc4b55..a71147716e 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -15,7 +15,10 @@ */ import { coreExtensionData } from './coreExtensionData'; -import { createExtensionBlueprint } from './createExtensionBlueprint'; +import { + createExtensionBlueprint, + createExtensionBlueprintParams, +} from './createExtensionBlueprint'; import { createExtensionTester, renderInTestApp, @@ -876,6 +879,21 @@ describe('createExtensionBlueprint', () => { test2: 'orig-2', }); + const extensionDef = blueprint.make({ + // Using define is optional in this case + params: define => + define({ + test1: 'orig-1', + test2: 'orig-2', + }), + }); + + expect(getOutputs(extensionDef)).toEqual({ + test1: 'orig-1', + test2: 'orig-2', + }); + + // Plain override expect( getOutputs( extension.override({ @@ -896,6 +914,8 @@ describe('createExtensionBlueprint', () => { extension.override({ params: { test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', }, }), ), @@ -904,6 +924,58 @@ describe('createExtensionBlueprint', () => { test2: 'override-2', }); + // Partial override with original define + expect( + getOutputs( + extensionDef.override({ + params: { + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }, + }), + ), + ).toEqual({ + test1: 'orig-1', + test2: 'override-2', + }); + + // Override with define + expect( + getOutputs( + extension.override({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + + // Override with define with original define + expect( + getOutputs( + extensionDef.override({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + expect( getOutputs( extension.override({ @@ -930,6 +1002,8 @@ describe('createExtensionBlueprint', () => { return origFactory({ params: { test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', }, }); }, @@ -940,6 +1014,70 @@ describe('createExtensionBlueprint', () => { test2: 'override-2', }); + // Partial override via factory with original define + expect( + getOutputs( + extensionDef.override({ + factory(origFactory) { + return origFactory({ + params: { + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }, + }); + }, + }), + ), + ).toEqual({ + test1: 'orig-1', + test2: 'override-2', + }); + + // Override via factory with define + expect( + getOutputs( + extension.override({ + factory(origFactory) { + return origFactory({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }); + }, + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + + // Override via factory with define with original define + expect( + getOutputs( + extensionDef.override({ + factory(origFactory) { + return origFactory({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }); + }, + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + expect(() => getOutputs( extension.override({ @@ -991,6 +1129,21 @@ describe('createExtensionBlueprint', () => { test2: 'orig-2', }); + const extensionDef = blueprint.make({ + // Using define is optional in this case + params: define => + define({ + test1: 'orig-1', + test2: 'orig-2', + }), + }); + + expect(getOutputs(extensionDef)).toEqual({ + test1: 'orig-1', + test2: 'orig-2', + }); + + // Plain override expect( getOutputs( extension.override({ @@ -1011,6 +1164,8 @@ describe('createExtensionBlueprint', () => { extension.override({ params: { test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', }, }), ), @@ -1019,6 +1174,59 @@ describe('createExtensionBlueprint', () => { test2: 'override-2', }); + // Partial override with original define + expect( + getOutputs( + extensionDef.override({ + params: { + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }, + }), + ), + ).toEqual({ + test1: 'orig-1', + test2: 'override-2', + }); + + // Override with define + expect( + getOutputs( + extension.override({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + + // Override with define with original define + expect( + getOutputs( + extensionDef.override({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + + // Override via factory expect( getOutputs( extension.override({ @@ -1045,6 +1253,8 @@ describe('createExtensionBlueprint', () => { return origFactory({ params: { test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', }, }); }, @@ -1055,6 +1265,70 @@ describe('createExtensionBlueprint', () => { test2: 'override-2', }); + // Partial override via factory with original define + expect( + getOutputs( + extensionDef.override({ + factory(origFactory) { + return origFactory({ + params: { + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }, + }); + }, + }), + ), + ).toEqual({ + test1: 'orig-1', + test2: 'override-2', + }); + + // Override via factory with define + expect( + getOutputs( + extension.override({ + factory(origFactory) { + return origFactory({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }); + }, + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + + // Override via factory with define with original define + expect( + getOutputs( + extensionDef.override({ + factory(origFactory) { + return origFactory({ + params: define => + define({ + test1: 'override-1', + test2: 'override-2', + // @ts-expect-error + test3: 'nonexistent', + }), + }); + }, + }), + ), + ).toEqual({ + test1: 'override-1', + test2: 'override-2', + }); + expect(() => getOutputs( extension.override({ @@ -1069,4 +1343,183 @@ describe('createExtensionBlueprint', () => { ), ).toThrow('Refused to override params and factory at the same time'); }); + + describe('with advanced parameter types', () => { + const testDataRef = createExtensionDataRef().with({ id: 'test' }); + + const TestExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: [testDataRef], + defineParams(params: { + a: A; + b: B; + }) { + return createExtensionBlueprintParams(params); + }, + factory(params) { + return [testDataRef(`${params.a} ${params.b}`)]; + }, + }); + + it('should allow creation of extension blueprints', () => { + TestExtensionBlueprint.make({ + // @ts-expect-error not using define func + params: { + a: 'x', + b: 'y', + }, + }); + + TestExtensionBlueprint.make({ + params: define => + define({ + a: 'x', + // @ts-expect-error b doesn't match a + b: 'y', + }), + }); + + const extension = TestExtensionBlueprint.make({ + params: define => + define({ + a: 'x', + b: 'x', + }), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + T: undefined, + attachTo: { + id: 'test', + input: 'default', + }, + configSchema: undefined, + disabled: false, + inputs: {}, + kind: 'test-extension', + name: undefined, + namespace: undefined, + output: [testDataRef], + factory: expect.any(Function), + toString: expect.any(Function), + override: expect.any(Function), + version: 'v2', + }); + + expect(createExtensionTester(extension).get(testDataRef)).toBe('x x'); + + extension.override({ + // @ts-expect-error not using define func + params: { + a: 'z', + b: 'w', + }, + }); + + extension.override({ + params: define => + define({ + a: 'z', + // @ts-expect-error b doesn't match a + b: 'w', + }), + }); + + const override = extension.override({ + params: define => + define({ + a: 'z', + b: 'z', + }), + }); + + expect(createExtensionTester(override).get(testDataRef)).toBe('z z'); + }); + + it('should allow overriding of the default factory', () => { + TestExtensionBlueprint.makeWithOverrides({ + factory(originalFactory) { + // @ts-expect-error not using define func + return originalFactory({ + a: 'x', + b: 'y', + }); + }, + }); + + TestExtensionBlueprint.makeWithOverrides({ + factory(originalFactory) { + return originalFactory(define => + define({ + a: 'x', + // @ts-expect-error b doesn't match a + b: 'y', + }), + ); + }, + }); + + const extension = TestExtensionBlueprint.makeWithOverrides({ + factory(originalFactory) { + return originalFactory(define => + define({ + a: 'x', + b: 'x', + }), + ); + }, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + T: undefined, + attachTo: { + id: 'test', + input: 'default', + }, + configSchema: undefined, + disabled: false, + inputs: {}, + kind: 'test-extension', + name: undefined, + namespace: undefined, + output: [testDataRef], + factory: expect.any(Function), + toString: expect.any(Function), + override: expect.any(Function), + version: 'v2', + }); + + expect(createExtensionTester(extension).get(testDataRef)).toBe('x x'); + + extension.override({ + // @ts-expect-error not using define func + params: { + a: 'z', + b: 'w', + }, + }); + + extension.override({ + params: define => + define({ + a: 'z', + // @ts-expect-error b doesn't match a + b: 'w', + }), + }); + + const override = extension.override({ + params: define => + define({ + a: 'z', + b: 'z', + }), + }); + + expect(createExtensionTester(override).get(testDataRef)).toBe('z z'); + }); + }); }); From 39e8111a30912d29d17d9124450328e0af5242ff Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Jul 2025 14:53:55 +0200 Subject: [PATCH 02/11] frontend-plugin-api: initial implementation of advanced blueprint params types Signed-off-by: Patrik Oldsberg --- .../src/wiring/createExtension.ts | 36 +++- .../wiring/createExtensionBlueprint.test.tsx | 20 +++ .../src/wiring/createExtensionBlueprint.ts | 155 ++++++++++++++++-- .../wiring/resolveExtensionDefinition.test.ts | 1 + .../src/wiring/resolveExtensionDefinition.ts | 1 + 5 files changed, 199 insertions(+), 14 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 04d7f15240..df097bd843 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -30,6 +30,10 @@ import { z } from 'zod'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; import { OpaqueExtensionDefinition } from '@internal/frontend'; import { ExtensionDataContainer } from './types'; +import { + BlueprintParamsDefiner, + BlueprintParamsFactory, +} from './createExtensionBlueprint'; /** * This symbol is used to pass parameter overrides from the extension override to the blueprint factory @@ -161,9 +165,16 @@ export type ExtensionDefinitionParameters = { { optional: boolean; singleton: boolean } >; }; - params?: object; + params?: object | BlueprintParamsDefiner; }; +type AnyParamsInput = + TParams extends BlueprintParamsDefiner + ? IParams | BlueprintParamsFactory + : + | TParams + | BlueprintParamsFactory>; + /** @public */ export type ExtensionDefinition< T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters, @@ -183,6 +194,7 @@ export type ExtensionDefinition< { optional: boolean; singleton: boolean } >; }, + TParamsReturn extends AnyParamsInput>, >( args: Expand< { @@ -200,14 +212,24 @@ export type ExtensionDefinition< }; }; factory?( - originalFactory: ( + originalFactory: < + TFactoryParamsReturn extends AnyParamsInput< + NonNullable + >, + >( context?: Expand< { config?: T['config']; inputs?: ResolveInputValueOverrides>; } & ([T['params']] extends [never] ? {} - : { params?: Partial }) + : { + params?: TFactoryParamsReturn extends BlueprintParamsDefiner + ? TFactoryParamsReturn + : T['params'] extends BlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' + : Partial; + }) >, ) => ExtensionDataContainer>, context: { @@ -223,7 +245,13 @@ export type ExtensionDefinition< ): Iterable; } & ([T['params']] extends [never] ? {} - : { params?: Partial }) + : { + params?: TParamsReturn extends BlueprintParamsDefiner + ? TParamsReturn + : T['params'] extends BlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' + : Partial; + }) > & VerifyExtensionFactoryOutput< AnyExtensionDataRef extends UNewOutput diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index a71147716e..faec493092 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -1380,6 +1380,16 @@ describe('createExtensionBlueprint', () => { }), }); + TestExtensionBlueprint.make({ + params: define => + define({ + a: 'x', + b: 'x', + // @ts-expect-error extra param + c: 'y', + }), + }); + const extension = TestExtensionBlueprint.make({ params: define => define({ @@ -1427,6 +1437,16 @@ describe('createExtensionBlueprint', () => { }), }); + extension.override({ + params: define => + define({ + a: 'z', + b: 'z', + // @ts-expect-error extra param + c: 'w', + }), + }); + const override = extension.override({ params: define => define({ diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 57848a7980..6f60950eb3 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -16,6 +16,7 @@ import { ApiHolder, AppNode } from '../apis'; import { Expand } from '@backstage/types'; +import { OpaqueType } from '@internal/opaque'; import { ExtensionAttachToSpec, ExtensionDefinition, @@ -37,13 +38,43 @@ import { } from './resolveInputOverrides'; import { ExtensionDataContainer } from './types'; +export type BlueprintParamsDefiner< + TParams extends object = object, + TInput = any, +> = (params: TInput) => BlueprintParams; +export type BlueprintParamsFactory = ( + define: TDefiner, +) => ReturnType; + +export type BlueprintParams = { + $$type: '@backstage/BlueprintParams'; + T: T; +}; + +const OpaqueBlueprintParams = OpaqueType.create<{ + public: BlueprintParams; + versions: { + version: 'v1'; + params: object; + }; +}>({ + type: '@backstage/BlueprintParams', + versions: ['v1'], +}); + +export function createExtensionBlueprintParams( + params: T, +): BlueprintParams { + return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params }); +} + /** * @public */ export type CreateExtensionBlueprintOptions< TKind extends string, TName extends string | undefined, - TParams, + TParams extends object | BlueprintParamsDefiner, UOutput extends AnyExtensionDataRef, TInputs extends { [inputName in string]: ExtensionInput< @@ -64,8 +95,13 @@ export type CreateExtensionBlueprintOptions< config?: { schema: TConfigSchema; }; + defineParams?: TParams extends BlueprintParamsDefiner + ? TParams + : 'The params option must be a function if provided, see the docs for details'; factory( - params: TParams, + params: TParams extends BlueprintParamsDefiner + ? ReturnType['T'] + : TParams, context: { node: AppNode; apis: ApiHolder; @@ -83,7 +119,7 @@ export type CreateExtensionBlueprintOptions< export type ExtensionBlueprintParameters = { kind: string; name?: string; - params?: object; + params: object | BlueprintParamsDefiner; configInput?: { [K in string]: any }; config?: { [K in string]: any }; output?: AnyExtensionDataRef; @@ -96,19 +132,40 @@ export type ExtensionBlueprintParameters = { dataRefs?: { [name in string]: AnyExtensionDataRef }; }; +/** + * Represents any form of params input that can be passed to a blueprint. + * This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback. + * + * @internal + */ +type AnyParamsInput = + TParams extends BlueprintParamsDefiner + ? IParams | BlueprintParamsFactory + : + | TParams + | BlueprintParamsFactory>; + /** * @public */ export interface ExtensionBlueprint< + // TParamsMapper extends (params: any) => object, T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters, > { dataRefs: T['dataRefs']; - make(args: { + make< + TNewName extends string | undefined, + TParamsReturn extends AnyParamsInput, + >(args: { name?: TNewName; attachTo?: ExtensionAttachToSpec; disabled?: boolean; - params: T['params']; + params: TParamsReturn extends BlueprintParamsDefiner + ? TParamsReturn + : T['params'] extends BlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `.make({ params: define => define() })`' + : TParamsReturn; }): ExtensionDefinition<{ kind: T['kind']; name: string | undefined extends TNewName ? T['name'] : TNewName; @@ -154,8 +211,12 @@ export interface ExtensionBlueprint< }; }; factory( - originalFactory: ( - params: T['params'], + originalFactory: >( + params: TParamsReturn extends BlueprintParamsDefiner + ? TParamsReturn + : T['params'] extends BlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' + : TParamsReturn, context?: { config?: T['config']; inputs?: ResolveInputValueOverrides>; @@ -205,6 +266,76 @@ export interface ExtensionBlueprint< }>; } +function unwrapParamsFactory( + // Allow `Function` because `typeof === 'function'` allows it, but in practice this should always be a param factory + params: BlueprintParamsFactory | Function, + defineParams: BlueprintParamsDefiner, + kind: string, +): TParams { + const paramDefinition = ( + params as BlueprintParamsFactory + )(defineParams); + try { + return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams; + } catch (e) { + throw new TypeError( + `Invalid invocation of blueprint with kind '${kind}', the parameter definition callback function did not return a valid parameter definition object; Caused by: ${e.message}`, + ); + } +} + +function unwrapParams( + params: object | BlueprintParamsFactory | string, + ctx: { node: AppNode; [ctxParamsSymbol]?: any }, + defineParams: BlueprintParamsDefiner | undefined, + kind: string, +): TParams { + const overrideParams = ctx[ctxParamsSymbol] as + | object + | BlueprintParamsFactory + | undefined; + + if (defineParams) { + if (overrideParams) { + if (typeof overrideParams !== 'function') { + throw new TypeError( + `Invalid extension override of blueprint with kind '${kind}', the override params were passed as a plain object, but this blueprint requires them to be passed in callback form`, + ); + } + return unwrapParamsFactory(overrideParams, defineParams, kind); + } + + if (typeof params !== 'function') { + throw new TypeError( + `Invalid invocation of blueprint with kind '${kind}', the parameters where passed as a plain object, but this blueprint requires them to be passed in callback form`, + ); + } + return unwrapParamsFactory(params, defineParams, kind); + } + + const base = + typeof params === 'function' + ? unwrapParamsFactory( + params, + createExtensionBlueprintParams, + kind, + ) + : (params as TParams); + const overrides = + typeof overrideParams === 'function' + ? unwrapParamsFactory( + overrideParams, + createExtensionBlueprintParams, + kind, + ) + : (overrideParams as Partial); + + return { + ...base, + ...overrides, + }; +} + /** * A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating * types and instances of those types. @@ -212,7 +343,7 @@ export interface ExtensionBlueprint< * @public */ export function createExtensionBlueprint< - TParams extends object, + TParams extends object | BlueprintParamsDefiner, UOutput extends AnyExtensionDataRef, TInputs extends { [inputName in string]: ExtensionInput< @@ -254,6 +385,10 @@ export function createExtensionBlueprint< >; dataRefs: TDataRefs; }> { + const defineParams = options.defineParams as + | BlueprintParamsDefiner + | undefined; + return { dataRefs: options.dataRefs, make(args) { @@ -267,7 +402,7 @@ export function createExtensionBlueprint< config: options.config, factory: ctx => options.factory( - { ...args.params, ...(ctx as any)[ctxParamsSymbol] }, + unwrapParams(args.params, ctx, defineParams, options.kind), ctx, ) as Iterable>, }) as ExtensionDefinition; @@ -295,7 +430,7 @@ export function createExtensionBlueprint< (innerParams, innerContext) => { return createExtensionDataContainer( options.factory( - { ...innerParams, ...(ctx as any)[ctxParamsSymbol] }, + unwrapParams(innerParams, ctx, defineParams, options.kind), { apis, node, diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts index b25a7b9375..a74d908024 100644 --- a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts @@ -113,6 +113,7 @@ describe('ResolveExtensionId', () => { kind: TKind; name: TName; output: any; + params: never; }>; const id1: 'k:ns' = {} as ResolveExtensionId< NamedExtension<'k', undefined>, diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts index 7e771c6c2c..c3ff381fdc 100644 --- a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts @@ -116,6 +116,7 @@ export type ResolveExtensionId< > = TExtension extends ExtensionDefinition<{ kind: infer IKind extends string | undefined; name: infer IName extends string | undefined; + params: any; }> ? [string] extends [IKind | IName] ? never From fa7861ddc5abe55eccbde5908a43bd9124fd84a8 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Jul 2025 15:13:18 +0200 Subject: [PATCH 03/11] frontend-plugin-api: refactor ApiBlueprint to use advanced param types Signed-off-by: Patrik Oldsberg --- .../src/blueprints/ApiBlueprint.test.ts | 115 +++++++++++++++--- .../src/blueprints/ApiBlueprint.ts | 14 ++- 2 files changed, 110 insertions(+), 19 deletions(-) diff --git a/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts index 862f802810..6eafcf2556 100644 --- a/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts +++ b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts @@ -16,21 +16,19 @@ import { createExtensionInput } from '../wiring'; import { ApiBlueprint } from './ApiBlueprint'; -import { createApiFactory, createApiRef } from '@backstage/core-plugin-api'; +import { createApiRef } from '@backstage/core-plugin-api'; describe('ApiBlueprint', () => { it('should create an extension with sensible defaults', () => { const api = createApiRef<{ foo: string }>({ id: 'test' }); - const factory = createApiFactory({ - api, - deps: {}, - factory: () => ({ foo: 'bar' }), - }); const extension = ApiBlueprint.make({ - params: { - factory, - }, + params: define => + define({ + api, + deps: {}, + factory: () => ({ foo: 'bar' }), + }), name: 'test', }); @@ -58,6 +56,97 @@ describe('ApiBlueprint', () => { `); }); + it('should properly type the API factory', () => { + const fooApi = createApiRef<{ foo: string }>({ id: 'foo' }); + const barApi = createApiRef<{ bar: string }>({ id: 'bar' }); + + expect('test').not.toBe('failing without assertions'); + + ApiBlueprint.make({ + params: define => + define({ api: fooApi, deps: {}, factory: () => ({ foo: 'foo' }) }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: {}, + // @ts-expect-error missing property + factory: () => ({}), + }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: {}, + // @ts-expect-error wrong property + factory: () => ({ + bar: 'bar', + }), + }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: {}, + factory: () => ({ + // @ts-expect-error wrong type + foo: 1, + }), + }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: { bar: barApi }, + factory: ({ bar }) => ({ foo: bar.bar }), + }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: { bar: barApi }, + factory: ({ bar }) => ({ + // @ts-expect-error not an available property + foo: bar.foo, + }), + }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: { bar: barApi }, + factory: ({ bar }) => ({ + // @ts-expect-error not an available property + foo: bar.foo, + }), + }), + }); + + ApiBlueprint.make({ + params: define => + define({ + api: fooApi, + deps: {}, + factory: ({ bar }) => ({ + // @ts-expect-error unknown dep + foo: bar.bar, + }), + }), + }); + }); + it('should create an extension with custom factory', () => { const api = createApiRef<{ foo: string }>({ id: 'test' }); const factory = jest.fn(() => ({ foo: 'bar' })); @@ -73,13 +162,7 @@ describe('ApiBlueprint', () => { }, name: api.id, factory(originalFactory, { config: _config, inputs: _inputs }) { - return originalFactory({ - factory: createApiFactory({ - api, - deps: {}, - factory, - }), - }); + return originalFactory(define => define({ api, deps: {}, factory })); }, }); diff --git a/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts index 1f28a3cf54..a066a362d9 100644 --- a/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts @@ -14,8 +14,9 @@ * limitations under the License. */ +import { AnyApiFactory, ApiFactory } from '../apis/system'; import { createExtensionBlueprint, createExtensionDataRef } from '../wiring'; -import { AnyApiFactory } from '@backstage/core-plugin-api'; +import { createExtensionBlueprintParams } from '../wiring/createExtensionBlueprint'; const factoryDataRef = createExtensionDataRef().with({ id: 'core.api.factory', @@ -33,7 +34,14 @@ export const ApiBlueprint = createExtensionBlueprint({ dataRefs: { factory: factoryDataRef, }, - *factory(params: { factory: AnyApiFactory }) { - yield factoryDataRef(params.factory); + defineParams: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => createExtensionBlueprintParams(params as AnyApiFactory), + *factory(params) { + yield factoryDataRef(params); }, }); From f2f133ce8d48c71a90c57aa2cad301592730a33f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Jul 2025 15:17:13 +0200 Subject: [PATCH 04/11] update all usages of ApiBlueprint Signed-off-by: Patrik Oldsberg --- .changeset/every-schools-find.md | 20 ++ .../src/collectLegacyRoutes.tsx | 2 +- .../src/convertLegacyApp.test.tsx | 47 +-- .../src/convertLegacyAppOptions.tsx | 5 +- .../src/convertLegacyPlugin.ts | 5 +- .../src/wiring/createSpecializedApp.test.tsx | 40 ++- plugins/api-docs/report-alpha.api.md | 12 +- plugins/api-docs/src/alpha.tsx | 6 +- plugins/app/report.api.md | 272 ++++++++++++------ plugins/app/src/defaultApis.ts | 105 +++---- plugins/app/src/extensions/AppLanguageApi.ts | 14 +- plugins/app/src/extensions/AppThemeApi.tsx | 19 +- plugins/app/src/extensions/ComponentsApi.tsx | 21 +- plugins/app/src/extensions/FeatureFlagsApi.ts | 8 +- plugins/app/src/extensions/IconsApi.ts | 23 +- .../app/src/extensions/TranslationsApi.tsx | 7 +- plugins/catalog-import/report-alpha.api.md | 12 +- plugins/catalog-import/src/alpha.tsx | 6 +- .../report-alpha.api.md | 12 +- .../src/alpha/plugin.tsx | 6 +- plugins/catalog/report-alpha.api.md | 32 ++- plugins/catalog/src/alpha/apis.tsx | 16 +- plugins/devtools/report-alpha.api.md | 12 +- plugins/devtools/src/alpha/plugin.tsx | 6 +- plugins/home/report-alpha.api.md | 12 +- plugins/home/src/alpha.tsx | 6 +- plugins/kubernetes/report-alpha.api.md | 42 ++- plugins/kubernetes/src/alpha/apis.tsx | 21 +- plugins/notifications/report-alpha.api.md | 12 +- plugins/notifications/src/alpha.tsx | 6 +- plugins/scaffolder-react/report-alpha.api.md | 12 +- .../src/next/api/FormFieldsApi.ts | 7 +- plugins/scaffolder/report-alpha.api.md | 42 ++- .../src/alpha/api/FormDecoratorsApi.ts | 7 +- plugins/scaffolder/src/alpha/extensions.tsx | 6 +- plugins/search/report-alpha.api.md | 22 +- plugins/search/src/alpha.tsx | 6 +- plugins/signals/report-alpha.api.md | 12 +- plugins/signals/src/alpha.tsx | 6 +- plugins/techdocs/report-alpha.api.md | 22 +- plugins/techdocs/src/alpha/index.tsx | 11 +- 41 files changed, 579 insertions(+), 381 deletions(-) create mode 100644 .changeset/every-schools-find.md diff --git a/.changeset/every-schools-find.md b/.changeset/every-schools-find.md new file mode 100644 index 0000000000..b4cb15bf52 --- /dev/null +++ b/.changeset/every-schools-find.md @@ -0,0 +1,20 @@ +--- +'@backstage/plugin-catalog-unprocessed-entities': patch +'@backstage/frontend-app-api': patch +'@backstage/core-compat-api': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-notifications': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-signals': patch +'@backstage/plugin-search': patch +'@backstage/plugin-home': patch +'@backstage/plugin-app': patch +--- + +Internal update to use the new variant of `ApiBlueprint`. diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx index 425f3684b6..e0705df307 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -310,7 +310,7 @@ export function collectLegacyRoutes( ...Array.from(plugin.getApis()).map(factory => ApiBlueprint.make({ name: factory.api.id, - params: { factory }, + params: define => define(factory), }), ), ], diff --git a/packages/core-compat-api/src/convertLegacyApp.test.tsx b/packages/core-compat-api/src/convertLegacyApp.test.tsx index 8a48042934..5742c80487 100644 --- a/packages/core-compat-api/src/convertLegacyApp.test.tsx +++ b/packages/core-compat-api/src/convertLegacyApp.test.tsx @@ -232,31 +232,32 @@ describe('convertLegacyApp', () => { const catalogOverride = catalogPlugin.withOverrides({ extensions: [ catalogPlugin.getExtension('api:catalog').override({ - params: { - factory: createApiFactory( - catalogApiRef, - catalogApiMock({ - entities: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'test', - metadata: { - name: 'x', + params: define => + define({ + api: catalogApiRef, + deps: {}, + factory: () => + catalogApiMock({ + entities: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'test', + metadata: { + name: 'x', + }, + spec: {}, }, - spec: {}, - }, - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'other', - metadata: { - name: 'x', + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'other', + metadata: { + name: 'x', + }, + spec: {}, }, - spec: {}, - }, - ], - }), - ), - }, + ], + }), + }), }), ], }); diff --git a/packages/core-compat-api/src/convertLegacyAppOptions.tsx b/packages/core-compat-api/src/convertLegacyAppOptions.tsx index 56aec7c1c5..c98875464c 100644 --- a/packages/core-compat-api/src/convertLegacyAppOptions.tsx +++ b/packages/core-compat-api/src/convertLegacyAppOptions.tsx @@ -74,7 +74,10 @@ export function convertLegacyAppOptions( new Map(allApis.map(api => [api.api.id, api])).values(), ); const extensions: ExtensionDefinition[] = deduplicatedApis.map(factory => - ApiBlueprint.make({ name: factory.api.id, params: { factory } }), + ApiBlueprint.make({ + name: factory.api.id, + params: define => define(factory), + }), ); if (icons) { diff --git a/packages/core-compat-api/src/convertLegacyPlugin.ts b/packages/core-compat-api/src/convertLegacyPlugin.ts index bf315563ef..952b50a836 100644 --- a/packages/core-compat-api/src/convertLegacyPlugin.ts +++ b/packages/core-compat-api/src/convertLegacyPlugin.ts @@ -29,7 +29,10 @@ export function convertLegacyPlugin( options: { extensions: ExtensionDefinition[] }, ): NewBackstagePlugin { const apiExtensions = Array.from(legacyPlugin.getApis()).map(factory => - ApiBlueprint.make({ name: factory.api.id, params: { factory } }), + ApiBlueprint.make({ + name: factory.api.id, + params: define => define(factory), + }), ); return createFrontendPlugin({ pluginId: legacyPlugin.getId(), diff --git a/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx b/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx index 7c6bb7958b..c9ff9fabd5 100644 --- a/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx @@ -31,11 +31,7 @@ import { import { screen, render } from '@testing-library/react'; import { createSpecializedApp } from './createSpecializedApp'; import { mockApis, TestApiRegistry } from '@backstage/test-utils'; -import { - configApiRef, - createApiFactory, - featureFlagsApiRef, -} from '@backstage/core-plugin-api'; +import { configApiRef, featureFlagsApiRef } from '@backstage/core-plugin-api'; import { MemoryRouter } from 'react-router-dom'; import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; import { Fragment } from 'react'; @@ -148,16 +144,20 @@ describe('createSpecializedApp', () => { ], }), ApiBlueprint.make({ - params: { - factory: createApiFactory(featureFlagsApiRef, { - registerFlag(flag) { - flags.push(flag); - }, - getRegisteredFlags() { - return flags; - }, - } as typeof featureFlagsApiRef.T), - }, + params: define => + define({ + api: featureFlagsApiRef, + deps: {}, + factory: () => + ({ + registerFlag(flag) { + flags.push(flag); + }, + getRegisteredFlags() { + return flags; + }, + } as typeof featureFlagsApiRef.T), + }), }), ], }), @@ -253,15 +253,14 @@ describe('createSpecializedApp', () => { pluginId: 'first', extensions: [ ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: analyticsApiRef, deps: {}, factory: () => { throw new Error('BROKEN'); }, }), - }, }), ], }), @@ -295,13 +294,12 @@ describe('createSpecializedApp', () => { }, }), ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: analyticsApiRef, deps: {}, factory: mockAnalyticsApi, }), - }, }), ], }), diff --git a/plugins/api-docs/report-alpha.api.md b/plugins/api-docs/report-alpha.api.md index b13fca4996..f0a65d45c8 100644 --- a/plugins/api-docs/report-alpha.api.md +++ b/plugins/api-docs/report-alpha.api.md @@ -6,6 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; @@ -73,9 +75,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'entity-card:api-docs/consumed-apis': ExtensionDefinition<{ kind: 'entity-card'; diff --git a/plugins/api-docs/src/alpha.tsx b/plugins/api-docs/src/alpha.tsx index 356328a61d..4ff73f0e26 100644 --- a/plugins/api-docs/src/alpha.tsx +++ b/plugins/api-docs/src/alpha.tsx @@ -20,7 +20,6 @@ import { ApiBlueprint, NavItemBlueprint, PageBlueprint, - createApiFactory, createFrontendPlugin, } from '@backstage/frontend-plugin-api'; @@ -55,8 +54,8 @@ const apiDocsNavItem = NavItemBlueprint.make({ const apiDocsConfigApi = ApiBlueprint.make({ name: 'config', - params: { - factory: createApiFactory({ + params: define => + define({ api: apiDocsConfigRef, deps: {}, factory: () => { @@ -68,7 +67,6 @@ const apiDocsConfigApi = ApiBlueprint.make({ }; }, }), - }, }); const apiDocsExplorerPage = PageBlueprint.makeWithOverrides({ diff --git a/plugins/app/report.api.md b/plugins/app/report.api.md index 027b6365b5..df1f47a68b 100644 --- a/plugins/app/report.api.md +++ b/plugins/app/report.api.md @@ -6,7 +6,9 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { AppTheme } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ComponentRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; @@ -222,9 +224,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/analytics': ExtensionDefinition<{ kind: 'api'; @@ -237,9 +243,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/app-language': ExtensionDefinition<{ kind: 'api'; @@ -252,9 +262,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/app-theme': ExtensionDefinition<{ config: {}; @@ -275,9 +289,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'app-theme'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/atlassian-auth': ExtensionDefinition<{ kind: 'api'; @@ -290,9 +308,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/bitbucket-auth': ExtensionDefinition<{ kind: 'api'; @@ -305,9 +327,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/bitbucket-server-auth': ExtensionDefinition<{ kind: 'api'; @@ -320,9 +346,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/components': ExtensionDefinition<{ config: {}; @@ -350,9 +380,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'components'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/dialog': ExtensionDefinition<{ kind: 'api'; @@ -365,9 +399,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/discovery': ExtensionDefinition<{ kind: 'api'; @@ -380,9 +418,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/error': ExtensionDefinition<{ kind: 'api'; @@ -395,9 +437,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/feature-flags': ExtensionDefinition<{ kind: 'api'; @@ -410,9 +456,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/fetch': ExtensionDefinition<{ kind: 'api'; @@ -425,9 +475,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/github-auth': ExtensionDefinition<{ kind: 'api'; @@ -440,9 +494,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/gitlab-auth': ExtensionDefinition<{ kind: 'api'; @@ -455,9 +513,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/google-auth': ExtensionDefinition<{ kind: 'api'; @@ -470,9 +532,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/icons': ExtensionDefinition<{ config: {}; @@ -499,9 +565,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'icons'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/microsoft-auth': ExtensionDefinition<{ kind: 'api'; @@ -514,9 +584,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/oauth-request': ExtensionDefinition<{ kind: 'api'; @@ -529,9 +603,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/okta-auth': ExtensionDefinition<{ kind: 'api'; @@ -544,9 +622,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/onelogin-auth': ExtensionDefinition<{ kind: 'api'; @@ -559,9 +641,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/permission': ExtensionDefinition<{ kind: 'api'; @@ -574,9 +660,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/scm-auth': ExtensionDefinition<{ kind: 'api'; @@ -589,9 +679,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/scm-integrations': ExtensionDefinition<{ kind: 'api'; @@ -604,9 +698,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/storage': ExtensionDefinition<{ kind: 'api'; @@ -619,9 +717,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/translations': ExtensionDefinition<{ config: {}; @@ -653,9 +755,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'translations'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:app/vmware-cloud-auth': ExtensionDefinition<{ kind: 'api'; @@ -668,9 +774,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'app-root-element:app/alert-display': ExtensionDefinition<{ config: { diff --git a/plugins/app/src/defaultApis.ts b/plugins/app/src/defaultApis.ts index 535be78e05..4da28b44a6 100644 --- a/plugins/app/src/defaultApis.ts +++ b/plugins/app/src/defaultApis.ts @@ -39,7 +39,6 @@ import { } from '../../../packages/core-app-api/src/apis/implementations'; import { - createApiFactory, alertApiRef, analyticsApiRef, errorApiRef, @@ -75,18 +74,17 @@ import { DefaultDialogApi } from './apis/DefaultDialogApi'; export const apis = [ ApiBlueprint.make({ name: 'dialog', - params: { - factory: createApiFactory({ + params: define => + define({ api: dialogApiRef, deps: {}, factory: () => new DefaultDialogApi(), }), - }, }), ApiBlueprint.make({ name: 'discovery', - params: { - factory: createApiFactory({ + params: define => + define({ api: discoveryApiRef, deps: { configApi: configApiRef }, factory: ({ configApi }) => @@ -94,32 +92,29 @@ export const apis = [ `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`, ), }), - }, }), ApiBlueprint.make({ name: 'alert', - params: { - factory: createApiFactory({ + params: define => + define({ api: alertApiRef, deps: {}, factory: () => new AlertApiForwarder(), }), - }, }), ApiBlueprint.make({ name: 'analytics', - params: { - factory: createApiFactory({ + params: define => + define({ api: analyticsApiRef, deps: {}, factory: () => new NoOpAnalyticsApi(), }), - }, }), ApiBlueprint.make({ name: 'error', - params: { - factory: createApiFactory({ + params: define => + define({ api: errorApiRef, deps: { alertApi: alertApiRef }, factory: ({ alertApi }) => { @@ -128,22 +123,20 @@ export const apis = [ return errorApi; }, }), - }, }), ApiBlueprint.make({ name: 'storage', - params: { - factory: createApiFactory({ + params: define => + define({ api: storageApiRef, deps: { errorApi: errorApiRef }, factory: ({ errorApi }) => WebStorage.create({ errorApi }), }), - }, }), ApiBlueprint.make({ name: 'fetch', - params: { - factory: createApiFactory({ + params: define => + define({ api: fetchApiRef, deps: { configApi: configApiRef, @@ -164,22 +157,20 @@ export const apis = [ }); }, }), - }, }), ApiBlueprint.make({ name: 'oauth-request', - params: { - factory: createApiFactory({ + params: define => + define({ api: oauthRequestApiRef, deps: {}, factory: () => new OAuthRequestManager(), }), - }, }), ApiBlueprint.make({ name: 'google-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: googleAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -194,12 +185,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'microsoft-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: microsoftAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -214,12 +204,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'github-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: githubAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -235,12 +224,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'okta-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: oktaAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -255,12 +243,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'gitlab-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: gitlabAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -275,12 +262,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'onelogin-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: oneloginAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -295,12 +281,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'bitbucket-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: bitbucketAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -316,12 +301,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'bitbucket-server-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: bitbucketServerAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -337,12 +321,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'atlassian-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: atlassianAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -358,12 +341,11 @@ export const apis = [ }); }, }), - }, }), ApiBlueprint.make({ name: 'vmware-cloud-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: vmwareCloudAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -379,12 +361,11 @@ export const apis = [ }); }, }), - }, }), ApiBlueprint.make({ name: 'permission', - params: { - factory: createApiFactory({ + params: define => + define({ api: permissionApiRef, deps: { discovery: discoveryApiRef, @@ -394,22 +375,18 @@ export const apis = [ factory: ({ config, discovery, identity }) => IdentityPermissionApi.create({ config, discovery, identity }), }), - }, }), ApiBlueprint.make({ name: 'scm-auth', - params: { - factory: ScmAuth.createDefaultApiFactory(), - }, + params: define => define(ScmAuth.createDefaultApiFactory()), }), ApiBlueprint.make({ name: 'scm-integrations', - params: { - factory: createApiFactory({ + params: define => + define({ api: scmIntegrationsApiRef, deps: { configApi: configApiRef }, factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), }), - }, }), ] as const; diff --git a/plugins/app/src/extensions/AppLanguageApi.ts b/plugins/app/src/extensions/AppLanguageApi.ts index 7a6c10db96..96d19a578a 100644 --- a/plugins/app/src/extensions/AppLanguageApi.ts +++ b/plugins/app/src/extensions/AppLanguageApi.ts @@ -17,14 +17,14 @@ // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppLanguageSelector } from '../../../../packages/core-app-api/src/apis/implementations/AppLanguageApi'; import { appLanguageApiRef } from '@backstage/core-plugin-api/alpha'; -import { ApiBlueprint, createApiFactory } from '@backstage/frontend-plugin-api'; +import { ApiBlueprint } from '@backstage/frontend-plugin-api'; export const AppLanguageApi = ApiBlueprint.make({ name: 'app-language', - params: { - factory: createApiFactory( - appLanguageApiRef, - AppLanguageSelector.createWithStorage(), - ), - }, + params: define => + define({ + api: appLanguageApiRef, + deps: {}, + factory: () => AppLanguageSelector.createWithStorage(), + }), }); diff --git a/plugins/app/src/extensions/AppThemeApi.tsx b/plugins/app/src/extensions/AppThemeApi.tsx index 2d35a50cd5..670c4504c6 100644 --- a/plugins/app/src/extensions/AppThemeApi.tsx +++ b/plugins/app/src/extensions/AppThemeApi.tsx @@ -24,7 +24,6 @@ import { createExtensionInput, ThemeBlueprint, ApiBlueprint, - createApiFactory, appThemeApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -41,14 +40,16 @@ export const AppThemeApi = ApiBlueprint.makeWithOverrides({ }), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory( - appThemeApiRef, - AppThemeSelector.createWithStorage( - inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)), - ), - ), - }); + return originalFactory(define => + define({ + api: appThemeApiRef, + deps: {}, + factory: () => + AppThemeSelector.createWithStorage( + inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)), + ), + }), + ); }, }); diff --git a/plugins/app/src/extensions/ComponentsApi.tsx b/plugins/app/src/extensions/ComponentsApi.tsx index b578429253..fa14d28b10 100644 --- a/plugins/app/src/extensions/ComponentsApi.tsx +++ b/plugins/app/src/extensions/ComponentsApi.tsx @@ -18,7 +18,6 @@ import { createComponentExtension, createExtensionInput, ApiBlueprint, - createApiFactory, componentsApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -36,15 +35,17 @@ export const ComponentsApi = ApiBlueprint.makeWithOverrides({ ), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory( - componentsApiRef, - DefaultComponentsApi.fromComponents( - inputs.components.map(i => - i.get(createComponentExtension.componentDataRef), + return originalFactory(define => + define({ + api: componentsApiRef, + deps: {}, + factory: () => + DefaultComponentsApi.fromComponents( + inputs.components.map(i => + i.get(createComponentExtension.componentDataRef), + ), ), - ), - ), - }); + }), + ); }, }); diff --git a/plugins/app/src/extensions/FeatureFlagsApi.ts b/plugins/app/src/extensions/FeatureFlagsApi.ts index 40a44d1348..1a2eff0084 100644 --- a/plugins/app/src/extensions/FeatureFlagsApi.ts +++ b/plugins/app/src/extensions/FeatureFlagsApi.ts @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, featureFlagsApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -27,12 +26,11 @@ import { LocalStorageFeatureFlags } from '../../../../packages/core-app-api/src/ */ export const FeatureFlagsApi = ApiBlueprint.make({ name: 'feature-flags', - params: { - // TODO: properly discovery feature flags, maybe rework the whole thing - factory: createApiFactory({ + params: define => + define({ + // TODO: properly discovery feature flags, maybe rework the whole thing api: featureFlagsApiRef, deps: {}, factory: () => new LocalStorageFeatureFlags(), }), - }, }); diff --git a/plugins/app/src/extensions/IconsApi.ts b/plugins/app/src/extensions/IconsApi.ts index e73a74132a..9457652870 100644 --- a/plugins/app/src/extensions/IconsApi.ts +++ b/plugins/app/src/extensions/IconsApi.ts @@ -18,7 +18,6 @@ import { createExtensionInput, IconBundleBlueprint, ApiBlueprint, - createApiFactory, iconsApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -37,15 +36,17 @@ export const IconsApi = ApiBlueprint.makeWithOverrides({ }), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory( - iconsApiRef, - new DefaultIconsApi( - inputs.icons - .map(i => i.get(IconBundleBlueprint.dataRefs.icons)) - .reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons), - ), - ), - }); + return originalFactory(define => + define({ + api: iconsApiRef, + deps: {}, + factory: () => + new DefaultIconsApi( + inputs.icons + .map(i => i.get(IconBundleBlueprint.dataRefs.icons)) + .reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons), + ), + }), + ); }, }); diff --git a/plugins/app/src/extensions/TranslationsApi.tsx b/plugins/app/src/extensions/TranslationsApi.tsx index ed7ab1abdb..d95c333e8b 100644 --- a/plugins/app/src/extensions/TranslationsApi.tsx +++ b/plugins/app/src/extensions/TranslationsApi.tsx @@ -16,7 +16,6 @@ import { ApiBlueprint, TranslationBlueprint, - createApiFactory, createExtensionInput, } from '@backstage/frontend-plugin-api'; import { @@ -39,8 +38,8 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({ ), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory({ + return originalFactory(define => + define({ api: translationApiRef, deps: { languageApi: appLanguageApiRef }, factory: ({ languageApi }) => @@ -51,6 +50,6 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({ ), }), }), - }); + ); }, }); diff --git a/plugins/catalog-import/report-alpha.api.md b/plugins/catalog-import/report-alpha.api.md index 229c2ff10c..31192683bd 100644 --- a/plugins/catalog-import/report-alpha.api.md +++ b/plugins/catalog-import/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/core-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -103,9 +105,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'page:catalog-import': ExtensionDefinition<{ kind: 'page'; diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx index 17260acc14..6f96bfbed1 100644 --- a/plugins/catalog-import/src/alpha.tsx +++ b/plugins/catalog-import/src/alpha.tsx @@ -16,7 +16,6 @@ import { configApiRef, - createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; @@ -53,8 +52,8 @@ const catalogImportPage = PageBlueprint.make({ }); const catalogImportApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: catalogImportApiRef, deps: { discoveryApi: discoveryApiRef, @@ -81,7 +80,6 @@ const catalogImportApi = ApiBlueprint.make({ configApi, }), }), - }, }); /** @alpha */ diff --git a/plugins/catalog-unprocessed-entities/report-alpha.api.md b/plugins/catalog-unprocessed-entities/report-alpha.api.md index 8b53bcb8ae..b742ece07c 100644 --- a/plugins/catalog-unprocessed-entities/report-alpha.api.md +++ b/plugins/catalog-unprocessed-entities/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -30,9 +32,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'nav-item:catalog-unprocessed-entities': ExtensionDefinition<{ kind: 'nav-item'; diff --git a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx index 34a40b23d7..cfe81eccc8 100644 --- a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx +++ b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx @@ -15,7 +15,6 @@ */ import { - createApiFactory, createFrontendPlugin, discoveryApiRef, fetchApiRef, @@ -37,8 +36,8 @@ import { rootRouteRef } from '../routes'; /** @alpha */ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: catalogUnprocessedEntitiesApiRef, deps: { discoveryApi: discoveryApiRef, @@ -47,7 +46,6 @@ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({ factory: ({ discoveryApi, fetchApi }) => new CatalogUnprocessedEntitiesClient(discoveryApi, fetchApi), }), - }, }); /** @alpha */ diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md index 81ebd10c3b..369b666905 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -6,6 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; @@ -146,9 +148,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:catalog/entity-presentation': ExtensionDefinition<{ kind: 'api'; @@ -161,9 +167,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:catalog/starred-entities': ExtensionDefinition<{ kind: 'api'; @@ -176,9 +186,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'catalog-filter:catalog/kind': ExtensionDefinition<{ config: { diff --git a/plugins/catalog/src/alpha/apis.tsx b/plugins/catalog/src/alpha/apis.tsx index d0f80c3aec..6bfa0a124b 100644 --- a/plugins/catalog/src/alpha/apis.tsx +++ b/plugins/catalog/src/alpha/apis.tsx @@ -15,7 +15,6 @@ */ import { - createApiFactory, discoveryApiRef, fetchApiRef, storageApiRef, @@ -33,8 +32,8 @@ import { } from '../apis'; export const catalogApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: catalogApiRef, deps: { discoveryApi: discoveryApiRef, @@ -43,31 +42,28 @@ export const catalogApi = ApiBlueprint.make({ factory: ({ discoveryApi, fetchApi }) => new CatalogClient({ discoveryApi, fetchApi }), }), - }, }); export const catalogStarredEntitiesApi = ApiBlueprint.make({ name: 'starred-entities', - params: { - factory: createApiFactory({ + params: define => + define({ api: starredEntitiesApiRef, deps: { storageApi: storageApiRef }, factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), }), - }, }); export const entityPresentationApi = ApiBlueprint.make({ name: 'entity-presentation', - params: { - factory: createApiFactory({ + params: define => + define({ api: entityPresentationApiRef, deps: { catalogApiImp: catalogApiRef }, factory: ({ catalogApiImp }) => DefaultEntityPresentationApi.create({ catalogApi: catalogApiImp }), }), - }, }); export default [catalogApi, catalogStarredEntitiesApi, entityPresentationApi]; diff --git a/plugins/devtools/report-alpha.api.md b/plugins/devtools/report-alpha.api.md index 663c4be34d..0b6b41ce3b 100644 --- a/plugins/devtools/report-alpha.api.md +++ b/plugins/devtools/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -30,9 +32,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'nav-item:devtools': ExtensionDefinition<{ kind: 'nav-item'; diff --git a/plugins/devtools/src/alpha/plugin.tsx b/plugins/devtools/src/alpha/plugin.tsx index 52caaf4786..d2f09521dd 100644 --- a/plugins/devtools/src/alpha/plugin.tsx +++ b/plugins/devtools/src/alpha/plugin.tsx @@ -15,7 +15,6 @@ */ import { - createApiFactory, createFrontendPlugin, discoveryApiRef, fetchApiRef, @@ -34,8 +33,8 @@ import { rootRouteRef } from '../routes'; /** @alpha */ export const devToolsApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: devToolsApiRef, deps: { discoveryApi: discoveryApiRef, @@ -44,7 +43,6 @@ export const devToolsApi = ApiBlueprint.make({ factory: ({ discoveryApi, fetchApi }) => new DevToolsClient({ discoveryApi, fetchApi }), }), - }, }); /** @alpha */ diff --git a/plugins/home/report-alpha.api.md b/plugins/home/report-alpha.api.md index c7fcf8ab67..17ca91ca2a 100644 --- a/plugins/home/report-alpha.api.md +++ b/plugins/home/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; @@ -31,9 +33,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'app-root-element:home/visit-listener': ExtensionDefinition<{ kind: 'app-root-element'; diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index 0d5b0fb94c..d093f353a2 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -24,7 +24,6 @@ import { AppRootElementBlueprint, identityApiRef, storageApiRef, - createApiFactory, ApiBlueprint, } from '@backstage/frontend-plugin-api'; import { compatWrapper } from '@backstage/core-compat-api'; @@ -79,8 +78,8 @@ const visitListenerAppRootElement = AppRootElementBlueprint.make({ const visitsApi = ApiBlueprint.make({ name: 'visits', - params: { - factory: createApiFactory({ + params: define => + define({ api: visitsApiRef, deps: { storageApi: storageApiRef, @@ -89,7 +88,6 @@ const visitsApi = ApiBlueprint.make({ factory: ({ storageApi, identityApi }) => VisitsStorageApi.create({ storageApi, identityApi }), }), - }, }); /** diff --git a/plugins/kubernetes/report-alpha.api.md b/plugins/kubernetes/report-alpha.api.md index e6cc199ae8..6971e1b1e0 100644 --- a/plugins/kubernetes/report-alpha.api.md +++ b/plugins/kubernetes/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; @@ -33,9 +35,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:kubernetes/auth-providers': ExtensionDefinition<{ kind: 'api'; @@ -48,9 +54,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:kubernetes/cluster-link-formatter': ExtensionDefinition<{ kind: 'api'; @@ -63,9 +73,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:kubernetes/proxy': ExtensionDefinition<{ kind: 'api'; @@ -78,9 +92,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'entity-content:kubernetes/kubernetes': ExtensionDefinition<{ kind: 'entity-content'; diff --git a/plugins/kubernetes/src/alpha/apis.tsx b/plugins/kubernetes/src/alpha/apis.tsx index 082a2da6c7..c57e9a1482 100644 --- a/plugins/kubernetes/src/alpha/apis.tsx +++ b/plugins/kubernetes/src/alpha/apis.tsx @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/frontend-plugin-api'; @@ -41,8 +40,8 @@ import { } from '@backstage/core-plugin-api'; export const kubernetesApiExtension = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesApiRef, deps: { discoveryApi: discoveryApiRef, @@ -56,13 +55,12 @@ export const kubernetesApiExtension = ApiBlueprint.make({ kubernetesAuthProvidersApi, }), }), - }, }); export const kubernetesProxyApi = ApiBlueprint.make({ name: 'proxy', - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesProxyApiRef, deps: { kubernetesApi: kubernetesApiRef, @@ -72,13 +70,12 @@ export const kubernetesProxyApi = ApiBlueprint.make({ kubernetesApi, }), }), - }, }); export const kubernetesAuthProvidersApi = ApiBlueprint.make({ name: 'auth-providers', - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesAuthProvidersApiRef, deps: { gitlabAuthApi: gitlabAuthApiRef, @@ -109,13 +106,12 @@ export const kubernetesAuthProvidersApi = ApiBlueprint.make({ }); }, }), - }, }); export const kubernetesClusterLinkFormatterApi = ApiBlueprint.make({ name: 'cluster-link-formatter', - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesClusterLinkFormatterApiRef, deps: { googleAuthApi: googleAuthApiRef }, factory: deps => { @@ -126,5 +122,4 @@ export const kubernetesClusterLinkFormatterApi = ApiBlueprint.make({ }); }, }), - }, }); diff --git a/plugins/notifications/report-alpha.api.md b/plugins/notifications/report-alpha.api.md index 734dd0a201..210ee8ac4f 100644 --- a/plugins/notifications/report-alpha.api.md +++ b/plugins/notifications/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -29,9 +31,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'page:notifications': ExtensionDefinition<{ kind: 'page'; diff --git a/plugins/notifications/src/alpha.tsx b/plugins/notifications/src/alpha.tsx index 4424659593..68d0ccab8d 100644 --- a/plugins/notifications/src/alpha.tsx +++ b/plugins/notifications/src/alpha.tsx @@ -17,7 +17,6 @@ import { ApiBlueprint, PageBlueprint, - createApiFactory, createFrontendPlugin, discoveryApiRef, fetchApiRef, @@ -41,14 +40,13 @@ const page = PageBlueprint.make({ }); const api = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: notificationsApiRef, deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, factory: ({ discoveryApi, fetchApi }) => new NotificationsClient({ discoveryApi, fetchApi }), }), - }, }); /** @alpha */ diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index 2014bff9be..ea8a864138 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -5,8 +5,10 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; @@ -218,9 +220,13 @@ export const formFieldsApi: ExtensionDefinition<{ }; kind: 'api'; name: 'form-fields'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; // @alpha @deprecated (undocumented) diff --git a/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts index 7712b91a18..d66c27980d 100644 --- a/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts +++ b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, createExtensionInput, } from '@backstage/frontend-plugin-api'; import { formFieldsApiRef } from './ref'; @@ -53,12 +52,12 @@ export const formFieldsApi = ApiBlueprint.makeWithOverrides({ e.get(FormFieldBlueprint.dataRefs.formFieldLoader), ); - return originalFactory({ - factory: createApiFactory({ + return originalFactory(define => + define({ api: formFieldsApiRef, deps: {}, factory: () => new DefaultScaffolderFormFieldsApi(formFieldLoaders), }), - }); + ); }, }); diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 509cfa8497..55c90ddb1b 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -5,7 +5,9 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; @@ -66,9 +68,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:scaffolder/form-decorators': ExtensionDefinition<{ config: {}; @@ -93,9 +99,13 @@ const _default: FrontendPlugin< }; kind: 'api'; name: 'form-decorators'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:scaffolder/form-fields': ExtensionDefinition<{ config: {}; @@ -120,9 +130,13 @@ const _default: FrontendPlugin< }; kind: 'api'; name: 'form-fields'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'entity-icon-link:scaffolder/launch-template': ExtensionDefinition<{ kind: 'entity-icon-link'; @@ -273,9 +287,13 @@ export const formDecoratorsApi: ExtensionDefinition<{ }; kind: 'api'; name: 'form-decorators'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; // @alpha (undocumented) diff --git a/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts index 41bf91dba0..4ae975ec5a 100644 --- a/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts +++ b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, createExtensionInput, } from '@backstage/frontend-plugin-api'; import { ScaffolderFormDecoratorsApi } from './types'; @@ -58,8 +57,8 @@ export const formDecoratorsApi = ApiBlueprint.makeWithOverrides({ e.get(FormDecoratorBlueprint.dataRefs.formDecoratorLoader), ); - return originalFactory({ - factory: createApiFactory({ + return originalFactory(define => + define({ api: formDecoratorsApiRef, deps: {}, factory: () => @@ -67,6 +66,6 @@ export const formDecoratorsApi = ApiBlueprint.makeWithOverrides({ decorators: formDecorators, }), }), - }); + ); }, }); diff --git a/plugins/scaffolder/src/alpha/extensions.tsx b/plugins/scaffolder/src/alpha/extensions.tsx index 7c82edc97f..351ad4ed56 100644 --- a/plugins/scaffolder/src/alpha/extensions.tsx +++ b/plugins/scaffolder/src/alpha/extensions.tsx @@ -22,7 +22,6 @@ import { NavItemBlueprint, PageBlueprint, ApiBlueprint, - createApiFactory, discoveryApiRef, fetchApiRef, identityApiRef, @@ -74,8 +73,8 @@ export const repoUrlPickerFormField = FormFieldBlueprint.make({ }); export const scaffolderApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: scaffolderApiRef, deps: { discoveryApi: discoveryApiRef, @@ -91,5 +90,4 @@ export const scaffolderApi = ApiBlueprint.make({ identityApi, }), }), - }, }); diff --git a/plugins/search/report-alpha.api.md b/plugins/search/report-alpha.api.md index 3af0384d89..f7916a8467 100644 --- a/plugins/search/report-alpha.api.md +++ b/plugins/search/report-alpha.api.md @@ -5,6 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/core-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; @@ -35,9 +37,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'nav-item:search': ExtensionDefinition<{ kind: 'nav-item'; @@ -145,9 +151,13 @@ export const searchApi: ExtensionDefinition<{ configInput: {}; output: ConfigurableExtensionDataRef; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; // @alpha (undocumented) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 136f95f39e..5028a404d4 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -31,7 +31,6 @@ import { useApi, discoveryApiRef, fetchApiRef, - createApiFactory, } from '@backstage/core-plugin-api'; import { @@ -77,14 +76,13 @@ import { /** @alpha */ export const searchApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: searchApiRef, deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, factory: ({ discoveryApi, fetchApi }) => new SearchClient({ discoveryApi, fetchApi }), }), - }, }); const useSearchPageStyles = makeStyles((theme: Theme) => ({ diff --git a/plugins/signals/report-alpha.api.md b/plugins/signals/report-alpha.api.md index 3fc89308c1..a0b8dfe18f 100644 --- a/plugins/signals/report-alpha.api.md +++ b/plugins/signals/report-alpha.api.md @@ -4,6 +4,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -25,9 +27,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'app-root-element:signals/signals-display': ExtensionDefinition<{ kind: 'app-root-element'; diff --git a/plugins/signals/src/alpha.tsx b/plugins/signals/src/alpha.tsx index 38955473e1..340425bebd 100644 --- a/plugins/signals/src/alpha.tsx +++ b/plugins/signals/src/alpha.tsx @@ -17,7 +17,6 @@ import { ApiBlueprint, AppRootElementBlueprint, - createApiFactory, createFrontendPlugin, discoveryApiRef, identityApiRef, @@ -28,8 +27,8 @@ import { SignalsDisplay } from './plugin'; import { compatWrapper } from '@backstage/core-compat-api'; const api = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: signalApiRef, deps: { identity: identityApiRef, @@ -42,7 +41,6 @@ const api = ApiBlueprint.make({ }); }, }), - }, }); const signalsDisplayAppRootElement = AppRootElementBlueprint.make({ diff --git a/plugins/techdocs/report-alpha.api.md b/plugins/techdocs/report-alpha.api.md index ce1d10a00c..ce5e06a35c 100644 --- a/plugins/techdocs/report-alpha.api.md +++ b/plugins/techdocs/report-alpha.api.md @@ -6,6 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; +import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; @@ -46,9 +48,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'api:techdocs/storage': ExtensionDefinition<{ kind: 'api'; @@ -61,9 +67,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => BlueprintParams; }>; 'empty-state:techdocs/entity-content': ExtensionDefinition<{ config: {}; diff --git a/plugins/techdocs/src/alpha/index.tsx b/plugins/techdocs/src/alpha/index.tsx index 44205a480a..38dcd40dc4 100644 --- a/plugins/techdocs/src/alpha/index.tsx +++ b/plugins/techdocs/src/alpha/index.tsx @@ -26,7 +26,6 @@ import { } from '@backstage/frontend-plugin-api'; import { configApiRef, - createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; @@ -68,8 +67,8 @@ const techdocsEntityIconLink = EntityIconLinkBlueprint.make({ /** @alpha */ const techDocsStorageApi = ApiBlueprint.make({ name: 'storage', - params: { - factory: createApiFactory({ + params: define => + define({ api: techdocsStorageApiRef, deps: { configApi: configApiRef, @@ -83,13 +82,12 @@ const techDocsStorageApi = ApiBlueprint.make({ fetchApi, }), }), - }, }); /** @alpha */ const techDocsClientApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: techdocsApiRef, deps: { configApi: configApiRef, @@ -103,7 +101,6 @@ const techDocsClientApi = ApiBlueprint.make({ fetchApi, }), }), - }, }); /** @alpha */ From 45f1b9fdce2b2e1407883f030226055207027c13 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Jul 2025 22:23:58 +0200 Subject: [PATCH 05/11] frontend-plugin-api: type cleanup, docs, and API reports for advanced blueprint types Signed-off-by: Patrik Oldsberg --- packages/frontend-plugin-api/report.api.md | 82 ++++++++-- .../src/wiring/createExtension.ts | 34 ++-- .../src/wiring/createExtensionBlueprint.ts | 147 +++++++++++++----- .../frontend-plugin-api/src/wiring/index.ts | 3 + plugins/api-docs/report-alpha.api.md | 4 +- plugins/app/report.api.md | 56 +++---- plugins/catalog-import/report-alpha.api.md | 4 +- .../report-alpha.api.md | 4 +- plugins/catalog/report-alpha.api.md | 8 +- plugins/devtools/report-alpha.api.md | 4 +- plugins/home/report-alpha.api.md | 4 +- plugins/kubernetes/report-alpha.api.md | 10 +- plugins/notifications/report-alpha.api.md | 4 +- plugins/scaffolder-react/report-alpha.api.md | 4 +- plugins/scaffolder/report-alpha.api.md | 10 +- plugins/search/report-alpha.api.md | 6 +- plugins/signals/report-alpha.api.md | 4 +- plugins/techdocs/report-alpha.api.md | 6 +- 18 files changed, 264 insertions(+), 130 deletions(-) diff --git a/packages/frontend-plugin-api/report.api.md b/packages/frontend-plugin-api/report.api.md index cd8f3d02ce..8ae1960221 100644 --- a/packages/frontend-plugin-api/report.api.md +++ b/packages/frontend-plugin-api/report.api.md @@ -179,9 +179,13 @@ export type AnyRoutes = { export const ApiBlueprint: ExtensionBlueprint<{ kind: 'api'; name: undefined; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; output: ConfigurableExtensionDataRef; inputs: {}; config: {}; @@ -519,7 +523,7 @@ export function createExtension< // @public export function createExtensionBlueprint< - TParams extends object, + TParams extends object | ExtensionBlueprintParamsDefiner, UOutput extends AnyExtensionDataRef, TInputs extends { [inputName in string]: ExtensionInput< @@ -575,7 +579,7 @@ export function createExtensionBlueprint< export type CreateExtensionBlueprintOptions< TKind extends string, TName extends string | undefined, - TParams, + TParams extends object | ExtensionBlueprintParamsDefiner, UOutput extends AnyExtensionDataRef, TInputs extends { [inputName in string]: ExtensionInput< @@ -603,8 +607,13 @@ export type CreateExtensionBlueprintOptions< config?: { schema: TConfigSchema; }; + defineParams?: TParams extends ExtensionBlueprintParamsDefiner + ? TParams + : 'The defineParams option must be a function if provided, see the docs for details'; factory( - params: TParams, + params: TParams extends ExtensionBlueprintParamsDefiner + ? ReturnType['T'] + : TParams, context: { node: AppNode; apis: ApiHolder; @@ -617,6 +626,11 @@ export type CreateExtensionBlueprintOptions< dataRefs?: TDataRefs; } & VerifyExtensionFactoryOutput; +// @public +export function createExtensionBlueprintParams( + params: T, +): ExtensionBlueprintParams; + // @public (undocumented) export function createExtensionDataRef(): { with(options: { @@ -911,11 +925,18 @@ export interface ExtensionBlueprint< // (undocumented) dataRefs: T['dataRefs']; // (undocumented) - make(args: { + make< + TNewName extends string | undefined, + TParamsInput extends AnyParamsInput_2>, + >(args: { name?: TNewName; attachTo?: ExtensionAttachToSpec; disabled?: boolean; - params: T['params']; + params: TParamsInput extends ExtensionBlueprintParamsDefiner + ? TParamsInput + : T['params'] extends ExtensionBlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `.make({ params: define => define() })`' + : TParamsInput; }): ExtensionDefinition<{ kind: T['kind']; name: string | undefined extends TNewName ? T['name'] : TNewName; @@ -957,8 +978,14 @@ export interface ExtensionBlueprint< }; }; factory( - originalFactory: ( - params: T['params'], + originalFactory: < + TParamsInput extends AnyParamsInput_2>, + >( + params: TParamsInput extends ExtensionBlueprintParamsDefiner + ? TParamsInput + : T['params'] extends ExtensionBlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' + : TParamsInput, context?: { config?: T['config']; inputs?: ResolveInputValueOverrides>; @@ -1012,7 +1039,7 @@ export interface ExtensionBlueprint< export type ExtensionBlueprintParameters = { kind: string; name?: string; - params?: object; + params?: object | ExtensionBlueprintParamsDefiner; configInput?: { [K in string]: any; }; @@ -1034,6 +1061,18 @@ export type ExtensionBlueprintParameters = { }; }; +// @public +export type ExtensionBlueprintParams = { + $$type: '@backstage/BlueprintParams'; + T: T; +}; + +// @public +export type ExtensionBlueprintParamsDefiner< + TParams extends object = object, + TInput = any, +> = (params: TInput) => ExtensionBlueprintParams; + // @public (undocumented) export function ExtensionBoundary(props: ExtensionBoundaryProps): JSX_2.Element; @@ -1130,6 +1169,7 @@ export type ExtensionDefinition< } >; }, + TParamsInput extends AnyParamsInput>, >( args: Expand< { @@ -1147,7 +1187,11 @@ export type ExtensionDefinition< }; }; factory?( - originalFactory: ( + originalFactory: < + TFactoryParamsReturn extends AnyParamsInput< + NonNullable + >, + >( context?: Expand< { config?: T['config']; @@ -1155,7 +1199,11 @@ export type ExtensionDefinition< } & ([T['params']] extends [never] ? {} : { - params?: Partial; + params?: TFactoryParamsReturn extends ExtensionBlueprintParamsDefiner + ? TFactoryParamsReturn + : T['params'] extends ExtensionBlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' + : Partial; }) >, ) => ExtensionDataContainer>, @@ -1173,7 +1221,11 @@ export type ExtensionDefinition< } & ([T['params']] extends [never] ? {} : { - params?: Partial; + params?: TParamsInput extends ExtensionBlueprintParamsDefiner + ? TParamsInput + : T['params'] extends ExtensionBlueprintParamsDefiner + ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' + : Partial; }) > & VerifyExtensionFactoryOutput< @@ -1223,7 +1275,7 @@ export type ExtensionDefinitionParameters = { } >; }; - params?: object; + params?: object | ExtensionBlueprintParamsDefiner; }; // @public (undocumented) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index df097bd843..8ade3d63c9 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -30,10 +30,7 @@ import { z } from 'zod'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; import { OpaqueExtensionDefinition } from '@internal/frontend'; import { ExtensionDataContainer } from './types'; -import { - BlueprintParamsDefiner, - BlueprintParamsFactory, -} from './createExtensionBlueprint'; +import { ExtensionBlueprintParamsDefiner } from './createExtensionBlueprint'; /** * This symbol is used to pass parameter overrides from the extension override to the blueprint factory @@ -165,15 +162,22 @@ export type ExtensionDefinitionParameters = { { optional: boolean; singleton: boolean } >; }; - params?: object | BlueprintParamsDefiner; + params?: object | ExtensionBlueprintParamsDefiner; }; -type AnyParamsInput = - TParams extends BlueprintParamsDefiner - ? IParams | BlueprintParamsFactory +/** + * Same as the one in `createExtensionBlueprint`, but with `ParamsFactory` inlined. + * It can't be exported because it breaks API reports. + * @ignore + */ +type AnyParamsInput = + TParams extends ExtensionBlueprintParamsDefiner + ? IParams | ((define: TParams) => ReturnType) : | TParams - | BlueprintParamsFactory>; + | (( + define: ExtensionBlueprintParamsDefiner, + ) => ReturnType>); /** @public */ export type ExtensionDefinition< @@ -194,7 +198,7 @@ export type ExtensionDefinition< { optional: boolean; singleton: boolean } >; }, - TParamsReturn extends AnyParamsInput>, + TParamsInput extends AnyParamsInput>, >( args: Expand< { @@ -224,9 +228,9 @@ export type ExtensionDefinition< } & ([T['params']] extends [never] ? {} : { - params?: TFactoryParamsReturn extends BlueprintParamsDefiner + params?: TFactoryParamsReturn extends ExtensionBlueprintParamsDefiner ? TFactoryParamsReturn - : T['params'] extends BlueprintParamsDefiner + : T['params'] extends ExtensionBlueprintParamsDefiner ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' : Partial; }) @@ -246,9 +250,9 @@ export type ExtensionDefinition< } & ([T['params']] extends [never] ? {} : { - params?: TParamsReturn extends BlueprintParamsDefiner - ? TParamsReturn - : T['params'] extends BlueprintParamsDefiner + params?: TParamsInput extends ExtensionBlueprintParamsDefiner + ? TParamsInput + : T['params'] extends ExtensionBlueprintParamsDefiner ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' : Partial; }) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 6f60950eb3..ced7eabc87 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -38,21 +38,42 @@ import { } from './resolveInputOverrides'; import { ExtensionDataContainer } from './types'; -export type BlueprintParamsDefiner< +/** + * A function used to define a parameter mapping function in order to facilitate + * advanced parameter typing for extension blueprints. + * + * @remarks + * + * This function is primarily intended to enable the use of inferred type + * parameters for blueprint params, but it can also be used to transoform the + * params before they are handed ot the blueprint. + * + * The function must return an object created with + * {@link createExtensionBlueprintParams}. + * + * @public + */ +export type ExtensionBlueprintParamsDefiner< TParams extends object = object, TInput = any, -> = (params: TInput) => BlueprintParams; -export type BlueprintParamsFactory = ( - define: TDefiner, -) => ReturnType; +> = (params: TInput) => ExtensionBlueprintParams; -export type BlueprintParams = { +/** + * An opaque type that represents a set of parameters to be passed to a blueprint. + * + * @remarks + * + * Created with {@link createExtensionBlueprintParams}. + * + * @public + */ +export type ExtensionBlueprintParams = { $$type: '@backstage/BlueprintParams'; T: T; }; const OpaqueBlueprintParams = OpaqueType.create<{ - public: BlueprintParams; + public: ExtensionBlueprintParams; versions: { version: 'v1'; params: object; @@ -62,9 +83,18 @@ const OpaqueBlueprintParams = OpaqueType.create<{ versions: ['v1'], }); +/** + * Wraps a plain blueprint parameter object in an opaque {@link ExtensionBlueprintParams} object. + * + * This is used in the definition of the `defineParams` option of {@link ExtensionBlueprint}. + * + * @public + * @param params - The plain blueprint parameter object to wrap. + * @returns The wrapped blueprint parameter object. + */ export function createExtensionBlueprintParams( params: T, -): BlueprintParams { +): ExtensionBlueprintParams { return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params }); } @@ -74,7 +104,7 @@ export function createExtensionBlueprintParams( export type CreateExtensionBlueprintOptions< TKind extends string, TName extends string | undefined, - TParams extends object | BlueprintParamsDefiner, + TParams extends object | ExtensionBlueprintParamsDefiner, UOutput extends AnyExtensionDataRef, TInputs extends { [inputName in string]: ExtensionInput< @@ -95,11 +125,49 @@ export type CreateExtensionBlueprintOptions< config?: { schema: TConfigSchema; }; - defineParams?: TParams extends BlueprintParamsDefiner + /** + * This option is used to further refine the blueprint params. When this + * option is used, the blueprint will require params to be passed in callback + * form. This function can both transform the params before they are handed to + * the blueprint factory, but importantly it also allows you to define + * inferred type parameters for your blueprint params. + * + * @example + * Blueprint definition with inferred type parameters: + * ```ts + * const ExampleBlueprint = createExtensionBlueprint({ + * kind: 'example', + * attachTo: { id: 'example', input: 'example' }, + * output: [exampleComponentDataRef, exampleFetcherDataRef], + * defineParams(params: { + * component(props: ExampleProps): JSX.Element | null + * fetcher(options: FetchOptions): Promise> + * }) { + * return createExtensionBlueprintParams(params); + * }, + * *factory(params) { + * yield exampleComponentDataRef(params.component) + * yield exampleFetcherDataRef(params.fetcher) + * }, + * }); + * ``` + * + * @example + * Usage of the above example blueprint: + * ```ts + * const example = ExampleBlueprint.make({ + * params: define => define({ + * component: ..., + * fetcher: ..., + * }), + * }); + * ``` + */ + defineParams?: TParams extends ExtensionBlueprintParamsDefiner ? TParams - : 'The params option must be a function if provided, see the docs for details'; + : 'The defineParams option must be a function if provided, see the docs for details'; factory( - params: TParams extends BlueprintParamsDefiner + params: TParams extends ExtensionBlueprintParamsDefiner ? ReturnType['T'] : TParams, context: { @@ -119,7 +187,7 @@ export type CreateExtensionBlueprintOptions< export type ExtensionBlueprintParameters = { kind: string; name?: string; - params: object | BlueprintParamsDefiner; + params?: object | ExtensionBlueprintParamsDefiner; configInput?: { [K in string]: any }; config?: { [K in string]: any }; output?: AnyExtensionDataRef; @@ -132,18 +200,23 @@ export type ExtensionBlueprintParameters = { dataRefs?: { [name in string]: AnyExtensionDataRef }; }; +/** @ignore */ +type ParamsFactory = ( + define: TDefiner, +) => ReturnType; + /** * Represents any form of params input that can be passed to a blueprint. * This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback. * - * @internal + * @ignore */ -type AnyParamsInput = - TParams extends BlueprintParamsDefiner - ? IParams | BlueprintParamsFactory +type AnyParamsInput = + TParams extends ExtensionBlueprintParamsDefiner + ? IParams | ParamsFactory : | TParams - | BlueprintParamsFactory>; + | ParamsFactory>; /** * @public @@ -156,16 +229,16 @@ export interface ExtensionBlueprint< make< TNewName extends string | undefined, - TParamsReturn extends AnyParamsInput, + TParamsInput extends AnyParamsInput>, >(args: { name?: TNewName; attachTo?: ExtensionAttachToSpec; disabled?: boolean; - params: TParamsReturn extends BlueprintParamsDefiner - ? TParamsReturn - : T['params'] extends BlueprintParamsDefiner + params: TParamsInput extends ExtensionBlueprintParamsDefiner + ? TParamsInput + : T['params'] extends ExtensionBlueprintParamsDefiner ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `.make({ params: define => define() })`' - : TParamsReturn; + : TParamsInput; }): ExtensionDefinition<{ kind: T['kind']; name: string | undefined extends TNewName ? T['name'] : TNewName; @@ -211,12 +284,14 @@ export interface ExtensionBlueprint< }; }; factory( - originalFactory: >( - params: TParamsReturn extends BlueprintParamsDefiner - ? TParamsReturn - : T['params'] extends BlueprintParamsDefiner + originalFactory: < + TParamsInput extends AnyParamsInput>, + >( + params: TParamsInput extends ExtensionBlueprintParamsDefiner + ? TParamsInput + : T['params'] extends ExtensionBlueprintParamsDefiner ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define())`' - : TParamsReturn, + : TParamsInput, context?: { config?: T['config']; inputs?: ResolveInputValueOverrides>; @@ -268,12 +343,12 @@ export interface ExtensionBlueprint< function unwrapParamsFactory( // Allow `Function` because `typeof === 'function'` allows it, but in practice this should always be a param factory - params: BlueprintParamsFactory | Function, - defineParams: BlueprintParamsDefiner, + params: ParamsFactory | Function, + defineParams: ExtensionBlueprintParamsDefiner, kind: string, ): TParams { const paramDefinition = ( - params as BlueprintParamsFactory + params as ParamsFactory )(defineParams); try { return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams; @@ -285,14 +360,14 @@ function unwrapParamsFactory( } function unwrapParams( - params: object | BlueprintParamsFactory | string, + params: object | ParamsFactory | string, ctx: { node: AppNode; [ctxParamsSymbol]?: any }, - defineParams: BlueprintParamsDefiner | undefined, + defineParams: ExtensionBlueprintParamsDefiner | undefined, kind: string, ): TParams { const overrideParams = ctx[ctxParamsSymbol] as | object - | BlueprintParamsFactory + | ParamsFactory | undefined; if (defineParams) { @@ -343,7 +418,7 @@ function unwrapParams( * @public */ export function createExtensionBlueprint< - TParams extends object | BlueprintParamsDefiner, + TParams extends object | ExtensionBlueprintParamsDefiner, UOutput extends AnyExtensionDataRef, TInputs extends { [inputName in string]: ExtensionInput< @@ -386,7 +461,7 @@ export function createExtensionBlueprint< dataRefs: TDataRefs; }> { const defineParams = options.defineParams as - | BlueprintParamsDefiner + | ExtensionBlueprintParamsDefiner | undefined; return { diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 24a4e1653f..0f170d949f 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -66,6 +66,9 @@ export { type CreateExtensionBlueprintOptions, type ExtensionBlueprint, type ExtensionBlueprintParameters, + type ExtensionBlueprintParams, + type ExtensionBlueprintParamsDefiner, createExtensionBlueprint, + createExtensionBlueprintParams, } from './createExtensionBlueprint'; export { type ResolveInputValueOverrides } from './resolveInputOverrides'; diff --git a/plugins/api-docs/report-alpha.api.md b/plugins/api-docs/report-alpha.api.md index f0a65d45c8..c383ea810c 100644 --- a/plugins/api-docs/report-alpha.api.md +++ b/plugins/api-docs/report-alpha.api.md @@ -7,12 +7,12 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; import { EntityCardType } from '@backstage/plugin-catalog-react/alpha'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; @@ -81,7 +81,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'entity-card:api-docs/consumed-apis': ExtensionDefinition<{ kind: 'entity-card'; diff --git a/plugins/app/report.api.md b/plugins/app/report.api.md index df1f47a68b..15001d2961 100644 --- a/plugins/app/report.api.md +++ b/plugins/app/report.api.md @@ -8,10 +8,10 @@ import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; import { AppTheme } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ComponentRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -230,7 +230,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/analytics': ExtensionDefinition<{ kind: 'api'; @@ -249,7 +249,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/app-language': ExtensionDefinition<{ kind: 'api'; @@ -268,7 +268,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/app-theme': ExtensionDefinition<{ config: {}; @@ -295,7 +295,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/atlassian-auth': ExtensionDefinition<{ kind: 'api'; @@ -314,7 +314,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/bitbucket-auth': ExtensionDefinition<{ kind: 'api'; @@ -333,7 +333,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/bitbucket-server-auth': ExtensionDefinition<{ kind: 'api'; @@ -352,7 +352,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/components': ExtensionDefinition<{ config: {}; @@ -386,7 +386,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/dialog': ExtensionDefinition<{ kind: 'api'; @@ -405,7 +405,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/discovery': ExtensionDefinition<{ kind: 'api'; @@ -424,7 +424,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/error': ExtensionDefinition<{ kind: 'api'; @@ -443,7 +443,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/feature-flags': ExtensionDefinition<{ kind: 'api'; @@ -462,7 +462,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/fetch': ExtensionDefinition<{ kind: 'api'; @@ -481,7 +481,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/github-auth': ExtensionDefinition<{ kind: 'api'; @@ -500,7 +500,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/gitlab-auth': ExtensionDefinition<{ kind: 'api'; @@ -519,7 +519,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/google-auth': ExtensionDefinition<{ kind: 'api'; @@ -538,7 +538,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/icons': ExtensionDefinition<{ config: {}; @@ -571,7 +571,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/microsoft-auth': ExtensionDefinition<{ kind: 'api'; @@ -590,7 +590,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/oauth-request': ExtensionDefinition<{ kind: 'api'; @@ -609,7 +609,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/okta-auth': ExtensionDefinition<{ kind: 'api'; @@ -628,7 +628,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/onelogin-auth': ExtensionDefinition<{ kind: 'api'; @@ -647,7 +647,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/permission': ExtensionDefinition<{ kind: 'api'; @@ -666,7 +666,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/scm-auth': ExtensionDefinition<{ kind: 'api'; @@ -685,7 +685,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/scm-integrations': ExtensionDefinition<{ kind: 'api'; @@ -704,7 +704,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/storage': ExtensionDefinition<{ kind: 'api'; @@ -723,7 +723,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/translations': ExtensionDefinition<{ config: {}; @@ -761,7 +761,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:app/vmware-cloud-auth': ExtensionDefinition<{ kind: 'api'; @@ -780,7 +780,7 @@ const appPlugin: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'app-root-element:app/alert-display': ExtensionDefinition<{ config: { diff --git a/plugins/catalog-import/report-alpha.api.md b/plugins/catalog-import/report-alpha.api.md index 31192683bd..2e75f9481c 100644 --- a/plugins/catalog-import/report-alpha.api.md +++ b/plugins/catalog-import/report-alpha.api.md @@ -6,8 +6,8 @@ import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/core-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; @@ -111,7 +111,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'page:catalog-import': ExtensionDefinition<{ kind: 'page'; diff --git a/plugins/catalog-unprocessed-entities/report-alpha.api.md b/plugins/catalog-unprocessed-entities/report-alpha.api.md index b742ece07c..fa64ed329a 100644 --- a/plugins/catalog-unprocessed-entities/report-alpha.api.md +++ b/plugins/catalog-unprocessed-entities/report-alpha.api.md @@ -6,8 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -38,7 +38,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'nav-item:catalog-unprocessed-entities': ExtensionDefinition<{ kind: 'nav-item'; diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md index 369b666905..cfbbc5388e 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -7,7 +7,6 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; @@ -15,6 +14,7 @@ import { EntityCardType } from '@backstage/plugin-catalog-react/alpha'; import { EntityContentLayoutProps } from '@backstage/plugin-catalog-react/alpha'; import { EntityContextMenuItemParams } from '@backstage/plugin-catalog-react/alpha'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; @@ -154,7 +154,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:catalog/entity-presentation': ExtensionDefinition<{ kind: 'api'; @@ -173,7 +173,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:catalog/starred-entities': ExtensionDefinition<{ kind: 'api'; @@ -192,7 +192,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'catalog-filter:catalog/kind': ExtensionDefinition<{ config: { diff --git a/plugins/devtools/report-alpha.api.md b/plugins/devtools/report-alpha.api.md index 0b6b41ce3b..2ede4d34b2 100644 --- a/plugins/devtools/report-alpha.api.md +++ b/plugins/devtools/report-alpha.api.md @@ -6,8 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -38,7 +38,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'nav-item:devtools': ExtensionDefinition<{ kind: 'nav-item'; diff --git a/plugins/home/report-alpha.api.md b/plugins/home/report-alpha.api.md index 17ca91ca2a..010918b029 100644 --- a/plugins/home/report-alpha.api.md +++ b/plugins/home/report-alpha.api.md @@ -6,8 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -39,7 +39,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'app-root-element:home/visit-listener': ExtensionDefinition<{ kind: 'app-root-element'; diff --git a/plugins/kubernetes/report-alpha.api.md b/plugins/kubernetes/report-alpha.api.md index 6971e1b1e0..37bb084bd7 100644 --- a/plugins/kubernetes/report-alpha.api.md +++ b/plugins/kubernetes/report-alpha.api.md @@ -6,11 +6,11 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; @@ -41,7 +41,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:kubernetes/auth-providers': ExtensionDefinition<{ kind: 'api'; @@ -60,7 +60,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:kubernetes/cluster-link-formatter': ExtensionDefinition<{ kind: 'api'; @@ -79,7 +79,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:kubernetes/proxy': ExtensionDefinition<{ kind: 'api'; @@ -98,7 +98,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'entity-content:kubernetes/kubernetes': ExtensionDefinition<{ kind: 'entity-content'; diff --git a/plugins/notifications/report-alpha.api.md b/plugins/notifications/report-alpha.api.md index 210ee8ac4f..b512d97ce3 100644 --- a/plugins/notifications/report-alpha.api.md +++ b/plugins/notifications/report-alpha.api.md @@ -6,8 +6,8 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; @@ -37,7 +37,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'page:notifications': ExtensionDefinition<{ kind: 'page'; diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index ea8a864138..7de5c1b819 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -8,12 +8,12 @@ import { AnyApiRef } from '@backstage/core-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; import { Dispatch } from 'react'; import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; @@ -226,7 +226,7 @@ export const formFieldsApi: ExtensionDefinition<{ TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; // @alpha @deprecated (undocumented) diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 55c90ddb1b..394ae081d6 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -7,11 +7,11 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; @@ -74,7 +74,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:scaffolder/form-decorators': ExtensionDefinition<{ config: {}; @@ -105,7 +105,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:scaffolder/form-fields': ExtensionDefinition<{ config: {}; @@ -136,7 +136,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'entity-icon-link:scaffolder/launch-template': ExtensionDefinition<{ kind: 'entity-icon-link'; @@ -293,7 +293,7 @@ export const formDecoratorsApi: ExtensionDefinition<{ TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; // @alpha (undocumented) diff --git a/plugins/search/report-alpha.api.md b/plugins/search/report-alpha.api.md index f7916a8467..1edc5e678d 100644 --- a/plugins/search/report-alpha.api.md +++ b/plugins/search/report-alpha.api.md @@ -6,8 +6,8 @@ import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/core-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -43,7 +43,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'nav-item:search': ExtensionDefinition<{ kind: 'nav-item'; @@ -157,7 +157,7 @@ export const searchApi: ExtensionDefinition<{ TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; // @alpha (undocumented) diff --git a/plugins/signals/report-alpha.api.md b/plugins/signals/report-alpha.api.md index a0b8dfe18f..13091a9032 100644 --- a/plugins/signals/report-alpha.api.md +++ b/plugins/signals/report-alpha.api.md @@ -5,8 +5,8 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; @@ -33,7 +33,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'app-root-element:signals/signals-display': ExtensionDefinition<{ kind: 'app-root-element'; diff --git a/plugins/techdocs/report-alpha.api.md b/plugins/techdocs/report-alpha.api.md index ce5e06a35c..fd63ec1daa 100644 --- a/plugins/techdocs/report-alpha.api.md +++ b/plugins/techdocs/report-alpha.api.md @@ -7,11 +7,11 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { BlueprintParams } from '@backstage/frontend-plugin-api/src/wiring/createExtensionBlueprint'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -54,7 +54,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'api:techdocs/storage': ExtensionDefinition<{ kind: 'api'; @@ -73,7 +73,7 @@ const _default: FrontendPlugin< TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => BlueprintParams; + ) => ExtensionBlueprintParams; }>; 'empty-state:techdocs/entity-content': ExtensionDefinition<{ config: {}; From 32cc054e9a639baa90bc5fd396ea3205b501e5af Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Jul 2025 22:25:42 +0200 Subject: [PATCH 06/11] frontend-plugin-api: add test for params transforms Signed-off-by: Patrik Oldsberg --- .../wiring/createExtensionBlueprint.test.tsx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index faec493092..f13741a088 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -1541,5 +1541,44 @@ describe('createExtensionBlueprint', () => { expect(createExtensionTester(override).get(testDataRef)).toBe('z z'); }); + + it('should allow the params definer to transform the params', () => { + const TestTransformExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: [testDataRef], + defineParams(params: { a: number; b: number }) { + return createExtensionBlueprintParams({ + x: params.a + 1, + y: params.b + 1, + }); + }, + factory(params) { + return [testDataRef(`${params.x} ${params.y}`)]; + }, + }); + + const extension = TestTransformExtensionBlueprint.make({ + params: define => + define({ + a: 0, + b: 10, + }), + }); + + expect(createExtensionTester(extension).get(testDataRef)).toBe(`1 11`); + + expect( + createExtensionTester( + extension.override({ + params: define => + define({ + a: 20, + b: 30, + }), + }), + ).get(testDataRef), + ).toBe(`21 31`); + }); }); }); From 805c298578299d6b646edb333c6fd0a3fda93836 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 29 Jul 2025 01:11:18 +0200 Subject: [PATCH 07/11] changesets: add changesets for new advanced blueprint types Signed-off-by: Patrik Oldsberg --- .changeset/odd-beans-sell.md | 40 +++++++++++++++++++++++++++++++ .changeset/quiet-parks-cheer.md | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 .changeset/odd-beans-sell.md create mode 100644 .changeset/quiet-parks-cheer.md diff --git a/.changeset/odd-beans-sell.md b/.changeset/odd-beans-sell.md new file mode 100644 index 0000000000..50b8ec0f89 --- /dev/null +++ b/.changeset/odd-beans-sell.md @@ -0,0 +1,40 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +**BREAKING**: The `ApiBlueprint` has been updated to use the new advanced type parameters through the new `defineParams` blueprint option. This is an immediate breaking change that requires all existing usages of `ApiBlueprint` to switch to the new callback format. Existing extensions created with the old format are still compatible with the latest version of the plugin API however, meaning that this does not break existing plugins. + +To update existing usages of `ApiBlueprint`, you remove the outer level of the `params` object and replace `createApiFactory(...)` with `define => define(...)`. + +For example, the following old usage: + +```ts +ApiBlueprint.make({ + name: 'error', + params: { + factory: createApiFactory({ + api: errorApiRef, + deps: { alertApi: alertApiRef }, + factory: ({ alertApi }) => { + return ...; + }, + }) + }, +}) +``` + +is migrated to the following: + +```ts +ApiBlueprint.make({ + name: 'error', + params: define => + define({ + api: errorApiRef, + deps: { alertApi: alertApiRef }, + factory: ({ alertApi }) => { + return ...; + }, + }), +}) +``` diff --git a/.changeset/quiet-parks-cheer.md b/.changeset/quiet-parks-cheer.md new file mode 100644 index 0000000000..335db347de --- /dev/null +++ b/.changeset/quiet-parks-cheer.md @@ -0,0 +1,42 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +Added support for advanced parameter types in extension blueprints. The primary purpose of this is to allow extension authors to use type inference in the definition of the blueprint parameters. This often removes the need for extra imports and improves discoverability of blueprint parameters. + +This feature is introduced through the new `defineParams` option of `createExtensionBlueprint`, along with accompanying `createExtensionBlueprintParams` function to help implement the new format. + +The following is an example of how to create an extension blueprint that uses the new option: + +```ts +const ExampleBlueprint = createExtensionBlueprint({ + kind: 'example', + attachTo: { id: 'example', input: 'example' }, + output: [exampleComponentDataRef, exampleFetcherDataRef], + defineParams(params: { + component(props: ExampleProps): JSX.Element | null; + fetcher(options: FetchOptions): Promise>; + }) { + // The returned params must be wrapped with `createExtensionBlueprintParams` + return createExtensionBlueprintParams(params); + }, + *factory(params) { + // These params are now inferred + yield exampleComponentDataRef(params.component); + yield exampleFetcherDataRef(params.fetcher); + }, +}); +``` + +Usage of the above example looks as follows: + +```ts +const example = ExampleBlueprint.make({ + params: define => define({ + component: ..., + fetcher: ..., + }), +}); +``` + +This `define => define()` is also known as the "callback syntax" and is is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible. From 781716d247e1ede10ae53b6727baa594c3c7b5d4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 29 Jul 2025 09:26:13 +0200 Subject: [PATCH 08/11] frontend-plugin-api: add test for blueprint param overloads Signed-off-by: Patrik Oldsberg --- .../wiring/createExtensionBlueprint.test.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index f13741a088..e0b43382b7 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -18,6 +18,7 @@ import { coreExtensionData } from './coreExtensionData'; import { createExtensionBlueprint, createExtensionBlueprintParams, + ExtensionBlueprintParams, } from './createExtensionBlueprint'; import { createExtensionTester, @@ -1580,5 +1581,35 @@ describe('createExtensionBlueprint', () => { ).get(testDataRef), ).toBe(`21 31`); }); + + it('should support overloads', () => { + const TestTransformExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: [testDataRef], + defineParams: (params => createExtensionBlueprintParams(params)) as { + (params: { x: 1 }): ExtensionBlueprintParams<{ x: number }>; + (params: { x: 2 }): ExtensionBlueprintParams<{ x: number }>; + }, + factory(params) { + return [testDataRef(`x: ${params.x}`)]; + }, + }); + + const extension = TestTransformExtensionBlueprint.make({ + params: define => define({ x: 1 }), + }); + + expect(createExtensionTester(extension).get(testDataRef)).toBe(`x: 1`); + + TestTransformExtensionBlueprint.make({ + params: define => define({ x: 2 }), + }); + + TestTransformExtensionBlueprint.make({ + // @ts-expect-error doesn't match any overload + params: define => define({ x: 3 }), + }); + }); }); }); From d6764eed83b385ee323ec6fedbe0dbdce395fa42 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 29 Jul 2025 10:31:58 +0200 Subject: [PATCH 09/11] docs/frontend-system: update existing usage of ApiBlueprint Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-apps/08-migrating.md | 5 ++--- docs/frontend-system/building-plugins/01-index.md | 7 +++---- docs/frontend-system/building-plugins/05-migrating.md | 11 +++-------- docs/frontend-system/utility-apis/02-creating.md | 6 ++---- docs/frontend-system/utility-apis/03-consuming.md | 6 ++---- 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index 6b1332834a..41b0a43b15 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -199,13 +199,12 @@ import { ApiBlueprint } from '@backstage/frontend-plugin-api'; const scmIntegrationsApi = ApiBlueprint.make({ name: 'scm-integrations', - params: { - factory: createApiFactory({ + params: define => + define({ api: scmIntegrationsApiRef, deps: { configApi: configApiRef }, factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), }), - }, }); ``` diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index e9d6f1cbe2..ecabf0e2ef 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -154,19 +154,18 @@ export function ExamplePage() { ``` ```tsx title="in src/plugin.ts - Registering a factory for our API" -import { createApiFactory, ApiBlueprint } from '@backstage/frontend-plugin-api'; +import { ApiBlueprint } from '@backstage/frontend-plugin-api'; import { exampleApiRef, DefaultExampleApi } from './api'; // highlight-add-start const exampleApi = ApiBlueprint.make({ name: 'example', - params: { - factory: createApiFactory({ + params: define => + define({ api: exampleApiRef, deps: {}, factory: () => new DefaultExampleApi(), }), - }, }); // highlight-add-end diff --git a/docs/frontend-system/building-plugins/05-migrating.md b/docs/frontend-system/building-plugins/05-migrating.md index 483ebf68f8..2215c548ae 100644 --- a/docs/frontend-system/building-plugins/05-migrating.md +++ b/docs/frontend-system/building-plugins/05-migrating.md @@ -205,22 +205,17 @@ The major changes we'll make are The end result, after simplifying imports and cleaning up a bit, might look like this: ```tsx title="in @internal/plugin-example" -import { - storageApiRef, - createApiFactory, - ApiBlueprint, -} from '@backstage/frontend-plugin-api'; +import { storageApiRef, ApiBlueprint } from '@backstage/frontend-plugin-api'; import { workApiRef } from '@internal/plugin-example-react'; import { WorkImpl } from './WorkImpl'; const exampleWorkApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: workApiRef, deps: { storageApi: storageApiRef }, factory: ({ storageApi }) => new WorkImpl({ storageApi }), }), - }, }); ``` diff --git a/docs/frontend-system/utility-apis/02-creating.md b/docs/frontend-system/utility-apis/02-creating.md index d02b74cbf6..d541173541 100644 --- a/docs/frontend-system/utility-apis/02-creating.md +++ b/docs/frontend-system/utility-apis/02-creating.md @@ -45,7 +45,6 @@ The plugin itself now wants to provide this API and its default implementation, ```tsx title="in @internal/plugin-example" import { ApiBlueprint, - createApiFactory, createFrontendPlugin, storageApiRef, StorageApi, @@ -63,15 +62,14 @@ class WorkImpl implements WorkApi { const workApi = ApiBlueprint.make({ name: 'work', - params: { - factory: createApiFactory({ + params: define => + define({ api: workApiRef, deps: { storageApi: storageApiRef }, factory: ({ storageApi }) => { return new WorkImpl({ storageApi }); }, }), - }, }); /** diff --git a/docs/frontend-system/utility-apis/03-consuming.md b/docs/frontend-system/utility-apis/03-consuming.md index d5ea537284..4652125d8e 100644 --- a/docs/frontend-system/utility-apis/03-consuming.md +++ b/docs/frontend-system/utility-apis/03-consuming.md @@ -46,14 +46,13 @@ Your utility APIs can depend on other utility APIs in their factories. You do th import { configApiRef, ApiBlueprint, - createApiFactory, discoveryApiRef, } from '@backstage/frontend-plugin-api'; import { MyApiImpl } from './MyApiImpl'; const myApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: myApiRef, deps: { configApi: configApiRef, @@ -63,7 +62,6 @@ const myApi = ApiBlueprint.make({ return new MyApiImpl({ configApi, discoveryApi }); }, }), - }, }); ``` From 0b91dc8bbc89de731300cc26dfee0d59f05503b1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 29 Jul 2025 11:12:57 +0200 Subject: [PATCH 10/11] docs/frontend-system: document advanced blueprint param types Signed-off-by: Patrik Oldsberg --- .../architecture/23-extension-blueprints.md | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/frontend-system/architecture/23-extension-blueprints.md b/docs/frontend-system/architecture/23-extension-blueprints.md index 081497655e..f7d019d6bc 100644 --- a/docs/frontend-system/architecture/23-extension-blueprints.md +++ b/docs/frontend-system/architecture/23-extension-blueprints.md @@ -60,6 +60,39 @@ When using `makeWithOverrides`, we no longer pass the blueprint parameters direc Apart from the addition of the blueprint parameters of the first argument to the original factory function, the `makeWithOverrides` method works the same way as [extension overrides](./25-extension-overrides.md). All the same options and rules apply, including the ability to define additional inputs, override outputs, and so on. We therefore defer to the [extension overrides](./25-extension-overrides.md) documentation for more information on how to use the `makeWithOverrides` method. +### Creating an extension from a blueprint with advanced parameter types + +Some blueprints may be defined with something known as "advanced parameter types". This is a feature that enables type inference and transform of the blueprint parameters, and the way that you pass the parameters look a little bit different. Rather than passing the parameters directly, they are instead passed as a callback function of the form `define => define()`. + +An example of a blueprint that uses advanced parameter types is the `ApiBlueprint` blueprint. Using it to create a simple implementation for the `AlertApi` might look like this: + +```ts +const alertApiBlueprint = ApiBlueprint.make({ + params: define => + define({ + api: alertApiRef, + deps: {}, + factory: () => new MyAlertApi(), + }), +}); +``` + +This also works with `makeWithOverrides`, where the define callback is passed as the first argument to the original factory: + +```ts +const alertApiBlueprint = ApiBlueprint.makeWithOverrides({ + factory(originalFactory, { config }) { + return originalFactory(define => + define({ + api: alertApiRef, + deps: {}, + factory: () => new MyAlertApi(config), + }), + ); + }, +}); +``` + ## Creating an extension blueprint To create a new extension blueprint, you use the `createExtensionBlueprint` function. At the surface it is very similar to `createExtension`, but with a few key differences. Firstly you must provide a `kind` option, which will be the kind of all extensions created with the blueprint. See the [naming patterns section](./50-naming-patterns.md) for more information about how to select a good extension kind. Secondly, the `factory` function has a new signature where the first parameter is the blueprint parameters, and the second is the factory context. And finally, rather than returning an extension, `createExtensionBlueprint` returns a blueprint object with the `make` method and friends, which is used as is described above. @@ -99,6 +132,41 @@ This is of course a quite bare-bones example blueprint, but still a very real ex Most of the options provided to `createExtensionBlueprint` can be overridden when using `makeWithOverrides` to create an extension from the blueprint. These overrides work the same way as [extension overrides](./25-extension-overrides.md), and we defer to that documentation for more information on how overrides work. +### Creating an extension blueprint with advanced parameter types + +In some cases you may want to use inferred type parameters in the definition of the blueprint parameters. For this you need to use something known as "advanced parameter types". This is a feature that enables type inference and transform of the blueprint parameters, and the way you define the parameter type is a bit different. Rather than defining the type of the parameters as part of the factory function, you instead provide a separate `defineParams` options. This is a function that takes the parameters as a single argument, and must then return the parameters wrapped with the `createExtensionBlueprintParams` function. + +The following is an example of how one might define a blueprint where the parameters make use of inferred types: + +```ts +export interface MyWidgetBlueprintParams { + defaultOptions: T; + elementFactory(options: T): JSX.Element; +} + +export const MyWidgetBlueprint = createExtensionBlueprint({ + kind: 'my-widget', + attachTo: { id: 'page:my-plugin', input: 'widgets' }, + output: [coreExtensionData.reactElement], + defineParams(params: MyWidgetBlueprintParams) { + return createExtensionBlueprintParams(params); + }, + // Note that we no longer define the parameters type here, they are inferred from the defineParams function + factory(params) { + return [ + coreExtensionData.reactElement( + , + ), + ]; + }, +}); +``` + +If you happen to ask yourself, "why can't I just define type parameters on the factory function instead?", this is a limitation in the TypeScript type system. We could technically support that in the blueprint definition, but there would be no way for that logic to be carried forward to the blueprint `.make` and `.makeWithOverrides` methods. + ### Blueprint-specific extension data references In some cases you may want to define and provide [extension data reference](./20-extensions.md#extension-data-references) that are specific to your blueprint. In the above example we might want to forward the `title` as data for example, rather than encapsulating it into the `MyWidgetContainer` component. This gives the parent extension more flexibility in the rendering for our example widget extensions. From e2b3726917a4b901c9c23207f7a873b26ee726a8 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 29 Jul 2025 12:13:49 +0200 Subject: [PATCH 11/11] Update .changeset/quiet-parks-cheer.md Co-authored-by: Ben Lambert Signed-off-by: Patrik Oldsberg --- .changeset/quiet-parks-cheer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/quiet-parks-cheer.md b/.changeset/quiet-parks-cheer.md index 335db347de..31e1ff8435 100644 --- a/.changeset/quiet-parks-cheer.md +++ b/.changeset/quiet-parks-cheer.md @@ -39,4 +39,4 @@ const example = ExampleBlueprint.make({ }); ``` -This `define => define()` is also known as the "callback syntax" and is is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible. +This `define => define()` is also known as the "callback syntax" and is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible.