@backstage/frontend-plugin-api 0.9.5-next.2 → 0.9.5

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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # @backstage/frontend-plugin-api
2
2
 
3
+ ## 0.9.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 3e21b8d: Added `getNodesByRoutePath` method to the `AppTreeApi`.
8
+ - f1efb47: Add support for defining multiple attachment points for extensions and blueprints.
9
+ - 58ec9e7: Removed older versions of React packages as a preparatory step for upgrading to React 19. This commit does not introduce any functional changes, but removes dependencies on previous React versions, allowing for a cleaner upgrade path in subsequent commits.
10
+ - 9ff3322: Allow route references to be installed in multiple app instances as long as their name is the same.
11
+ - Updated dependencies
12
+ - @backstage/core-components@0.16.4
13
+ - @backstage/core-plugin-api@1.10.4
14
+ - @backstage/version-bridge@1.0.11
15
+ - @backstage/types@1.2.1
16
+
17
+ ## 0.9.5-next.3
18
+
19
+ ### Patch Changes
20
+
21
+ - f1efb47: Add support for defining multiple attachment points for extensions and blueprints.
22
+ - Updated dependencies
23
+ - @backstage/core-components@0.16.4-next.1
24
+ - @backstage/core-plugin-api@1.10.4-next.0
25
+ - @backstage/types@1.2.1
26
+ - @backstage/version-bridge@1.0.11-next.0
27
+
3
28
  ## 0.9.5-next.2
4
29
 
5
30
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"AppTreeApi.esm.js","sources":["../../../src/apis/definitions/AppTreeApi.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 { createApiRef } from '@backstage/core-plugin-api';\nimport { FrontendPlugin, Extension, ExtensionDataRef } from '../../wiring';\n\n/**\n * The specification for this {@link AppNode} in the {@link AppTree}.\n *\n * @public\n * @remarks\n *\n * The specifications for a collection of app nodes is all the information needed\n * to build the tree and instantiate the nodes.\n */\nexport interface AppNodeSpec {\n readonly id: string;\n readonly attachTo: { id: string; input: string };\n readonly extension: Extension<unknown, unknown>;\n readonly disabled: boolean;\n readonly config?: unknown;\n readonly source?: FrontendPlugin;\n}\n\n/**\n * The connections from this {@link AppNode} to other nodes.\n *\n * @public\n * @remarks\n *\n * The app node edges are resolved based on the app node specs, regardless of whether\n * adjacent nodes are disabled or not. If no parent attachment is present or\n */\nexport interface AppNodeEdges {\n readonly attachedTo?: { node: AppNode; input: string };\n readonly attachments: ReadonlyMap<string, AppNode[]>;\n}\n\n/**\n * The instance of this {@link AppNode} in the {@link AppTree}.\n *\n * @public\n * @remarks\n *\n * The app node instance is created when the `factory` function of an extension is called.\n * Instances will only be present for nodes in the app that are connected to the root\n * node and not disabled\n */\nexport interface AppNodeInstance {\n /** Returns a sequence of all extension data refs that were output by this instance */\n getDataRefs(): Iterable<ExtensionDataRef<unknown>>;\n /** Get the output data for a single extension data ref */\n getData<T>(ref: ExtensionDataRef<T>): T | undefined;\n}\n\n/**\n * A node in the {@link AppTree}.\n *\n * @public\n */\nexport interface AppNode {\n /** The specification for how this node should be instantiated */\n readonly spec: AppNodeSpec;\n /** The edges from this node to other nodes in the app tree */\n readonly edges: AppNodeEdges;\n /** The instance of this node, if it was instantiated */\n readonly instance?: AppNodeInstance;\n}\n\n/**\n * The app tree containing all {@link AppNode}s of the app.\n *\n * @public\n */\nexport interface AppTree {\n /** The root node of the app */\n readonly root: AppNode;\n /** A map of all nodes in the app by ID, including orphaned or disabled nodes */\n readonly nodes: ReadonlyMap<string /* id */, AppNode>;\n /** A sequence of all nodes with a parent that is not reachable from the app root node */\n readonly orphans: Iterable<AppNode>;\n}\n\n/**\n * The API for interacting with the {@link AppTree}.\n *\n * @public\n */\nexport interface AppTreeApi {\n /**\n * Get the {@link AppTree} for the app.\n */\n getTree(): { tree: AppTree };\n\n /**\n * Get all nodes in the app that are mounted at a given route path.\n */\n getNodesByRoutePath(sourcePath: string): { nodes: AppNode[] };\n}\n\n/**\n * The `ApiRef` of {@link AppTreeApi}.\n *\n * @public\n */\nexport const appTreeApiRef = createApiRef<AppTreeApi>({ id: 'core.app-tree' });\n"],"names":[],"mappings":";;AAsHO,MAAM,aAAgB,GAAA,YAAA,CAAyB,EAAE,EAAA,EAAI,iBAAiB;;;;"}
1
+ {"version":3,"file":"AppTreeApi.esm.js","sources":["../../../src/apis/definitions/AppTreeApi.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 { createApiRef } from '@backstage/core-plugin-api';\nimport {\n FrontendPlugin,\n Extension,\n ExtensionDataRef,\n ExtensionAttachToSpec,\n} from '../../wiring';\n\n/**\n * The specification for this {@link AppNode} in the {@link AppTree}.\n *\n * @public\n * @remarks\n *\n * The specifications for a collection of app nodes is all the information needed\n * to build the tree and instantiate the nodes.\n */\nexport interface AppNodeSpec {\n readonly id: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly extension: Extension<unknown, unknown>;\n readonly disabled: boolean;\n readonly config?: unknown;\n readonly source?: FrontendPlugin;\n}\n\n/**\n * The connections from this {@link AppNode} to other nodes.\n *\n * @public\n * @remarks\n *\n * The app node edges are resolved based on the app node specs, regardless of whether\n * adjacent nodes are disabled or not. If no parent attachment is present or\n */\nexport interface AppNodeEdges {\n readonly attachedTo?: { node: AppNode; input: string };\n readonly attachments: ReadonlyMap<string, AppNode[]>;\n}\n\n/**\n * The instance of this {@link AppNode} in the {@link AppTree}.\n *\n * @public\n * @remarks\n *\n * The app node instance is created when the `factory` function of an extension is called.\n * Instances will only be present for nodes in the app that are connected to the root\n * node and not disabled\n */\nexport interface AppNodeInstance {\n /** Returns a sequence of all extension data refs that were output by this instance */\n getDataRefs(): Iterable<ExtensionDataRef<unknown>>;\n /** Get the output data for a single extension data ref */\n getData<T>(ref: ExtensionDataRef<T>): T | undefined;\n}\n\n/**\n * A node in the {@link AppTree}.\n *\n * @public\n */\nexport interface AppNode {\n /** The specification for how this node should be instantiated */\n readonly spec: AppNodeSpec;\n /** The edges from this node to other nodes in the app tree */\n readonly edges: AppNodeEdges;\n /** The instance of this node, if it was instantiated */\n readonly instance?: AppNodeInstance;\n}\n\n/**\n * The app tree containing all {@link AppNode}s of the app.\n *\n * @public\n */\nexport interface AppTree {\n /** The root node of the app */\n readonly root: AppNode;\n /** A map of all nodes in the app by ID, including orphaned or disabled nodes */\n readonly nodes: ReadonlyMap<string /* id */, AppNode>;\n /** A sequence of all nodes with a parent that is not reachable from the app root node */\n readonly orphans: Iterable<AppNode>;\n}\n\n/**\n * The API for interacting with the {@link AppTree}.\n *\n * @public\n */\nexport interface AppTreeApi {\n /**\n * Get the {@link AppTree} for the app.\n */\n getTree(): { tree: AppTree };\n\n /**\n * Get all nodes in the app that are mounted at a given route path.\n */\n getNodesByRoutePath(sourcePath: string): { nodes: AppNode[] };\n}\n\n/**\n * The `ApiRef` of {@link AppTreeApi}.\n *\n * @public\n */\nexport const appTreeApiRef = createApiRef<AppTreeApi>({ id: 'core.app-tree' });\n"],"names":[],"mappings":";;AA2HO,MAAM,aAAgB,GAAA,YAAA,CAAyB,EAAE,EAAA,EAAI,iBAAiB;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2024 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 {\n AnyExtensionDataRef,\n ApiHolder,\n AppNode,\n ExtensionDataValue,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: ExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: { id: string; input: string };\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: AnyExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: AnyExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: { id: string; input: string };\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n readonly output: Array<AnyExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n };\n}>({\n type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AA6Ba,MAAA,yBAAA,GAA4B,WAAW,MA6DjD,CAAA;AAAA,EACD,IAAM,EAAA,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;;;"}
1
+ {"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2024 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 {\n AnyExtensionDataRef,\n ApiHolder,\n AppNode,\n ExtensionAttachToSpec,\n ExtensionDataValue,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: ExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: AnyExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: AnyExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n readonly output: Array<AnyExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n };\n}>({\n type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AA8Ba,MAAA,yBAAA,GAA4B,WAAW,MA6DjD,CAAA;AAAA,EACD,IAAM,EAAA,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;;;"}
package/dist/index.d.ts CHANGED
@@ -350,6 +350,14 @@ type JoinStringUnion<U, TDiv extends string = ', ', TResult extends string = ''>
350
350
  /** @ignore */
