@backstage/core-app-api 1.12.5 → 1.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/dist/apis/implementations/AlertApi/AlertApiForwarder.esm.js +1 -9
- package/dist/apis/implementations/AlertApi/AlertApiForwarder.esm.js.map +1 -1
- package/dist/apis/implementations/AppLanguageApi/AppLanguageSelector.esm.js +26 -51
- package/dist/apis/implementations/AppLanguageApi/AppLanguageSelector.esm.js.map +1 -1
- package/dist/apis/implementations/AppThemeApi/AppThemeSelector.esm.js +4 -12
- package/dist/apis/implementations/AppThemeApi/AppThemeSelector.esm.js.map +1 -1
- package/dist/apis/implementations/DiscoveryApi/FrontendHostDiscovery.esm.js +2 -3
- package/dist/apis/implementations/DiscoveryApi/FrontendHostDiscovery.esm.js.map +1 -1
- package/dist/apis/implementations/ErrorApi/ErrorAlerter.esm.js +1 -1
- package/dist/apis/implementations/ErrorApi/ErrorAlerter.esm.js.map +1 -1
- package/dist/apis/implementations/ErrorApi/ErrorApiForwarder.esm.js +1 -9
- package/dist/apis/implementations/ErrorApi/ErrorApiForwarder.esm.js.map +1 -1
- package/dist/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.esm.js +2 -10
- package/dist/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.esm.js.map +1 -1
- package/dist/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.esm.js +2 -3
- package/dist/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.esm.js.map +1 -1
- package/dist/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.esm.js +1 -1
- package/dist/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.esm.js.map +1 -1
- package/dist/apis/implementations/FetchApi/createFetchApi.esm.js +1 -2
- package/dist/apis/implementations/FetchApi/createFetchApi.esm.js.map +1 -1
- package/dist/apis/implementations/IdentityApi/AppIdentityProxy.esm.js +10 -37
- package/dist/apis/implementations/IdentityApi/AppIdentityProxy.esm.js.map +1 -1
- package/dist/apis/implementations/IdentityApi/startCookieAuthRefresh.esm.js +4 -4
- package/dist/apis/implementations/IdentityApi/startCookieAuthRefresh.esm.js.map +1 -1
- package/dist/apis/implementations/OAuthRequestApi/OAuthPendingRequests.esm.js +4 -12
- package/dist/apis/implementations/OAuthRequestApi/OAuthPendingRequests.esm.js.map +1 -1
- package/dist/apis/implementations/OAuthRequestApi/OAuthRequestManager.esm.js +3 -11
- package/dist/apis/implementations/OAuthRequestApi/OAuthRequestManager.esm.js.map +1 -1
- package/dist/apis/implementations/StorageApi/WebStorage.esm.js +18 -27
- package/dist/apis/implementations/StorageApi/WebStorage.esm.js.map +1 -1
- package/dist/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js +85 -126
- package/dist/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js.map +1 -1
- package/dist/apis/implementations/auth/microsoft/MicrosoftAuth.esm.js +20 -29
- package/dist/apis/implementations/auth/microsoft/MicrosoftAuth.esm.js.map +1 -1
- package/dist/apis/implementations/auth/oauth2/OAuth2.esm.js +12 -21
- package/dist/apis/implementations/auth/oauth2/OAuth2.esm.js.map +1 -1
- package/dist/apis/implementations/auth/saml/SamlAuth.esm.js +2 -2
- package/dist/apis/implementations/auth/saml/SamlAuth.esm.js.map +1 -1
- package/dist/apis/system/ApiAggregator.esm.js +1 -7
- package/dist/apis/system/ApiAggregator.esm.js.map +1 -1
- package/dist/apis/system/ApiFactoryRegistry.esm.js +1 -9
- package/dist/apis/system/ApiFactoryRegistry.esm.js.map +1 -1
- package/dist/apis/system/ApiProvider.esm.js +1 -2
- package/dist/apis/system/ApiProvider.esm.js.map +1 -1
- package/dist/apis/system/ApiRegistry.esm.js +1 -9
- package/dist/apis/system/ApiRegistry.esm.js.map +1 -1
- package/dist/apis/system/ApiResolver.esm.js +1 -7
- package/dist/apis/system/ApiResolver.esm.js.map +1 -1
- package/dist/app/AppManager.esm.js +47 -71
- package/dist/app/AppManager.esm.js.map +1 -1
- package/dist/app/AppRouter.esm.js +1 -2
- package/dist/app/AppRouter.esm.js.map +1 -1
- package/dist/app/isProtectedApp.esm.js +1 -2
- package/dist/app/isProtectedApp.esm.js.map +1 -1
- package/dist/app/resolveRouteBindings.esm.js +61 -2
- package/dist/app/resolveRouteBindings.esm.js.map +1 -1
- package/dist/extensions/traversal.esm.js +3 -5
- package/dist/extensions/traversal.esm.js.map +1 -1
- package/dist/lib/AuthConnector/DefaultAuthConnector.esm.js +11 -19
- package/dist/lib/AuthConnector/DefaultAuthConnector.esm.js.map +1 -1
- package/dist/lib/AuthConnector/DirectAuthConnector.esm.js +3 -9
- package/dist/lib/AuthConnector/DirectAuthConnector.esm.js.map +1 -1
- package/dist/lib/AuthSessionManager/AuthSessionStore.esm.js +6 -12
- package/dist/lib/AuthSessionManager/AuthSessionStore.esm.js.map +1 -1
- package/dist/lib/AuthSessionManager/RefreshingAuthSessionManager.esm.js +7 -13
- package/dist/lib/AuthSessionManager/RefreshingAuthSessionManager.esm.js.map +1 -1
- package/dist/lib/AuthSessionManager/SessionStateTracker.esm.js +4 -12
- package/dist/lib/AuthSessionManager/SessionStateTracker.esm.js.map +1 -1
- package/dist/lib/AuthSessionManager/StaticAuthSessionManager.esm.js +4 -10
- package/dist/lib/AuthSessionManager/StaticAuthSessionManager.esm.js.map +1 -1
- package/dist/lib/subjects.esm.js +20 -28
- package/dist/lib/subjects.esm.js.map +1 -1
- package/dist/routing/FlatRoutes.esm.js +1 -2
- package/dist/routing/FlatRoutes.esm.js.map +1 -1
- package/dist/routing/RouteResolver.esm.js +1 -2
- package/dist/routing/RouteResolver.esm.js.map +1 -1
- package/dist/routing/RouteTracker.esm.js +4 -7
- package/dist/routing/RouteTracker.esm.js.map +1 -1
- package/dist/routing/collectors.esm.js +28 -31
- package/dist/routing/collectors.esm.js.map +1 -1
- package/dist/routing/validation.esm.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# @backstage/core-app-api
|
|
2
2
|
|
|
3
|
+
## 1.12.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 35fbe09: Added support for configuration of route bindings through static configuration, and default targets for external route refs.
|
|
8
|
+
|
|
9
|
+
In addition to configuring route bindings through code, it is now also possible to configure route bindings under the `app.routes.bindings` key, for example:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
app:
|
|
13
|
+
routes:
|
|
14
|
+
bindings:
|
|
15
|
+
catalog.createComponent: catalog-import.importPage
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Each key in the route binding object is of the form `<plugin-id>.<externalRouteName>`, where the route name is key used in the `externalRoutes` object passed to `createPlugin`. The value is of the same form, but with the name taken from the plugin `routes` option instead.
|
|
19
|
+
|
|
20
|
+
The equivalent of the above configuration in code is the following:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const app = createApp({
|
|
24
|
+
// ...
|
|
25
|
+
bindRoutes({ bind }) {
|
|
26
|
+
bind(catalogPlugin.externalRoutes, {
|
|
27
|
+
createComponent: catalogImportPlugin.routes.importPage,
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- Updated dependencies
|
|
34
|
+
- @backstage/core-plugin-api@1.9.3
|
|
35
|
+
- @backstage/config@1.2.0
|
|
36
|
+
- @backstage/types@1.1.1
|
|
37
|
+
- @backstage/version-bridge@1.0.8
|
|
38
|
+
|
|
39
|
+
## 1.12.6-next.0
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 35fbe09: Added support for configuration of route bindings through static configuration, and default targets for external route refs.
|
|
44
|
+
|
|
45
|
+
In addition to configuring route bindings through code, it is now also possible to configure route bindings under the `app.routes.bindings` key, for example:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
app:
|
|
49
|
+
routes:
|
|
50
|
+
bindings:
|
|
51
|
+
catalog.createComponent: catalog-import.importPage
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Each key in the route binding object is of the form `<plugin-id>.<externalRouteName>`, where the route name is key used in the `externalRoutes` object passed to `createPlugin`. The value is of the same form, but with the name taken from the plugin `routes` option instead.
|
|
55
|
+
|
|
56
|
+
The equivalent of the above configuration in code is the following:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const app = createApp({
|
|
60
|
+
// ...
|
|
61
|
+
bindRoutes({ bind }) {
|
|
62
|
+
bind(catalogPlugin.externalRoutes, {
|
|
63
|
+
createComponent: catalogImportPlugin.routes.importPage,
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- Updated dependencies
|
|
70
|
+
- @backstage/core-plugin-api@1.9.3-next.0
|
|
71
|
+
- @backstage/config@1.2.0
|
|
72
|
+
- @backstage/types@1.1.1
|
|
73
|
+
- @backstage/version-bridge@1.0.8
|
|
74
|
+
|
|
3
75
|
## 1.12.5
|
|
4
76
|
|
|
5
77
|
### Patch Changes
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { PublishSubject } from '../../../lib/subjects.esm.js';
|
|
2
2
|
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
-
var __publicField = (obj, key, value) => {
|
|
6
|
-
__defNormalProp(obj, key + "" , value);
|
|
7
|
-
return value;
|
|
8
|
-
};
|
|
9
3
|
class AlertApiForwarder {
|
|
10
|
-
|
|
11
|
-
__publicField(this, "subject", new PublishSubject());
|
|
12
|
-
}
|
|
4
|
+
subject = new PublishSubject();
|
|
13
5
|
post(alert) {
|
|
14
6
|
this.subject.next(alert);
|
|
15
7
|
}
|
|
@@ -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":"
|
|
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,CAAA;AAAA,EAE5D,KAAK,KAAqB,EAAA;AACxB,IAAK,IAAA,CAAA,OAAA,CAAQ,KAAK,KAAK,CAAA,CAAA;AAAA,GACzB;AAAA,EAEA,MAAmC,GAAA;AACjC,IAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AAAA,GACd;AACF;;;;"}
|
|
@@ -1,41 +1,11 @@
|
|
|
1
1
|
import { BehaviorSubject } from '../../../lib/subjects.esm.js';
|
|
2
2
|
import '@backstage/core-plugin-api';
|
|
3
3
|
|
|
4
|
-
var __accessCheck = (obj, member, msg) => {
|
|
5
|
-
if (!member.has(obj))
|
|
6
|
-
throw TypeError("Cannot " + msg);
|
|
7
|
-
};
|
|
8
|
-
var __privateGet = (obj, member, getter) => {
|
|
9
|
-
__accessCheck(obj, member, "read from private field");
|
|
10
|
-
return member.get(obj);
|
|
11
|
-
};
|
|
12
|
-
var __privateAdd = (obj, member, value) => {
|
|
13
|
-
if (member.has(obj))
|
|
14
|
-
throw TypeError("Cannot add the same private member more than once");
|
|
15
|
-
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
16
|
-
};
|
|
17
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
18
|
-
__accessCheck(obj, member, "write to private field");
|
|
19
|
-
member.set(obj, value);
|
|
20
|
-
return value;
|
|
21
|
-
};
|
|
22
|
-
var _languages, _language, _subject;
|
|
23
4
|
const STORAGE_KEY = "language";
|
|
24
5
|
const DEFAULT_LANGUAGE = "en";
|
|
25
|
-
|
|
26
|
-
constructor(languages, initialLanguage) {
|
|
27
|
-
__privateAdd(this, _languages, void 0);
|
|
28
|
-
__privateAdd(this, _language, void 0);
|
|
29
|
-
__privateAdd(this, _subject, void 0);
|
|
30
|
-
__privateSet(this, _languages, languages);
|
|
31
|
-
__privateSet(this, _language, initialLanguage);
|
|
32
|
-
__privateSet(this, _subject, new BehaviorSubject({
|
|
33
|
-
language: __privateGet(this, _language)
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
6
|
+
class AppLanguageSelector {
|
|
36
7
|
static create(options) {
|
|
37
|
-
|
|
38
|
-
const languages = (_a = options == null ? void 0 : options.availableLanguages) != null ? _a : [DEFAULT_LANGUAGE];
|
|
8
|
+
const languages = options?.availableLanguages ?? [DEFAULT_LANGUAGE];
|
|
39
9
|
if (languages.length !== new Set(languages).size) {
|
|
40
10
|
throw new Error(
|
|
41
11
|
`Supported languages may not contain duplicates, got '${languages.join(
|
|
@@ -46,16 +16,16 @@ const _AppLanguageSelector = class _AppLanguageSelector {
|
|
|
46
16
|
if (!languages.includes(DEFAULT_LANGUAGE)) {
|
|
47
17
|
throw new Error(`Supported languages must include '${DEFAULT_LANGUAGE}'`);
|
|
48
18
|
}
|
|
49
|
-
const initialLanguage =
|
|
19
|
+
const initialLanguage = options?.defaultLanguage ?? DEFAULT_LANGUAGE;
|
|
50
20
|
if (!languages.includes(initialLanguage)) {
|
|
51
21
|
throw new Error(
|
|
52
22
|
`Initial language must be one of the supported languages, got '${initialLanguage}'`
|
|
53
23
|
);
|
|
54
24
|
}
|
|
55
|
-
return new
|
|
25
|
+
return new AppLanguageSelector(languages, initialLanguage);
|
|
56
26
|
}
|
|
57
27
|
static createWithStorage(options) {
|
|
58
|
-
const selector =
|
|
28
|
+
const selector = AppLanguageSelector.create(options);
|
|
59
29
|
if (!window.localStorage) {
|
|
60
30
|
return selector;
|
|
61
31
|
}
|
|
@@ -70,9 +40,8 @@ const _AppLanguageSelector = class _AppLanguageSelector {
|
|
|
70
40
|
}
|
|
71
41
|
});
|
|
72
42
|
window.addEventListener("storage", (event) => {
|
|
73
|
-
var _a;
|
|
74
43
|
if (event.key === STORAGE_KEY) {
|
|
75
|
-
const language =
|
|
44
|
+
const language = localStorage.getItem(STORAGE_KEY) ?? void 0;
|
|
76
45
|
if (language) {
|
|
77
46
|
selector.setLanguage(language);
|
|
78
47
|
}
|
|
@@ -80,35 +49,41 @@ const _AppLanguageSelector = class _AppLanguageSelector {
|
|
|
80
49
|
});
|
|
81
50
|
return selector;
|
|
82
51
|
}
|
|
52
|
+
#languages;
|
|
53
|
+
#language;
|
|
54
|
+
#subject;
|
|
55
|
+
constructor(languages, initialLanguage) {
|
|
56
|
+
this.#languages = languages;
|
|
57
|
+
this.#language = initialLanguage;
|
|
58
|
+
this.#subject = new BehaviorSubject({
|
|
59
|
+
language: this.#language
|
|
60
|
+
});
|
|
61
|
+
}
|
|
83
62
|
getAvailableLanguages() {
|
|
84
|
-
return { languages:
|
|
63
|
+
return { languages: this.#languages.slice() };
|
|
85
64
|
}
|
|
86
65
|
setLanguage(language) {
|
|
87
|
-
const lng = language
|
|
88
|
-
if (lng ===
|
|
66
|
+
const lng = language ?? DEFAULT_LANGUAGE;
|
|
67
|
+
if (lng === this.#language) {
|
|
89
68
|
return;
|
|
90
69
|
}
|
|
91
|
-
if (lng && !
|
|
70
|
+
if (lng && !this.#languages.includes(lng)) {
|
|
92
71
|
throw new Error(
|
|
93
|
-
`Failed to change language to '${lng}', available languages are '${
|
|
72
|
+
`Failed to change language to '${lng}', available languages are '${this.#languages.join(
|
|
94
73
|
"', '"
|
|
95
74
|
)}'`
|
|
96
75
|
);
|
|
97
76
|
}
|
|
98
|
-
|
|
99
|
-
|
|
77
|
+
this.#language = lng;
|
|
78
|
+
this.#subject.next({ language: lng });
|
|
100
79
|
}
|
|
101
80
|
getLanguage() {
|
|
102
|
-
return { language:
|
|
81
|
+
return { language: this.#language };
|
|
103
82
|
}
|
|
104
83
|
language$() {
|
|
105
|
-
return
|
|
84
|
+
return this.#subject;
|
|
106
85
|
}
|
|
107
|
-
}
|
|
108
|
-
_languages = new WeakMap();
|
|
109
|
-
_language = new WeakMap();
|
|
110
|
-
_subject = new WeakMap();
|
|
111
|
-
let AppLanguageSelector = _AppLanguageSelector;
|
|
86
|
+
}
|
|
112
87
|
|
|
113
88
|
export { AppLanguageSelector, DEFAULT_LANGUAGE };
|
|
114
89
|
//# sourceMappingURL=AppLanguageSelector.esm.js.map
|
|
@@ -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":"
|
|
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,25 +1,16 @@
|
|
|
1
1
|
import { BehaviorSubject } from '../../../lib/subjects.esm.js';
|
|
2
2
|
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
-
var __publicField = (obj, key, value) => {
|
|
6
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
-
return value;
|
|
8
|
-
};
|
|
9
3
|
const STORAGE_KEY = "theme";
|
|
10
4
|
class AppThemeSelector {
|
|
11
5
|
constructor(themes) {
|
|
12
6
|
this.themes = themes;
|
|
13
|
-
__publicField(this, "activeThemeId");
|
|
14
|
-
__publicField(this, "subject", new BehaviorSubject(void 0));
|
|
15
7
|
}
|
|
16
8
|
static createWithStorage(themes) {
|
|
17
|
-
var _a;
|
|
18
9
|
const selector = new AppThemeSelector(themes);
|
|
19
10
|
if (!window.localStorage) {
|
|
20
11
|
return selector;
|
|
21
12
|
}
|
|
22
|
-
const initialThemeId =
|
|
13
|
+
const initialThemeId = window.localStorage.getItem(STORAGE_KEY) ?? void 0;
|
|
23
14
|
selector.setActiveThemeId(initialThemeId);
|
|
24
15
|
selector.activeThemeId$().subscribe((themeId) => {
|
|
25
16
|
if (themeId) {
|
|
@@ -29,14 +20,15 @@ class AppThemeSelector {
|
|
|
29
20
|
}
|
|
30
21
|
});
|
|
31
22
|
window.addEventListener("storage", (event) => {
|
|
32
|
-
var _a2;
|
|
33
23
|
if (event.key === STORAGE_KEY) {
|
|
34
|
-
const themeId =
|
|
24
|
+
const themeId = localStorage.getItem(STORAGE_KEY) ?? void 0;
|
|
35
25
|
selector.setActiveThemeId(themeId);
|
|
36
26
|
}
|
|
37
27
|
});
|
|
38
28
|
return selector;
|
|
39
29
|
}
|
|
30
|
+
activeThemeId;
|
|
31
|
+
subject = new BehaviorSubject(void 0);
|
|
40
32
|
getInstalledThemes() {
|
|
41
33
|
return this.themes.slice();
|
|
42
34
|
}
|
|
@@ -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":[
|
|
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,CAAA;AAQb,MAAM,gBAAwC,CAAA;AAAA,EAkCnD,YAA6B,MAAoB,EAAA;AAApB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAAqB;AAAA,EAjClD,OAAO,kBAAkB,MAAoB,EAAA;AAC3C,IAAM,MAAA,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM,CAAA,CAAA;AAE5C,IAAI,IAAA,CAAC,OAAO,YAAc,EAAA;AACxB,MAAO,OAAA,QAAA,CAAA;AAAA,KACT;AAEA,IAAA,MAAM,cACJ,GAAA,MAAA,CAAO,YAAa,CAAA,OAAA,CAAQ,WAAW,CAAK,IAAA,KAAA,CAAA,CAAA;AAE9C,IAAA,QAAA,CAAS,iBAAiB,cAAc,CAAA,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,CAAA;AAAA,OAC3C,MAAA;AACL,QAAO,MAAA,CAAA,YAAA,CAAa,WAAW,WAAW,CAAA,CAAA;AAAA,OAC5C;AAAA,KACD,CAAA,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,CAAA;AACrD,QAAA,QAAA,CAAS,iBAAiB,OAAO,CAAA,CAAA;AAAA,OACnC;AAAA,KACD,CAAA,CAAA;AAED,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AAAA,EAEQ,aAAA,CAAA;AAAA,EACS,OAAA,GAAU,IAAI,eAAA,CAAoC,KAAS,CAAA,CAAA,CAAA;AAAA,EAI5E,kBAAiC,GAAA;AAC/B,IAAO,OAAA,IAAA,CAAK,OAAO,KAAM,EAAA,CAAA;AAAA,GAC3B;AAAA,EAEA,cAAiD,GAAA;AAC/C,IAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AAAA,GACd;AAAA,EAEA,gBAAuC,GAAA;AACrC,IAAA,OAAO,IAAK,CAAA,aAAA,CAAA;AAAA,GACd;AAAA,EAEA,iBAAiB,OAAwB,EAAA;AACvC,IAAA,IAAA,CAAK,aAAgB,GAAA,OAAA,CAAA;AACrB,IAAK,IAAA,CAAA,OAAA,CAAQ,KAAK,OAAO,CAAA,CAAA;AAAA,GAC3B;AACF;;;;"}
|
|
@@ -27,10 +27,9 @@ class FrontendHostDiscovery {
|
|
|
27
27
|
* the provided `pathPattern` appended. The default path pattern is `"/api/{{ pluginId }}"`.
|
|
28
28
|
*/
|
|
29
29
|
static fromConfig(config, options) {
|
|
30
|
-
|
|
31
|
-
const path = (_a = options == null ? void 0 : options.pathPattern) != null ? _a : "/api/{{ pluginId }}";
|
|
30
|
+
const path = options?.pathPattern ?? "/api/{{ pluginId }}";
|
|
32
31
|
const baseUrl = config.getString("backend.baseUrl");
|
|
33
|
-
const endpoints =
|
|
32
|
+
const endpoints = config.getOptionalConfigArray("discovery.endpoints")?.flatMap((e) => {
|
|
34
33
|
const target = typeof e.get("target") === "object" ? e.getString("target.external") : e.getString("target");
|
|
35
34
|
const discovery = UrlPatternDiscovery.compile(target);
|
|
36
35
|
return e.getStringArray("plugins").map((pluginId) => [pluginId, discovery]);
|
|
@@ -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.getString('target.external')\n : e.getString('target');\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,EA6CjD,WAAA,CACW,WACA,eACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA,CAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA,CAAA;AAAA,GAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA1BH,OAAO,UAAW,CAAA,MAAA,EAAgB,OAAoC,EAAA;
|
|
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.getString('target.external')\n : e.getString('target');\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,EA6CjD,WAAA,CACW,WACA,eACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA,CAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA,CAAA;AAAA,GAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA1BH,OAAO,UAAW,CAAA,MAAA,EAAgB,OAAoC,EAAA;AACpE,IAAM,MAAA,IAAA,GAAO,SAAS,WAAe,IAAA,qBAAA,CAAA;AACrC,IAAM,MAAA,OAAA,GAAU,MAAO,CAAA,SAAA,CAAU,iBAAiB,CAAA,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,SAAU,CAAA,iBAAiB,CAC7B,GAAA,CAAA,CAAE,UAAU,QAAQ,CAAA,CAAA;AAC1B,MAAM,MAAA,SAAA,GAAY,mBAAoB,CAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AACpD,MAAO,OAAA,CAAA,CACJ,eAAe,SAAS,CAAA,CACxB,IAAI,CAAY,QAAA,KAAA,CAAC,QAAU,EAAA,SAAS,CAAU,CAAA,CAAA;AAAA,KAClD,CAAA,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,CAAA;AAAA,KACjD,CAAA;AAAA,GACF;AAAA,EAOA,MAAM,WAAW,QAAmC,EAAA;AAClD,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,SAAU,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAC5C,IAAA,IAAI,QAAU,EAAA;AACZ,MAAO,OAAA,QAAA,CAAS,WAAW,QAAQ,CAAA,CAAA;AAAA,KACrC;AACA,IAAO,OAAA,IAAA,CAAK,eAAgB,CAAA,UAAA,CAAW,QAAQ,CAAA,CAAA;AAAA,GACjD;AACF;;;;"}
|
|
@@ -4,7 +4,7 @@ class ErrorAlerter {
|
|
|
4
4
|
this.errorApi = errorApi;
|
|
5
5
|
}
|
|
6
6
|
post(error, context) {
|
|
7
|
-
if (!
|
|
7
|
+
if (!context?.hidden) {
|
|
8
8
|
this.alertApi.post({ message: error.message, severity: "error" });
|
|
9
9
|
}
|
|
10
10
|
return this.errorApi.post(error, context);
|
|
@@ -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,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AAAA,GAChB;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAgC,EAAA;AACzD,IAAI,IAAA,
|
|
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,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AAAA,GAChB;AAAA,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,CAAA;AAAA,KAClE;AAEA,IAAA,OAAO,IAAK,CAAA,QAAA,CAAS,IAAK,CAAA,KAAA,EAAO,OAAO,CAAA,CAAA;AAAA,GAC1C;AAAA,EAEA,MAAS,GAAA;AACP,IAAO,OAAA,IAAA,CAAK,SAAS,MAAO,EAAA,CAAA;AAAA,GAC9B;AACF;;;;"}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { PublishSubject } from '../../../lib/subjects.esm.js';
|
|
2
2
|
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
-
var __publicField = (obj, key, value) => {
|
|
6
|
-
__defNormalProp(obj, key + "" , value);
|
|
7
|
-
return value;
|
|
8
|
-
};
|
|
9
3
|
class ErrorApiForwarder {
|
|
10
|
-
|
|
11
|
-
__publicField(this, "subject", new PublishSubject());
|
|
12
|
-
}
|
|
4
|
+
subject = new PublishSubject();
|
|
13
5
|
post(error, context) {
|
|
14
6
|
this.subject.next({ error, context });
|
|
15
7
|
}
|
|
@@ -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":"
|
|
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,CAAA;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAgC,EAAA;AACzD,IAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,EAAE,KAAA,EAAO,SAAS,CAAA,CAAA;AAAA,GACtC;AAAA,EAEA,MAAuE,GAAA;AACrE,IAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AAAA,GACd;AACF;;;;"}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { FeatureFlagState } from '@backstage/core-plugin-api';
|
|
2
2
|
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
-
var __publicField = (obj, key, value) => {
|
|
6
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
-
return value;
|
|
8
|
-
};
|
|
9
3
|
function validateFlagName(name) {
|
|
10
4
|
if (name.length < 3) {
|
|
11
5
|
throw new Error(
|
|
@@ -24,10 +18,8 @@ function validateFlagName(name) {
|
|
|
24
18
|
}
|
|
25
19
|
}
|
|
26
20
|
class LocalStorageFeatureFlags {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
__publicField(this, "flags");
|
|
30
|
-
}
|
|
21
|
+
registeredFeatureFlags = [];
|
|
22
|
+
flags;
|
|
31
23
|
registerFlag(flag) {
|
|
32
24
|
validateFlagName(flag.name);
|
|
33
25
|
this.registeredFeatureFlags.push(flag);
|
|
@@ -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":"
|
|
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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"}
|
|
@@ -6,10 +6,9 @@ class IdentityAuthInjectorFetchMiddleware {
|
|
|
6
6
|
this.headerValue = headerValue;
|
|
7
7
|
}
|
|
8
8
|
static create(options) {
|
|
9
|
-
var _a, _b;
|
|
10
9
|
const matcher = buildMatcher(options);
|
|
11
|
-
const headerName =
|
|
12
|
-
const headerValue =
|
|
10
|
+
const headerName = options.header?.name || "authorization";
|
|
11
|
+
const headerValue = options.header?.value || ((token) => `Bearer ${token}`);
|
|
13
12
|
return new IdentityAuthInjectorFetchMiddleware(
|
|
14
13
|
options.identityApi,
|
|
15
14
|
matcher,
|
|
@@ -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 constructor(\n public readonly identityApi: IdentityApi,\n public readonly allowUrl: (url: string) => boolean,\n public readonly headerName: string,\n public readonly headerValue: (pluginId: string) => string,\n ) {}\n\n apply(next: typeof fetch): typeof fetch {\n return async (input, init) => {\n // Skip this middleware if the header already exists, or if the URL\n // doesn't match any of the allowlist items, or if there was no token.\n // NOTE(freben): The \"as any\" casts here and below are because of subtle\n // undici type differences that happened in a node types bump. Those are\n // immaterial to the code at hand at runtime, as the global fetch and\n // Request are always taken from the same place.\n const request = new Request(input as any, init);\n const { token } = await this.identityApi.getCredentials();\n if (\n request.headers.get(this.headerName) ||\n typeof token !== 'string' ||\n !token ||\n !this.allowUrl(request.url)\n ) {\n return next(input as any, init);\n }\n\n request.headers.set(this.headerName, this.headerValue(token));\n return next(request);\n };\n }\n}\n\nfunction buildMatcher(options: {\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n}): (url: string) => boolean {\n if (options.allowUrl) {\n return options.allowUrl;\n } else if (options.urlPrefixAllowlist) {\n return buildPrefixMatcher(options.urlPrefixAllowlist);\n } else if (options.config) {\n return buildPrefixMatcher([options.config.getString('backend.baseUrl')]);\n }\n return () => false;\n}\n\nfunction buildPrefixMatcher(prefixes: string[]): (url: string) => boolean {\n const trimmedPrefixes = prefixes.map(prefix => prefix.replace(/\\/$/, ''));\n return url =>\n trimmedPrefixes.some(\n prefix => url === prefix || url.startsWith(`${prefix}/`),\n );\n}\n"],"names":[],"mappings":"AAwBO,MAAM,mCAA+D,CAAA;AAAA,EAuB1E,WACkB,CAAA,WAAA,EACA,QACA,EAAA,UAAA,EACA,WAChB,EAAA;AAJgB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AAAA,GACf;AAAA,EA3BH,OAAO,OAAO,OAS0B,EAAA;
|
|
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 constructor(\n public readonly identityApi: IdentityApi,\n public readonly allowUrl: (url: string) => boolean,\n public readonly headerName: string,\n public readonly headerValue: (pluginId: string) => string,\n ) {}\n\n apply(next: typeof fetch): typeof fetch {\n return async (input, init) => {\n // Skip this middleware if the header already exists, or if the URL\n // doesn't match any of the allowlist items, or if there was no token.\n // NOTE(freben): The \"as any\" casts here and below are because of subtle\n // undici type differences that happened in a node types bump. Those are\n // immaterial to the code at hand at runtime, as the global fetch and\n // Request are always taken from the same place.\n const request = new Request(input as any, init);\n const { token } = await this.identityApi.getCredentials();\n if (\n request.headers.get(this.headerName) ||\n typeof token !== 'string' ||\n !token ||\n !this.allowUrl(request.url)\n ) {\n return next(input as any, init);\n }\n\n request.headers.set(this.headerName, this.headerValue(token));\n return next(request);\n };\n }\n}\n\nfunction buildMatcher(options: {\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n}): (url: string) => boolean {\n if (options.allowUrl) {\n return options.allowUrl;\n } else if (options.urlPrefixAllowlist) {\n return buildPrefixMatcher(options.urlPrefixAllowlist);\n } else if (options.config) {\n return buildPrefixMatcher([options.config.getString('backend.baseUrl')]);\n }\n return () => false;\n}\n\nfunction buildPrefixMatcher(prefixes: string[]): (url: string) => boolean {\n const trimmedPrefixes = prefixes.map(prefix => prefix.replace(/\\/$/, ''));\n return url =>\n trimmedPrefixes.some(\n prefix => url === prefix || url.startsWith(`${prefix}/`),\n );\n}\n"],"names":[],"mappings":"AAwBO,MAAM,mCAA+D,CAAA;AAAA,EAuB1E,WACkB,CAAA,WAAA,EACA,QACA,EAAA,UAAA,EACA,WAChB,EAAA;AAJgB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AAAA,GACf;AAAA,EA3BH,OAAO,OAAO,OAS0B,EAAA;AACtC,IAAM,MAAA,OAAA,GAAU,aAAa,OAAO,CAAA,CAAA;AACpC,IAAM,MAAA,UAAA,GAAa,OAAQ,CAAA,MAAA,EAAQ,IAAQ,IAAA,eAAA,CAAA;AAC3C,IAAA,MAAM,cAAc,OAAQ,CAAA,MAAA,EAAQ,KAAU,KAAA,CAAA,KAAA,KAAS,UAAU,KAAK,CAAA,CAAA,CAAA,CAAA;AAEtE,IAAA,OAAO,IAAI,mCAAA;AAAA,MACT,OAAQ,CAAA,WAAA;AAAA,MACR,OAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EASA,MAAM,IAAkC,EAAA;AACtC,IAAO,OAAA,OAAO,OAAO,IAAS,KAAA;AAO5B,MAAA,MAAM,OAAU,GAAA,IAAI,OAAQ,CAAA,KAAA,EAAc,IAAI,CAAA,CAAA;AAC9C,MAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,YAAY,cAAe,EAAA,CAAA;AACxD,MAAA,IACE,QAAQ,OAAQ,CAAA,GAAA,CAAI,IAAK,CAAA,UAAU,KACnC,OAAO,KAAA,KAAU,QACjB,IAAA,CAAC,SACD,CAAC,IAAA,CAAK,QAAS,CAAA,OAAA,CAAQ,GAAG,CAC1B,EAAA;AACA,QAAO,OAAA,IAAA,CAAK,OAAc,IAAI,CAAA,CAAA;AAAA,OAChC;AAEA,MAAA,OAAA,CAAQ,QAAQ,GAAI,CAAA,IAAA,CAAK,YAAY,IAAK,CAAA,WAAA,CAAY,KAAK,CAAC,CAAA,CAAA;AAC5D,MAAA,OAAO,KAAK,OAAO,CAAA,CAAA;AAAA,KACrB,CAAA;AAAA,GACF;AACF,CAAA;AAEA,SAAS,aAAa,OAIO,EAAA;AAC3B,EAAA,IAAI,QAAQ,QAAU,EAAA;AACpB,IAAA,OAAO,OAAQ,CAAA,QAAA,CAAA;AAAA,GACjB,MAAA,IAAW,QAAQ,kBAAoB,EAAA;AACrC,IAAO,OAAA,kBAAA,CAAmB,QAAQ,kBAAkB,CAAA,CAAA;AAAA,GACtD,MAAA,IAAW,QAAQ,MAAQ,EAAA;AACzB,IAAA,OAAO,mBAAmB,CAAC,OAAA,CAAQ,OAAO,SAAU,CAAA,iBAAiB,CAAC,CAAC,CAAA,CAAA;AAAA,GACzE;AACA,EAAA,OAAO,MAAM,KAAA,CAAA;AACf,CAAA;AAEA,SAAS,mBAAmB,QAA8C,EAAA;AACxE,EAAM,MAAA,eAAA,GAAkB,SAAS,GAAI,CAAA,CAAA,MAAA,KAAU,OAAO,OAAQ,CAAA,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA;AACxE,EAAA,OAAO,SACL,eAAgB,CAAA,IAAA;AAAA,IACd,YAAU,GAAQ,KAAA,MAAA,IAAU,IAAI,UAAW,CAAA,CAAA,EAAG,MAAM,CAAG,CAAA,CAAA,CAAA;AAAA,GACzD,CAAA;AACJ;;;;"}
|
|
@@ -33,7 +33,7 @@ class PluginProtocolResolverFetchMiddleware {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
function isUrl(a) {
|
|
36
|
-
return typeof a === "object" &&
|
|
36
|
+
return typeof a === "object" && a?.constructor === URL;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export { PluginProtocolResolverFetchMiddleware };
|
|
@@ -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,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,CAAA,EAAG,IAAK,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,CAAA,EAAI,KAAM,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,CAAA,CAAA;AAC/D,CAAA;AAMO,MAAM,qCAAiE,CAAA;AAAA,EAC5E,YAA6B,YAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AAAA,GAA6B;AAAA,EAE1D,MAAM,IAAkC,EAAA;AACtC,IAAO,OAAA,OAAO,OAAO,IAAS,KAAA;AAK5B,MAAA,MAAM,OAAU,GAAA,IAAI,OAAQ,CAAA,KAAA,EAAc,IAAI,CAAA,CAAA;AAC9C,MAAA,MAAM,MAAS,GAAA,WAAA,CAAA;AAEf,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAI,CAAA,UAAA,CAAW,MAAM,CAAG,EAAA;AACnC,QAAO,OAAA,IAAA,CAAK,OAAc,IAAI,CAAA,CAAA;AAAA,OAChC;AAIA,MAAM,MAAA,EAAE,UAAU,QAAU,EAAA,MAAA,EAAQ,MAAM,QAAU,EAAA,QAAA,KAAa,IAAI,GAAA;AAAA,QACnE,UAAU,OAAQ,CAAA,GAAA,CAAI,SAAU,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAAA,OAChD,CAAA;AAEA,MAAA,IAAI,IAAO,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA,CAAA;AACtD,MAAA,IAAI,YAAY,QAAU,EAAA;AACxB,QAAM,MAAA,OAAA,GAAU,IAAI,GAAA,CAAI,IAAI,CAAA,CAAA;AAC5B,QAAM,MAAA,SAAA,GAAY,GAAG,QAAQ,CAAA,EAAG,WAAW,CAAI,CAAA,EAAA,QAAQ,KAAK,EAAE,CAAA,CAAA,CAAA,CAAA;AAC9D,QAAO,IAAA,GAAA,CAAA,EAAG,OAAQ,CAAA,QAAQ,CAAK,EAAA,EAAA,SAAS,GAAG,OAAQ,CAAA,IAAI,CAAG,EAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA,CAAA;AAAA,OAC5E;AAEA,MAAM,MAAA,MAAA,GAAS,GAAG,IAAK,CAAA,IAAA,EAAM,QAAQ,CAAC,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAA,CAAA;AACtD,MAAO,OAAA,IAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAO,KAAU,KAAA,QAAA,IAAY,KAAM,CAAA,KAAK,IAAI,IAAQ,GAAA,KAAA;AAAA,OACtD,CAAA;AAAA,KACF,CAAA;AAAA,GACF;AACF,CAAA;AAEA,SAAS,MAAM,CAAsB,EAAA;AACnC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAY,IAAA,CAAA,
|
|
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,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,CAAA,EAAG,IAAK,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,CAAA,EAAI,KAAM,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,CAAA,CAAA;AAC/D,CAAA;AAMO,MAAM,qCAAiE,CAAA;AAAA,EAC5E,YAA6B,YAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AAAA,GAA6B;AAAA,EAE1D,MAAM,IAAkC,EAAA;AACtC,IAAO,OAAA,OAAO,OAAO,IAAS,KAAA;AAK5B,MAAA,MAAM,OAAU,GAAA,IAAI,OAAQ,CAAA,KAAA,EAAc,IAAI,CAAA,CAAA;AAC9C,MAAA,MAAM,MAAS,GAAA,WAAA,CAAA;AAEf,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAI,CAAA,UAAA,CAAW,MAAM,CAAG,EAAA;AACnC,QAAO,OAAA,IAAA,CAAK,OAAc,IAAI,CAAA,CAAA;AAAA,OAChC;AAIA,MAAM,MAAA,EAAE,UAAU,QAAU,EAAA,MAAA,EAAQ,MAAM,QAAU,EAAA,QAAA,KAAa,IAAI,GAAA;AAAA,QACnE,UAAU,OAAQ,CAAA,GAAA,CAAI,SAAU,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAAA,OAChD,CAAA;AAEA,MAAA,IAAI,IAAO,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA,CAAA;AACtD,MAAA,IAAI,YAAY,QAAU,EAAA;AACxB,QAAM,MAAA,OAAA,GAAU,IAAI,GAAA,CAAI,IAAI,CAAA,CAAA;AAC5B,QAAM,MAAA,SAAA,GAAY,GAAG,QAAQ,CAAA,EAAG,WAAW,CAAI,CAAA,EAAA,QAAQ,KAAK,EAAE,CAAA,CAAA,CAAA,CAAA;AAC9D,QAAO,IAAA,GAAA,CAAA,EAAG,OAAQ,CAAA,QAAQ,CAAK,EAAA,EAAA,SAAS,GAAG,OAAQ,CAAA,IAAI,CAAG,EAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA,CAAA;AAAA,OAC5E;AAEA,MAAM,MAAA,MAAA,GAAS,GAAG,IAAK,CAAA,IAAA,EAAM,QAAQ,CAAC,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAA,CAAA;AACtD,MAAO,OAAA,IAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAO,KAAU,KAAA,QAAA,IAAY,KAAM,CAAA,KAAK,IAAI,IAAQ,GAAA,KAAA;AAAA,OACtD,CAAA;AAAA,KACF,CAAA;AAAA,GACF;AACF,CAAA;AAEA,SAAS,MAAM,CAAsB,EAAA;AACnC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAY,IAAA,CAAA,EAAG,WAAgB,KAAA,GAAA,CAAA;AACrD;;;;"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
function createFetchApi(options) {
|
|
2
|
-
var _a;
|
|
3
2
|
let result = options.baseImplementation || global.fetch;
|
|
4
|
-
const middleware = [
|
|
3
|
+
const middleware = [options.middleware ?? []].flat().reverse();
|
|
5
4
|
for (const m of middleware) {
|
|
6
5
|
result = m.apply(result);
|
|
7
6
|
}
|
|
@@ -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;
|
|
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,CAAA;AAElD,EAAM,MAAA,UAAA,GAAa,CAAC,OAAQ,CAAA,UAAA,IAAc,EAAE,CAAA,CAAE,IAAK,EAAA,CAAE,OAAQ,EAAA,CAAA;AAC7D,EAAA,KAAA,MAAW,KAAK,UAAY,EAAA;AAC1B,IAAS,MAAA,GAAA,CAAA,CAAE,MAAM,MAAM,CAAA,CAAA;AAAA,GACzB;AAEA,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,MAAA;AAAA,GACT,CAAA;AACF;;;;"}
|