@backstage/plugin-app 0.1.2 → 0.1.4-next.0

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,19 @@
1
1
  # @backstage/plugin-app
2
2
 
3
+ ## 0.1.4-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - e5fa018: The OAuth 2 client implementations will now attempt to refresh the session when the existing session doesn't have the required scopes. The previous behavior was to only try to refresh the session of it was missing, and otherwise directly request a new session. This fixes an issue where some auth providers will not return access tokens with certain scopes unless explicitly requested, leading to an auth popup even if the underlying session already had been granted the requested scopes.
8
+ - 5f04976: Fixed a bug that caused missing code in published packages.
9
+ - Updated dependencies
10
+ - @backstage/frontend-plugin-api@0.9.3-next.0
11
+ - @backstage/theme@0.6.3-next.0
12
+ - @backstage/core-components@0.16.2-next.0
13
+ - @backstage/core-plugin-api@1.10.1
14
+ - @backstage/integration-react@1.2.2-next.0
15
+ - @backstage/plugin-permission-react@0.4.28
16
+
3
17
  ## 0.1.2
4
18
 
5
19
  ### Patch Changes
@@ -2,7 +2,7 @@ import GithubAuth from './packages/core-app-api/src/apis/implementations/auth/gi
2
2
  import GitlabAuth from './packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.esm.js';
3
3
  import GoogleAuth from './packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.esm.js';
4
4
  import 'zen-observable';
5
- import { createApiFactory, configApiRef, discoveryApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, identityApiRef, fetchApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, vmwareCloudAuthApiRef } from '@backstage/core-plugin-api';
5
+ import { createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, vmwareCloudAuthApiRef } from '@backstage/core-plugin-api';
6
6
  import OktaAuth from './packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.esm.js';
7
7
  import './packages/core-app-api/src/apis/implementations/auth/saml/types.esm.js';
8
8
  import MicrosoftAuth from './packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.esm.js';
@@ -23,8 +23,8 @@ import { FetchMiddlewares } from './packages/core-app-api/src/apis/implementatio
23
23
  import { OAuthRequestManager } from './packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.esm.js';
24
24
  import { WebStorage } from './packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.esm.js';
25
25
  import { ApiBlueprint } from '@backstage/frontend-plugin-api';
26
- import { ScmAuth, ScmIntegrationsApi, scmIntegrationsApiRef } from '@backstage/integration-react';
27
- import { IdentityPermissionApi, permissionApiRef } from '@backstage/plugin-permission-react';
26
+ import { ScmAuth, scmIntegrationsApiRef, ScmIntegrationsApi } from '@backstage/integration-react';
27
+ import { permissionApiRef, IdentityPermissionApi } from '@backstage/plugin-permission-react';
28
28
 
