@backstage/frontend-plugin-api 0.11.0-next.0 → 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.
Files changed (61) hide show
  1. package/CHANGELOG.md +211 -0
  2. package/dist/analytics/useAnalytics.esm.js +1 -1
  3. package/dist/apis/definitions/AnalyticsApi.esm.js.map +1 -1
  4. package/dist/apis/definitions/AppTreeApi.esm.js.map +1 -1
  5. package/dist/apis/definitions/DialogApi.esm.js.map +1 -1
  6. package/dist/apis/definitions/RouteResolutionApi.esm.js.map +1 -1
  7. package/dist/apis/definitions/SwappableComponentsApi.esm.js +8 -0
  8. package/dist/apis/definitions/SwappableComponentsApi.esm.js.map +1 -0
  9. package/dist/blueprints/AnalyticsImplementationBlueprint.esm.js +24 -0
  10. package/dist/blueprints/AnalyticsImplementationBlueprint.esm.js.map +1 -0
  11. package/dist/blueprints/AppRootElementBlueprint.esm.js +1 -3
  12. package/dist/blueprints/AppRootElementBlueprint.esm.js.map +1 -1
  13. package/dist/blueprints/AppRootWrapperBlueprint.esm.js +1 -5
  14. package/dist/blueprints/AppRootWrapperBlueprint.esm.js.map +1 -1
  15. package/dist/blueprints/PageBlueprint.esm.js +17 -9
  16. package/dist/blueprints/PageBlueprint.esm.js.map +1 -1
  17. package/dist/blueprints/RouterBlueprint.esm.js +2 -2
  18. package/dist/blueprints/RouterBlueprint.esm.js.map +1 -1
  19. package/dist/blueprints/SignInPageBlueprint.esm.js +9 -1
  20. package/dist/blueprints/SignInPageBlueprint.esm.js.map +1 -1
  21. package/dist/blueprints/SwappableComponentBlueprint.esm.js +27 -0
  22. package/dist/blueprints/SwappableComponentBlueprint.esm.js.map +1 -0
  23. package/dist/components/DefaultSwappableComponents.esm.js +16 -0
  24. package/dist/components/DefaultSwappableComponents.esm.js.map +1 -0
  25. package/dist/components/ErrorBoundary.esm.js +3 -2
  26. package/dist/components/ErrorBoundary.esm.js.map +1 -1
  27. package/dist/components/ExtensionBoundary.esm.js +9 -16
  28. package/dist/components/ExtensionBoundary.esm.js.map +1 -1
  29. package/dist/components/createSwappableComponent.esm.js +52 -0
  30. package/dist/components/createSwappableComponent.esm.js.map +1 -0
  31. package/dist/frontend-internal/src/wiring/InternalExtensionDefinition.esm.js.map +1 -1
  32. package/dist/frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js +9 -0
  33. package/dist/frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js.map +1 -0
  34. package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js +4 -1
  35. package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js.map +1 -1
  36. package/dist/index.d.ts +493 -294
  37. package/dist/index.esm.js +5 -4
  38. package/dist/index.esm.js.map +1 -1
  39. package/dist/routing/RouteRef.esm.js +8 -2
  40. package/dist/routing/RouteRef.esm.js.map +1 -1
  41. package/dist/routing/useRouteRef.esm.js +1 -1
  42. package/dist/wiring/createExtension.esm.js +7 -0
  43. package/dist/wiring/createExtension.esm.js.map +1 -1
  44. package/dist/wiring/createExtensionBlueprint.esm.js +3 -2
  45. package/dist/wiring/createExtensionBlueprint.esm.js.map +1 -1
  46. package/dist/wiring/createExtensionDataRef.esm.js.map +1 -1
  47. package/dist/wiring/createFrontendModule.esm.js.map +1 -1
  48. package/dist/wiring/createFrontendPlugin.esm.js +2 -6
  49. package/dist/wiring/createFrontendPlugin.esm.js.map +1 -1
  50. package/dist/wiring/resolveExtensionDefinition.esm.js.map +1 -1
  51. package/dist/wiring/resolveInputOverrides.esm.js +3 -0
  52. package/dist/wiring/resolveInputOverrides.esm.js.map +1 -1
  53. package/package.json +5 -5
  54. package/dist/apis/definitions/ComponentsApi.esm.js +0 -12
  55. package/dist/apis/definitions/ComponentsApi.esm.js.map +0 -1
  56. package/dist/components/coreComponentRefs.esm.js +0 -19
  57. package/dist/components/coreComponentRefs.esm.js.map +0 -1
  58. package/dist/components/createComponentRef.esm.js +0 -12
  59. package/dist/components/createComponentRef.esm.js.map +0 -1
  60. package/dist/extensions/createComponentExtension.esm.js +0 -43
  61. package/dist/extensions/createComponentExtension.esm.js.map +0 -1
package/dist/index.esm.js CHANGED
@@ -2,11 +2,12 @@ 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 { componentsApiRef, useComponentRef } from './apis/definitions/ComponentsApi.esm.js';
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';
9
9
  export { analyticsApiRef } from './apis/definitions/AnalyticsApi.esm.js';
10
+ export { AnalyticsImplementationBlueprint } from './blueprints/AnalyticsImplementationBlueprint.esm.js';
10
11
  export { ApiBlueprint } from './blueprints/ApiBlueprint.esm.js';
11
12
  export { AppRootElementBlueprint } from './blueprints/AppRootElementBlueprint.esm.js';
12
13
  export { AppRootWrapperBlueprint } from './blueprints/AppRootWrapperBlueprint.esm.js';
@@ -18,11 +19,11 @@ export { RouterBlueprint } from './blueprints/RouterBlueprint.esm.js';
18
19
  export { SignInPageBlueprint } from './blueprints/SignInPageBlueprint.esm.js';
19
20
  export { ThemeBlueprint } from './blueprints/ThemeBlueprint.esm.js';
20
21
  export { TranslationBlueprint } from './blueprints/TranslationBlueprint.esm.js';
22
+ export { SwappableComponentBlueprint } from './blueprints/SwappableComponentBlueprint.esm.js';
21
23
  export { ExtensionBoundary } from './components/ExtensionBoundary.esm.js';
22
- export { coreComponentRefs } from './components/coreComponentRefs.esm.js';
23
- export { createComponentRef } from './components/createComponentRef.esm.js';
24
+ export { createSwappableComponent } from './components/createSwappableComponent.esm.js';
24
25
  export { useAppNode } from './components/AppNodeProvider.esm.js';
25
- export { createComponentExtension } from './extensions/createComponentExtension.esm.js';
26
+ export { ErrorDisplay, NotFoundErrorPage, Progress } from './components/DefaultSwappableComponents.esm.js';
26
27
  export { createRouteRef } from './routing/RouteRef.esm.js';
27
28
  export { createSubRouteRef } from './routing/SubRouteRef.esm.js';
28
29
  export { createExternalRouteRef } from './routing/ExternalRouteRef.esm.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -8,19 +8,24 @@ function toInternalRouteRef(resource) {
8
8
  return r;
9
9
  }
