@backstage/core-app-api 0.6.0 → 1.0.1-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,38 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 1.0.1-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 24254fd433: build(deps): bump `@testing-library/user-event` from 13.5.0 to 14.0.0
8
+ - 3ff2bfb66e: Refactored the route collection logic to prepare for future changes and avoid duplicate element tree traversal for the analytics context.
9
+ - 230ad0826f: Bump to using `@types/node` v16
10
+ - Updated dependencies
11
+ - @backstage/core-plugin-api@1.0.1-next.0
12
+
13
+ ## 1.0.1-next.0
14
+
15
+ ### Patch Changes
16
+
17
+ - a7bb762dab: fixed empty body issue for POST requests using FetchAPI with 'plugin://' prefix
18
+ - c47509e1a0: Implemented changes suggested by Deepsource.io including multiple double non-null assertion operators and unexpected awaits for non-promise values.
19
+
20
+ ## 1.0.0
21
+
22
+ ### Major Changes
23
+
24
+ - b58c70c223: This package has been promoted to v1.0! To understand how this change affects the package, please check out our [versioning policy](https://backstage.io/docs/overview/versioning-policy).
25
+
26
+ ### Patch Changes
27
+
28
+ - a422d7ce5e: chore(deps): bump `@testing-library/react` from 11.2.6 to 12.1.3
29
+ - f24ef7864e: Minor typo fixes
30
+ - Updated dependencies
31
+ - @backstage/core-plugin-api@1.0.0
32
+ - @backstage/version-bridge@1.0.0
33
+ - @backstage/config@1.0.0
34
+ - @backstage/types@1.0.0
35
+
3
36
  ## 0.6.0
4
37
 
5
38
  ### Minor Changes
package/README.md CHANGED
@@ -6,9 +6,8 @@ This package provides the core API used by Backstage apps.
6
6
 
7
7
  Install the package via Yarn:
8
8
 
9
- ```sh
10
- cd packages/app
11
- yarn add @backstage/core-app-api
9
+ ```bash
10
+ yarn add --cwd packages/app @backstage/core-app-api
12
11
  ```
13
12
 
14
13
  ## Documentation
package/dist/index.d.ts CHANGED
@@ -648,7 +648,7 @@ declare type AppOptions = {
648
648
  apis?: Iterable<AnyApiFactory>;
649
649
  /**
650
650
  * A collection of ApiFactories to register in the application as default APIs.
651
- * Theses APIs can not be overridden by plugin factories, but can be overridden
651
+ * These APIs cannot be overridden by plugin factories, but can be overridden
652
652
  * by plugin APIs provided through the
653
653
  * A collection of ApiFactories to register in the application to either
654
654
  * add new ones, or override factories provided by default or by plugins.
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useContext, Children, isValidElement, useMemo, useEffect, useState } from 'react';
1
+ import React, { useContext, Children, isValidElement, useEffect, useMemo, useState, createContext } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { createVersionedContext, createVersionedValueMap, getOrCreateGlobalSingleton } from '@backstage/version-bridge';
4
4
  import ObservableImpl from 'zen-observable';
@@ -1402,7 +1402,7 @@ class PluginProtocolResolverFetchMiddleware {
1402
1402
  base = `${baseUrl.protocol}//${authority}${baseUrl.host}${baseUrl.pathname}`;
1403
1403
  }
1404
1404
  const target = `${join(base, pathname)}${search}${hash}`;
1405
- return next(target, request);
1405
+ return next(target, typeof input === "string" ? init : input);
1406
1406
  };
1407
1407
  }
1408
1408
  }
@@ -1671,88 +1671,64 @@ const FeatureFlagged = (props) => {
1671
1671
  };
1672
1672
  attachComponentData(FeatureFlagged, "core.featureFlagged", true);
1673
1673
 
