@backstage/core-app-api 0.5.0 → 0.5.3

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,41 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 0.5.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 1ed305728b: Bump `node-fetch` to version 2.6.7 and `cross-fetch` to version 3.1.5
8
+ - c77c5c7eb6: Added `backstage.role` to `package.json`
9
+ - Updated dependencies
10
+ - @backstage/core-plugin-api@0.6.1
11
+ - @backstage/config@0.1.14
12
+ - @backstage/types@0.1.2
13
+ - @backstage/version-bridge@0.1.2
14
+
15
+ ## 0.5.2
16
+
17
+ ### Patch Changes
18
+
19
+ - 40775bd263: Switched out the `GithubAuth` implementation to use the common `OAuth2` implementation. This relies on the simultaneous change in `@backstage/plugin-auth-backend` that enabled access token storage in cookies rather than the current solution that's based on `LocalStorage`.
20
+
21
+ > **NOTE:** Make sure you upgrade the `auth-backend` deployment before or at the same time as you deploy this change.
22
+
23
+ ## 0.5.2-next.0
24
+
25
+ ### Patch Changes
26
+
27
+ - 40775bd263: Switched out the `GithubAuth` implementation to use the common `OAuth2` implementation. This relies on the simultaneous change in `@backstage/plugin-auth-backend` that enabled access token storage in cookies rather than the current solution that's based on `LocalStorage`.
28
+
29
+ > **NOTE:** Make sure you upgrade the `auth-backend` deployment before or at the same time as you deploy this change.
30
+
31
+ ## 0.5.1
32
+
33
+ ### Patch Changes
34
+
35
+ - f959c22787: Asynchronous methods on the identity API can now reliably be called at any time, including early in the bootstrap process or prior to successful sign-in.
36
+
37
+ Previously in such situations, a `Tried to access IdentityApi before app was loaded` error would be thrown. Now, those methods will wait and resolve eventually (as soon as a concrete identity API is provided).
38
+
3
39
  ## 0.5.0
4
40
 
5
41
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactNode, PropsWithChildren, ComponentType } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { ApiHolder, ApiRef, ApiFactory, AnyApiRef, ProfileInfo, BackstageIdentityResponse, OAuthRequestApi, DiscoveryApi, AuthProviderInfo, OAuthApi, SessionApi, SessionState, AuthRequestOptions, gitlabAuthApiRef, googleAuthApiRef, OpenIdConnectApi, ProfileInfoApi, BackstageIdentityApi, oktaAuthApiRef, auth0AuthApiRef, microsoftAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, atlassianAuthApiRef, AlertApi, AlertMessage, AnalyticsApi, AnalyticsEvent, AppThemeApi, AppTheme, ErrorApi, ErrorApiError, ErrorApiErrorContext, FeatureFlagsApi, FeatureFlag, FeatureFlagsSaveOptions, FetchApi, IdentityApi, OAuthRequesterOptions, OAuthRequester, PendingOAuthRequest, StorageApi, StorageValueSnapshot, BackstagePlugin, IconComponent, ExternalRouteRef, AnyApiFactory, RouteRef, SubRouteRef } from '@backstage/core-plugin-api';
3
+ import { ApiHolder, ApiRef, ApiFactory, AnyApiRef, ProfileInfo, BackstageIdentityResponse, OAuthRequestApi, DiscoveryApi, AuthProviderInfo, githubAuthApiRef, gitlabAuthApiRef, googleAuthApiRef, OAuthApi, OpenIdConnectApi, ProfileInfoApi, BackstageIdentityApi, SessionApi, SessionState, AuthRequestOptions, oktaAuthApiRef, auth0AuthApiRef, microsoftAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, atlassianAuthApiRef, AlertApi, AlertMessage, AnalyticsApi, AnalyticsEvent, AppThemeApi, AppTheme, ErrorApi, ErrorApiError, ErrorApiErrorContext, FeatureFlagsApi, FeatureFlag, FeatureFlagsSaveOptions, FetchApi, IdentityApi, OAuthRequesterOptions, OAuthRequester, PendingOAuthRequest, StorageApi, StorageValueSnapshot, BackstagePlugin, IconComponent, ExternalRouteRef, AnyApiFactory, RouteRef, SubRouteRef } from '@backstage/core-plugin-api';
4
4
  import * as _backstage_types from '@backstage/types';
