@backstage/frontend-plugin-api 0.11.0-next.1 → 0.11.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/dist/analytics/useAnalytics.esm.js +1 -1
- package/dist/apis/definitions/AppTreeApi.esm.js.map +1 -1
- package/dist/apis/definitions/DialogApi.esm.js.map +1 -1
- package/dist/apis/definitions/SwappableComponentsApi.esm.js +8 -0
- package/dist/apis/definitions/SwappableComponentsApi.esm.js.map +1 -0
- package/dist/blueprints/PageBlueprint.esm.js +10 -0
- package/dist/blueprints/PageBlueprint.esm.js.map +1 -1
- package/dist/blueprints/SignInPageBlueprint.esm.js +8 -0
- package/dist/blueprints/SignInPageBlueprint.esm.js.map +1 -1
- package/dist/blueprints/SwappableComponentBlueprint.esm.js +27 -0
- package/dist/blueprints/SwappableComponentBlueprint.esm.js.map +1 -0
- package/dist/components/DefaultSwappableComponents.esm.js +16 -0
- package/dist/components/DefaultSwappableComponents.esm.js.map +1 -0
- package/dist/components/ErrorBoundary.esm.js +3 -2
- package/dist/components/ErrorBoundary.esm.js.map +1 -1
- package/dist/components/ExtensionBoundary.esm.js +2 -10
- package/dist/components/ExtensionBoundary.esm.js.map +1 -1
- package/dist/components/createSwappableComponent.esm.js +52 -0
- package/dist/components/createSwappableComponent.esm.js.map +1 -0
- package/dist/frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js +9 -0
- package/dist/frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js.map +1 -0
- package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js +4 -1
- package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js.map +1 -1
- package/dist/index.d.ts +244 -86
- package/dist/index.esm.js +4 -4
- package/dist/routing/useRouteRef.esm.js +1 -1
- package/dist/wiring/createExtension.esm.js +7 -0
- package/dist/wiring/createExtension.esm.js.map +1 -1
- package/dist/wiring/createExtensionBlueprint.esm.js +1 -0
- package/dist/wiring/createExtensionBlueprint.esm.js.map +1 -1
- package/dist/wiring/createFrontendModule.esm.js.map +1 -1
- package/dist/wiring/createFrontendPlugin.esm.js +2 -6
- package/dist/wiring/createFrontendPlugin.esm.js.map +1 -1
- package/dist/wiring/resolveInputOverrides.esm.js +3 -0
- package/dist/wiring/resolveInputOverrides.esm.js.map +1 -1
- package/package.json +4 -4
- package/dist/apis/definitions/ComponentsApi.esm.js +0 -12
- package/dist/apis/definitions/ComponentsApi.esm.js.map +0 -1
- package/dist/components/coreComponentRefs.esm.js +0 -19
- package/dist/components/coreComponentRefs.esm.js.map +0 -1
- package/dist/components/createComponentRef.esm.js +0 -12
- package/dist/components/createComponentRef.esm.js.map +0 -1
- package/dist/extensions/createComponentExtension.esm.js +0 -43
- package/dist/extensions/createComponentExtension.esm.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -160,8 +160,8 @@ declare function createExtensionInput<UExtensionData extends ExtensionDataRef<un
|
|
|
160
160
|
optional: TConfig['optional'] extends true ? true : false;
|
|
161
161
|
}>;
|
|
162
162
|
|
|
163
|
-
/** @
|
|
164
|
-
type
|
|
163
|
+
/** @ignore */
|
|
164
|
+
type ResolvedInputValueOverrides<TInputs extends {
|
|
165
165
|
[inputName in string]: ExtensionInput<ExtensionDataRef, {
|
|
166
166
|
optional: boolean;
|
|
167
167
|
singleton: boolean;
|
|
@@ -200,7 +200,45 @@ interface FrontendModule {
|
|
|
200
200
|
readonly $$type: '@backstage/FrontendModule';
|
|
201
201
|
readonly pluginId: string;
|
|
202
202
|
}
|
|
203
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* Creates a new module that can be installed in a Backstage app.
|
|
205
|
+
*
|
|
206
|
+
* @remarks
|
|
207
|
+
*
|
|
208
|
+
* Modules are used to add or override extensions for an existing plugin. If a
|
|
209
|
+
* module provides an extension with the same ID as one provided by the plugin,
|
|
210
|
+
* the extension provided by the module will always take precedence.
|
|
211
|
+
*
|
|
212
|
+
* Every module is created for a specific plugin by providing the
|
|
213
|
+
* unique ID of the plugin that the module should be installed for. If that
|
|
214
|
+
* plugin is not present in the app, the module will be ignored and have no
|
|
215
|
+
* effect.
|
|
216
|
+
*
|
|
217
|
+
* For more information on how modules work, see the
|
|
218
|
+
* {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}
|
|
219
|
+
* in the frontend system documentation.
|
|
220
|
+
*
|
|
221
|
+
* It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
*
|
|
225
|
+
* ```tsx
|
|
226
|
+
* import { createFrontendModule } from '@backstage/frontend-plugin-api';
|
|
227
|
+
*
|
|
228
|
+
* export const exampleModuleCustomPage = createFrontendModule({
|
|
229
|
+
* pluginId: 'example',
|
|
230
|
+
* extensions: [
|
|
231
|
+
* // Overrides the default page for the 'example' plugin
|
|
232
|
+
* PageBlueprint.make({
|
|
233
|
+
* path: '/example',
|
|
234
|
+
* loader: () => import('./CustomPage').then(m => <m.CustomPage />),
|
|
235
|
+
* }),
|
|
236
|
+
* ],
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @public
|
|
241
|
+
*/
|
|
204
242
|
declare function createFrontendModule<TId extends string, TExtensions extends readonly ExtensionDefinition[] = []>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule;
|
|
205
243
|
|
|
206
244
|
/** @public */
|
|
@@ -490,23 +528,41 @@ interface PluginOptions<TId extends string, TRoutes extends {
|
|
|
490
528
|
featureFlags?: FeatureFlagConfig[];
|
|
491
529
|
info?: FrontendPluginInfoOptions;
|
|
492
530
|
}
|
|
493
|
-
/** @public */
|
|
494
|
-
declare function createFrontendPlugin<TId extends string, TRoutes extends {
|
|
495
|
-
[name in string]: RouteRef | SubRouteRef;
|
|
496
|
-
} = {}, TExternalRoutes extends {
|
|
497
|
-
[name in string]: ExternalRouteRef;
|
|
498
|
-
} = {}, TExtensions extends readonly ExtensionDefinition[] = []>(options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>): FrontendPlugin<TRoutes, TExternalRoutes, MakeSortedExtensionsMap<TExtensions[number], TId>>;
|
|
499
531
|
/**
|
|
532
|
+
* Creates a new plugin that can be installed in a Backstage app.
|
|
533
|
+
*
|
|
534
|
+
* @remarks
|
|
535
|
+
*
|
|
536
|
+
* Every plugin is created with a unique ID and a set of extensions
|
|
537
|
+
* that are installed as part of the plugin.
|
|
538
|
+
*
|
|
539
|
+
* For more information on how plugins work, see the
|
|
540
|
+
* {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}
|
|
541
|
+
* in the frontend system documentation.
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
*
|
|
545
|
+
* ```tsx
|
|
546
|
+
* import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
|
|
547
|
+
*
|
|
548
|
+
* export const examplePlugin = createFrontendPlugin({
|
|
549
|
+
* pluginId: 'example',
|
|
550
|
+
* extensions: [
|
|
551
|
+
* PageBlueprint.make({
|
|
552
|
+
* path: '/example',
|
|
553
|
+
* loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),
|
|
554
|
+
* }),
|
|
555
|
+
* ],
|
|
556
|
+
* });
|
|
557
|
+
* ```
|
|
558
|
+
*
|
|
500
559
|
* @public
|
|
501
|
-
* @deprecated The `id` option is deprecated, use `pluginId` instead.
|
|
502
560
|
*/
|
|
503
561
|
declare function createFrontendPlugin<TId extends string, TRoutes extends {
|
|
504
562
|
[name in string]: RouteRef | SubRouteRef;
|
|
505
563
|
} = {}, TExternalRoutes extends {
|
|
506
564
|
[name in string]: ExternalRouteRef;
|
|
507
|
-
} = {}, TExtensions extends readonly ExtensionDefinition[] = []>(options:
|
|
508
|
-
id: string;
|
|
509
|
-
}): FrontendPlugin<TRoutes, TExternalRoutes, MakeSortedExtensionsMap<TExtensions[number], TId>>;
|
|
565
|
+
} = {}, TExtensions extends readonly ExtensionDefinition[] = []>(options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>): FrontendPlugin<TRoutes, TExternalRoutes, MakeSortedExtensionsMap<TExtensions[number], TId>>;
|
|
510
566
|
|
|
511
567
|
/**
|
|
512
568
|
* Feature flag configuration.
|
|
@@ -718,7 +774,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
|
|
|
718
774
|
};
|
|
719
775
|
factory(originalFactory: <TParamsInput extends AnyParamsInput$1<NonNullable<T['params']>>>(params: TParamsInput extends ExtensionBlueprintDefineParams ? TParamsInput : T['params'] extends ExtensionBlueprintDefineParams ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`' : T['params'], context?: {
|
|
720
776
|
config?: T['config'];
|
|
721
|
-
inputs?:
|
|
777
|
+
inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;
|
|
722
778
|
}) => ExtensionDataContainer<NonNullable<T['output']>>, context: {
|
|
723
779
|
node: AppNode;
|
|
724
780
|
apis: ApiHolder;
|
|
@@ -742,9 +798,52 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
|
|
|
742
798
|
}>;
|
|
743
799
|
}
|
|
744
800
|
/**
|
|
745
|
-
*
|
|
746
|
-
*
|
|
801
|
+
* Creates a new extension blueprint that encapsulates the creation of
|
|
802
|
+
* extensions of particular kinds.
|
|
747
803
|
*
|
|
804
|
+
* @remarks
|
|
805
|
+
*
|
|
806
|
+
* For details on how blueprints work, see the
|
|
807
|
+
* {@link https://backstage.io/docs/frontend-system/architecture/extension-blueprints | documentation for extension blueprints}
|
|
808
|
+
* in the frontend system documentation.
|
|
809
|
+
*
|
|
810
|
+
* Extension blueprints make it much easier for users to create new extensions
|
|
811
|
+
* for your plugin. Rather than letting them use {@link createExtension}
|
|
812
|
+
* directly, you can define a set of parameters and default factory for your
|
|
813
|
+
* blueprint, removing a lot of the boilerplate and complexity that is otherwise
|
|
814
|
+
* needed to create an extension.
|
|
815
|
+
*
|
|
816
|
+
* Each blueprint has its own `kind` that helps identify and group the
|
|
817
|
+
* extensions that have been created with it. For example the
|
|
818
|
+
* {@link PageBlueprint} has the kind `'page'`, and extensions created with it
|
|
819
|
+
* will be given the ID `'page:<plugin-id>[/<name>]'`. Blueprints should always
|
|
820
|
+
* be exported as `<PascalCaseKind>Blueprint`.
|
|
821
|
+
*
|
|
822
|
+
* When creating a blueprint the type of the parameters are inferred from the
|
|
823
|
+
* `factory` function that you provide. The exception to that is when you need
|
|
824
|
+
* your blueprint to include inferred type parameters, in which case you need to
|
|
825
|
+
* use the `defineParams` option. See the documentation for the `defineParams`
|
|
826
|
+
* option for more details on how that works.
|
|
827
|
+
*
|
|
828
|
+
* @example
|
|
829
|
+
* ```tsx
|
|
830
|
+
* // In your plugin library
|
|
831
|
+
* export const GreetingBlueprint = createExtensionBlueprint({
|
|
832
|
+
* kind: 'greeting',
|
|
833
|
+
* attachTo: { id: 'example', input: 'greetings' },
|
|
834
|
+
* output: [coreExtensionData.reactElement],
|
|
835
|
+
* factory(params: { greeting: string }) {
|
|
836
|
+
* return [coreExtensionData.reactElement(<h1>{params.greeting}</h1>)];
|
|
837
|
+
* },
|
|
838
|
+
* });
|
|
839
|
+
*
|
|
840
|
+
* // Someone using your blueprint in their plugin
|
|
841
|
+
* const exampleGreeting = GreetingBlueprint.make({
|
|
842
|
+
* params: {
|
|
843
|
+
* greeting: 'Hello, world!',
|
|
844
|
+
* },
|
|
845
|
+
* });
|
|
846
|
+
* ```
|
|
748
847
|
* @public
|
|
749
848
|
*/
|
|
750
849
|
declare function createExtensionBlueprint<TParams extends object | ExtensionBlueprintDefineParams, UOutput extends ExtensionDataRef, TInputs extends {
|
|
@@ -877,7 +976,7 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
|
|
|
877
976
|
};
|
|
878
977
|
factory?(originalFactory: <TFactoryParamsReturn extends AnyParamsInput<NonNullable<T['params']>>>(context?: Expand<{
|
|
879
978
|
config?: T['config'];
|
|
880
|
-
inputs?:
|
|
979
|
+
inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;
|
|
881
980
|
} & ([T['params']] extends [never] ? {} : {
|
|
882
981
|
params?: TFactoryParamsReturn extends ExtensionBlueprintDefineParams ? TFactoryParamsReturn : T['params'] extends ExtensionBlueprintDefineParams ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`' : Partial<T['params']>;
|
|
883
982
|
})>) => ExtensionDataContainer<NonNullable<T['output']>>, context: {
|
|
@@ -903,7 +1002,41 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
|
|
|
903
1002
|
}>>;
|
|
904
1003
|
}>;
|
|
905
1004
|
};
|
|
906
|
-
/**
|
|
1005
|
+
/**
|
|
1006
|
+
* Creates a new extension definition for installation in a Backstage app.
|
|
1007
|
+
*
|
|
1008
|
+
* @remarks
|
|
1009
|
+
*
|
|
1010
|
+
* This is a low-level function for creation of extensions with arbitrary inputs
|
|
1011
|
+
* and outputs and is typically only intended to be used for advanced overrides
|
|
1012
|
+
* or framework-level extensions. For most extension creation needs, it is
|
|
1013
|
+
* recommended to use existing {@link ExtensionBlueprint}s instead. You can find
|
|
1014
|
+
* blueprints both in the `@backstage/frontend-plugin-api` package as well as
|
|
1015
|
+
* other plugin libraries. There is also a list of
|
|
1016
|
+
* {@link https://backstage.io/docs/frontend-system/building-plugins/common-extension-blueprints | commonly used blueprints}
|
|
1017
|
+
* in the frontend system documentation.
|
|
1018
|
+
*
|
|
1019
|
+
* Extension definitions that are created with this function can be installed in
|
|
1020
|
+
* a Backstage app via a {@link FrontendPlugin} or {@link FrontendModule}.
|
|
1021
|
+
*
|
|
1022
|
+
* For more details on how extensions work, see the
|
|
1023
|
+
* {@link https://backstage.io/docs/frontend-system/architecture/extensions | documentation for extensions}.
|
|
1024
|
+
*
|
|
1025
|
+
* @example
|
|
1026
|
+
*
|
|
1027
|
+
* ```ts
|
|
1028
|
+
* const myExtension = createExtension({
|
|
1029
|
+
* name: 'example',
|
|
1030
|
+
* attachTo: { id: 'app', input: 'root' },
|
|
1031
|
+
* output: [coreExtensionData.reactElement],
|
|
1032
|
+
* factory() {
|
|
1033
|
+
* return [coreExtensionData.reactElement(<h1>Hello, world!</h1>)];
|
|
1034
|
+
* },
|
|
1035
|
+
* });
|
|
1036
|
+
* ```
|
|
1037
|
+
*
|
|
1038
|
+
* @public
|
|
1039
|
+
*/
|
|
907
1040
|
declare function createExtension<UOutput extends ExtensionDataRef, TInputs extends {
|
|
908
1041
|
[inputName in string]: ExtensionInput<ExtensionDataRef, {
|
|
909
1042
|
optional: boolean;
|
|
@@ -959,7 +1092,7 @@ interface AppNodeSpec {
|
|
|
959
1092
|
readonly extension: Extension<unknown, unknown>;
|
|
960
1093
|
readonly disabled: boolean;
|
|
961
1094
|
readonly config?: unknown;
|
|
962
|
-
readonly plugin
|
|
1095
|
+
readonly plugin: FrontendPlugin;
|
|
963
1096
|
}
|
|
964
1097
|
/**
|
|
965
1098
|
* The connections from this {@link AppNode} to other nodes.
|
|
@@ -1034,7 +1167,7 @@ interface AppTreeApi {
|
|
|
1034
1167
|
/**
|
|
1035
1168
|
* Get all nodes in the app that are mounted at a given route path.
|
|
1036
1169
|
*/
|
|
1037
|
-
getNodesByRoutePath(
|
|
1170
|
+
getNodesByRoutePath(routePath: string): {
|
|
1038
1171
|
nodes: AppNode[];
|
|
1039
1172
|
};
|
|
1040
1173
|
}
|
|
@@ -1059,33 +1192,30 @@ declare namespace ExtensionBoundary {
|
|
|
1059
1192
|
}
|
|
1060
1193
|
|
|
1061
1194
|
/** @public */
|
|
1062
|
-
type
|
|
1195
|
+
type SwappableComponentRef<TInnerComponentProps extends {} = {}, TExternalComponentProps extends {} = TInnerComponentProps> = {
|
|
1063
1196
|
id: string;
|
|
1064
|
-
|
|
1197
|
+
TProps: TInnerComponentProps;
|
|
1198
|
+
TExternalProps: TExternalComponentProps;
|
|
1199
|
+
$$type: '@backstage/SwappableComponentRef';
|
|
1065
1200
|
};
|
|
1066
|
-
/**
|
|
1067
|
-
|
|
1201
|
+
/**
|
|
1202
|
+
* Options for creating an SwappableComponent.
|
|
1203
|
+
*
|
|
1204
|
+
* @public
|
|
1205
|
+
*/
|
|
1206
|
+
type CreateSwappableComponentOptions<TInnerComponentProps extends {}, TExternalComponentProps extends {} = TInnerComponentProps> = {
|
|
1068
1207
|
id: string;
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
/** @public */
|
|
1072
|
-
type CoreProgressProps = {};
|
|
1073
|
-
/** @public */
|
|
1074
|
-
type CoreNotFoundErrorPageProps = {
|
|
1075
|
-
children?: ReactNode;
|
|
1208
|
+
loader?: (() => (props: TInnerComponentProps) => JSX.Element | null) | (() => Promise<(props: TInnerComponentProps) => JSX.Element | null>);
|
|
1209
|
+
transformProps?: (props: TExternalComponentProps) => TInnerComponentProps;
|
|
1076
1210
|
};
|
|
1077
|
-
/**
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
declare const coreComponentRefs: {
|
|
1086
|
-
progress: ComponentRef<CoreProgressProps>;
|
|
1087
|
-
notFoundErrorPage: ComponentRef<CoreNotFoundErrorPageProps>;
|
|
1088
|
-
errorBoundaryFallback: ComponentRef<CoreErrorBoundaryFallbackProps>;
|
|
1211
|
+
/**
|
|
1212
|
+
* Creates a SwappableComponent that can be used to render the component, optionally overridden by the app.
|
|
1213
|
+
*
|
|
1214
|
+
* @public
|
|
1215
|
+
*/
|
|
1216
|
+
declare function createSwappableComponent<TInnerComponentProps extends {}, TExternalComponentProps extends {} = TInnerComponentProps>(options: CreateSwappableComponentOptions<TInnerComponentProps, TExternalComponentProps>): {
|
|
1217
|
+
(props: TExternalComponentProps): JSX.Element | null;
|
|
1218
|
+
ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
|
1089
1219
|
};
|
|
1090
1220
|
|
|
1091
1221
|
/**
|
|
@@ -1103,25 +1233,55 @@ declare const coreComponentRefs: {
|
|
|
1103
1233
|
*/
|
|
1104
1234
|
declare function useAppNode(): AppNode | undefined;
|
|
1105
1235
|
|
|
1236
|
+
/** @public */
|
|
1237
|
+
type ProgressProps = {};
|
|
1238
|
+
/** @public */
|
|
1239
|
+
type NotFoundErrorPageProps = {
|
|
1240
|
+
children?: ReactNode;
|
|
1241
|
+
};
|
|
1242
|
+
/** @public */
|
|
1243
|
+
type ErrorDisplayProps = {
|
|
1244
|
+
plugin?: FrontendPlugin;
|
|
1245
|
+
error: Error;
|
|
1246
|
+
resetError: () => void;
|
|
1247
|
+
};
|
|
1248
|
+
|
|
1106
1249
|
/**
|
|
1107
|
-
* API for looking up components based on component refs.
|
|
1108
|
-
*
|
|
1109
1250
|
* @public
|
|
1110
1251
|
*/
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1252
|
+
declare const Progress: {
|
|
1253
|
+
(props: ProgressProps): JSX.Element | null;
|
|
1254
|
+
ref: SwappableComponentRef<ProgressProps, ProgressProps>;
|
|
1255
|
+
};
|
|
1114
1256
|
/**
|
|
1115
|
-
*
|
|
1257
|
+
* @public
|
|
1258
|
+
*/
|
|
1259
|
+
declare const NotFoundErrorPage: {
|
|
1260
|
+
(props: NotFoundErrorPageProps): JSX.Element | null;
|
|
1261
|
+
ref: SwappableComponentRef<NotFoundErrorPageProps, NotFoundErrorPageProps>;
|
|
1262
|
+
};
|
|
1263
|
+
/**
|
|
1264
|
+
* @public
|
|
1265
|
+
*/
|
|
1266
|
+
declare const ErrorDisplay: {
|
|
1267
|
+
(props: ErrorDisplayProps): JSX.Element | null;
|
|
1268
|
+
ref: SwappableComponentRef<ErrorDisplayProps, ErrorDisplayProps>;
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* API for looking up components based on component refs.
|
|
1116
1273
|
*
|
|
1117
1274
|
* @public
|
|
1118
1275
|
*/
|
|
1119
|
-
|
|
1276
|
+
interface SwappableComponentsApi {
|
|
1277
|
+
getComponent<TInnerComponentProps extends {}, TExternalComponentProps extends {} = TInnerComponentProps>(ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>): (props: TInnerComponentProps) => JSX.Element | null;
|
|
1278
|
+
}
|
|
1120
1279
|
/**
|
|
1280
|
+
* The `ApiRef` of {@link SwappableComponentsApi}.
|
|
1281
|
+
*
|
|
1121
1282
|
* @public
|
|
1122
|
-
* Returns the component associated with the given ref.
|
|
1123
1283
|
*/
|
|
1124
|
-
declare
|
|
1284
|
+
declare const swappableComponentsApiRef: _backstage_core_plugin_api.ApiRef<SwappableComponentsApi>;
|
|
1125
1285
|
|
|
1126
1286
|
/**
|
|
1127
1287
|
* IconComponent is the common icon type used throughout Backstage when
|
|
@@ -1168,7 +1328,7 @@ declare const iconsApiRef: _backstage_core_plugin_api.ApiRef<IconsApi>;
|
|
|
1168
1328
|
*
|
|
1169
1329
|
* @public
|
|
1170
1330
|
*/
|
|
1171
|
-
interface DialogApiDialog<TResult =
|
|
1331
|
+
interface DialogApiDialog<TResult = void> {
|
|
1172
1332
|
/**
|
|
1173
1333
|
* Closes the dialog with that provided result.
|
|
1174
1334
|
*
|
|
@@ -1245,7 +1405,7 @@ interface DialogApi {
|
|
|
1245
1405
|
* @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.
|
|
1246
1406
|
* @public
|
|
1247
1407
|
*/
|
|
1248
|
-
show<TResult =
|
|
1408
|
+
show<TResult = void>(elementOrComponent: JSX.Element | ((props: {
|
|
1249
1409
|
dialog: DialogApiDialog<TResult | undefined>;
|
|
1250
1410
|
}) => JSX.Element)): DialogApiDialog<TResult | undefined>;
|
|
1251
1411
|
/**
|
|
@@ -1292,7 +1452,7 @@ interface DialogApi {
|
|
|
1292
1452
|
* @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.
|
|
1293
1453
|
* @public
|
|
1294
1454
|
*/
|
|
1295
|
-
showModal<TResult =
|
|
1455
|
+
showModal<TResult = void>(elementOrComponent: JSX.Element | ((props: {
|
|
1296
1456
|
dialog: DialogApiDialog<TResult>;
|
|
1297
1457
|
}) => JSX.Element)): DialogApiDialog<TResult>;
|
|
1298
1458
|
}
|
|
@@ -1762,39 +1922,37 @@ declare const TranslationBlueprint: ExtensionBlueprint<{
|
|
|
1762
1922
|
};
|
|
1763
1923
|
}>;
|
|
1764
1924
|
|
|
1765
|
-
/**
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
}):
|
|
1925
|
+
/**
|
|
1926
|
+
* Blueprint for creating swappable components from a SwappableComponentRef and a loader
|
|
1927
|
+
*
|
|
1928
|
+
* @public
|
|
1929
|
+
*/
|
|
1930
|
+
declare const SwappableComponentBlueprint: ExtensionBlueprint<{
|
|
1931
|
+
kind: "component";
|
|
1932
|
+
params: <Ref extends SwappableComponentRef<any>>(params: {
|
|
1933
|
+
component: Ref extends SwappableComponentRef<any, infer IExternalComponentProps> ? {
|
|
1934
|
+
ref: Ref;
|
|
1935
|
+
} & ((props: IExternalComponentProps) => JSX.Element | null) : never;
|
|
1936
|
+
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any> ? (() => (props: IInnerComponentProps) => JSX.Element | null) | (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>) : never;
|
|
1937
|
+
}) => ExtensionBlueprintParams<{
|
|
1938
|
+
component: Ref extends SwappableComponentRef<any, infer IExternalComponentProps> ? {
|
|
1939
|
+
ref: Ref;
|
|
1940
|
+
} & ((props: IExternalComponentProps) => JSX.Element | null) : never;
|
|
1941
|
+
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any> ? (() => (props: IInnerComponentProps) => JSX.Element | null) | (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>) : never;
|
|
1942
|
+
}>;
|
|
1943
|
+
output: ExtensionDataRef<{
|
|
1944
|
+
ref: SwappableComponentRef;
|
|
1945
|
+
loader: (() => (props: {}) => JSX.Element | null) | (() => Promise<(props: {}) => JSX.Element | null>);
|
|
1946
|
+
}, "core.swappableComponent", {}>;
|
|
1947
|
+
inputs: {};
|
|
1776
1948
|
config: {};
|
|
1777
1949
|
configInput: {};
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
[x: string]: ExtensionInput<ExtensionDataRef, {
|
|
1784
|
-
optional: boolean;
|
|
1785
|
-
singleton: boolean;
|
|
1786
|
-
}>;
|
|
1950
|
+
dataRefs: {
|
|
1951
|
+
component: ConfigurableExtensionDataRef<{
|
|
1952
|
+
ref: SwappableComponentRef;
|
|
1953
|
+
loader: (() => (props: {}) => JSX.Element | null) | (() => Promise<(props: {}) => JSX.Element | null>);
|
|
1954
|
+
}, "core.swappableComponent", {}>;
|
|
1787
1955
|
};
|
|
1788
|
-
params: never;
|
|
1789
|
-
kind: "component";
|
|
1790
|
-
name: string;
|
|
1791
1956
|
}>;
|
|
1792
|
-
/** @public */
|
|
1793
|
-
declare namespace createComponentExtension {
|
|
1794
|
-
const componentDataRef: ConfigurableExtensionDataRef<{
|
|
1795
|
-
ref: ComponentRef;
|
|
1796
|
-
impl: ComponentType;
|
|
1797
|
-
}, "core.component.component", {}>;
|
|
1798
|
-
}
|
|
1799
1957
|
|
|
1800
|
-
export { type AnalyticsApi, AnalyticsContext, type AnalyticsContextValue, type AnalyticsEvent, type AnalyticsEventAttributes, type AnalyticsImplementation, AnalyticsImplementationBlueprint, type AnalyticsImplementationFactory, type AnalyticsTracker, type AnyExtensionDataRef, type AnyRouteRefParams, ApiBlueprint, type AppNode, type AppNodeEdges, type AppNodeInstance, type AppNodeSpec, AppRootElementBlueprint, AppRootWrapperBlueprint, type AppTree, type AppTreeApi, type
|
|
1958
|
+
export { type AnalyticsApi, AnalyticsContext, type AnalyticsContextValue, type AnalyticsEvent, type AnalyticsEventAttributes, type AnalyticsImplementation, AnalyticsImplementationBlueprint, type AnalyticsImplementationFactory, type AnalyticsTracker, type AnyExtensionDataRef, type AnyRouteRefParams, ApiBlueprint, type AppNode, type AppNodeEdges, type AppNodeInstance, type AppNodeSpec, AppRootElementBlueprint, AppRootWrapperBlueprint, type AppTree, type AppTreeApi, type ConfigurableExtensionDataRef, type CreateExtensionBlueprintOptions, type CreateExtensionOptions, type CreateFrontendFeatureLoaderOptions, type CreateFrontendModuleOptions, type CreateSwappableComponentOptions, type DialogApi, type DialogApiDialog, ErrorDisplay, type ErrorDisplayProps, type Extension, type ExtensionAttachToSpec, type ExtensionBlueprint, type ExtensionBlueprintDefineParams, type ExtensionBlueprintParameters, type ExtensionBlueprintParams, ExtensionBoundary, type ExtensionBoundaryProps, type ExtensionDataContainer, type ExtensionDataRef, type ExtensionDataRefToValue, type ExtensionDataValue, type ExtensionDefinition, type ExtensionDefinitionParameters, type ExtensionFactoryMiddleware, type ExtensionInput, type ExternalRouteRef, type FeatureFlagConfig, type FrontendFeature, type FrontendFeatureLoader, type FrontendModule, type FrontendPlugin, type FrontendPluginInfo, type FrontendPluginInfoOptions, IconBundleBlueprint, type IconComponent, type IconsApi, NavContentBlueprint, type NavContentComponent, type NavContentComponentProps, NavItemBlueprint, NotFoundErrorPage, type NotFoundErrorPageProps, PageBlueprint, type PluginOptions, type PortableSchema, Progress, type ProgressProps, type ResolvedExtensionInput, type ResolvedExtensionInputs, type RouteFunc, type RouteRef, type RouteResolutionApi, RouterBlueprint, SignInPageBlueprint, type SubRouteRef, SwappableComponentBlueprint, type SwappableComponentRef, type SwappableComponentsApi, ThemeBlueprint, TranslationBlueprint, analyticsApiRef, appTreeApiRef, coreExtensionData, createExtension, createExtensionBlueprint, createExtensionBlueprintParams, createExtensionDataRef, createExtensionInput, createExternalRouteRef, createFrontendFeatureLoader, createFrontendModule, createFrontendPlugin, createRouteRef, createSubRouteRef, createSwappableComponent, dialogApiRef, iconsApiRef, routeResolutionApiRef, swappableComponentsApiRef, useAnalytics, useAppNode, useRouteRef, useRouteRefParams };
|
package/dist/index.esm.js
CHANGED
|
@@ -2,7 +2,7 @@ export { AnalyticsContext } from './analytics/AnalyticsContext.esm.js';
|
|
|
2
2
|
export { useAnalytics } from './analytics/useAnalytics.esm.js';
|
|
3
3
|
export { appTreeApiRef } from './apis/definitions/AppTreeApi.esm.js';
|
|
4
4
|
export { SessionState, alertApiRef, appThemeApiRef, atlassianAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, configApiRef, createApiFactory, createApiRef, discoveryApiRef, errorApiRef, featureFlagsApiRef, fetchApiRef, githubAuthApiRef, gitlabAuthApiRef, googleAuthApiRef, identityApiRef, microsoftAuthApiRef, oauthRequestApiRef, oktaAuthApiRef, oneloginAuthApiRef, storageApiRef, useApi, useApiHolder, vmwareCloudAuthApiRef, withApis } from '@backstage/core-plugin-api';
|
|
5
|
-
export {
|
|
5
|
+
export { swappableComponentsApiRef } from './apis/definitions/SwappableComponentsApi.esm.js';
|
|
6
6
|
export { iconsApiRef } from './apis/definitions/IconsApi.esm.js';
|
|
7
7
|
export { dialogApiRef } from './apis/definitions/DialogApi.esm.js';
|
|
8
8
|
export { routeResolutionApiRef } from './apis/definitions/RouteResolutionApi.esm.js';
|
|
@@ -19,11 +19,11 @@ export { RouterBlueprint } from './blueprints/RouterBlueprint.esm.js';
|
|
|
19
19
|
export { SignInPageBlueprint } from './blueprints/SignInPageBlueprint.esm.js';
|
|
20
20
|
export { ThemeBlueprint } from './blueprints/ThemeBlueprint.esm.js';
|
|
21
21
|
export { TranslationBlueprint } from './blueprints/TranslationBlueprint.esm.js';
|
|
22
|
+
export { SwappableComponentBlueprint } from './blueprints/SwappableComponentBlueprint.esm.js';
|
|
22
23
|
export { ExtensionBoundary } from './components/ExtensionBoundary.esm.js';
|
|
23
|
-
export {
|
|
24
|
-
export { createComponentRef } from './components/createComponentRef.esm.js';
|
|
24
|
+
export { createSwappableComponent } from './components/createSwappableComponent.esm.js';
|
|
25
25
|
export { useAppNode } from './components/AppNodeProvider.esm.js';
|
|
26
|
-
export {
|
|
26
|
+
export { ErrorDisplay, NotFoundErrorPage, Progress } from './components/DefaultSwappableComponents.esm.js';
|
|
27
27
|
export { createRouteRef } from './routing/RouteRef.esm.js';
|
|
28
28
|
export { createSubRouteRef } from './routing/SubRouteRef.esm.js';
|
|
29
29
|
export { createExternalRouteRef } from './routing/ExternalRouteRef.esm.js';
|
|
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|
|
2
2
|
import { useLocation } from 'react-router-dom';
|
|
3
3
|
import '../apis/definitions/AppTreeApi.esm.js';
|
|
4
4
|
import { useApi } from '@backstage/core-plugin-api';
|
|
5
|
-
import '../apis/definitions/
|
|
5
|
+
import '../apis/definitions/SwappableComponentsApi.esm.js';
|
|
6
6
|
import '../apis/definitions/IconsApi.esm.js';
|
|
7
7
|
import '../apis/definitions/DialogApi.esm.js';
|
|
8
8
|
import { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi.esm.js';
|
|
@@ -2,6 +2,7 @@ import { resolveInputOverrides } from './resolveInputOverrides.esm.js';
|
|
|
2
2
|
import { createSchemaFromZod } from '../schema/createSchemaFromZod.esm.js';
|
|
3
3
|
import { OpaqueExtensionDefinition } from '../frontend-internal/src/wiring/InternalExtensionDefinition.esm.js';
|
|
4
4
|
import { createExtensionDataContainer } from '../frontend-internal/src/wiring/createExtensionDataContainer.esm.js';
|
|
5
|
+
import '../frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js';
|
|
5
6
|
import '../frontend-internal/src/wiring/InternalFrontendPlugin.esm.js';
|
|
6
7
|
|
|
7
8
|
const ctxParamsSymbol = Symbol("params");
|
|
@@ -90,6 +91,7 @@ function createExtension(options) {
|
|
|
90
91
|
),
|
|
91
92
|
[ctxParamsSymbol]: innerContext?.params
|
|
92
93
|
}),
|
|
94
|
+
"original extension factory",
|
|
93
95
|
options.output
|
|
94
96
|
);
|
|
95
97
|
},
|
|
@@ -100,6 +102,11 @@ function createExtension(options) {
|
|
|
100
102
|
inputs
|
|
101
103
|
}
|
|
102
104
|
);
|
|
105
|
+
if (typeof parentResult !== "object" || !parentResult?.[Symbol.iterator]) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
"extension factory override did not provide an iterable object"
|
|
108
|
+
);
|
|
109
|
+
}
|
|
103
110
|
const deduplicatedResult = /* @__PURE__ */ new Map();
|
|
104
111
|
for (const item of parentResult) {
|
|
105
112
|
deduplicatedResult.set(item.id, item);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createExtension.esm.js","sources":["../../src/wiring/createExtension.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ApiHolder, AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport {\n ResolveInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { z } from 'zod';\nimport { createSchemaFromZod } from '../schema/createSchemaFromZod';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\nimport { ExtensionDataContainer } from './types';\nimport { ExtensionBlueprintDefineParams } from './createExtensionBlueprint';\n\n/**\n * This symbol is used to pass parameter overrides from the extension override to the blueprint factory\n * @internal\n */\nexport const ctxParamsSymbol = Symbol('params');\n\n/**\n * Convert a single extension input into a matching resolved input.\n * @public\n */\nexport type ResolvedExtensionInput<\n TExtensionInput extends ExtensionInput<any, any>,\n> = TExtensionInput['extensionData'] extends Array<ExtensionDataRef>\n ? {\n node: AppNode;\n } & ExtensionDataContainer<TExtensionInput['extensionData'][number]>\n : never;\n\n/**\n * Converts an extension input map into a matching collection of resolved inputs.\n * @public\n */\nexport type ResolvedExtensionInputs<\n TInputs extends {\n [name in string]: ExtensionInput<any, any>;\n },\n> = {\n [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']\n ? Array<Expand<ResolvedExtensionInput<TInputs[InputName]>>>\n : false extends TInputs[InputName]['config']['optional']\n ? Expand<ResolvedExtensionInput<TInputs[InputName]>>\n : Expand<ResolvedExtensionInput<TInputs[InputName]> | undefined>;\n};\n\ntype ToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\ntype PopUnion<U> = ToIntersection<\n U extends any ? () => U : never\n> extends () => infer R\n ? [rest: Exclude<U, R>, next: R]\n : undefined;\n\n/** @ignore */\ntype JoinStringUnion<\n U,\n TDiv extends string = ', ',\n TResult extends string = '',\n> = PopUnion<U> extends [infer IRest extends string, infer INext extends string]\n ? TResult extends ''\n ? JoinStringUnion<IRest, TDiv, INext>\n : JoinStringUnion<IRest, TDiv, `${TResult}${TDiv}${INext}`>\n : TResult;\n\n/** @ignore */\nexport type VerifyExtensionFactoryOutput<\n UDeclaredOutput extends ExtensionDataRef,\n UFactoryOutput extends ExtensionDataValue<any, any>,\n> = (\n UDeclaredOutput extends any\n ? UDeclaredOutput['config']['optional'] extends true\n ? never\n : UDeclaredOutput['id']\n : never\n) extends infer IRequiredOutputIds\n ? [IRequiredOutputIds] extends [UFactoryOutput['id']]\n ? [UFactoryOutput['id']] extends [UDeclaredOutput['id']]\n ? {}\n : `Error: The extension factory has undeclared output(s): ${JoinStringUnion<\n Exclude<UFactoryOutput['id'], UDeclaredOutput['id']>\n >}`\n : `Error: The extension factory is missing the following output(s): ${JoinStringUnion<\n Exclude<IRequiredOutputIds, UFactoryOutput['id']>\n >}`\n : never;\n\n/** @public */\nexport type ExtensionAttachToSpec =\n | { id: string; input: string }\n | Array<{ id: string; input: string }>;\n\n/** @public */\nexport type CreateExtensionOptions<\n TKind extends string | undefined,\n TName extends string | undefined,\n UOutput extends ExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n> = {\n kind?: TKind;\n name?: TName;\n attachTo: ExtensionAttachToSpec;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n inputs: Expand<ResolvedExtensionInputs<TInputs>>;\n }): Iterable<UFactoryOutput>;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionDefinitionParameters = {\n kind?: string;\n name?: string;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: ExtensionDataRef;\n inputs?: {\n [KName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n params?: object | ExtensionBlueprintDefineParams;\n};\n\n/**\n * Same as the one in `createExtensionBlueprint`, but with `ParamsFactory` inlined.\n * It can't be exported because it breaks API reports.\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ((define: TParams) => ReturnType<TParams>)\n :\n | TParams\n | ((\n define: ExtensionBlueprintDefineParams<TParams, TParams>,\n ) => ReturnType<ExtensionBlueprintDefineParams<TParams, TParams>>);\n\n/** @public */\nexport type ExtensionDefinition<\n T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters,\n> = {\n $$type: '@backstage/ExtensionDefinition';\n readonly T: T;\n\n override<\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends ExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(\n args: Expand<\n {\n attachTo?: ExtensionAttachToSpec;\n disabled?: boolean;\n inputs?: TExtraInputs & {\n [KName in keyof T['inputs']]?: `Error: Input '${KName &\n string}' is already defined in parent definition`;\n };\n output?: Array<UNewOutput>;\n config?: {\n schema: TExtensionConfigSchema & {\n [KName in keyof T['config']]?: `Error: Config key '${KName &\n string}' is already defined in parent schema`;\n };\n };\n factory?(\n originalFactory: <\n TFactoryParamsReturn extends AnyParamsInput<\n NonNullable<T['params']>\n >,\n >(\n context?: Expand<\n {\n config?: T['config'];\n inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TFactoryParamsReturn extends ExtensionBlueprintDefineParams\n ? TFactoryParamsReturn\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n >,\n ) => ExtensionDataContainer<NonNullable<T['output']>>,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;\n },\n ): Iterable<UFactoryOutput>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n > &\n VerifyExtensionFactoryOutput<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >,\n ): ExtensionDefinition<{\n kind: T['kind'];\n name: T['name'];\n output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n configInput: T['configInput'] &\n z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >;\n }>;\n};\n\n/** @public */\nexport function createExtension<\n UOutput extends ExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n const TKind extends string | undefined = undefined,\n const TName extends string | undefined = undefined,\n>(\n options: CreateExtensionOptions<\n TKind,\n TName,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput\n >,\n): ExtensionDefinition<{\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n // This inference and remapping back to ExtensionDataRef eliminates any occurrences ConfigurationExtensionDataRef\n output: UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never;\n inputs: TInputs;\n params: never;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n}> {\n const schemaDeclaration = options.config?.schema;\n const configSchema =\n schemaDeclaration &&\n createSchemaFromZod(innerZ =>\n innerZ.object(\n Object.fromEntries(\n Object.entries(schemaDeclaration).map(([k, v]) => [k, v(innerZ)]),\n ),\n ),\n );\n\n return OpaqueExtensionDefinition.createInstance('v2', {\n T: undefined as unknown as {\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<\n ReturnType<TConfigSchema[key]>\n >;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n output: UOutput;\n inputs: TInputs;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n },\n kind: options.kind,\n name: options.name,\n attachTo: options.attachTo,\n disabled: options.disabled ?? false,\n inputs: options.inputs ?? {},\n output: options.output,\n configSchema,\n factory: options.factory,\n toString() {\n const parts: string[] = [];\n if (options.kind) {\n parts.push(`kind=${options.kind}`);\n }\n if (options.name) {\n parts.push(`name=${options.name}`);\n }\n parts.push(\n `attachTo=${[options.attachTo]\n .flat()\n .map(a => `${a.id}@${a.input}`)\n .join('+')}`,\n );\n return `ExtensionDefinition{${parts.join(',')}}`;\n },\n override(overrideOptions) {\n if (!Array.isArray(options.output)) {\n throw new Error(\n 'Cannot override an extension that is not declared using the new format with outputs as an array',\n );\n }\n\n // TODO(Rugvip): Making this a type check would be optimal, but it seems\n // like it's tricky to add that and still have the type\n // inference work correctly for the factory output.\n if (overrideOptions.output && !overrideOptions.factory) {\n throw new Error(\n 'Refused to override output without also overriding factory',\n );\n }\n // TODO(Rugvip): Similar to above, would be nice to error during type checking, but don't want to complicate the types too much\n if (overrideOptions.params && overrideOptions.factory) {\n throw new Error(\n 'Refused to override params and factory at the same time',\n );\n }\n\n return createExtension({\n kind: options.kind,\n name: options.name,\n attachTo: overrideOptions.attachTo ?? options.attachTo,\n disabled: overrideOptions.disabled ?? options.disabled,\n inputs: { ...overrideOptions.inputs, ...options.inputs },\n output: (overrideOptions.output ??\n options.output) as ExtensionDataRef[],\n config:\n options.config || overrideOptions.config\n ? {\n schema: {\n ...options.config?.schema,\n ...overrideOptions.config?.schema,\n },\n }\n : undefined,\n factory: ({ node, apis, config, inputs }) => {\n if (!overrideOptions.factory) {\n return options.factory({\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n [ctxParamsSymbol as any]: overrideOptions.params,\n });\n }\n const parentResult = overrideOptions.factory(\n (innerContext): ExtensionDataContainer<UOutput> => {\n return createExtensionDataContainer<UOutput>(\n options.factory({\n node,\n apis,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n [ctxParamsSymbol as any]: innerContext?.params,\n }) as Iterable<any>,\n options.output,\n );\n },\n {\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n },\n );\n\n const deduplicatedResult = new Map<\n string,\n ExtensionDataValue<any, any>\n >();\n for (const item of parentResult) {\n deduplicatedResult.set(item.id, item);\n }\n\n return deduplicatedResult.values();\n },\n }) as ExtensionDefinition<any>;\n },\n });\n}\n"],"names":[],"mappings":";;;;;;AAmCa,MAAA,eAAA,GAAkB,OAAO,QAAQ;AAyPvC,SAAS,gBAad,OAiCC,EAAA;AACD,EAAM,MAAA,iBAAA,GAAoB,QAAQ,MAAQ,EAAA,MAAA;AAC1C,EAAA,MAAM,eACJ,iBACA,IAAA,mBAAA;AAAA,IAAoB,YAClB,MAAO,CAAA,MAAA;AAAA,MACL,MAAO,CAAA,WAAA;AAAA,QACL,MAAO,CAAA,OAAA,CAAQ,iBAAiB,CAAA,CAAE,IAAI,CAAC,CAAC,CAAG,EAAA,CAAC,MAAM,CAAC,CAAA,EAAG,CAAE,CAAA,MAAM,CAAC,CAAC;AAAA;AAClE;AACF,GACF;AAEF,EAAO,OAAA,yBAAA,CAA0B,eAAe,IAAM,EAAA;AAAA,IACpD,CAAG,EAAA,KAAA,CAAA;AAAA,IAoBH,MAAM,OAAQ,CAAA,IAAA;AAAA,IACd,MAAM,OAAQ,CAAA,IAAA;AAAA,IACd,UAAU,OAAQ,CAAA,QAAA;AAAA,IAClB,QAAA,EAAU,QAAQ,QAAY,IAAA,KAAA;AAAA,IAC9B,MAAA,EAAQ,OAAQ,CAAA,MAAA,IAAU,EAAC;AAAA,IAC3B,QAAQ,OAAQ,CAAA,MAAA;AAAA,IAChB,YAAA;AAAA,IACA,SAAS,OAAQ,CAAA,OAAA;AAAA,IACjB,QAAW,GAAA;AACT,MAAA,MAAM,QAAkB,EAAC;AACzB,MAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,QAAA,KAAA,CAAM,IAAK,CAAA,CAAA,KAAA,EAAQ,OAAQ,CAAA,IAAI,CAAE,CAAA,CAAA;AAAA;AAEnC,MAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,QAAA,KAAA,CAAM,IAAK,CAAA,CAAA,KAAA,EAAQ,OAAQ,CAAA,IAAI,CAAE,CAAA,CAAA;AAAA;AAEnC,MAAM,KAAA,CAAA,IAAA;AAAA,QACJ,YAAY,CAAC,OAAA,CAAQ,QAAQ,CAC1B,CAAA,IAAA,GACA,GAAI,CAAA,CAAA,CAAA,KAAK,GAAG,CAAE,CAAA,EAAE,IAAI,CAAE,CAAA,KAAK,EAAE,CAC7B,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,OACd;AACA,MAAA,OAAO,CAAuB,oBAAA,EAAA,KAAA,CAAM,IAAK,CAAA,GAAG,CAAC,CAAA,CAAA,CAAA;AAAA,KAC/C;AAAA,IACA,SAAS,eAAiB,EAAA;AACxB,MAAA,IAAI,CAAC,KAAA,CAAM,OAAQ,CAAA,OAAA,CAAQ,MAAM,CAAG,EAAA;AAClC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA;AAMF,MAAA,IAAI,eAAgB,CAAA,MAAA,IAAU,CAAC,eAAA,CAAgB,OAAS,EAAA;AACtD,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA;AAGF,MAAI,IAAA,eAAA,CAAgB,MAAU,IAAA,eAAA,CAAgB,OAAS,EAAA;AACrD,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA;AAGF,MAAA,OAAO,eAAgB,CAAA;AAAA,QACrB,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,QAAA,EAAU,eAAgB,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QAC9C,QAAA,EAAU,eAAgB,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QAC9C,QAAQ,EAAE,GAAG,gBAAgB,MAAQ,EAAA,GAAG,QAAQ,MAAO,EAAA;AAAA,QACvD,MAAA,EAAS,eAAgB,CAAA,MAAA,IACvB,OAAQ,CAAA,MAAA;AAAA,QACV,MACE,EAAA,OAAA,CAAQ,MAAU,IAAA,eAAA,CAAgB,MAC9B,GAAA;AAAA,UACE,MAAQ,EAAA;AAAA,YACN,GAAG,QAAQ,MAAQ,EAAA,MAAA;AAAA,YACnB,GAAG,gBAAgB,MAAQ,EAAA;AAAA;AAC7B,SAEF,GAAA,KAAA,CAAA;AAAA,QACN,SAAS,CAAC,EAAE,MAAM,IAAM,EAAA,MAAA,EAAQ,QAAa,KAAA;AAC3C,UAAI,IAAA,CAAC,gBAAgB,OAAS,EAAA;AAC5B,YAAA,OAAO,QAAQ,OAAQ,CAAA;AAAA,cACrB,IAAA;AAAA,cACA,IAAA;AAAA,cACA,MAAA;AAAA,cACA,MAAA;AAAA,cACA,CAAC,eAAsB,GAAG,eAAgB,CAAA;AAAA,aAC3C,CAAA;AAAA;AAEH,UAAA,MAAM,eAAe,eAAgB,CAAA,OAAA;AAAA,YACnC,CAAC,YAAkD,KAAA;AACjD,cAAO,OAAA,4BAAA;AAAA,gBACL,QAAQ,OAAQ,CAAA;AAAA,kBACd,IAAA;AAAA,kBACA,IAAA;AAAA,kBACA,MAAA,EAAS,cAAc,MAAU,IAAA,MAAA;AAAA,kBACjC,MAAQ,EAAA,qBAAA;AAAA,oBACN,OAAQ,CAAA,MAAA;AAAA,oBACR,MAAA;AAAA,oBACA,YAAc,EAAA;AAAA,mBAChB;AAAA,kBACA,CAAC,eAAsB,GAAG,YAAc,EAAA;AAAA,iBACzC,CAAA;AAAA,gBACD,OAAQ,CAAA;AAAA,eACV;AAAA,aACF;AAAA,YACA;AAAA,cACE,IAAA;AAAA,cACA,IAAA;AAAA,cACA,MAAA;AAAA,cACA;AAAA;AACF,WACF;AAEA,UAAM,MAAA,kBAAA,uBAAyB,GAG7B,EAAA;AACF,UAAA,KAAA,MAAW,QAAQ,YAAc,EAAA;AAC/B,YAAmB,kBAAA,CAAA,GAAA,CAAI,IAAK,CAAA,EAAA,EAAI,IAAI,CAAA;AAAA;AAGtC,UAAA,OAAO,mBAAmB,MAAO,EAAA;AAAA;AACnC,OACD,CAAA;AAAA;AACH,GACD,CAAA;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"createExtension.esm.js","sources":["../../src/wiring/createExtension.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ApiHolder, AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport {\n ResolvedInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { z } from 'zod';\nimport { createSchemaFromZod } from '../schema/createSchemaFromZod';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\nimport { ExtensionDataContainer } from './types';\nimport {\n ExtensionBlueprint,\n ExtensionBlueprintDefineParams,\n} from './createExtensionBlueprint';\nimport { FrontendPlugin } from './createFrontendPlugin';\nimport { FrontendModule } from './createFrontendModule';\n\n/**\n * This symbol is used to pass parameter overrides from the extension override to the blueprint factory\n * @internal\n */\nexport const ctxParamsSymbol = Symbol('params');\n\n/**\n * Convert a single extension input into a matching resolved input.\n * @public\n */\nexport type ResolvedExtensionInput<\n TExtensionInput extends ExtensionInput<any, any>,\n> = TExtensionInput['extensionData'] extends Array<ExtensionDataRef>\n ? {\n node: AppNode;\n } & ExtensionDataContainer<TExtensionInput['extensionData'][number]>\n : never;\n\n/**\n * Converts an extension input map into a matching collection of resolved inputs.\n * @public\n */\nexport type ResolvedExtensionInputs<\n TInputs extends {\n [name in string]: ExtensionInput<any, any>;\n },\n> = {\n [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']\n ? Array<Expand<ResolvedExtensionInput<TInputs[InputName]>>>\n : false extends TInputs[InputName]['config']['optional']\n ? Expand<ResolvedExtensionInput<TInputs[InputName]>>\n : Expand<ResolvedExtensionInput<TInputs[InputName]> | undefined>;\n};\n\ntype ToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\ntype PopUnion<U> = ToIntersection<\n U extends any ? () => U : never\n> extends () => infer R\n ? [rest: Exclude<U, R>, next: R]\n : undefined;\n\n/** @ignore */\ntype JoinStringUnion<\n U,\n TDiv extends string = ', ',\n TResult extends string = '',\n> = PopUnion<U> extends [infer IRest extends string, infer INext extends string]\n ? TResult extends ''\n ? JoinStringUnion<IRest, TDiv, INext>\n : JoinStringUnion<IRest, TDiv, `${TResult}${TDiv}${INext}`>\n : TResult;\n\n/** @ignore */\nexport type VerifyExtensionFactoryOutput<\n UDeclaredOutput extends ExtensionDataRef,\n UFactoryOutput extends ExtensionDataValue<any, any>,\n> = (\n UDeclaredOutput extends any\n ? UDeclaredOutput['config']['optional'] extends true\n ? never\n : UDeclaredOutput['id']\n : never\n) extends infer IRequiredOutputIds\n ? [IRequiredOutputIds] extends [UFactoryOutput['id']]\n ? [UFactoryOutput['id']] extends [UDeclaredOutput['id']]\n ? {}\n : `Error: The extension factory has undeclared output(s): ${JoinStringUnion<\n Exclude<UFactoryOutput['id'], UDeclaredOutput['id']>\n >}`\n : `Error: The extension factory is missing the following output(s): ${JoinStringUnion<\n Exclude<IRequiredOutputIds, UFactoryOutput['id']>\n >}`\n : never;\n\n/** @public */\nexport type ExtensionAttachToSpec =\n | { id: string; input: string }\n | Array<{ id: string; input: string }>;\n\n/** @public */\nexport type CreateExtensionOptions<\n TKind extends string | undefined,\n TName extends string | undefined,\n UOutput extends ExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n> = {\n kind?: TKind;\n name?: TName;\n attachTo: ExtensionAttachToSpec;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n inputs: Expand<ResolvedExtensionInputs<TInputs>>;\n }): Iterable<UFactoryOutput>;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionDefinitionParameters = {\n kind?: string;\n name?: string;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: ExtensionDataRef;\n inputs?: {\n [KName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n params?: object | ExtensionBlueprintDefineParams;\n};\n\n/**\n * Same as the one in `createExtensionBlueprint`, but with `ParamsFactory` inlined.\n * It can't be exported because it breaks API reports.\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ((define: TParams) => ReturnType<TParams>)\n :\n | TParams\n | ((\n define: ExtensionBlueprintDefineParams<TParams, TParams>,\n ) => ReturnType<ExtensionBlueprintDefineParams<TParams, TParams>>);\n\n/** @public */\nexport type ExtensionDefinition<\n T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters,\n> = {\n $$type: '@backstage/ExtensionDefinition';\n readonly T: T;\n\n override<\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends ExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(\n args: Expand<\n {\n attachTo?: ExtensionAttachToSpec;\n disabled?: boolean;\n inputs?: TExtraInputs & {\n [KName in keyof T['inputs']]?: `Error: Input '${KName &\n string}' is already defined in parent definition`;\n };\n output?: Array<UNewOutput>;\n config?: {\n schema: TExtensionConfigSchema & {\n [KName in keyof T['config']]?: `Error: Config key '${KName &\n string}' is already defined in parent schema`;\n };\n };\n factory?(\n originalFactory: <\n TFactoryParamsReturn extends AnyParamsInput<\n NonNullable<T['params']>\n >,\n >(\n context?: Expand<\n {\n config?: T['config'];\n inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TFactoryParamsReturn extends ExtensionBlueprintDefineParams\n ? TFactoryParamsReturn\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n >,\n ) => ExtensionDataContainer<NonNullable<T['output']>>,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;\n },\n ): Iterable<UFactoryOutput>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n > &\n VerifyExtensionFactoryOutput<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >,\n ): ExtensionDefinition<{\n kind: T['kind'];\n name: T['name'];\n output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n configInput: T['configInput'] &\n z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >;\n }>;\n};\n\n/**\n * Creates a new extension definition for installation in a Backstage app.\n *\n * @remarks\n *\n * This is a low-level function for creation of extensions with arbitrary inputs\n * and outputs and is typically only intended to be used for advanced overrides\n * or framework-level extensions. For most extension creation needs, it is\n * recommended to use existing {@link ExtensionBlueprint}s instead. You can find\n * blueprints both in the `@backstage/frontend-plugin-api` package as well as\n * other plugin libraries. There is also a list of\n * {@link https://backstage.io/docs/frontend-system/building-plugins/common-extension-blueprints | commonly used blueprints}\n * in the frontend system documentation.\n *\n * Extension definitions that are created with this function can be installed in\n * a Backstage app via a {@link FrontendPlugin} or {@link FrontendModule}.\n *\n * For more details on how extensions work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extensions | documentation for extensions}.\n *\n * @example\n *\n * ```ts\n * const myExtension = createExtension({\n * name: 'example',\n * attachTo: { id: 'app', input: 'root' },\n * output: [coreExtensionData.reactElement],\n * factory() {\n * return [coreExtensionData.reactElement(<h1>Hello, world!</h1>)];\n * },\n * });\n * ```\n *\n * @public\n */\nexport function createExtension<\n UOutput extends ExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n const TKind extends string | undefined = undefined,\n const TName extends string | undefined = undefined,\n>(\n options: CreateExtensionOptions<\n TKind,\n TName,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput\n >,\n): ExtensionDefinition<{\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n // This inference and remapping back to ExtensionDataRef eliminates any occurrences ConfigurationExtensionDataRef\n output: UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never;\n inputs: TInputs;\n params: never;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n}> {\n const schemaDeclaration = options.config?.schema;\n const configSchema =\n schemaDeclaration &&\n createSchemaFromZod(innerZ =>\n innerZ.object(\n Object.fromEntries(\n Object.entries(schemaDeclaration).map(([k, v]) => [k, v(innerZ)]),\n ),\n ),\n );\n\n return OpaqueExtensionDefinition.createInstance('v2', {\n T: undefined as unknown as {\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<\n ReturnType<TConfigSchema[key]>\n >;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n output: UOutput;\n inputs: TInputs;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n },\n kind: options.kind,\n name: options.name,\n attachTo: options.attachTo,\n disabled: options.disabled ?? false,\n inputs: options.inputs ?? {},\n output: options.output,\n configSchema,\n factory: options.factory,\n toString() {\n const parts: string[] = [];\n if (options.kind) {\n parts.push(`kind=${options.kind}`);\n }\n if (options.name) {\n parts.push(`name=${options.name}`);\n }\n parts.push(\n `attachTo=${[options.attachTo]\n .flat()\n .map(a => `${a.id}@${a.input}`)\n .join('+')}`,\n );\n return `ExtensionDefinition{${parts.join(',')}}`;\n },\n override(overrideOptions) {\n if (!Array.isArray(options.output)) {\n throw new Error(\n 'Cannot override an extension that is not declared using the new format with outputs as an array',\n );\n }\n\n // TODO(Rugvip): Making this a type check would be optimal, but it seems\n // like it's tricky to add that and still have the type\n // inference work correctly for the factory output.\n if (overrideOptions.output && !overrideOptions.factory) {\n throw new Error(\n 'Refused to override output without also overriding factory',\n );\n }\n // TODO(Rugvip): Similar to above, would be nice to error during type checking, but don't want to complicate the types too much\n if (overrideOptions.params && overrideOptions.factory) {\n throw new Error(\n 'Refused to override params and factory at the same time',\n );\n }\n\n return createExtension({\n kind: options.kind,\n name: options.name,\n attachTo: overrideOptions.attachTo ?? options.attachTo,\n disabled: overrideOptions.disabled ?? options.disabled,\n inputs: { ...overrideOptions.inputs, ...options.inputs },\n output: (overrideOptions.output ??\n options.output) as ExtensionDataRef[],\n config:\n options.config || overrideOptions.config\n ? {\n schema: {\n ...options.config?.schema,\n ...overrideOptions.config?.schema,\n },\n }\n : undefined,\n factory: ({ node, apis, config, inputs }) => {\n if (!overrideOptions.factory) {\n return options.factory({\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n [ctxParamsSymbol as any]: overrideOptions.params,\n });\n }\n const parentResult = overrideOptions.factory(\n (innerContext): ExtensionDataContainer<UOutput> => {\n return createExtensionDataContainer<UOutput>(\n options.factory({\n node,\n apis,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n [ctxParamsSymbol as any]: innerContext?.params,\n }) as Iterable<any>,\n 'original extension factory',\n options.output,\n );\n },\n {\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n },\n );\n\n if (\n typeof parentResult !== 'object' ||\n !parentResult?.[Symbol.iterator]\n ) {\n throw new Error(\n 'extension factory override did not provide an iterable object',\n );\n }\n\n const deduplicatedResult = new Map<\n string,\n ExtensionDataValue<any, any>\n >();\n for (const item of parentResult) {\n deduplicatedResult.set(item.id, item);\n }\n\n return deduplicatedResult.values();\n },\n }) as ExtensionDefinition<any>;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|