@backstage/core-app-api 1.18.0 → 1.19.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.
Files changed (82) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/apis/implementations/AlertApi/AlertApiForwarder.esm.js.map +1 -1
  3. package/dist/apis/implementations/AnalyticsApi/MultipleAnalyticsApi.esm.js.map +1 -1
  4. package/dist/apis/implementations/AnalyticsApi/NoOpAnalyticsApi.esm.js.map +1 -1
  5. package/dist/apis/implementations/AppLanguageApi/AppLanguageSelector.esm.js +0 -3
  6. package/dist/apis/implementations/AppLanguageApi/AppLanguageSelector.esm.js.map +1 -1
  7. package/dist/apis/implementations/AppThemeApi/AppThemeSelector.esm.js.map +1 -1
  8. package/dist/apis/implementations/DiscoveryApi/FrontendHostDiscovery.esm.js.map +1 -1
  9. package/dist/apis/implementations/DiscoveryApi/UrlPatternDiscovery.esm.js.map +1 -1
  10. package/dist/apis/implementations/ErrorApi/ErrorAlerter.esm.js.map +1 -1
  11. package/dist/apis/implementations/ErrorApi/ErrorApiForwarder.esm.js.map +1 -1
  12. package/dist/apis/implementations/ErrorApi/UnhandledErrorForwarder.esm.js.map +1 -1
  13. package/dist/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.esm.js.map +1 -1
  14. package/dist/apis/implementations/FetchApi/FetchMiddlewares.esm.js.map +1 -1
  15. package/dist/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.esm.js.map +1 -1
  16. package/dist/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.esm.js.map +1 -1
  17. package/dist/apis/implementations/FetchApi/createFetchApi.esm.js.map +1 -1
  18. package/dist/apis/implementations/IdentityApi/AppIdentityProxy.esm.js.map +1 -1
  19. package/dist/apis/implementations/IdentityApi/startCookieAuthRefresh.esm.js.map +1 -1
  20. package/dist/apis/implementations/OAuthRequestApi/OAuthPendingRequests.esm.js.map +1 -1
  21. package/dist/apis/implementations/OAuthRequestApi/OAuthRequestManager.esm.js.map +1 -1
  22. package/dist/apis/implementations/StorageApi/WebStorage.esm.js.map +1 -1
  23. package/dist/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js.map +1 -1
  24. package/dist/apis/implementations/auth/atlassian/AtlassianAuth.esm.js.map +1 -1
  25. package/dist/apis/implementations/auth/bitbucket/BitbucketAuth.esm.js.map +1 -1
  26. package/dist/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.esm.js.map +1 -1
  27. package/dist/apis/implementations/auth/github/GithubAuth.esm.js.map +1 -1
  28. package/dist/apis/implementations/auth/gitlab/GitlabAuth.esm.js.map +1 -1
  29. package/dist/apis/implementations/auth/google/GoogleAuth.esm.js.map +1 -1
  30. package/dist/apis/implementations/auth/microsoft/MicrosoftAuth.esm.js.map +1 -1
  31. package/dist/apis/implementations/auth/oauth2/OAuth2.esm.js.map +1 -1
  32. package/dist/apis/implementations/auth/okta/OktaAuth.esm.js.map +1 -1
  33. package/dist/apis/implementations/auth/onelogin/OneLoginAuth.esm.js.map +1 -1
  34. package/dist/apis/implementations/auth/openshift/OpenShiftAuth.esm.js +30 -0
  35. package/dist/apis/implementations/auth/openshift/OpenShiftAuth.esm.js.map +1 -0
  36. package/dist/apis/implementations/auth/saml/SamlAuth.esm.js.map +1 -1
  37. package/dist/apis/implementations/auth/saml/types.esm.js.map +1 -1
  38. package/dist/apis/implementations/auth/vmwareCloud/VMwareCloudAuth.esm.js.map +1 -1
  39. package/dist/apis/system/ApiAggregator.esm.js.map +1 -1
  40. package/dist/apis/system/ApiFactoryRegistry.esm.js.map +1 -1
  41. package/dist/apis/system/ApiProvider.esm.js.map +1 -1
  42. package/dist/apis/system/ApiRegistry.esm.js.map +1 -1
  43. package/dist/apis/system/ApiResolver.esm.js.map +1 -1
  44. package/dist/app/AppContext.esm.js.map +1 -1
  45. package/dist/app/AppManager.esm.js +1 -1
  46. package/dist/app/AppManager.esm.js.map +1 -1
  47. package/dist/app/AppRouter.esm.js.map +1 -1
  48. package/dist/app/AppThemeProvider.esm.js.map +1 -1
  49. package/dist/app/InternalAppContext.esm.js.map +1 -1
  50. package/dist/app/createSpecializedApp.esm.js.map +1 -1
  51. package/dist/app/defaultConfigLoader.esm.js.map +1 -1
  52. package/dist/app/isProtectedApp.esm.js.map +1 -1
  53. package/dist/app/isReactRouterBeta.esm.js.map +1 -1
  54. package/dist/app/overrideBaseUrlConfigs.esm.js.map +1 -1
  55. package/dist/app/resolveRouteBindings.esm.js.map +1 -1
  56. package/dist/core-plugin-api/src/translation/TranslationRef.esm.js.map +1 -1
  57. package/dist/core-plugin-api/src/translation/TranslationResource.esm.js.map +1 -1
  58. package/dist/extensions/traversal.esm.js.map +1 -1
  59. package/dist/index.d.ts +12 -3
  60. package/dist/index.esm.js +1 -0
  61. package/dist/index.esm.js.map +1 -1
  62. package/dist/lib/AuthConnector/DefaultAuthConnector.esm.js.map +1 -1
  63. package/dist/lib/AuthConnector/DirectAuthConnector.esm.js.map +1 -1
  64. package/dist/lib/AuthSessionManager/AuthSessionStore.esm.js.map +1 -1
  65. package/dist/lib/AuthSessionManager/RefreshingAuthSessionManager.esm.js.map +1 -1
  66. package/dist/lib/AuthSessionManager/SessionStateTracker.esm.js.map +1 -1
  67. package/dist/lib/AuthSessionManager/StaticAuthSessionManager.esm.js.map +1 -1
  68. package/dist/lib/AuthSessionManager/common.esm.js.map +1 -1
  69. package/dist/lib/loginPopup.esm.js.map +1 -1
  70. package/dist/lib/subjects.esm.js.map +1 -1
  71. package/dist/plugins/collectors.esm.js.map +1 -1
  72. package/dist/routing/FeatureFlagged.esm.js.map +1 -1
  73. package/dist/routing/FlatRoutes.esm.js.map +1 -1
  74. package/dist/routing/RouteResolver.esm.js +1 -1
  75. package/dist/routing/RouteResolver.esm.js.map +1 -1
  76. package/dist/routing/RouteTracker.esm.js.map +1 -1
  77. package/dist/routing/RoutingProvider.esm.js.map +1 -1
  78. package/dist/routing/collectors.esm.js.map +1 -1
  79. package/dist/routing/helpers.esm.js.map +1 -1
  80. package/dist/routing/types.esm.js.map +1 -1
  81. package/dist/routing/validation.esm.js.map +1 -1
  82. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 1.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3fca906: Add `OpenShiftAuth` helper to create default OAuth flow for OpenShift.
8
+
9
+ ### Patch Changes
10
+
11
+ - 5ae6d9d: feat: support no en languages
12
+ - Updated dependencies
13
+ - @backstage/core-plugin-api@1.11.0
14
+ - @backstage/types@1.2.2
15
+
3
16
  ## 1.18.0
4
17
 
5
18
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"AlertApiForwarder.esm.js","sources":["../../../../src/apis/implementations/AlertApi/AlertApiForwarder.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 { AlertApi, AlertMessage } from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { PublishSubject } from '../../../lib/subjects';\n\n/**\n * Base implementation for the AlertApi that simply forwards alerts to consumers.\n *\n * @public\n */\nexport class AlertApiForwarder implements AlertApi {\n private readonly subject = new PublishSubject<AlertMessage>();\n\n post(alert: AlertMessage) {\n this.subject.next(alert);\n }\n\n alert$(): Observable<AlertMessage> {\n return this.subject;\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAM,iBAAsC,CAAA;AAAA,EAChC,OAAA,GAAU,IAAI,cAA6B,EAAA;AAAA,EAE5D,KAAK,KAAqB,EAAA;AACxB,IAAK,IAAA,CAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA;AACzB,EAEA,MAAmC,GAAA;AACjC,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AAEhB;;;;"}
1
+ {"version":3,"file":"AlertApiForwarder.esm.js","sources":["../../../../src/apis/implementations/AlertApi/AlertApiForwarder.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 { AlertApi, AlertMessage } from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { PublishSubject } from '../../../lib/subjects';\n\n/**\n * Base implementation for the AlertApi that simply forwards alerts to consumers.\n *\n * @public\n */\nexport class AlertApiForwarder implements AlertApi {\n private readonly subject = new PublishSubject<AlertMessage>();\n\n post(alert: AlertMessage) {\n this.subject.next(alert);\n }\n\n alert$(): Observable<AlertMessage> {\n return this.subject;\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAM,iBAAA,CAAsC;AAAA,EAChC,OAAA,GAAU,IAAI,cAAA,EAA6B;AAAA,EAE5D,KAAK,KAAA,EAAqB;AACxB,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,EACzB;AAAA,EAEA,MAAA,GAAmC;AACjC,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"MultipleAnalyticsApi.esm.js","sources":["../../../../src/apis/implementations/AnalyticsApi/MultipleAnalyticsApi.ts"],"sourcesContent":["/*\n * Copyright 2022 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 */\nimport { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';\n\n/**\n * An implementation of the AnalyticsApi that can be used to forward analytics\n * events to multiple concrete implementations.\n *\n * @public\n *\n * @example\n *\n * ```jsx\n * createApiFactory({\n * api: analyticsApiRef,\n * deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef },\n * factory: ({ configApi, identityApi, storageApi }) =>\n * MultipleAnalyticsApi.fromApis([\n * VendorAnalyticsApi.fromConfig(configApi, { identityApi }),\n * CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }),\n * ]),\n * });\n * ```\n */\nexport class MultipleAnalyticsApi implements AnalyticsApi {\n private constructor(private readonly actualApis: AnalyticsApi[]) {}\n\n /**\n * Create an AnalyticsApi implementation from an array of concrete\n * implementations.\n *\n * @example\n *\n * ```jsx\n * MultipleAnalyticsApi.fromApis([\n * SomeAnalyticsApi.fromConfig(configApi),\n * new CustomAnalyticsApi(),\n * ]);\n * ```\n */\n static fromApis(actualApis: AnalyticsApi[]) {\n return new MultipleAnalyticsApi(actualApis);\n }\n\n /**\n * Forward the event to all configured analytics API implementations.\n */\n captureEvent(event: AnalyticsEvent): void {\n this.actualApis.forEach(analyticsApi => {\n try {\n analyticsApi.captureEvent(event);\n } catch {\n /* ignored */\n }\n });\n }\n}\n"],"names":[],"mappings":"AAqCO,MAAM,oBAA6C,CAAA;AAAA,EAChD,YAA6B,UAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAAA;AAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAelE,OAAO,SAAS,UAA4B,EAAA;AAC1C,IAAO,OAAA,IAAI,qBAAqB,UAAU,CAAA;AAAA;AAC5C;AAAA;AAAA;AAAA,EAKA,aAAa,KAA6B,EAAA;AACxC,IAAK,IAAA,CAAA,UAAA,CAAW,QAAQ,CAAgB,YAAA,KAAA;AACtC,MAAI,IAAA;AACF,QAAA,YAAA,CAAa,aAAa,KAAK,CAAA;AAAA,OACzB,CAAA,MAAA;AAAA;AAER,KACD,CAAA;AAAA;AAEL;;;;"}
1
+ {"version":3,"file":"MultipleAnalyticsApi.esm.js","sources":["../../../../src/apis/implementations/AnalyticsApi/MultipleAnalyticsApi.ts"],"sourcesContent":["/*\n * Copyright 2022 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 */\nimport { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';\n\n/**\n * An implementation of the AnalyticsApi that can be used to forward analytics\n * events to multiple concrete implementations.\n *\n * @public\n *\n * @example\n *\n * ```jsx\n * createApiFactory({\n * api: analyticsApiRef,\n * deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef },\n * factory: ({ configApi, identityApi, storageApi }) =>\n * MultipleAnalyticsApi.fromApis([\n * VendorAnalyticsApi.fromConfig(configApi, { identityApi }),\n * CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }),\n * ]),\n * });\n * ```\n */\nexport class MultipleAnalyticsApi implements AnalyticsApi {\n private constructor(private readonly actualApis: AnalyticsApi[]) {}\n\n /**\n * Create an AnalyticsApi implementation from an array of concrete\n * implementations.\n *\n * @example\n *\n * ```jsx\n * MultipleAnalyticsApi.fromApis([\n * SomeAnalyticsApi.fromConfig(configApi),\n * new CustomAnalyticsApi(),\n * ]);\n * ```\n */\n static fromApis(actualApis: AnalyticsApi[]) {\n return new MultipleAnalyticsApi(actualApis);\n }\n\n /**\n * Forward the event to all configured analytics API implementations.\n */\n captureEvent(event: AnalyticsEvent): void {\n this.actualApis.forEach(analyticsApi => {\n try {\n analyticsApi.captureEvent(event);\n } catch {\n /* ignored */\n }\n });\n }\n}\n"],"names":[],"mappings":"AAqCO,MAAM,oBAAA,CAA6C;AAAA,EAChD,YAA6B,UAAA,EAA4B;AAA5B,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAAA,EAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAelE,OAAO,SAAS,UAAA,EAA4B;AAC1C,IAAA,OAAO,IAAI,qBAAqB,UAAU,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAA,EAA6B;AACxC,IAAA,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,YAAA,KAAgB;AACtC,MAAA,IAAI;AACF,QAAA,YAAA,CAAa,aAAa,KAAK,CAAA;AAAA,MACjC,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NoOpAnalyticsApi.esm.js","sources":["../../../../src/apis/implementations/AnalyticsApi/NoOpAnalyticsApi.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 */\nimport { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';\n\n/**\n * Base implementation for the AnalyticsApi that does nothing.\n *\n * @public\n */\nexport class NoOpAnalyticsApi implements AnalyticsApi {\n captureEvent(_event: AnalyticsEvent): void {}\n}\n"],"names":[],"mappings":"AAsBO,MAAM,gBAAyC,CAAA;AAAA,EACpD,aAAa,MAA8B,EAAA;AAAA;AAC7C;;;;"}
1
+ {"version":3,"file":"NoOpAnalyticsApi.esm.js","sources":["../../../../src/apis/implementations/AnalyticsApi/NoOpAnalyticsApi.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 */\nimport { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';\n\n/**\n * Base implementation for the AnalyticsApi that does nothing.\n *\n * @public\n */\nexport class NoOpAnalyticsApi implements AnalyticsApi {\n captureEvent(_event: AnalyticsEvent): void {}\n}\n"],"names":[],"mappings":"AAsBO,MAAM,gBAAA,CAAyC;AAAA,EACpD,aAAa,MAAA,EAA8B;AAAA,EAAC;AAC9C;;;;"}
@@ -13,9 +13,6 @@ class AppLanguageSelector {
13
13
  )}'`
14
14
  );
15
15
  }