1674
- function getMountPoint(node) {
1675
- var _a;
1676
- const element = (_a = node.props) == null ? void 0 : _a.element;
1677
- let routeRef = getComponentData(node, "core.mountPoint");
1678
- if (!routeRef && isValidElement(element)) {
1679
- routeRef = getComponentData(element, "core.mountPoint");
1680
- }
1681
- return routeRef;
1682
- }
1683
- const routePathCollector = createCollector(() => /* @__PURE__ */ new Map(), (acc, node, parent, ctxPath) => {
1684
- var _a, _b;
1685
- let currentCtxPath = ctxPath;
1674
+ const MATCH_ALL_ROUTE = {
1675
+ caseSensitive: false,
1676
+ path: "/*",
1677
+ element: "match-all",
1678
+ routeRefs: /* @__PURE__ */ new Set()
1679
+ };
1680
+ const routingV1Collector = createCollector(() => ({
1681
+ paths: /* @__PURE__ */ new Map(),
1682
+ parents: /* @__PURE__ */ new Map(),
1683
+ objects: new Array()
1684
+ }), (acc, node, parent, ctx) => {
1685
+ var _a, _b, _c, _d, _e;
1686
1686
  if ((parent == null ? void 0 : parent.props.element) === node) {
1687
- return currentCtxPath;
1687
+ return ctx;
1688
1688
  }
1689
+ let currentObj = ctx == null ? void 0 : ctx.obj;
1690
+ let currentParentRouteRef = ctx == null ? void 0 : ctx.routeRef;
1691
+ let sticky = ctx == null ? void 0 : ctx.sticky;
1692
+ const path = (_a = node.props) == null ? void 0 : _a.path;
1693
+ const parentChildren = (_b = currentObj == null ? void 0 : currentObj.children) != null ? _b : acc.objects;
1694
+ const caseSensitive = Boolean((_c = node.props) == null ? void 0 : _c.caseSensitive);
1695
+ let currentCtxPath = ctx == null ? void 0 : ctx.path;
1689
1696
  if (getComponentData(node, "core.gatherMountPoints")) {
1690
- const path = (_a = node.props) == null ? void 0 : _a.path;
1691
1697
  if (!path) {
1692
1698
  throw new Error("Mount point gatherer must have a path");
1693
1699
  }
1694
1700
  currentCtxPath = path;
1695
1701
  }
1696
- const routeRef = getMountPoint(node);
1702
+ const element = (_d = node.props) == null ? void 0 : _d.element;
1703
+ let routeRef = getComponentData(node, "core.mountPoint");
1704
+ if (!routeRef && isValidElement(element)) {
1705
+ routeRef = getComponentData(element, "core.mountPoint");
1706
+ }
1697
1707
  if (routeRef) {
1698
- let path = (_b = node.props) == null ? void 0 : _b.path;
1708
+ let routePath = path;
1699
1709
  if (currentCtxPath) {
1700
- if (path) {
1710
+ if (routePath) {
1701
1711
  currentCtxPath = void 0;
1702
1712
  } else {
1703
- path = currentCtxPath;
1713
+ routePath = currentCtxPath;
1704
1714
  }
1705
1715
  }
1706
- if (!path) {
1716
+ if (!routePath) {
1707
1717
  throw new Error("Mounted routable extension must have a path");
1708
1718
  }
1709
- acc.set(routeRef, path);
1710
- }
1711
- return currentCtxPath;
1712
- });
1713
- const routeParentCollector = createCollector(() => /* @__PURE__ */ new Map(), (acc, node, parent, parentRouteRef) => {
1714
- var _a;
1715
- if ((parent == null ? void 0 : parent.props.element) === node) {
1716
- return parentRouteRef;
1717
- }
1718
- let nextParent = parentRouteRef;
1719
- const routeRef = getMountPoint(node);
1720
- if (routeRef) {
1721
- if (parentRouteRef && "sticky" in parentRouteRef) {
1722
- acc.set(routeRef, parentRouteRef.sticky);
1723
- if ((_a = node.props) == null ? void 0 : _a.path) {
1724
- nextParent = routeRef;
1725
- } else {
1726
- nextParent = parentRouteRef;
1719
+ acc.paths.set(routeRef, routePath);
1720
+ if (currentParentRouteRef && sticky) {
1721
+ acc.parents.set(routeRef, currentParentRouteRef);
1722
+ if (path) {
1723
+ currentParentRouteRef = routeRef;
1724
+ sticky = false;
1727
1725
  }
1728
1726
  } else {
1729
- acc.set(routeRef, parentRouteRef);
1730
- nextParent = routeRef;
1727
+ acc.parents.set(routeRef, currentParentRouteRef);
1728
+ currentParentRouteRef = routeRef;
1731
1729
  }
1732
- }
1733
- if (getComponentData(node, "core.gatherMountPoints")) {
1734
- return { sticky: nextParent };
1735
- }
1736
- return nextParent;
1737
- });
1738
- const MATCH_ALL_ROUTE = {
1739
- caseSensitive: false,
1740
- path: "/*",
1741
- element: "match-all",
1742
- routeRefs: /* @__PURE__ */ new Set()
1743
- };
1744
- const routeObjectCollector = createCollector(() => Array(), (acc, node, parent, parentObj) => {
1745
- var _a, _b, _c;
1746
- const parentChildren = (_a = parentObj == null ? void 0 : parentObj.children) != null ? _a : acc;
1747
- if ((parent == null ? void 0 : parent.props.element) === node) {
1748
- return parentObj;
1749
- }
1750
- const path = (_b = node.props) == null ? void 0 : _b.path;
1751
- const caseSensitive = Boolean((_c = node.props) == null ? void 0 : _c.caseSensitive);
1752
- const routeRef = getMountPoint(node);
1753
- if (routeRef) {
1754
1730
  if (path) {
1755
- const newObject = {
1731
+ currentObj = {
1756
1732
  caseSensitive,
1757
1733
  path,
1758
1734
  element: "mounted",
@@ -1760,28 +1736,37 @@ const routeObjectCollector = createCollector(() => Array(), (acc, node, parent,
1760
1736
  children: [MATCH_ALL_ROUTE],
1761
1737
  plugin: getComponentData(node.props.element, "core.plugin")
1762
1738
  };
1763
- parentChildren.push(newObject);
1764
- return newObject;
1739
+ parentChildren.push(currentObj);
1740
+ } else {
1741
+ currentObj == null ? void 0 : currentObj.routeRefs.add(routeRef);
1765
1742
  }
1766
- parentObj == null ? void 0 : parentObj.routeRefs.add(routeRef);
1743
+ }
1744
+ if (getComponentData(node, "core.gatherMountPoints")) {
1745
+ sticky = true;
1767
1746
  }
1768
1747
  const isGatherer = getComponentData(node, "core.gatherMountPoints");
1769
1748
  if (isGatherer) {
1770
1749
  if (!path) {
1771
1750
  throw new Error("Mount point gatherer must have a path");
1772
1751
  }
1773
- const newObject = {
1774
- caseSensitive,
1775
- path,
1776
- element: "gathered",
1777
- routeRefs: /* @__PURE__ */ new Set(),
1778
- children: [MATCH_ALL_ROUTE],
1779
- plugin: parentObj == null ? void 0 : parentObj.plugin
1780
- };
1781
- parentChildren.push(newObject);
1782
- return newObject;
1752
+ if (!routeRef) {
1753
+ currentObj = {
1754
+ caseSensitive,
1755
+ path,
1756
+ element: "gathered",
1757
+ routeRefs: /* @__PURE__ */ new Set(),
1758
+ children: [MATCH_ALL_ROUTE],
1759
+ plugin: (_e = ctx == null ? void 0 : ctx.obj) == null ? void 0 : _e.plugin
1760
+ };
1761
+ parentChildren.push(currentObj);
1762
+ }
1783
1763
  }
1784
- return parentObj;
1764
+ return {
1765
+ obj: currentObj,
1766
+ path: currentCtxPath,
1767
+ routeRef: currentParentRouteRef,
1768
+ sticky
1769
+ };
1785
1770
  });
1786
1771
  const featureFlagCollector = createCollector(() => /* @__PURE__ */ new Set(), (acc, node) => {
1787
1772
  if (node.type === FeatureFlagged) {
@@ -1964,17 +1949,10 @@ const TrackNavigation = ({
1964
1949
  }, [analytics, pathname, search, hash]);
1965
1950
  return null;
1966
1951
  };
1967
- const RouteTracker = ({ tree }) => {
1952
+ const RouteTracker = ({
1953
+ routeObjects
1954
+ }) => {
1968
1955
  const { pathname, search, hash } = useLocation();
1969
- const { routeObjects } = useMemo(() => {
1970
- return traverseElementTree({
1971
- root: tree,
1972
- discoverers: [childDiscoverer, routeElementDiscoverer],
1973
- collectors: {
1974
- routeObjects: routeObjectCollector
1975
- }
1976
- });
1977
- }, [tree]);
1978
1956
  return /* @__PURE__ */ React.createElement(AnalyticsContext, {
1979
1957
  attributes: getExtensionContext(pathname, routeObjects)
1980
1958
  }, /* @__PURE__ */ React.createElement(TrackNavigation, {
@@ -2239,6 +2217,7 @@ function resolveRouteBindings(bindRoutes) {
2239
2217
  return result;
2240
2218
  }
2241
2219
 
2220
+ const InternalAppContext = createContext({ routeObjects: [] });
2242
2221
  function getBasePath(configApi) {
2243
2222
  var _a;
2244
2223
  let { pathname } = new URL((_a = configApi.getOptionalString("app.baseUrl")) != null ? _a : "/", "http://dummy.dev");
@@ -2313,20 +2292,12 @@ class AppManager {
2313
2292
  let routesHaveBeenValidated = false;
2314
2293
  const Provider = ({ children }) => {
2315
2294
  const appThemeApi = useMemo(() => AppThemeSelector.createWithStorage(this.themes), []);
2316
- const {
2317
- routePaths,
2318
- routeParents,
2319
- routeObjects,
2320
- featureFlags,
2321
- routeBindings
2322
- } = useMemo(() => {
2295
+ const { routing, featureFlags, routeBindings } = useMemo(() => {
2323
2296
  const result = traverseElementTree({
2324
2297
  root: children,
2325
2298
  discoverers: [childDiscoverer, routeElementDiscoverer],
2326
2299
  collectors: {
2327
- routePaths: routePathCollector,
2328
- routeParents: routeParentCollector,
2329
- routeObjects: routeObjectCollector,
2300
+ routing: routingV1Collector,
2330
2301
  collectedPlugins: pluginCollector,
2331
2302
  featureFlags: featureFlagCollector
2332
2303
  }
@@ -2341,7 +2312,7 @@ class AppManager {
2341
2312
  }, [children]);
2342
2313
  if (!routesHaveBeenValidated) {
2343
2314
  routesHaveBeenValidated = true;
2344
- validateRouteParameters(routePaths, routeParents);
2315
+ validateRouteParameters(routing.paths, routing.parents);
2345
2316
  validateRouteBindings(routeBindings, this.plugins);
2346
2317
  }
2347
2318
  const loadedConfig = useConfigLoader(this.configLoader, this.components, appThemeApi);
@@ -2386,12 +2357,14 @@ class AppManager {
2386
2357
  }, /* @__PURE__ */ React.createElement(AppContextProvider, {
2387
2358
  appContext
2388
2359
  }, /* @__PURE__ */ React.createElement(ThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, {
2389
- routePaths,
2390
- routeParents,
2391
- routeObjects,
2360
+ routePaths: routing.paths,
2361
+ routeParents: routing.parents,
2362
+ routeObjects: routing.objects,
2392
2363
  routeBindings,
2393
2364
  basePath: getBasePath(loadedConfig.api)
2394
- }, children))));
2365
+ }, /* @__PURE__ */ React.createElement(InternalAppContext.Provider, {
2366
+ value: { routeObjects: routing.objects }
2367
+ }, children)))));
2395
2368
  };
2396
2369
  return Provider;
2397
2370
  }
@@ -2413,6 +2386,7 @@ class AppManager {
2413
2386
  const AppRouter = ({ children }) => {
2414
2387
  const configApi = useApi(configApiRef);
2415
2388
  const mountPath = `${getBasePath(configApi)}/*`;
2389
+ const { routeObjects } = useContext(InternalAppContext);
2416
2390
  if (!SignInPageComponent) {
2417
2391
  this.appIdentityProxy.setTarget({
2418
2392
  getUserId: () => "guest",
@@ -2435,14 +2409,14 @@ class AppManager {
2435
2409
  }
2436
2410
  });
2437
2411
  return /* @__PURE__ */ React.createElement(RouterComponent, null, /* @__PURE__ */ React.createElement(RouteTracker, {
2438
- tree: children
2412
+ routeObjects
2439
2413
  }), /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {
2440
2414
  path: mountPath,
2441
2415
  element: /* @__PURE__ */ React.createElement(React.Fragment, null, children)
2442
2416
  })));
2443
2417
  }
2444
2418
  return /* @__PURE__ */ React.createElement(RouterComponent, null, /* @__PURE__ */ React.createElement(RouteTracker, {
2445
- tree: children
2419
+ routeObjects
2446
2420
  }), /* @__PURE__ */ React.createElement(SignInPageWrapper, {
2447
2421
  component: SignInPageComponent
2448
2422
  }, /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {