@backstage/plugin-app 0.0.0-nightly-20240828022712

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.
Files changed (154) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +9 -0
  3. package/dist/defaultApis.esm.js +334 -0
  4. package/dist/defaultApis.esm.js.map +1 -0
  5. package/dist/extensions/App.esm.js +39 -0
  6. package/dist/extensions/App.esm.js.map +1 -0
  7. package/dist/extensions/AppLanguageApi.esm.js +16 -0
  8. package/dist/extensions/AppLanguageApi.esm.js.map +1 -0
  9. package/dist/extensions/AppLayout.esm.js +26 -0
  10. package/dist/extensions/AppLayout.esm.js.map +1 -0
  11. package/dist/extensions/AppNav.esm.js +66 -0
  12. package/dist/extensions/AppNav.esm.js.map +1 -0
  13. package/dist/extensions/AppRoot.esm.js +153 -0
  14. package/dist/extensions/AppRoot.esm.js.map +1 -0
  15. package/dist/extensions/AppRoutes.esm.js +39 -0
  16. package/dist/extensions/AppRoutes.esm.js.map +1 -0
  17. package/dist/extensions/AppThemeApi.esm.js +56 -0
  18. package/dist/extensions/AppThemeApi.esm.js.map +1 -0
  19. package/dist/extensions/ComponentsApi.esm.js +27 -0
  20. package/dist/extensions/ComponentsApi.esm.js.map +1 -0
  21. package/dist/extensions/FeatureFlagsApi.esm.js +17 -0
  22. package/dist/extensions/FeatureFlagsApi.esm.js.map +1 -0
  23. package/dist/extensions/IconsApi.esm.js +33 -0
  24. package/dist/extensions/IconsApi.esm.js.map +1 -0
  25. package/dist/extensions/TranslationsApi.esm.js +30 -0
  26. package/dist/extensions/TranslationsApi.esm.js.map +1 -0
  27. package/dist/extensions/components.esm.js +52 -0
  28. package/dist/extensions/components.esm.js.map +1 -0
  29. package/dist/extensions/elements.esm.js +32 -0
  30. package/dist/extensions/elements.esm.js.map +1 -0
  31. package/dist/index.d.ts +430 -0
  32. package/dist/index.esm.js +2 -0
  33. package/dist/index.esm.js.map +1 -0
  34. package/dist/packages/app/src/components/Root/LogoFull.esm.js +33 -0
  35. package/dist/packages/app/src/components/Root/LogoFull.esm.js.map +1 -0
  36. package/dist/packages/app/src/components/Root/LogoIcon.esm.js +33 -0
  37. package/dist/packages/app/src/components/Root/LogoIcon.esm.js.map +1 -0
  38. package/dist/packages/app-defaults/src/defaults/apis.esm.js +219 -0
  39. package/dist/packages/app-defaults/src/defaults/apis.esm.js.map +1 -0
  40. package/dist/packages/app-defaults/src/defaults/components.esm.js +46 -0
  41. package/dist/packages/app-defaults/src/defaults/components.esm.js.map +1 -0
  42. package/dist/packages/app-defaults/src/defaults/icons.esm.js +51 -0
  43. package/dist/packages/app-defaults/src/defaults/icons.esm.js.map +1 -0
  44. package/dist/packages/core-app-api/src/apis/implementations/AlertApi/AlertApiForwarder.esm.js +14 -0
  45. package/dist/packages/core-app-api/src/apis/implementations/AlertApi/AlertApiForwarder.esm.js.map +1 -0
  46. package/dist/packages/core-app-api/src/apis/implementations/AnalyticsApi/NoOpAnalyticsApi.esm.js +7 -0
  47. package/dist/packages/core-app-api/src/apis/implementations/AnalyticsApi/NoOpAnalyticsApi.esm.js.map +1 -0
  48. package/dist/packages/core-app-api/src/apis/implementations/AppLanguageApi/AppLanguageSelector.esm.js +89 -0
  49. package/dist/packages/core-app-api/src/apis/implementations/AppLanguageApi/AppLanguageSelector.esm.js.map +1 -0
  50. package/dist/packages/core-app-api/src/apis/implementations/AppThemeApi/AppThemeSelector.esm.js +48 -0
  51. package/dist/packages/core-app-api/src/apis/implementations/AppThemeApi/AppThemeSelector.esm.js.map +1 -0
  52. package/dist/packages/core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.esm.js +39 -0
  53. package/dist/packages/core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.esm.js.map +1 -0
  54. package/dist/packages/core-app-api/src/apis/implementations/ErrorApi/ErrorAlerter.esm.js +18 -0
  55. package/dist/packages/core-app-api/src/apis/implementations/ErrorApi/ErrorAlerter.esm.js.map +1 -0
  56. package/dist/packages/core-app-api/src/apis/implementations/ErrorApi/ErrorApiForwarder.esm.js +14 -0
  57. package/dist/packages/core-app-api/src/apis/implementations/ErrorApi/ErrorApiForwarder.esm.js.map +1 -0
  58. package/dist/packages/core-app-api/src/apis/implementations/ErrorApi/UnhandledErrorForwarder.esm.js +16 -0
  59. package/dist/packages/core-app-api/src/apis/implementations/ErrorApi/UnhandledErrorForwarder.esm.js.map +1 -0
  60. package/dist/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.esm.js +76 -0
  61. package/dist/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.esm.js.map +1 -0
  62. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.esm.js +45 -0
  63. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.esm.js.map +1 -0
  64. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.esm.js +49 -0
  65. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.esm.js.map +1 -0
  66. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.esm.js +40 -0
  67. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.esm.js.map +1 -0
  68. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/createFetchApi.esm.js +13 -0
  69. package/dist/packages/core-app-api/src/apis/implementations/FetchApi/createFetchApi.esm.js.map +1 -0
  70. package/dist/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.esm.js +71 -0
  71. package/dist/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.esm.js.map +1 -0
  72. package/dist/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.esm.js +54 -0
  73. package/dist/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.esm.js.map +1 -0
  74. package/dist/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.esm.js +96 -0
  75. package/dist/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.esm.js.map +1 -0
  76. package/dist/packages/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js +234 -0
  77. package/dist/packages/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js.map +1 -0
  78. package/dist/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.esm.js +28 -0
  79. package/dist/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.esm.js.map +1 -0
  80. package/dist/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.esm.js +30 -0
  81. package/dist/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.esm.js.map +1 -0
  82. package/dist/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.esm.js +30 -0
  83. package/dist/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.esm.js.map +1 -0
  84. package/dist/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.esm.js +30 -0
  85. package/dist/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.esm.js.map +1 -0
  86. package/dist/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.esm.js +30 -0
  87. package/dist/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.esm.js.map +1 -0
  88. package/dist/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.esm.js +49 -0
  89. package/dist/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.esm.js.map +1 -0
  90. package/dist/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.esm.js +130 -0
  91. package/dist/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.esm.js.map +1 -0
  92. package/dist/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.esm.js +127 -0
  93. package/dist/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.esm.js.map +1 -0
  94. package/dist/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.esm.js +51 -0
  95. package/dist/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.esm.js.map +1 -0
  96. package/dist/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.esm.js +50 -0
  97. package/dist/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.esm.js.map +1 -0
  98. package/dist/packages/core-app-api/src/apis/implementations/auth/saml/types.esm.js +18 -0
  99. package/dist/packages/core-app-api/src/apis/implementations/auth/saml/types.esm.js.map +1 -0
  100. package/dist/packages/core-app-api/src/apis/implementations/auth/vmwareCloud/VMwareCloudAuth.esm.js +30 -0
  101. package/dist/packages/core-app-api/src/apis/implementations/auth/vmwareCloud/VMwareCloudAuth.esm.js.map +1 -0
  102. package/dist/packages/core-app-api/src/apis/system/ApiAggregator.esm.js +18 -0
  103. package/dist/packages/core-app-api/src/apis/system/ApiAggregator.esm.js.map +1 -0
  104. package/dist/packages/core-app-api/src/apis/system/ApiProvider.esm.js +25 -0
  105. package/dist/packages/core-app-api/src/apis/system/ApiProvider.esm.js.map +1 -0
  106. package/dist/packages/core-app-api/src/app/AppContext.esm.js +5 -0
  107. package/dist/packages/core-app-api/src/app/AppContext.esm.js.map +1 -0
  108. package/dist/packages/core-app-api/src/app/AppRouter.esm.js +94 -0
  109. package/dist/packages/core-app-api/src/app/AppRouter.esm.js.map +1 -0
  110. package/dist/packages/core-app-api/src/app/AppThemeProvider.esm.js +60 -0
  111. package/dist/packages/core-app-api/src/app/AppThemeProvider.esm.js.map +1 -0
  112. package/dist/packages/core-app-api/src/app/InternalAppContext.esm.js +6 -0
  113. package/dist/packages/core-app-api/src/app/InternalAppContext.esm.js.map +1 -0
  114. package/dist/packages/core-app-api/src/app/isProtectedApp.esm.js +8 -0
  115. package/dist/packages/core-app-api/src/app/isProtectedApp.esm.js.map +1 -0
  116. package/dist/packages/core-app-api/src/app/isReactRouterBeta.esm.js +10 -0
  117. package/dist/packages/core-app-api/src/app/isReactRouterBeta.esm.js.map +1 -0
  118. package/dist/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.esm.js +164 -0
  119. package/dist/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.esm.js.map +1 -0
  120. package/dist/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.esm.js +91 -0
  121. package/dist/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.esm.js.map +1 -0
  122. package/dist/packages/core-app-api/src/lib/AuthSessionManager/SessionStateTracker.esm.js +23 -0
  123. package/dist/packages/core-app-api/src/lib/AuthSessionManager/SessionStateTracker.esm.js.map +1 -0
  124. package/dist/packages/core-app-api/src/lib/AuthSessionManager/common.esm.js +44 -0
  125. package/dist/packages/core-app-api/src/lib/AuthSessionManager/common.esm.js.map +1 -0
  126. package/dist/packages/core-app-api/src/lib/loginPopup.esm.js +62 -0
  127. package/dist/packages/core-app-api/src/lib/loginPopup.esm.js.map +1 -0
  128. package/dist/packages/core-app-api/src/lib/subjects.esm.js +124 -0
  129. package/dist/packages/core-app-api/src/lib/subjects.esm.js.map +1 -0
  130. package/dist/packages/core-app-api/src/routing/FeatureFlagged.esm.js +13 -0
  131. package/dist/packages/core-app-api/src/routing/FeatureFlagged.esm.js.map +1 -0
  132. package/dist/packages/core-app-api/src/routing/FlatRoutes.esm.js +59 -0
  133. package/dist/packages/core-app-api/src/routing/FlatRoutes.esm.js.map +1 -0
  134. package/dist/packages/core-app-api/src/routing/RouteTracker.esm.js +77 -0
  135. package/dist/packages/core-app-api/src/routing/RouteTracker.esm.js.map +1 -0
  136. package/dist/packages/core-app-api/src/routing/RoutingProvider.esm.js +10 -0
  137. package/dist/packages/core-app-api/src/routing/RoutingProvider.esm.js.map +1 -0
  138. package/dist/packages/core-app-api/src/routing/types.esm.js +7 -0
  139. package/dist/packages/core-app-api/src/routing/types.esm.js.map +1 -0
  140. package/dist/packages/core-plugin-api/src/translation/TranslationRef.esm.js +13 -0
  141. package/dist/packages/core-plugin-api/src/translation/TranslationRef.esm.js.map +1 -0
  142. package/dist/packages/core-plugin-api/src/translation/TranslationResource.esm.js +13 -0
  143. package/dist/packages/core-plugin-api/src/translation/TranslationResource.esm.js.map +1 -0
  144. package/dist/packages/frontend-app-api/src/apis/implementations/ComponentsApi/DefaultComponentsApi.esm.js +21 -0
  145. package/dist/packages/frontend-app-api/src/apis/implementations/ComponentsApi/DefaultComponentsApi.esm.js.map +1 -0
  146. package/dist/packages/frontend-app-api/src/apis/implementations/IconsApi/DefaultIconsApi.esm.js +15 -0
  147. package/dist/packages/frontend-app-api/src/apis/implementations/IconsApi/DefaultIconsApi.esm.js.map +1 -0
  148. package/dist/packages/frontend-app-api/src/routing/RouteTracker.esm.js +69 -0
  149. package/dist/packages/frontend-app-api/src/routing/RouteTracker.esm.js.map +1 -0
  150. package/dist/packages/frontend-app-api/src/routing/getBasePath.esm.js +12 -0
  151. package/dist/packages/frontend-app-api/src/routing/getBasePath.esm.js.map +1 -0
  152. package/dist/plugin.esm.js +43 -0
  153. package/dist/plugin.esm.js.map +1 -0
  154. package/package.json +66 -0