29
29
  const apis = [
30
30
  ApiBlueprint.make({
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { createExtension, coreExtensionData, ExtensionBoundary, createExtensionInput } from '@backstage/frontend-plugin-api';
2
+ import { createExtension, createExtensionInput, coreExtensionData, ExtensionBoundary } from '@backstage/frontend-plugin-api';
3
3
  import { ApiProvider } from '../packages/core-app-api/src/apis/system/ApiProvider.esm.js';
4
4
  import 'zen-observable';
5
5
  import '@backstage/core-plugin-api';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { createExtension, coreExtensionData, createExtensionInput } from '@backstage/frontend-plugin-api';
2
+ import { createExtension, createExtensionInput, coreExtensionData } from '@backstage/frontend-plugin-api';
3
3
  import { SidebarPage } from '@backstage/core-components';
4
4
 
5
5
  const AppLayout = createExtension({
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
- import { createExtension, coreExtensionData, NavLogoBlueprint, useRouteRef, NavItemBlueprint, createExtensionInput } from '@backstage/frontend-plugin-api';
2
+ import { createExtension, createExtensionInput, NavItemBlueprint, NavLogoBlueprint, coreExtensionData, useRouteRef } from '@backstage/frontend-plugin-api';
3
3
  import { makeStyles } from '@material-ui/core/styles';
4
- import { sidebarConfig, Sidebar, useSidebarOpenState, Link, SidebarDivider, SidebarItem } from '@backstage/core-components';
4
+ import { sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem } from '@backstage/core-components';
5
5
  import LogoIcon from '../packages/app/src/components/Root/LogoIcon.esm.js';
6
6
  import LogoFull from '../packages/app/src/components/Root/LogoFull.esm.js';
7
7
 
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react';
2
- import { createExtension, discoveryApiRef, errorApiRef, fetchApiRef, coreExtensionData, AppRootWrapperBlueprint, routeResolutionApiRef, RouterBlueprint, SignInPageBlueprint, createExtensionInput } from '@backstage/frontend-plugin-api';
2
+ import { createExtension, createExtensionInput, RouterBlueprint, SignInPageBlueprint, coreExtensionData, AppRootWrapperBlueprint, discoveryApiRef, errorApiRef, fetchApiRef, routeResolutionApiRef } from '@backstage/frontend-plugin-api';
3
3
  import { identityApiRef, useApi, configApiRef } from '@backstage/core-plugin-api';
4
4
  import { isProtectedApp } from '../packages/core-app-api/src/app/isProtectedApp.esm.js';
5
5
  import { BrowserRouter } from 'react-router-dom';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { createExtension, coreExtensionData, useComponentRef, coreComponentRefs, createExtensionInput } from '@backstage/frontend-plugin-api';
2
+ import { createExtension, createExtensionInput, coreExtensionData, useComponentRef, coreComponentRefs } from '@backstage/frontend-plugin-api';
3
3
  import { useRoutes } from 'react-router-dom';
4
4
 
5
5
  const AppRoutes = createExtension({
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { UnifiedThemeProvider, themes } from '@backstage/theme';
3
3
  import DarkIcon from '@material-ui/icons/Brightness2';
4
4
  import LightIcon from '@material-ui/icons/WbSunny';
5
- import { ApiBlueprint, createApiFactory, appThemeApiRef, ThemeBlueprint, createExtensionInput } from '@backstage/frontend-plugin-api';
5
+ import { ApiBlueprint, createExtensionInput, ThemeBlueprint, createApiFactory, appThemeApiRef } from '@backstage/frontend-plugin-api';
6
6
  import 'zen-observable';
7
7
  import '@backstage/core-plugin-api';
8
8
  import '../packages/core-app-api/src/apis/implementations/auth/saml/types.esm.js';
@@ -1,4 +1,4 @@
1
- import { ApiBlueprint, createApiFactory, componentsApiRef, createComponentExtension, createExtensionInput } from '@backstage/frontend-plugin-api';
1
+ import { ApiBlueprint, createExtensionInput, createComponentExtension, createApiFactory, componentsApiRef } from '@backstage/frontend-plugin-api';
2
2
  import { DefaultComponentsApi } from '../packages/frontend-app-api/src/apis/implementations/ComponentsApi/DefaultComponentsApi.esm.js';
3
3
 
4
4
  const ComponentsApi = ApiBlueprint.makeWithOverrides({
@@ -1,4 +1,4 @@
1
- import { ApiBlueprint, createApiFactory, iconsApiRef, IconBundleBlueprint, createExtensionInput } from '@backstage/frontend-plugin-api';
1
+ import { ApiBlueprint, createExtensionInput, IconBundleBlueprint, createApiFactory, iconsApiRef } from '@backstage/frontend-plugin-api';
2
2
  import { DefaultIconsApi } from '../packages/frontend-app-api/src/apis/implementations/IconsApi/DefaultIconsApi.esm.js';
3
3
  import '../packages/app-defaults/src/defaults/apis.esm.js';
4
4
  import 'react';
@@ -1,5 +1,5 @@
1
- import { ApiBlueprint, createApiFactory, TranslationBlueprint, createExtensionInput } from '@backstage/frontend-plugin-api';
2
- import { appLanguageApiRef, translationApiRef } from '@backstage/core-plugin-api/alpha';
1
+ import { ApiBlueprint, createExtensionInput, TranslationBlueprint, createApiFactory } from '@backstage/frontend-plugin-api';
2
+ import { translationApiRef, appLanguageApiRef } from '@backstage/core-plugin-api/alpha';
3
3
  import { I18nextTranslationApi } from '../packages/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js';
4
4
 
5
5
  const TranslationsApi = ApiBlueprint.makeWithOverrides({
@@ -1,6 +1,6 @@
1
1
  import { UrlPatternDiscovery, AlertApiForwarder, NoOpAnalyticsApi, ErrorAlerter, ErrorApiForwarder, UnhandledErrorForwarder, WebStorage, createFetchApi, FetchMiddlewares, OAuthRequestManager, GoogleAuth, MicrosoftAuth, GithubAuth, OktaAuth, GitlabAuth, OneLoginAuth, BitbucketAuth, BitbucketServerAuth, AtlassianAuth, VMwareCloudAuth } from '@backstage/core-app-api';
2
- import { createApiFactory, configApiRef, discoveryApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, identityApiRef, fetchApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, vmwareCloudAuthApiRef } from '@backstage/core-plugin-api';
3
- import { IdentityPermissionApi, permissionApiRef } from '@backstage/plugin-permission-react';
2
+ import { createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, vmwareCloudAuthApiRef } from '@backstage/core-plugin-api';
3
+ import { permissionApiRef, IdentityPermissionApi } from '@backstage/plugin-permission-react';
4
4
 
5
5
  [
6
6
  createApiFactory({
@@ -1,12 +1,46 @@
1
1
  import React from 'react';
2
- import '@material-ui/core/Button';
3
- import { Progress, ErrorPage } from '@backstage/core-components';
4
- import 'react-router-dom';
2
+ import Button from '@material-ui/core/Button';
3
+ import { Progress, ErrorPage, ErrorPanel } from '@backstage/core-components';
4
+ import { BrowserRouter, useInRouterContext, MemoryRouter } from 'react-router-dom';
5
5
 
6
+ function OptionallyWrapInRouter({ children }) {
7
+ if (useInRouterContext()) {
8
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
9
+ }
10
+ return /* @__PURE__ */ React.createElement(MemoryRouter, null, children);
11
+ }
6
12
  const DefaultNotFoundPage = () => /* @__PURE__ */ React.createElement(ErrorPage, { status: "404", statusMessage: "PAGE NOT FOUND" });
13
+ const DefaultBootErrorPage = ({ step, error }) => {
14
+ let message = "";
15
+ if (step === "load-config") {
16
+ message = `The configuration failed to load, someone should have a look at this error: ${error.message}`;
17
+ } else if (step === "load-chunk") {
18
+ message = `Lazy loaded chunk failed to load, try to reload the page: ${error.message}`;
19
+ }
20
+ return /* @__PURE__ */ React.createElement(OptionallyWrapInRouter, null, /* @__PURE__ */ React.createElement(ErrorPage, { statusMessage: message, stack: error.stack }));
21
+ };
22
+ const DefaultErrorBoundaryFallback = ({
23
+ error,
24
+ resetError,
25
+ plugin
26
+ }) => {
27
+ return /* @__PURE__ */ React.createElement(
28
+ ErrorPanel,
29
+ {
30
+ title: `Error in ${plugin?.getId()}`,
31
+ defaultExpanded: true,
32
+ error
33
+ },
34
+ /* @__PURE__ */ React.createElement(Button, { variant: "outlined", onClick: resetError }, "Retry")
35
+ );
36
+ };
7
37
  const components = {
8
38
  Progress,
9
- NotFoundErrorPage: DefaultNotFoundPage};
39
+ Router: BrowserRouter,
40
+ NotFoundErrorPage: DefaultNotFoundPage,
41
+ BootErrorPage: DefaultBootErrorPage,
42
+ ErrorBoundaryFallback: DefaultErrorBoundaryFallback
43
+ };
10
44
 
11
- export { components };
45
+ export { OptionallyWrapInRouter, components };
12
46
  //# sourceMappingURL=components.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"components.esm.js","sources":["../../../../../../../packages/app-defaults/src/defaults/components.tsx"],"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 React, { ReactNode } from 'react';\nimport Button from '@material-ui/core/Button';\nimport { ErrorPanel, Progress, ErrorPage } from '@backstage/core-components';\nimport {\n MemoryRouter,\n useInRouterContext,\n BrowserRouter,\n} from 'react-router-dom';\nimport {\n AppComponents,\n BootErrorPageProps,\n ErrorBoundaryFallbackProps,\n} from '@backstage/core-plugin-api';\n\nexport function OptionallyWrapInRouter({ children }: { children: ReactNode }) {\n if (useInRouterContext()) {\n return <>{children}</>;\n }\n return <MemoryRouter>{children}</MemoryRouter>;\n}\n\nconst DefaultNotFoundPage = () => (\n <ErrorPage status=\"404\" statusMessage=\"PAGE NOT FOUND\" />\n);\n\nconst DefaultBootErrorPage = ({ step, error }: BootErrorPageProps) => {\n let message = '';\n if (step === 'load-config') {\n message = `The configuration failed to load, someone should have a look at this error: ${error.message}`;\n } else if (step === 'load-chunk') {\n message = `Lazy loaded chunk failed to load, try to reload the page: ${error.message}`;\n }\n // TODO: figure out a nicer way to handle routing on the error page, when it can be done.\n return (\n <OptionallyWrapInRouter>\n <ErrorPage statusMessage={message} stack={error.stack} />\n </OptionallyWrapInRouter>\n );\n};\n\nconst DefaultErrorBoundaryFallback = ({\n error,\n resetError,\n plugin,\n}: ErrorBoundaryFallbackProps) => {\n return (\n <ErrorPanel\n title={`Error in ${plugin?.getId()}`}\n defaultExpanded\n error={error}\n >\n <Button variant=\"outlined\" onClick={resetError}>\n Retry\n </Button>\n </ErrorPanel>\n );\n};\n\n/**\n * Creates a set of default components to pass along to {@link @backstage/core-app-api#createSpecializedApp}.\n *\n * @public\n */\nexport const components: AppComponents = {\n Progress,\n Router: BrowserRouter,\n NotFoundErrorPage: DefaultNotFoundPage,\n BootErrorPage: DefaultBootErrorPage,\n ErrorBoundaryFallback: DefaultErrorBoundaryFallback,\n};\n"],"names":[],"mappings":";;;;;AAqCA,MAAM,sBAAsB,sBAC1B,KAAA,CAAA,aAAA,CAAC,aAAU,MAAO,EAAA,KAAA,EAAM,eAAc,gBAAiB,EAAA,CAAA;AAyClD,MAAM,UAA4B,GAAA;AAAA,EACvC,QAAA;AAAA,EAEA,iBAAmB,EAAA,mBAGrB;;;;"}
1
+ {"version":3,"file":"components.esm.js","sources":["../../../../../../../packages/app-defaults/src/defaults/components.tsx"],"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 React, { ReactNode } from 'react';\nimport Button from '@material-ui/core/Button';\nimport { ErrorPanel, Progress, ErrorPage } from '@backstage/core-components';\nimport {\n MemoryRouter,\n useInRouterContext,\n BrowserRouter,\n} from 'react-router-dom';\nimport {\n AppComponents,\n BootErrorPageProps,\n ErrorBoundaryFallbackProps,\n} from '@backstage/core-plugin-api';\n\nexport function OptionallyWrapInRouter({ children }: { children: ReactNode }) {\n if (useInRouterContext()) {\n return <>{children}</>;\n }\n return <MemoryRouter>{children}</MemoryRouter>;\n}\n\nconst DefaultNotFoundPage = () => (\n <ErrorPage status=\"404\" statusMessage=\"PAGE NOT FOUND\" />\n);\n\nconst DefaultBootErrorPage = ({ step, error }: BootErrorPageProps) => {\n let message = '';\n if (step === 'load-config') {\n message = `The configuration failed to load, someone should have a look at this error: ${error.message}`;\n } else if (step === 'load-chunk') {\n message = `Lazy loaded chunk failed to load, try to reload the page: ${error.message}`;\n }\n // TODO: figure out a nicer way to handle routing on the error page, when it can be done.\n return (\n <OptionallyWrapInRouter>\n <ErrorPage statusMessage={message} stack={error.stack} />\n </OptionallyWrapInRouter>\n );\n};\n\nconst DefaultErrorBoundaryFallback = ({\n error,\n resetError,\n plugin,\n}: ErrorBoundaryFallbackProps) => {\n return (\n <ErrorPanel\n title={`Error in ${plugin?.getId()}`}\n defaultExpanded\n error={error}\n >\n <Button variant=\"outlined\" onClick={resetError}>\n Retry\n </Button>\n </ErrorPanel>\n );\n};\n\n/**\n * Creates a set of default components to pass along to {@link @backstage/core-app-api#createSpecializedApp}.\n *\n * @public\n */\nexport const components: AppComponents = {\n Progress,\n Router: BrowserRouter,\n NotFoundErrorPage: DefaultNotFoundPage,\n BootErrorPage: DefaultBootErrorPage,\n ErrorBoundaryFallback: DefaultErrorBoundaryFallback,\n};\n"],"names":[],"mappings":";;;;;AA8BgB,SAAA,sBAAA,CAAuB,EAAE,QAAA,EAAqC,EAAA;AAC5E,EAAA,IAAI,oBAAsB,EAAA;AACxB,IAAA,iEAAU,QAAS,CAAA;AAAA;AAErB,EAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,oBAAc,QAAS,CAAA;AACjC;AAEA,MAAM,sBAAsB,sBAC1B,KAAA,CAAA,aAAA,CAAC,aAAU,MAAO,EAAA,KAAA,EAAM,eAAc,gBAAiB,EAAA,CAAA;AAGzD,MAAM,oBAAuB,GAAA,CAAC,EAAE,IAAA,EAAM,OAAgC,KAAA;AACpE,EAAA,IAAI,OAAU,GAAA,EAAA;AACd,EAAA,IAAI,SAAS,aAAe,EAAA;AAC1B,IAAU,OAAA,GAAA,CAAA,4EAAA,EAA+E,MAAM,OAAO,CAAA,CAAA;AAAA,GACxG,MAAA,IAAW,SAAS,YAAc,EAAA;AAChC,IAAU,OAAA,GAAA,CAAA,0DAAA,EAA6D,MAAM,OAAO,CAAA,CAAA;AAAA;AAGtF,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,8CACE,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,EAAU,eAAe,OAAS,EAAA,KAAA,EAAO,KAAM,CAAA,KAAA,EAAO,CACzD,CAAA;AAEJ,CAAA;AAEA,MAAM,+BAA+B,CAAC;AAAA,EACpC,KAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAkC,KAAA;AAChC,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,KAAO,EAAA,CAAA,SAAA,EAAY,MAAQ,EAAA,KAAA,EAAO,CAAA,CAAA;AAAA,MAClC,eAAe,EAAA,IAAA;AAAA,MACf;AAAA,KAAA;AAAA,wCAEC,MAAO,EAAA,EAAA,OAAA,EAAQ,UAAW,EAAA,OAAA,EAAS,cAAY,OAEhD;AAAA,GACF;AAEJ,CAAA;AAOO,MAAM,UAA4B,GAAA;AAAA,EACvC,QAAA;AAAA,EACA,MAAQ,EAAA,aAAA;AAAA,EACR,iBAAmB,EAAA,mBAAA;AAAA,EACnB,aAAe,EAAA,oBAAA;AAAA,EACf,qBAAuB,EAAA;AACzB;;;;"}
@@ -71,7 +71,7 @@ class OAuth2 {
71
71
  (session.backstageIdentity.expiresAt.getTime() - Date.now()) / 1e3
72
72
  );
73
73
  }
74
- return min < 60 * 5;
74
+ return min < 60 * 3;
75
75
  }
76
76
  });
77
77
  return new OAuth2({ sessionManager, scopeTransform });
@@ -1 +1 @@
1
- {"version":3,"file":"OAuth2.esm.js","sources":["../../../../../../../../../../packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.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 {\n DefaultAuthConnector,\n PopupOptions,\n} from '../../../../lib/AuthConnector';\nimport { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager';\nimport { SessionManager } from '../../../../lib/AuthSessionManager/types';\nimport {\n AuthRequestOptions,\n BackstageIdentityResponse,\n OAuthApi,\n OpenIdConnectApi,\n ProfileInfo,\n ProfileInfoApi,\n SessionState,\n SessionApi,\n BackstageIdentityApi,\n BackstageUserIdentity,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { OAuth2Session } from './types';\nimport { OAuthApiCreateOptions } from '../types';\n\n/**\n * OAuth2 create options.\n * @public\n */\nexport type OAuth2CreateOptions = OAuthApiCreateOptions & {\n scopeTransform?: (scopes: string[]) => string[];\n popupOptions?: PopupOptions;\n};\n\nexport type OAuth2Response = {\n providerInfo: {\n accessToken: string;\n idToken: string;\n scope: string;\n expiresInSeconds?: number;\n };\n profile: ProfileInfo;\n backstageIdentity: {\n token: string;\n expiresInSeconds?: number;\n identity: BackstageUserIdentity;\n };\n};\n\nconst DEFAULT_PROVIDER = {\n id: 'oauth2',\n title: 'Your Identity Provider',\n icon: () => null,\n};\n\n/**\n * Implements a generic OAuth2 flow for auth.\n *\n * @public\n */\nexport default class OAuth2\n implements\n OAuthApi,\n OpenIdConnectApi,\n ProfileInfoApi,\n BackstageIdentityApi,\n SessionApi\n{\n static create(options: OAuth2CreateOptions) {\n const {\n configApi,\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = [],\n scopeTransform = x => x,\n popupOptions,\n } = options;\n\n const connector = new DefaultAuthConnector({\n configApi,\n discoveryApi,\n environment,\n provider,\n oauthRequestApi: oauthRequestApi,\n sessionTransform({\n backstageIdentity,\n ...res\n }: OAuth2Response): OAuth2Session {\n const session: OAuth2Session = {\n ...res,\n providerInfo: {\n idToken: res.providerInfo.idToken,\n accessToken: res.providerInfo.accessToken,\n scopes: OAuth2.normalizeScopes(\n scopeTransform,\n res.providerInfo.scope,\n ),\n expiresAt: res.providerInfo.expiresInSeconds\n ? new Date(Date.now() + res.providerInfo.expiresInSeconds * 1000)\n : undefined,\n },\n };\n if (backstageIdentity) {\n session.backstageIdentity = {\n token: backstageIdentity.token,\n identity: backstageIdentity.identity,\n expiresAt: backstageIdentity.expiresInSeconds\n ? new Date(Date.now() + backstageIdentity.expiresInSeconds * 1000)\n : undefined,\n };\n }\n return session;\n },\n popupOptions,\n });\n\n const sessionManager = new RefreshingAuthSessionManager({\n connector,\n defaultScopes: new Set(defaultScopes),\n sessionScopes: (session: OAuth2Session) => session.providerInfo.scopes,\n sessionShouldRefresh: (session: OAuth2Session) => {\n // TODO(Rugvip): Optimize to use separate checks for provider vs backstage session expiration\n let min = Infinity;\n if (session.providerInfo?.expiresAt) {\n min = Math.min(\n min,\n (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000,\n );\n }\n if (session.backstageIdentity?.expiresAt) {\n min = Math.min(\n min,\n (session.backstageIdentity.expiresAt.getTime() - Date.now()) / 1000,\n );\n }\n return min < 60 * 5;\n },\n });\n\n return new OAuth2({ sessionManager, scopeTransform });\n }\n\n private readonly sessionManager: SessionManager<OAuth2Session>;\n private readonly scopeTransform: (scopes: string[]) => string[];\n\n private constructor(options: {\n sessionManager: SessionManager<OAuth2Session>;\n scopeTransform: (scopes: string[]) => string[];\n }) {\n this.sessionManager = options.sessionManager;\n this.scopeTransform = options.scopeTransform;\n }\n\n async signIn() {\n await this.getAccessToken();\n }\n\n async signOut() {\n await this.sessionManager.removeSession();\n }\n\n sessionState$(): Observable<SessionState> {\n return this.sessionManager.sessionState$();\n }\n\n async getAccessToken(\n scope?: string | string[],\n options?: AuthRequestOptions,\n ) {\n const normalizedScopes = OAuth2.normalizeScopes(this.scopeTransform, scope);\n const session = await this.sessionManager.getSession({\n ...options,\n scopes: normalizedScopes,\n });\n return session?.providerInfo.accessToken ?? '';\n }\n\n async getIdToken(options: AuthRequestOptions = {}) {\n const session = await this.sessionManager.getSession({\n ...options,\n scopes: new Set(['openid']),\n });\n return session?.providerInfo.idToken ?? '';\n }\n\n async getBackstageIdentity(\n options: AuthRequestOptions = {},\n ): Promise<BackstageIdentityResponse | undefined> {\n const session = await this.sessionManager.getSession(options);\n return session?.backstageIdentity;\n }\n\n async getProfile(options: AuthRequestOptions = {}) {\n const session = await this.sessionManager.getSession(options);\n return session?.profile;\n }\n\n private static normalizeScopes(\n scopeTransform: (scopes: string[]) => string[],\n scopes?: string | string[],\n ): Set<string> {\n if (!scopes) {\n return new Set();\n }\n\n const scopeList = Array.isArray(scopes)\n ? scopes\n : scopes.split(/[\\s|,]/).filter(Boolean);\n\n return new Set(scopeTransform(scopeList));\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OAuth2.esm.js","sources":["../../../../../../../../../../packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.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 {\n DefaultAuthConnector,\n PopupOptions,\n} from '../../../../lib/AuthConnector';\nimport { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager';\nimport { SessionManager } from '../../../../lib/AuthSessionManager/types';\nimport {\n AuthRequestOptions,\n BackstageIdentityResponse,\n OAuthApi,\n OpenIdConnectApi,\n ProfileInfo,\n ProfileInfoApi,\n SessionState,\n SessionApi,\n BackstageIdentityApi,\n BackstageUserIdentity,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { OAuth2Session } from './types';\nimport { OAuthApiCreateOptions } from '../types';\n\n/**\n * OAuth2 create options.\n * @public\n */\nexport type OAuth2CreateOptions = OAuthApiCreateOptions & {\n scopeTransform?: (scopes: string[]) => string[];\n popupOptions?: PopupOptions;\n};\n\nexport type OAuth2Response = {\n providerInfo: {\n accessToken: string;\n idToken: string;\n scope: string;\n expiresInSeconds?: number;\n };\n profile: ProfileInfo;\n backstageIdentity: {\n token: string;\n expiresInSeconds?: number;\n identity: BackstageUserIdentity;\n };\n};\n\nconst DEFAULT_PROVIDER = {\n id: 'oauth2',\n title: 'Your Identity Provider',\n icon: () => null,\n};\n\n/**\n * Implements a generic OAuth2 flow for auth.\n *\n * @public\n */\nexport default class OAuth2\n implements\n OAuthApi,\n OpenIdConnectApi,\n ProfileInfoApi,\n BackstageIdentityApi,\n SessionApi\n{\n static create(options: OAuth2CreateOptions) {\n const {\n configApi,\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = [],\n scopeTransform = x => x,\n popupOptions,\n } = options;\n\n const connector = new DefaultAuthConnector({\n configApi,\n discoveryApi,\n environment,\n provider,\n oauthRequestApi: oauthRequestApi,\n sessionTransform({\n backstageIdentity,\n ...res\n }: OAuth2Response): OAuth2Session {\n const session: OAuth2Session = {\n ...res,\n providerInfo: {\n idToken: res.providerInfo.idToken,\n accessToken: res.providerInfo.accessToken,\n scopes: OAuth2.normalizeScopes(\n scopeTransform,\n res.providerInfo.scope,\n ),\n expiresAt: res.providerInfo.expiresInSeconds\n ? new Date(Date.now() + res.providerInfo.expiresInSeconds * 1000)\n : undefined,\n },\n };\n if (backstageIdentity) {\n session.backstageIdentity = {\n token: backstageIdentity.token,\n identity: backstageIdentity.identity,\n expiresAt: backstageIdentity.expiresInSeconds\n ? new Date(Date.now() + backstageIdentity.expiresInSeconds * 1000)\n : undefined,\n };\n }\n return session;\n },\n popupOptions,\n });\n\n const sessionManager = new RefreshingAuthSessionManager({\n connector,\n defaultScopes: new Set(defaultScopes),\n sessionScopes: (session: OAuth2Session) => session.providerInfo.scopes,\n sessionShouldRefresh: (session: OAuth2Session) => {\n // TODO(Rugvip): Optimize to use separate checks for provider vs backstage session expiration\n let min = Infinity;\n if (session.providerInfo?.expiresAt) {\n min = Math.min(\n min,\n (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000,\n );\n }\n if (session.backstageIdentity?.expiresAt) {\n min = Math.min(\n min,\n (session.backstageIdentity.expiresAt.getTime() - Date.now()) / 1000,\n );\n }\n return min < 60 * 3;\n },\n });\n\n return new OAuth2({ sessionManager, scopeTransform });\n }\n\n private readonly sessionManager: SessionManager<OAuth2Session>;\n private readonly scopeTransform: (scopes: string[]) => string[];\n\n private constructor(options: {\n sessionManager: SessionManager<OAuth2Session>;\n scopeTransform: (scopes: string[]) => string[];\n }) {\n this.sessionManager = options.sessionManager;\n this.scopeTransform = options.scopeTransform;\n }\n\n async signIn() {\n await this.getAccessToken();\n }\n\n async signOut() {\n await this.sessionManager.removeSession();\n }\n\n sessionState$(): Observable<SessionState> {\n return this.sessionManager.sessionState$();\n }\n\n async getAccessToken(\n scope?: string | string[],\n options?: AuthRequestOptions,\n ) {\n const normalizedScopes = OAuth2.normalizeScopes(this.scopeTransform, scope);\n const session = await this.sessionManager.getSession({\n ...options,\n scopes: normalizedScopes,\n });\n return session?.providerInfo.accessToken ?? '';\n }\n\n async getIdToken(options: AuthRequestOptions = {}) {\n const session = await this.sessionManager.getSession({\n ...options,\n scopes: new Set(['openid']),\n });\n return session?.providerInfo.idToken ?? '';\n }\n\n async getBackstageIdentity(\n options: AuthRequestOptions = {},\n ): Promise<BackstageIdentityResponse | undefined> {\n const session = await this.sessionManager.getSession(options);\n return session?.backstageIdentity;\n }\n\n async getProfile(options: AuthRequestOptions = {}) {\n const session = await this.sessionManager.getSession(options);\n return session?.profile;\n }\n\n private static normalizeScopes(\n scopeTransform: (scopes: string[]) => string[],\n scopes?: string | string[],\n ): Set<string> {\n if (!scopes) {\n return new Set();\n }\n\n const scopeList = Array.isArray(scopes)\n ? scopes\n : scopes.split(/[\\s|,]/).filter(Boolean);\n\n return new Set(scopeTransform(scopeList));\n }\n}\n"],"names":[],"mappings":"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"}
@@ -44,7 +44,7 @@ class RefreshingAuthSessionManager {
44
44
  throw error;
45
45
  }
46
46
  }
47
- if (!this.currentSession && !options.instantPopup) {
47
+ if (!options.instantPopup) {
48
48
  try {
49
49
  const newSession = await this.collapsedSessionRefresh(options.scopes);
50
50
  this.currentSession = newSession;
@@ -79,6 +79,11 @@ class RefreshingAuthSessionManager {
79
79
  );
80
80
  try {
81
81
  const session = await this.refreshPromise;
82
+ if (!this.helper.sessionExistsAndHasScope(session, scopes)) {
83
+ throw new Error(
84
+ "Refreshed session did not receive the required scopes"
85
+ );
86
+ }
82
87
  this.stateTracker.setIsSignedIn(true);
83
88
  return session;
84
89
  } finally {
@@ -1 +1 @@
1
- {"version":3,"file":"RefreshingAuthSessionManager.esm.js","sources":["../../../../../../../../packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.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 {\n SessionManager,\n SessionScopesFunc,\n SessionShouldRefreshFunc,\n GetSessionOptions,\n} from './types';\nimport { AuthConnector } from '../AuthConnector';\nimport { SessionScopeHelper, hasScopes } from './common';\nimport { SessionStateTracker } from './SessionStateTracker';\n\ntype Options<T> = {\n /** The connector used for acting on the auth session */\n connector: AuthConnector<T>;\n /** Used to get the scope of the session */\n sessionScopes: SessionScopesFunc<T>;\n /** Used to check if the session needs to be refreshed */\n sessionShouldRefresh: SessionShouldRefreshFunc<T>;\n /** The default scopes that should always be present in a session, defaults to none. */\n defaultScopes?: Set<string>;\n};\n\n/**\n * RefreshingAuthSessionManager manages an underlying session that has\n * and expiration time and needs to be refreshed periodically.\n */\nexport class RefreshingAuthSessionManager<T> implements SessionManager<T> {\n private readonly connector: AuthConnector<T>;\n private readonly helper: SessionScopeHelper<T>;\n private readonly sessionScopesFunc: SessionScopesFunc<T>;\n private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc<T>;\n private readonly stateTracker = new SessionStateTracker();\n\n private refreshPromise?: Promise<T>;\n private currentSession: T | undefined;\n\n constructor(options: Options<T>) {\n const {\n connector,\n defaultScopes = new Set(),\n sessionScopes,\n sessionShouldRefresh,\n } = options;\n\n this.connector = connector;\n this.sessionScopesFunc = sessionScopes;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });\n }\n\n async getSession(options: GetSessionOptions): Promise<T | undefined> {\n if (\n this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)\n ) {\n const shouldRefresh = this.sessionShouldRefreshFunc(this.currentSession!);\n if (!shouldRefresh) {\n return this.currentSession!;\n }\n\n try {\n const refreshedSession = await this.collapsedSessionRefresh(\n options.scopes,\n );\n const currentScopes = this.sessionScopesFunc(this.currentSession!);\n const refreshedScopes = this.sessionScopesFunc(refreshedSession);\n if (hasScopes(refreshedScopes, currentScopes)) {\n this.currentSession = refreshedSession;\n }\n return refreshedSession;\n } catch (error) {\n if (options.optional) {\n return undefined;\n }\n throw error;\n }\n }\n\n // The user may still have a valid refresh token in their cookies. Attempt to\n // initiate a fresh session through the backend using that refresh token.\n //\n // We skip this check if an instant login popup is requested, as we need to\n // stay in a synchronous call stack from the user interaction. The downside\n // is that the user will sometimes be requested to log in even if they\n // already had an existing session.\n if (!this.currentSession && !options.instantPopup) {\n try {\n const newSession = await this.collapsedSessionRefresh(options.scopes);\n this.currentSession = newSession;\n // The session might not have the scopes requested so go back and check again\n return this.getSession(options);\n } catch {\n // If the refresh attempt fails we assume we don't have a session, so continue to create one.\n }\n }\n\n // If we continue here we will show a popup, so exit if this is an optional session request.\n if (options.optional) {\n return undefined;\n }\n\n // We can call authRequester multiple times, the returned session will contain all requested scopes.\n this.currentSession = await this.connector.createSession({\n ...options,\n scopes: this.helper.getExtendedScope(this.currentSession, options.scopes),\n });\n this.stateTracker.setIsSignedIn(true);\n return this.currentSession;\n }\n\n async removeSession() {\n this.currentSession = undefined;\n await this.connector.removeSession();\n this.stateTracker.setIsSignedIn(false);\n }\n\n sessionState$() {\n return this.stateTracker.sessionState$();\n }\n\n private async collapsedSessionRefresh(scopes?: Set<string>): Promise<T> {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.connector.refreshSession(\n this.helper.getExtendedScope(this.currentSession, scopes),\n );\n\n try {\n const session = await this.refreshPromise;\n this.stateTracker.setIsSignedIn(true);\n return session;\n } finally {\n delete this.refreshPromise;\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RefreshingAuthSessionManager.esm.js","sources":["../../../../../../../../packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.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 {\n SessionManager,\n SessionScopesFunc,\n SessionShouldRefreshFunc,\n GetSessionOptions,\n} from './types';\nimport { AuthConnector } from '../AuthConnector';\nimport { SessionScopeHelper, hasScopes } from './common';\nimport { SessionStateTracker } from './SessionStateTracker';\n\ntype Options<T> = {\n /** The connector used for acting on the auth session */\n connector: AuthConnector<T>;\n /** Used to get the scope of the session */\n sessionScopes: SessionScopesFunc<T>;\n /** Used to check if the session needs to be refreshed */\n sessionShouldRefresh: SessionShouldRefreshFunc<T>;\n /** The default scopes that should always be present in a session, defaults to none. */\n defaultScopes?: Set<string>;\n};\n\n/**\n * RefreshingAuthSessionManager manages an underlying session that has\n * and expiration time and needs to be refreshed periodically.\n */\nexport class RefreshingAuthSessionManager<T> implements SessionManager<T> {\n private readonly connector: AuthConnector<T>;\n private readonly helper: SessionScopeHelper<T>;\n private readonly sessionScopesFunc: SessionScopesFunc<T>;\n private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc<T>;\n private readonly stateTracker = new SessionStateTracker();\n\n private refreshPromise?: Promise<T>;\n private currentSession: T | undefined;\n\n constructor(options: Options<T>) {\n const {\n connector,\n defaultScopes = new Set(),\n sessionScopes,\n sessionShouldRefresh,\n } = options;\n\n this.connector = connector;\n this.sessionScopesFunc = sessionScopes;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });\n }\n\n async getSession(options: GetSessionOptions): Promise<T | undefined> {\n if (\n this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)\n ) {\n const shouldRefresh = this.sessionShouldRefreshFunc(this.currentSession!);\n if (!shouldRefresh) {\n return this.currentSession!;\n }\n\n try {\n const refreshedSession = await this.collapsedSessionRefresh(\n options.scopes,\n );\n const currentScopes = this.sessionScopesFunc(this.currentSession!);\n const refreshedScopes = this.sessionScopesFunc(refreshedSession);\n if (hasScopes(refreshedScopes, currentScopes)) {\n this.currentSession = refreshedSession;\n }\n return refreshedSession;\n } catch (error) {\n if (options.optional) {\n return undefined;\n }\n throw error;\n }\n }\n\n // The user may still have a valid refresh token in their cookies. Attempt to\n // initiate a fresh session through the backend using that refresh token.\n //\n // We skip this check if an instant login popup is requested, as we need to\n // stay in a synchronous call stack from the user interaction. The downside\n // is that the user will sometimes be requested to log in even if they\n // already had an existing session.\n if (!options.instantPopup) {\n try {\n const newSession = await this.collapsedSessionRefresh(options.scopes);\n this.currentSession = newSession;\n // The session might not have the scopes requested so go back and check again\n return this.getSession(options);\n } catch {\n // If the refresh attempt fails we assume we don't have a session, so continue to create one.\n }\n }\n\n // If we continue here we will show a popup, so exit if this is an optional session request.\n if (options.optional) {\n return undefined;\n }\n\n // We can call authRequester multiple times, the returned session will contain all requested scopes.\n this.currentSession = await this.connector.createSession({\n ...options,\n scopes: this.helper.getExtendedScope(this.currentSession, options.scopes),\n });\n this.stateTracker.setIsSignedIn(true);\n return this.currentSession;\n }\n\n async removeSession() {\n this.currentSession = undefined;\n await this.connector.removeSession();\n this.stateTracker.setIsSignedIn(false);\n }\n\n sessionState$() {\n return this.stateTracker.sessionState$();\n }\n\n private async collapsedSessionRefresh(scopes?: Set<string>): Promise<T> {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.connector.refreshSession(\n this.helper.getExtendedScope(this.currentSession, scopes),\n );\n\n try {\n const session = await this.refreshPromise;\n if (!this.helper.sessionExistsAndHasScope(session, scopes)) {\n throw new Error(\n 'Refreshed session did not receive the required scopes',\n );\n }\n this.stateTracker.setIsSignedIn(true);\n return session;\n } finally {\n delete this.refreshPromise;\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-app",
3
- "version": "0.1.2",
3
+ "version": "0.1.4-next.0",
4
4
  "backstage": {
5
5
  "role": "frontend-plugin",
6
6
  "pluginId": "app",
@@ -37,21 +37,21 @@
37
37
  "test": "backstage-cli package test"
38
38
  },
39
39
  "dependencies": {
40
- "@backstage/core-components": "^0.16.0",
41
- "@backstage/core-plugin-api": "^1.10.1",
42
- "@backstage/frontend-plugin-api": "^0.9.1",
43
- "@backstage/integration-react": "^1.2.1",
44
- "@backstage/plugin-permission-react": "^0.4.28",
45
- "@backstage/theme": "^0.6.1",
40
+ "@backstage/core-components": "0.16.2-next.0",
41
+ "@backstage/core-plugin-api": "1.10.1",
42
+ "@backstage/frontend-plugin-api": "0.9.3-next.0",
43
+ "@backstage/integration-react": "1.2.2-next.0",
44
+ "@backstage/plugin-permission-react": "0.4.28",
45
+ "@backstage/theme": "0.6.3-next.0",
46
46
  "@material-ui/core": "^4.9.13",
47
47
  "@material-ui/icons": "^4.9.1",
48
48
  "@material-ui/lab": "^4.0.0-alpha.61",
49
49
  "react-use": "^17.2.4"
50
50
  },
51
51
  "devDependencies": {
52
- "@backstage/cli": "^0.29.0",
53
- "@backstage/dev-utils": "^1.1.3",
54
- "@backstage/frontend-test-utils": "^0.2.2",
52
+ "@backstage/cli": "0.29.3-next.0",
53
+ "@backstage/dev-utils": "1.1.5-next.0",
54
+ "@backstage/frontend-test-utils": "0.2.4-next.0",
55
55
  "@testing-library/jest-dom": "^6.0.0",
56
56
  "@testing-library/react": "^16.0.0",
57
57
  "@testing-library/user-event": "^14.0.0",