diff --git a/.changeset/move-extension-factory-middleware-app-api.md b/.changeset/move-extension-factory-middleware-app-api.md new file mode 100644 index 0000000000..6cc77a5d26 --- /dev/null +++ b/.changeset/move-extension-factory-middleware-app-api.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Added the `ExtensionFactoryMiddleware` type as a public export. diff --git a/.changeset/move-extension-factory-middleware-plugin-api.md b/.changeset/move-extension-factory-middleware-plugin-api.md new file mode 100644 index 0000000000..607da295a3 --- /dev/null +++ b/.changeset/move-extension-factory-middleware-plugin-api.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Deprecated the `ExtensionFactoryMiddleware` type, which has been moved to `@backstage/frontend-app-api`. diff --git a/packages/frontend-app-api/report.api.md b/packages/frontend-app-api/report.api.md index e8fc019007..68ac18a1e4 100644 --- a/packages/frontend-app-api/report.api.md +++ b/packages/frontend-app-api/report.api.md @@ -4,10 +4,13 @@ ```ts import { ApiHolder } from '@backstage/core-plugin-api'; +import { ApiHolder as ApiHolder_2 } from '@backstage/frontend-plugin-api'; import { AppNode } from '@backstage/frontend-plugin-api'; import { AppTree } from '@backstage/frontend-plugin-api'; import { ConfigApi } from '@backstage/core-plugin-api'; -import { ExtensionFactoryMiddleware } from '@backstage/frontend-plugin-api'; +import { ExtensionDataContainer } from '@backstage/frontend-plugin-api'; +import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionDataValue } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { FrontendFeature } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -177,6 +180,18 @@ export type CreateSpecializedAppOptions = { }; }; +// @public (undocumented) +export type ExtensionFactoryMiddleware = ( + originalFactory: (contextOverrides?: { + config?: JsonObject; + }) => ExtensionDataContainer, + context: { + node: AppNode; + apis: ApiHolder_2; + config?: JsonObject; + }, +) => Iterable>; + // @public export type FrontendPluginInfoResolver = (ctx: { packageJson(): Promise; diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index b1da35313e..fcef41daec 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -19,7 +19,6 @@ import { Extension, ExtensionDataRef, ExtensionDefinition, - ExtensionFactoryMiddleware, ExtensionInput, PortableSchema, ResolvedExtensionInput, @@ -29,6 +28,7 @@ import { createExtensionInput, createFrontendPlugin, } from '@backstage/frontend-plugin-api'; +import { ExtensionFactoryMiddleware } from '../wiring/types'; import { createAppNodeInstance, instantiateAppNodeTree, diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts index 070cf1d687..9e8e3cc2eb 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts @@ -18,10 +18,10 @@ import { ApiHolder, ExtensionDataContainer, ExtensionDataRef, - ExtensionFactoryMiddleware, ExtensionInput, ResolvedExtensionInputs, } from '@backstage/frontend-plugin-api'; +import { ExtensionFactoryMiddleware } from '../wiring/types'; import mapValues from 'lodash/mapValues'; import { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports diff --git a/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx b/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx index d56a609bb9..1d52274acc 100644 --- a/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx +++ b/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx @@ -29,9 +29,9 @@ import { createApiFactory, routeResolutionApiRef, AppNode, - ExtensionFactoryMiddleware, FrontendFeature, } from '@backstage/frontend-plugin-api'; +import { ExtensionFactoryMiddleware } from './types'; import { AnyApiFactory, ApiHolder, diff --git a/packages/frontend-app-api/src/wiring/index.ts b/packages/frontend-app-api/src/wiring/index.ts index 1e18859ddd..cae2117df5 100644 --- a/packages/frontend-app-api/src/wiring/index.ts +++ b/packages/frontend-app-api/src/wiring/index.ts @@ -20,3 +20,4 @@ export { } from './createSpecializedApp'; export { type FrontendPluginInfoResolver } from './createPluginInfoAttacher'; export { type AppError, type AppErrorTypes } from './createErrorCollector'; +export { type ExtensionFactoryMiddleware } from './types'; diff --git a/packages/frontend-app-api/src/wiring/types.ts b/packages/frontend-app-api/src/wiring/types.ts new file mode 100644 index 0000000000..0bb7497179 --- /dev/null +++ b/packages/frontend-app-api/src/wiring/types.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JsonObject } from '@backstage/types'; +import { + ApiHolder, + AppNode, + ExtensionDataContainer, + ExtensionDataRef, + ExtensionDataValue, +} from '@backstage/frontend-plugin-api'; + +/** @public */ +export type ExtensionFactoryMiddleware = ( + originalFactory: (contextOverrides?: { + config?: JsonObject; + }) => ExtensionDataContainer, + context: { + node: AppNode; + apis: ApiHolder; + config?: JsonObject; + }, +) => Iterable>; diff --git a/packages/frontend-defaults/report.api.md b/packages/frontend-defaults/report.api.md index 75392d2dc1..14b546282a 100644 --- a/packages/frontend-defaults/report.api.md +++ b/packages/frontend-defaults/report.api.md @@ -8,7 +8,7 @@ import { AppErrorTypes } from '@backstage/frontend-app-api'; import { Config } from '@backstage/config'; import { ConfigApi } from '@backstage/frontend-plugin-api'; import { CreateAppRouteBinder } from '@backstage/frontend-app-api'; -import { ExtensionFactoryMiddleware } from '@backstage/frontend-plugin-api'; +import { ExtensionFactoryMiddleware } from '@backstage/frontend-app-api'; import { FrontendFeature } from '@backstage/frontend-plugin-api'; import { FrontendFeatureLoader } from '@backstage/frontend-plugin-api'; import { FrontendPluginInfoResolver } from '@backstage/frontend-app-api'; diff --git a/packages/frontend-defaults/src/createApp.tsx b/packages/frontend-defaults/src/createApp.tsx index 4ff67f6d5a..ffc605a747 100644 --- a/packages/frontend-defaults/src/createApp.tsx +++ b/packages/frontend-defaults/src/createApp.tsx @@ -18,7 +18,6 @@ import { JSX, lazy, ReactNode, Suspense } from 'react'; import { ConfigApi, coreExtensionData, - ExtensionFactoryMiddleware, FrontendFeature, FrontendFeatureLoader, } from '@backstage/frontend-plugin-api'; @@ -31,6 +30,7 @@ import { ConfigReader } from '@backstage/config'; import { CreateAppRouteBinder, createSpecializedApp, + ExtensionFactoryMiddleware, FrontendPluginInfoResolver, } from '@backstage/frontend-app-api'; import appPlugin from '@backstage/plugin-app'; diff --git a/packages/frontend-plugin-api/report.api.md b/packages/frontend-plugin-api/report.api.md index c83511fc47..9ccd0593bd 100644 --- a/packages/frontend-plugin-api/report.api.md +++ b/packages/frontend-plugin-api/report.api.md @@ -3,17 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyRouteRefParams as AnyRouteRefParams_2 } from '@backstage/frontend-plugin-api'; -import { ApiRef as ApiRef_2 } from '@backstage/frontend-plugin-api'; +import { ApiRef as ApiRef_2 } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import type { Config } from '@backstage/config'; -import { ConfigurableExtensionDataRef as ConfigurableExtensionDataRef_2 } from '@backstage/frontend-plugin-api'; import { Expand } from '@backstage/types'; import { ExpandRecursive } from '@backstage/types'; import { ExtensionBlueprint as ExtensionBlueprint_2 } from '@backstage/frontend-plugin-api'; -import { ExtensionBlueprintParams as ExtensionBlueprintParams_2 } from '@backstage/frontend-plugin-api'; import { ExtensionDataRef as ExtensionDataRef_2 } from '@backstage/frontend-plugin-api'; -import { ExtensionInput as ExtensionInput_2 } from '@backstage/frontend-plugin-api'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; import { JSX as JSX_2 } from 'react'; @@ -21,7 +17,6 @@ import { JSX as JSX_3 } from 'react/jsx-runtime'; import { Observable } from '@backstage/types'; import { PropsWithChildren } from 'react'; import { ReactNode } from 'react'; -import { SwappableComponentRef as SwappableComponentRef_2 } from '@backstage/frontend-plugin-api'; import type { z } from 'zod'; // @public @@ -82,12 +77,12 @@ export type AnalyticsImplementation = { }; // @public -export const AnalyticsImplementationBlueprint: ExtensionBlueprint_2<{ +export const AnalyticsImplementationBlueprint: ExtensionBlueprint<{ kind: 'analytics'; params: ( params: AnalyticsImplementationFactory, - ) => ExtensionBlueprintParams_2>; - output: ExtensionDataRef_2< + ) => ExtensionBlueprintParams>; + output: ExtensionDataRef< AnalyticsImplementationFactory<{}>, 'core.analytics.factory', {} @@ -96,7 +91,7 @@ export const AnalyticsImplementationBlueprint: ExtensionBlueprint_2<{ config: {}; configInput: {}; dataRefs: { - factory: ConfigurableExtensionDataRef_2< + factory: ConfigurableExtensionDataRef< AnalyticsImplementationFactory<{}>, 'core.analytics.factory', {} @@ -149,7 +144,7 @@ export type AnyRouteRefParams = | undefined; // @public -export const ApiBlueprint: ExtensionBlueprint_2<{ +export const ApiBlueprint: ExtensionBlueprint<{ kind: 'api'; params: < TApi, @@ -157,13 +152,13 @@ export const ApiBlueprint: ExtensionBlueprint_2<{ TDeps extends { [name in string]: unknown }, >( params: ApiFactory, - ) => ExtensionBlueprintParams_2; - output: ExtensionDataRef_2; + ) => ExtensionBlueprintParams; + output: ExtensionDataRef; inputs: {}; config: {}; configInput: {}; dataRefs: { - factory: ConfigurableExtensionDataRef_2< + factory: ConfigurableExtensionDataRef< AnyApiFactory, 'core.api.factory', {} @@ -388,16 +383,16 @@ export interface ConfigurableExtensionDataRef< // @public (undocumented) export const coreExtensionData: { - title: ConfigurableExtensionDataRef_2; - icon: ConfigurableExtensionDataRef_2; - reactElement: ConfigurableExtensionDataRef_2< + title: ConfigurableExtensionDataRef; + icon: ConfigurableExtensionDataRef; + reactElement: ConfigurableExtensionDataRef< JSX_2.Element, 'core.reactElement', {} >; - routePath: ConfigurableExtensionDataRef_2; - routeRef: ConfigurableExtensionDataRef_2< - RouteRef, + routePath: ConfigurableExtensionDataRef; + routeRef: ConfigurableExtensionDataRef< + RouteRef, 'core.routing.ref', {} >; @@ -909,7 +904,7 @@ export const errorApiRef: ApiRef; // @public (undocumented) export const ErrorDisplay: { (props: ErrorDisplayProps): JSX.Element | null; - ref: SwappableComponentRef_2; + ref: SwappableComponentRef; }; // @public (undocumented) @@ -956,7 +951,7 @@ export interface ExtensionBlueprint< // (undocumented) make< TName extends string | undefined, - TParamsInput extends AnyParamsInput_2>, + TParamsInput extends AnyParamsInput>, UParentInputs extends ExtensionDataRef, >(args: { name?: TName; @@ -1011,7 +1006,7 @@ export interface ExtensionBlueprint< }; factory( originalFactory: < - TParamsInput extends AnyParamsInput_2>, + TParamsInput extends AnyParamsInput>, >( params: TParamsInput extends ExtensionBlueprintDefineParams ? TParamsInput @@ -1226,7 +1221,7 @@ export type ExtensionDefinitionParameters = { params?: object | ExtensionBlueprintDefineParams; }; -// @public (undocumented) +// @public @deprecated (undocumented) export type ExtensionFactoryMiddleware = ( originalFactory: (contextOverrides?: { config?: JsonObject; @@ -1471,14 +1466,14 @@ export const microsoftAuthApiRef: ApiRef< >; // @public -export const NavItemBlueprint: ExtensionBlueprint_2<{ +export const NavItemBlueprint: ExtensionBlueprint<{ kind: 'nav-item'; params: { title: string; icon: IconComponent; routeRef: RouteRef; }; - output: ExtensionDataRef_2< + output: ExtensionDataRef< { title: string; icon: IconComponent; @@ -1491,7 +1486,7 @@ export const NavItemBlueprint: ExtensionBlueprint_2<{ config: {}; configInput: {}; dataRefs: { - target: ConfigurableExtensionDataRef_2< + target: ConfigurableExtensionDataRef< { title: string; icon: IconComponent; @@ -1506,7 +1501,7 @@ export const NavItemBlueprint: ExtensionBlueprint_2<{ // @public (undocumented) export const NotFoundErrorPage: { (props: NotFoundErrorPageProps): JSX.Element | null; - ref: SwappableComponentRef_2; + ref: SwappableComponentRef; }; // @public (undocumented) @@ -1594,7 +1589,7 @@ export interface OverridableExtensionDefinition< TExtraInputs extends { [inputName in string]: ExtensionInput; }, - TParamsInput extends AnyParamsInput>, + TParamsInput extends AnyParamsInput_2>, UParentInputs extends ExtensionDataRef, >( args: Expand< @@ -1620,7 +1615,7 @@ export interface OverridableExtensionDefinition< }; factory?( originalFactory: < - TFactoryParamsReturn extends AnyParamsInput< + TFactoryParamsReturn extends AnyParamsInput_2< NonNullable >, >( @@ -1719,7 +1714,7 @@ export interface OverridableFrontendPlugin< } // @public -export const PageBlueprint: ExtensionBlueprint_2<{ +export const PageBlueprint: ExtensionBlueprint<{ kind: 'page'; params: { defaultPath?: [Error: `Use the 'path' param instead`]; @@ -1731,23 +1726,23 @@ export const PageBlueprint: ExtensionBlueprint_2<{ noHeader?: boolean; }; output: - | ExtensionDataRef_2 - | ExtensionDataRef_2< - RouteRef, + | ExtensionDataRef + | ExtensionDataRef< + RouteRef, 'core.routing.ref', { optional: true; } > - | ExtensionDataRef_2 - | ExtensionDataRef_2< + | ExtensionDataRef + | ExtensionDataRef< string, 'core.title', { optional: true; } > - | ExtensionDataRef_2< + | ExtensionDataRef< IconElement, 'core.icon', { @@ -1755,24 +1750,24 @@ export const PageBlueprint: ExtensionBlueprint_2<{ } >; inputs: { - pages: ExtensionInput_2< - | ConfigurableExtensionDataRef_2 - | ConfigurableExtensionDataRef_2 - | ConfigurableExtensionDataRef_2< - RouteRef, + pages: ExtensionInput< + | ConfigurableExtensionDataRef + | ConfigurableExtensionDataRef + | ConfigurableExtensionDataRef< + RouteRef, 'core.routing.ref', { optional: true; } > - | ConfigurableExtensionDataRef_2< + | ConfigurableExtensionDataRef< string, 'core.title', { optional: true; } > - | ConfigurableExtensionDataRef_2< + | ConfigurableExtensionDataRef< IconElement, 'core.icon', { @@ -1800,7 +1795,7 @@ export const PageBlueprint: ExtensionBlueprint_2<{ // @public export const PageLayout: { (props: PageLayoutProps): JSX.Element | null; - ref: SwappableComponentRef_2; + ref: SwappableComponentRef; }; // @public @@ -1839,14 +1834,14 @@ export type PendingOAuthRequest = { }; // @public -export const PluginHeaderActionBlueprint: ExtensionBlueprint_2<{ +export const PluginHeaderActionBlueprint: ExtensionBlueprint<{ kind: 'plugin-header-action'; params: (params: { loader: () => Promise; - }) => ExtensionBlueprintParams_2<{ + }) => ExtensionBlueprintParams<{ loader: () => Promise; }>; - output: ExtensionDataRef_2; + output: ExtensionDataRef; inputs: {}; config: {}; configInput: {}; @@ -1909,7 +1904,7 @@ export type ProfileInfoApi = { // @public (undocumented) export const Progress: { (props: ProgressProps): JSX.Element | null; - ref: SwappableComponentRef_2; + ref: SwappableComponentRef; }; // @public (undocumented) @@ -2020,7 +2015,7 @@ export type StorageValueSnapshot = }; // @public -export const SubPageBlueprint: ExtensionBlueprint_2<{ +export const SubPageBlueprint: ExtensionBlueprint<{ kind: 'sub-page'; params: { path: string; @@ -2030,17 +2025,17 @@ export const SubPageBlueprint: ExtensionBlueprint_2<{ routeRef?: RouteRef; }; output: - | ExtensionDataRef_2 - | ExtensionDataRef_2< - RouteRef, + | ExtensionDataRef + | ExtensionDataRef< + RouteRef, 'core.routing.ref', { optional: true; } > - | ExtensionDataRef_2 - | ExtensionDataRef_2 - | ExtensionDataRef_2< + | ExtensionDataRef + | ExtensionDataRef + | ExtensionDataRef< IconElement, 'core.icon', { diff --git a/packages/frontend-plugin-api/src/wiring/types.ts b/packages/frontend-plugin-api/src/wiring/types.ts index 0b59e7a7fb..d462803820 100644 --- a/packages/frontend-plugin-api/src/wiring/types.ts +++ b/packages/frontend-plugin-api/src/wiring/types.ts @@ -60,7 +60,10 @@ export type ExtensionDataContainer = : never; }; -/** @public */ +/** + * @public + * @deprecated Moved to {@link @backstage/frontend-app-api#ExtensionFactoryMiddleware} + */ export type ExtensionFactoryMiddleware = ( originalFactory: (contextOverrides?: { config?: JsonObject;