@@ -0,0 +1,14 @@
1
+ import { PublishSubject } from '../../../lib/subjects.esm.js';
2
+
3
+ class ErrorApiForwarder {
4
+ subject = new PublishSubject();
5
+ post(error, context) {
6
+ this.subject.next({ error, context });
7
+ }
8
+ error$() {
9
+ return this.subject;
10
+ }
11
+ }
12
+
13
+ export { ErrorApiForwarder };
14
+ //# sourceMappingURL=ErrorApiForwarder.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorApiForwarder.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/ErrorApi/ErrorApiForwarder.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 ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { PublishSubject } from '../../../lib/subjects';\n\n/**\n * Base implementation for the ErrorApi that simply forwards errors to consumers.\n *\n * @public\n */\nexport class ErrorApiForwarder implements ErrorApi {\n private readonly subject = new PublishSubject<{\n error: Error;\n context?: ErrorApiErrorContext;\n }>();\n\n post(error: ErrorApiError, context?: ErrorApiErrorContext) {\n this.subject.next({ error, context });\n }\n\n error$(): Observable<{ error: Error; context?: ErrorApiErrorContext }> {\n return this.subject;\n }\n}\n"],"names":[],"mappings":";;AA6BO,MAAM,iBAAsC,CAAA;AAAA,EAChC,OAAA,GAAU,IAAI,cAG5B,EAAA,CAAA;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAgC,EAAA;AACzD,IAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,EAAE,KAAA,EAAO,SAAS,CAAA,CAAA;AAAA,GACtC;AAAA,EAEA,MAAuE,GAAA;AACrE,IAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AAAA,GACd;AACF;;;;"}
@@ -0,0 +1,16 @@
1
+ class UnhandledErrorForwarder {
2
+ /**
3
+ * Add event listener, such that unhandled errors can be forwarded using an given `ErrorApi` instance
4
+ */
5
+ static forward(errorApi, errorContext) {
6
+ window.addEventListener(
7
+ "unhandledrejection",
8
+ (e) => {
9
+ errorApi.post(e.reason, errorContext);
10
+ }
11
+ );
12
+ }
13
+ }
14
+
15
+ export { UnhandledErrorForwarder };
16
+ //# sourceMappingURL=UnhandledErrorForwarder.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnhandledErrorForwarder.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/ErrorApi/UnhandledErrorForwarder.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 ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n} from '@backstage/core-plugin-api';\n\n/**\n * Utility class that helps with error forwarding.\n *\n * @public\n */\nexport class UnhandledErrorForwarder {\n /**\n * Add event listener, such that unhandled errors can be forwarded using an given `ErrorApi` instance\n */\n static forward(errorApi: ErrorApi, errorContext: ErrorApiErrorContext) {\n window.addEventListener(\n 'unhandledrejection',\n (e: PromiseRejectionEvent) => {\n errorApi.post(e.reason as ErrorApiError, errorContext);\n },\n );\n }\n}\n"],"names":[],"mappings":"AA2BO,MAAM,uBAAwB,CAAA;AAAA;AAAA;AAAA;AAAA,EAInC,OAAO,OAAQ,CAAA,QAAA,EAAoB,YAAoC,EAAA;AACrE,IAAO,MAAA,CAAA,gBAAA;AAAA,MACL,oBAAA;AAAA,MACA,CAAC,CAA6B,KAAA;AAC5B,QAAS,QAAA,CAAA,IAAA,CAAK,CAAE,CAAA,MAAA,EAAyB,YAAY,CAAA,CAAA;AAAA,OACvD;AAAA,KACF,CAAA;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,76 @@
1
+ import { FeatureFlagState } from '@backstage/core-plugin-api';
2
+
3
+ function validateFlagName(name) {
4
+ if (name.length < 3) {
5
+ throw new Error(
6
+ `The '${name}' feature flag must have a minimum length of three characters.`
7
+ );
8
+ }
9
+ if (name.length > 150) {
10
+ throw new Error(
11
+ `The '${name}' feature flag must not exceed 150 characters.`
12
+ );
13
+ }
14
+ if (!name.match(/^[a-z]+[a-z0-9-]+$/)) {
15
+ throw new Error(
16
+ `The '${name}' feature flag must start with a lowercase letter and only contain lowercase letters, numbers and hyphens. Examples: feature-flag-one, alpha, release-2020`
17
+ );
18
+ }
19
+ }
20
+ class LocalStorageFeatureFlags {
21
+ registeredFeatureFlags = [];
22
+ flags;
23
+ registerFlag(flag) {
24
+ validateFlagName(flag.name);
25
+ this.registeredFeatureFlags.push(flag);
26
+ }
27
+ getRegisteredFlags() {
28
+ return this.registeredFeatureFlags.slice();
29
+ }
30
+ isActive(name) {
31
+ if (!this.flags) {
32
+ this.flags = this.load();
33
+ }
34
+ return this.flags.get(name) === FeatureFlagState.Active;
35
+ }
36
+ save(options) {
37
+ if (!this.flags) {
38
+ this.flags = this.load();
39
+ }
40
+ if (!options.merge) {
41
+ this.flags.clear();
42
+ }
43
+ for (const [name, state] of Object.entries(options.states)) {
44
+ this.flags.set(name, state);
45
+ }
46
+ const enabled = Array.from(this.flags.entries()).filter(
47
+ ([, state]) => state === FeatureFlagState.Active
48
+ );
49
+ window.localStorage.setItem(
50
+ "featureFlags",
51
+ JSON.stringify(Object.fromEntries(enabled))
52
+ );
53
+ }
54
+ load() {
55
+ try {
56
+ const jsonStr = window.localStorage.getItem("featureFlags");
57
+ if (!jsonStr) {
58
+ return /* @__PURE__ */ new Map();
59
+ }
60
+ const json = JSON.parse(jsonStr);
61
+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
62
+ return /* @__PURE__ */ new Map();
63
+ }
64
+ const entries = Object.entries(json).filter(([name, value]) => {
65
+ validateFlagName(name);
66
+ return value === FeatureFlagState.Active;
67
+ });
68
+ return new Map(entries);
69
+ } catch {
70
+ return /* @__PURE__ */ new Map();
71
+ }
72
+ }
73
+ }
74
+
75
+ export { LocalStorageFeatureFlags, validateFlagName };
76
+ //# sourceMappingURL=LocalStorageFeatureFlags.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalStorageFeatureFlags.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.tsx"],"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 FeatureFlagState,\n FeatureFlagsApi,\n FeatureFlag,\n FeatureFlagsSaveOptions,\n} from '@backstage/core-plugin-api';\n\nexport function validateFlagName(name: string): void {\n if (name.length < 3) {\n throw new Error(\n `The '${name}' feature flag must have a minimum length of three characters.`,\n );\n }\n\n if (name.length > 150) {\n throw new Error(\n `The '${name}' feature flag must not exceed 150 characters.`,\n );\n }\n\n if (!name.match(/^[a-z]+[a-z0-9-]+$/)) {\n throw new Error(\n `The '${name}' feature flag must start with a lowercase letter and only contain lowercase letters, numbers and hyphens. ` +\n 'Examples: feature-flag-one, alpha, release-2020',\n );\n }\n}\n\n/**\n * A feature flags implementation that stores the flags in the browser's local\n * storage.\n *\n * @public\n */\nexport class LocalStorageFeatureFlags implements FeatureFlagsApi {\n private registeredFeatureFlags: FeatureFlag[] = [];\n private flags?: Map<string, FeatureFlagState>;\n\n registerFlag(flag: FeatureFlag) {\n validateFlagName(flag.name);\n this.registeredFeatureFlags.push(flag);\n }\n\n getRegisteredFlags(): FeatureFlag[] {\n return this.registeredFeatureFlags.slice();\n }\n\n isActive(name: string): boolean {\n if (!this.flags) {\n this.flags = this.load();\n }\n return this.flags.get(name) === FeatureFlagState.Active;\n }\n\n save(options: FeatureFlagsSaveOptions): void {\n if (!this.flags) {\n this.flags = this.load();\n }\n if (!options.merge) {\n this.flags.clear();\n }\n for (const [name, state] of Object.entries(options.states)) {\n this.flags.set(name, state);\n }\n\n const enabled = Array.from(this.flags.entries()).filter(\n ([, state]) => state === FeatureFlagState.Active,\n );\n window.localStorage.setItem(\n 'featureFlags',\n JSON.stringify(Object.fromEntries(enabled)),\n );\n }\n\n private load(): Map<string, FeatureFlagState> {\n try {\n const jsonStr = window.localStorage.getItem('featureFlags');\n if (!jsonStr) {\n return new Map();\n }\n const json = JSON.parse(jsonStr) as unknown;\n if (typeof json !== 'object' || json === null || Array.isArray(json)) {\n return new Map();\n }\n\n const entries = Object.entries(json).filter(([name, value]) => {\n validateFlagName(name);\n return value === FeatureFlagState.Active;\n });\n\n return new Map(entries);\n } catch {\n return new Map();\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { IdentityAuthInjectorFetchMiddleware } from './IdentityAuthInjectorFetchMiddleware.esm.js';
2
+ import { PluginProtocolResolverFetchMiddleware } from './PluginProtocolResolverFetchMiddleware.esm.js';
3
+
4
+ class FetchMiddlewares {
5
+ /**
6
+ * Handles translation from `plugin://` URLs to concrete http(s) URLs based on
7
+ * the discovery API.
8
+ *
9
+ * @remarks
10
+ *
11
+ * If the request is for `plugin://catalog/entities?filter=x=y`, the discovery
12
+ * API will be queried for `'catalog'`. If it returned
13
+ * `https://backstage.example.net/api/catalog`, the resulting query would be
14
+ * `https://backstage.example.net/api/catalog/entities?filter=x=y`.
15
+ *
16
+ * If the incoming URL protocol was not `plugin`, the request is just passed
17
+ * through verbatim to the underlying implementation.
18
+ */
19
+ static resolvePluginProtocol(options) {
20
+ return new PluginProtocolResolverFetchMiddleware(options.discoveryApi);
21
+ }
22
+ /**
23
+ * Injects a Backstage token header when the user is signed in.
24
+ *
25
+ * @remarks
26
+ *
27
+ * Per default, an `Authorization: Bearer <token>` is generated. This can be
28
+ * customized using the `header` option.
29
+ *
30
+ * The header injection only happens on allowlisted URLs. Per default, if the
31
+ * `config` option is passed in, the `backend.baseUrl` is allowlisted, unless
32
+ * the `urlPrefixAllowlist` or `allowUrl` options are passed in, in which case
33
+ * they take precedence. If you pass in neither config nor an
34
+ * allowlist/callback, the middleware will have no effect since effectively no
35
+ * request will match the (nonexistent) rules.
36
+ */
37
+ static injectIdentityAuth(options) {
38
+ return IdentityAuthInjectorFetchMiddleware.create(options);
39
+ }
40
+ constructor() {
41
+ }
42
+ }
43
+
44
+ export { FetchMiddlewares };
45
+ //# sourceMappingURL=FetchMiddlewares.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FetchMiddlewares.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';\nimport { IdentityAuthInjectorFetchMiddleware } from './IdentityAuthInjectorFetchMiddleware';\nimport { PluginProtocolResolverFetchMiddleware } from './PluginProtocolResolverFetchMiddleware';\nimport { FetchMiddleware } from './types';\n\n/**\n * A collection of common middlewares for the FetchApi.\n *\n * @public\n */\nexport class FetchMiddlewares {\n /**\n * Handles translation from `plugin://` URLs to concrete http(s) URLs based on\n * the discovery API.\n *\n * @remarks\n *\n * If the request is for `plugin://catalog/entities?filter=x=y`, the discovery\n * API will be queried for `'catalog'`. If it returned\n * `https://backstage.example.net/api/catalog`, the resulting query would be\n * `https://backstage.example.net/api/catalog/entities?filter=x=y`.\n *\n * If the incoming URL protocol was not `plugin`, the request is just passed\n * through verbatim to the underlying implementation.\n */\n static resolvePluginProtocol(options: {\n discoveryApi: DiscoveryApi;\n }): FetchMiddleware {\n return new PluginProtocolResolverFetchMiddleware(options.discoveryApi);\n }\n\n /**\n * Injects a Backstage token header when the user is signed in.\n *\n * @remarks\n *\n * Per default, an `Authorization: Bearer <token>` is generated. This can be\n * customized using the `header` option.\n *\n * The header injection only happens on allowlisted URLs. Per default, if the\n * `config` option is passed in, the `backend.baseUrl` is allowlisted, unless\n * the `urlPrefixAllowlist` or `allowUrl` options are passed in, in which case\n * they take precedence. If you pass in neither config nor an\n * allowlist/callback, the middleware will have no effect since effectively no\n * request will match the (nonexistent) rules.\n */\n static injectIdentityAuth(options: {\n identityApi: IdentityApi;\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n header?: {\n name: string;\n value: (backstageToken: string) => string;\n };\n }): FetchMiddleware {\n return IdentityAuthInjectorFetchMiddleware.create(options);\n }\n\n private constructor() {}\n}\n"],"names":[],"mappings":";;;AA2BO,MAAM,gBAAiB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe5B,OAAO,sBAAsB,OAET,EAAA;AAClB,IAAO,OAAA,IAAI,qCAAsC,CAAA,OAAA,CAAQ,YAAY,CAAA,CAAA;AAAA,GACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,OAAO,mBAAmB,OASN,EAAA;AAClB,IAAO,OAAA,mCAAA,CAAoC,OAAO,OAAO,CAAA,CAAA;AAAA,GAC3D;AAAA,EAEQ,WAAc,GAAA;AAAA,GAAC;AACzB;;;;"}
@@ -0,0 +1,49 @@
1
+ class IdentityAuthInjectorFetchMiddleware {
2
+ constructor(identityApi, allowUrl, headerName, headerValue) {
3
+ this.identityApi = identityApi;
4
+ this.allowUrl = allowUrl;
5
+ this.headerName = headerName;
6
+ this.headerValue = headerValue;
7
+ }
8
+ static create(options) {
9
+ const matcher = buildMatcher(options);
10
+ const headerName = options.header?.name || "authorization";
11
+ const headerValue = options.header?.value || ((token) => `Bearer ${token}`);
12
+ return new IdentityAuthInjectorFetchMiddleware(
13
+ options.identityApi,
14
+ matcher,
15
+ headerName,
16
+ headerValue
17
+ );
18
+ }
19
+ apply(next) {
20
+ return async (input, init) => {
21
+ const request = new Request(input, init);
22
+ const { token } = await this.identityApi.getCredentials();
23
+ if (request.headers.get(this.headerName) || typeof token !== "string" || !token || !this.allowUrl(request.url)) {
24
+ return next(input, init);
25
+ }
26
+ request.headers.set(this.headerName, this.headerValue(token));
27
+ return next(request);
28
+ };
29
+ }
30
+ }
31
+ function buildMatcher(options) {
32
+ if (options.allowUrl) {
33
+ return options.allowUrl;
34
+ } else if (options.urlPrefixAllowlist) {
35
+ return buildPrefixMatcher(options.urlPrefixAllowlist);
36
+ } else if (options.config) {
37
+ return buildPrefixMatcher([options.config.getString("backend.baseUrl")]);
38
+ }
39
+ return () => false;
40
+ }
41
+ function buildPrefixMatcher(prefixes) {
42
+ const trimmedPrefixes = prefixes.map((prefix) => prefix.replace(/\/$/, ""));
43
+ return (url) => trimmedPrefixes.some(
44
+ (prefix) => url === prefix || url.startsWith(`${prefix}/`)
45
+ );
46
+ }
47
+
48
+ export { IdentityAuthInjectorFetchMiddleware };
49
+ //# sourceMappingURL=IdentityAuthInjectorFetchMiddleware.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdentityAuthInjectorFetchMiddleware.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { IdentityApi } from '@backstage/core-plugin-api';\nimport { FetchMiddleware } from './types';\n\n/**\n * A fetch middleware, which injects a Backstage token header when the user is\n * signed in.\n */\nexport class IdentityAuthInjectorFetchMiddleware implements FetchMiddleware {\n static create(options: {\n identityApi: IdentityApi;\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n header?: {\n name: string;\n value: (backstageToken: string) => string;\n };\n }): IdentityAuthInjectorFetchMiddleware {\n const matcher = buildMatcher(options);\n const headerName = options.header?.name || 'authorization';\n const headerValue = options.header?.value || (token => `Bearer ${token}`);\n\n return new IdentityAuthInjectorFetchMiddleware(\n options.identityApi,\n matcher,\n headerName,\n headerValue,\n );\n }\n\n constructor(\n public readonly identityApi: IdentityApi,\n public readonly allowUrl: (url: string) => boolean,\n public readonly headerName: string,\n public readonly headerValue: (pluginId: string) => string,\n ) {}\n\n apply(next: typeof fetch): typeof fetch {\n return async (input, init) => {\n // Skip this middleware if the header already exists, or if the URL\n // doesn't match any of the allowlist items, or if there was no token.\n // NOTE(freben): The \"as any\" casts here and below are because of subtle\n // undici type differences that happened in a node types bump. Those are\n // immaterial to the code at hand at runtime, as the global fetch and\n // Request are always taken from the same place.\n const request = new Request(input as any, init);\n const { token } = await this.identityApi.getCredentials();\n if (\n request.headers.get(this.headerName) ||\n typeof token !== 'string' ||\n !token ||\n !this.allowUrl(request.url)\n ) {\n return next(input as any, init);\n }\n\n request.headers.set(this.headerName, this.headerValue(token));\n return next(request);\n };\n }\n}\n\nfunction buildMatcher(options: {\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n}): (url: string) => boolean {\n if (options.allowUrl) {\n return options.allowUrl;\n } else if (options.urlPrefixAllowlist) {\n return buildPrefixMatcher(options.urlPrefixAllowlist);\n } else if (options.config) {\n return buildPrefixMatcher([options.config.getString('backend.baseUrl')]);\n }\n return () => false;\n}\n\nfunction buildPrefixMatcher(prefixes: string[]): (url: string) => boolean {\n const trimmedPrefixes = prefixes.map(prefix => prefix.replace(/\\/$/, ''));\n return url =>\n trimmedPrefixes.some(\n prefix => url === prefix || url.startsWith(`${prefix}/`),\n );\n}\n"],"names":[],"mappings":"AAwBO,MAAM,mCAA+D,CAAA;AAAA,EAuB1E,WACkB,CAAA,WAAA,EACA,QACA,EAAA,UAAA,EACA,WAChB,EAAA;AAJgB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AAAA,GACf;AAAA,EA3BH,OAAO,OAAO,OAS0B,EAAA;AACtC,IAAM,MAAA,OAAA,GAAU,aAAa,OAAO,CAAA,CAAA;AACpC,IAAM,MAAA,UAAA,GAAa,OAAQ,CAAA,MAAA,EAAQ,IAAQ,IAAA,eAAA,CAAA;AAC3C,IAAA,MAAM,cAAc,OAAQ,CAAA,MAAA,EAAQ,KAAU,KAAA,CAAA,KAAA,KAAS,UAAU,KAAK,CAAA,CAAA,CAAA,CAAA;AAEtE,IAAA,OAAO,IAAI,mCAAA;AAAA,MACT,OAAQ,CAAA,WAAA;AAAA,MACR,OAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EASA,MAAM,IAAkC,EAAA;AACtC,IAAO,OAAA,OAAO,OAAO,IAAS,KAAA;AAO5B,MAAA,MAAM,OAAU,GAAA,IAAI,OAAQ,CAAA,KAAA,EAAc,IAAI,CAAA,CAAA;AAC9C,MAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,YAAY,cAAe,EAAA,CAAA;AACxD,MAAA,IACE,QAAQ,OAAQ,CAAA,GAAA,CAAI,IAAK,CAAA,UAAU,KACnC,OAAO,KAAA,KAAU,QACjB,IAAA,CAAC,SACD,CAAC,IAAA,CAAK,QAAS,CAAA,OAAA,CAAQ,GAAG,CAC1B,EAAA;AACA,QAAO,OAAA,IAAA,CAAK,OAAc,IAAI,CAAA,CAAA;AAAA,OAChC;AAEA,MAAA,OAAA,CAAQ,QAAQ,GAAI,CAAA,IAAA,CAAK,YAAY,IAAK,CAAA,WAAA,CAAY,KAAK,CAAC,CAAA,CAAA;AAC5D,MAAA,OAAO,KAAK,OAAO,CAAA,CAAA;AAAA,KACrB,CAAA;AAAA,GACF;AACF,CAAA;AAEA,SAAS,aAAa,OAIO,EAAA;AAC3B,EAAA,IAAI,QAAQ,QAAU,EAAA;AACpB,IAAA,OAAO,OAAQ,CAAA,QAAA,CAAA;AAAA,GACjB,MAAA,IAAW,QAAQ,kBAAoB,EAAA;AACrC,IAAO,OAAA,kBAAA,CAAmB,QAAQ,kBAAkB,CAAA,CAAA;AAAA,GACtD,MAAA,IAAW,QAAQ,MAAQ,EAAA;AACzB,IAAA,OAAO,mBAAmB,CAAC,OAAA,CAAQ,OAAO,SAAU,CAAA,iBAAiB,CAAC,CAAC,CAAA,CAAA;AAAA,GACzE;AACA,EAAA,OAAO,MAAM,KAAA,CAAA;AACf,CAAA;AAEA,SAAS,mBAAmB,QAA8C,EAAA;AACxE,EAAM,MAAA,eAAA,GAAkB,SAAS,GAAI,CAAA,CAAA,MAAA,KAAU,OAAO,OAAQ,CAAA,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA;AACxE,EAAA,OAAO,SACL,eAAgB,CAAA,IAAA;AAAA,IACd,YAAU,GAAQ,KAAA,MAAA,IAAU,IAAI,UAAW,CAAA,CAAA,EAAG,MAAM,CAAG,CAAA,CAAA,CAAA;AAAA,GACzD,CAAA;AACJ;;;;"}
@@ -0,0 +1,40 @@
1
+ function join(left, right) {
2
+ if (!right || right === "/") {
3
+ return left;
4
+ }
5
+ return `${left.replace(/\/$/, "")}/${right.replace(/^\//, "")}`;
6
+ }
7
+ class PluginProtocolResolverFetchMiddleware {
8
+ constructor(discoveryApi) {
9
+ this.discoveryApi = discoveryApi;
10
+ }
11
+ apply(next) {
12
+ return async (input, init) => {
13
+ const request = new Request(input, init);
14
+ const prefix = "plugin://";
15
+ if (!request.url.startsWith(prefix)) {
16
+ return next(input, init);
17
+ }
18
+ const { hostname, pathname, search, hash, username, password } = new URL(
19
+ `http://${request.url.substring(prefix.length)}`
20
+ );
21
+ let base = await this.discoveryApi.getBaseUrl(hostname);
22
+ if (username || password) {
23
+ const baseUrl = new URL(base);
24
+ const authority = `${username}${password ? `:${password}` : ""}@`;
25
+ base = `${baseUrl.protocol}//${authority}${baseUrl.host}${baseUrl.pathname}`;
26
+ }
27
+ const target = `${join(base, pathname)}${search}${hash}`;
28
+ return next(
29
+ target,
30
+ typeof input === "string" || isUrl(input) ? init : input
31
+ );
32
+ };
33
+ }
34
+ }
35
+ function isUrl(a) {
36
+ return typeof a === "object" && a?.constructor === URL;
37
+ }
38
+
39
+ export { PluginProtocolResolverFetchMiddleware };
40
+ //# sourceMappingURL=PluginProtocolResolverFetchMiddleware.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginProtocolResolverFetchMiddleware.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryApi } from '@backstage/core-plugin-api';\nimport { FetchMiddleware } from './types';\n\nfunction join(left: string, right: string): string {\n if (!right || right === '/') {\n return left;\n }\n\n return `${left.replace(/\\/$/, '')}/${right.replace(/^\\//, '')}`;\n}\n\n/**\n * Handles translation from plugin://some-plugin-id/<path> to concrete http(s)\n * URLs.\n */\nexport class PluginProtocolResolverFetchMiddleware implements FetchMiddleware {\n constructor(private readonly discoveryApi: DiscoveryApi) {}\n\n apply(next: typeof fetch): typeof fetch {\n return async (input, init) => {\n // NOTE(freben): The \"as any\" casts here and below are because of subtle\n // undici type differences that happened in a node types bump. Those are\n // immaterial to the code at hand at runtime, as the global fetch and\n // Request are always taken from the same place.\n const request = new Request(input as any, init);\n const prefix = 'plugin://';\n\n if (!request.url.startsWith(prefix)) {\n return next(input as any, init);\n }\n\n // Switch to a known protocol, since browser URL parsing misbehaves wildly\n // on foreign protocols\n const { hostname, pathname, search, hash, username, password } = new URL(\n `http://${request.url.substring(prefix.length)}`,\n );\n\n let base = await this.discoveryApi.getBaseUrl(hostname);\n if (username || password) {\n const baseUrl = new URL(base);\n const authority = `${username}${password ? `:${password}` : ''}@`;\n base = `${baseUrl.protocol}//${authority}${baseUrl.host}${baseUrl.pathname}`;\n }\n\n const target = `${join(base, pathname)}${search}${hash}`;\n return next(\n target,\n typeof input === 'string' || isUrl(input) ? init : (input as any),\n );\n };\n }\n}\n\nfunction isUrl(a: unknown): a is URL {\n return typeof a === 'object' && a?.constructor === URL;\n}\n"],"names":[],"mappings":"AAmBA,SAAS,IAAA,CAAK,MAAc,KAAuB,EAAA;AACjD,EAAI,IAAA,CAAC,KAAS,IAAA,KAAA,KAAU,GAAK,EAAA;AAC3B,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,CAAA,EAAG,IAAK,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,CAAA,EAAI,KAAM,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,CAAA,CAAA;AAC/D,CAAA;AAMO,MAAM,qCAAiE,CAAA;AAAA,EAC5E,YAA6B,YAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AAAA,GAA6B;AAAA,EAE1D,MAAM,IAAkC,EAAA;AACtC,IAAO,OAAA,OAAO,OAAO,IAAS,KAAA;AAK5B,MAAA,MAAM,OAAU,GAAA,IAAI,OAAQ,CAAA,KAAA,EAAc,IAAI,CAAA,CAAA;AAC9C,MAAA,MAAM,MAAS,GAAA,WAAA,CAAA;AAEf,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAI,CAAA,UAAA,CAAW,MAAM,CAAG,EAAA;AACnC,QAAO,OAAA,IAAA,CAAK,OAAc,IAAI,CAAA,CAAA;AAAA,OAChC;AAIA,MAAM,MAAA,EAAE,UAAU,QAAU,EAAA,MAAA,EAAQ,MAAM,QAAU,EAAA,QAAA,KAAa,IAAI,GAAA;AAAA,QACnE,UAAU,OAAQ,CAAA,GAAA,CAAI,SAAU,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAAA,OAChD,CAAA;AAEA,MAAA,IAAI,IAAO,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA,CAAA;AACtD,MAAA,IAAI,YAAY,QAAU,EAAA;AACxB,QAAM,MAAA,OAAA,GAAU,IAAI,GAAA,CAAI,IAAI,CAAA,CAAA;AAC5B,QAAM,MAAA,SAAA,GAAY,GAAG,QAAQ,CAAA,EAAG,WAAW,CAAI,CAAA,EAAA,QAAQ,KAAK,EAAE,CAAA,CAAA,CAAA,CAAA;AAC9D,QAAO,IAAA,GAAA,CAAA,EAAG,OAAQ,CAAA,QAAQ,CAAK,EAAA,EAAA,SAAS,GAAG,OAAQ,CAAA,IAAI,CAAG,EAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA,CAAA;AAAA,OAC5E;AAEA,MAAM,MAAA,MAAA,GAAS,GAAG,IAAK,CAAA,IAAA,EAAM,QAAQ,CAAC,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAA,CAAA;AACtD,MAAO,OAAA,IAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAO,KAAU,KAAA,QAAA,IAAY,KAAM,CAAA,KAAK,IAAI,IAAQ,GAAA,KAAA;AAAA,OACtD,CAAA;AAAA,KACF,CAAA;AAAA,GACF;AACF,CAAA;AAEA,SAAS,MAAM,CAAsB,EAAA;AACnC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAY,IAAA,CAAA,EAAG,WAAgB,KAAA,GAAA,CAAA;AACrD;;;;"}
@@ -0,0 +1,13 @@
1
+ function createFetchApi(options) {
2
+ let result = options.baseImplementation || global.fetch;
3
+ const middleware = [options.middleware ?? []].flat().reverse();
4
+ for (const m of middleware) {
5
+ result = m.apply(result);
6
+ }
7
+ return {
8
+ fetch: result
9
+ };
10
+ }
11
+
12
+ export { createFetchApi };
13
+ //# sourceMappingURL=createFetchApi.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createFetchApi.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/FetchApi/createFetchApi.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FetchApi } from '@backstage/core-plugin-api';\nimport { FetchMiddleware } from './types';\n\n/**\n * Builds a fetch API, based on the builtin fetch wrapped by a set of optional\n * middleware implementations that add behaviors.\n *\n * @remarks\n *\n * The middleware are applied in reverse order, i.e. the last one will be\n * \"closest\" to the base implementation. Passing in `[M1, M2, M3]` effectively\n * leads to `M1(M2(M3(baseImplementation)))`.\n *\n * @public\n */\nexport function createFetchApi(options: {\n baseImplementation?: typeof fetch | undefined;\n middleware?: FetchMiddleware | FetchMiddleware[] | undefined;\n}): FetchApi {\n let result = options.baseImplementation || global.fetch;\n\n const middleware = [options.middleware ?? []].flat().reverse();\n for (const m of middleware) {\n result = m.apply(result);\n }\n\n return {\n fetch: result,\n };\n}\n"],"names":[],"mappings":"AA+BO,SAAS,eAAe,OAGlB,EAAA;AACX,EAAI,IAAA,MAAA,GAAS,OAAQ,CAAA,kBAAA,IAAsB,MAAO,CAAA,KAAA,CAAA;AAElD,EAAM,MAAA,UAAA,GAAa,CAAC,OAAQ,CAAA,UAAA,IAAc,EAAE,CAAA,CAAE,IAAK,EAAA,CAAE,OAAQ,EAAA,CAAA;AAC7D,EAAA,KAAA,MAAW,KAAK,UAAY,EAAA;AAC1B,IAAS,MAAA,GAAA,CAAA,CAAE,MAAM,MAAM,CAAA,CAAA;AAAA,GACzB;AAEA,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,MAAA;AAAA,GACT,CAAA;AACF;;;;"}
@@ -0,0 +1,71 @@
1
+ import { BehaviorSubject } from '../../../lib/subjects.esm.js';
2
+
3
+ function hasScopes(searched, searchFor) {
4
+ for (const scope of searchFor) {
5
+ if (!searched.has(scope)) {
6
+ return false;
7
+ }
8
+ }
9
+ return true;
10
+ }
11
+ function joinScopes(scopes, ...moreScopess) {
12
+ const result = new Set(scopes);
13
+ for (const moreScopes of moreScopess) {
14
+ for (const scope of moreScopes) {
15
+ result.add(scope);
16
+ }
17
+ }
18
+ return result;
19
+ }
20
+ class OAuthPendingRequests {
21
+ requests = [];
22
+ subject = new BehaviorSubject(
23
+ this.getCurrentPending()
24
+ );
25
+ request(scopes) {
26
+ return new Promise((resolve, reject) => {
27
+ this.requests.push({ scopes, resolve, reject });
28
+ this.subject.next(this.getCurrentPending());
29
+ });
30
+ }
31
+ resolve(scopes, result) {
32
+ this.requests = this.requests.filter((request) => {
33
+ if (hasScopes(scopes, request.scopes)) {
34
+ request.resolve(result);
35
+ return false;
36
+ }
37
+ return true;
38
+ });
39
+ this.subject.next(this.getCurrentPending());
40
+ }
41
+ reject(error) {
42
+ this.requests.forEach((request) => request.reject(error));
43
+ this.requests = [];
44
+ this.subject.next(this.getCurrentPending());
45
+ }
46
+ pending() {
47
+ return this.subject;
48
+ }
49
+ getCurrentPending() {
50
+ const currentScopes = this.requests.length === 0 ? void 0 : this.requests.slice(1).reduce(
51
+ (acc, current) => joinScopes(acc, current.scopes),
52
+ this.requests[0].scopes
53
+ );
54
+ return {
55
+ scopes: currentScopes,
56
+ resolve: (value) => {
57
+ if (currentScopes) {
58
+ this.resolve(currentScopes, value);
59
+ }
60
+ },
61
+ reject: (reason) => {
62
+ if (currentScopes) {
63
+ this.reject(reason);
64
+ }
65
+ }
66
+ };
67
+ }
68
+ }
69
+
70
+ export { OAuthPendingRequests, hasScopes, joinScopes };
71
+ //# sourceMappingURL=OAuthPendingRequests.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OAuthPendingRequests.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.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 { Observable } from '@backstage/types';\nimport { BehaviorSubject } from '../../../lib/subjects';\n\ntype RequestQueueEntry<ResultType> = {\n scopes: Set<string>;\n resolve: (value: ResultType | PromiseLike<ResultType>) => void;\n reject: (reason: Error) => void;\n};\n\nexport type PendingRequest<ResultType> = {\n scopes: Set<string> | undefined;\n resolve: (value: ResultType) => void;\n reject: (reason: Error) => void;\n};\n\nexport function hasScopes(\n searched: Set<string>,\n searchFor: Set<string>,\n): boolean {\n for (const scope of searchFor) {\n if (!searched.has(scope)) {\n return false;\n }\n }\n return true;\n}\n\nexport function joinScopes(\n scopes: Set<string>,\n ...moreScopess: Set<string>[]\n): Set<string> {\n const result = new Set(scopes);\n\n for (const moreScopes of moreScopess) {\n for (const scope of moreScopes) {\n result.add(scope);\n }\n }\n\n return result;\n}\n\n/**\n * The OAuthPendingRequests class is a utility for managing and observing\n * a stream of requests for oauth scopes for a single provider, and resolving\n * them correctly once requests are fulfilled.\n */\nexport class OAuthPendingRequests<ResultType> {\n private requests: RequestQueueEntry<ResultType>[] = [];\n private subject = new BehaviorSubject<PendingRequest<ResultType>>(\n this.getCurrentPending(),\n );\n\n request(scopes: Set<string>): Promise<ResultType> {\n return new Promise((resolve, reject) => {\n this.requests.push({ scopes, resolve, reject });\n\n this.subject.next(this.getCurrentPending());\n });\n }\n\n resolve(scopes: Set<string>, result: ResultType): void {\n this.requests = this.requests.filter(request => {\n if (hasScopes(scopes, request.scopes)) {\n request.resolve(result);\n return false;\n }\n return true;\n });\n\n this.subject.next(this.getCurrentPending());\n }\n\n reject(error: Error) {\n this.requests.forEach(request => request.reject(error));\n this.requests = [];\n\n this.subject.next(this.getCurrentPending());\n }\n\n pending(): Observable<PendingRequest<ResultType>> {\n return this.subject;\n }\n\n private getCurrentPending(): PendingRequest<ResultType> {\n const currentScopes =\n this.requests.length === 0\n ? undefined\n : this.requests\n .slice(1)\n .reduce(\n (acc, current) => joinScopes(acc, current.scopes),\n this.requests[0].scopes,\n );\n\n return {\n scopes: currentScopes,\n resolve: (value: ResultType) => {\n if (currentScopes) {\n this.resolve(currentScopes, value);\n }\n },\n reject: (reason: Error) => {\n if (currentScopes) {\n this.reject(reason);\n }\n },\n };\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { OAuthPendingRequests } from './OAuthPendingRequests.esm.js';
2
+ import { BehaviorSubject } from '../../../lib/subjects.esm.js';
3
+
4
+ class OAuthRequestManager {
5
+ subject = new BehaviorSubject([]);
6
+ currentRequests = [];
7
+ handlerCount = 0;
8
+ createAuthRequester(options) {
9
+ const handler = new OAuthPendingRequests();
10
+ const index = this.handlerCount;
11
+ this.handlerCount++;
12
+ handler.pending().subscribe({
13
+ next: (scopeRequest) => {
14
+ const newRequests = this.currentRequests.slice();
15
+ const request = this.makeAuthRequest(scopeRequest, options);
16
+ if (!request) {
17
+ delete newRequests[index];
18
+ } else {
19
+ newRequests[index] = request;
20
+ }
21
+ this.currentRequests = newRequests;
22
+ this.subject.next(newRequests.filter(Boolean));
23
+ }
24
+ });
25
+ return (scopes) => {
26
+ return handler.request(scopes);
27
+ };
28
+ }
29
+ // Converts the pending request and popup options into a popup request that we can forward to subscribers.
30
+ makeAuthRequest(request, options) {
31
+ const { scopes } = request;
32
+ if (!scopes) {
33
+ return void 0;
34
+ }
35
+ return {
36
+ provider: options.provider,
37
+ trigger: async () => {
38
+ const result = await options.onAuthRequest(scopes);
39
+ request.resolve(result);
40
+ },
41
+ reject: () => {
42
+ const error = new Error("Login failed, rejected by user");
43
+ error.name = "RejectedError";
44
+ request.reject(error);
45
+ }
46
+ };
47
+ }
48
+ authRequest$() {
49
+ return this.subject;
50
+ }
51
+ }
52
+
53
+ export { OAuthRequestManager };
54
+ //# sourceMappingURL=OAuthRequestManager.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OAuthRequestManager.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.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 OAuthRequestApi,\n PendingOAuthRequest,\n OAuthRequester,\n OAuthRequesterOptions,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { OAuthPendingRequests, PendingRequest } from './OAuthPendingRequests';\nimport { BehaviorSubject } from '../../../lib/subjects';\n\n/**\n * The OAuthRequestManager is an implementation of the OAuthRequestApi.\n *\n * The purpose of this class and the API is to read a stream of incoming requests\n * of OAuth access tokens from different providers with varying scope, and funnel\n * them all together into a single request for each OAuth provider.\n *\n * @public\n */\nexport class OAuthRequestManager implements OAuthRequestApi {\n private readonly subject = new BehaviorSubject<PendingOAuthRequest[]>([]);\n private currentRequests: PendingOAuthRequest[] = [];\n private handlerCount = 0;\n\n createAuthRequester<T>(options: OAuthRequesterOptions<T>): OAuthRequester<T> {\n const handler = new OAuthPendingRequests<T>();\n\n const index = this.handlerCount;\n this.handlerCount++;\n\n handler.pending().subscribe({\n next: scopeRequest => {\n const newRequests = this.currentRequests.slice();\n const request = this.makeAuthRequest(scopeRequest, options);\n if (!request) {\n delete newRequests[index];\n } else {\n newRequests[index] = request;\n }\n this.currentRequests = newRequests;\n // Convert from sparse array to array of present items only\n this.subject.next(newRequests.filter(Boolean));\n },\n });\n\n return scopes => {\n return handler.request(scopes);\n };\n }\n\n // Converts the pending request and popup options into a popup request that we can forward to subscribers.\n private makeAuthRequest(\n request: PendingRequest<any>,\n options: OAuthRequesterOptions<any>,\n ): PendingOAuthRequest | undefined {\n const { scopes } = request;\n if (!scopes) {\n return undefined;\n }\n\n return {\n provider: options.provider,\n trigger: async () => {\n const result = await options.onAuthRequest(scopes);\n request.resolve(result);\n },\n reject: () => {\n const error = new Error('Login failed, rejected by user');\n error.name = 'RejectedError';\n request.reject(error);\n },\n };\n }\n\n authRequest$(): Observable<PendingOAuthRequest[]> {\n return this.subject;\n }\n}\n"],"names":[],"mappings":";;;AAmCO,MAAM,mBAA+C,CAAA;AAAA,EACzC,OAAU,GAAA,IAAI,eAAuC,CAAA,EAAE,CAAA,CAAA;AAAA,EAChE,kBAAyC,EAAC,CAAA;AAAA,EAC1C,YAAe,GAAA,CAAA,CAAA;AAAA,EAEvB,oBAAuB,OAAsD,EAAA;AAC3E,IAAM,MAAA,OAAA,GAAU,IAAI,oBAAwB,EAAA,CAAA;AAE5C,IAAA,MAAM,QAAQ,IAAK,CAAA,YAAA,CAAA;AACnB,IAAK,IAAA,CAAA,YAAA,EAAA,CAAA;AAEL,IAAQ,OAAA,CAAA,OAAA,GAAU,SAAU,CAAA;AAAA,MAC1B,MAAM,CAAgB,YAAA,KAAA;AACpB,QAAM,MAAA,WAAA,GAAc,IAAK,CAAA,eAAA,CAAgB,KAAM,EAAA,CAAA;AAC/C,QAAA,MAAM,OAAU,GAAA,IAAA,CAAK,eAAgB,CAAA,YAAA,EAAc,OAAO,CAAA,CAAA;AAC1D,QAAA,IAAI,CAAC,OAAS,EAAA;AACZ,UAAA,OAAO,YAAY,KAAK,CAAA,CAAA;AAAA,SACnB,MAAA;AACL,UAAA,WAAA,CAAY,KAAK,CAAI,GAAA,OAAA,CAAA;AAAA,SACvB;AACA,QAAA,IAAA,CAAK,eAAkB,GAAA,WAAA,CAAA;AAEvB,QAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,WAAY,CAAA,MAAA,CAAO,OAAO,CAAC,CAAA,CAAA;AAAA,OAC/C;AAAA,KACD,CAAA,CAAA;AAED,IAAA,OAAO,CAAU,MAAA,KAAA;AACf,MAAO,OAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA,CAAA;AAAA,KAC/B,CAAA;AAAA,GACF;AAAA;AAAA,EAGQ,eAAA,CACN,SACA,OACiC,EAAA;AACjC,IAAM,MAAA,EAAE,QAAW,GAAA,OAAA,CAAA;AACnB,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACT;AAEA,IAAO,OAAA;AAAA,MACL,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,SAAS,YAAY;AACnB,QAAA,MAAM,MAAS,GAAA,MAAM,OAAQ,CAAA,aAAA,CAAc,MAAM,CAAA,CAAA;AACjD,QAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA,CAAA;AAAA,OACxB;AAAA,MACA,QAAQ,MAAM;AACZ,QAAM,MAAA,KAAA,GAAQ,IAAI,KAAA,CAAM,gCAAgC,CAAA,CAAA;AACxD,QAAA,KAAA,CAAM,IAAO,GAAA,eAAA,CAAA;AACb,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA,CAAA;AAAA,OACtB;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,YAAkD,GAAA;AAChD,IAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AAAA,GACd;AACF;;;;"}
@@ -0,0 +1,96 @@
1
+ import ObservableImpl from 'zen-observable';
2
+
3
+ const buckets = /* @__PURE__ */ new Map();
4
+ class WebStorage {
5
+ constructor(namespace, errorApi) {
6
+ this.namespace = namespace;
7
+ this.errorApi = errorApi;
8
+ }
9
+ static hasSubscribed = false;
10
+ static create(options) {
11
+ return new WebStorage(options.namespace ?? "", options.errorApi);
12
+ }
13
+ static addStorageEventListener() {
14
+ window.addEventListener("storage", (event) => {
15
+ for (const [bucketPath, webStorage] of buckets.entries()) {
16
+ if (event.key?.startsWith(bucketPath)) {
17
+ webStorage.handleStorageChange(event.key);
18
+ }
19
+ }
20
+ });
21
+ }
22
+ get(key) {
23
+ return this.snapshot(key).value;
24
+ }
25
+ snapshot(key) {
26
+ let value = void 0;
27
+ let presence = "absent";
28
+ try {
29
+ const item = localStorage.getItem(this.getKeyName(key));
30
+ if (item) {
31
+ value = JSON.parse(item, (_key, val) => {
32
+ if (typeof val === "object" && val !== null) {
33
+ Object.freeze(val);
34
+ }
35
+ return val;
36
+ });
37
+ presence = "present";
38
+ }
39
+ } catch (e) {
40
+ this.errorApi.post(
41
+ new Error(`Error when parsing JSON config from storage for: ${key}`)
42
+ );
43
+ }
44
+ return { key, value, presence };
45
+ }
46
+ forBucket(name) {
47
+ const bucketPath = `${this.namespace}/${name}`;
48
+ if (!buckets.has(bucketPath)) {
49
+ buckets.set(bucketPath, new WebStorage(bucketPath, this.errorApi));
50
+ }
51
+ return buckets.get(bucketPath);
52
+ }
53
+ async set(key, data) {
54
+ localStorage.setItem(this.getKeyName(key), JSON.stringify(data));
55
+ this.notifyChanges(key);
56
+ }
57
+ async remove(key) {
58
+ localStorage.removeItem(this.getKeyName(key));
59
+ this.notifyChanges(key);
60
+ }
61
+ observe$(key) {
62
+ if (!WebStorage.hasSubscribed) {
63
+ WebStorage.addStorageEventListener();
64
+ WebStorage.hasSubscribed = true;
65
+ }
66
+ return this.observable.filter(({ key: messageKey }) => messageKey === key);
67
+ }
68
+ handleStorageChange(eventKey) {
69
+ if (!eventKey?.startsWith(this.namespace)) {
70
+ return;
71
+ }
72
+ const trimmedKey = eventKey?.slice(`${this.namespace}/`.length);
73
+ if (!trimmedKey.includes("/")) {
74
+ this.notifyChanges(decodeURIComponent(trimmedKey));
75
+ }
76
+ }
77
+ getKeyName(key) {
78
+ return `${this.namespace}/${encodeURIComponent(key)}`;
79
+ }
80
+ notifyChanges(key) {
81
+ const snapshot = this.snapshot(key);
82
+ for (const subscription of this.subscribers) {
83
+ subscription.next(snapshot);
84
+ }
85
+ }
86
+ subscribers = /* @__PURE__ */ new Set();
87
+ observable = new ObservableImpl((subscriber) => {
88
+ this.subscribers.add(subscriber);
89
+ return () => {
90
+ this.subscribers.delete(subscriber);
91
+ };
92
+ });
93
+ }
94
+
95
+ export { WebStorage, buckets };
96
+ //# sourceMappingURL=WebStorage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebStorage.esm.js","sources":["../../../../../../../../../packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.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 StorageApi,\n StorageValueSnapshot,\n ErrorApi,\n} from '@backstage/core-plugin-api';\nimport { JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\nexport const buckets = new Map<string, WebStorage>();\n\n/**\n * An implementation of the storage API, that uses the browser's local storage.\n *\n * @public\n */\nexport class WebStorage implements StorageApi {\n constructor(\n private readonly namespace: string,\n private readonly errorApi: ErrorApi,\n ) {}\n\n private static hasSubscribed = false;\n\n static create(options: {\n errorApi: ErrorApi;\n namespace?: string;\n }): WebStorage {\n return new WebStorage(options.namespace ?? '', options.errorApi);\n }\n\n private static addStorageEventListener() {\n window.addEventListener('storage', event => {\n for (const [bucketPath, webStorage] of buckets.entries()) {\n if (event.key?.startsWith(bucketPath)) {\n webStorage.handleStorageChange(event.key);\n }\n }\n });\n }\n\n get<T>(key: string): T | undefined {\n return this.snapshot(key).value as T | undefined;\n }\n\n snapshot<T extends JsonValue>(key: string): StorageValueSnapshot<T> {\n let value = undefined;\n let presence: 'present' | 'absent' = 'absent';\n try {\n const item = localStorage.getItem(this.getKeyName(key));\n if (item) {\n value = JSON.parse(item, (_key, val) => {\n if (typeof val === 'object' && val !== null) {\n Object.freeze(val);\n }\n return val;\n });\n presence = 'present';\n }\n } catch (e) {\n this.errorApi.post(\n new Error(`Error when parsing JSON config from storage for: ${key}`),\n );\n }\n return { key, value, presence };\n }\n\n forBucket(name: string): WebStorage {\n const bucketPath = `${this.namespace}/${name}`;\n if (!buckets.has(bucketPath)) {\n buckets.set(bucketPath, new WebStorage(bucketPath, this.errorApi));\n }\n return buckets.get(bucketPath)!;\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n localStorage.setItem(this.getKeyName(key), JSON.stringify(data));\n this.notifyChanges(key);\n }\n\n async remove(key: string): Promise<void> {\n localStorage.removeItem(this.getKeyName(key));\n this.notifyChanges(key);\n }\n\n observe$<T extends JsonValue>(\n key: string,\n ): Observable<StorageValueSnapshot<T>> {\n if (!WebStorage.hasSubscribed) {\n WebStorage.addStorageEventListener();\n WebStorage.hasSubscribed = true;\n }\n return this.observable.filter(({ key: messageKey }) => messageKey === key);\n }\n\n private handleStorageChange(eventKey: StorageEvent['key']) {\n if (!eventKey?.startsWith(this.namespace)) {\n return;\n }\n // Grab the part of this key that is local to this bucket\n const trimmedKey = eventKey?.slice(`${this.namespace}/`.length);\n\n // If the key still contains a slash, it means it's a sub-bucket\n if (!trimmedKey.includes('/')) {\n this.notifyChanges(decodeURIComponent(trimmedKey));\n }\n }\n\n private getKeyName(key: string) {\n return `${this.namespace}/${encodeURIComponent(key)}`;\n }\n\n private notifyChanges(key: string) {\n const snapshot = this.snapshot(key);\n for (const subscription of this.subscribers) {\n subscription.next(snapshot);\n }\n }\n\n private subscribers = new Set<\n ZenObservable.SubscriptionObserver<StorageValueSnapshot<JsonValue>>\n >();\n\n private readonly observable = new ObservableImpl<\n StorageValueSnapshot<JsonValue>\n >(subscriber => {\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n}\n"],"names":[],"mappings":"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"}