@backstage/frontend-plugin-api 0.12.1 → 0.12.2-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @backstage/frontend-plugin-api
2
2
 
3
+ ## 0.12.2-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 878c251: Updated to `ExtensionInput` to make all type parameters optional.
8
+ - Updated dependencies
9
+ - @backstage/core-components@0.18.3-next.1
10
+ - @backstage/core-plugin-api@1.11.2-next.1
11
+
12
+ ## 0.12.2-next.0
13
+
14
+ ### Patch Changes
15
+
16
+ - 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
17
+ - Updated dependencies
18
+ - @backstage/core-plugin-api@1.11.2-next.0
19
+ - @backstage/core-components@0.18.3-next.0
20
+ - @backstage/types@1.2.2
21
+ - @backstage/version-bridge@1.0.11
22
+
3
23
  ## 0.12.1
4
24
 
5
25
  ### Patch Changes
@@ -10,6 +10,8 @@ const globalEvents = getOrCreateGlobalSingleton(
10
10
  );
11
11
  const routableExtensionRenderedEvent = "_ROUTABLE-EXTENSION-RENDERED";
12
12
  class Tracker {
13
+ analyticsApi;
14
+ context;
13
15
  constructor(analyticsApi, context = {
14
16
  pluginId: "root",
15
17
  extensionId: "App"
@@ -1 +1 @@
1
- {"version":3,"file":"Tracker.esm.js","sources":["../../src/analytics/Tracker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\nimport {\n AnalyticsApi,\n AnalyticsEventAttributes,\n AnalyticsTracker,\n} from '../apis';\nimport { AnalyticsContextValue } from './';\n\ntype TempGlobalEvents = {\n /**\n * Stores the most recent \"gathered\" mountpoint navigation.\n */\n mostRecentGatheredNavigation?: {\n action: string;\n subject: string;\n value?: number;\n attributes?: AnalyticsEventAttributes;\n context: AnalyticsContextValue;\n };\n /**\n * Stores the most recent routable extension render.\n */\n mostRecentRoutableExtensionRender?: {\n context: AnalyticsContextValue;\n };\n /**\n * Tracks whether or not a beforeunload event listener has already been\n * registered.\n */\n beforeUnloadRegistered: boolean;\n};\n\n/**\n * Temporary global store for select event data. Used to make `navigate` events\n * more accurate when gathered mountpoints are used.\n */\nconst globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(\n 'core-plugin-api:analytics-tracker-events',\n () => ({\n mostRecentGatheredNavigation: undefined,\n mostRecentRoutableExtensionRender: undefined,\n beforeUnloadRegistered: false,\n }),\n);\n\n/**\n * Internal-only event representing when a routable extension is rendered.\n */\nexport const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';\n\nexport class Tracker implements AnalyticsTracker {\n constructor(\n private readonly analyticsApi: AnalyticsApi,\n private context: AnalyticsContextValue = {\n pluginId: 'root',\n extensionId: 'App',\n },\n ) {\n // Only register a single beforeunload event across all trackers.\n if (!globalEvents.beforeUnloadRegistered) {\n // Before the page unloads, attempt to capture any deferred navigation\n // events that haven't yet been captured.\n addEventListener(\n 'beforeunload',\n () => {\n if (globalEvents.mostRecentGatheredNavigation) {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n },\n { once: true, passive: true },\n );\n\n // Prevent duplicate handlers from being registered.\n globalEvents.beforeUnloadRegistered = true;\n }\n }\n\n setContext(context: AnalyticsContextValue) {\n this.context = context;\n }\n\n captureEvent(\n action: string,\n subject: string,\n {\n value,\n attributes,\n }: { value?: number; attributes?: AnalyticsEventAttributes } = {},\n ) {\n // Never pass internal \"_routeNodeType\" context value.\n const context = this.context;\n\n // Never fire the special \"_routable-extension-rendered\" internal event.\n if (action === routableExtensionRenderedEvent) {\n // But keep track of it if we're delaying a `navigate` event for a\n // a gathered route node type.\n if (globalEvents.mostRecentGatheredNavigation) {\n globalEvents.mostRecentRoutableExtensionRender = {\n context: {\n ...context,\n extensionId: 'App',\n },\n };\n }\n return;\n }\n\n // If we are about to fire a real event, and we have an un-fired gathered\n // mountpoint navigation on the global store, we need to fire the navigate\n // event first, so this real event happens accurately after the navigation.\n if (globalEvents.mostRecentGatheredNavigation) {\n try {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n\n // Clear the global stores.\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n\n // Never directly fire a navigation event on a gathered route with default\n // contextual details.\n if (action === 'navigate' && context.pluginId === 'root') {\n // Instead, set it on the global store.\n globalEvents.mostRecentGatheredNavigation = {\n action,\n subject,\n value,\n attributes,\n context,\n };\n return;\n }\n\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n"],"names":[],"mappings":";;AAoDA,MAAM,YAAA,GAAe,0BAAA;AAAA,EACnB,0CAAA;AAAA,EACA,OAAO;AAAA,IACL,4BAAA,EAA8B,MAAA;AAAA,IAC9B,iCAAA,EAAmC,MAAA;AAAA,IACnC,sBAAA,EAAwB;AAAA,GAC1B;AACF,CAAA;AAKO,MAAM,8BAAA,GAAiC;AAEvC,MAAM,OAAA,CAAoC;AAAA,EAC/C,WAAA,CACmB,cACT,OAAA,GAAiC;AAAA,IACvC,QAAA,EAAU,MAAA;AAAA,IACV,WAAA,EAAa;AAAA,GACf,EACA;AALiB,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AACT,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAMR,IAAA,IAAI,CAAC,aAAa,sBAAA,EAAwB;AAGxC,MAAA,gBAAA;AAAA,QACE,cAAA;AAAA,QACA,MAAM;AACJ,UAAA,IAAI,aAAa,4BAAA,EAA8B;AAC7C,YAAA,IAAA,CAAK,aAAa,YAAA,CAAa;AAAA,cAC7B,GAAG,YAAA,CAAa,4BAAA;AAAA,cAChB,GAAG,YAAA,CAAa;AAAA,aACjB,CAAA;AACD,YAAA,YAAA,CAAa,4BAAA,GAA+B,MAAA;AAC5C,YAAA,YAAA,CAAa,iCAAA,GAAoC,MAAA;AAAA,UACnD;AAAA,QACF,CAAA;AAAA,QACA,EAAE,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,IAAA;AAAK,OAC9B;AAGA,MAAA,YAAA,CAAa,sBAAA,GAAyB,IAAA;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,WAAW,OAAA,EAAgC;AACzC,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA,EAEA,YAAA,CACE,QACA,OAAA,EACA;AAAA,IACE,KAAA;AAAA,IACA;AAAA,GACF,GAA+D,EAAC,EAChE;AAEA,IAAA,MAAM,UAAU,IAAA,CAAK,OAAA;AAGrB,IAAA,IAAI,WAAW,8BAAA,EAAgC;AAG7C,MAAA,IAAI,aAAa,4BAAA,EAA8B;AAC7C,QAAA,YAAA,CAAa,iCAAA,GAAoC;AAAA,UAC/C,OAAA,EAAS;AAAA,YACP,GAAG,OAAA;AAAA,YACH,WAAA,EAAa;AAAA;AACf,SACF;AAAA,MACF;AACA,MAAA;AAAA,IACF;AAKA,IAAA,IAAI,aAAa,4BAAA,EAA8B;AAC7C,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,aAAa,YAAA,CAAa;AAAA,UAC7B,GAAG,YAAA,CAAa,4BAAA;AAAA,UAChB,GAAG,YAAA,CAAa;AAAA,SACjB,CAAA;AAAA,MACH,SAAS,CAAA,EAAG;AAEV,QAAA,OAAA,CAAQ,IAAA,CAAK,4CAA4C,CAAC,CAAA;AAAA,MAC5D;AAGA,MAAA,YAAA,CAAa,4BAAA,GAA+B,MAAA;AAC5C,MAAA,YAAA,CAAa,iCAAA,GAAoC,MAAA;AAAA,IACnD;AAIA,IAAA,IAAI,MAAA,KAAW,UAAA,IAAc,OAAA,CAAQ,QAAA,KAAa,MAAA,EAAQ;AAExD,MAAA,YAAA,CAAa,4BAAA,GAA+B;AAAA,QAC1C,MAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,IAAA,CAAK,aAAa,YAAA,CAAa;AAAA,QAC7B,MAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AAEV,MAAA,OAAA,CAAQ,IAAA,CAAK,4CAA4C,CAAC,CAAA;AAAA,IAC5D;AAAA,EACF;AACF;;;;"}
1
+ {"version":3,"file":"Tracker.esm.js","sources":["../../src/analytics/Tracker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\nimport {\n AnalyticsApi,\n AnalyticsEventAttributes,\n AnalyticsTracker,\n} from '../apis';\nimport { AnalyticsContextValue } from './';\n\ntype TempGlobalEvents = {\n /**\n * Stores the most recent \"gathered\" mountpoint navigation.\n */\n mostRecentGatheredNavigation?: {\n action: string;\n subject: string;\n value?: number;\n attributes?: AnalyticsEventAttributes;\n context: AnalyticsContextValue;\n };\n /**\n * Stores the most recent routable extension render.\n */\n mostRecentRoutableExtensionRender?: {\n context: AnalyticsContextValue;\n };\n /**\n * Tracks whether or not a beforeunload event listener has already been\n * registered.\n */\n beforeUnloadRegistered: boolean;\n};\n\n/**\n * Temporary global store for select event data. Used to make `navigate` events\n * more accurate when gathered mountpoints are used.\n */\nconst globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(\n 'core-plugin-api:analytics-tracker-events',\n () => ({\n mostRecentGatheredNavigation: undefined,\n mostRecentRoutableExtensionRender: undefined,\n beforeUnloadRegistered: false,\n }),\n);\n\n/**\n * Internal-only event representing when a routable extension is rendered.\n */\nexport const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';\n\nexport class Tracker implements AnalyticsTracker {\n private readonly analyticsApi: AnalyticsApi;\n private context: AnalyticsContextValue;\n\n constructor(\n analyticsApi: AnalyticsApi,\n context: AnalyticsContextValue = {\n pluginId: 'root',\n extensionId: 'App',\n },\n ) {\n this.analyticsApi = analyticsApi;\n this.context = context;\n // Only register a single beforeunload event across all trackers.\n if (!globalEvents.beforeUnloadRegistered) {\n // Before the page unloads, attempt to capture any deferred navigation\n // events that haven't yet been captured.\n addEventListener(\n 'beforeunload',\n () => {\n if (globalEvents.mostRecentGatheredNavigation) {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n },\n { once: true, passive: true },\n );\n\n // Prevent duplicate handlers from being registered.\n globalEvents.beforeUnloadRegistered = true;\n }\n }\n\n setContext(context: AnalyticsContextValue) {\n this.context = context;\n }\n\n captureEvent(\n action: string,\n subject: string,\n {\n value,\n attributes,\n }: { value?: number; attributes?: AnalyticsEventAttributes } = {},\n ) {\n // Never pass internal \"_routeNodeType\" context value.\n const context = this.context;\n\n // Never fire the special \"_routable-extension-rendered\" internal event.\n if (action === routableExtensionRenderedEvent) {\n // But keep track of it if we're delaying a `navigate` event for a\n // a gathered route node type.\n if (globalEvents.mostRecentGatheredNavigation) {\n globalEvents.mostRecentRoutableExtensionRender = {\n context: {\n ...context,\n extensionId: 'App',\n },\n };\n }\n return;\n }\n\n // If we are about to fire a real event, and we have an un-fired gathered\n // mountpoint navigation on the global store, we need to fire the navigate\n // event first, so this real event happens accurately after the navigation.\n if (globalEvents.mostRecentGatheredNavigation) {\n try {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n\n // Clear the global stores.\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n\n // Never directly fire a navigation event on a gathered route with default\n // contextual details.\n if (action === 'navigate' && context.pluginId === 'root') {\n // Instead, set it on the global store.\n globalEvents.mostRecentGatheredNavigation = {\n action,\n subject,\n value,\n attributes,\n context,\n };\n return;\n }\n\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tracker.esm.js","sources":["../../../../../core-plugin-api/src/analytics/Tracker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\nimport {\n AnalyticsApi,\n AnalyticsEventAttributes,\n AnalyticsTracker,\n} from '../apis';\nimport { AnalyticsContextValue } from './types';\n\ntype TempGlobalEvents = {\n /**\n * Stores the most recent \"gathered\" mountpoint navigation.\n */\n mostRecentGatheredNavigation?: {\n action: string;\n subject: string;\n value?: number;\n attributes?: AnalyticsEventAttributes;\n context: AnalyticsContextValue;\n };\n /**\n * Stores the most recent routable extension render.\n */\n mostRecentRoutableExtensionRender?: {\n context: AnalyticsContextValue;\n };\n /**\n * Tracks whether or not a beforeunload event listener has already been\n * registered.\n */\n beforeUnloadRegistered: boolean;\n};\n\n/**\n * Temporary global store for select event data. Used to make `navigate` events\n * more accurate when gathered mountpoints are used.\n */\nconst globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(\n 'core-plugin-api:analytics-tracker-events',\n () => ({\n mostRecentGatheredNavigation: undefined,\n mostRecentRoutableExtensionRender: undefined,\n beforeUnloadRegistered: false,\n }),\n);\n\n/**\n * Internal-only event representing when a routable extension is rendered.\n */\nexport const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';\n\nexport class Tracker implements AnalyticsTracker {\n constructor(\n private readonly analyticsApi: AnalyticsApi,\n private context: AnalyticsContextValue = {\n routeRef: 'unknown',\n pluginId: 'root',\n extension: 'App',\n },\n ) {\n // Only register a single beforeunload event across all trackers.\n if (!globalEvents.beforeUnloadRegistered) {\n // Before the page unloads, attempt to capture any deferred navigation\n // events that haven't yet been captured.\n addEventListener(\n 'beforeunload',\n () => {\n if (globalEvents.mostRecentGatheredNavigation) {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n },\n { once: true, passive: true },\n );\n\n // Prevent duplicate handlers from being registered.\n globalEvents.beforeUnloadRegistered = true;\n }\n }\n\n setContext(context: AnalyticsContextValue) {\n this.context = context;\n }\n\n captureEvent(\n action: string,\n subject: string,\n {\n value,\n attributes,\n }: { value?: number; attributes?: AnalyticsEventAttributes } = {},\n ) {\n // Never pass internal \"_routeNodeType\" context value.\n const { _routeNodeType, ...context } = this.context;\n\n // Never fire the special \"_routable-extension-rendered\" internal event.\n if (action === routableExtensionRenderedEvent) {\n // But keep track of it if we're delaying a `navigate` event for a\n // a gathered route node type.\n if (globalEvents.mostRecentGatheredNavigation) {\n globalEvents.mostRecentRoutableExtensionRender = {\n context: {\n ...context,\n extension: 'App',\n },\n };\n }\n return;\n }\n\n // If we are about to fire a real event, and we have an un-fired gathered\n // mountpoint navigation on the global store, we need to fire the navigate\n // event first, so this real event happens accurately after the navigation.\n if (globalEvents.mostRecentGatheredNavigation) {\n try {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n\n // Clear the global stores.\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n\n // Never directly fire a navigation event on a gathered route with default\n // contextual details.\n if (\n action === 'navigate' &&\n _routeNodeType === 'gathered' &&\n context.pluginId === 'root'\n ) {\n // Instead, set it on the global store.\n globalEvents.mostRecentGatheredNavigation = {\n action,\n subject,\n value,\n attributes,\n context,\n };\n return;\n }\n\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n"],"names":[],"mappings":";;AAoDqB,0BAAA;AAAA,EACnB,0CAAA;AAAA,EACA,OAAO;AAAA,IACL,4BAAA,EAA8B,MAAA;AAAA,IAC9B,iCAAA,EAAmC,MAAA;AAAA,IACnC,sBAAA,EAAwB;AAAA,GAC1B;AACF;AAKO,MAAM,8BAAA,GAAiC;;;;"}
1
+ {"version":3,"file":"Tracker.esm.js","sources":["../../../../../core-plugin-api/src/analytics/Tracker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\nimport {\n AnalyticsApi,\n AnalyticsEventAttributes,\n AnalyticsTracker,\n} from '../apis';\nimport { AnalyticsContextValue } from './types';\n\ntype TempGlobalEvents = {\n /**\n * Stores the most recent \"gathered\" mountpoint navigation.\n */\n mostRecentGatheredNavigation?: {\n action: string;\n subject: string;\n value?: number;\n attributes?: AnalyticsEventAttributes;\n context: AnalyticsContextValue;\n };\n /**\n * Stores the most recent routable extension render.\n */\n mostRecentRoutableExtensionRender?: {\n context: AnalyticsContextValue;\n };\n /**\n * Tracks whether or not a beforeunload event listener has already been\n * registered.\n */\n beforeUnloadRegistered: boolean;\n};\n\n/**\n * Temporary global store for select event data. Used to make `navigate` events\n * more accurate when gathered mountpoints are used.\n */\nconst globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(\n 'core-plugin-api:analytics-tracker-events',\n () => ({\n mostRecentGatheredNavigation: undefined,\n mostRecentRoutableExtensionRender: undefined,\n beforeUnloadRegistered: false,\n }),\n);\n\n/**\n * Internal-only event representing when a routable extension is rendered.\n */\nexport const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';\n\nexport class Tracker implements AnalyticsTracker {\n private readonly analyticsApi: AnalyticsApi;\n private context: AnalyticsContextValue;\n\n constructor(\n analyticsApi: AnalyticsApi,\n context: AnalyticsContextValue = {\n routeRef: 'unknown',\n pluginId: 'root',\n extension: 'App',\n },\n ) {\n this.analyticsApi = analyticsApi;\n this.context = context;\n // Only register a single beforeunload event across all trackers.\n if (!globalEvents.beforeUnloadRegistered) {\n // Before the page unloads, attempt to capture any deferred navigation\n // events that haven't yet been captured.\n addEventListener(\n 'beforeunload',\n () => {\n if (globalEvents.mostRecentGatheredNavigation) {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n },\n { once: true, passive: true },\n );\n\n // Prevent duplicate handlers from being registered.\n globalEvents.beforeUnloadRegistered = true;\n }\n }\n\n setContext(context: AnalyticsContextValue) {\n this.context = context;\n }\n\n captureEvent(\n action: string,\n subject: string,\n {\n value,\n attributes,\n }: { value?: number; attributes?: AnalyticsEventAttributes } = {},\n ) {\n // Never pass internal \"_routeNodeType\" context value.\n const { _routeNodeType, ...context } = this.context;\n\n // Never fire the special \"_routable-extension-rendered\" internal event.\n if (action === routableExtensionRenderedEvent) {\n // But keep track of it if we're delaying a `navigate` event for a\n // a gathered route node type.\n if (globalEvents.mostRecentGatheredNavigation) {\n globalEvents.mostRecentRoutableExtensionRender = {\n context: {\n ...context,\n extension: 'App',\n },\n };\n }\n return;\n }\n\n // If we are about to fire a real event, and we have an un-fired gathered\n // mountpoint navigation on the global store, we need to fire the navigate\n // event first, so this real event happens accurately after the navigation.\n if (globalEvents.mostRecentGatheredNavigation) {\n try {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n\n // Clear the global stores.\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n\n // Never directly fire a navigation event on a gathered route with default\n // contextual details.\n if (\n action === 'navigate' &&\n _routeNodeType === 'gathered' &&\n context.pluginId === 'root'\n ) {\n // Instead, set it on the global store.\n globalEvents.mostRecentGatheredNavigation = {\n action,\n subject,\n value,\n attributes,\n context,\n };\n return;\n }\n\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n"],"names":[],"mappings":";;AAoDqB,0BAAA;AAAA,EACnB,0CAAA;AAAA,EACA,OAAO;AAAA,IACL,4BAAA,EAA8B,MAAA;AAAA,IAC9B,iCAAA,EAAmC,MAAA;AAAA,IACnC,sBAAA,EAAwB;AAAA,GAC1B;AACF;AAKO,MAAM,8BAAA,GAAiC;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiHolder,\n AppNode,\n ExtensionAttachToSpec,\n ExtensionDataValue,\n ExtensionDataRef,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: ExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n };\n readonly output: Array<ExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\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 type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AA8BO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CA6DjD;AAAA,EACD,IAAA,EAAM,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;;;"}
1
+ {"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiHolder,\n AppNode,\n ExtensionAttachToSpec,\n ExtensionDataValue,\n ExtensionDataRef,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: ExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n };\n}>({\n type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AA8BO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CAqDjD;AAAA,EACD,IAAA,EAAM,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;;;"}
package/dist/index.d.ts CHANGED
@@ -133,7 +133,10 @@ declare const coreExtensionData: {
133
133
  /** @public */
134
134
  interface ExtensionInput<UExtensionData extends ExtensionDataRef<unknown, string, {
135
135
  optional?: true;
136
- }>, TConfig extends {
136
+ }> = ExtensionDataRef, TConfig extends {
137
+ singleton: boolean;
138
+ optional: boolean;
139
+ } = {
137
140
  singleton: boolean;
138
141
  optional: boolean;
139
142
  }> {
@@ -163,15 +166,9 @@ declare function createExtensionInput<UExtensionData extends ExtensionDataRef<un
163
166
 
164
167
  /** @ignore */
165
168
  type ResolvedInputValueOverrides<TInputs extends {
166
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
167
- optional: boolean;
168
- singleton: boolean;
169
- }>;
169
+ [inputName in string]: ExtensionInput;
170
170
  } = {
171
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
172
- optional: boolean;
173
- singleton: boolean;
174
- }>;
171
+ [inputName in string]: ExtensionInput;
175
172
  }> = Expand<{
176
173
  [KName in keyof TInputs as TInputs[KName] extends ExtensionInput<any, {
177
174
  optional: infer IOptional extends boolean;
@@ -647,10 +644,7 @@ declare function createExtensionBlueprintParams<T extends object = object>(param
647
644
  * @public
648
645
  */
649
646
  type CreateExtensionBlueprintOptions<TKind extends string, TParams extends object | ExtensionBlueprintDefineParams, UOutput extends ExtensionDataRef, TInputs extends {
650
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
651
- optional: boolean;
652
- singleton: boolean;
653
- }>;
647
+ [inputName in string]: ExtensionInput;
654
648
  }, TConfigSchema extends {
655
649
  [key in string]: (zImpl: typeof z) => z.ZodType;
656
650
  }, UFactoryOutput extends ExtensionDataValue<any, any>, TDataRefs extends {
@@ -725,10 +719,7 @@ type ExtensionBlueprintParameters = {
725
719
  };
726
720
  output?: ExtensionDataRef;
727
721
  inputs?: {
728
- [KName in string]: ExtensionInput<ExtensionDataRef, {
729
- optional: boolean;
730
- singleton: boolean;
731
- }>;
722
+ [KName in string]: ExtensionInput;
732
723
  };
733
724
  dataRefs?: {
734
725
  [name in string]: ExtensionDataRef;
@@ -771,10 +762,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
771
762
  makeWithOverrides<TName extends string | undefined, TExtensionConfigSchema extends {
772
763
  [key in string]: (zImpl: typeof z) => z.ZodType;
773
764
  }, UFactoryOutput extends ExtensionDataValue<any, any>, UNewOutput extends ExtensionDataRef, TExtraInputs extends {
774
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
775
- optional: boolean;
776
- singleton: boolean;
777
- }>;
765
+ [inputName in string]: ExtensionInput;
778
766
  }>(args: {
779
767
  name?: TName;
780
768
  attachTo?: ExtensionAttachToSpec;
@@ -863,10 +851,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
863
851
  * @public
864
852
  */
865
853
  declare function createExtensionBlueprint<TParams extends object | ExtensionBlueprintDefineParams, UOutput extends ExtensionDataRef, TInputs extends {
866
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
867
- optional: boolean;
868
- singleton: boolean;
869
- }>;
854
+ [inputName in string]: ExtensionInput;
870
855
  }, TConfigSchema extends {
871
856
  [key in string]: (zImpl: typeof z) => z.ZodType;
872
857
  }, UFactoryOutput extends ExtensionDataValue<any, any>, TKind extends string, TDataRefs extends {
@@ -889,7 +874,7 @@ declare function createExtensionBlueprint<TParams extends object | ExtensionBlue
889
874
  * Convert a single extension input into a matching resolved input.
890
875
  * @public
891
876
  */
892
- type ResolvedExtensionInput<TExtensionInput extends ExtensionInput<any, any>> = TExtensionInput['extensionData'] extends Array<ExtensionDataRef> ? {
877
+ type ResolvedExtensionInput<TExtensionInput extends ExtensionInput> = TExtensionInput['extensionData'] extends Array<ExtensionDataRef> ? {
893
878
  node: AppNode;
894
879
  } & ExtensionDataContainer<TExtensionInput['extensionData'][number]> : never;
895
880
  /**
@@ -897,7 +882,7 @@ type ResolvedExtensionInput<TExtensionInput extends ExtensionInput<any, any>> =
897
882
  * @public
898
883
  */
899
884
  type ResolvedExtensionInputs<TInputs extends {
900
- [name in string]: ExtensionInput<any, any>;
885
+ [name in string]: ExtensionInput;
901
886
  }> = {
902
887
  [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] ? Array<Expand<ResolvedExtensionInput<TInputs[InputName]>>> : false extends TInputs[InputName]['config']['optional'] ? Expand<ResolvedExtensionInput<TInputs[InputName]>> : Expand<ResolvedExtensionInput<TInputs[InputName]> | undefined>;
903
888
  };
@@ -917,10 +902,7 @@ type ExtensionAttachToSpec = {
917
902
  }>;
918
903
  /** @public */
919
904
  type CreateExtensionOptions<TKind extends string | undefined, TName extends string | undefined, UOutput extends ExtensionDataRef, TInputs extends {
920
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
921
- optional: boolean;
922
- singleton: boolean;
923
- }>;
905
+ [inputName in string]: ExtensionInput;
924
906
  }, TConfigSchema extends {
925
907
  [key: string]: (zImpl: typeof z) => z.ZodType;
926
908
  }, UFactoryOutput extends ExtensionDataValue<any, any>> = {
@@ -954,10 +936,7 @@ type ExtensionDefinitionParameters = {
954
936
  };
955
937
  output?: ExtensionDataRef;
956
938
  inputs?: {
957
- [KName in string]: ExtensionInput<ExtensionDataRef, {
958
- optional: boolean;
959
- singleton: boolean;
960
- }>;
939
+ [KName in string]: ExtensionInput;
961
940
  };
962
941
  params?: object | ExtensionBlueprintDefineParams;
963
942
  };
@@ -974,10 +953,7 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
974
953
  override<TExtensionConfigSchema extends {
975
954
  [key in string]: (zImpl: typeof z) => z.ZodType;
976
955
  }, UFactoryOutput extends ExtensionDataValue<any, any>, UNewOutput extends ExtensionDataRef, TExtraInputs extends {
977
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
978
- optional: boolean;
979
- singleton: boolean;
980
- }>;
956
+ [inputName in string]: ExtensionInput;
981
957
  }, TParamsInput extends AnyParamsInput<NonNullable<T['params']>>>(args: Expand<{
982
958
  attachTo?: ExtensionAttachToSpec;
983
959
  disabled?: boolean;
@@ -1054,10 +1030,7 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
1054
1030
  * @public
1055
1031
  */
1056
1032
  declare function createExtension<UOutput extends ExtensionDataRef, TInputs extends {
1057
- [inputName in string]: ExtensionInput<ExtensionDataRef, {
1058
- optional: boolean;
1059
- singleton: boolean;
1060
- }>;
1033
+ [inputName in string]: ExtensionInput;
1061
1034
  }, TConfigSchema extends {
1062
1035
  [key: string]: (zImpl: typeof z) => z.ZodType;
1063
1036
  }, UFactoryOutput extends ExtensionDataValue<any, any>, const TKind extends string | undefined = undefined, const TName extends string | undefined = undefined>(options: CreateExtensionOptions<TKind, TName, UOutput, TInputs, TConfigSchema, UFactoryOutput>): ExtensionDefinition<{
@@ -2,12 +2,14 @@ import { RouteRefImpl } from './RouteRef.esm.js';
2
2
  import { describeParentCallSite } from './describeParentCallSite.esm.js';
3
3
 
4
4
  class ExternalRouteRefImpl extends RouteRefImpl {
5
+ $$type = "@backstage/ExternalRouteRef";
6
+ params;
7
+ defaultTarget;
5
8
  constructor(params = [], defaultTarget, creationSite) {
6
9
  super(params, creationSite);
7
10
  this.params = params;
8
11
  this.defaultTarget = defaultTarget;
9
12
  }
10
- $$type = "@backstage/ExternalRouteRef";
11
13
  getDefaultTarget() {
12
14
  return this.defaultTarget;
13
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ExternalRouteRef.esm.js","sources":["../../src/routing/ExternalRouteRef.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 { RouteRefImpl } from './RouteRef';\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface ExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/ExternalRouteRef';\n readonly T: TParams;\n}\n\n/** @internal */\nexport interface InternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends ExternalRouteRef<TParams> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n>(resource: ExternalRouteRef<TParams>): InternalExternalRouteRef<TParams> {\n const r = resource as InternalExternalRouteRef<TParams>;\n if (r.$$type !== '@backstage/ExternalRouteRef') {\n throw new Error(`Invalid ExternalRouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/** @internal */\nexport function isExternalRouteRef(opaque: {\n $$type: string;\n}): opaque is ExternalRouteRef {\n return opaque.$$type === '@backstage/ExternalRouteRef';\n}\n\n/** @internal */\nclass ExternalRouteRefImpl\n extends RouteRefImpl\n implements InternalExternalRouteRef\n{\n readonly $$type = '@backstage/ExternalRouteRef' as any;\n\n constructor(\n readonly params: string[] = [],\n readonly defaultTarget: string | undefined,\n creationSite: string,\n ) {\n super(params, creationSite);\n }\n\n getDefaultTarget() {\n return this.defaultTarget;\n }\n}\n\n/**\n * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @param options - Description of the route reference to be created.\n * @public\n */\nexport function createExternalRouteRef<\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(options?: {\n /**\n * The parameters that will be provided to the external route reference.\n */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n /**\n * The route (typically in another plugin) that this should map to by default.\n *\n * The string is expected to be on the standard `<plugin id>.<route id>` form,\n * for example `techdocs.docRoot`.\n */\n defaultTarget?: string;\n}): ExternalRouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n return new ExternalRouteRefImpl(\n options?.params as string[] | undefined,\n options?.defaultTarget,\n describeParentCallSite(),\n );\n}\n"],"names":[],"mappings":";;;AAoEA,MAAM,6BACI,YAAA,CAEV;AAAA,EAGE,WAAA,CACW,MAAA,GAAmB,EAAC,EACpB,eACT,YAAA,EACA;AACA,IAAA,KAAA,CAAM,QAAQ,YAAY,CAAA;AAJjB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AAAA,EAIX;AAAA,EARS,MAAA,GAAS,6BAAA;AAAA,EAUlB,gBAAA,GAAmB;AACjB,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,EACd;AACF;AAYO,SAAS,uBAGd,OAAA,EAqBA;AACA,EAAA,OAAO,IAAI,oBAAA;AAAA,IACT,OAAA,EAAS,MAAA;AAAA,IACT,OAAA,EAAS,aAAA;AAAA,IACT,sBAAA;AAAuB,GACzB;AACF;;;;"}
1
+ {"version":3,"file":"ExternalRouteRef.esm.js","sources":["../../src/routing/ExternalRouteRef.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 { RouteRefImpl } from './RouteRef';\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface ExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/ExternalRouteRef';\n readonly T: TParams;\n}\n\n/** @internal */\nexport interface InternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends ExternalRouteRef<TParams> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n>(resource: ExternalRouteRef<TParams>): InternalExternalRouteRef<TParams> {\n const r = resource as InternalExternalRouteRef<TParams>;\n if (r.$$type !== '@backstage/ExternalRouteRef') {\n throw new Error(`Invalid ExternalRouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/** @internal */\nexport function isExternalRouteRef(opaque: {\n $$type: string;\n}): opaque is ExternalRouteRef {\n return opaque.$$type === '@backstage/ExternalRouteRef';\n}\n\n/** @internal */\nclass ExternalRouteRefImpl\n extends RouteRefImpl\n implements InternalExternalRouteRef\n{\n readonly $$type = '@backstage/ExternalRouteRef' as any;\n readonly params: string[];\n readonly defaultTarget: string | undefined;\n\n constructor(\n params: string[] = [],\n defaultTarget: string | undefined,\n creationSite: string,\n ) {\n super(params, creationSite);\n this.params = params;\n this.defaultTarget = defaultTarget;\n }\n\n getDefaultTarget() {\n return this.defaultTarget;\n }\n}\n\n/**\n * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @param options - Description of the route reference to be created.\n * @public\n */\nexport function createExternalRouteRef<\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(options?: {\n /**\n * The parameters that will be provided to the external route reference.\n */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n /**\n * The route (typically in another plugin) that this should map to by default.\n *\n * The string is expected to be on the standard `<plugin id>.<route id>` form,\n * for example `techdocs.docRoot`.\n */\n defaultTarget?: string;\n}): ExternalRouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n return new ExternalRouteRefImpl(\n options?.params as string[] | undefined,\n options?.defaultTarget,\n describeParentCallSite(),\n );\n}\n"],"names":[],"mappings":";;;AAoEA,MAAM,6BACI,YAAA,CAEV;AAAA,EACW,MAAA,GAAS,6BAAA;AAAA,EACT,MAAA;AAAA,EACA,aAAA;AAAA,EAET,WAAA,CACE,MAAA,GAAmB,EAAC,EACpB,eACA,YAAA,EACA;AACA,IAAA,KAAA,CAAM,QAAQ,YAAY,CAAA;AAC1B,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AAAA,EACvB;AAAA,EAEA,gBAAA,GAAmB;AACjB,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,EACd;AACF;AAYO,SAAS,uBAGd,OAAA,EAqBA;AACA,EAAA,OAAO,IAAI,oBAAA;AAAA,IACT,OAAA,EAAS,MAAA;AAAA,IACT,OAAA,EAAS,aAAA;AAAA,IACT,sBAAA;AAAuB,GACzB;AACF;;;;"}
@@ -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 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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"}
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<TExtensionInput extends ExtensionInput> =\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;\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 { [inputName in string]: ExtensionInput },\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?: { [KName in string]: ExtensionInput };\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 { [inputName in string]: ExtensionInput },\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 { [inputName in string]: ExtensionInput },\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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"}
@@ -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 { 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
+ {"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 { [inputName in string]: ExtensionInput },\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?: { [KName in string]: ExtensionInput };\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 { [inputName in string]: ExtensionInput },\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 { [inputName in string]: ExtensionInput },\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":"createExtensionInput.esm.js","sources":["../../src/wiring/createExtensionInput.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 { ExtensionDataRef } from './createExtensionDataRef';\n\n/** @public */\nexport interface ExtensionInput<\n UExtensionData extends ExtensionDataRef<unknown, string, { optional?: true }>,\n TConfig extends { singleton: boolean; optional: boolean },\n> {\n $$type: '@backstage/ExtensionInput';\n extensionData: Array<UExtensionData>;\n config: TConfig;\n replaces?: Array<{ id: string; input: string }>;\n}\n\n/** @public */\nexport function createExtensionInput<\n UExtensionData extends ExtensionDataRef<unknown, string, { optional?: true }>,\n TConfig extends { singleton?: boolean; optional?: boolean },\n>(\n extensionData: Array<UExtensionData>,\n config?: TConfig & { replaces?: Array<{ id: string; input: string }> },\n): ExtensionInput<\n UExtensionData,\n {\n singleton: TConfig['singleton'] extends true ? true : false;\n optional: TConfig['optional'] extends true ? true : false;\n }\n> {\n if (process.env.NODE_ENV !== 'production') {\n if (Array.isArray(extensionData)) {\n const seen = new Set();\n const duplicates = [];\n for (const dataRef of extensionData) {\n if (seen.has(dataRef.id)) {\n duplicates.push(dataRef.id);\n } else {\n seen.add(dataRef.id);\n }\n }\n if (duplicates.length > 0) {\n throw new Error(\n `ExtensionInput may not have duplicate data refs: '${duplicates.join(\n \"', '\",\n )}'`,\n );\n }\n }\n }\n return {\n $$type: '@backstage/ExtensionInput',\n extensionData,\n config: {\n singleton: Boolean(config?.singleton) as TConfig['singleton'] extends true\n ? true\n : false,\n optional: Boolean(config?.optional) as TConfig['optional'] extends true\n ? true\n : false,\n },\n replaces: config?.replaces,\n } as ExtensionInput<\n UExtensionData,\n {\n singleton: TConfig['singleton'] extends true ? true : false;\n optional: TConfig['optional'] extends true ? true : false;\n }\n >;\n}\n"],"names":[],"mappings":"AA8BO,SAAS,oBAAA,CAId,eACA,MAAA,EAOA;AACA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AACzC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,aAAa,CAAA,EAAG;AAChC,MAAA,MAAM,IAAA,uBAAW,GAAA,EAAI;AACrB,MAAA,MAAM,aAAa,EAAC;AACpB,MAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,QAAA,IAAI,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA,EAAG;AACxB,UAAA,UAAA,CAAW,IAAA,CAAK,QAAQ,EAAE,CAAA;AAAA,QAC5B,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,GAAA,CAAI,QAAQ,EAAE,CAAA;AAAA,QACrB;AAAA,MACF;AACA,MAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,qDAAqD,UAAA,CAAW,IAAA;AAAA,YAC9D;AAAA,WACD,CAAA,CAAA;AAAA,SACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,2BAAA;AAAA,IACR,aAAA;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,SAAA,EAAW,OAAA,CAAQ,MAAA,EAAQ,SAAS,CAAA;AAAA,MAGpC,QAAA,EAAU,OAAA,CAAQ,MAAA,EAAQ,QAAQ;AAAA,KAGpC;AAAA,IACA,UAAU,MAAA,EAAQ;AAAA,GACpB;AAOF;;;;"}
1
+ {"version":3,"file":"createExtensionInput.esm.js","sources":["../../src/wiring/createExtensionInput.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 { ExtensionDataRef } from './createExtensionDataRef';\n\n/** @public */\nexport interface ExtensionInput<\n UExtensionData extends ExtensionDataRef<\n unknown,\n string,\n { optional?: true }\n > = ExtensionDataRef,\n TConfig extends { singleton: boolean; optional: boolean } = {\n singleton: boolean;\n optional: boolean;\n },\n> {\n $$type: '@backstage/ExtensionInput';\n extensionData: Array<UExtensionData>;\n config: TConfig;\n replaces?: Array<{ id: string; input: string }>;\n}\n\n/** @public */\nexport function createExtensionInput<\n UExtensionData extends ExtensionDataRef<unknown, string, { optional?: true }>,\n TConfig extends { singleton?: boolean; optional?: boolean },\n>(\n extensionData: Array<UExtensionData>,\n config?: TConfig & { replaces?: Array<{ id: string; input: string }> },\n): ExtensionInput<\n UExtensionData,\n {\n singleton: TConfig['singleton'] extends true ? true : false;\n optional: TConfig['optional'] extends true ? true : false;\n }\n> {\n if (process.env.NODE_ENV !== 'production') {\n if (Array.isArray(extensionData)) {\n const seen = new Set();\n const duplicates = [];\n for (const dataRef of extensionData) {\n if (seen.has(dataRef.id)) {\n duplicates.push(dataRef.id);\n } else {\n seen.add(dataRef.id);\n }\n }\n if (duplicates.length > 0) {\n throw new Error(\n `ExtensionInput may not have duplicate data refs: '${duplicates.join(\n \"', '\",\n )}'`,\n );\n }\n }\n }\n return {\n $$type: '@backstage/ExtensionInput',\n extensionData,\n config: {\n singleton: Boolean(config?.singleton) as TConfig['singleton'] extends true\n ? true\n : false,\n optional: Boolean(config?.optional) as TConfig['optional'] extends true\n ? true\n : false,\n },\n replaces: config?.replaces,\n } as ExtensionInput<\n UExtensionData,\n {\n singleton: TConfig['singleton'] extends true ? true : false;\n optional: TConfig['optional'] extends true ? true : false;\n }\n >;\n}\n"],"names":[],"mappings":"AAqCO,SAAS,oBAAA,CAId,eACA,MAAA,EAOA;AACA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AACzC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,aAAa,CAAA,EAAG;AAChC,MAAA,MAAM,IAAA,uBAAW,GAAA,EAAI;AACrB,MAAA,MAAM,aAAa,EAAC;AACpB,MAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,QAAA,IAAI,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA,EAAG;AACxB,UAAA,UAAA,CAAW,IAAA,CAAK,QAAQ,EAAE,CAAA;AAAA,QAC5B,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,GAAA,CAAI,QAAQ,EAAE,CAAA;AAAA,QACrB;AAAA,MACF;AACA,MAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,qDAAqD,UAAA,CAAW,IAAA;AAAA,YAC9D;AAAA,WACD,CAAA,CAAA;AAAA,SACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,2BAAA;AAAA,IACR,aAAA;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,SAAA,EAAW,OAAA,CAAQ,MAAA,EAAQ,SAAS,CAAA;AAAA,MAGpC,QAAA,EAAU,OAAA,CAAQ,MAAA,EAAQ,QAAQ;AAAA,KAGpC;AAAA,IACA,UAAU,MAAA,EAAQ;AAAA,GACpB;AAOF;;;;"}
@@ -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 { 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":";;AAiIO,SAAS,0BAAA,CAGd,YACA,OAAA,EAC0C;AAC1C,EAAA,MAAM,kBAAA,GAAqB,yBAAA,CAA0B,UAAA,CAAW,UAAU,CAAA;AAC1E,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA,EAAW,MAAA;AAAA,IACX,QAAA,EAAU,MAAA;AAAA,IACV,GAAG;AAAA,GACL,GAAI,kBAAA;AAEJ,EAAA,MAAM,SAAA,GAAY,kBAAA,CAAmB,SAAA,IAAa,OAAA,EAAS,SAAA;AAE3D,EAAA,MAAM,QAAA,GACJ,QAAQ,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,IAAI,KAAK,SAAA,IAAa,IAAA;AAC5D,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,oGAAA,EAAuG,IAAI,CAAA,WAAA,EAAc,SAAS,SAAS,IAAI,CAAA;AAAA,KACjJ;AAAA,EACF;AAEA,EAAA,MAAM,KAAK,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,GAAK,QAAA;AAE1C,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,MAAA,EAAQ,sBAAA;AAAA,IACR,SAAS,kBAAA,CAAmB,OAAA;AAAA,IAC5B,EAAA;AAAA,IACA,QAAA,GAAW;AACT,MAAA,OAAO,gBAAgB,EAAE,CAAA,CAAA,CAAA;AAAA,IAC3B;AAAA,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: { [inputName in string]: ExtensionInput };\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 }>;\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":";;AAyHO,SAAS,0BAAA,CAGd,YACA,OAAA,EAC0C;AAC1C,EAAA,MAAM,kBAAA,GAAqB,yBAAA,CAA0B,UAAA,CAAW,UAAU,CAAA;AAC1E,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA,EAAW,MAAA;AAAA,IACX,QAAA,EAAU,MAAA;AAAA,IACV,GAAG;AAAA,GACL,GAAI,kBAAA;AAEJ,EAAA,MAAM,SAAA,GAAY,kBAAA,CAAmB,SAAA,IAAa,OAAA,EAAS,SAAA;AAE3D,EAAA,MAAM,QAAA,GACJ,QAAQ,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,IAAI,KAAK,SAAA,IAAa,IAAA;AAC5D,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,oGAAA,EAAuG,IAAI,CAAA,WAAA,EAAc,SAAS,SAAS,IAAI,CAAA;AAAA,KACjJ;AAAA,EACF;AAEA,EAAA,MAAM,KAAK,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,GAAK,QAAA;AAE1C,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,MAAA,EAAQ,sBAAA;AAAA,IACR,SAAS,kBAAA,CAAmB,OAAA;AAAA,IAC5B,EAAA;AAAA,IACA,QAAA,GAAW;AACT,MAAA,OAAO,gBAAgB,EAAE,CAAA,CAAA,CAAA;AAAA,IAC3B;AAAA,GACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveInputOverrides.esm.js","sources":["../../src/wiring/resolveInputOverrides.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 { AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport { ResolvedExtensionInput } from './createExtension';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport {\n ExtensionDataRef,\n ExtensionDataRefToValue,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataContainer } from './types';\n\n/** @ignore */\nexport type ResolvedInputValueOverrides<\n TInputs extends {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n } = {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n> = Expand<\n {\n [KName in keyof TInputs as TInputs[KName] extends ExtensionInput<\n any,\n {\n optional: infer IOptional extends boolean;\n singleton: boolean;\n }\n >\n ? IOptional extends true\n ? never\n : KName\n : never]: TInputs[KName] extends ExtensionInput<\n infer IDataRefs,\n { optional: boolean; singleton: infer ISingleton extends boolean }\n >\n ? ISingleton extends true\n ? Iterable<ExtensionDataRefToValue<IDataRefs>>\n : Array<Iterable<ExtensionDataRefToValue<IDataRefs>>>\n : never;\n } & {\n [KName in keyof TInputs as TInputs[KName] extends ExtensionInput<\n any,\n {\n optional: infer IOptional extends boolean;\n singleton: boolean;\n }\n >\n ? IOptional extends true\n ? KName\n : never\n : never]?: TInputs[KName] extends ExtensionInput<\n infer IDataRefs,\n { optional: boolean; singleton: infer ISingleton extends boolean }\n >\n ? ISingleton extends true\n ? Iterable<ExtensionDataRefToValue<IDataRefs>>\n : Array<Iterable<ExtensionDataRefToValue<IDataRefs>>>\n : never;\n }\n>;\n\nfunction expectArray<T>(value: T | T[]): T[] {\n return value as T[];\n}\nfunction expectItem<T>(value: T | T[]): T {\n return value as T;\n}\n\n/** @internal */\nexport function resolveInputOverrides(\n declaredInputs?: {\n [inputName in string]: ExtensionInput<\n ExtensionDataRef,\n { optional: boolean; singleton: boolean }\n >;\n },\n inputs?: {\n [KName in string]?:\n | ({ node: AppNode } & ExtensionDataContainer<any>)\n | Array<{ node: AppNode } & ExtensionDataContainer<any>>;\n },\n inputOverrides?: ResolvedInputValueOverrides,\n) {\n if (!declaredInputs || !inputs || !inputOverrides) {\n return inputs;\n }\n\n const newInputs: typeof inputs = {};\n for (const name in declaredInputs) {\n if (!Object.hasOwn(declaredInputs, name)) {\n continue;\n }\n const declaredInput = declaredInputs[name];\n const providedData = inputOverrides[name];\n if (declaredInput.config.singleton) {\n const originalInput = expectItem(inputs[name]);\n if (providedData) {\n const providedContainer = createExtensionDataContainer(\n providedData as Iterable<ExtensionDataValue<any, any>>,\n 'extension input override',\n declaredInput.extensionData,\n );\n if (!originalInput) {\n throw new Error(\n `attempted to override data of input '${name}' but it is not present in the original inputs`,\n );\n }\n newInputs[name] = Object.assign(providedContainer, {\n node: (originalInput as ResolvedExtensionInput<any>).node,\n }) as any;\n }\n } else {\n const originalInput = expectArray(inputs[name]);\n if (!Array.isArray(providedData)) {\n throw new Error(\n `override data provided for input '${name}' must be an array`,\n );\n }\n\n // Regular inputs can be overridden in two different ways:\n // 1) Forward a subset of the original inputs in a new order\n // 2) Provide new data for each original input\n\n // First check if all inputs are being removed\n if (providedData.length === 0) {\n newInputs[name] = [];\n } else {\n // Check how many of the provided data items have a node property, i.e. is a forwarded input\n const withNodesCount = providedData.filter(d => 'node' in d).length;\n if (withNodesCount === 0) {\n if (originalInput.length !== providedData.length) {\n throw new Error(\n `override data provided for input '${name}' must match the length of the original inputs`,\n );\n }\n newInputs[name] = providedData.map((data, i) => {\n const providedContainer = createExtensionDataContainer(\n data as Iterable<ExtensionDataValue<any, any>>,\n 'extension input override',\n declaredInput.extensionData,\n );\n return Object.assign(providedContainer, {\n node: (originalInput[i] as ResolvedExtensionInput<any>).node,\n }) as any;\n });\n } else if (withNodesCount === providedData.length) {\n newInputs[name] = providedData as any;\n } else {\n throw new Error(\n `override data for input '${name}' may not mix forwarded inputs with data overrides`,\n );\n }\n }\n }\n }\n return newInputs;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolveInputOverrides.esm.js","sources":["../../src/wiring/resolveInputOverrides.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 { AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport { ResolvedExtensionInput } from './createExtension';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport {\n ExtensionDataRefToValue,\n ExtensionDataValue,\n} from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataContainer } from './types';\n\n/** @ignore */\nexport type ResolvedInputValueOverrides<\n TInputs extends { [inputName in string]: ExtensionInput } = {\n [inputName in string]: ExtensionInput;\n },\n> = Expand<\n {\n [KName in keyof TInputs as TInputs[KName] extends ExtensionInput<\n any,\n {\n optional: infer IOptional extends boolean;\n singleton: boolean;\n }\n >\n ? IOptional extends true\n ? never\n : KName\n : never]: TInputs[KName] extends ExtensionInput<\n infer IDataRefs,\n { optional: boolean; singleton: infer ISingleton extends boolean }\n >\n ? ISingleton extends true\n ? Iterable<ExtensionDataRefToValue<IDataRefs>>\n : Array<Iterable<ExtensionDataRefToValue<IDataRefs>>>\n : never;\n } & {\n [KName in keyof TInputs as TInputs[KName] extends ExtensionInput<\n any,\n {\n optional: infer IOptional extends boolean;\n singleton: boolean;\n }\n >\n ? IOptional extends true\n ? KName\n : never\n : never]?: TInputs[KName] extends ExtensionInput<\n infer IDataRefs,\n { optional: boolean; singleton: infer ISingleton extends boolean }\n >\n ? ISingleton extends true\n ? Iterable<ExtensionDataRefToValue<IDataRefs>>\n : Array<Iterable<ExtensionDataRefToValue<IDataRefs>>>\n : never;\n }\n>;\n\nfunction expectArray<T>(value: T | T[]): T[] {\n return value as T[];\n}\nfunction expectItem<T>(value: T | T[]): T {\n return value as T;\n}\n\n/** @internal */\nexport function resolveInputOverrides(\n declaredInputs?: { [inputName in string]: ExtensionInput },\n inputs?: {\n [KName in string]?:\n | ({ node: AppNode } & ExtensionDataContainer<any>)\n | Array<{ node: AppNode } & ExtensionDataContainer<any>>;\n },\n inputOverrides?: ResolvedInputValueOverrides,\n) {\n if (!declaredInputs || !inputs || !inputOverrides) {\n return inputs;\n }\n\n const newInputs: typeof inputs = {};\n for (const name in declaredInputs) {\n if (!Object.hasOwn(declaredInputs, name)) {\n continue;\n }\n const declaredInput = declaredInputs[name];\n const providedData = inputOverrides[name];\n if (declaredInput.config.singleton) {\n const originalInput = expectItem(inputs[name]);\n if (providedData) {\n const providedContainer = createExtensionDataContainer(\n providedData as Iterable<ExtensionDataValue<any, any>>,\n 'extension input override',\n declaredInput.extensionData,\n );\n if (!originalInput) {\n throw new Error(\n `attempted to override data of input '${name}' but it is not present in the original inputs`,\n );\n }\n newInputs[name] = Object.assign(providedContainer, {\n node: (originalInput as ResolvedExtensionInput<any>).node,\n }) as any;\n }\n } else {\n const originalInput = expectArray(inputs[name]);\n if (!Array.isArray(providedData)) {\n throw new Error(\n `override data provided for input '${name}' must be an array`,\n );\n }\n\n // Regular inputs can be overridden in two different ways:\n // 1) Forward a subset of the original inputs in a new order\n // 2) Provide new data for each original input\n\n // First check if all inputs are being removed\n if (providedData.length === 0) {\n newInputs[name] = [];\n } else {\n // Check how many of the provided data items have a node property, i.e. is a forwarded input\n const withNodesCount = providedData.filter(d => 'node' in d).length;\n if (withNodesCount === 0) {\n if (originalInput.length !== providedData.length) {\n throw new Error(\n `override data provided for input '${name}' must match the length of the original inputs`,\n );\n }\n newInputs[name] = providedData.map((data, i) => {\n const providedContainer = createExtensionDataContainer(\n data as Iterable<ExtensionDataValue<any, any>>,\n 'extension input override',\n declaredInput.extensionData,\n );\n return Object.assign(providedContainer, {\n node: (originalInput[i] as ResolvedExtensionInput<any>).node,\n }) as any;\n });\n } else if (withNodesCount === providedData.length) {\n newInputs[name] = providedData as any;\n } else {\n throw new Error(\n `override data for input '${name}' may not mix forwarded inputs with data overrides`,\n );\n }\n }\n }\n }\n return newInputs;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/frontend-plugin-api",
3
- "version": "0.12.1",
3
+ "version": "0.12.2-next.1",
4
4
  "backstage": {
5
5
  "role": "web-library"
6
6
  },
@@ -31,20 +31,20 @@
31
31
  "test": "backstage-cli package test"
32
32
  },
33
33
  "dependencies": {
34
- "@backstage/core-components": "^0.18.2",
35
- "@backstage/core-plugin-api": "^1.11.1",
36
- "@backstage/types": "^1.2.2",
37
- "@backstage/version-bridge": "^1.0.11",
34
+ "@backstage/core-components": "0.18.3-next.1",
35
+ "@backstage/core-plugin-api": "1.11.2-next.1",
36
+ "@backstage/types": "1.2.2",
37
+ "@backstage/version-bridge": "1.0.11",
38
38
  "@material-ui/core": "^4.12.4",
39
39
  "lodash": "^4.17.21",
40
40
  "zod": "^3.22.4",
41
41
  "zod-to-json-schema": "^3.21.4"
42
42
  },
43
43
  "devDependencies": {
44
- "@backstage/cli": "^0.34.4",
45
- "@backstage/frontend-app-api": "^0.13.1",
46
- "@backstage/frontend-test-utils": "^0.4.0",
47
- "@backstage/test-utils": "^1.7.12",
44
+ "@backstage/cli": "0.34.5-next.1",
45
+ "@backstage/frontend-app-api": "0.13.2-next.0",
46
+ "@backstage/frontend-test-utils": "0.4.1-next.0",
47
+ "@backstage/test-utils": "1.7.13-next.0",
48
48
  "@testing-library/jest-dom": "^6.0.0",
49
49
  "@testing-library/react": "^16.0.0",
50
50
  "@types/react": "^18.0.0",