@backstage/frontend-app-api 0.3.1-next.0 → 0.4.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1,46 +1,46 @@
1
- import React, { useMemo, useState, useEffect } from 'react';
1
+ import React, { useMemo, useState, useEffect, createContext, useContext } from 'react';
2
2
  import { ConfigReader } from '@backstage/config';
3
- import { createExtension, createExtensionInput, coreExtensionData, useRouteRef, createThemeExtension, appTreeApiRef } from '@backstage/frontend-plugin-api';
4
- import { useRoutes, BrowserRouter, useInRouterContext, MemoryRouter, matchRoutes, generatePath, Route } from 'react-router-dom';
3
+ import { createExtension, createExtensionInput, coreExtensionData, createTranslationExtension, useComponentRef, coreComponentRefs, useRouteRef, createThemeExtension, createComponentExtension, AnalyticsContext, useAnalytics, appTreeApiRef, componentsApiRef } from '@backstage/frontend-plugin-api';
4
+ import { useRoutes, BrowserRouter, useInRouterContext, MemoryRouter, matchRoutes, generatePath, useLocation, Route } from 'react-router-dom';
5
5
  import { SidebarPage, sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem, Progress, ErrorPage, ErrorPanel } from '@backstage/core-components';
6
- import { makeStyles } from '@material-ui/core';
7
- import { useApi, appThemeApiRef, FeatureFlagState, createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, attachComponentData, featureFlagsApiRef } from '@backstage/core-plugin-api';
6
+ import { makeStyles, Button as Button$1 } from '@material-ui/core';
7
+ import { useApi, appThemeApiRef, FeatureFlagState, createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, createApiRef, attachComponentData, featureFlagsApiRef } from '@backstage/core-plugin-api';
8
8
  import { UrlPatternDiscovery, AlertApiForwarder, NoOpAnalyticsApi, ErrorAlerter, ErrorApiForwarder, UnhandledErrorForwarder, WebStorage, createFetchApi, FetchMiddlewares, OAuthRequestManager, GoogleAuth, MicrosoftAuth, GithubAuth, OktaAuth, GitlabAuth, OneLoginAuth, BitbucketAuth, BitbucketServerAuth, AtlassianAuth, ApiFactoryRegistry, AppThemeSelector, ApiResolver, ApiProvider } from '@backstage/core-app-api';
9
9
  import useObservable from 'react-use/lib/useObservable';
10
- import { createVersionedContext, createVersionedValueMap, getOrCreateGlobalSingleton } from '@backstage/version-bridge';
11
10
  import ObservableImpl from 'zen-observable';
12
11
  import { createInstance } from 'i18next';
13
12
  import { permissionApiRef, IdentityPermissionApi } from '@backstage/plugin-permission-react';
14
13
  import Button from '@material-ui/core/Button';
15
- import MuiApartmentIcon from '@material-ui/icons/Apartment';
16
- import MuiBrokenImageIcon from '@material-ui/icons/BrokenImage';
17
- import MuiCategoryIcon from '@material-ui/icons/Category';
18
- import MuiCreateNewFolderIcon from '@material-ui/icons/CreateNewFolder';
19
- import MuiSubjectIcon from '@material-ui/icons/Subject';
20
- import MuiSearchIcon from '@material-ui/icons/Search';
21
- import MuiChatIcon from '@material-ui/icons/Chat';
22
- import MuiDashboardIcon from '@material-ui/icons/Dashboard';
23
- import MuiDocsIcon from '@material-ui/icons/Description';
24
- import MuiEmailIcon from '@material-ui/icons/Email';
25
- import MuiExtensionIcon from '@material-ui/icons/Extension';
26
- import MuiGitHubIcon from '@material-ui/icons/GitHub';
27
- import MuiHelpIcon from '@material-ui/icons/Help';
28
- import MuiLocationOnIcon from '@material-ui/icons/LocationOn';
29
- import MuiMemoryIcon from '@material-ui/icons/Memory';
30
- import MuiMenuBookIcon from '@material-ui/icons/MenuBook';
31
- import MuiPeopleIcon from '@material-ui/icons/People';
32
- import MuiPersonIcon from '@material-ui/icons/Person';
33
- import MuiWarningIcon from '@material-ui/icons/Warning';
34
- import MuiWorkIcon from '@material-ui/icons/Work';
35
- import MuiFeaturedPlayListIcon from '@material-ui/icons/FeaturedPlayList';
14
+ import '@material-ui/icons/Apartment';
15
+ import '@material-ui/icons/BrokenImage';
16
+ import '@material-ui/icons/Category';
17
+ import '@material-ui/icons/CreateNewFolder';
18
+ import '@material-ui/icons/Subject';
19
+ import '@material-ui/icons/Search';
20
+ import '@material-ui/icons/Chat';
21
+ import '@material-ui/icons/Dashboard';
22
+ import '@material-ui/icons/Description';
23
+ import '@material-ui/icons/Email';
24
+ import '@material-ui/icons/Extension';
25
+ import '@material-ui/icons/GitHub';
26
+ import '@material-ui/icons/Help';
27
+ import '@material-ui/icons/LocationOn';
28
+ import '@material-ui/icons/Memory';
29
+ import '@material-ui/icons/MenuBook';
30
+ import '@material-ui/icons/People';
31
+ import '@material-ui/icons/Person';
32
+ import '@material-ui/icons/Warning';
33
+ import '@material-ui/icons/Work';
34
+ import '@material-ui/icons/FeaturedPlayList';
36
35
  import { UnifiedThemeProvider, themes } from '@backstage/theme';
37
36
  import DarkIcon from '@material-ui/icons/Brightness2';
38
37
  import LightIcon from '@material-ui/icons/WbSunny';