16
- if (!languages.includes(DEFAULT_LANGUAGE)) {
17
- throw new Error(`Supported languages must include '${DEFAULT_LANGUAGE}'`);
18
- }
19
16
  const initialLanguage = options?.defaultLanguage ?? DEFAULT_LANGUAGE;
20
17
  if (!languages.includes(initialLanguage)) {
21
18
  throw new Error(
@@ -1 +1 @@
1
- {"version":3,"file":"AppLanguageSelector.esm.js","sources":["../../../../src/apis/implementations/AppLanguageApi/AppLanguageSelector.ts"],"sourcesContent":["/*\n * Copyright 2023 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\n// Internal import to avoid code duplication, this will lead to duplication in build output\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppLanguageApi } from '@backstage/core-plugin-api/alpha';\nimport { Observable } from '@backstage/types';\nimport { BehaviorSubject } from '../../../lib';\n\nconst STORAGE_KEY = 'language';\nexport const DEFAULT_LANGUAGE = 'en';\n\n/** @alpha */\nexport interface AppLanguageSelectorOptions {\n defaultLanguage?: string;\n availableLanguages?: string[];\n}\n\n/**\n * Exposes the available languages in the app and allows for switching of the active language.\n *\n * @alpha\n */\nexport class AppLanguageSelector implements AppLanguageApi {\n static create(options?: AppLanguageSelectorOptions) {\n const languages = options?.availableLanguages ?? [DEFAULT_LANGUAGE];\n if (languages.length !== new Set(languages).size) {\n throw new Error(\n `Supported languages may not contain duplicates, got '${languages.join(\n \"', '\",\n )}'`,\n );\n }\n if (!languages.includes(DEFAULT_LANGUAGE)) {\n throw new Error(`Supported languages must include '${DEFAULT_LANGUAGE}'`);\n }\n\n const initialLanguage = options?.defaultLanguage ?? DEFAULT_LANGUAGE;\n if (!languages.includes(initialLanguage)) {\n throw new Error(\n `Initial language must be one of the supported languages, got '${initialLanguage}'`,\n );\n }\n\n return new AppLanguageSelector(languages, initialLanguage);\n }\n\n static createWithStorage(options?: AppLanguageSelectorOptions) {\n const selector = AppLanguageSelector.create(options);\n\n if (!window.localStorage) {\n return selector;\n }\n\n const storedLanguage = window.localStorage.getItem(STORAGE_KEY);\n const { languages } = selector.getAvailableLanguages();\n if (storedLanguage && languages.includes(storedLanguage)) {\n selector.setLanguage(storedLanguage);\n }\n\n selector.language$().subscribe(({ language }) => {\n if (language !== window.localStorage.getItem(STORAGE_KEY)) {\n window.localStorage.setItem(STORAGE_KEY, language);\n }\n });\n\n window.addEventListener('storage', event => {\n if (event.key === STORAGE_KEY) {\n const language = localStorage.getItem(STORAGE_KEY) ?? undefined;\n if (language) {\n selector.setLanguage(language);\n }\n }\n });\n\n return selector;\n }\n\n #languages: string[];\n #language: string;\n #subject: BehaviorSubject<{ language: string }>;\n\n private constructor(languages: string[], initialLanguage: string) {\n this.#languages = languages;\n this.#language = initialLanguage;\n this.#subject = new BehaviorSubject<{ language: string }>({\n language: this.#language,\n });\n }\n\n getAvailableLanguages(): { languages: string[] } {\n return { languages: this.#languages.slice() };\n }\n\n setLanguage(language?: string | undefined): void {\n const lng = language ?? DEFAULT_LANGUAGE;\n if (lng === this.#language) {\n return;\n }\n if (lng && !this.#languages.includes(lng)) {\n throw new Error(\n `Failed to change language to '${lng}', available languages are '${this.#languages.join(\n \"', '\",\n )}'`,\n );\n }\n this.#language = lng;\n this.#subject.next({ language: lng });\n }\n\n getLanguage(): { language: string } {\n return { language: this.#language };\n }\n\n language$(): Observable<{ language: string }> {\n return this.#subject;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AppLanguageSelector.esm.js","sources":["../../../../src/apis/implementations/AppLanguageApi/AppLanguageSelector.ts"],"sourcesContent":["/*\n * Copyright 2023 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\n// Internal import to avoid code duplication, this will lead to duplication in build output\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppLanguageApi } from '@backstage/core-plugin-api/alpha';\nimport { Observable } from '@backstage/types';\nimport { BehaviorSubject } from '../../../lib';\n\nconst STORAGE_KEY = 'language';\nexport const DEFAULT_LANGUAGE = 'en';\n\n/** @alpha */\nexport interface AppLanguageSelectorOptions {\n defaultLanguage?: string;\n availableLanguages?: string[];\n}\n\n/**\n * Exposes the available languages in the app and allows for switching of the active language.\n *\n * @alpha\n */\nexport class AppLanguageSelector implements AppLanguageApi {\n static create(options?: AppLanguageSelectorOptions) {\n const languages = options?.availableLanguages ?? [DEFAULT_LANGUAGE];\n if (languages.length !== new Set(languages).size) {\n throw new Error(\n `Supported languages may not contain duplicates, got '${languages.join(\n \"', '\",\n )}'`,\n );\n }\n\n const initialLanguage = options?.defaultLanguage ?? DEFAULT_LANGUAGE;\n\n if (!languages.includes(initialLanguage)) {\n throw new Error(\n `Initial language must be one of the supported languages, got '${initialLanguage}'`,\n );\n }\n\n return new AppLanguageSelector(languages, initialLanguage);\n }\n\n static createWithStorage(options?: AppLanguageSelectorOptions) {\n const selector = AppLanguageSelector.create(options);\n\n if (!window.localStorage) {\n return selector;\n }\n\n const storedLanguage = window.localStorage.getItem(STORAGE_KEY);\n const { languages } = selector.getAvailableLanguages();\n if (storedLanguage && languages.includes(storedLanguage)) {\n selector.setLanguage(storedLanguage);\n }\n\n selector.language$().subscribe(({ language }) => {\n if (language !== window.localStorage.getItem(STORAGE_KEY)) {\n window.localStorage.setItem(STORAGE_KEY, language);\n }\n });\n\n window.addEventListener('storage', event => {\n if (event.key === STORAGE_KEY) {\n const language = localStorage.getItem(STORAGE_KEY) ?? undefined;\n if (language) {\n selector.setLanguage(language);\n }\n }\n });\n\n return selector;\n }\n\n #languages: string[];\n #language: string;\n #subject: BehaviorSubject<{ language: string }>;\n\n private constructor(languages: string[], initialLanguage: string) {\n this.#languages = languages;\n this.#language = initialLanguage;\n this.#subject = new BehaviorSubject<{ language: string }>({\n language: this.#language,\n });\n }\n\n getAvailableLanguages(): { languages: string[] } {\n return { languages: this.#languages.slice() };\n }\n\n setLanguage(language?: string | undefined): void {\n const lng = language ?? DEFAULT_LANGUAGE;\n if (lng === this.#language) {\n return;\n }\n if (lng && !this.#languages.includes(lng)) {\n throw new Error(\n `Failed to change language to '${lng}', available languages are '${this.#languages.join(\n \"', '\",\n )}'`,\n );\n }\n this.#language = lng;\n this.#subject.next({ language: lng });\n }\n\n getLanguage(): { language: string } {\n return { language: this.#language };\n }\n\n language$(): Observable<{ language: string }> {\n return this.#subject;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AppThemeSelector.esm.js","sources":["../../../../src/apis/implementations/AppThemeApi/AppThemeSelector.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 { AppThemeApi, AppTheme } from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { BehaviorSubject } from '../../../lib/subjects';\n\nconst STORAGE_KEY = 'theme';\n\n/**\n * Exposes the themes installed in the app, and permits switching the currently\n * active theme.\n *\n * @public\n */\nexport class AppThemeSelector implements AppThemeApi {\n static createWithStorage(themes: AppTheme[]) {\n const selector = new AppThemeSelector(themes);\n\n if (!window.localStorage) {\n return selector;\n }\n\n const initialThemeId =\n window.localStorage.getItem(STORAGE_KEY) ?? undefined;\n\n selector.setActiveThemeId(initialThemeId);\n\n selector.activeThemeId$().subscribe(themeId => {\n if (themeId) {\n window.localStorage.setItem(STORAGE_KEY, themeId);\n } else {\n window.localStorage.removeItem(STORAGE_KEY);\n }\n });\n\n window.addEventListener('storage', event => {\n if (event.key === STORAGE_KEY) {\n const themeId = localStorage.getItem(STORAGE_KEY) ?? undefined;\n selector.setActiveThemeId(themeId);\n }\n });\n\n return selector;\n }\n\n private activeThemeId: string | undefined;\n private readonly subject = new BehaviorSubject<string | undefined>(undefined);\n\n constructor(private readonly themes: AppTheme[]) {}\n\n getInstalledThemes(): AppTheme[] {\n return this.themes.slice();\n }\n\n activeThemeId$(): Observable<string | undefined> {\n return this.subject;\n }\n\n getActiveThemeId(): string | undefined {\n return this.activeThemeId;\n }\n\n setActiveThemeId(themeId?: string): void {\n this.activeThemeId = themeId;\n this.subject.next(themeId);\n }\n}\n"],"names":[],"mappings":";;AAoBA,MAAM,WAAc,GAAA,OAAA;AAQb,MAAM,gBAAwC,CAAA;AAAA,EAkCnD,YAA6B,MAAoB,EAAA;AAApB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAAqB,EAjClD,OAAO,kBAAkB,MAAoB,EAAA;AAC3C,IAAM,MAAA,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM,CAAA;AAE5C,IAAI,IAAA,CAAC,OAAO,YAAc,EAAA;AACxB,MAAO,OAAA,QAAA;AAAA;AAGT,IAAA,MAAM,cACJ,GAAA,MAAA,CAAO,YAAa,CAAA,OAAA,CAAQ,WAAW,CAAK,IAAA,KAAA,CAAA;AAE9C,IAAA,QAAA,CAAS,iBAAiB,cAAc,CAAA;AAExC,IAAS,QAAA,CAAA,cAAA,EAAiB,CAAA,SAAA,CAAU,CAAW,OAAA,KAAA;AAC7C,MAAA,IAAI,OAAS,EAAA;AACX,QAAO,MAAA,CAAA,YAAA,CAAa,OAAQ,CAAA,WAAA,EAAa,OAAO,CAAA;AAAA,OAC3C,MAAA;AACL,QAAO,MAAA,CAAA,YAAA,CAAa,WAAW,WAAW,CAAA;AAAA;AAC5C,KACD,CAAA;AAED,IAAO,MAAA,CAAA,gBAAA,CAAiB,WAAW,CAAS,KAAA,KAAA;AAC1C,MAAI,IAAA,KAAA,CAAM,QAAQ,WAAa,EAAA;AAC7B,QAAA,MAAM,OAAU,GAAA,YAAA,CAAa,OAAQ,CAAA,WAAW,CAAK,IAAA,KAAA,CAAA;AACrD,QAAA,QAAA,CAAS,iBAAiB,OAAO,CAAA;AAAA;AACnC,KACD,CAAA;AAED,IAAO,OAAA,QAAA;AAAA;AACT,EAEQ,aAAA;AAAA,EACS,OAAA,GAAU,IAAI,eAAA,CAAoC,KAAS,CAAA,CAAA;AAAA,EAI5E,kBAAiC,GAAA;AAC/B,IAAO,OAAA,IAAA,CAAK,OAAO,KAAM,EAAA;AAAA;AAC3B,EAEA,cAAiD,GAAA;AAC/C,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AACd,EAEA,gBAAuC,GAAA;AACrC,IAAA,OAAO,IAAK,CAAA,aAAA;AAAA;AACd,EAEA,iBAAiB,OAAwB,EAAA;AACvC,IAAA,IAAA,CAAK,aAAgB,GAAA,OAAA;AACrB,IAAK,IAAA,CAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA;AAE7B;;;;"}
1
+ {"version":3,"file":"AppThemeSelector.esm.js","sources":["../../../../src/apis/implementations/AppThemeApi/AppThemeSelector.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 { AppThemeApi, AppTheme } from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { BehaviorSubject } from '../../../lib/subjects';\n\nconst STORAGE_KEY = 'theme';\n\n/**\n * Exposes the themes installed in the app, and permits switching the currently\n * active theme.\n *\n * @public\n */\nexport class AppThemeSelector implements AppThemeApi {\n static createWithStorage(themes: AppTheme[]) {\n const selector = new AppThemeSelector(themes);\n\n if (!window.localStorage) {\n return selector;\n }\n\n const initialThemeId =\n window.localStorage.getItem(STORAGE_KEY) ?? undefined;\n\n selector.setActiveThemeId(initialThemeId);\n\n selector.activeThemeId$().subscribe(themeId => {\n if (themeId) {\n window.localStorage.setItem(STORAGE_KEY, themeId);\n } else {\n window.localStorage.removeItem(STORAGE_KEY);\n }\n });\n\n window.addEventListener('storage', event => {\n if (event.key === STORAGE_KEY) {\n const themeId = localStorage.getItem(STORAGE_KEY) ?? undefined;\n selector.setActiveThemeId(themeId);\n }\n });\n\n return selector;\n }\n\n private activeThemeId: string | undefined;\n private readonly subject = new BehaviorSubject<string | undefined>(undefined);\n\n constructor(private readonly themes: AppTheme[]) {}\n\n getInstalledThemes(): AppTheme[] {\n return this.themes.slice();\n }\n\n activeThemeId$(): Observable<string | undefined> {\n return this.subject;\n }\n\n getActiveThemeId(): string | undefined {\n return this.activeThemeId;\n }\n\n setActiveThemeId(themeId?: string): void {\n this.activeThemeId = themeId;\n this.subject.next(themeId);\n }\n}\n"],"names":[],"mappings":";;AAoBA,MAAM,WAAA,GAAc,OAAA;AAQb,MAAM,gBAAA,CAAwC;AAAA,EAkCnD,YAA6B,MAAA,EAAoB;AAApB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAAqB;AAAA,EAjClD,OAAO,kBAAkB,MAAA,EAAoB;AAC3C,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM,CAAA;AAE5C,IAAA,IAAI,CAAC,OAAO,YAAA,EAAc;AACxB,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAA,GACJ,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA,IAAK,MAAA;AAE9C,IAAA,QAAA,CAAS,iBAAiB,cAAc,CAAA;AAExC,IAAA,QAAA,CAAS,cAAA,EAAe,CAAE,SAAA,CAAU,CAAA,OAAA,KAAW;AAC7C,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,WAAA,EAAa,OAAO,CAAA;AAAA,MAClD,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,YAAA,CAAa,WAAW,WAAW,CAAA;AAAA,MAC5C;AAAA,IACF,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,CAAA,KAAA,KAAS;AAC1C,MAAA,IAAI,KAAA,CAAM,QAAQ,WAAA,EAAa;AAC7B,QAAA,MAAM,OAAA,GAAU,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA,IAAK,MAAA;AACrD,QAAA,QAAA,CAAS,iBAAiB,OAAO,CAAA;AAAA,MACnC;AAAA,IACF,CAAC,CAAA;AAED,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEQ,aAAA;AAAA,EACS,OAAA,GAAU,IAAI,eAAA,CAAoC,MAAS,CAAA;AAAA,EAI5E,kBAAA,GAAiC;AAC/B,IAAA,OAAO,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,EAC3B;AAAA,EAEA,cAAA,GAAiD;AAC/C,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA,EAEA,gBAAA,GAAuC;AACrC,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,EACd;AAAA,EAEA,iBAAiB,OAAA,EAAwB;AACvC,IAAA,IAAA,CAAK,aAAA,GAAgB,OAAA;AACrB,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA,EAC3B;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"FrontendHostDiscovery.esm.js","sources":["../../../../src/apis/implementations/DiscoveryApi/FrontendHostDiscovery.ts"],"sourcesContent":["/*\n * Copyright 2023 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 */\nimport { Config } from '@backstage/config';\nimport { DiscoveryApi } from '@backstage/core-plugin-api';\nimport { UrlPatternDiscovery } from './UrlPatternDiscovery';\n\n/**\n * FrontendHostDiscovery is a config driven DiscoveryApi implementation.\n * It uses the app-config to determine the url for a plugin.\n *\n * @public\n */\nexport class FrontendHostDiscovery implements DiscoveryApi {\n /**\n * Creates a new FrontendHostDiscovery discovery instance by reading\n * the external target URL from the `discovery.endpoints` config section.\n *\n * eg.\n * ```yaml\n * discovery:\n * endpoints:\n * - target: https://internal.example.com/internal-catalog\n * plugins: [catalog]\n * - target: https://internal.example.com/secure/api/{{pluginId}}\n * plugins: [auth, permissions]\n * - target:\n * internal: https://internal.example.com/search\n * external: https://example.com/search\n * plugins: [search]\n * ```\n *\n * If a plugin is not declared in the config, the discovery will fall back to using the baseUrl with\n * the provided `pathPattern` appended. The default path pattern is `\"/api/{{ pluginId }}\"`.\n */\n static fromConfig(config: Config, options?: { pathPattern?: string }) {\n const path = options?.pathPattern ?? '/api/{{ pluginId }}';\n const baseUrl = config.getString('backend.baseUrl');\n\n const endpoints = config\n .getOptionalConfigArray('discovery.endpoints')\n ?.flatMap(e => {\n const target =\n typeof e.get('target') === 'object'\n ? e.getOptionalString('target.external')\n : e.getString('target');\n if (!target) {\n return [];\n }\n const discovery = UrlPatternDiscovery.compile(target);\n return e\n .getStringArray('plugins')\n .map(pluginId => [pluginId, discovery] as const);\n });\n\n return new FrontendHostDiscovery(\n new Map(endpoints),\n UrlPatternDiscovery.compile(`${baseUrl}${path}`),\n );\n }\n\n private constructor(\n private readonly endpoints: Map<string, DiscoveryApi>,\n private readonly defaultEndpoint: DiscoveryApi,\n ) {}\n\n async getBaseUrl(pluginId: string): Promise<string> {\n const endpoint = this.endpoints.get(pluginId);\n if (endpoint) {\n return endpoint.getBaseUrl(pluginId);\n }\n return this.defaultEndpoint.getBaseUrl(pluginId);\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAM,qBAA8C,CAAA;AAAA,EAgDjD,WAAA,CACW,WACA,eACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA;AAAA;AAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA7BH,OAAO,UAAW,CAAA,MAAA,EAAgB,OAAoC,EAAA;AACpE,IAAM,MAAA,IAAA,GAAO,SAAS,WAAe,IAAA,qBAAA;AACrC,IAAM,MAAA,OAAA,GAAU,MAAO,CAAA,SAAA,CAAU,iBAAiB,CAAA;AAElD,IAAA,MAAM,YAAY,MACf,CAAA,sBAAA,CAAuB,qBAAqB,CAAA,EAC3C,QAAQ,CAAK,CAAA,KAAA;AACb,MAAA,MAAM,MACJ,GAAA,OAAO,CAAE,CAAA,GAAA,CAAI,QAAQ,CAAA,KAAM,QACvB,GAAA,CAAA,CAAE,iBAAkB,CAAA,iBAAiB,CACrC,GAAA,CAAA,CAAE,UAAU,QAAQ,CAAA;AAC1B,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAA,OAAO,EAAC;AAAA;AAEV,MAAM,MAAA,SAAA,GAAY,mBAAoB,CAAA,OAAA,CAAQ,MAAM,CAAA;AACpD,MAAO,OAAA,CAAA,CACJ,eAAe,SAAS,CAAA,CACxB,IAAI,CAAY,QAAA,KAAA,CAAC,QAAU,EAAA,SAAS,CAAU,CAAA;AAAA,KAClD,CAAA;AAEH,IAAA,OAAO,IAAI,qBAAA;AAAA,MACT,IAAI,IAAI,SAAS,CAAA;AAAA,MACjB,oBAAoB,OAAQ,CAAA,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAE,CAAA;AAAA,KACjD;AAAA;AACF,EAOA,MAAM,WAAW,QAAmC,EAAA;AAClD,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,SAAU,CAAA,GAAA,CAAI,QAAQ,CAAA;AAC5C,IAAA,IAAI,QAAU,EAAA;AACZ,MAAO,OAAA,QAAA,CAAS,WAAW,QAAQ,CAAA;AAAA;AAErC,IAAO,OAAA,IAAA,CAAK,eAAgB,CAAA,UAAA,CAAW,QAAQ,CAAA;AAAA;AAEnD;;;;"}
1
+ {"version":3,"file":"FrontendHostDiscovery.esm.js","sources":["../../../../src/apis/implementations/DiscoveryApi/FrontendHostDiscovery.ts"],"sourcesContent":["/*\n * Copyright 2023 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 */\nimport { Config } from '@backstage/config';\nimport { DiscoveryApi } from '@backstage/core-plugin-api';\nimport { UrlPatternDiscovery } from './UrlPatternDiscovery';\n\n/**\n * FrontendHostDiscovery is a config driven DiscoveryApi implementation.\n * It uses the app-config to determine the url for a plugin.\n *\n * @public\n */\nexport class FrontendHostDiscovery implements DiscoveryApi {\n /**\n * Creates a new FrontendHostDiscovery discovery instance by reading\n * the external target URL from the `discovery.endpoints` config section.\n *\n * eg.\n * ```yaml\n * discovery:\n * endpoints:\n * - target: https://internal.example.com/internal-catalog\n * plugins: [catalog]\n * - target: https://internal.example.com/secure/api/{{pluginId}}\n * plugins: [auth, permissions]\n * - target:\n * internal: https://internal.example.com/search\n * external: https://example.com/search\n * plugins: [search]\n * ```\n *\n * If a plugin is not declared in the config, the discovery will fall back to using the baseUrl with\n * the provided `pathPattern` appended. The default path pattern is `\"/api/{{ pluginId }}\"`.\n */\n static fromConfig(config: Config, options?: { pathPattern?: string }) {\n const path = options?.pathPattern ?? '/api/{{ pluginId }}';\n const baseUrl = config.getString('backend.baseUrl');\n\n const endpoints = config\n .getOptionalConfigArray('discovery.endpoints')\n ?.flatMap(e => {\n const target =\n typeof e.get('target') === 'object'\n ? e.getOptionalString('target.external')\n : e.getString('target');\n if (!target) {\n return [];\n }\n const discovery = UrlPatternDiscovery.compile(target);\n return e\n .getStringArray('plugins')\n .map(pluginId => [pluginId, discovery] as const);\n });\n\n return new FrontendHostDiscovery(\n new Map(endpoints),\n UrlPatternDiscovery.compile(`${baseUrl}${path}`),\n );\n }\n\n private constructor(\n private readonly endpoints: Map<string, DiscoveryApi>,\n private readonly defaultEndpoint: DiscoveryApi,\n ) {}\n\n async getBaseUrl(pluginId: string): Promise<string> {\n const endpoint = this.endpoints.get(pluginId);\n if (endpoint) {\n return endpoint.getBaseUrl(pluginId);\n }\n return this.defaultEndpoint.getBaseUrl(pluginId);\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAM,qBAAA,CAA8C;AAAA,EAgDjD,WAAA,CACW,WACA,eAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA7BH,OAAO,UAAA,CAAW,MAAA,EAAgB,OAAA,EAAoC;AACpE,IAAA,MAAM,IAAA,GAAO,SAAS,WAAA,IAAe,qBAAA;AACrC,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,SAAA,CAAU,iBAAiB,CAAA;AAElD,IAAA,MAAM,YAAY,MAAA,CACf,sBAAA,CAAuB,qBAAqB,CAAA,EAC3C,QAAQ,CAAA,CAAA,KAAK;AACb,MAAA,MAAM,MAAA,GACJ,OAAO,CAAA,CAAE,GAAA,CAAI,QAAQ,CAAA,KAAM,QAAA,GACvB,CAAA,CAAE,iBAAA,CAAkB,iBAAiB,CAAA,GACrC,CAAA,CAAE,UAAU,QAAQ,CAAA;AAC1B,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO,EAAC;AAAA,MACV;AACA,MAAA,MAAM,SAAA,GAAY,mBAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AACpD,MAAA,OAAO,CAAA,CACJ,eAAe,SAAS,CAAA,CACxB,IAAI,CAAA,QAAA,KAAY,CAAC,QAAA,EAAU,SAAS,CAAU,CAAA;AAAA,IACnD,CAAC,CAAA;AAEH,IAAA,OAAO,IAAI,qBAAA;AAAA,MACT,IAAI,IAAI,SAAS,CAAA;AAAA,MACjB,oBAAoB,OAAA,CAAQ,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAA,CAAE;AAAA,KACjD;AAAA,EACF;AAAA,EAOA,MAAM,WAAW,QAAA,EAAmC;AAClD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAQ,CAAA;AAC5C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,OAAO,QAAA,CAAS,WAAW,QAAQ,CAAA;AAAA,IACrC;AACA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,UAAA,CAAW,QAAQ,CAAA;AAAA,EACjD;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"UrlPatternDiscovery.esm.js","sources":["../../../../src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.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 { DiscoveryApi } from '@backstage/core-plugin-api';\n\nconst ERROR_PREFIX = 'Invalid discovery URL pattern,';\n\n/**\n * UrlPatternDiscovery is a lightweight DiscoveryApi implementation.\n * It uses a single template string to construct URLs for each plugin.\n *\n * @public\n */\nexport class UrlPatternDiscovery implements DiscoveryApi {\n /**\n * Creates a new UrlPatternDiscovery given a template. The only\n * interpolation done for the template is to replace instances of `{{pluginId}}`\n * with the ID of the plugin being requested.\n *\n * Example pattern: `http://localhost:7007/api/{{ pluginId }}`\n */\n static compile(pattern: string): UrlPatternDiscovery {\n const parts = pattern.split(/\\{\\{\\s*pluginId\\s*\\}\\}/);\n const urlStr = parts.join('pluginId');\n\n let url;\n try {\n url = new URL(urlStr);\n } catch {\n throw new Error(`${ERROR_PREFIX} URL '${urlStr}' is invalid`);\n }\n if (url.hash) {\n throw new Error(`${ERROR_PREFIX} URL must not have a hash`);\n }\n if (url.search) {\n throw new Error(`${ERROR_PREFIX} URL must not have a query`);\n }\n if (urlStr.endsWith('/')) {\n throw new Error(`${ERROR_PREFIX} URL must not end with a slash`);\n }\n\n return new UrlPatternDiscovery(parts);\n }\n\n private constructor(private readonly parts: string[]) {}\n\n async getBaseUrl(pluginId: string): Promise<string> {\n return this.parts.join(encodeURIComponent(pluginId));\n }\n}\n"],"names":[],"mappings":"AAkBA,MAAM,YAAe,GAAA,gCAAA;AAQd,MAAM,mBAA4C,CAAA;AAAA,EA+B/C,YAA6B,KAAiB,EAAA;AAAjB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA;AAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAvBvD,OAAO,QAAQ,OAAsC,EAAA;AACnD,IAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,wBAAwB,CAAA;AACpD,IAAM,MAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,UAAU,CAAA;AAEpC,IAAI,IAAA,GAAA;AACJ,IAAI,IAAA;AACF,MAAM,GAAA,GAAA,IAAI,IAAI,MAAM,CAAA;AAAA,KACd,CAAA,MAAA;AACN,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,EAAG,YAAY,CAAA,MAAA,EAAS,MAAM,CAAc,YAAA,CAAA,CAAA;AAAA;AAE9D,IAAA,IAAI,IAAI,IAAM,EAAA;AACZ,MAAA,MAAM,IAAI,KAAA,CAAM,CAAG,EAAA,YAAY,CAA2B,yBAAA,CAAA,CAAA;AAAA;AAE5D,IAAA,IAAI,IAAI,MAAQ,EAAA;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAG,EAAA,YAAY,CAA4B,0BAAA,CAAA,CAAA;AAAA;AAE7D,IAAI,IAAA,MAAA,CAAO,QAAS,CAAA,GAAG,CAAG,EAAA;AACxB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAG,EAAA,YAAY,CAAgC,8BAAA,CAAA,CAAA;AAAA;AAGjE,IAAO,OAAA,IAAI,oBAAoB,KAAK,CAAA;AAAA;AACtC,EAIA,MAAM,WAAW,QAAmC,EAAA;AAClD,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,kBAAA,CAAmB,QAAQ,CAAC,CAAA;AAAA;AAEvD;;;;"}
1
+ {"version":3,"file":"UrlPatternDiscovery.esm.js","sources":["../../../../src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.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 { DiscoveryApi } from '@backstage/core-plugin-api';\n\nconst ERROR_PREFIX = 'Invalid discovery URL pattern,';\n\n/**\n * UrlPatternDiscovery is a lightweight DiscoveryApi implementation.\n * It uses a single template string to construct URLs for each plugin.\n *\n * @public\n */\nexport class UrlPatternDiscovery implements DiscoveryApi {\n /**\n * Creates a new UrlPatternDiscovery given a template. The only\n * interpolation done for the template is to replace instances of `{{pluginId}}`\n * with the ID of the plugin being requested.\n *\n * Example pattern: `http://localhost:7007/api/{{ pluginId }}`\n */\n static compile(pattern: string): UrlPatternDiscovery {\n const parts = pattern.split(/\\{\\{\\s*pluginId\\s*\\}\\}/);\n const urlStr = parts.join('pluginId');\n\n let url;\n try {\n url = new URL(urlStr);\n } catch {\n throw new Error(`${ERROR_PREFIX} URL '${urlStr}' is invalid`);\n }\n if (url.hash) {\n throw new Error(`${ERROR_PREFIX} URL must not have a hash`);\n }\n if (url.search) {\n throw new Error(`${ERROR_PREFIX} URL must not have a query`);\n }\n if (urlStr.endsWith('/')) {\n throw new Error(`${ERROR_PREFIX} URL must not end with a slash`);\n }\n\n return new UrlPatternDiscovery(parts);\n }\n\n private constructor(private readonly parts: string[]) {}\n\n async getBaseUrl(pluginId: string): Promise<string> {\n return this.parts.join(encodeURIComponent(pluginId));\n }\n}\n"],"names":[],"mappings":"AAkBA,MAAM,YAAA,GAAe,gCAAA;AAQd,MAAM,mBAAA,CAA4C;AAAA,EA+B/C,YAA6B,KAAA,EAAiB;AAAjB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA,EAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAvBvD,OAAO,QAAQ,OAAA,EAAsC;AACnD,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,wBAAwB,CAAA;AACpD,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,UAAU,CAAA;AAEpC,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,IAAI,IAAI,MAAM,CAAA;AAAA,IACtB,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,MAAA,EAAS,MAAM,CAAA,YAAA,CAAc,CAAA;AAAA,IAC9D;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACZ,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,yBAAA,CAA2B,CAAA;AAAA,IAC5D;AACA,IAAA,IAAI,IAAI,MAAA,EAAQ;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,0BAAA,CAA4B,CAAA;AAAA,IAC7D;AACA,IAAA,IAAI,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AACxB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,8BAAA,CAAgC,CAAA;AAAA,IACjE;AAEA,IAAA,OAAO,IAAI,oBAAoB,KAAK,CAAA;AAAA,EACtC;AAAA,EAIA,MAAM,WAAW,QAAA,EAAmC;AAClD,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,kBAAA,CAAmB,QAAQ,CAAC,CAAA;AAAA,EACrD;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorAlerter.esm.js","sources":["../../../../src/apis/implementations/ErrorApi/ErrorAlerter.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 */\nimport {\n ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n AlertApi,\n} from '@backstage/core-plugin-api';\n\n/**\n * Decorates an ErrorApi by also forwarding error messages\n * to the alertApi with an 'error' severity.\n *\n * @public\n */\nexport class ErrorAlerter implements ErrorApi {\n constructor(\n private readonly alertApi: AlertApi,\n private readonly errorApi: ErrorApi,\n ) {}\n\n post(error: ErrorApiError, context?: ErrorApiErrorContext) {\n if (!context?.hidden) {\n this.alertApi.post({ message: error.message, severity: 'error' });\n }\n\n return this.errorApi.post(error, context);\n }\n\n error$() {\n return this.errorApi.error$();\n }\n}\n"],"names":[],"mappings":"AA4BO,MAAM,YAAiC,CAAA;AAAA,EAC5C,WAAA,CACmB,UACA,QACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA;AAChB,EAEH,IAAA,CAAK,OAAsB,OAAgC,EAAA;AACzD,IAAI,IAAA,CAAC,SAAS,MAAQ,EAAA;AACpB,MAAK,IAAA,CAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,MAAM,OAAS,EAAA,QAAA,EAAU,SAAS,CAAA;AAAA;AAGlE,IAAA,OAAO,IAAK,CAAA,QAAA,CAAS,IAAK,CAAA,KAAA,EAAO,OAAO,CAAA;AAAA;AAC1C,EAEA,MAAS,GAAA;AACP,IAAO,OAAA,IAAA,CAAK,SAAS,MAAO,EAAA;AAAA;AAEhC;;;;"}
1
+ {"version":3,"file":"ErrorAlerter.esm.js","sources":["../../../../src/apis/implementations/ErrorApi/ErrorAlerter.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 */\nimport {\n ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n AlertApi,\n} from '@backstage/core-plugin-api';\n\n/**\n * Decorates an ErrorApi by also forwarding error messages\n * to the alertApi with an 'error' severity.\n *\n * @public\n */\nexport class ErrorAlerter implements ErrorApi {\n constructor(\n private readonly alertApi: AlertApi,\n private readonly errorApi: ErrorApi,\n ) {}\n\n post(error: ErrorApiError, context?: ErrorApiErrorContext) {\n if (!context?.hidden) {\n this.alertApi.post({ message: error.message, severity: 'error' });\n }\n\n return this.errorApi.post(error, context);\n }\n\n error$() {\n return this.errorApi.error$();\n }\n}\n"],"names":[],"mappings":"AA4BO,MAAM,YAAA,CAAiC;AAAA,EAC5C,WAAA,CACmB,UACA,QAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAChB;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAA,EAAgC;AACzD,IAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AACpB,MAAA,IAAA,CAAK,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,MAAM,OAAA,EAAS,QAAA,EAAU,SAAS,CAAA;AAAA,IAClE;AAEA,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,KAAA,EAAO,OAAO,CAAA;AAAA,EAC1C;AAAA,EAEA,MAAA,GAAS;AACP,IAAA,OAAO,IAAA,CAAK,SAAS,MAAA,EAAO;AAAA,EAC9B;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorApiForwarder.esm.js","sources":["../../../../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;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAgC,EAAA;AACzD,IAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,EAAE,KAAA,EAAO,SAAS,CAAA;AAAA;AACtC,EAEA,MAAuE,GAAA;AACrE,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AAEhB;;;;"}
1
+ {"version":3,"file":"ErrorApiForwarder.esm.js","sources":["../../../../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,iBAAA,CAAsC;AAAA,EAChC,OAAA,GAAU,IAAI,cAAA,EAG5B;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAA,EAAgC;AACzD,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,SAAS,CAAA;AAAA,EACtC;AAAA,EAEA,MAAA,GAAuE;AACrE,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"UnhandledErrorForwarder.esm.js","sources":["../../../../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;AAAA;AACvD,KACF;AAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"UnhandledErrorForwarder.esm.js","sources":["../../../../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,uBAAA,CAAwB;AAAA;AAAA;AAAA;AAAA,EAInC,OAAO,OAAA,CAAQ,QAAA,EAAoB,YAAA,EAAoC;AACrE,IAAA,MAAA,CAAO,gBAAA;AAAA,MACL,oBAAA;AAAA,MACA,CAAC,CAAA,KAA6B;AAC5B,QAAA,QAAA,CAAS,IAAA,CAAK,CAAA,CAAE,MAAA,EAAyB,YAAY,CAAA;AAAA,MACvD;AAAA,KACF;AAAA,EACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorageFeatureFlags.esm.js","sources":["../../../../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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"}
1
+ {"version":3,"file":"LocalStorageFeatureFlags.esm.js","sources":["../../../../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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FetchMiddlewares.esm.js","sources":["../../../../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;AAAA;AACvE;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;AAAA;AAC3D,EAEQ,WAAc,GAAA;AAAA;AACxB;;;;"}
1
+ {"version":3,"file":"FetchMiddlewares.esm.js","sources":["../../../../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,gBAAA,CAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe5B,OAAO,sBAAsB,OAAA,EAET;AAClB,IAAA,OAAO,IAAI,qCAAA,CAAsC,OAAA,CAAQ,YAAY,CAAA;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,OAAO,mBAAmB,OAAA,EASN;AAClB,IAAA,OAAO,mCAAA,CAAoC,OAAO,OAAO,CAAA;AAAA,EAC3D;AAAA,EAEQ,WAAA,GAAc;AAAA,EAAC;AACzB;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"IdentityAuthInjectorFetchMiddleware.esm.js","sources":["../../../../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 /**\n * Returns an array of plugin URL prefixes derived from the static `discovery`\n * configuration, to be used as `urlPrefixAllowlist` option of {@link create}.\n */\n static getDiscoveryUrlPrefixes(config: Config): string[] {\n const endpointConfigs =\n config.getOptionalConfigArray('discovery.endpoints') || [];\n return endpointConfigs.flatMap(c => {\n const target =\n typeof c.get('target') === 'object'\n ? c.getString('target.external')\n : c.getString('target');\n const plugins = c.getStringArray('plugins');\n return plugins.map(pluginId =>\n target.replace(/\\{\\{\\s*pluginId\\s*\\}\\}/g, pluginId),\n );\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([\n options.config.getString('backend.baseUrl'),\n ...IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(\n options.config,\n ),\n ]);\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":"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"}
1
+ {"version":3,"file":"IdentityAuthInjectorFetchMiddleware.esm.js","sources":["../../../../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 /**\n * Returns an array of plugin URL prefixes derived from the static `discovery`\n * configuration, to be used as `urlPrefixAllowlist` option of {@link create}.\n */\n static getDiscoveryUrlPrefixes(config: Config): string[] {\n const endpointConfigs =\n config.getOptionalConfigArray('discovery.endpoints') || [];\n return endpointConfigs.flatMap(c => {\n const target =\n typeof c.get('target') === 'object'\n ? c.getString('target.external')\n : c.getString('target');\n const plugins = c.getStringArray('plugins');\n return plugins.map(pluginId =>\n target.replace(/\\{\\{\\s*pluginId\\s*\\}\\}/g, pluginId),\n );\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([\n options.config.getString('backend.baseUrl'),\n ...IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(\n options.config,\n ),\n ]);\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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PluginProtocolResolverFetchMiddleware.esm.js","sources":["../../../../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;AAAA;AAGT,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;AAC/D;AAMO,MAAM,qCAAiE,CAAA;AAAA,EAC5E,YAA6B,YAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AAAA;AAA6B,EAE1D,MAAM,IAAkC,EAAA;AACtC,IAAO,OAAA,OAAO,OAAO,IAAS,KAAA;AAK5B,MAAA,MAAM,OAAU,GAAA,IAAI,OAAQ,CAAA,KAAA,EAAc,IAAI,CAAA;AAC9C,MAAA,MAAM,MAAS,GAAA,WAAA;AAEf,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAI,CAAA,UAAA,CAAW,MAAM,CAAG,EAAA;AACnC,QAAO,OAAA,IAAA,CAAK,OAAc,IAAI,CAAA;AAAA;AAKhC,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;AAAA,OAChD;AAEA,MAAA,IAAI,IAAO,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA;AACtD,MAAA,IAAI,YAAY,QAAU,EAAA;AACxB,QAAM,MAAA,OAAA,GAAU,IAAI,GAAA,CAAI,IAAI,CAAA;AAC5B,QAAM,MAAA,SAAA,GAAY,GAAG,QAAQ,CAAA,EAAG,WAAW,CAAI,CAAA,EAAA,QAAQ,KAAK,EAAE,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;AAAA;AAG5E,MAAM,MAAA,MAAA,GAAS,GAAG,IAAK,CAAA,IAAA,EAAM,QAAQ,CAAC,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAA;AACtD,MAAO,OAAA,IAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAO,KAAU,KAAA,QAAA,IAAY,KAAM,CAAA,KAAK,IAAI,IAAQ,GAAA;AAAA,OACtD;AAAA,KACF;AAAA;AAEJ;AAEA,SAAS,MAAM,CAAsB,EAAA;AACnC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAY,IAAA,CAAA,EAAG,WAAgB,KAAA,GAAA;AACrD;;;;"}
1
+ {"version":3,"file":"PluginProtocolResolverFetchMiddleware.esm.js","sources":["../../../../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,KAAA,EAAuB;AACjD,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,KAAU,GAAA,EAAK;AAC3B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA;AAC/D;AAMO,MAAM,qCAAA,CAAiE;AAAA,EAC5E,YAA6B,YAAA,EAA4B;AAA5B,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AAAA,EAA6B;AAAA,EAE1D,MAAM,IAAA,EAAkC;AACtC,IAAA,OAAO,OAAO,OAAO,IAAA,KAAS;AAK5B,MAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,KAAA,EAAc,IAAI,CAAA;AAC9C,MAAA,MAAM,MAAA,GAAS,WAAA;AAEf,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,UAAA,CAAW,MAAM,CAAA,EAAG;AACnC,QAAA,OAAO,IAAA,CAAK,OAAc,IAAI,CAAA;AAAA,MAChC;AAIA,MAAA,MAAM,EAAE,UAAU,QAAA,EAAU,MAAA,EAAQ,MAAM,QAAA,EAAU,QAAA,KAAa,IAAI,GAAA;AAAA,QACnE,UAAU,OAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,MAAA,CAAO,MAAM,CAAC,CAAA;AAAA,OAChD;AAEA,MAAA,IAAI,IAAA,GAAO,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AACtD,MAAA,IAAI,YAAY,QAAA,EAAU;AACxB,QAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAI,CAAA;AAC5B,QAAA,MAAM,SAAA,GAAY,GAAG,QAAQ,CAAA,EAAG,WAAW,CAAA,CAAA,EAAI,QAAQ,KAAK,EAAE,CAAA,CAAA,CAAA;AAC9D,QAAA,IAAA,GAAO,CAAA,EAAG,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK,SAAS,GAAG,OAAA,CAAQ,IAAI,CAAA,EAAG,OAAA,CAAQ,QAAQ,CAAA,CAAA;AAAA,MAC5E;AAEA,MAAA,MAAM,MAAA,GAAS,GAAG,IAAA,CAAK,IAAA,EAAM,QAAQ,CAAC,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAA;AACtD,MAAA,OAAO,IAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,KAAK,IAAI,IAAA,GAAQ;AAAA,OACtD;AAAA,IACF,CAAA;AAAA,EACF;AACF;AAEA,SAAS,MAAM,CAAA,EAAsB;AACnC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,EAAG,WAAA,KAAgB,GAAA;AACrD;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createFetchApi.esm.js","sources":["../../../../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;AAElD,EAAM,MAAA,UAAA,GAAa,CAAC,OAAQ,CAAA,UAAA,IAAc,EAAE,CAAA,CAAE,IAAK,EAAA,CAAE,OAAQ,EAAA;AAC7D,EAAA,KAAA,MAAW,KAAK,UAAY,EAAA;AAC1B,IAAS,MAAA,GAAA,CAAA,CAAE,MAAM,MAAM,CAAA;AAAA;AAGzB,EAAO,OAAA;AAAA,IACL,KAAO,EAAA;AAAA,GACT;AACF;;;;"}
1
+ {"version":3,"file":"createFetchApi.esm.js","sources":["../../../../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,OAAA,EAGlB;AACX,EAAA,IAAI,MAAA,GAAS,OAAA,CAAQ,kBAAA,IAAsB,MAAA,CAAO,KAAA;AAElD,EAAA,MAAM,UAAA,GAAa,CAAC,OAAA,CAAQ,UAAA,IAAc,EAAE,CAAA,CAAE,IAAA,EAAK,CAAE,OAAA,EAAQ;AAC7D,EAAA,KAAA,MAAW,KAAK,UAAA,EAAY;AAC1B,IAAA,MAAA,GAAS,CAAA,CAAE,MAAM,MAAM,CAAA;AAAA,EACzB;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO;AAAA,GACT;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AppIdentityProxy.esm.js","sources":["../../../../src/apis/implementations/IdentityApi/AppIdentityProxy.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 IdentityApi,\n ProfileInfo,\n BackstageUserIdentity,\n ErrorApi,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { startCookieAuthRefresh } from './startCookieAuthRefresh';\n\nfunction mkError(thing: string) {\n return new Error(\n `Tried to access IdentityApi ${thing} before app was loaded`,\n );\n}\n\nfunction logDeprecation(thing: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: Call to ${thing} is deprecated and will break in the future`,\n );\n}\n\n// We use this for a period of backwards compatibility. It is a hidden\n// compatibility that will allow old plugins to continue working for a limited time.\ntype CompatibilityIdentityApi = IdentityApi & {\n getUserId?(): string;\n getIdToken?(): Promise<string | undefined>;\n getProfile?(): ProfileInfo;\n};\n\n/**\n * Implementation of the connection between the App-wide IdentityApi\n * and sign-in page.\n */\nexport class AppIdentityProxy implements IdentityApi {\n private target?: CompatibilityIdentityApi;\n private waitForTarget: Promise<CompatibilityIdentityApi>;\n private resolveTarget: (api: CompatibilityIdentityApi) => void = () => {};\n private signOutTargetUrl = '/';\n\n #cookieAuthSignOut?: () => Promise<void>;\n\n constructor() {\n this.waitForTarget = new Promise<CompatibilityIdentityApi>(resolve => {\n this.resolveTarget = resolve;\n });\n }\n\n // This is called by the app manager once the sign-in page provides us with an implementation\n setTarget(\n identityApi: CompatibilityIdentityApi,\n targetOptions: { signOutTargetUrl: string },\n ) {\n this.target = identityApi;\n this.signOutTargetUrl = targetOptions.signOutTargetUrl;\n this.resolveTarget(identityApi);\n }\n\n getUserId(): string {\n if (!this.target) {\n throw mkError('getUserId');\n }\n if (!this.target.getUserId) {\n throw new Error('IdentityApi does not implement getUserId');\n }\n logDeprecation('getUserId');\n return this.target.getUserId();\n }\n\n getProfile(): ProfileInfo {\n if (!this.target) {\n throw mkError('getProfile');\n }\n if (!this.target.getProfile) {\n throw new Error('IdentityApi does not implement getProfile');\n }\n logDeprecation('getProfile');\n return this.target.getProfile();\n }\n\n async getProfileInfo(): Promise<ProfileInfo> {\n return this.waitForTarget.then(target => target.getProfileInfo());\n }\n\n async getBackstageIdentity(): Promise<BackstageUserIdentity> {\n const identity = await this.waitForTarget.then(target =>\n target.getBackstageIdentity(),\n );\n if (!identity.userEntityRef.match(/^.*:.*\\/.*$/)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The App IdentityApi provided an invalid userEntityRef, '${identity.userEntityRef}'. ` +\n `It must be a full Entity Reference of the form '<kind>:<namespace>/<name>'.`,\n );\n }\n\n return identity;\n }\n\n async getCredentials(): Promise<{ token?: string | undefined }> {\n return this.waitForTarget.then(target => target.getCredentials());\n }\n\n async getIdToken(): Promise<string | undefined> {\n return this.waitForTarget.then(target => {\n if (!target.getIdToken) {\n throw new Error('IdentityApi does not implement getIdToken');\n }\n logDeprecation('getIdToken');\n return target.getIdToken();\n });\n }\n\n async signOut(): Promise<void> {\n await this.waitForTarget.then(target => target.signOut());\n\n await this.#cookieAuthSignOut?.();\n\n window.location.href = this.signOutTargetUrl;\n }\n\n enableCookieAuth(ctx: {\n errorApi: ErrorApi;\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n }) {\n if (this.#cookieAuthSignOut) {\n return;\n }\n\n const stopRefresh = startCookieAuthRefresh(ctx);\n\n this.#cookieAuthSignOut = async () => {\n stopRefresh();\n\n // It is fine if we do NOT worry yet about deleting cookies for OTHER backends like techdocs\n const appBaseUrl = await ctx.discoveryApi.getBaseUrl('app');\n try {\n await fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, {\n method: 'DELETE',\n credentials: 'include',\n });\n } catch {\n // Ignore the error for those who use static serving of the frontend\n }\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AppIdentityProxy.esm.js","sources":["../../../../src/apis/implementations/IdentityApi/AppIdentityProxy.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 IdentityApi,\n ProfileInfo,\n BackstageUserIdentity,\n ErrorApi,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { startCookieAuthRefresh } from './startCookieAuthRefresh';\n\nfunction mkError(thing: string) {\n return new Error(\n `Tried to access IdentityApi ${thing} before app was loaded`,\n );\n}\n\nfunction logDeprecation(thing: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: Call to ${thing} is deprecated and will break in the future`,\n );\n}\n\n// We use this for a period of backwards compatibility. It is a hidden\n// compatibility that will allow old plugins to continue working for a limited time.\ntype CompatibilityIdentityApi = IdentityApi & {\n getUserId?(): string;\n getIdToken?(): Promise<string | undefined>;\n getProfile?(): ProfileInfo;\n};\n\n/**\n * Implementation of the connection between the App-wide IdentityApi\n * and sign-in page.\n */\nexport class AppIdentityProxy implements IdentityApi {\n private target?: CompatibilityIdentityApi;\n private waitForTarget: Promise<CompatibilityIdentityApi>;\n private resolveTarget: (api: CompatibilityIdentityApi) => void = () => {};\n private signOutTargetUrl = '/';\n\n #cookieAuthSignOut?: () => Promise<void>;\n\n constructor() {\n this.waitForTarget = new Promise<CompatibilityIdentityApi>(resolve => {\n this.resolveTarget = resolve;\n });\n }\n\n // This is called by the app manager once the sign-in page provides us with an implementation\n setTarget(\n identityApi: CompatibilityIdentityApi,\n targetOptions: { signOutTargetUrl: string },\n ) {\n this.target = identityApi;\n this.signOutTargetUrl = targetOptions.signOutTargetUrl;\n this.resolveTarget(identityApi);\n }\n\n getUserId(): string {\n if (!this.target) {\n throw mkError('getUserId');\n }\n if (!this.target.getUserId) {\n throw new Error('IdentityApi does not implement getUserId');\n }\n logDeprecation('getUserId');\n return this.target.getUserId();\n }\n\n getProfile(): ProfileInfo {\n if (!this.target) {\n throw mkError('getProfile');\n }\n if (!this.target.getProfile) {\n throw new Error('IdentityApi does not implement getProfile');\n }\n logDeprecation('getProfile');\n return this.target.getProfile();\n }\n\n async getProfileInfo(): Promise<ProfileInfo> {\n return this.waitForTarget.then(target => target.getProfileInfo());\n }\n\n async getBackstageIdentity(): Promise<BackstageUserIdentity> {\n const identity = await this.waitForTarget.then(target =>\n target.getBackstageIdentity(),\n );\n if (!identity.userEntityRef.match(/^.*:.*\\/.*$/)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The App IdentityApi provided an invalid userEntityRef, '${identity.userEntityRef}'. ` +\n `It must be a full Entity Reference of the form '<kind>:<namespace>/<name>'.`,\n );\n }\n\n return identity;\n }\n\n async getCredentials(): Promise<{ token?: string | undefined }> {\n return this.waitForTarget.then(target => target.getCredentials());\n }\n\n async getIdToken(): Promise<string | undefined> {\n return this.waitForTarget.then(target => {\n if (!target.getIdToken) {\n throw new Error('IdentityApi does not implement getIdToken');\n }\n logDeprecation('getIdToken');\n return target.getIdToken();\n });\n }\n\n async signOut(): Promise<void> {\n await this.waitForTarget.then(target => target.signOut());\n\n await this.#cookieAuthSignOut?.();\n\n window.location.href = this.signOutTargetUrl;\n }\n\n enableCookieAuth(ctx: {\n errorApi: ErrorApi;\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n }) {\n if (this.#cookieAuthSignOut) {\n return;\n }\n\n const stopRefresh = startCookieAuthRefresh(ctx);\n\n this.#cookieAuthSignOut = async () => {\n stopRefresh();\n\n // It is fine if we do NOT worry yet about deleting cookies for OTHER backends like techdocs\n const appBaseUrl = await ctx.discoveryApi.getBaseUrl('app');\n try {\n await fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, {\n method: 'DELETE',\n credentials: 'include',\n });\n } catch {\n // Ignore the error for those who use static serving of the frontend\n }\n };\n }\n}\n"],"names":[],"mappings":";;AA0BA,SAAS,QAAQ,KAAA,EAAe;AAC9B,EAAA,OAAO,IAAI,KAAA;AAAA,IACT,+BAA+B,KAAK,CAAA,sBAAA;AAAA,GACtC;AACF;AAEA,SAAS,eAAe,KAAA,EAAe;AAErC,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,oBAAoB,KAAK,CAAA,2CAAA;AAAA,GAC3B;AACF;AAcO,MAAM,gBAAA,CAAwC;AAAA,EAC3C,MAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAyD,MAAM;AAAA,EAAC,CAAA;AAAA,EAChE,gBAAA,GAAmB,GAAA;AAAA,EAE3B,kBAAA;AAAA,EAEA,WAAA,GAAc;AACZ,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAI,OAAA,CAAkC,CAAA,OAAA,KAAW;AACpE,MAAA,IAAA,CAAK,aAAA,GAAgB,OAAA;AAAA,IACvB,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,SAAA,CACE,aACA,aAAA,EACA;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,WAAA;AACd,IAAA,IAAA,CAAK,mBAAmB,aAAA,CAAc,gBAAA;AACtC,IAAA,IAAA,CAAK,cAAc,WAAW,CAAA;AAAA,EAChC;AAAA,EAEA,SAAA,GAAoB;AAClB,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,QAAQ,WAAW,CAAA;AAAA,IAC3B;AACA,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,SAAA,EAAW;AAC1B,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AACA,IAAA,cAAA,CAAe,WAAW,CAAA;AAC1B,IAAA,OAAO,IAAA,CAAK,OAAO,SAAA,EAAU;AAAA,EAC/B;AAAA,EAEA,UAAA,GAA0B;AACxB,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,QAAQ,YAAY,CAAA;AAAA,IAC5B;AACA,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,UAAA,EAAY;AAC3B,MAAA,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAAA,IAC7D;AACA,IAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,IAAA,OAAO,IAAA,CAAK,OAAO,UAAA,EAAW;AAAA,EAChC;AAAA,EAEA,MAAM,cAAA,GAAuC;AAC3C,IAAA,OAAO,KAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU,MAAA,CAAO,gBAAgB,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,oBAAA,GAAuD;AAC3D,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,aAAA,CAAc,IAAA;AAAA,MAAK,CAAA,MAAA,KAC7C,OAAO,oBAAA;AAAqB,KAC9B;AACA,IAAA,IAAI,CAAC,QAAA,CAAS,aAAA,CAAc,KAAA,CAAM,aAAa,CAAA,EAAG;AAEhD,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,iEAAA,EAAoE,SAAS,aAAa,CAAA,8EAAA;AAAA,OAE5F;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,MAAM,cAAA,GAA0D;AAC9D,IAAA,OAAO,KAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU,MAAA,CAAO,gBAAgB,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,UAAA,GAA0C;AAC9C,IAAA,OAAO,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU;AACvC,MAAA,IAAI,CAAC,OAAO,UAAA,EAAY;AACtB,QAAA,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAAA,MAC7D;AACA,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,OAAO,OAAO,UAAA,EAAW;AAAA,IAC3B,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,OAAA,GAAyB;AAC7B,IAAA,MAAM,KAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU,MAAA,CAAO,SAAS,CAAA;AAExD,IAAA,MAAM,KAAK,kBAAA,IAAqB;AAEhC,IAAA,MAAA,CAAO,QAAA,CAAS,OAAO,IAAA,CAAK,gBAAA;AAAA,EAC9B;AAAA,EAEA,iBAAiB,GAAA,EAId;AACD,IAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,WAAA,GAAc,uBAAuB,GAAG,CAAA;AAE9C,IAAA,IAAA,CAAK,qBAAqB,YAAY;AACpC,MAAA,WAAA,EAAY;AAGZ,MAAA,MAAM,UAAA,GAAa,MAAM,GAAA,CAAI,YAAA,CAAa,WAAW,KAAK,CAAA;AAC1D,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA,0BAAA,CAAA,EAA8B;AAAA,UACrD,MAAA,EAAQ,QAAA;AAAA,UACR,WAAA,EAAa;AAAA,SACd,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,EACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"startCookieAuthRefresh.esm.js","sources":["../../../../src/apis/implementations/IdentityApi/startCookieAuthRefresh.ts"],"sourcesContent":["/*\n * Copyright 2024 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, ErrorApi, FetchApi } from '@backstage/core-plugin-api';\n\nconst PLUGIN_ID = 'app';\nconst CHANNEL_ID = `${PLUGIN_ID}-auth-cookie-expires-at`;\n\nconst MIN_BASE_DELAY_MS = 5 * 60_000;\n\nconst ERROR_BACKOFF_START = 5_000;\nconst ERROR_BACKOFF_FACTOR = 2;\nconst ERROR_BACKOFF_MAX = 5 * 60_000;\n\n// Messaging implementation and IDs must match\n// plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx\nexport function startCookieAuthRefresh({\n discoveryApi,\n fetchApi,\n errorApi,\n}: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n errorApi: ErrorApi;\n}) {\n let stopped = false;\n let timeout: NodeJS.Timeout | undefined;\n let firstError = true;\n let errorBackoff = ERROR_BACKOFF_START;\n\n const channel =\n 'BroadcastChannel' in window ? new BroadcastChannel(CHANNEL_ID) : undefined;\n\n // Randomize the refreshing margin with a margin of 1-4 minutes to avoid all tabs refreshing at the same time\n const getDelay = (expiresAt: number) => {\n const margin = (1 + 3 * Math.random()) * 60000;\n const delay = Math.max(expiresAt - Date.now(), MIN_BASE_DELAY_MS) - margin;\n return delay;\n };\n\n const refresh = async () => {\n try {\n const baseUrl = await discoveryApi.getBaseUrl(PLUGIN_ID);\n const requestUrl = `${baseUrl}/.backstage/auth/v1/cookie`;\n const res = await fetchApi.fetch(requestUrl, {\n credentials: 'include',\n });\n\n if (!res.ok) {\n throw new Error(\n `Request failed with status ${res.status} ${res.statusText}, see request towards ${requestUrl} for more details`,\n );\n }\n\n const data = await res.json();\n if (!data.expiresAt) {\n throw new Error('No expiration date in response');\n }\n\n const expiresAt = Date.parse(data.expiresAt);\n if (Number.isNaN(expiresAt)) {\n throw new Error('Invalid expiration date in response');\n }\n\n firstError = true;\n\n channel?.postMessage({\n action: 'COOKIE_REFRESH_SUCCESS',\n payload: { expiresAt: new Date(expiresAt).toISOString() },\n });\n\n scheduleRefresh(getDelay(expiresAt));\n } catch (error) {\n // Ignore the first error after successful requests\n if (firstError) {\n firstError = false;\n errorBackoff = ERROR_BACKOFF_START;\n } else {\n errorBackoff = Math.min(\n ERROR_BACKOFF_MAX,\n errorBackoff * ERROR_BACKOFF_FACTOR,\n );\n // eslint-disable-next-line no-console\n console.error('Session cookie refresh failed', error);\n errorApi.post(\n new Error(\n `Session refresh failed, see developer console for details`,\n ),\n );\n }\n\n scheduleRefresh(errorBackoff);\n }\n };\n\n const onMessage = (\n event: MessageEvent<\n | {\n action: 'COOKIE_REFRESH_SUCCESS';\n payload: { expiresAt: string };\n }\n | object\n >,\n ) => {\n const { data } = event;\n if (data === null || typeof data !== 'object') {\n return;\n }\n if ('action' in data && data.action === 'COOKIE_REFRESH_SUCCESS') {\n const expiresAt = Date.parse(data.payload.expiresAt);\n if (Number.isNaN(expiresAt)) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Received invalid expiration from session refresh channel',\n );\n return;\n }\n\n scheduleRefresh(getDelay(expiresAt));\n }\n };\n\n function scheduleRefresh(delayMs: number) {\n if (stopped) {\n return;\n }\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(refresh, delayMs);\n }\n\n channel?.addEventListener('message', onMessage);\n refresh();\n\n return () => {\n stopped = true;\n if (timeout) {\n clearTimeout(timeout);\n }\n channel?.removeEventListener('message', onMessage);\n channel?.close();\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"startCookieAuthRefresh.esm.js","sources":["../../../../src/apis/implementations/IdentityApi/startCookieAuthRefresh.ts"],"sourcesContent":["/*\n * Copyright 2024 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, ErrorApi, FetchApi } from '@backstage/core-plugin-api';\n\nconst PLUGIN_ID = 'app';\nconst CHANNEL_ID = `${PLUGIN_ID}-auth-cookie-expires-at`;\n\nconst MIN_BASE_DELAY_MS = 5 * 60_000;\n\nconst ERROR_BACKOFF_START = 5_000;\nconst ERROR_BACKOFF_FACTOR = 2;\nconst ERROR_BACKOFF_MAX = 5 * 60_000;\n\n// Messaging implementation and IDs must match\n// plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx\nexport function startCookieAuthRefresh({\n discoveryApi,\n fetchApi,\n errorApi,\n}: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n errorApi: ErrorApi;\n}) {\n let stopped = false;\n let timeout: NodeJS.Timeout | undefined;\n let firstError = true;\n let errorBackoff = ERROR_BACKOFF_START;\n\n const channel =\n 'BroadcastChannel' in window ? new BroadcastChannel(CHANNEL_ID) : undefined;\n\n // Randomize the refreshing margin with a margin of 1-4 minutes to avoid all tabs refreshing at the same time\n const getDelay = (expiresAt: number) => {\n const margin = (1 + 3 * Math.random()) * 60000;\n const delay = Math.max(expiresAt - Date.now(), MIN_BASE_DELAY_MS) - margin;\n return delay;\n };\n\n const refresh = async () => {\n try {\n const baseUrl = await discoveryApi.getBaseUrl(PLUGIN_ID);\n const requestUrl = `${baseUrl}/.backstage/auth/v1/cookie`;\n const res = await fetchApi.fetch(requestUrl, {\n credentials: 'include',\n });\n\n if (!res.ok) {\n throw new Error(\n `Request failed with status ${res.status} ${res.statusText}, see request towards ${requestUrl} for more details`,\n );\n }\n\n const data = await res.json();\n if (!data.expiresAt) {\n throw new Error('No expiration date in response');\n }\n\n const expiresAt = Date.parse(data.expiresAt);\n if (Number.isNaN(expiresAt)) {\n throw new Error('Invalid expiration date in response');\n }\n\n firstError = true;\n\n channel?.postMessage({\n action: 'COOKIE_REFRESH_SUCCESS',\n payload: { expiresAt: new Date(expiresAt).toISOString() },\n });\n\n scheduleRefresh(getDelay(expiresAt));\n } catch (error) {\n // Ignore the first error after successful requests\n if (firstError) {\n firstError = false;\n errorBackoff = ERROR_BACKOFF_START;\n } else {\n errorBackoff = Math.min(\n ERROR_BACKOFF_MAX,\n errorBackoff * ERROR_BACKOFF_FACTOR,\n );\n // eslint-disable-next-line no-console\n console.error('Session cookie refresh failed', error);\n errorApi.post(\n new Error(\n `Session refresh failed, see developer console for details`,\n ),\n );\n }\n\n scheduleRefresh(errorBackoff);\n }\n };\n\n const onMessage = (\n event: MessageEvent<\n | {\n action: 'COOKIE_REFRESH_SUCCESS';\n payload: { expiresAt: string };\n }\n | object\n >,\n ) => {\n const { data } = event;\n if (data === null || typeof data !== 'object') {\n return;\n }\n if ('action' in data && data.action === 'COOKIE_REFRESH_SUCCESS') {\n const expiresAt = Date.parse(data.payload.expiresAt);\n if (Number.isNaN(expiresAt)) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Received invalid expiration from session refresh channel',\n );\n return;\n }\n\n scheduleRefresh(getDelay(expiresAt));\n }\n };\n\n function scheduleRefresh(delayMs: number) {\n if (stopped) {\n return;\n }\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(refresh, delayMs);\n }\n\n channel?.addEventListener('message', onMessage);\n refresh();\n\n return () => {\n stopped = true;\n if (timeout) {\n clearTimeout(timeout);\n }\n channel?.removeEventListener('message', onMessage);\n channel?.close();\n };\n}\n"],"names":[],"mappings":"AAkBA,MAAM,SAAA,GAAY,KAAA;AAClB,MAAM,UAAA,GAAa,GAAG,SAAS,CAAA,uBAAA,CAAA;AAE/B,MAAM,oBAAoB,CAAA,GAAI,GAAA;AAE9B,MAAM,mBAAA,GAAsB,GAAA;AAC5B,MAAM,oBAAA,GAAuB,CAAA;AAC7B,MAAM,oBAAoB,CAAA,GAAI,GAAA;AAIvB,SAAS,sBAAA,CAAuB;AAAA,EACrC,YAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,UAAA,GAAa,IAAA;AACjB,EAAA,IAAI,YAAA,GAAe,mBAAA;AAEnB,EAAA,MAAM,UACJ,kBAAA,IAAsB,MAAA,GAAS,IAAI,gBAAA,CAAiB,UAAU,CAAA,GAAI,MAAA;AAGpE,EAAA,MAAM,QAAA,GAAW,CAAC,SAAA,KAAsB;AACtC,IAAA,MAAM,MAAA,GAAA,CAAU,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,QAAO,IAAK,GAAA;AACzC,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,SAAA,GAAY,KAAK,GAAA,EAAI,EAAG,iBAAiB,CAAA,GAAI,MAAA;AACpE,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,UAAU,YAAY;AAC1B,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,MAAM,YAAA,CAAa,UAAA,CAAW,SAAS,CAAA;AACvD,MAAA,MAAM,UAAA,GAAa,GAAG,OAAO,CAAA,0BAAA,CAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,KAAA,CAAM,UAAA,EAAY;AAAA,QAC3C,WAAA,EAAa;AAAA,OACd,CAAA;AAED,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,8BAA8B,GAAA,CAAI,MAAM,IAAI,GAAA,CAAI,UAAU,yBAAyB,UAAU,CAAA,iBAAA;AAAA,SAC/F;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,MAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,QAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,MAClD;AAEA,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AAC3C,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,EAAG;AAC3B,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,UAAA,GAAa,IAAA;AAEb,MAAA,OAAA,EAAS,WAAA,CAAY;AAAA,QACnB,MAAA,EAAQ,wBAAA;AAAA,QACR,OAAA,EAAS,EAAE,SAAA,EAAW,IAAI,KAAK,SAAS,CAAA,CAAE,aAAY;AAAE,OACzD,CAAA;AAED,MAAA,eAAA,CAAgB,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IACrC,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,UAAA,GAAa,KAAA;AACb,QAAA,YAAA,GAAe,mBAAA;AAAA,MACjB,CAAA,MAAO;AACL,QAAA,YAAA,GAAe,IAAA,CAAK,GAAA;AAAA,UAClB,iBAAA;AAAA,UACA,YAAA,GAAe;AAAA,SACjB;AAEA,QAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,KAAK,CAAA;AACpD,QAAA,QAAA,CAAS,IAAA;AAAA,UACP,IAAI,KAAA;AAAA,YACF,CAAA,yDAAA;AAAA;AACF,SACF;AAAA,MACF;AAEA,MAAA,eAAA,CAAgB,YAAY,CAAA;AAAA,IAC9B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAChB,KAAA,KAOG;AACH,IAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,IAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AAC7C,MAAA;AAAA,IACF;AACA,IAAA,IAAI,QAAA,IAAY,IAAA,IAAQ,IAAA,CAAK,MAAA,KAAW,wBAAA,EAA0B;AAChE,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,QAAQ,SAAS,CAAA;AACnD,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,EAAG;AAE3B,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,eAAA,CAAgB,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IACrC;AAAA,EACF,CAAA;AAEA,EAAA,SAAS,gBAAgB,OAAA,EAAiB;AACxC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,YAAA,CAAa,OAAO,CAAA;AAAA,IACtB;AACA,IAAA,OAAA,GAAU,UAAA,CAAW,SAAS,OAAO,CAAA;AAAA,EACvC;AAEA,EAAA,OAAA,EAAS,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC9C,EAAA,OAAA,EAAQ;AAER,EAAA,OAAO,MAAM;AACX,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,YAAA,CAAa,OAAO,CAAA;AAAA,IACtB;AACA,IAAA,OAAA,EAAS,mBAAA,CAAoB,WAAW,SAAS,CAAA;AACjD,IAAA,OAAA,EAAS,KAAA,EAAM;AAAA,EACjB,CAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OAuthPendingRequests.esm.js","sources":["../../../../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":";;AA+BgB,SAAA,SAAA,CACd,UACA,SACS,EAAA;AACT,EAAA,KAAA,MAAW,SAAS,SAAW,EAAA;AAC7B,IAAA,IAAI,CAAC,QAAA,CAAS,GAAI,CAAA,KAAK,CAAG,EAAA;AACxB,MAAO,OAAA,KAAA;AAAA;AACT;AAEF,EAAO,OAAA,IAAA;AACT;AAEgB,SAAA,UAAA,CACd,WACG,WACU,EAAA;AACb,EAAM,MAAA,MAAA,GAAS,IAAI,GAAA,CAAI,MAAM,CAAA;AAE7B,EAAA,KAAA,MAAW,cAAc,WAAa,EAAA;AACpC,IAAA,KAAA,MAAW,SAAS,UAAY,EAAA;AAC9B,MAAA,MAAA,CAAO,IAAI,KAAK,CAAA;AAAA;AAClB;AAGF,EAAO,OAAA,MAAA;AACT;AAOO,MAAM,oBAAiC,CAAA;AAAA,EACpC,WAA4C,EAAC;AAAA,EAC7C,UAAU,IAAI,eAAA;AAAA,IACpB,KAAK,iBAAkB;AAAA,GACzB;AAAA,EAEA,QAAQ,MAA0C,EAAA;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAW,KAAA;AACtC,MAAA,IAAA,CAAK,SAAS,IAAK,CAAA,EAAE,MAAQ,EAAA,OAAA,EAAS,QAAQ,CAAA;AAE9C,MAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,IAAK,CAAA,iBAAA,EAAmB,CAAA;AAAA,KAC3C,CAAA;AAAA;AACH,EAEA,OAAA,CAAQ,QAAqB,MAA0B,EAAA;AACrD,IAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAK,QAAS,CAAA,MAAA,CAAO,CAAW,OAAA,KAAA;AAC9C,MAAA,IAAI,SAAU,CAAA,MAAA,EAAQ,OAAQ,CAAA,MAAM,CAAG,EAAA;AACrC,QAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA;AACtB,QAAO,OAAA,KAAA;AAAA;AAET,MAAO,OAAA,IAAA;AAAA,KACR,CAAA;AAED,IAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,IAAK,CAAA,iBAAA,EAAmB,CAAA;AAAA;AAC5C,EAEA,OAAO,KAAc,EAAA;AACnB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,CAAA,OAAA,KAAW,OAAQ,CAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AACtD,IAAA,IAAA,CAAK,WAAW,EAAC;AAEjB,IAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,IAAK,CAAA,iBAAA,EAAmB,CAAA;AAAA;AAC5C,EAEA,OAAkD,GAAA;AAChD,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AACd,EAEQ,iBAAgD,GAAA;AACtD,IAAM,MAAA,aAAA,GACJ,IAAK,CAAA,QAAA,CAAS,MAAW,KAAA,CAAA,GACrB,SACA,IAAK,CAAA,QAAA,CACF,KAAM,CAAA,CAAC,CACP,CAAA,MAAA;AAAA,MACC,CAAC,GAAK,EAAA,OAAA,KAAY,UAAW,CAAA,GAAA,EAAK,QAAQ,MAAM,CAAA;AAAA,MAChD,IAAA,CAAK,QAAS,CAAA,CAAC,CAAE,CAAA;AAAA,KACnB;AAER,IAAO,OAAA;AAAA,MACL,MAAQ,EAAA,aAAA;AAAA,MACR,OAAA,EAAS,CAAC,KAAsB,KAAA;AAC9B,QAAA,IAAI,aAAe,EAAA;AACjB,UAAK,IAAA,CAAA,OAAA,CAAQ,eAAe,KAAK,CAAA;AAAA;AACnC,OACF;AAAA,MACA,MAAA,EAAQ,CAAC,MAAkB,KAAA;AACzB,QAAA,IAAI,aAAe,EAAA;AACjB,UAAA,IAAA,CAAK,OAAO,MAAM,CAAA;AAAA;AACpB;AACF,KACF;AAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"OAuthPendingRequests.esm.js","sources":["../../../../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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OAuthRequestManager.esm.js","sources":["../../../../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 { PublishSubject } 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 PublishSubject<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,OAAA,GAAU,IAAI,cAAsC,EAAA;AAAA,EAC7D,kBAAyC,EAAC;AAAA,EAC1C,YAAe,GAAA,CAAA;AAAA,EAEvB,oBAAuB,OAAsD,EAAA;AAC3E,IAAM,MAAA,OAAA,GAAU,IAAI,oBAAwB,EAAA;AAE5C,IAAA,MAAM,QAAQ,IAAK,CAAA,YAAA;AACnB,IAAK,IAAA,CAAA,YAAA,EAAA;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;AAC/C,QAAA,MAAM,OAAU,GAAA,IAAA,CAAK,eAAgB,CAAA,YAAA,EAAc,OAAO,CAAA;AAC1D,QAAA,IAAI,CAAC,OAAS,EAAA;AACZ,UAAA,OAAO,YAAY,KAAK,CAAA;AAAA,SACnB,MAAA;AACL,UAAA,WAAA,CAAY,KAAK,CAAI,GAAA,OAAA;AAAA;AAEvB,QAAA,IAAA,CAAK,eAAkB,GAAA,WAAA;AAEvB,QAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,WAAY,CAAA,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA;AAC/C,KACD,CAAA;AAED,IAAA,OAAO,CAAU,MAAA,KAAA;AACf,MAAO,OAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,KAC/B;AAAA;AACF;AAAA,EAGQ,eAAA,CACN,SACA,OACiC,EAAA;AACjC,IAAM,MAAA,EAAE,QAAW,GAAA,OAAA;AACnB,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAO,OAAA,KAAA,CAAA;AAAA;AAGT,IAAO,OAAA;AAAA,MACL,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,SAAS,YAAY;AACnB,QAAA,MAAM,MAAS,GAAA,MAAM,OAAQ,CAAA,aAAA,CAAc,MAAM,CAAA;AACjD,QAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,OACxB;AAAA,MACA,QAAQ,MAAM;AACZ,QAAM,MAAA,KAAA,GAAQ,IAAI,KAAA,CAAM,gCAAgC,CAAA;AACxD,QAAA,KAAA,CAAM,IAAO,GAAA,eAAA;AACb,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AAAA;AACtB,KACF;AAAA;AACF,EAEA,YAAkD,GAAA;AAChD,IAAA,OAAO,IAAK,CAAA,OAAA;AAAA;AAEhB;;;;"}
1
+ {"version":3,"file":"OAuthRequestManager.esm.js","sources":["../../../../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 { PublishSubject } 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 PublishSubject<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,mBAAA,CAA+C;AAAA,EACzC,OAAA,GAAU,IAAI,cAAA,EAAsC;AAAA,EAC7D,kBAAyC,EAAC;AAAA,EAC1C,YAAA,GAAe,CAAA;AAAA,EAEvB,oBAAuB,OAAA,EAAsD;AAC3E,IAAA,MAAM,OAAA,GAAU,IAAI,oBAAA,EAAwB;AAE5C,IAAA,MAAM,QAAQ,IAAA,CAAK,YAAA;AACnB,IAAA,IAAA,CAAK,YAAA,EAAA;AAEL,IAAA,OAAA,CAAQ,OAAA,GAAU,SAAA,CAAU;AAAA,MAC1B,MAAM,CAAA,YAAA,KAAgB;AACpB,QAAA,MAAM,WAAA,GAAc,IAAA,CAAK,eAAA,CAAgB,KAAA,EAAM;AAC/C,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,eAAA,CAAgB,YAAA,EAAc,OAAO,CAAA;AAC1D,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,OAAO,YAAY,KAAK,CAAA;AAAA,QAC1B,CAAA,MAAO;AACL,UAAA,WAAA,CAAY,KAAK,CAAA,GAAI,OAAA;AAAA,QACvB;AACA,QAAA,IAAA,CAAK,eAAA,GAAkB,WAAA;AAEvB,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,MAC/C;AAAA,KACD,CAAA;AAED,IAAA,OAAO,CAAA,MAAA,KAAU;AACf,MAAA,OAAO,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,IAC/B,CAAA;AAAA,EACF;AAAA;AAAA,EAGQ,eAAA,CACN,SACA,OAAA,EACiC;AACjC,IAAA,MAAM,EAAE,QAAO,GAAI,OAAA;AACnB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO;AAAA,MACL,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,SAAS,YAAY;AACnB,QAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,aAAA,CAAc,MAAM,CAAA;AACjD,QAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,MACxB,CAAA;AAAA,MACA,QAAQ,MAAM;AACZ,QAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,gCAAgC,CAAA;AACxD,QAAA,KAAA,CAAM,IAAA,GAAO,eAAA;AACb,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AAAA,MACtB;AAAA,KACF;AAAA,EACF;AAAA,EAEA,YAAA,GAAkD;AAChD,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AACF;;;;"}