351
351
  type VerifyExtensionFactoryOutput<UDeclaredOutput extends AnyExtensionDataRef, UFactoryOutput extends ExtensionDataValue<any, any>> = (UDeclaredOutput extends any ? UDeclaredOutput['config']['optional'] extends true ? never : UDeclaredOutput['id'] : never) extends infer IRequiredOutputIds ? [IRequiredOutputIds] extends [UFactoryOutput['id']] ? [UFactoryOutput['id']] extends [UDeclaredOutput['id']] ? {} : `Error: The extension factory has undeclared output(s): ${JoinStringUnion<Exclude<UFactoryOutput['id'], UDeclaredOutput['id']>>}` : `Error: The extension factory is missing the following output(s): ${JoinStringUnion<Exclude<IRequiredOutputIds, UFactoryOutput['id']>>}` : never;
352
352
  /** @public */
353
+ type ExtensionAttachToSpec = {
354
+ id: string;
355
+ input: string;
356
+ } | Array<{
357
+ id: string;
358
+ input: string;
359
+ }>;
360
+ /** @public */
353
361
  type CreateExtensionOptions<TKind extends string | undefined, TName extends string | undefined, UOutput extends AnyExtensionDataRef, TInputs extends {
354
362
  [inputName in string]: ExtensionInput<AnyExtensionDataRef, {
355
363
  optional: boolean;
@@ -360,10 +368,7 @@ type CreateExtensionOptions<TKind extends string | undefined, TName extends stri
360
368
  }, UFactoryOutput extends ExtensionDataValue<any, any>> = {
361
369
  kind?: TKind;
362
370
  name?: TName;
363
- attachTo: {
364
- id: string;
365
- input: string;
366
- };
371
+ attachTo: ExtensionAttachToSpec;
367
372
  disabled?: boolean;
368
373
  inputs?: TInputs;
369
374
  output: Array<UOutput>;
@@ -410,10 +415,7 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
410
415
  singleton: boolean;
411
416
  }>;
412
417
  }>(args: Expand<{
413
- attachTo?: {
414
- id: string;
415
- input: string;
416
- };
418
+ attachTo?: ExtensionAttachToSpec;
417
419
  disabled?: boolean;
418
420
  inputs?: TExtraInputs & {
419
421
  [KName in keyof T['inputs']]?: `Error: Input '${KName & string}' is already defined in parent definition`;
@@ -484,10 +486,7 @@ type PortableSchema<TOutput, TInput = TOutput> = {
484
486
  interface Extension<TConfig, TConfigInput = TConfig> {
485
487
  $$type: '@backstage/Extension';
486
488
  readonly id: string;
487
- readonly attachTo: {
488
- id: string;
489
- input: string;
490
- };
489
+ readonly attachTo: ExtensionAttachToSpec;
491
490
  readonly disabled: boolean;
492
491
  readonly configSchema?: PortableSchema<TConfig, TConfigInput>;
493
492
  }
@@ -580,10 +579,7 @@ type CreateExtensionBlueprintOptions<TKind extends string, TName extends string
580
579
  [name in string]: AnyExtensionDataRef;
581
580
  }> = {
582
581
  kind: TKind;
583
- attachTo: {
584
- id: string;
585
- input: string;
586
- };
582
+ attachTo: ExtensionAttachToSpec;
587
583
  disabled?: boolean;
588
584
  inputs?: TInputs;
589
585
  output: Array<UOutput>;
@@ -630,10 +626,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
630
626
  dataRefs: T['dataRefs'];
631
627
  make<TNewName extends string | undefined>(args: {
632
628
  name?: TNewName;
633
- attachTo?: {
634
- id: string;
635
- input: string;
636
- };
629
+ attachTo?: ExtensionAttachToSpec;
637
630
  disabled?: boolean;
638
631
  params: T['params'];
639
632
  }): ExtensionDefinition<{
@@ -660,10 +653,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
660
653
  }>;
661
654
  }>(args: {
662
655
  name?: TNewName;
663
- attachTo?: {
664
- id: string;
665
- input: string;
666
- };
656
+ attachTo?: ExtensionAttachToSpec;
667
657
  disabled?: boolean;
668
658
  inputs?: TExtraInputs & {
669
659
  [KName in keyof T['inputs']]?: `Error: Input '${KName & string}' is already defined in parent definition`;
@@ -740,10 +730,7 @@ declare function createExtensionBlueprint<TParams extends object, UOutput extend
740
730
  */
741
731
  interface AppNodeSpec {
742
732
  readonly id: string;
743
- readonly attachTo: {
744
- id: string;
745
- input: string;
746
- };
733
+ readonly attachTo: ExtensionAttachToSpec;
747
734
  readonly extension: Extension<unknown, unknown>;
748
735
  readonly disabled: boolean;
749
736
  readonly config?: unknown;
@@ -1369,4 +1356,4 @@ declare namespace createComponentExtension {
1369
1356
  }, "core.component.component", {}>;
1370
1357
  }
1371
1358
 
1372
- export { type AnalyticsApi, AnalyticsContext, type AnalyticsContextValue, type AnalyticsEvent, type AnalyticsEventAttributes, type AnalyticsTracker, type AnyExtensionDataRef, type AnyExternalRoutes, type AnyRouteRefParams, type AnyRoutes, ApiBlueprint, type AppNode, type AppNodeEdges, type AppNodeInstance, type AppNodeSpec, AppRootElementBlueprint, AppRootWrapperBlueprint, type AppTree, type AppTreeApi, type CommonAnalyticsContext, type ComponentRef, type ComponentsApi, type ConfigurableExtensionDataRef, type CoreErrorBoundaryFallbackProps, type CoreNotFoundErrorPageProps, type CoreProgressProps, type CreateExtensionBlueprintOptions, type CreateExtensionOptions, type CreateFrontendModuleOptions, type Extension, type ExtensionBlueprint, type ExtensionBlueprintParameters, ExtensionBoundary, type ExtensionBoundaryProps, type ExtensionDataContainer, type ExtensionDataRef, type ExtensionDataRefToValue, type ExtensionDataValue, type ExtensionDefinition, type ExtensionDefinitionParameters, type ExtensionInput, type ExtensionOverrides, type ExternalRouteRef, type FeatureFlagConfig, type FrontendFeature, type FrontendModule, type FrontendPlugin, IconBundleBlueprint, type IconComponent, type IconsApi, NavItemBlueprint, NavLogoBlueprint, PageBlueprint, type PluginOptions, type PortableSchema, type ResolveInputValueOverrides, type ResolvedExtensionInput, type ResolvedExtensionInputs, type RouteFunc, type RouteRef, type RouteResolutionApi, type RouteResolutionApiResolveOptions, RouterBlueprint, SignInPageBlueprint, type SubRouteRef, ThemeBlueprint, TranslationBlueprint, analyticsApiRef, appTreeApiRef, componentsApiRef, coreComponentRefs, coreExtensionData, createComponentExtension, createComponentRef, createExtension, createExtensionBlueprint, createExtensionDataRef, createExtensionInput, createExternalRouteRef, createFrontendModule, createFrontendPlugin, createRouteRef, createSubRouteRef, iconsApiRef, routeResolutionApiRef, useAnalytics, useComponentRef, useRouteRef, useRouteRefParams };
1359
+ export { type AnalyticsApi, AnalyticsContext, type AnalyticsContextValue, type AnalyticsEvent, type AnalyticsEventAttributes, type AnalyticsTracker, type AnyExtensionDataRef, type AnyExternalRoutes, type AnyRouteRefParams, type AnyRoutes, ApiBlueprint, type AppNode, type AppNodeEdges, type AppNodeInstance, type AppNodeSpec, AppRootElementBlueprint, AppRootWrapperBlueprint, type AppTree, type AppTreeApi, type CommonAnalyticsContext, type ComponentRef, type ComponentsApi, type ConfigurableExtensionDataRef, type CoreErrorBoundaryFallbackProps, type CoreNotFoundErrorPageProps, type CoreProgressProps, type CreateExtensionBlueprintOptions, type CreateExtensionOptions, type CreateFrontendModuleOptions, type Extension, type ExtensionAttachToSpec, type ExtensionBlueprint, type ExtensionBlueprintParameters, ExtensionBoundary, type ExtensionBoundaryProps, type ExtensionDataContainer, type ExtensionDataRef, type ExtensionDataRefToValue, type ExtensionDataValue, type ExtensionDefinition, type ExtensionDefinitionParameters, type ExtensionInput, type ExtensionOverrides, type ExternalRouteRef, type FeatureFlagConfig, type FrontendFeature, type FrontendModule, type FrontendPlugin, IconBundleBlueprint, type IconComponent, type IconsApi, NavItemBlueprint, NavLogoBlueprint, PageBlueprint, type PluginOptions, type PortableSchema, type ResolveInputValueOverrides, type ResolvedExtensionInput, type ResolvedExtensionInputs, type RouteFunc, type RouteRef, type RouteResolutionApi, type RouteResolutionApiResolveOptions, RouterBlueprint, SignInPageBlueprint, type SubRouteRef, ThemeBlueprint, TranslationBlueprint, analyticsApiRef, appTreeApiRef, componentsApiRef, coreComponentRefs, coreExtensionData, createComponentExtension, createComponentRef, createExtension, createExtensionBlueprint, createExtensionDataRef, createExtensionInput, createExternalRouteRef, createFrontendModule, createFrontendPlugin, createRouteRef, createSubRouteRef, iconsApiRef, routeResolutionApiRef, useAnalytics, useComponentRef, useRouteRef, useRouteRefParams };
@@ -32,7 +32,9 @@ function createExtension(options) {
32
32
  if (options.name) {
33
33
  parts.push(`name=${options.name}`);
34
34
  }
35
- parts.push(`attachTo=${options.attachTo.id}@${options.attachTo.input}`);
35
+ parts.push(
36
+ `attachTo=${[options.attachTo].flat().map((a) => `${a.id}@${a.input}`).join("+")}`
37
+ );
36
38
  return `ExtensionDefinition{${parts.join(",")}}`;
37
39
  },
38
40
  override(overrideOptions) {
@@ -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 {\n ExtensionDataContainer,\n createExtensionDataContainer,\n} from './createExtensionDataContainer';\nimport {\n AnyExtensionDataRef,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { z } from 'zod';\nimport { createSchemaFromZod } from '../schema/createSchemaFromZod';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\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<AnyExtensionDataRef>\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 AnyExtensionDataRef,\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 CreateExtensionOptions<\n TKind extends string | undefined,\n TName extends string | undefined,\n UOutput extends AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\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: { id: string; input: string };\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?: AnyExtensionDataRef;\n inputs?: {\n [KName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n params?: object;\n};\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 AnyExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n >(\n args: Expand<\n {\n attachTo?: { id: string; input: string };\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 context?: Expand<\n {\n config?: T['config'];\n inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;\n } & ([T['params']] extends [never]\n ? {}\n : { params?: Partial<T['params']> })\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 : { params?: Partial<T['params']> })\n > &\n VerifyExtensionFactoryOutput<\n AnyExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >,\n ): ExtensionDefinition<{\n kind: T['kind'];\n name: T['name'];\n output: AnyExtensionDataRef 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 AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\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 output: UOutput;\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(`attachTo=${options.attachTo.id}@${options.attachTo.input}`);\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 AnyExtensionDataRef[],\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":"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"}
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 {\n ExtensionDataContainer,\n createExtensionDataContainer,\n} from './createExtensionDataContainer';\nimport {\n AnyExtensionDataRef,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { z } from 'zod';\nimport { createSchemaFromZod } from '../schema/createSchemaFromZod';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\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<AnyExtensionDataRef>\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 AnyExtensionDataRef,\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 AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\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?: AnyExtensionDataRef;\n inputs?: {\n [KName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n params?: object;\n};\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 AnyExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\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 context?: Expand<\n {\n config?: T['config'];\n inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;\n } & ([T['params']] extends [never]\n ? {}\n : { params?: Partial<T['params']> })\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 : { params?: Partial<T['params']> })\n > &\n VerifyExtensionFactoryOutput<\n AnyExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >,\n ): ExtensionDefinition<{\n kind: T['kind'];\n name: T['name'];\n output: AnyExtensionDataRef 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 AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\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 output: UOutput;\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 AnyExtensionDataRef[],\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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"createExtensionBlueprint.esm.js","sources":["../../src/wiring/createExtensionBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 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 ExtensionDefinition,\n ResolvedExtensionInputs,\n VerifyExtensionFactoryOutput,\n createExtension,\n ctxParamsSymbol,\n} from './createExtension';\nimport { z } from 'zod';\nimport { ExtensionInput } from './createExtensionInput';\nimport {\n AnyExtensionDataRef,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport {\n ExtensionDataContainer,\n createExtensionDataContainer,\n} from './createExtensionDataContainer';\nimport {\n ResolveInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\n\n/**\n * @public\n */\nexport type CreateExtensionBlueprintOptions<\n TKind extends string,\n TName extends string | undefined,\n TParams,\n UOutput extends AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TDataRefs extends { [name in string]: AnyExtensionDataRef },\n> = {\n kind: TKind;\n attachTo: { id: string; input: string };\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n name?: TName;\n config?: {\n schema: TConfigSchema;\n };\n factory(\n params: TParams,\n 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 },\n ): Iterable<UFactoryOutput>;\n\n dataRefs?: TDataRefs;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionBlueprintParameters = {\n kind: string;\n name?: string;\n params?: object;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: AnyExtensionDataRef;\n inputs?: {\n [KName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n dataRefs?: { [name in string]: AnyExtensionDataRef };\n};\n\n/**\n * @public\n */\nexport interface ExtensionBlueprint<\n T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,\n> {\n dataRefs: T['dataRefs'];\n\n make<TNewName extends string | undefined>(args: {\n name?: TNewName;\n attachTo?: { id: string; input: string };\n disabled?: boolean;\n params: T['params'];\n }): ExtensionDefinition<{\n kind: T['kind'];\n name: string | undefined extends TNewName ? T['name'] : TNewName;\n config: T['config'];\n configInput: T['configInput'];\n output: T['output'];\n inputs: T['inputs'];\n params: T['params'];\n }>;\n\n /**\n * Creates a new extension from the blueprint.\n *\n * You must either pass `params` directly, or define a `factory` that can\n * optionally call the original factory with the same params.\n */\n makeWithOverrides<\n TNewName extends string | undefined,\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends AnyExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n >(args: {\n name?: TNewName;\n attachTo?: { id: string; input: string };\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 params: T['params'],\n context?: {\n config?: T['config'];\n inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;\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 VerifyExtensionFactoryOutput<\n AnyExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >;\n }): ExtensionDefinition<{\n config: (string extends keyof TExtensionConfigSchema\n ? {}\n : {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n }) &\n T['config'];\n configInput: (string extends keyof TExtensionConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >) &\n T['configInput'];\n output: AnyExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n kind: T['kind'];\n name: string | undefined extends TNewName ? T['name'] : TNewName;\n params: T['params'];\n }>;\n}\n\n/**\n * A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating\n * types and instances of those types.\n *\n * @public\n */\nexport function createExtensionBlueprint<\n TParams extends object,\n UOutput extends AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TKind extends string,\n TName extends string | undefined = undefined,\n TDataRefs extends { [name in string]: AnyExtensionDataRef } = never,\n>(\n options: CreateExtensionBlueprintOptions<\n TKind,\n TName,\n TParams,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n TDataRefs\n >,\n): ExtensionBlueprint<{\n kind: TKind;\n name: TName;\n params: TParams;\n output: UOutput;\n inputs: string extends keyof TInputs ? {} : TInputs;\n config: string extends keyof TConfigSchema\n ? {}\n : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n dataRefs: TDataRefs;\n}> {\n return {\n dataRefs: options.dataRefs,\n make(args) {\n return createExtension({\n kind: options.kind,\n name: args.name ?? options.name,\n attachTo: args.attachTo ?? options.attachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: options.inputs,\n output: options.output as AnyExtensionDataRef[],\n config: options.config,\n factory: ctx =>\n options.factory(\n { ...args.params, ...(ctx as any)[ctxParamsSymbol] },\n ctx,\n ) as Iterable<ExtensionDataValue<any, any>>,\n }) as ExtensionDefinition;\n },\n makeWithOverrides(args) {\n return createExtension({\n kind: options.kind,\n name: args.name ?? options.name,\n attachTo: args.attachTo ?? options.attachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: { ...args.inputs, ...options.inputs },\n output: (args.output ?? options.output) as AnyExtensionDataRef[],\n config:\n options.config || args.config\n ? {\n schema: {\n ...options.config?.schema,\n ...args.config?.schema,\n },\n }\n : undefined,\n factory: ctx => {\n const { node, config, inputs, apis } = ctx;\n return args.factory(\n (innerParams, innerContext) => {\n return createExtensionDataContainer<UOutput>(\n options.factory(\n { ...innerParams, ...(ctx as any)[ctxParamsSymbol] },\n {\n apis,\n node,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n },\n ) as Iterable<any>,\n options.output,\n );\n },\n {\n apis,\n node,\n config: config as any,\n inputs: inputs as any,\n },\n ) as Iterable<ExtensionDataValue<any, any>>;\n },\n }) as ExtensionDefinition;\n },\n } as ExtensionBlueprint<{\n kind: TKind;\n name: TName;\n params: TParams;\n output: UOutput;\n inputs: string extends keyof TInputs ? {} : TInputs;\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 dataRefs: TDataRefs;\n }>;\n}\n"],"names":[],"mappings":";;;;AAsNO,SAAS,yBAed,OA2BC,EAAA;AACD,EAAO,OAAA;AAAA,IACL,UAAU,OAAQ,CAAA,QAAA;AAAA,IAClB,KAAK,IAAM,EAAA;AACT,MAAA,OAAO,eAAgB,CAAA;AAAA,QACrB,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,IAAA,EAAM,IAAK,CAAA,IAAA,IAAQ,OAAQ,CAAA,IAAA;AAAA,QAC3B,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,OAAA,EAAS,SACP,OAAQ,CAAA,OAAA;AAAA,UACN,EAAE,GAAG,IAAA,CAAK,QAAQ,GAAI,GAAA,CAAY,eAAe,CAAE,EAAA;AAAA,UACnD;AAAA;AACF,OACH,CAAA;AAAA,KACH;AAAA,IACA,kBAAkB,IAAM,EAAA;AACtB,MAAA,OAAO,eAAgB,CAAA;AAAA,QACrB,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,IAAA,EAAM,IAAK,CAAA,IAAA,IAAQ,OAAQ,CAAA,IAAA;AAAA,QAC3B,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAQ,EAAE,GAAG,KAAK,MAAQ,EAAA,GAAG,QAAQ,MAAO,EAAA;AAAA,QAC5C,MAAA,EAAS,IAAK,CAAA,MAAA,IAAU,OAAQ,CAAA,MAAA;AAAA,QAChC,MACE,EAAA,OAAA,CAAQ,MAAU,IAAA,IAAA,CAAK,MACnB,GAAA;AAAA,UACE,MAAQ,EAAA;AAAA,YACN,GAAG,QAAQ,MAAQ,EAAA,MAAA;AAAA,YACnB,GAAG,KAAK,MAAQ,EAAA;AAAA;AAClB,SAEF,GAAA,KAAA,CAAA;AAAA,QACN,SAAS,CAAO,GAAA,KAAA;AACd,UAAA,MAAM,EAAE,IAAA,EAAM,MAAQ,EAAA,MAAA,EAAQ,MAAS,GAAA,GAAA;AACvC,UAAA,OAAO,IAAK,CAAA,OAAA;AAAA,YACV,CAAC,aAAa,YAAiB,KAAA;AAC7B,cAAO,OAAA,4BAAA;AAAA,gBACL,OAAQ,CAAA,OAAA;AAAA,kBACN,EAAE,GAAG,WAAA,EAAa,GAAI,GAAA,CAAY,eAAe,CAAE,EAAA;AAAA,kBACnD;AAAA,oBACE,IAAA;AAAA,oBACA,IAAA;AAAA,oBACA,MAAA,EAAS,cAAc,MAAU,IAAA,MAAA;AAAA,oBACjC,MAAQ,EAAA,qBAAA;AAAA,sBACN,OAAQ,CAAA,MAAA;AAAA,sBACR,MAAA;AAAA,sBACA,YAAc,EAAA;AAAA;AAChB;AACF,iBACF;AAAA,gBACA,OAAQ,CAAA;AAAA,eACV;AAAA,aACF;AAAA,YACA;AAAA,cACE,IAAA;AAAA,cACA,IAAA;AAAA,cACA,MAAA;AAAA,cACA;AAAA;AACF,WACF;AAAA;AACF,OACD,CAAA;AAAA;AACH,GACF;AAoBF;;;;"}
1
+ {"version":3,"file":"createExtensionBlueprint.esm.js","sources":["../../src/wiring/createExtensionBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 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 ExtensionAttachToSpec,\n ExtensionDefinition,\n ResolvedExtensionInputs,\n VerifyExtensionFactoryOutput,\n createExtension,\n ctxParamsSymbol,\n} from './createExtension';\nimport { z } from 'zod';\nimport { ExtensionInput } from './createExtensionInput';\nimport {\n AnyExtensionDataRef,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport {\n ExtensionDataContainer,\n createExtensionDataContainer,\n} from './createExtensionDataContainer';\nimport {\n ResolveInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\n\n/**\n * @public\n */\nexport type CreateExtensionBlueprintOptions<\n TKind extends string,\n TName extends string | undefined,\n TParams,\n UOutput extends AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TDataRefs extends { [name in string]: AnyExtensionDataRef },\n> = {\n kind: TKind;\n attachTo: ExtensionAttachToSpec;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n name?: TName;\n config?: {\n schema: TConfigSchema;\n };\n factory(\n params: TParams,\n 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 },\n ): Iterable<UFactoryOutput>;\n\n dataRefs?: TDataRefs;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionBlueprintParameters = {\n kind: string;\n name?: string;\n params?: object;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: AnyExtensionDataRef;\n inputs?: {\n [KName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n dataRefs?: { [name in string]: AnyExtensionDataRef };\n};\n\n/**\n * @public\n */\nexport interface ExtensionBlueprint<\n T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,\n> {\n dataRefs: T['dataRefs'];\n\n make<TNewName extends string | undefined>(args: {\n name?: TNewName;\n attachTo?: ExtensionAttachToSpec;\n disabled?: boolean;\n params: T['params'];\n }): ExtensionDefinition<{\n kind: T['kind'];\n name: string | undefined extends TNewName ? T['name'] : TNewName;\n config: T['config'];\n configInput: T['configInput'];\n output: T['output'];\n inputs: T['inputs'];\n params: T['params'];\n }>;\n\n /**\n * Creates a new extension from the blueprint.\n *\n * You must either pass `params` directly, or define a `factory` that can\n * optionally call the original factory with the same params.\n */\n makeWithOverrides<\n TNewName extends string | undefined,\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends AnyExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n >(args: {\n name?: TNewName;\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 params: T['params'],\n context?: {\n config?: T['config'];\n inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;\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 VerifyExtensionFactoryOutput<\n AnyExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >;\n }): ExtensionDefinition<{\n config: (string extends keyof TExtensionConfigSchema\n ? {}\n : {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n }) &\n T['config'];\n configInput: (string extends keyof TExtensionConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >) &\n T['configInput'];\n output: AnyExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n kind: T['kind'];\n name: string | undefined extends TNewName ? T['name'] : TNewName;\n params: T['params'];\n }>;\n}\n\n/**\n * A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating\n * types and instances of those types.\n *\n * @public\n */\nexport function createExtensionBlueprint<\n TParams extends object,\n UOutput extends AnyExtensionDataRef,\n TInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TKind extends string,\n TName extends string | undefined = undefined,\n TDataRefs extends { [name in string]: AnyExtensionDataRef } = never,\n>(\n options: CreateExtensionBlueprintOptions<\n TKind,\n TName,\n TParams,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n TDataRefs\n >,\n): ExtensionBlueprint<{\n kind: TKind;\n name: TName;\n params: TParams;\n output: UOutput;\n inputs: string extends keyof TInputs ? {} : TInputs;\n config: string extends keyof TConfigSchema\n ? {}\n : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n dataRefs: TDataRefs;\n}> {\n return {\n dataRefs: options.dataRefs,\n make(args) {\n return createExtension({\n kind: options.kind,\n name: args.name ?? options.name,\n attachTo: args.attachTo ?? options.attachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: options.inputs,\n output: options.output as AnyExtensionDataRef[],\n config: options.config,\n factory: ctx =>\n options.factory(\n { ...args.params, ...(ctx as any)[ctxParamsSymbol] },\n ctx,\n ) as Iterable<ExtensionDataValue<any, any>>,\n }) as ExtensionDefinition;\n },\n makeWithOverrides(args) {\n return createExtension({\n kind: options.kind,\n name: args.name ?? options.name,\n attachTo: args.attachTo ?? options.attachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: { ...args.inputs, ...options.inputs },\n output: (args.output ?? options.output) as AnyExtensionDataRef[],\n config:\n options.config || args.config\n ? {\n schema: {\n ...options.config?.schema,\n ...args.config?.schema,\n },\n }\n : undefined,\n factory: ctx => {\n const { node, config, inputs, apis } = ctx;\n return args.factory(\n (innerParams, innerContext) => {\n return createExtensionDataContainer<UOutput>(\n options.factory(\n { ...innerParams, ...(ctx as any)[ctxParamsSymbol] },\n {\n apis,\n node,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n },\n ) as Iterable<any>,\n options.output,\n );\n },\n {\n apis,\n node,\n config: config as any,\n inputs: inputs as any,\n },\n ) as Iterable<ExtensionDataValue<any, any>>;\n },\n }) as ExtensionDefinition;\n },\n } as ExtensionBlueprint<{\n kind: TKind;\n name: TName;\n params: TParams;\n output: UOutput;\n inputs: string extends keyof TInputs ? {} : TInputs;\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 dataRefs: TDataRefs;\n }>;\n}\n"],"names":[],"mappings":";;;;AAuNO,SAAS,yBAed,OA2BC,EAAA;AACD,EAAO,OAAA;AAAA,IACL,UAAU,OAAQ,CAAA,QAAA;AAAA,IAClB,KAAK,IAAM,EAAA;AACT,MAAA,OAAO,eAAgB,CAAA;AAAA,QACrB,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,IAAA,EAAM,IAAK,CAAA,IAAA,IAAQ,OAAQ,CAAA,IAAA;AAAA,QAC3B,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,OAAA,EAAS,SACP,OAAQ,CAAA,OAAA;AAAA,UACN,EAAE,GAAG,IAAA,CAAK,QAAQ,GAAI,GAAA,CAAY,eAAe,CAAE,EAAA;AAAA,UACnD;AAAA;AACF,OACH,CAAA;AAAA,KACH;AAAA,IACA,kBAAkB,IAAM,EAAA;AACtB,MAAA,OAAO,eAAgB,CAAA;AAAA,QACrB,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,IAAA,EAAM,IAAK,CAAA,IAAA,IAAQ,OAAQ,CAAA,IAAA;AAAA,QAC3B,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAA,EAAU,IAAK,CAAA,QAAA,IAAY,OAAQ,CAAA,QAAA;AAAA,QACnC,QAAQ,EAAE,GAAG,KAAK,MAAQ,EAAA,GAAG,QAAQ,MAAO,EAAA;AAAA,QAC5C,MAAA,EAAS,IAAK,CAAA,MAAA,IAAU,OAAQ,CAAA,MAAA;AAAA,QAChC,MACE,EAAA,OAAA,CAAQ,MAAU,IAAA,IAAA,CAAK,MACnB,GAAA;AAAA,UACE,MAAQ,EAAA;AAAA,YACN,GAAG,QAAQ,MAAQ,EAAA,MAAA;AAAA,YACnB,GAAG,KAAK,MAAQ,EAAA;AAAA;AAClB,SAEF,GAAA,KAAA,CAAA;AAAA,QACN,SAAS,CAAO,GAAA,KAAA;AACd,UAAA,MAAM,EAAE,IAAA,EAAM,MAAQ,EAAA,MAAA,EAAQ,MAAS,GAAA,GAAA;AACvC,UAAA,OAAO,IAAK,CAAA,OAAA;AAAA,YACV,CAAC,aAAa,YAAiB,KAAA;AAC7B,cAAO,OAAA,4BAAA;AAAA,gBACL,OAAQ,CAAA,OAAA;AAAA,kBACN,EAAE,GAAG,WAAA,EAAa,GAAI,GAAA,CAAY,eAAe,CAAE,EAAA;AAAA,kBACnD;AAAA,oBACE,IAAA;AAAA,oBACA,IAAA;AAAA,oBACA,MAAA,EAAS,cAAc,MAAU,IAAA,MAAA;AAAA,oBACjC,MAAQ,EAAA,qBAAA;AAAA,sBACN,OAAQ,CAAA,MAAA;AAAA,sBACR,MAAA;AAAA,sBACA,YAAc,EAAA;AAAA;AAChB;AACF,iBACF;AAAA,gBACA,OAAQ,CAAA;AAAA,eACV;AAAA,aACF;AAAA,YACA;AAAA,cACE,IAAA;AAAA,cACA,IAAA;AAAA,cACA,MAAA;AAAA,cACA;AAAA;AACF,WACF;AAAA;AACF,OACD,CAAA;AAAA;AACH,GACF;AAoBF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../src/wiring/resolveExtensionDefinition.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 {\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport {\n AnyExtensionDataRef,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: { id: string; input: string };\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: AnyExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: AnyExtensionDataRef;\n };\n factory(context: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly inputs: {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n readonly output: Array<AnyExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n const {\n name,\n kind,\n namespace: _skip1,\n override: _skip2,\n ...rest\n } = internalDefinition;\n\n const namespace = internalDefinition.namespace ?? context?.namespace;\n\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n const id = kind ? `${kind}:${namePart}` : namePart;\n\n return {\n ...rest,\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":";;AAkIgB,SAAA,0BAAA,CAGd,YACA,OAC0C,EAAA;AAC1C,EAAM,MAAA,kBAAA,GAAqB,yBAA0B,CAAA,UAAA,CAAW,UAAU,CAAA;AAC1E,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAW,EAAA,MAAA;AAAA,IACX,QAAU,EAAA,MAAA;AAAA,IACV,GAAG;AAAA,GACD,GAAA,kBAAA;AAEJ,EAAM,MAAA,SAAA,GAAY,kBAAmB,CAAA,SAAA,IAAa,OAAS,EAAA,SAAA;AAE3D,EAAM,MAAA,QAAA,GACJ,QAAQ,SAAY,GAAA,CAAA,EAAG,SAAS,CAAI,CAAA,EAAA,IAAI,KAAK,SAAa,IAAA,IAAA;AAC5D,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAuG,oGAAA,EAAA,IAAI,CAAc,WAAA,EAAA,SAAS,SAAS,IAAI,CAAA;AAAA,KACjJ;AAAA;AAGF,EAAA,MAAM,KAAK,IAAO,GAAA,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAK,CAAA,GAAA,QAAA;AAE1C,EAAO,OAAA;AAAA,IACL,GAAG,IAAA;AAAA,IACH,MAAQ,EAAA,sBAAA;AAAA,IACR,SAAS,kBAAmB,CAAA,OAAA;AAAA,IAC5B,EAAA;AAAA,IACA,QAAW,GAAA;AACT,MAAA,OAAO,gBAAgB,EAAE,CAAA,CAAA,CAAA;AAAA;AAC3B,GACF;AACF;;;;"}
1
+ {"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../src/wiring/resolveExtensionDefinition.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 {\n ExtensionAttachToSpec,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport {\n AnyExtensionDataRef,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: AnyExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: AnyExtensionDataRef;\n };\n factory(context: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly inputs: {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n readonly output: Array<AnyExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n const {\n name,\n kind,\n namespace: _skip1,\n override: _skip2,\n ...rest\n } = internalDefinition;\n\n const namespace = internalDefinition.namespace ?? context?.namespace;\n\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n const id = kind ? `${kind}:${namePart}` : namePart;\n\n return {\n ...rest,\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":";;AAmIgB,SAAA,0BAAA,CAGd,YACA,OAC0C,EAAA;AAC1C,EAAM,MAAA,kBAAA,GAAqB,yBAA0B,CAAA,UAAA,CAAW,UAAU,CAAA;AAC1E,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAW,EAAA,MAAA;AAAA,IACX,QAAU,EAAA,MAAA;AAAA,IACV,GAAG;AAAA,GACD,GAAA,kBAAA;AAEJ,EAAM,MAAA,SAAA,GAAY,kBAAmB,CAAA,SAAA,IAAa,OAAS,EAAA,SAAA;AAE3D,EAAM,MAAA,QAAA,GACJ,QAAQ,SAAY,GAAA,CAAA,EAAG,SAAS,CAAI,CAAA,EAAA,IAAI,KAAK,SAAa,IAAA,IAAA;AAC5D,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAuG,oGAAA,EAAA,IAAI,CAAc,WAAA,EAAA,SAAS,SAAS,IAAI,CAAA;AAAA,KACjJ;AAAA;AAGF,EAAA,MAAM,KAAK,IAAO,GAAA,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAK,CAAA,GAAA,QAAA;AAE1C,EAAO,OAAA;AAAA,IACL,GAAG,IAAA;AAAA,IACH,MAAQ,EAAA,sBAAA;AAAA,IACR,SAAS,kBAAmB,CAAA,OAAA;AAAA,IAC5B,EAAA;AAAA,IACA,QAAW,GAAA;AACT,MAAA,OAAO,gBAAgB,EAAE,CAAA,CAAA,CAAA;AAAA;AAC3B,GACF;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/frontend-plugin-api",
3
- "version": "0.9.5-next.2",
3
+ "version": "0.9.5",
4
4
  "backstage": {
5
5
  "role": "web-library"
6
6
  },
@@ -31,20 +31,20 @@
31
31
  "test": "backstage-cli package test"
32
32
  },
33
33
  "dependencies": {
34
- "@backstage/core-components": "0.16.4-next.1",
35
- "@backstage/core-plugin-api": "1.10.4-next.0",
36
- "@backstage/types": "1.2.1",
37
- "@backstage/version-bridge": "1.0.11-next.0",
34
+ "@backstage/core-components": "^0.16.4",
35
+ "@backstage/core-plugin-api": "^1.10.4",
36
+ "@backstage/types": "^1.2.1",
37
+ "@backstage/version-bridge": "^1.0.11",
38
38
  "@material-ui/core": "^4.12.4",
39
39
  "lodash": "^4.17.21",
40
40
  "zod": "^3.22.4",
41
41
  "zod-to-json-schema": "^3.21.4"
42
42
  },
43
43
  "devDependencies": {
44
- "@backstage/cli": "0.30.0-next.2",
45
- "@backstage/frontend-app-api": "0.10.5-next.2",
46
- "@backstage/frontend-test-utils": "0.2.6-next.2",
47
- "@backstage/test-utils": "1.7.5-next.0",
44
+ "@backstage/cli": "^0.30.0",
45
+ "@backstage/frontend-app-api": "^0.10.5",
46
+ "@backstage/frontend-test-utils": "^0.2.6",
47
+ "@backstage/test-utils": "^1.7.5",
48
48
  "@testing-library/jest-dom": "^6.0.0",
49
49
  "@testing-library/react": "^16.0.0",
50
50
  "@types/react": "^18.0.0",