10
10
  class RouteRefImpl {
11
- constructor(params = [], creationSite) {
11
+ constructor(params = [], creationSite, alias) {
12
12
  this.params = params;
13
13
  this.#params = params;
14
14
  this.#creationSite = creationSite;
15
+ this.#alias = alias;
15
16
  }
16
17
  $$type = "@backstage/RouteRef";
17
18
  version = "v1";
18
19
  #id;
19
20
  #params;
20
21
  #creationSite;
22
+ #alias;
21
23
  getParams() {
22
24
  return this.#params;
23
25
  }
26
+ get alias() {
27
+ return this.#alias;
28
+ }
24
29
  getDescription() {
25
30
  if (this.#id) {
26
31
  return this.#id;
@@ -48,7 +53,8 @@ class RouteRefImpl {
48
53
  function createRouteRef(config) {
49
54
  return new RouteRefImpl(
50
55
  config?.params,
51
- describeParentCallSite()
56
+ describeParentCallSite(),
57
+ config?.aliasFor
52
58
  );
53
59
  }
54
60
 
@@ -1 +1 @@
1
- {"version":3,"file":"RouteRef.esm.js","sources":["../../src/routing/RouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Absolute route reference.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface RouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/RouteRef';\n readonly T: TParams;\n}\n\n/** @internal */\nexport interface InternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends RouteRef<TParams> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n>(resource: RouteRef<TParams>): InternalRouteRef<TParams> {\n const r = resource as InternalRouteRef<TParams>;\n if (r.$$type !== '@backstage/RouteRef') {\n throw new Error(`Invalid RouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/** @internal */\nexport function isRouteRef(opaque: { $$type: string }): opaque is RouteRef {\n return opaque.$$type === '@backstage/RouteRef';\n}\n\n/** @internal */\nexport class RouteRefImpl implements InternalRouteRef {\n readonly $$type = '@backstage/RouteRef';\n readonly version = 'v1';\n declare readonly T: never;\n\n #id?: string;\n #params: string[];\n #creationSite: string;\n\n constructor(readonly params: string[] = [], creationSite: string) {\n this.#params = params;\n this.#creationSite = creationSite;\n }\n\n getParams(): string[] {\n return this.#params;\n }\n\n getDescription(): string {\n if (this.#id) {\n return this.#id;\n }\n return `created at '${this.#creationSite}'`;\n }\n\n get #name() {\n return this.$$type.slice('@backstage/'.length);\n }\n\n setId(id: string): void {\n if (!id) {\n throw new Error(`${this.#name} id must be a non-empty string`);\n }\n if (this.#id && this.#id !== id) {\n throw new Error(\n `${this.#name} was referenced twice as both '${this.#id}' and '${id}'`,\n );\n }\n this.#id = id;\n }\n\n toString(): string {\n return `${this.#name}{${this.getDescription()}}`;\n }\n}\n\n/**\n * Create a {@link RouteRef} from a route descriptor.\n *\n * @param config - Description of the route reference to be created.\n * @public\n */\nexport function createRouteRef<\n // Params is the type that we care about and the one to be embedded in the route ref.\n // For example, given the params ['name', 'kind'], Params will be {name: string, kind: string}\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(config?: {\n /** A list of parameter names that the path that this route ref is bound to must contain */\n readonly params: string extends TParamKeys ? (keyof TParams)[] : TParamKeys[];\n}): RouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n return new RouteRefImpl(\n config?.params as string[] | undefined,\n describeParentCallSite(),\n ) as RouteRef<any>;\n}\n"],"names":[],"mappings":";;AA+CO,SAAS,mBAEd,QAAwD,EAAA;AACxD,EAAA,MAAM,CAAI,GAAA,QAAA;AACV,EAAI,IAAA,CAAA,CAAE,WAAW,qBAAuB,EAAA;AACtC,IAAA,MAAM,IAAI,KAAA,CAAM,CAA+B,4BAAA,EAAA,CAAA,CAAE,MAAM,CAAG,CAAA,CAAA,CAAA;AAAA;AAG5D,EAAO,OAAA,CAAA;AACT;AAQO,MAAM,YAAyC,CAAA;AAAA,EASpD,WAAqB,CAAA,MAAA,GAAmB,EAAC,EAAG,YAAsB,EAAA;AAA7C,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACnB,IAAA,IAAA,CAAK,OAAU,GAAA,MAAA;AACf,IAAA,IAAA,CAAK,aAAgB,GAAA,YAAA;AAAA;AACvB,EAXS,MAAS,GAAA,qBAAA;AAAA,EACT,OAAU,GAAA,IAAA;AAAA,EAGnB,GAAA;AAAA,EACA,OAAA;AAAA,EACA,aAAA;AAAA,EAOA,SAAsB,GAAA;AACpB,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AACd,EAEA,cAAyB,GAAA;AACvB,IAAA,IAAI,KAAK,GAAK,EAAA;AACZ,MAAA,OAAO,IAAK,CAAA,GAAA;AAAA;AAEd,IAAO,OAAA,CAAA,YAAA,EAAe,KAAK,aAAa,CAAA,CAAA,CAAA;AAAA;AAC1C,EAEA,IAAI,KAAQ,GAAA;AACV,IAAA,OAAO,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,aAAA,CAAc,MAAM,CAAA;AAAA;AAC/C,EAEA,MAAM,EAAkB,EAAA;AACtB,IAAA,IAAI,CAAC,EAAI,EAAA;AACP,MAAA,MAAM,IAAI,KAAA,CAAM,CAAG,EAAA,IAAA,CAAK,KAAK,CAAgC,8BAAA,CAAA,CAAA;AAAA;AAE/D,IAAA,IAAI,IAAK,CAAA,GAAA,IAAO,IAAK,CAAA,GAAA,KAAQ,EAAI,EAAA;AAC/B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,GAAG,IAAK,CAAA,KAAK,kCAAkC,IAAK,CAAA,GAAG,UAAU,EAAE,CAAA,CAAA;AAAA,OACrE;AAAA;AAEF,IAAA,IAAA,CAAK,GAAM,GAAA,EAAA;AAAA;AACb,EAEA,QAAmB,GAAA;AACjB,IAAA,OAAO,GAAG,IAAK,CAAA,KAAK,CAAI,CAAA,EAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA,CAAA;AAAA;AAEjD;AAQO,SAAS,eAKd,MASA,EAAA;AACA,EAAA,OAAO,IAAI,YAAA;AAAA,IACT,MAAQ,EAAA,MAAA;AAAA,IACR,sBAAuB;AAAA,GACzB;AACF;;;;"}
1
+ {"version":3,"file":"RouteRef.esm.js","sources":["../../src/routing/RouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Absolute route reference.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface RouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/RouteRef';\n readonly T: TParams;\n}\n\n/** @internal */\nexport interface InternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends RouteRef<TParams> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n\n alias: string | undefined;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n>(resource: RouteRef<TParams>): InternalRouteRef<TParams> {\n const r = resource as InternalRouteRef<TParams>;\n if (r.$$type !== '@backstage/RouteRef') {\n throw new Error(`Invalid RouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/** @internal */\nexport function isRouteRef(opaque: { $$type: string }): opaque is RouteRef {\n return opaque.$$type === '@backstage/RouteRef';\n}\n\n/** @internal */\nexport class RouteRefImpl implements InternalRouteRef {\n readonly $$type = '@backstage/RouteRef';\n readonly version = 'v1';\n declare readonly T: never;\n\n #id?: string;\n readonly #params: string[];\n readonly #creationSite: string;\n readonly #alias?: string;\n\n constructor(\n readonly params: string[] = [],\n creationSite: string,\n alias?: string,\n ) {\n this.#params = params;\n this.#creationSite = creationSite;\n this.#alias = alias;\n }\n\n getParams(): string[] {\n return this.#params;\n }\n\n get alias(): string | undefined {\n return this.#alias;\n }\n\n getDescription(): string {\n if (this.#id) {\n return this.#id;\n }\n return `created at '${this.#creationSite}'`;\n }\n\n get #name() {\n return this.$$type.slice('@backstage/'.length);\n }\n\n setId(id: string): void {\n if (!id) {\n throw new Error(`${this.#name} id must be a non-empty string`);\n }\n if (this.#id && this.#id !== id) {\n throw new Error(\n `${this.#name} was referenced twice as both '${this.#id}' and '${id}'`,\n );\n }\n this.#id = id;\n }\n\n toString(): string {\n return `${this.#name}{${this.getDescription()}}`;\n }\n}\n\n/**\n * Create a {@link RouteRef} from a route descriptor.\n *\n * @param config - Description of the route reference to be created.\n * @public\n */\nexport function createRouteRef<\n // Params is the type that we care about and the one to be embedded in the route ref.\n // For example, given the params ['name', 'kind'], Params will be {name: string, kind: string}\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(config?: {\n /** A list of parameter names that the path that this route ref is bound to must contain */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n aliasFor?: string;\n}): RouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n return new RouteRefImpl(\n config?.params as string[] | undefined,\n describeParentCallSite(),\n config?.aliasFor,\n ) as RouteRef<any>;\n}\n"],"names":[],"mappings":";;AAiDO,SAAS,mBAEd,QAAwD,EAAA;AACxD,EAAA,MAAM,CAAI,GAAA,QAAA;AACV,EAAI,IAAA,CAAA,CAAE,WAAW,qBAAuB,EAAA;AACtC,IAAA,MAAM,IAAI,KAAA,CAAM,CAA+B,4BAAA,EAAA,CAAA,CAAE,MAAM,CAAG,CAAA,CAAA,CAAA;AAAA;AAG5D,EAAO,OAAA,CAAA;AACT;AAQO,MAAM,YAAyC,CAAA;AAAA,EAUpD,WACW,CAAA,MAAA,GAAmB,EAAC,EAC7B,cACA,KACA,EAAA;AAHS,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAIT,IAAA,IAAA,CAAK,OAAU,GAAA,MAAA;AACf,IAAA,IAAA,CAAK,aAAgB,GAAA,YAAA;AACrB,IAAA,IAAA,CAAK,MAAS,GAAA,KAAA;AAAA;AAChB,EAjBS,MAAS,GAAA,qBAAA;AAAA,EACT,OAAU,GAAA,IAAA;AAAA,EAGnB,GAAA;AAAA,EACS,OAAA;AAAA,EACA,aAAA;AAAA,EACA,MAAA;AAAA,EAYT,SAAsB,GAAA;AACpB,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AACd,EAEA,IAAI,KAA4B,GAAA;AAC9B,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AACd,EAEA,cAAyB,GAAA;AACvB,IAAA,IAAI,KAAK,GAAK,EAAA;AACZ,MAAA,OAAO,IAAK,CAAA,GAAA;AAAA;AAEd,IAAO,OAAA,CAAA,YAAA,EAAe,KAAK,aAAa,CAAA,CAAA,CAAA;AAAA;AAC1C,EAEA,IAAI,KAAQ,GAAA;AACV,IAAA,OAAO,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,aAAA,CAAc,MAAM,CAAA;AAAA;AAC/C,EAEA,MAAM,EAAkB,EAAA;AACtB,IAAA,IAAI,CAAC,EAAI,EAAA;AACP,MAAA,MAAM,IAAI,KAAA,CAAM,CAAG,EAAA,IAAA,CAAK,KAAK,CAAgC,8BAAA,CAAA,CAAA;AAAA;AAE/D,IAAA,IAAI,IAAK,CAAA,GAAA,IAAO,IAAK,CAAA,GAAA,KAAQ,EAAI,EAAA;AAC/B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,GAAG,IAAK,CAAA,KAAK,kCAAkC,IAAK,CAAA,GAAG,UAAU,EAAE,CAAA,CAAA;AAAA,OACrE;AAAA;AAEF,IAAA,IAAA,CAAK,GAAM,GAAA,EAAA;AAAA;AACb,EAEA,QAAmB,GAAA;AACjB,IAAA,OAAO,GAAG,IAAK,CAAA,KAAK,CAAI,CAAA,EAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA,CAAA;AAAA;AAEjD;AAQO,SAAS,eAKd,MAaA,EAAA;AACA,EAAA,OAAO,IAAI,YAAA;AAAA,IACT,MAAQ,EAAA,MAAA;AAAA,IACR,sBAAuB,EAAA;AAAA,IACvB,MAAQ,EAAA;AAAA,GACV;AACF;;;;"}
@@ -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/ComponentsApi.esm.js';
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 {\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';\nimport { ExtensionDataContainer } from './types';\nimport { ExtensionBlueprintParamsDefiner } 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<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 | ExtensionBlueprintParamsDefiner;\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 | ExtensionBlueprintParamsDefiner> =\n TParams extends ExtensionBlueprintParamsDefiner<infer IParams>\n ? IParams | ((define: TParams) => ReturnType<TParams>)\n :\n | TParams\n | ((\n define: ExtensionBlueprintParamsDefiner<TParams, TParams>,\n ) => ReturnType<ExtensionBlueprintParamsDefiner<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 AnyExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n AnyExtensionDataRef,\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 ExtensionBlueprintParamsDefiner\n ? TFactoryParamsReturn\n : T['params'] extends ExtensionBlueprintParamsDefiner\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<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 ExtensionBlueprintParamsDefiner\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintParamsDefiner\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'\n : Partial<T['params']>;\n })\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
+ {"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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"}
@@ -60,7 +60,7 @@ function createExtensionBlueprint(options) {
60
60
  make(args) {
61
61
  return createExtension({
62
62
  kind: options.kind,
63
- name: args.name ?? options.name,
63
+ name: args.name,
64
64
  attachTo: args.attachTo ?? options.attachTo,
65
65
  disabled: args.disabled ?? options.disabled,
66
66
  inputs: options.inputs,
@@ -75,7 +75,7 @@ function createExtensionBlueprint(options) {
75
75
  makeWithOverrides(args) {
76
76
  return createExtension({
77
77
  kind: options.kind,
78
- name: args.name ?? options.name,
78
+ name: args.name,
79
79
  attachTo: args.attachTo ?? options.attachTo,
80
80
  disabled: args.disabled ?? options.disabled,
81
81
  inputs: { ...args.inputs, ...options.inputs },
@@ -104,6 +104,7 @@ function createExtensionBlueprint(options) {
104
104
  )
105
105
  }
106
106
  ),
107
+ "original blueprint factory",
107
108
  options.output
108
109
  );
109
110
  },
@@ -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 { OpaqueType } from '@internal/opaque';\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 { createExtensionDataContainer } from '@internal/frontend';\nimport {\n ResolveInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport { ExtensionDataContainer } from './types';\n\n/**\n * A function used to define a parameter mapping function in order to facilitate\n * advanced parameter typing for extension blueprints.\n *\n * @remarks\n *\n * This function is primarily intended to enable the use of inferred type\n * parameters for blueprint params, but it can also be used to transoform the\n * params before they are handed ot the blueprint.\n *\n * The function must return an object created with\n * {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintParamsDefiner<\n TParams extends object = object,\n TInput = any,\n> = (params: TInput) => ExtensionBlueprintParams<TParams>;\n\n/**\n * An opaque type that represents a set of parameters to be passed to a blueprint.\n *\n * @remarks\n *\n * Created with {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintParams<T extends object = object> = {\n $$type: '@backstage/BlueprintParams';\n T: T;\n};\n\nconst OpaqueBlueprintParams = OpaqueType.create<{\n public: ExtensionBlueprintParams;\n versions: {\n version: 'v1';\n params: object;\n };\n}>({\n type: '@backstage/BlueprintParams',\n versions: ['v1'],\n});\n\n/**\n * Wraps a plain blueprint parameter object in an opaque {@link ExtensionBlueprintParams} object.\n *\n * This is used in the definition of the `defineParams` option of {@link ExtensionBlueprint}.\n *\n * @public\n * @param params - The plain blueprint parameter object to wrap.\n * @returns The wrapped blueprint parameter object.\n */\nexport function createExtensionBlueprintParams<T extends object = object>(\n params: T,\n): ExtensionBlueprintParams<T> {\n return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params });\n}\n\n/**\n * @public\n */\nexport type CreateExtensionBlueprintOptions<\n TKind extends string,\n TName extends string | undefined,\n TParams extends object | ExtensionBlueprintParamsDefiner,\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 /**\n * This option is used to further refine the blueprint params. When this\n * option is used, the blueprint will require params to be passed in callback\n * form. This function can both transform the params before they are handed to\n * the blueprint factory, but importantly it also allows you to define\n * inferred type parameters for your blueprint params.\n *\n * @example\n * Blueprint definition with inferred type parameters:\n * ```ts\n * const ExampleBlueprint = createExtensionBlueprint({\n * kind: 'example',\n * attachTo: { id: 'example', input: 'example' },\n * output: [exampleComponentDataRef, exampleFetcherDataRef],\n * defineParams<T>(params: {\n * component(props: ExampleProps<T>): JSX.Element | null\n * fetcher(options: FetchOptions): Promise<FetchResult<T>>\n * }) {\n * return createExtensionBlueprintParams(params);\n * },\n * *factory(params) {\n * yield exampleComponentDataRef(params.component)\n * yield exampleFetcherDataRef(params.fetcher)\n * },\n * });\n * ```\n *\n * @example\n * Usage of the above example blueprint:\n * ```ts\n * const example = ExampleBlueprint.make({\n * params: define => define({\n * component: ...,\n * fetcher: ...,\n * }),\n * });\n * ```\n */\n defineParams?: TParams extends ExtensionBlueprintParamsDefiner\n ? TParams\n : 'The defineParams option must be a function if provided, see the docs for details';\n factory(\n params: TParams extends ExtensionBlueprintParamsDefiner\n ? ReturnType<TParams>['T']\n : 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 | ExtensionBlueprintParamsDefiner;\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/** @ignore */\ntype ParamsFactory<TDefiner extends ExtensionBlueprintParamsDefiner> = (\n define: TDefiner,\n) => ReturnType<TDefiner>;\n\n/**\n * Represents any form of params input that can be passed to a blueprint.\n * This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback.\n *\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintParamsDefiner> =\n TParams extends ExtensionBlueprintParamsDefiner<infer IParams>\n ? IParams | ParamsFactory<TParams>\n :\n | TParams\n | ParamsFactory<ExtensionBlueprintParamsDefiner<TParams, TParams>>;\n\n/**\n * @public\n */\nexport interface ExtensionBlueprint<\n // TParamsMapper extends (params: any) => object,\n T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,\n> {\n dataRefs: T['dataRefs'];\n\n make<\n TNewName extends string | undefined,\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(args: {\n name?: TNewName;\n attachTo?: ExtensionAttachToSpec;\n disabled?: boolean;\n params: TParamsInput extends ExtensionBlueprintParamsDefiner\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintParamsDefiner\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: define => define(<params>) })`'\n : TParamsInput;\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 TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(\n params: TParamsInput extends ExtensionBlueprintParamsDefiner\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintParamsDefiner\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'\n : TParamsInput,\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\nfunction unwrapParamsFactory<TParams extends object>(\n // Allow `Function` because `typeof <object> === 'function'` allows it, but in practice this should always be a param factory\n params: ParamsFactory<ExtensionBlueprintParamsDefiner> | Function,\n defineParams: ExtensionBlueprintParamsDefiner,\n kind: string,\n): TParams {\n const paramDefinition = (\n params as ParamsFactory<ExtensionBlueprintParamsDefiner>\n )(defineParams);\n try {\n return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams;\n } catch (e) {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameter definition callback function did not return a valid parameter definition object; Caused by: ${e.message}`,\n );\n }\n}\n\nfunction unwrapParams<TParams extends object>(\n params: object | ParamsFactory<ExtensionBlueprintParamsDefiner> | string,\n ctx: { node: AppNode; [ctxParamsSymbol]?: any },\n defineParams: ExtensionBlueprintParamsDefiner | undefined,\n kind: string,\n): TParams {\n const overrideParams = ctx[ctxParamsSymbol] as\n | object\n | ParamsFactory<ExtensionBlueprintParamsDefiner>\n | undefined;\n\n if (defineParams) {\n if (overrideParams) {\n if (typeof overrideParams !== 'function') {\n throw new TypeError(\n `Invalid extension override of blueprint with kind '${kind}', the override params were passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(overrideParams, defineParams, kind);\n }\n\n if (typeof params !== 'function') {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameters where passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(params, defineParams, kind);\n }\n\n const base =\n typeof params === 'function'\n ? unwrapParamsFactory<TParams>(\n params,\n createExtensionBlueprintParams,\n kind,\n )\n : (params as TParams);\n const overrides =\n typeof overrideParams === 'function'\n ? unwrapParamsFactory<TParams>(\n overrideParams,\n createExtensionBlueprintParams,\n kind,\n )\n : (overrideParams as Partial<TParams>);\n\n return {\n ...base,\n ...overrides,\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 | ExtensionBlueprintParamsDefiner,\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 const defineParams = options.defineParams as\n | ExtensionBlueprintParamsDefiner\n | undefined;\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 unwrapParams(args.params, ctx, defineParams, options.kind),\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 unwrapParams(innerParams, ctx, defineParams, options.kind),\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":"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"}
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 { OpaqueType } from '@internal/opaque';\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 { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport {\n ResolvedInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport { ExtensionDataContainer } from './types';\nimport { PageBlueprint } from '../blueprints/PageBlueprint';\n\n/**\n * A function used to define a parameter mapping function in order to facilitate\n * advanced parameter typing for extension blueprints.\n *\n * @remarks\n *\n * This function is primarily intended to enable the use of inferred type\n * parameters for blueprint params, but it can also be used to transoform the\n * params before they are handed ot the blueprint.\n *\n * The function must return an object created with\n * {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintDefineParams<\n TParams extends object = object,\n TInput = any,\n> = (params: TInput) => ExtensionBlueprintParams<TParams>;\n\n/**\n * An opaque type that represents a set of parameters to be passed to a blueprint.\n *\n * @remarks\n *\n * Created with {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintParams<T extends object = object> = {\n $$type: '@backstage/BlueprintParams';\n T: T;\n};\n\nconst OpaqueBlueprintParams = OpaqueType.create<{\n public: ExtensionBlueprintParams;\n versions: {\n version: 'v1';\n params: object;\n };\n}>({\n type: '@backstage/BlueprintParams',\n versions: ['v1'],\n});\n\n/**\n * Wraps a plain blueprint parameter object in an opaque {@link ExtensionBlueprintParams} object.\n *\n * This is used in the definition of the `defineParams` option of {@link ExtensionBlueprint}.\n *\n * @public\n * @param params - The plain blueprint parameter object to wrap.\n * @returns The wrapped blueprint parameter object.\n */\nexport function createExtensionBlueprintParams<T extends object = object>(\n params: T,\n): ExtensionBlueprintParams<T> {\n return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params });\n}\n\n/**\n * @public\n */\nexport type CreateExtensionBlueprintOptions<\n TKind extends string,\n TParams extends object | ExtensionBlueprintDefineParams,\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 in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TDataRefs extends { [name in string]: ExtensionDataRef },\n> = {\n kind: TKind;\n attachTo: ExtensionAttachToSpec;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n /**\n * This option is used to further refine the blueprint params. When this\n * option is used, the blueprint will require params to be passed in callback\n * form. This function can both transform the params before they are handed to\n * the blueprint factory, but importantly it also allows you to define\n * inferred type parameters for your blueprint params.\n *\n * @example\n * Blueprint definition with inferred type parameters:\n * ```ts\n * const ExampleBlueprint = createExtensionBlueprint({\n * kind: 'example',\n * attachTo: { id: 'example', input: 'example' },\n * output: [exampleComponentDataRef, exampleFetcherDataRef],\n * defineParams<T>(params: {\n * component(props: ExampleProps<T>): JSX.Element | null\n * fetcher(options: FetchOptions): Promise<FetchResult<T>>\n * }) {\n * return createExtensionBlueprintParams(params);\n * },\n * *factory(params) {\n * yield exampleComponentDataRef(params.component)\n * yield exampleFetcherDataRef(params.fetcher)\n * },\n * });\n * ```\n *\n * @example\n * Usage of the above example blueprint:\n * ```ts\n * const example = ExampleBlueprint.make({\n * params: defineParams => defineParams({\n * component: ...,\n * fetcher: ...,\n * }),\n * });\n * ```\n */\n defineParams?: TParams extends ExtensionBlueprintDefineParams\n ? TParams\n : 'The defineParams option must be a function if provided, see the docs for details';\n factory(\n params: TParams extends ExtensionBlueprintDefineParams\n ? ReturnType<TParams>['T']\n : 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 params?: object | ExtensionBlueprintDefineParams;\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 dataRefs?: { [name in string]: ExtensionDataRef };\n};\n\n/** @ignore */\ntype ParamsFactory<TDefiner extends ExtensionBlueprintDefineParams> = (\n defineParams: TDefiner,\n) => ReturnType<TDefiner>;\n\n/**\n * Represents any form of params input that can be passed to a blueprint.\n * This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback.\n *\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ParamsFactory<TParams>\n : TParams | ParamsFactory<ExtensionBlueprintDefineParams<TParams, TParams>>;\n\n/**\n * @public\n */\nexport interface ExtensionBlueprint<\n T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,\n> {\n dataRefs: T['dataRefs'];\n\n make<\n TName extends string | undefined,\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(args: {\n name?: TName;\n attachTo?: ExtensionAttachToSpec;\n disabled?: boolean;\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: `<blueprint>.make({ params: defineParams => defineParams(<params>) })`'\n : T['params'];\n }): ExtensionDefinition<{\n kind: T['kind'];\n name: string | undefined extends TName ? undefined : TName;\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 TName 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 ExtensionDataRef,\n TExtraInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n >(args: {\n name?: TName;\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 TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\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 : T['params'],\n context?: {\n config?: T['config'];\n inputs?: ResolvedInputValueOverrides<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 ExtensionDataRef 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: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n kind: T['kind'];\n name: string | undefined extends TName ? undefined : TName;\n params: T['params'];\n }>;\n}\n\nfunction unwrapParamsFactory<TParams extends object>(\n // Allow `Function` because `typeof <object> === 'function'` allows it, but in practice this should always be a param factory\n params: ParamsFactory<ExtensionBlueprintDefineParams> | Function,\n defineParams: ExtensionBlueprintDefineParams,\n kind: string,\n): TParams {\n const paramDefinition = (\n params as ParamsFactory<ExtensionBlueprintDefineParams>\n )(defineParams);\n try {\n return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams;\n } catch (e) {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameter definition callback function did not return a valid parameter definition object; Caused by: ${e.message}`,\n );\n }\n}\n\nfunction unwrapParams<TParams extends object>(\n params: object | ParamsFactory<ExtensionBlueprintDefineParams> | string,\n ctx: { node: AppNode; [ctxParamsSymbol]?: any },\n defineParams: ExtensionBlueprintDefineParams | undefined,\n kind: string,\n): TParams {\n const overrideParams = ctx[ctxParamsSymbol] as\n | object\n | ParamsFactory<ExtensionBlueprintDefineParams>\n | undefined;\n\n if (defineParams) {\n if (overrideParams) {\n if (typeof overrideParams !== 'function') {\n throw new TypeError(\n `Invalid extension override of blueprint with kind '${kind}', the override params were passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(overrideParams, defineParams, kind);\n }\n\n if (typeof params !== 'function') {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameters where passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(params, defineParams, kind);\n }\n\n const base =\n typeof params === 'function'\n ? unwrapParamsFactory<TParams>(\n params,\n createExtensionBlueprintParams,\n kind,\n )\n : (params as TParams);\n const overrides =\n typeof overrideParams === 'function'\n ? unwrapParamsFactory<TParams>(\n overrideParams,\n createExtensionBlueprintParams,\n kind,\n )\n : (overrideParams as Partial<TParams>);\n\n return {\n ...base,\n ...overrides,\n };\n}\n\n/**\n * Creates a new extension blueprint that encapsulates the creation of\n * extensions of particular kinds.\n *\n * @remarks\n *\n * For details on how blueprints work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-blueprints | documentation for extension blueprints}\n * in the frontend system documentation.\n *\n * Extension blueprints make it much easier for users to create new extensions\n * for your plugin. Rather than letting them use {@link createExtension}\n * directly, you can define a set of parameters and default factory for your\n * blueprint, removing a lot of the boilerplate and complexity that is otherwise\n * needed to create an extension.\n *\n * Each blueprint has its own `kind` that helps identify and group the\n * extensions that have been created with it. For example the\n * {@link PageBlueprint} has the kind `'page'`, and extensions created with it\n * will be given the ID `'page:<plugin-id>[/<name>]'`. Blueprints should always\n * be exported as `<PascalCaseKind>Blueprint`.\n *\n * When creating a blueprint the type of the parameters are inferred from the\n * `factory` function that you provide. The exception to that is when you need\n * your blueprint to include inferred type parameters, in which case you need to\n * use the `defineParams` option. See the documentation for the `defineParams`\n * option for more details on how that works.\n *\n * @example\n * ```tsx\n * // In your plugin library\n * export const GreetingBlueprint = createExtensionBlueprint({\n * kind: 'greeting',\n * attachTo: { id: 'example', input: 'greetings' },\n * output: [coreExtensionData.reactElement],\n * factory(params: { greeting: string }) {\n * return [coreExtensionData.reactElement(<h1>{params.greeting}</h1>)];\n * },\n * });\n *\n * // Someone using your blueprint in their plugin\n * const exampleGreeting = GreetingBlueprint.make({\n * params: {\n * greeting: 'Hello, world!',\n * },\n * });\n * ```\n * @public\n */\nexport function createExtensionBlueprint<\n TParams extends object | ExtensionBlueprintDefineParams,\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 in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TKind extends string,\n TDataRefs extends { [name in string]: ExtensionDataRef } = never,\n>(\n options: CreateExtensionBlueprintOptions<\n TKind,\n TParams,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n TDataRefs\n >,\n): ExtensionBlueprint<{\n kind: TKind;\n params: TParams;\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: 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 const defineParams = options.defineParams as\n | ExtensionBlueprintDefineParams\n | undefined;\n\n return {\n dataRefs: options.dataRefs,\n make(args) {\n return createExtension({\n kind: options.kind,\n name: args.name,\n attachTo: args.attachTo ?? options.attachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: options.inputs,\n output: options.output as ExtensionDataRef[],\n config: options.config,\n factory: ctx =>\n options.factory(\n unwrapParams(args.params, ctx, defineParams, options.kind),\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,\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 ExtensionDataRef[],\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<\n UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never\n >(\n options.factory(\n unwrapParams(innerParams, ctx, defineParams, options.kind),\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 'original blueprint factory',\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 params: TParams;\n output: any;\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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"createExtensionDataRef.esm.js","sources":["../../src/wiring/createExtensionDataRef.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\n/** @public */\nexport type ExtensionDataValue<TData, TId extends string> = {\n readonly $$type: '@backstage/ExtensionDataValue';\n readonly id: TId;\n readonly value: TData;\n};\n\n/** @public */\nexport type ExtensionDataRef<\n TData,\n TId extends string = string,\n TConfig extends { optional?: true } = {},\n> = {\n readonly $$type: '@backstage/ExtensionDataRef';\n readonly id: TId;\n readonly T: TData;\n readonly config: TConfig;\n};\n\n/** @public */\nexport type ExtensionDataRefToValue<TDataRef extends AnyExtensionDataRef> =\n TDataRef extends ExtensionDataRef<infer IData, infer IId, any>\n ? ExtensionDataValue<IData, IId>\n : never;\n\n/** @public */\nexport type AnyExtensionDataRef = ExtensionDataRef<\n unknown,\n string,\n { optional?: true }\n>;\n\n/** @public */\nexport interface ConfigurableExtensionDataRef<\n TData,\n TId extends string,\n TConfig extends { optional?: true } = {},\n> extends ExtensionDataRef<TData, TId, TConfig> {\n optional(): ConfigurableExtensionDataRef<\n TData,\n TId,\n TConfig & { optional: true }\n >;\n (t: TData): ExtensionDataValue<TData, TId>;\n}\n\n/** @public */\nexport function createExtensionDataRef<TData>(): {\n with<TId extends string>(options: {\n id: TId;\n }): ConfigurableExtensionDataRef<TData, TId>;\n} {\n const createRef = <TId extends string>(refId: TId) =>\n Object.assign(\n (value: TData): ExtensionDataValue<TData, TId> => ({\n $$type: '@backstage/ExtensionDataValue',\n id: refId,\n value,\n }),\n {\n id: refId,\n $$type: '@backstage/ExtensionDataRef',\n config: {},\n optional() {\n return {\n ...this,\n config: { ...this.config, optional: true },\n };\n },\n toString() {\n const optional = Boolean(this.config.optional);\n return `ExtensionDataRef{id=${refId},optional=${optional}}`;\n },\n } as ConfigurableExtensionDataRef<TData, TId, { optional?: true }>,\n );\n return {\n with<TId extends string>(options: { id: TId }) {\n return createRef(options.id);\n },\n };\n}\n"],"names":[],"mappings":"AA+DO,SAAS,sBAId,GAAA;AACA,EAAM,MAAA,SAAA,GAAY,CAAqB,KAAA,KACrC,MAAO,CAAA,MAAA;AAAA,IACL,CAAC,KAAkD,MAAA;AAAA,MACjD,MAAQ,EAAA,+BAAA;AAAA,MACR,EAAI,EAAA,KAAA;AAAA,MACJ;AAAA,KACF,CAAA;AAAA,IACA;AAAA,MACE,EAAI,EAAA,KAAA;AAAA,MACJ,MAAQ,EAAA,6BAAA;AAAA,MACR,QAAQ,EAAC;AAAA,MACT,QAAW,GAAA;AACT,QAAO,OAAA;AAAA,UACL,GAAG,IAAA;AAAA,UACH,QAAQ,EAAE,GAAG,IAAK,CAAA,MAAA,EAAQ,UAAU,IAAK;AAAA,SAC3C;AAAA,OACF;AAAA,MACA,QAAW,GAAA;AACT,QAAA,MAAM,QAAW,GAAA,OAAA,CAAQ,IAAK,CAAA,MAAA,CAAO,QAAQ,CAAA;AAC7C,QAAO,OAAA,CAAA,oBAAA,EAAuB,KAAK,CAAA,UAAA,EAAa,QAAQ,CAAA,CAAA,CAAA;AAAA;AAC1D;AACF,GACF;AACF,EAAO,OAAA;AAAA,IACL,KAAyB,OAAsB,EAAA;AAC7C,MAAO,OAAA,SAAA,CAAU,QAAQ,EAAE,CAAA;AAAA;AAC7B,GACF;AACF;;;;"}
1
+ {"version":3,"file":"createExtensionDataRef.esm.js","sources":["../../src/wiring/createExtensionDataRef.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\n/** @public */\nexport type ExtensionDataValue<TData, TId extends string> = {\n readonly $$type: '@backstage/ExtensionDataValue';\n readonly id: TId;\n readonly value: TData;\n};\n\n/** @public */\nexport type ExtensionDataRef<\n TData = unknown,\n TId extends string = string,\n TConfig extends { optional?: true } = { optional?: true },\n> = {\n readonly $$type: '@backstage/ExtensionDataRef';\n readonly id: TId;\n readonly T: TData;\n readonly config: TConfig;\n};\n\n/** @public */\nexport type ExtensionDataRefToValue<TDataRef extends AnyExtensionDataRef> =\n TDataRef extends ExtensionDataRef<infer IData, infer IId, any>\n ? ExtensionDataValue<IData, IId>\n : never;\n\n/**\n * @deprecated Use `ExtensionDataRef` without type parameters instead.\n * @public\n */\nexport type AnyExtensionDataRef = ExtensionDataRef;\n\n/** @public */\nexport interface ConfigurableExtensionDataRef<\n TData,\n TId extends string,\n TConfig extends { optional?: true } = {},\n> extends ExtensionDataRef<TData, TId, TConfig> {\n optional(): ConfigurableExtensionDataRef<\n TData,\n TId,\n TConfig & { optional: true }\n >;\n (t: TData): ExtensionDataValue<TData, TId>;\n}\n\n/** @public */\nexport function createExtensionDataRef<TData>(): {\n with<TId extends string>(options: {\n id: TId;\n }): ConfigurableExtensionDataRef<TData, TId>;\n} {\n const createRef = <TId extends string>(refId: TId) =>\n Object.assign(\n (value: TData): ExtensionDataValue<TData, TId> => ({\n $$type: '@backstage/ExtensionDataValue',\n id: refId,\n value,\n }),\n {\n id: refId,\n $$type: '@backstage/ExtensionDataRef',\n config: {},\n optional() {\n return {\n ...this,\n config: { ...this.config, optional: true },\n };\n },\n toString() {\n const optional = Boolean(this.config.optional);\n return `ExtensionDataRef{id=${refId},optional=${optional}}`;\n },\n } as ConfigurableExtensionDataRef<TData, TId, { optional?: true }>,\n );\n return {\n with<TId extends string>(options: { id: TId }) {\n return createRef(options.id);\n },\n };\n}\n"],"names":[],"mappings":"AA8DO,SAAS,sBAId,GAAA;AACA,EAAM,MAAA,SAAA,GAAY,CAAqB,KAAA,KACrC,MAAO,CAAA,MAAA;AAAA,IACL,CAAC,KAAkD,MAAA;AAAA,MACjD,MAAQ,EAAA,+BAAA;AAAA,MACR,EAAI,EAAA,KAAA;AAAA,MACJ;AAAA,KACF,CAAA;AAAA,IACA;AAAA,MACE,EAAI,EAAA,KAAA;AAAA,MACJ,MAAQ,EAAA,6BAAA;AAAA,MACR,QAAQ,EAAC;AAAA,MACT,QAAW,GAAA;AACT,QAAO,OAAA;AAAA,UACL,GAAG,IAAA;AAAA,UACH,QAAQ,EAAE,GAAG,IAAK,CAAA,MAAA,EAAQ,UAAU,IAAK;AAAA,SAC3C;AAAA,OACF;AAAA,MACA,QAAW,GAAA;AACT,QAAA,MAAM,QAAW,GAAA,OAAA,CAAQ,IAAK,CAAA,MAAA,CAAO,QAAQ,CAAA;AAC7C,QAAO,OAAA,CAAA,oBAAA,EAAuB,KAAK,CAAA,UAAA,EAAa,QAAQ,CAAA,CAAA,CAAA;AAAA;AAC1D;AACF,GACF;AACF,EAAO,OAAA;AAAA,IACL,KAAyB,OAAsB,EAAA;AAC7C,MAAO,OAAA,SAAA,CAAU,QAAQ,EAAE,CAAA;AAAA;AAC7B,GACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createFrontendModule.esm.js","sources":["../../src/wiring/createFrontendModule.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 { OpaqueExtensionDefinition } from '@internal/frontend';\nimport { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\n\n/** @public */\nexport interface CreateFrontendModuleOptions<\n TPluginId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TPluginId;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n}\n\n/** @public */\nexport interface FrontendModule {\n readonly $$type: '@backstage/FrontendModule';\n readonly pluginId: string;\n}\n\n/** @internal */\nexport interface InternalFrontendModule extends FrontendModule {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n}\n\n/** @public */\nexport function createFrontendModule<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[] = [],\n>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule {\n const { pluginId } = options;\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return {\n $$type: '@backstage/FrontendModule',\n version: 'v1',\n pluginId,\n featureFlags: options.featureFlags ?? [],\n extensions,\n toString() {\n return `Module{pluginId=${pluginId}}`;\n },\n } as InternalFrontendModule;\n}\n\n/** @internal */\nexport function isInternalFrontendModule(opaque: {\n $$type: string;\n}): opaque is InternalFrontendModule {\n if (opaque.$$type === '@backstage/FrontendModule') {\n // Make sure we throw if invalid\n toInternalFrontendModule(opaque as FrontendModule);\n return true;\n }\n return false;\n}\n\n/** @internal */\nexport function toInternalFrontendModule(\n plugin: FrontendModule,\n): InternalFrontendModule {\n const internal = plugin as InternalFrontendModule;\n if (internal.$$type !== '@backstage/FrontendModule') {\n throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);\n }\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid plugin instance, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n"],"names":[],"mappings":";;;AAgDO,SAAS,qBAGd,OAAwE,EAAA;AACxE,EAAM,MAAA,EAAE,UAAa,GAAA,OAAA;AAErB,EAAM,MAAA,UAAA,GAAa,IAAI,KAAsB,EAAA;AAC7C,EAAM,MAAA,wBAAA,uBAA+B,GAGnC,EAAA;AAEF,EAAA,KAAA,MAAW,GAAO,IAAA,OAAA,CAAQ,UAAc,IAAA,EAAI,EAAA;AAC1C,IAAM,MAAA,QAAA,GAAW,yBAA0B,CAAA,UAAA,CAAW,GAAG,CAAA;AACzD,IAAA,MAAM,MAAM,0BAA2B,CAAA,GAAA,EAAK,EAAE,SAAA,EAAW,UAAU,CAAA;AACnE,IAAA,UAAA,CAAW,KAAK,GAAG,CAAA;AACnB,IAAyB,wBAAA,CAAA,GAAA,CAAI,IAAI,EAAI,EAAA;AAAA,MACnC,GAAG,QAAA;AAAA,MACH,SAAW,EAAA;AAAA,KACZ,CAAA;AAAA;AAGH,EAAI,IAAA,UAAA,CAAW,MAAW,KAAA,wBAAA,CAAyB,IAAM,EAAA;AACvD,IAAA,MAAM,YAAe,GAAA,UAAA,CAAW,GAAI,CAAA,CAAA,CAAA,KAAK,EAAE,EAAE,CAAA;AAC7C,IAAA,MAAM,aAAa,KAAM,CAAA,IAAA;AAAA,MACvB,IAAI,GAAA;AAAA,QACF,YAAA,CAAa,OAAO,CAAC,EAAA,EAAI,UAAU,YAAa,CAAA,OAAA,CAAQ,EAAE,CAAA,KAAM,KAAK;AAAA;AACvE,KACF;AAEA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,QAAA,EAAW,QAAQ,CAAA,iCAAA,EAAoC,UAAW,CAAA,IAAA;AAAA,QAChE;AAAA,OACD,CAAA;AAAA,KACH;AAAA;AAGF,EAAO,OAAA;AAAA,IACL,MAAQ,EAAA,2BAAA;AAAA,IACR,OAAS,EAAA,IAAA;AAAA,IACT,QAAA;AAAA,IACA,YAAA,EAAc,OAAQ,CAAA,YAAA,IAAgB,EAAC;AAAA,IACvC,UAAA;AAAA,IACA,QAAW,GAAA;AACT,MAAA,OAAO,mBAAmB,QAAQ,CAAA,CAAA,CAAA;AAAA;AACpC,GACF;AACF;;;;"}
1
+ {"version":3,"file":"createFrontendModule.esm.js","sources":["../../src/wiring/createFrontendModule.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 { OpaqueExtensionDefinition } from '@internal/frontend';\nimport { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\n\n/** @public */\nexport interface CreateFrontendModuleOptions<\n TPluginId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TPluginId;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n}\n\n/** @public */\nexport interface FrontendModule {\n readonly $$type: '@backstage/FrontendModule';\n readonly pluginId: string;\n}\n\n/** @internal */\nexport interface InternalFrontendModule extends FrontendModule {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n}\n\n/**\n * Creates a new module that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Modules are used to add or override extensions for an existing plugin. If a\n * module provides an extension with the same ID as one provided by the plugin,\n * the extension provided by the module will always take precedence.\n *\n * Every module is created for a specific plugin by providing the\n * unique ID of the plugin that the module should be installed for. If that\n * plugin is not present in the app, the module will be ignored and have no\n * effect.\n *\n * For more information on how modules work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}\n * in the frontend system documentation.\n *\n * It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendModule } from '@backstage/frontend-plugin-api';\n *\n * export const exampleModuleCustomPage = createFrontendModule({\n * pluginId: 'example',\n * extensions: [\n * // Overrides the default page for the 'example' plugin\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./CustomPage').then(m => <m.CustomPage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendModule<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[] = [],\n>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule {\n const { pluginId } = options;\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return {\n $$type: '@backstage/FrontendModule',\n version: 'v1',\n pluginId,\n featureFlags: options.featureFlags ?? [],\n extensions,\n toString() {\n return `Module{pluginId=${pluginId}}`;\n },\n } as InternalFrontendModule;\n}\n\n/** @internal */\nexport function isInternalFrontendModule(opaque: {\n $$type: string;\n}): opaque is InternalFrontendModule {\n if (opaque.$$type === '@backstage/FrontendModule') {\n // Make sure we throw if invalid\n toInternalFrontendModule(opaque as FrontendModule);\n return true;\n }\n return false;\n}\n\n/** @internal */\nexport function toInternalFrontendModule(\n plugin: FrontendModule,\n): InternalFrontendModule {\n const internal = plugin as InternalFrontendModule;\n if (internal.$$type !== '@backstage/FrontendModule') {\n throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);\n }\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid plugin instance, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n"],"names":[],"mappings":";;;AAsFO,SAAS,qBAGd,OAAwE,EAAA;AACxE,EAAM,MAAA,EAAE,UAAa,GAAA,OAAA;AAErB,EAAM,MAAA,UAAA,GAAa,IAAI,KAAsB,EAAA;AAC7C,EAAM,MAAA,wBAAA,uBAA+B,GAGnC,EAAA;AAEF,EAAA,KAAA,MAAW,GAAO,IAAA,OAAA,CAAQ,UAAc,IAAA,EAAI,EAAA;AAC1C,IAAM,MAAA,QAAA,GAAW,yBAA0B,CAAA,UAAA,CAAW,GAAG,CAAA;AACzD,IAAA,MAAM,MAAM,0BAA2B,CAAA,GAAA,EAAK,EAAE,SAAA,EAAW,UAAU,CAAA;AACnE,IAAA,UAAA,CAAW,KAAK,GAAG,CAAA;AACnB,IAAyB,wBAAA,CAAA,GAAA,CAAI,IAAI,EAAI,EAAA;AAAA,MACnC,GAAG,QAAA;AAAA,MACH,SAAW,EAAA;AAAA,KACZ,CAAA;AAAA;AAGH,EAAI,IAAA,UAAA,CAAW,MAAW,KAAA,wBAAA,CAAyB,IAAM,EAAA;AACvD,IAAA,MAAM,YAAe,GAAA,UAAA,CAAW,GAAI,CAAA,CAAA,CAAA,KAAK,EAAE,EAAE,CAAA;AAC7C,IAAA,MAAM,aAAa,KAAM,CAAA,IAAA;AAAA,MACvB,IAAI,GAAA;AAAA,QACF,YAAA,CAAa,OAAO,CAAC,EAAA,EAAI,UAAU,YAAa,CAAA,OAAA,CAAQ,EAAE,CAAA,KAAM,KAAK;AAAA;AACvE,KACF;AAEA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,QAAA,EAAW,QAAQ,CAAA,iCAAA,EAAoC,UAAW,CAAA,IAAA;AAAA,QAChE;AAAA,OACD,CAAA;AAAA,KACH;AAAA;AAGF,EAAO,OAAA;AAAA,IACL,MAAQ,EAAA,2BAAA;AAAA,IACR,OAAS,EAAA,IAAA;AAAA,IACT,QAAA;AAAA,IACA,YAAA,EAAc,OAAQ,CAAA,YAAA,IAAgB,EAAC;AAAA,IACvC,UAAA;AAAA,IACA,QAAW,GAAA;AACT,MAAA,OAAO,mBAAmB,QAAQ,CAAA,CAAA,CAAA;AAAA;AACpC,GACF;AACF;;;;"}
@@ -1,14 +1,10 @@
1
1
  import { resolveExtensionDefinition } from './resolveExtensionDefinition.esm.js';
2
2
  import { OpaqueFrontendPlugin } from '../frontend-internal/src/wiring/InternalFrontendPlugin.esm.js';
3
+ import '../frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js';
3
4
  import { OpaqueExtensionDefinition } from '../frontend-internal/src/wiring/InternalExtensionDefinition.esm.js';
4
5
 
5
6
  function createFrontendPlugin(options) {
6
- const pluginId = "pluginId" in options ? options.pluginId : options.id;
7
- if (!pluginId) {
8
- throw new Error(
9
- "Either 'id' or 'pluginId' must be provided to createFrontendPlugin"
10
- );
11
- }
7
+ const pluginId = options.pluginId;
12
8
  const extensions = new Array();
13
9
  const extensionDefinitionsById = /* @__PURE__ */ new Map();
14
10
  for (const def of options.extensions ?? []) {
@@ -1 +1 @@
1
- {"version":3,"file":"createFrontendPlugin.esm.js","sources":["../../src/wiring/createFrontendPlugin.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 {\n OpaqueExtensionDefinition,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { AnyExternalRoutes, AnyRoutes, FeatureFlagConfig } from './types';\nimport { MakeSortedExtensionsMap } from './MakeSortedExtensionsMap';\nimport { JsonObject } from '@backstage/types';\n\n/**\n * Information about the plugin.\n *\n * @public\n * @remarks\n *\n * This interface is intended to be extended via [module\n * augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)\n * in order to add fields that are specific to each project.\n *\n * For example, one might add a `slackChannel` field that is read from the\n * opaque manifest file.\n *\n * See the options for `createApp` for more information about how to\n * customize the parsing of manifest files.\n */\nexport interface FrontendPluginInfo {\n /**\n * The name of the package that implements the plugin.\n */\n packageName?: string;\n\n /**\n * The version of the plugin, typically the version of the package.json file.\n */\n version?: string;\n\n /**\n * As short description of the plugin, typically the description field in\n * package.json.\n */\n description?: string;\n\n /**\n * The owner entity references of the plugin.\n */\n ownerEntityRefs?: string[];\n\n /**\n * Links related to the plugin.\n */\n links?: Array<{ title: string; url: string }>;\n}\n\n/**\n * Options for providing information for a plugin.\n *\n * @public\n */\nexport type FrontendPluginInfoOptions = {\n /**\n * A loader function for the package.json file for the plugin.\n */\n packageJson?: () => Promise<{ name: string } & JsonObject>;\n /**\n * A loader function for an opaque manifest file for the plugin.\n */\n manifest?: () => Promise<JsonObject>;\n};\n\n/** @public */\nexport interface FrontendPlugin<\n TRoutes extends AnyRoutes = AnyRoutes,\n TExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes,\n TExtensionMap extends { [id in string]: ExtensionDefinition } = {\n [id in string]: ExtensionDefinition;\n },\n> {\n readonly $$type: '@backstage/FrontendPlugin';\n readonly id: string;\n readonly routes: TRoutes;\n readonly externalRoutes: TExternalRoutes;\n\n /**\n * Loads the plugin info.\n */\n info(): Promise<FrontendPluginInfo>;\n getExtension<TId extends keyof TExtensionMap>(id: TId): TExtensionMap[TId];\n withOverrides(options: {\n extensions: Array<ExtensionDefinition>;\n\n /**\n * Overrides the original info loaders of the plugin one by one.\n */\n info?: FrontendPluginInfoOptions;\n }): FrontendPlugin<TRoutes, TExternalRoutes, TExtensionMap>;\n}\n\n/** @public */\nexport interface PluginOptions<\n TId extends string,\n TRoutes extends AnyRoutes,\n TExternalRoutes extends AnyExternalRoutes,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TId;\n routes?: TRoutes;\n externalRoutes?: TExternalRoutes;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n info?: FrontendPluginInfoOptions;\n}\n\n/** @public */\nexport function createFrontendPlugin<\n TId extends string,\n TRoutes extends AnyRoutes = {},\n TExternalRoutes extends AnyExternalRoutes = {},\n TExtensions extends readonly ExtensionDefinition[] = [],\n>(\n options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n): FrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n>;\n/**\n * @public\n * @deprecated The `id` option is deprecated, use `pluginId` instead.\n */\nexport function createFrontendPlugin<\n TId extends string,\n TRoutes extends AnyRoutes = {},\n TExternalRoutes extends AnyExternalRoutes = {},\n TExtensions extends readonly ExtensionDefinition[] = [],\n>(\n options: Omit<\n PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n 'pluginId'\n > & { id: string },\n): FrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n>;\nexport function createFrontendPlugin<\n TId extends string,\n TRoutes extends AnyRoutes = {},\n TExternalRoutes extends AnyExternalRoutes = {},\n TExtensions extends readonly ExtensionDefinition[] = [],\n>(\n options:\n | PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>\n | (Omit<\n PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n 'pluginId'\n > & { id: string }),\n): FrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n> {\n const pluginId = 'pluginId' in options ? options.pluginId : options.id;\n if (!pluginId) {\n throw new Error(\n \"Either 'id' or 'pluginId' must be provided to createFrontendPlugin\",\n );\n }\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return OpaqueFrontendPlugin.createInstance('v1', {\n id: pluginId,\n routes: options.routes ?? ({} as TRoutes),\n externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),\n featureFlags: options.featureFlags ?? [],\n extensions: extensions,\n infoOptions: options.info,\n\n // This method is overridden when the plugin instance is installed in an app\n async info() {\n throw new Error(\n `Attempted to load plugin info for plugin '${pluginId}', but the plugin instance is not installed in an app`,\n );\n },\n getExtension(id) {\n const ext = extensionDefinitionsById.get(id);\n if (!ext) {\n throw new Error(\n `Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,\n );\n }\n return ext;\n },\n toString() {\n return `Plugin{id=${pluginId}}`;\n },\n withOverrides(overrides) {\n const overriddenExtensionIds = new Set(\n overrides.extensions.map(\n e => resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n const nonOverriddenExtensions = (options.extensions ?? []).filter(\n e =>\n !overriddenExtensionIds.has(\n resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n return createFrontendPlugin({\n ...options,\n pluginId,\n extensions: [...nonOverriddenExtensions, ...overrides.extensions],\n info: {\n ...options.info,\n ...overrides.info,\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"createFrontendPlugin.esm.js","sources":["../../src/wiring/createFrontendPlugin.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 {\n OpaqueExtensionDefinition,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { MakeSortedExtensionsMap } from './MakeSortedExtensionsMap';\nimport { JsonObject } from '@backstage/types';\nimport { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';\n\n/**\n * Information about the plugin.\n *\n * @public\n * @remarks\n *\n * This interface is intended to be extended via [module\n * augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)\n * in order to add fields that are specific to each project.\n *\n * For example, one might add a `slackChannel` field that is read from the\n * opaque manifest file.\n *\n * See the options for `createApp` for more information about how to\n * customize the parsing of manifest files.\n */\nexport interface FrontendPluginInfo {\n /**\n * The name of the package that implements the plugin.\n */\n packageName?: string;\n\n /**\n * The version of the plugin, typically the version of the package.json file.\n */\n version?: string;\n\n /**\n * As short description of the plugin, typically the description field in\n * package.json.\n */\n description?: string;\n\n /**\n * The owner entity references of the plugin.\n */\n ownerEntityRefs?: string[];\n\n /**\n * Links related to the plugin.\n */\n links?: Array<{ title: string; url: string }>;\n}\n\n/**\n * Options for providing information for a plugin.\n *\n * @public\n */\nexport type FrontendPluginInfoOptions = {\n /**\n * A loader function for the package.json file for the plugin.\n */\n packageJson?: () => Promise<{ name: string } & JsonObject>;\n /**\n * A loader function for an opaque manifest file for the plugin.\n */\n manifest?: () => Promise<JsonObject>;\n};\n\n/** @public */\nexport interface FrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n TExtensionMap extends { [id in string]: ExtensionDefinition } = {\n [id in string]: ExtensionDefinition;\n },\n> {\n readonly $$type: '@backstage/FrontendPlugin';\n readonly id: string;\n readonly routes: TRoutes;\n readonly externalRoutes: TExternalRoutes;\n\n /**\n * Loads the plugin info.\n */\n info(): Promise<FrontendPluginInfo>;\n getExtension<TId extends keyof TExtensionMap>(id: TId): TExtensionMap[TId];\n withOverrides(options: {\n extensions: Array<ExtensionDefinition>;\n\n /**\n * Overrides the original info loaders of the plugin one by one.\n */\n info?: FrontendPluginInfoOptions;\n }): FrontendPlugin<TRoutes, TExternalRoutes, TExtensionMap>;\n}\n\n/** @public */\nexport interface PluginOptions<\n TId extends string,\n TRoutes extends { [name in string]: RouteRef | SubRouteRef },\n TExternalRoutes extends { [name in string]: ExternalRouteRef },\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TId;\n routes?: TRoutes;\n externalRoutes?: TExternalRoutes;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n info?: FrontendPluginInfoOptions;\n}\n\n/**\n * Creates a new plugin that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Every plugin is created with a unique ID and a set of extensions\n * that are installed as part of the plugin.\n *\n * For more information on how plugins work, see the\n * {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}\n * in the frontend system documentation.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendPlugin } from '@backstage/frontend-plugin-api';\n *\n * export const examplePlugin = createFrontendPlugin({\n * pluginId: 'example',\n * extensions: [\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendPlugin<\n TId extends string,\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {},\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {},\n TExtensions extends readonly ExtensionDefinition[] = [],\n>(\n options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n): FrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n> {\n const pluginId = options.pluginId;\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return OpaqueFrontendPlugin.createInstance('v1', {\n id: pluginId,\n routes: options.routes ?? ({} as TRoutes),\n externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),\n featureFlags: options.featureFlags ?? [],\n extensions: extensions,\n infoOptions: options.info,\n\n // This method is overridden when the plugin instance is installed in an app\n async info() {\n throw new Error(\n `Attempted to load plugin info for plugin '${pluginId}', but the plugin instance is not installed in an app`,\n );\n },\n getExtension(id) {\n const ext = extensionDefinitionsById.get(id);\n if (!ext) {\n throw new Error(\n `Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,\n );\n }\n return ext;\n },\n toString() {\n return `Plugin{id=${pluginId}}`;\n },\n withOverrides(overrides) {\n const overriddenExtensionIds = new Set(\n overrides.extensions.map(\n e => resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n const nonOverriddenExtensions = (options.extensions ?? []).filter(\n e =>\n !overriddenExtensionIds.has(\n resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n return createFrontendPlugin({\n ...options,\n pluginId,\n extensions: [...nonOverriddenExtensions, ...overrides.extensions],\n info: {\n ...options.info,\n ...overrides.info,\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
@@ -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 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 params: any;\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":";;AAoIgB,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 { ExtensionDataRef, ExtensionDataValue } 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]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\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 ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\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 params: any;\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":";;AAiIgB,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,4 +1,5 @@
1
1
  import { createExtensionDataContainer } from '../frontend-internal/src/wiring/createExtensionDataContainer.esm.js';
2
+ import '../frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js';
2
3
  import '../frontend-internal/src/wiring/InternalExtensionDefinition.esm.js';
3
4
  import '../frontend-internal/src/wiring/InternalFrontendPlugin.esm.js';
4
5
 
@@ -24,6 +25,7 @@ function resolveInputOverrides(declaredInputs, inputs, inputOverrides) {
24
25
  if (providedData) {
25
26
  const providedContainer = createExtensionDataContainer(
26
27
  providedData,
28
+ "extension input override",
27
29
  declaredInput.extensionData
28
30
  );
29
31
  if (!originalInput) {
@@ -55,6 +57,7 @@ function resolveInputOverrides(declaredInputs, inputs, inputOverrides) {
55
57
  newInputs[name] = providedData.map((data, i) => {
56
58
  const providedContainer = createExtensionDataContainer(
57
59
  data,
60
+ "extension input override",
58
61
  declaredInput.extensionData
59
62
  );
60
63
  return Object.assign(providedContainer, {