38
+ import { getOrCreateGlobalSingleton, createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
39
39
  import { appLanguageApiRef, translationApiRef } from '@backstage/core-plugin-api/alpha';
40
40
  import mapValues from 'lodash/mapValues';
41
41
 
42
42
  const Core = createExtension({
43
- id: "core",
43
+ namespace: "core",
44
44
  attachTo: { id: "root", input: "default" },
45
45
  // ignored
46
46
  inputs: {
@@ -50,6 +50,12 @@ const Core = createExtension({
50
50
  themes: createExtensionInput({
51
51
  theme: coreExtensionData.theme
52
52
  }),
53
+ components: createExtensionInput({
54
+ component: coreExtensionData.component
55
+ }),
56
+ translations: createExtensionInput({
57
+ translation: createTranslationExtension.translationDataRef
58
+ }),
53
59
  root: createExtensionInput(
54
60
  {
55
61
  element: coreExtensionData.reactElement
@@ -62,14 +68,15 @@ const Core = createExtension({
62
68
  },
63
69
  factory({ inputs }) {
64
70
  return {
65
- root: inputs.root.element
71
+ root: inputs.root.output.element
66
72
  };
67
73
  }
68
74
  });
69
75
 
70
76
  const CoreRoutes = createExtension({
71
- id: "core.routes",
72
- attachTo: { id: "core.layout", input: "content" },
77
+ namespace: "core",
78
+ name: "routes",
79
+ attachTo: { id: "core/layout", input: "content" },
73
80
  inputs: {
74
81
  routes: createExtensionInput({
75
82
  path: coreExtensionData.routePath,
@@ -82,12 +89,19 @@ const CoreRoutes = createExtension({
82
89
  },
83
90
  factory({ inputs }) {
84
91
  const Routes = () => {
85
- const element = useRoutes(
86
- inputs.routes.map((route) => ({
87
- path: `${route.path}/*`,
88
- element: route.element
89
- }))
92
+ const NotFoundErrorPage = useComponentRef(
93
+ coreComponentRefs.notFoundErrorPage
90
94
  );
95
+ const element = useRoutes([
96
+ ...inputs.routes.map((route) => ({
97
+ path: `${route.output.path}/*`,
98
+ element: route.output.element
99
+ })),
100
+ {
101
+ path: "*",
102
+ element: /* @__PURE__ */ React.createElement(NotFoundErrorPage, null)
103
+ }
104
+ ]);
91
105
  return element;
92
106
  };
93
107
  return {
@@ -97,8 +111,9 @@ const CoreRoutes = createExtension({
97
111
  });
98
112
 
99
113
  const CoreLayout = createExtension({
100
- id: "core.layout",
101
- attachTo: { id: "core", input: "root" },
114
+ namespace: "core",
115
+ name: "layout",
116
+ attachTo: { id: "core/router", input: "children" },
102
117
  inputs: {
103
118
  nav: createExtensionInput(
104
119
  {
@@ -118,7 +133,7 @@ const CoreLayout = createExtension({
118
133
  },
119
134
  factory({ inputs }) {
120
135
  return {
121
- element: /* @__PURE__ */ React.createElement(SidebarPage, null, inputs.nav.element, inputs.content.element)
136
+ element: /* @__PURE__ */ React.createElement(SidebarPage, null, inputs.nav.output.element, inputs.content.output.element)
122
137
  };
123
138
  }
124
139
  });
@@ -193,10 +208,11 @@ const useSidebarLogoStyles = makeStyles({
193
208
  marginLeft: 24
194
209
  }
195
210
  });
196
- const SidebarLogo = () => {
211
+ const SidebarLogo = (props) => {
212
+ var _a, _b;
197
213
  const classes = useSidebarLogoStyles();
198
214
  const { isOpen } = useSidebarOpenState();
199
- return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Link, { to: "/", underline: "none", className: classes.link, "aria-label": "Home" }, isOpen ? /* @__PURE__ */ React.createElement(LogoFull, null) : /* @__PURE__ */ React.createElement(LogoIcon, null)));
215
+ return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Link, { to: "/", underline: "none", className: classes.link, "aria-label": "Home" }, isOpen ? (_a = props == null ? void 0 : props.logoFull) != null ? _a : /* @__PURE__ */ React.createElement(LogoFull, null) : (_b = props == null ? void 0 : props.logoIcon) != null ? _b : /* @__PURE__ */ React.createElement(LogoIcon, null)));
200
216
  };
201
217
  const SidebarNavItem = (props) => {
202
218
  const { icon: Icon, title, routeRef } = props;
@@ -204,19 +220,30 @@ const SidebarNavItem = (props) => {
204
220
  return /* @__PURE__ */ React.createElement(SidebarItem, { to, icon: Icon, text: title });
205
221
  };
206
222
  const CoreNav = createExtension({
207
- id: "core.nav",
208
- attachTo: { id: "core.layout", input: "nav" },
223
+ namespace: "core",
224
+ name: "nav",
225
+ attachTo: { id: "core/layout", input: "nav" },
209
226
  inputs: {
210
227
  items: createExtensionInput({
211
228
  target: coreExtensionData.navTarget
212
- })
229
+ }),
230
+ logos: createExtensionInput(
231
+ {
232
+ elements: coreExtensionData.logoElements
233
+ },
234
+ {
235
+ singleton: true,
236
+ optional: true
237
+ }
238
+ )
213
239
  },
214
240
  output: {
215
241
  element: coreExtensionData.reactElement
216
242
  },
217
243
  factory({ inputs }) {
244
+ var _a;
218
245
  return {
219
- element: /* @__PURE__ */ React.createElement(Sidebar, null, /* @__PURE__ */ React.createElement(SidebarLogo, null), /* @__PURE__ */ React.createElement(SidebarDivider, null), inputs.items.map((item, index) => /* @__PURE__ */ React.createElement(SidebarNavItem, { ...item.target, key: index })))
246
+ element: /* @__PURE__ */ React.createElement(Sidebar, null, /* @__PURE__ */ React.createElement(SidebarLogo, { ...(_a = inputs.logos) == null ? void 0 : _a.output.elements }), /* @__PURE__ */ React.createElement(SidebarDivider, null), inputs.items.map((item, index) => /* @__PURE__ */ React.createElement(SidebarNavItem, { ...item.output.target, key: index })))
220
247
  };
221
248
  }
222
249
  });
@@ -412,15 +439,6 @@ class AppIdentityProxy {
412
439
  }
413
440
  }
414
441
 
415
- const AppContext = createVersionedContext("app-context");
416
- const AppContextProvider = ({
417
- appContext,
418
- children
419
- }) => {
420
- const versionedValue = createVersionedValueMap({ 1: appContext });
421
- return /* @__PURE__ */ React.createElement(AppContext.Provider, { value: versionedValue, children });
422
- };
423
-
424
442
  var __defProp$2 = Object.defineProperty;
425
443
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
426
444
  var __publicField$2 = (obj, key, value) => {
@@ -649,21 +667,21 @@ class BehaviorSubject {
649
667
  }
650
668
  }
651
669
 
652
- var __accessCheck$1 = (obj, member, msg) => {
670
+ var __accessCheck$2 = (obj, member, msg) => {
653
671
  if (!member.has(obj))
654
672
  throw TypeError("Cannot " + msg);
655
673
  };
656
- var __privateGet$1 = (obj, member, getter) => {
657
- __accessCheck$1(obj, member, "read from private field");
674
+ var __privateGet$2 = (obj, member, getter) => {
675
+ __accessCheck$2(obj, member, "read from private field");
658
676
  return getter ? getter.call(obj) : member.get(obj);
659
677
  };
660
- var __privateAdd$1 = (obj, member, value) => {
678
+ var __privateAdd$2 = (obj, member, value) => {
661
679
  if (member.has(obj))
662
680
  throw TypeError("Cannot add the same private member more than once");
663
681
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
664
682
  };
665
- var __privateSet$1 = (obj, member, value, setter) => {
666
- __accessCheck$1(obj, member, "write to private field");
683
+ var __privateSet$2 = (obj, member, value, setter) => {
684
+ __accessCheck$2(obj, member, "write to private field");
667
685
  setter ? setter.call(obj, value) : member.set(obj, value);
668
686
  return value;
669
687
  };
@@ -672,13 +690,13 @@ const STORAGE_KEY = "language";
672
690
  const DEFAULT_LANGUAGE = "en";
673
691
  const _AppLanguageSelector = class _AppLanguageSelector {
674
692
  constructor(languages, initialLanguage) {
675
- __privateAdd$1(this, _languages, void 0);
676
- __privateAdd$1(this, _language$1, void 0);
677
- __privateAdd$1(this, _subject, void 0);
678
- __privateSet$1(this, _languages, languages);
679
- __privateSet$1(this, _language$1, initialLanguage);
680
- __privateSet$1(this, _subject, new BehaviorSubject({
681
- language: __privateGet$1(this, _language$1)
693
+ __privateAdd$2(this, _languages, void 0);
694
+ __privateAdd$2(this, _language$1, void 0);
695
+ __privateAdd$2(this, _subject, void 0);
696
+ __privateSet$2(this, _languages, languages);
697
+ __privateSet$2(this, _language$1, initialLanguage);
698
+ __privateSet$2(this, _subject, new BehaviorSubject({
699
+ language: __privateGet$2(this, _language$1)
682
700
  }));
683
701
  }
684
702
  static create(options) {
@@ -729,28 +747,28 @@ const _AppLanguageSelector = class _AppLanguageSelector {
729
747
  return selector;
730
748
  }
731
749
  getAvailableLanguages() {
732
- return { languages: __privateGet$1(this, _languages).slice() };
750
+ return { languages: __privateGet$2(this, _languages).slice() };
733
751
  }
734
752
  setLanguage(language) {
735
753
  const lng = language != null ? language : DEFAULT_LANGUAGE;
736
- if (lng === __privateGet$1(this, _language$1)) {
754
+ if (lng === __privateGet$2(this, _language$1)) {
737
755
  return;
738
756
  }
739
- if (lng && !__privateGet$1(this, _languages).includes(lng)) {
757
+ if (lng && !__privateGet$2(this, _languages).includes(lng)) {
740
758
  throw new Error(
741
- `Failed to change language to '${lng}', available languages are '${__privateGet$1(this, _languages).join(
759
+ `Failed to change language to '${lng}', available languages are '${__privateGet$2(this, _languages).join(
742
760
  "', '"
743
761
  )}'`
744
762
  );
745
763
  }
746
- __privateSet$1(this, _language$1, lng);
747
- __privateGet$1(this, _subject).next({ language: lng });
764
+ __privateSet$2(this, _language$1, lng);
765
+ __privateGet$2(this, _subject).next({ language: lng });
748
766
  }
749
767
  getLanguage() {
750
- return { language: __privateGet$1(this, _language$1) };
768
+ return { language: __privateGet$2(this, _language$1) };
751
769
  }
752
770
  language$() {
753
- return __privateGet$1(this, _subject);
771
+ return __privateGet$2(this, _subject);
754
772
  }
755
773
  };
756
774
  _languages = new WeakMap();
@@ -780,26 +798,26 @@ function toInternalTranslationRef(ref) {
780
798
  return r;
781
799
  }
782
800
 
783
- var __accessCheck = (obj, member, msg) => {
801
+ var __accessCheck$1 = (obj, member, msg) => {
784
802
  if (!member.has(obj))
785
803
  throw TypeError("Cannot " + msg);
786
804
  };
787
- var __privateGet = (obj, member, getter) => {
788
- __accessCheck(obj, member, "read from private field");
805
+ var __privateGet$1 = (obj, member, getter) => {
806
+ __accessCheck$1(obj, member, "read from private field");
789
807
  return getter ? getter.call(obj) : member.get(obj);
790
808
  };
791
- var __privateAdd = (obj, member, value) => {
809
+ var __privateAdd$1 = (obj, member, value) => {
792
810
  if (member.has(obj))
793
811
  throw TypeError("Cannot add the same private member more than once");
794
812
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
795
813
  };
796
- var __privateSet = (obj, member, value, setter) => {
797
- __accessCheck(obj, member, "write to private field");
814
+ var __privateSet$1 = (obj, member, value, setter) => {
815
+ __accessCheck$1(obj, member, "write to private field");
798
816
  setter ? setter.call(obj, value) : member.set(obj, value);
799
817
  return value;
800
818
  };
801
819
  var __privateMethod = (obj, member, method) => {
802
- __accessCheck(obj, member, "access private method");
820
+ __accessCheck$1(obj, member, "access private method");
803
821
  return method;
804
822
  };
805
823
  var _loaded, _loading, _loaders, _getLoaderKey, getLoaderKey_fn, _i18n, _loader, _language, _registeredRefs, _languageChangeListeners, _changeLanguage, changeLanguage_fn, _createSnapshot, createSnapshot_fn, _registerDefaults, registerDefaults_fn;
@@ -813,41 +831,41 @@ function removeNulls(messages) {
813
831
  class ResourceLoader {
814
832
  constructor(onLoad) {
815
833
  this.onLoad = onLoad;
816
- __privateAdd(this, _getLoaderKey);
834
+ __privateAdd$1(this, _getLoaderKey);
817
835
  /** Loaded resources by loader key */
818
- __privateAdd(this, _loaded, /* @__PURE__ */ new Set());
836
+ __privateAdd$1(this, _loaded, /* @__PURE__ */ new Set());
819
837
  /** Resource loading promises by loader key */
820
- __privateAdd(this, _loading, /* @__PURE__ */ new Map());
838
+ __privateAdd$1(this, _loading, /* @__PURE__ */ new Map());
821
839
  /** Loaders for each resource language */
822
- __privateAdd(this, _loaders, /* @__PURE__ */ new Map());
840
+ __privateAdd$1(this, _loaders, /* @__PURE__ */ new Map());
823
841
  }
824
842
  addTranslationResource(resource) {
825
843
  const internalResource = toInternalTranslationResource(resource);
826
844
  for (const entry of internalResource.resources) {
827
845
  const key = __privateMethod(this, _getLoaderKey, getLoaderKey_fn).call(this, entry.language, internalResource.id);
828
- if (!__privateGet(this, _loaders).has(key)) {
829
- __privateGet(this, _loaders).set(key, entry.loader);
846
+ if (!__privateGet$1(this, _loaders).has(key)) {
847
+ __privateGet$1(this, _loaders).set(key, entry.loader);
830
848
  }
831
849
  }
832
850
  }
833
851
  needsLoading(language, namespace) {
834
852
  const key = __privateMethod(this, _getLoaderKey, getLoaderKey_fn).call(this, language, namespace);
835
- const loader = __privateGet(this, _loaders).get(key);
853
+ const loader = __privateGet$1(this, _loaders).get(key);
836
854
  if (!loader) {
837
855
  return false;
838
856
  }
839
- return !__privateGet(this, _loaded).has(key);
857
+ return !__privateGet$1(this, _loaded).has(key);
840
858
  }
841
859
  async load(language, namespace) {
842
860
  const key = __privateMethod(this, _getLoaderKey, getLoaderKey_fn).call(this, language, namespace);
843
- const loader = __privateGet(this, _loaders).get(key);
861
+ const loader = __privateGet$1(this, _loaders).get(key);
844
862
  if (!loader) {
845
863
  return;
846
864
  }
847
- if (__privateGet(this, _loaded).has(key)) {
865
+ if (__privateGet$1(this, _loaded).has(key)) {
848
866
  return;
849
867
  }
850
- const loading = __privateGet(this, _loading).get(key);
868
+ const loading = __privateGet$1(this, _loading).get(key);
851
869
  if (loading) {
852
870
  await loading;
853
871
  return;
@@ -855,14 +873,14 @@ class ResourceLoader {
855
873
  const load = loader().then(
856
874
  (result) => {
857
875
  this.onLoad({ language, namespace, messages: result.messages });
858
- __privateGet(this, _loaded).add(key);
876
+ __privateGet$1(this, _loaded).add(key);
859
877
  },
860
878
  (error) => {
861
- __privateGet(this, _loaded).add(key);
879
+ __privateGet$1(this, _loaded).add(key);
862
880
  throw error;
863
881
  }
864
882
  );
865
- __privateGet(this, _loading).set(key, load);
883
+ __privateGet$1(this, _loading).set(key, load);
866
884
  await load;
867
885
  }
868
886
  }
@@ -875,19 +893,19 @@ getLoaderKey_fn = function(language, namespace) {
875
893
  };
876
894
  const _I18nextTranslationApi = class _I18nextTranslationApi {
877
895
  constructor(i18n, loader, language) {
878
- __privateAdd(this, _changeLanguage);
879
- __privateAdd(this, _createSnapshot);
880
- __privateAdd(this, _registerDefaults);
881
- __privateAdd(this, _i18n, void 0);
882
- __privateAdd(this, _loader, void 0);
883
- __privateAdd(this, _language, void 0);
896
+ __privateAdd$1(this, _changeLanguage);
897
+ __privateAdd$1(this, _createSnapshot);
898
+ __privateAdd$1(this, _registerDefaults);
899
+ __privateAdd$1(this, _i18n, void 0);
900
+ __privateAdd$1(this, _loader, void 0);
901
+ __privateAdd$1(this, _language, void 0);
884
902
  /** Keep track of which refs we have registered default resources for */
885
- __privateAdd(this, _registeredRefs, /* @__PURE__ */ new Set());
903
+ __privateAdd$1(this, _registeredRefs, /* @__PURE__ */ new Set());
886
904
  /** Notify observers when language changes */
887
- __privateAdd(this, _languageChangeListeners, /* @__PURE__ */ new Set());
888
- __privateSet(this, _i18n, i18n);
889
- __privateSet(this, _loader, loader);
890
- __privateSet(this, _language, language);
905
+ __privateAdd$1(this, _languageChangeListeners, /* @__PURE__ */ new Set());
906
+ __privateSet$1(this, _i18n, i18n);
907
+ __privateSet$1(this, _loader, loader);
908
+ __privateSet$1(this, _language, language);
891
909
  }
892
910
  static create(options) {
893
911
  const { languages } = options.languageApi.getAvailableLanguages();
@@ -963,7 +981,7 @@ const _I18nextTranslationApi = class _I18nextTranslationApi {
963
981
  const loadResource = () => {
964
982
  loadTicket = {};
965
983
  const ticket = loadTicket;
966
- __privateGet(this, _loader).load(__privateGet(this, _language), internalRef.id).then(
984
+ __privateGet$1(this, _loader).load(__privateGet$1(this, _language), internalRef.id).then(
967
985
  () => {
968
986
  if (ticket === loadTicket) {
969
987
  const snapshot = __privateMethod(this, _createSnapshot, createSnapshot_fn).call(this, internalRef);
@@ -987,12 +1005,12 @@ const _I18nextTranslationApi = class _I18nextTranslationApi {
987
1005
  loadResource();
988
1006
  }
989
1007
  };
990
- if (__privateGet(this, _loader).needsLoading(__privateGet(this, _language), internalRef.id)) {
1008
+ if (__privateGet$1(this, _loader).needsLoading(__privateGet$1(this, _language), internalRef.id)) {
991
1009
  loadResource();
992
1010
  }
993
- __privateGet(this, _languageChangeListeners).add(onChange);
1011
+ __privateGet$1(this, _languageChangeListeners).add(onChange);
994
1012
  return () => {
995
- __privateGet(this, _languageChangeListeners).delete(onChange);
1013
+ __privateGet$1(this, _languageChangeListeners).delete(onChange);
996
1014
  };
997
1015
  });
998
1016
  }
@@ -1004,18 +1022,18 @@ _registeredRefs = new WeakMap();
1004
1022
  _languageChangeListeners = new WeakMap();
1005
1023
  _changeLanguage = new WeakSet();
1006
1024
  changeLanguage_fn = function(language) {
1007
- if (__privateGet(this, _language) !== language) {
1008
- __privateSet(this, _language, language);
1009
- __privateGet(this, _i18n).changeLanguage(language);
1010
- __privateGet(this, _languageChangeListeners).forEach((listener) => listener());
1025
+ if (__privateGet$1(this, _language) !== language) {
1026
+ __privateSet$1(this, _language, language);
1027
+ __privateGet$1(this, _i18n).changeLanguage(language);
1028
+ __privateGet$1(this, _languageChangeListeners).forEach((listener) => listener());
1011
1029
  }
1012
1030
  };
1013
1031
  _createSnapshot = new WeakSet();
1014
1032
  createSnapshot_fn = function(internalRef) {
1015
- if (__privateGet(this, _loader).needsLoading(__privateGet(this, _language), internalRef.id)) {
1033
+ if (__privateGet$1(this, _loader).needsLoading(__privateGet$1(this, _language), internalRef.id)) {
1016
1034
  return { ready: false };
1017
1035
  }
1018
- const t = __privateGet(this, _i18n).getFixedT(
1036
+ const t = __privateGet$1(this, _i18n).getFixedT(
1019
1037
  null,
1020
1038
  internalRef.id
1021
1039
  );
@@ -1026,12 +1044,12 @@ createSnapshot_fn = function(internalRef) {
1026
1044
  };
1027
1045
  _registerDefaults = new WeakSet();
1028
1046
  registerDefaults_fn = function(internalRef) {
1029
- if (__privateGet(this, _registeredRefs).has(internalRef.id)) {
1047
+ if (__privateGet$1(this, _registeredRefs).has(internalRef.id)) {
1030
1048
  return;
1031
1049
  }
1032
- __privateGet(this, _registeredRefs).add(internalRef.id);
1050
+ __privateGet$1(this, _registeredRefs).add(internalRef.id);
1033
1051
  const defaultMessages = internalRef.getDefaultMessages();
1034
- __privateGet(this, _i18n).addResourceBundle(
1052
+ __privateGet$1(this, _i18n).addResourceBundle(
1035
1053
  DEFAULT_LANGUAGE,
1036
1054
  internalRef.id,
1037
1055
  defaultMessages,
@@ -1042,11 +1060,28 @@ registerDefaults_fn = function(internalRef) {
1042
1060
  );
1043
1061
  const defaultResource = internalRef.getDefaultResource();
1044
1062
  if (defaultResource) {
1045
- __privateGet(this, _loader).addTranslationResource(defaultResource);
1063
+ __privateGet$1(this, _loader).addTranslationResource(defaultResource);
1046
1064
  }
1047
1065
  };
1048
1066
  let I18nextTranslationApi = _I18nextTranslationApi;
1049
1067
 
1068
+ function resolveExtensionDefinition(definition, context) {
1069
+ var _a;
1070
+ const { name, kind, namespace: _, ...rest } = definition;
1071
+ const namespace = (_a = definition.namespace) != null ? _a : context == null ? void 0 : context.namespace;
1072
+ const namePart = name && namespace ? `${namespace}/${name}` : namespace || name;
1073
+ if (!namePart) {
1074
+ throw new Error(
1075
+ `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`
1076
+ );
1077
+ }
1078
+ return {
1079
+ ...rest,
1080
+ id: kind ? `${kind}:${namePart}` : namePart,
1081
+ $$type: "@backstage/Extension"
1082
+ };
1083
+ }
1084
+
1050
1085
  const apis = [
1051
1086
  createApiFactory({
1052
1087
  api: discoveryApiRef,
@@ -1285,33 +1320,6 @@ const components = {
1285
1320
  ErrorBoundaryFallback: DefaultErrorBoundaryFallback
1286
1321
  };
1287
1322
 
1288
- const icons = {
1289
- brokenImage: MuiBrokenImageIcon,
1290
- // To be confirmed: see https://github.com/backstage/backstage/issues/4970
1291
- catalog: MuiMenuBookIcon,
1292
- scaffolder: MuiCreateNewFolderIcon,
1293
- techdocs: MuiSubjectIcon,
1294
- search: MuiSearchIcon,
1295
- chat: MuiChatIcon,
1296
- dashboard: MuiDashboardIcon,
1297
- docs: MuiDocsIcon,
1298
- email: MuiEmailIcon,
1299
- github: MuiGitHubIcon,
1300
- group: MuiPeopleIcon,
1301
- help: MuiHelpIcon,
1302
- "kind:api": MuiExtensionIcon,
1303
- "kind:component": MuiMemoryIcon,
1304
- "kind:domain": MuiApartmentIcon,
1305
- "kind:group": MuiPeopleIcon,
1306
- "kind:location": MuiLocationOnIcon,
1307
- "kind:system": MuiCategoryIcon,
1308
- "kind:user": MuiPersonIcon,
1309
- "kind:resource": MuiWorkIcon,
1310
- "kind:template": MuiFeaturedPlayListIcon,
1311
- user: MuiPersonIcon,
1312
- warning: MuiWarningIcon
1313
- };
1314
-
1315
1323
  const LightTheme = createThemeExtension({
1316
1324
  id: "light",
1317
1325
  title: "Light Theme",
@@ -1394,7 +1402,8 @@ function extractRouteInfoFromAppNode(node) {
1394
1402
  routeRefs: /* @__PURE__ */ new Set(),
1395
1403
  caseSensitive: false,
1396
1404
  children: [MATCH_ALL_ROUTE],
1397
- plugins: /* @__PURE__ */ new Set()
1405
+ plugins: /* @__PURE__ */ new Set(),
1406
+ appNode: current
1398
1407
  };
1399
1408
  parentChildren.push(currentObj);
1400
1409
  newParentRef = candidateParentRef;
@@ -1731,14 +1740,6 @@ function expandShorthandExtensionParameters(arrayEntry, arrayIndex) {
1731
1740
  errorMsg("extension ID must not be empty or contain whitespace")
1732
1741
  );
1733
1742
  }
1734
- if (id2.includes("/")) {
1735
- let message = `extension ID must not contain slashes; got '${id2}'`;
1736
- const good = id2.split("/")[0];
1737
- if (good) {
1738
- message += `, did you mean '${good}'?`;
1739
- }
1740
- throw new Error(errorMsg(message));
1741
- }
1742
1743
  }
1743
1744
  if (typeof arrayEntry === "string") {
1744
1745
  assertValidId(arrayEntry);
@@ -1918,12 +1919,25 @@ function toInternalExtensionOverrides(overrides) {
1918
1919
  const internal = overrides;
1919
1920
  if (internal.$$type !== "@backstage/ExtensionOverrides") {
1920
1921
  throw new Error(
1921
- `Invalid translation resource, bad type '${internal.$$type}'`
1922
+ `Invalid extension overrides instance, bad type '${internal.$$type}'`
1923
+ );
1924
+ }
1925
+ if (internal.version !== "v1") {
1926
+ throw new Error(
1927
+ `Invalid extension overrides instance, bad version '${internal.version}'`
1922
1928
  );
1923
1929
  }
1930
+ return internal;
1931
+ }
1932
+
1933
+ function toInternalBackstagePlugin(plugin) {
1934
+ const internal = plugin;
1935
+ if (internal.$$type !== "@backstage/BackstagePlugin") {
1936
+ throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);
1937
+ }
1924
1938
  if (internal.version !== "v1") {
1925
1939
  throw new Error(
1926
- `Invalid translation resource, bad version '${internal.version}'`
1940
+ `Invalid plugin instance, bad version '${internal.version}'`
1927
1941
  );
1928
1942
  }
1929
1943
  return internal;
@@ -1939,7 +1953,10 @@ function resolveAppNodeSpecs(options) {
1939
1953
  (f) => f.$$type === "@backstage/ExtensionOverrides"
1940
1954
  );
1941
1955
  const pluginExtensions = plugins.flatMap((source) => {
1942
- return source.extensions.map((extension) => ({ ...extension, source }));
1956
+ return toInternalBackstagePlugin(source).extensions.map((extension) => ({
1957
+ ...extension,
1958
+ source
1959
+ }));
1943
1960
  });
1944
1961
  const overrideExtensions = overrides.flatMap(
1945
1962
  (override) => toInternalExtensionOverrides(override).extensions
@@ -2078,10 +2095,11 @@ function resolveAppNodeSpecs(options) {
2078
2095
 
2079
2096
  function resolveInputData(dataMap, attachment, inputName) {
2080
2097
  return mapValues(dataMap, (ref) => {
2081
- const value = attachment.instance.getData(ref);
2098
+ var _a;
2099
+ const value = (_a = attachment.instance) == null ? void 0 : _a.getData(ref);
2082
2100
  if (value === void 0 && !ref.config.optional) {
2083
2101
  throw new Error(
2084
- `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.id}'`
2102
+ `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.spec.id}'`
2085
2103
  );
2086
2104
  }
2087
2105
  return value;
@@ -2094,7 +2112,7 @@ function resolveInputs(inputMap, attachments) {
2094
2112
  if (undeclaredAttachments.length > 0) {
2095
2113
  throw new Error(
2096
2114
  `received undeclared input${undeclaredAttachments.length > 1 ? "s" : ""} ${undeclaredAttachments.map(
2097
- ([k, exts]) => `'${k}' from extension${exts.length > 1 ? "s" : ""} '${exts.map((e) => e.id).join("', '")}'`
2115
+ ([k, exts]) => `'${k}' from extension${exts.length > 1 ? "s" : ""} '${exts.map((e) => e.spec.id).join("', '")}'`
2098
2116
  ).join(" and ")}`
2099
2117
  );
2100
2118
  }
@@ -2103,7 +2121,7 @@ function resolveInputs(inputMap, attachments) {
2103
2121
  const attachedNodes = (_a = attachments.get(inputName)) != null ? _a : [];
2104
2122
  if (input.config.singleton) {
2105
2123
  if (attachedNodes.length > 1) {
2106
- const attachedNodeIds = attachedNodes.map((e) => e.id);
2124
+ const attachedNodeIds = attachedNodes.map((e) => e.spec.id);
2107
2125
  throw Error(
2108
2126
  `expected ${input.config.optional ? "at most" : "exactly"} one '${inputName}' input but received multiple: '${attachedNodeIds.join(
2109
2127
  "', '"
@@ -2115,17 +2133,25 @@ function resolveInputs(inputMap, attachments) {
2115
2133
  }
2116
2134
  throw Error(`input '${inputName}' is required but was not received`);
2117
2135
  }
2118
- return resolveInputData(input.extensionData, attachedNodes[0], inputName);
2136
+ return {
2137
+ node: attachedNodes[0],
2138
+ output: resolveInputData(
2139
+ input.extensionData,
2140
+ attachedNodes[0],
2141
+ inputName
2142
+ )
2143
+ };
2119
2144
  }
2120
- return attachedNodes.map(
2121
- (attachment) => resolveInputData(input.extensionData, attachment, inputName)
2122
- );
2145
+ return attachedNodes.map((attachment) => ({
2146
+ node: attachment,
2147
+ output: resolveInputData(input.extensionData, attachment, inputName)
2148
+ }));
2123
2149
  });
2124
2150
  }
2125
2151
  function createAppNodeInstance(options) {
2126
2152
  var _a;
2127
- const { spec, attachments } = options;
2128
- const { id, extension, config, source } = spec;
2153
+ const { node, attachments } = options;
2154
+ const { id, extension, config } = node.spec;
2129
2155
  const extensionData = /* @__PURE__ */ new Map();
2130
2156
  const extensionDataRefs = /* @__PURE__ */ new Set();
2131
2157
  let parsedConfig;
@@ -2138,7 +2164,7 @@ function createAppNodeInstance(options) {
2138
2164
  }
2139
2165
  try {
2140
2166
  const namedOutputs = extension.factory({
2141
- source,
2167
+ node,
2142
2168
  config: parsedConfig,
2143
2169
  inputs: resolveInputs(extension.inputs, attachments)
2144
2170
  });
@@ -2157,7 +2183,7 @@ function createAppNodeInstance(options) {
2157
2183
  }
2158
2184
  } catch (e) {
2159
2185
  throw new Error(
2160
- `Failed to instantiate extension '${id}'${e.name === "Error" ? `, ${e.message}` : `; caused by ${e}`}`
2186
+ `Failed to instantiate extension '${id}'${e.name === "Error" ? `, ${e.message}` : `; caused by ${e.stack}`}`
2161
2187
  );
2162
2188
  }
2163
2189
  return {
@@ -2184,14 +2210,14 @@ function instantiateAppNodeTree(rootNode) {
2184
2210
  if (!childInstance) {
2185
2211
  return [];
2186
2212
  }
2187
- return [{ id: child.spec.id, instance: childInstance }];
2213
+ return [child];
2188
2214
  });
2189
2215
  if (instantiatedChildren.length > 0) {
2190
2216
  instantiatedAttachments.set(input, instantiatedChildren);
2191
2217
  }
2192
2218
  }
2193
2219
  node.instance = createAppNodeInstance({
2194
- spec: node.spec,
2220
+ node,
2195
2221
  attachments: instantiatedAttachments
2196
2222
  });
2197
2223
  return node.instance;
@@ -2213,14 +2239,271 @@ function createAppTree(options) {
2213
2239
  return tree;
2214
2240
  }
2215
2241
 
2242
+ const DefaultProgressComponent = createComponentExtension({
2243
+ ref: coreComponentRefs.progress,
2244
+ component: { sync: () => components.Progress }
2245
+ });
2246
+ const DefaultNotFoundErrorPageComponent = createComponentExtension({
2247
+ ref: coreComponentRefs.notFoundErrorPage,
2248
+ component: { sync: () => components.NotFoundErrorPage }
2249
+ });
2250
+ const DefaultErrorBoundaryComponent = createComponentExtension({
2251
+ ref: coreComponentRefs.errorBoundaryFallback,
2252
+ component: {
2253
+ sync: () => (props) => {
2254
+ const { plugin, error, resetError } = props;
2255
+ const title = `Error in ${plugin == null ? void 0 : plugin.id}`;
2256
+ return /* @__PURE__ */ React.createElement(ErrorPanel, { title, error, defaultExpanded: true }, /* @__PURE__ */ React.createElement(Button$1, { variant: "outlined", onClick: resetError }, "Retry"));
2257
+ }
2258
+ }
2259
+ });
2260
+
2261
+ const InternalAppContext = createContext(void 0);
2262
+
2263
+ getOrCreateGlobalSingleton(
2264
+ "core-plugin-api:analytics-tracker-events",
2265
+ () => ({
2266
+ mostRecentGatheredNavigation: void 0,
2267
+ mostRecentRoutableExtensionRender: void 0,
2268
+ beforeUnloadRegistered: false
2269
+ })
2270
+ );
2271
+
2272
+ createApiRef({ id: "core.app-tree" });
2273
+
2274
+ createApiRef({
2275
+ id: "core.components"
2276
+ });
2277
+
2278
+ createApiRef({
2279
+ id: "core.analytics"
2280
+ });
2281
+
2282
+ function createExtensionDataRef(id) {
2283
+ return {
2284
+ id,
2285
+ $$type: "@backstage/ExtensionDataRef",
2286
+ config: {},
2287
+ optional() {
2288
+ return { ...this, config: { ...this.config, optional: true } };
2289
+ }
2290
+ };
2291
+ }
2292
+
2293
+ const signInPageComponentDataRef = createExtensionDataRef("core.signInPage");
2294
+
2295
+ const getExtensionContext = (pathname, routes) => {
2296
+ var _a, _b;
2297
+ try {
2298
+ const matches = matchRoutes(routes, { pathname });
2299
+ const routeMatch = matches == null ? void 0 : matches.filter((match) => {
2300
+ var _a2;
2301
+ return ((_a2 = match == null ? void 0 : match.route.routeRefs) == null ? void 0 : _a2.size) > 0;
2302
+ }).pop();
2303
+ const routeObject = routeMatch == null ? void 0 : routeMatch.route;
2304
+ if (!routeObject) {
2305
+ return void 0;
2306
+ }
2307
+ if (routeObject.path === "" && pathname !== "/") {
2308
+ return void 0;
2309
+ }
2310
+ const params = Object.entries(
2311
+ (routeMatch == null ? void 0 : routeMatch.params) || {}
2312
+ ).reduce((acc, [key, value]) => {
2313
+ if (value !== void 0 && key !== "*") {
2314
+ acc[key] = value;
2315
+ }
2316
+ return acc;
2317
+ }, {});
2318
+ const plugin = (_a = routeObject.appNode) == null ? void 0 : _a.spec.source;
2319
+ const extension = (_b = routeObject.appNode) == null ? void 0 : _b.spec.extension;
2320
+ return {
2321
+ params,
2322
+ pluginId: (plugin == null ? void 0 : plugin.id) || "root",
2323
+ extensionId: (extension == null ? void 0 : extension.id) || "App"
2324
+ };
2325
+ } catch {
2326
+ return void 0;
2327
+ }
2328
+ };
2329
+ const TrackNavigation = ({
2330
+ pathname,
2331
+ search,
2332
+ hash,
2333
+ attributes
2334
+ }) => {
2335
+ const analytics = useAnalytics();
2336
+ useEffect(() => {
2337
+ analytics.captureEvent("navigate", `${pathname}${search}${hash}`, {
2338
+ attributes
2339
+ });
2340
+ }, [analytics, pathname, search, hash, attributes]);
2341
+ return null;
2342
+ };
2343
+ const RouteTracker = ({
2344
+ routeObjects
2345
+ }) => {
2346
+ const { pathname, search, hash } = useLocation();
2347
+ const { params, ...attributes } = getExtensionContext(
2348
+ pathname,
2349
+ routeObjects
2350
+ ) || { params: {} };
2351
+ return /* @__PURE__ */ React.createElement(AnalyticsContext, { attributes }, /* @__PURE__ */ React.createElement(
2352
+ TrackNavigation,
2353
+ {
2354
+ pathname,
2355
+ search,
2356
+ hash,
2357
+ attributes: params
2358
+ }
2359
+ ));
2360
+ };
2361
+
2362
+ const CoreRouter = createExtension({
2363
+ namespace: "core",
2364
+ name: "router",
2365
+ attachTo: { id: "core", input: "root" },
2366
+ inputs: {
2367
+ signInPage: createExtensionInput(
2368
+ {
2369
+ component: signInPageComponentDataRef
2370
+ },
2371
+ { singleton: true, optional: true }
2372
+ ),
2373
+ children: createExtensionInput(
2374
+ {
2375
+ element: coreExtensionData.reactElement
2376
+ },
2377
+ { singleton: true }
2378
+ )
2379
+ },
2380
+ output: {
2381
+ element: coreExtensionData.reactElement
2382
+ },
2383
+ factory({ inputs }) {
2384
+ var _a;
2385
+ return {
2386
+ element: /* @__PURE__ */ React.createElement(AppRouter, { SignInPageComponent: (_a = inputs.signInPage) == null ? void 0 : _a.output.component }, inputs.children.output.element)
2387
+ };
2388
+ }
2389
+ });
2390
+ function getBasePath(configApi) {
2391
+ var _a;
2392
+ let { pathname } = new URL(
2393
+ (_a = configApi.getOptionalString("app.baseUrl")) != null ? _a : "/",
2394
+ "http://sample.dev"
2395
+ // baseUrl can be specified as just a path
2396
+ );
2397
+ pathname = pathname.replace(/\/*$/, "");
2398
+ return pathname;
2399
+ }
2400
+ function SignInPageWrapper({
2401
+ component: Component,
2402
+ appIdentityProxy,
2403
+ children
2404
+ }) {
2405
+ const [identityApi, setIdentityApi] = useState();
2406
+ const configApi = useApi(configApiRef);
2407
+ const basePath = getBasePath(configApi);
2408
+ if (!identityApi) {
2409
+ return /* @__PURE__ */ React.createElement(Component, { onSignInSuccess: setIdentityApi });
2410
+ }
2411
+ appIdentityProxy.setTarget(identityApi, {
2412
+ signOutTargetUrl: basePath || "/"
2413
+ });
2414
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
2415
+ }
2416
+ function AppRouter(props) {
2417
+ const { children, SignInPageComponent } = props;
2418
+ const configApi = useApi(configApiRef);
2419
+ const basePath = getBasePath(configApi);
2420
+ const internalAppContext = useContext(InternalAppContext);
2421
+ if (!internalAppContext) {
2422
+ throw new Error("AppRouter must be rendered within the AppProvider");
2423
+ }
2424
+ const { routeObjects, appIdentityProxy } = internalAppContext;
2425
+ if (!SignInPageComponent) {
2426
+ appIdentityProxy.setTarget(
2427
+ {
2428
+ getUserId: () => "guest",
2429
+ getIdToken: async () => void 0,
2430
+ getProfile: () => ({
2431
+ email: "guest@example.com",
2432
+ displayName: "Guest"
2433
+ }),
2434
+ getProfileInfo: async () => ({
2435
+ email: "guest@example.com",
2436
+ displayName: "Guest"
2437
+ }),
2438
+ getBackstageIdentity: async () => ({
2439
+ type: "user",
2440
+ userEntityRef: "user:default/guest",
2441
+ ownershipEntityRefs: ["user:default/guest"]
2442
+ }),
2443
+ getCredentials: async () => ({}),
2444
+ signOut: async () => {
2445
+ }
2446
+ },
2447
+ { signOutTargetUrl: basePath || "/" }
2448
+ );
2449
+ return /* @__PURE__ */ React.createElement(BrowserRouter, { basename: basePath }, /* @__PURE__ */ React.createElement(RouteTracker, { routeObjects }), children);
2450
+ }
2451
+ return /* @__PURE__ */ React.createElement(BrowserRouter, { basename: basePath }, /* @__PURE__ */ React.createElement(RouteTracker, { routeObjects }), /* @__PURE__ */ React.createElement(
2452
+ SignInPageWrapper,
2453
+ {
2454
+ component: SignInPageComponent,
2455
+ appIdentityProxy
2456
+ },
2457
+ children
2458
+ ));
2459
+ }
2460
+
2461
+ var __accessCheck = (obj, member, msg) => {
2462
+ if (!member.has(obj))
2463
+ throw TypeError("Cannot " + msg);
2464
+ };
2465
+ var __privateGet = (obj, member, getter) => {
2466
+ __accessCheck(obj, member, "read from private field");
2467
+ return getter ? getter.call(obj) : member.get(obj);
2468
+ };
2469
+ var __privateAdd = (obj, member, value) => {
2470
+ if (member.has(obj))
2471
+ throw TypeError("Cannot add the same private member more than once");
2472
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2473
+ };
2474
+ var __privateSet = (obj, member, value, setter) => {
2475
+ __accessCheck(obj, member, "write to private field");
2476
+ setter ? setter.call(obj, value) : member.set(obj, value);
2477
+ return value;
2478
+ };
2479
+ var _components;
2480
+ class DefaultComponentsApi {
2481
+ constructor(components) {
2482
+ __privateAdd(this, _components, void 0);
2483
+ __privateSet(this, _components, components);
2484
+ }
2485
+ getComponent(ref) {
2486
+ const impl = __privateGet(this, _components).get(ref);
2487
+ if (!impl) {
2488
+ throw new Error(`No implementation found for component ref ${ref}`);
2489
+ }
2490
+ return impl;
2491
+ }
2492
+ }
2493
+ _components = new WeakMap();
2494
+
2216
2495
  const builtinExtensions = [
2217
2496
  Core,
2497
+ CoreRouter,
2218
2498
  CoreRoutes,
2219
2499
  CoreNav,
2220
2500
  CoreLayout,
2501
+ DefaultProgressComponent,
2502
+ DefaultErrorBoundaryComponent,
2503
+ DefaultNotFoundErrorPageComponent,
2221
2504
  LightTheme,
2222
2505
  DarkTheme
2223
- ];
2506
+ ].map((def) => resolveExtensionDefinition(def));
2224
2507
  function createExtensionTree(options) {
2225
2508
  const features = getAvailableFeatures(options.config);
2226
2509
  const tree = createAppTree({
@@ -2246,7 +2529,7 @@ function createExtensionTree(options) {
2246
2529
  return (_c = (_b = (_a = tree.nodes.get(id)) == null ? void 0 : _a.edges.attachments.get(inputName)) == null ? void 0 : _b.map(convertNode).filter((node) => Boolean(node))) != null ? _c : [];
2247
2530
  },
2248
2531
  getRootRoutes() {
2249
- return this.getExtensionAttachments("core.routes", "routes").map((node) => {
2532
+ return this.getExtensionAttachments("core/routes", "routes").map((node) => {
2250
2533
  const path = node.getData(coreExtensionData.routePath);
2251
2534
  const element = node.getData(coreExtensionData.reactElement);
2252
2535
  const routeRef = node.getData(coreExtensionData.routeRef);
@@ -2265,7 +2548,7 @@ function createExtensionTree(options) {
2265
2548
  const location = useRouteRef(props.routeRef);
2266
2549
  return /* @__PURE__ */ React.createElement(SidebarItem, { icon: props.icon, to: location(), text: props.title });
2267
2550
  };
2268
- return this.getExtensionAttachments("core.nav", "items").map((node, index) => {
2551
+ return this.getExtensionAttachments("core/nav", "items").map((node, index) => {
2269
2552
  const target = node.getData(coreExtensionData.navTarget);
2270
2553
  if (!target) {
2271
2554
  return null;
@@ -2334,12 +2617,26 @@ function createSpecializedApp(options) {
2334
2617
  builtinExtensions,
2335
2618
  config
2336
2619
  });
2337
- const appContext = createLegacyAppContext(
2338
- features.filter(
2339
- (f) => f.$$type === "@backstage/BackstagePlugin"
2340
- )
2341
- );
2342
- const apiHolder = createApiHolder(tree, config);
2620
+ const appIdentityProxy = new AppIdentityProxy();
2621
+ const apiHolder = createApiHolder(tree, config, appIdentityProxy);
2622
+ const featureFlagApi = apiHolder.get(featureFlagsApiRef);
2623
+ if (featureFlagApi) {
2624
+ for (const feature of features) {
2625
+ if (feature.$$type === "@backstage/BackstagePlugin") {
2626
+ toInternalBackstagePlugin(feature).featureFlags.forEach(
2627
+ (flag) => featureFlagApi.registerFlag({
2628
+ name: flag.name,
2629
+ pluginId: feature.id
2630
+ })
2631
+ );
2632
+ }
2633
+ if (feature.$$type === "@backstage/ExtensionOverrides") {
2634
+ toInternalExtensionOverrides(feature).featureFlags.forEach(
2635
+ (flag) => featureFlagApi.registerFlag({ name: flag.name, pluginId: "" })
2636
+ );
2637
+ }
2638
+ }
2639
+ }
2343
2640
  const routeInfo = extractRouteInfoFromAppNode(tree.root);
2344
2641
  const routeBindings = resolveRouteBindings(
2345
2642
  options == null ? void 0 : options.bindRoutes,
@@ -2347,31 +2644,21 @@ function createSpecializedApp(options) {
2347
2644
  collectRouteIds(features)
2348
2645
  );
2349
2646
  const rootEl = tree.root.instance.getData(coreExtensionData.reactElement);
2350
- const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: apiHolder }, /* @__PURE__ */ React.createElement(AppContextProvider, { appContext }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, { ...routeInfo, routeBindings }, /* @__PURE__ */ React.createElement(BrowserRouter, null, rootEl)))));
2647
+ const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: apiHolder }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, { ...routeInfo, routeBindings }, /* @__PURE__ */ React.createElement(
2648
+ InternalAppContext.Provider,
2649
+ {
2650
+ value: { appIdentityProxy, routeObjects: routeInfo.routeObjects }
2651
+ },
2652
+ rootEl
2653
+ ))));
2351
2654
  return {
2352
2655
  createRoot() {
2353
2656
  return /* @__PURE__ */ React.createElement(App, null);
2354
2657
  }
2355
2658
  };
2356
2659
  }
2357
- function createLegacyAppContext(plugins) {
2358
- return {
2359
- getPlugins() {
2360
- return plugins.map(toLegacyPlugin);
2361
- },
2362
- getSystemIcon(key) {
2363
- return key in icons ? icons[key] : void 0;
2364
- },
2365
- getSystemIcons() {
2366
- return icons;
2367
- },
2368
- getComponents() {
2369
- return components;
2370
- }
2371
- };
2372
- }
2373
- function createApiHolder(tree, configApi) {
2374
- var _a, _b, _c, _d;
2660
+ function createApiHolder(tree, configApi, appIdentityProxy) {
2661
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2375
2662
  const factoryRegistry = new ApiFactoryRegistry();
2376
2663
  const pluginApis = (_b = (_a = tree.root.edges.attachments.get("apis")) == null ? void 0 : _a.map((e) => {
2377
2664
  var _a2;
@@ -2381,6 +2668,14 @@ function createApiHolder(tree, configApi) {
2381
2668
  var _a2;
2382
2669
  return (_a2 = e.instance) == null ? void 0 : _a2.getData(coreExtensionData.theme);
2383
2670
  }).filter((x) => !!x)) != null ? _d : [];
2671
+ const translationResources = (_f = (_e = tree.root.edges.attachments.get("translations")) == null ? void 0 : _e.map(
2672
+ (e) => {
2673
+ var _a2;
2674
+ return (_a2 = e.instance) == null ? void 0 : _a2.getData(createTranslationExtension.translationDataRef);
2675
+ }
2676
+ ).filter(
2677
+ (x) => !!x
2678
+ )) != null ? _f : [];
2384
2679
  for (const factory of [...apis, ...pluginApis]) {
2385
2680
  factoryRegistry.register("default", factory);
2386
2681
  }
@@ -2392,33 +2687,7 @@ function createApiHolder(tree, configApi) {
2392
2687
  factoryRegistry.register("static", {
2393
2688
  api: identityApiRef,
2394
2689
  deps: {},
2395
- factory: () => {
2396
- const appIdentityProxy = new AppIdentityProxy();
2397
- appIdentityProxy.setTarget(
2398
- {
2399
- getUserId: () => "guest",
2400
- getIdToken: async () => void 0,
2401
- getProfile: () => ({
2402
- email: "guest@example.com",
2403
- displayName: "Guest"
2404
- }),
2405
- getProfileInfo: async () => ({
2406
- email: "guest@example.com",
2407
- displayName: "Guest"
2408
- }),
2409
- getBackstageIdentity: async () => ({
2410
- type: "user",
2411
- userEntityRef: "user:default/guest",
2412
- ownershipEntityRefs: ["user:default/guest"]
2413
- }),
2414
- getCredentials: async () => ({}),
2415
- signOut: async () => {
2416
- }
2417
- },
2418
- { signOutTargetUrl: "/" }
2419
- );
2420
- return appIdentityProxy;
2421
- }
2690
+ factory: () => appIdentityProxy
2422
2691
  });
2423
2692
  factoryRegistry.register("static", {
2424
2693
  api: appTreeApiRef,
@@ -2427,6 +2696,19 @@ function createApiHolder(tree, configApi) {
2427
2696
  getTree: () => ({ tree })
2428
2697
  })
2429
2698
  });
2699
+ const componentsExtensions = (_h = (_g = tree.root.edges.attachments.get("components")) == null ? void 0 : _g.map((e) => {
2700
+ var _a2;
2701
+ return (_a2 = e.instance) == null ? void 0 : _a2.getData(coreExtensionData.component);
2702
+ }).filter((x) => !!x)) != null ? _h : [];
2703
+ const componentsMap = componentsExtensions.reduce(
2704
+ (components, component) => component ? components.set(component.ref, component == null ? void 0 : component.impl) : components,
2705
+ /* @__PURE__ */ new Map()
2706
+ );
2707
+ factoryRegistry.register("static", {
2708
+ api: componentsApiRef,
2709
+ deps: {},
2710
+ factory: () => new DefaultComponentsApi(componentsMap)
2711
+ });
2430
2712
  factoryRegistry.register("static", {
2431
2713
  api: appThemeApiRef,
2432
2714
  deps: {},
@@ -2438,13 +2720,6 @@ function createApiHolder(tree, configApi) {
2438
2720
  deps: {},
2439
2721
  factory: () => AppLanguageSelector.createWithStorage()
2440
2722
  });
2441
- factoryRegistry.register("default", {
2442
- api: translationApiRef,
2443
- deps: { languageApi: appLanguageApiRef },
2444
- factory: ({ languageApi }) => I18nextTranslationApi.create({
2445
- languageApi
2446
- })
2447
- });
2448
2723
  factoryRegistry.register("static", {
2449
2724
  api: configApiRef,
2450
2725
  deps: {},
@@ -2455,11 +2730,12 @@ function createApiHolder(tree, configApi) {
2455
2730
  deps: {},
2456
2731
  factory: () => AppLanguageSelector.createWithStorage()
2457
2732
  });
2458
- factoryRegistry.register("default", {
2733
+ factoryRegistry.register("static", {
2459
2734
  api: translationApiRef,
2460
2735
  deps: { languageApi: appLanguageApiRef },
2461
2736
  factory: ({ languageApi }) => I18nextTranslationApi.create({
2462
- languageApi
2737
+ languageApi,
2738
+ resources: translationResources
2463
2739
  })
2464
2740
  });
2465
2741
  for (const factory of apis) {