5
5
  import { Observable, JsonValue } from '@backstage/types';
6
6
  import { Config, AppConfig } from '@backstage/config';
@@ -130,16 +130,11 @@ declare type AuthApiCreateOptions = {
130
130
  *
131
131
  * @public
132
132
  */
133
- declare class GithubAuth implements OAuthApi, SessionApi {
134
- private readonly sessionManager;
135
- static create(options: OAuthApiCreateOptions): GithubAuth;
136
- private constructor();
137
- signIn(): Promise<void>;
138
- signOut(): Promise<void>;
139
- sessionState$(): Observable<SessionState>;
140
- getAccessToken(scope?: string, options?: AuthRequestOptions): Promise<string>;
141
- getBackstageIdentity(options?: AuthRequestOptions): Promise<BackstageIdentityResponse | undefined>;
142
- getProfile(options?: AuthRequestOptions): Promise<ProfileInfo | undefined>;
133
+ declare class GithubAuth {
134
+ static create(options: OAuthApiCreateOptions): typeof githubAuthApiRef.T;
135
+ /**
136
+ * @deprecated This method is deprecated and will be removed in a future release.
137
+ */
143
138
  static normalizeScope(scope?: string): Set<string>;
144
139
  }
145
140
 
package/dist/index.esm.js CHANGED
@@ -725,167 +725,7 @@ class AuthSessionStore {
725
725
  }
726
726
  }
727
727
 
728
- class OptionalRefreshSessionManagerMux {
729
- constructor(options) {
730
- this.stateTracker = new SessionStateTracker();
731
- this.sessionCanRefresh = options.sessionCanRefresh;
732
- this.staticSessionManager = options.staticSessionManager;
733
- this.refreshingSessionManager = options.refreshingSessionManager;
734
- }
735
- async getSession(options) {
736
- const staticSession = await this.staticSessionManager.getSession({
737
- ...options,
738
- optional: true
739
- });
740
- if (staticSession) {
741
- this.stateTracker.setIsSignedIn(true);
742
- return staticSession;
743
- }
744
- const session = await this.refreshingSessionManager.getSession(options);
745
- if (!session) {
746
- this.stateTracker.setIsSignedIn(false);
747
- return void 0;
748
- }
749
- if (this.sessionCanRefresh(session)) {
750
- this.stateTracker.setIsSignedIn(true);
751
- return session;
752
- }
753
- this.staticSessionManager.setSession(session);
754
- this.stateTracker.setIsSignedIn(true);
755
- return session;
756
- }
757
- async removeSession() {
758
- await Promise.all([
759
- this.refreshingSessionManager.removeSession(),
760
- this.staticSessionManager.removeSession()
761
- ]);
762
- this.stateTracker.setIsSignedIn(false);
763
- }
764
- sessionState$() {
765
- return this.stateTracker.sessionState$();
766
- }
767
- }
768
-
769
- const githubSessionSchema = z.object({
770
- providerInfo: z.object({
771
- accessToken: z.string(),
772
- scopes: z.set(z.string()),
773
- expiresAt: z.date().optional()
774
- }),
775
- profile: z.object({
776
- email: z.string().optional(),
777
- displayName: z.string().optional(),
778
- picture: z.string().optional()
779
- }),
780
- backstageIdentity: z.object({
781
- id: z.string(),
782
- token: z.string(),
783
- identity: z.object({
784
- type: z.literal("user"),
785
- userEntityRef: z.string(),
786
- ownershipEntityRefs: z.array(z.string())
787
- })
788
- })
789
- });
790
-
791
728
  const DEFAULT_PROVIDER$a = {
792
- id: "github",
793
- title: "GitHub",
794
- icon: () => null
795
- };
796
- class GithubAuth {
797
- constructor(sessionManager) {
798
- this.sessionManager = sessionManager;
799
- }
800
- static create(options) {
801
- const {
802
- discoveryApi,
803
- environment = "development",
804
- provider = DEFAULT_PROVIDER$a,
805
- oauthRequestApi,
806
- defaultScopes = ["read:user"]
807
- } = options;
808
- const connector = new DefaultAuthConnector({
809
- discoveryApi,
810
- environment,
811
- provider,
812
- oauthRequestApi,
813
- sessionTransform(res) {
814
- return {
815
- ...res,
816
- providerInfo: {
817
- accessToken: res.providerInfo.accessToken,
818
- scopes: GithubAuth.normalizeScope(res.providerInfo.scope),
819
- expiresAt: res.providerInfo.expiresInSeconds ? new Date(Date.now() + res.providerInfo.expiresInSeconds * 1e3) : void 0
820
- }
821
- };
822
- }
823
- });
824
- const refreshingSessionManager = new RefreshingAuthSessionManager({
825
- connector,
826
- defaultScopes: new Set(defaultScopes),
827
- sessionScopes: (session) => session.providerInfo.scopes,
828
- sessionShouldRefresh: (session) => {
829
- const { expiresAt } = session.providerInfo;
830
- if (!expiresAt) {
831
- return false;
832
- }
833
- const expiresInSec = (expiresAt.getTime() - Date.now()) / 1e3;
834
- return expiresInSec < 60 * 5;
835
- }
836
- });
837
- const staticSessionManager = new AuthSessionStore({
838
- manager: new StaticAuthSessionManager({
839
- connector,
840
- defaultScopes: new Set(defaultScopes),
841
- sessionScopes: (session) => session.providerInfo.scopes
842
- }),
843
- storageKey: `${provider.id}Session`,
844
- schema: githubSessionSchema,
845
- sessionScopes: (session) => session.providerInfo.scopes
846
- });
847
- const sessionManagerMux = new OptionalRefreshSessionManagerMux({
848
- refreshingSessionManager,
849
- staticSessionManager,
850
- sessionCanRefresh: (session) => session.providerInfo.expiresAt !== void 0
851
- });
852
- return new GithubAuth(sessionManagerMux);
853
- }
854
- async signIn() {
855
- await this.getAccessToken();
856
- }
857
- async signOut() {
858
- await this.sessionManager.removeSession();
859
- }
860
- sessionState$() {
861
- return this.sessionManager.sessionState$();
862
- }
863
- async getAccessToken(scope, options) {
864
- var _a;
865
- const session = await this.sessionManager.getSession({
866
- ...options,
867
- scopes: GithubAuth.normalizeScope(scope)
868
- });
869
- return (_a = session == null ? void 0 : session.providerInfo.accessToken) != null ? _a : "";
870
- }
871
- async getBackstageIdentity(options = {}) {
872
- const session = await this.sessionManager.getSession(options);
873
- return session == null ? void 0 : session.backstageIdentity;
874
- }
875
- async getProfile(options = {}) {
876
- const session = await this.sessionManager.getSession(options);
877
- return session == null ? void 0 : session.profile;
878
- }
879
- static normalizeScope(scope) {
880
- if (!scope) {
881
- return /* @__PURE__ */ new Set();
882
- }
883
- const scopeList = Array.isArray(scope) ? scope : scope.split(/[\s|,]/).filter(Boolean);
884
- return new Set(scopeList);
885
- }
886
- }
887
-
888
- const DEFAULT_PROVIDER$9 = {
889
729
  id: "oauth2",
890
730
  title: "Your Identity Provider",
891
731
  icon: () => null
@@ -895,7 +735,7 @@ class OAuth2 {
895
735
  const {
896
736
  discoveryApi,
897
737
  environment = "development",
898
- provider = DEFAULT_PROVIDER$9,
738
+ provider = DEFAULT_PROVIDER$a,
899
739
  oauthRequestApi,
900
740
  defaultScopes = [],
901
741
  scopeTransform = (x) => x
@@ -972,6 +812,37 @@ class OAuth2 {
972
812
  }
973
813
  }
974
814
 
815
+ const DEFAULT_PROVIDER$9 = {
816
+ id: "github",
817
+ title: "GitHub",
818
+ icon: () => null
819
+ };
820
+ class GithubAuth {
821
+ static create(options) {
822
+ const {
823
+ discoveryApi,
824
+ environment = "development",
825
+ provider = DEFAULT_PROVIDER$9,
826
+ oauthRequestApi,
827
+ defaultScopes = ["read:user"]
828
+ } = options;
829
+ return OAuth2.create({
830
+ discoveryApi,
831
+ oauthRequestApi,
832
+ provider,
833
+ environment,
834
+ defaultScopes
835
+ });
836
+ }
837
+ static normalizeScope(scope) {
838
+ if (!scope) {
839
+ return /* @__PURE__ */ new Set();
840
+ }
841
+ const scopeList = Array.isArray(scope) ? scope : scope.split(/[\s|,]/).filter(Boolean);
842
+ return new Set(scopeList);
843
+ }
844
+ }
845
+
975
846
  const DEFAULT_PROVIDER$8 = {
976
847
  id: "gitlab",
977
848
  title: "GitLab",
@@ -2211,8 +2082,16 @@ function logDeprecation(thing) {
2211
2082
  console.warn(`WARNING: Call to ${thing} is deprecated and will break in the future`);
2212
2083
  }
2213
2084
  class AppIdentityProxy {
2085
+ constructor() {
2086
+ this.resolveTarget = () => {
2087
+ };
2088
+ this.waitForTarget = new Promise((resolve) => {
2089
+ this.resolveTarget = resolve;
2090
+ });
2091
+ }
2214
2092
  setTarget(identityApi) {
2215
2093
  this.target = identityApi;
2094
+ this.resolveTarget(identityApi);
2216
2095
  }
2217
2096
  getUserId() {
2218
2097
  if (!this.target) {
@@ -2235,42 +2114,29 @@ class AppIdentityProxy {
2235
2114
  return this.target.getProfile();
2236
2115
  }
2237
2116
  async getProfileInfo() {
2238
- if (!this.target) {
2239
- throw mkError("getProfileInfo");
2240
- }
2241
- return this.target.getProfileInfo();
2117
+ return this.waitForTarget.then((target) => target.getProfileInfo());
2242
2118
  }
2243
2119
  async getBackstageIdentity() {
2244
- if (!this.target) {
2245
- throw mkError("getBackstageIdentity");
2246
- }
2247
- const identity = await this.target.getBackstageIdentity();
2120
+ const identity = await this.waitForTarget.then((target) => target.getBackstageIdentity());
2248
2121
  if (!identity.userEntityRef.match(/^.*:.*\/.*$/)) {
2249
2122
  console.warn(`WARNING: The App IdentityApi provided an invalid userEntityRef, '${identity.userEntityRef}'. It must be a full Entity Reference of the form '<kind>:<namespace>/<name>'.`);
2250
2123
  }
2251
2124
  return identity;
2252
2125
  }
2253
2126
  async getCredentials() {
2254
- if (!this.target) {
2255
- throw mkError("getCredentials");
2256
- }
2257
- return this.target.getCredentials();
2127
+ return this.waitForTarget.then((target) => target.getCredentials());
2258
2128
  }
2259
2129
  async getIdToken() {
2260
- if (!this.target) {
2261
- throw mkError("getIdToken");
2262
- }
2263
- if (!this.target.getIdToken) {
2264
- throw new Error("IdentityApi does not implement getIdToken");
2265
- }
2266
- logDeprecation("getIdToken");
2267
- return this.target.getIdToken();
2130
+ return this.waitForTarget.then((target) => {
2131
+ if (!target.getIdToken) {
2132
+ throw new Error("IdentityApi does not implement getIdToken");
2133
+ }
2134
+ logDeprecation("getIdToken");
2135
+ return target.getIdToken();
2136
+ });
2268
2137
  }
2269
2138
  async signOut() {
2270
- if (!this.target) {
2271
- throw mkError("signOut");
2272
- }
2273
- await this.target.signOut();
2139
+ await this.waitForTarget.then((target) => target.signOut());
2274
2140
  location.reload();
2275
2141
  }
2276
2142
  }