@backstage/frontend-defaults 0.1.7-next.0 → 0.2.0-next.2
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 +29 -0
- package/dist/createApp.esm.js +16 -24
- package/dist/createApp.esm.js.map +1 -1
- package/dist/discovery.esm.js +15 -15
- package/dist/discovery.esm.js.map +1 -1
- package/dist/index.d.ts +19 -2
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/resolution.esm.js +25 -0
- package/dist/resolution.esm.js.map +1 -0
- package/package.json +6 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @backstage/frontend-defaults
|
|
2
2
|
|
|
3
|
+
## 0.2.0-next.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8250ffe: **BREAKING**: Dropped support for the removed opaque `@backstage/ExtensionOverrides` and `@backstage/BackstagePlugin` types.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 4d18b55: It's now possible to provide a middleware that wraps all extension factories by passing an `extensionFactoryMiddleware` to either `createApp()` or `createSpecializedApp()`.
|
|
12
|
+
- abcdf44: Internal refactor to match updated `createSpecializedApp`.
|
|
13
|
+
- e3f19db: Feature discovery and resolution logic used in `createApp` is now exposed via the `discoverAvailableFeatures` and `resolveAsyncFeatures` functions respectively.
|
|
14
|
+
- Updated dependencies
|
|
15
|
+
- @backstage/frontend-app-api@0.11.0-next.2
|
|
16
|
+
- @backstage/frontend-plugin-api@0.10.0-next.2
|
|
17
|
+
- @backstage/plugin-app@0.1.7-next.2
|
|
18
|
+
- @backstage/config@1.3.2
|
|
19
|
+
- @backstage/errors@1.2.7
|
|
20
|
+
|
|
21
|
+
## 0.1.7-next.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
- @backstage/plugin-app@0.1.7-next.1
|
|
27
|
+
- @backstage/config@1.3.2
|
|
28
|
+
- @backstage/errors@1.2.7
|
|
29
|
+
- @backstage/frontend-app-api@0.10.6-next.1
|
|
30
|
+
- @backstage/frontend-plugin-api@0.9.6-next.1
|
|
31
|
+
|
|
3
32
|
## 0.1.7-next.0
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/dist/createApp.esm.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { coreExtensionData } from '@backstage/frontend-plugin-api';
|
|
3
3
|
import { defaultConfigLoaderSync } from './core-app-api/src/app/defaultConfigLoader.esm.js';
|
|
4
4
|
import { overrideBaseUrlConfigs } from './core-app-api/src/app/overrideBaseUrlConfigs.esm.js';
|
|
5
|
-
import { getAvailableFeatures } from './discovery.esm.js';
|
|
6
5
|
import { ConfigReader } from '@backstage/config';
|
|
7
|
-
import appPlugin from '@backstage/plugin-app';
|
|
8
6
|
import { createSpecializedApp } from '@backstage/frontend-app-api';
|
|
7
|
+
import appPlugin from '@backstage/plugin-app';
|
|
8
|
+
import { discoverAvailableFeatures } from './discovery.esm.js';
|
|
9
|
+
import { resolveAsyncFeatures } from './resolution.esm.js';
|
|
9
10
|
|
|
10
11
|
function createApp(options) {
|
|
11
12
|
let suspenseFallback = options?.loadingComponent;
|
|
@@ -16,30 +17,21 @@ function createApp(options) {
|
|
|
16
17
|
const config = await options?.configLoader?.().then((c) => c.config) ?? ConfigReader.fromConfigs(
|
|
17
18
|
overrideBaseUrlConfigs(defaultConfigLoaderSync())
|
|
18
19
|
);
|
|
19
|
-
const discoveredFeatures =
|
|
20
|
-
const providedFeatures =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const result = await entry.load({ config });
|
|
25
|
-
providedFeatures.push(...result.features);
|
|
26
|
-
} catch (e) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`Failed to read frontend features from loader '${entry.getLoaderName()}', ${stringifyError(
|
|
29
|
-
e
|
|
30
|
-
)}`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
providedFeatures.push(entry);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
20
|
+
const { features: discoveredFeatures } = discoverAvailableFeatures(config);
|
|
21
|
+
const { features: providedFeatures } = await resolveAsyncFeatures({
|
|
22
|
+
config,
|
|
23
|
+
features: options?.features
|
|
24
|
+
});
|
|
37
25
|
const app = createSpecializedApp({
|
|
38
26
|
config,
|
|
39
27
|
features: [appPlugin, ...discoveredFeatures, ...providedFeatures],
|
|
40
|
-
bindRoutes: options?.bindRoutes
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
bindRoutes: options?.bindRoutes,
|
|
29
|
+
extensionFactoryMiddleware: options?.extensionFactoryMiddleware
|
|
30
|
+
});
|
|
31
|
+
const rootEl = app.tree.root.instance.getData(
|
|
32
|
+
coreExtensionData.reactElement
|
|
33
|
+
);
|
|
34
|
+
return { default: () => rootEl };
|
|
43
35
|
}
|
|
44
36
|
return {
|
|
45
37
|
createRoot() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createApp.esm.js","sources":["../src/createApp.tsx"],"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 React, { JSX, ReactNode } from 'react';\nimport {
|
|
1
|
+
{"version":3,"file":"createApp.esm.js","sources":["../src/createApp.tsx"],"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 React, { JSX, ReactNode } from 'react';\nimport {\n ConfigApi,\n coreExtensionData,\n ExtensionFactoryMiddleware,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { defaultConfigLoaderSync } from '../../core-app-api/src/app/defaultConfigLoader';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { overrideBaseUrlConfigs } from '../../core-app-api/src/app/overrideBaseUrlConfigs';\nimport { ConfigReader } from '@backstage/config';\nimport {\n CreateAppRouteBinder,\n FrontendFeature,\n createSpecializedApp,\n} from '@backstage/frontend-app-api';\nimport appPlugin from '@backstage/plugin-app';\nimport { discoverAvailableFeatures } from './discovery';\nimport { resolveAsyncFeatures } from './resolution';\n\n/**\n * A source of dynamically loaded frontend features.\n *\n * @public\n */\nexport interface CreateAppFeatureLoader {\n /**\n * Returns name of this loader. suitable for showing to users.\n */\n getLoaderName(): string;\n\n /**\n * Loads a number of features dynamically.\n */\n load(options: { config: ConfigApi }): Promise<{\n features: FrontendFeature[];\n }>;\n}\n\n/**\n * Options for {@link createApp}.\n *\n * @public\n */\nexport interface CreateAppOptions {\n features?: (FrontendFeature | CreateAppFeatureLoader)[];\n configLoader?: () => Promise<{ config: ConfigApi }>;\n bindRoutes?(context: { bind: CreateAppRouteBinder }): void;\n /**\n * The component to render while loading the app (waiting for config, features, etc)\n *\n * Is the text \"Loading...\" by default.\n * If set to \"null\" then no loading fallback component is rendered. *\n */\n loadingComponent?: ReactNode;\n extensionFactoryMiddleware?:\n | ExtensionFactoryMiddleware\n | ExtensionFactoryMiddleware[];\n}\n\n/**\n * Creates a new Backstage frontend app instance. See https://backstage.io/docs/frontend-system/building-apps/index\n *\n * @public\n */\nexport function createApp(options?: CreateAppOptions): {\n createRoot(): JSX.Element;\n} {\n let suspenseFallback = options?.loadingComponent;\n if (suspenseFallback === undefined) {\n suspenseFallback = 'Loading...';\n }\n\n async function appLoader() {\n const config =\n (await options?.configLoader?.().then(c => c.config)) ??\n ConfigReader.fromConfigs(\n overrideBaseUrlConfigs(defaultConfigLoaderSync()),\n );\n\n const { features: discoveredFeatures } = discoverAvailableFeatures(config);\n const { features: providedFeatures } = await resolveAsyncFeatures({\n config,\n features: options?.features,\n });\n\n const app = createSpecializedApp({\n config,\n features: [appPlugin, ...discoveredFeatures, ...providedFeatures],\n bindRoutes: options?.bindRoutes,\n extensionFactoryMiddleware: options?.extensionFactoryMiddleware,\n });\n\n const rootEl = app.tree.root.instance!.getData(\n coreExtensionData.reactElement,\n );\n\n return { default: () => rootEl };\n }\n\n return {\n createRoot() {\n const LazyApp = React.lazy(appLoader);\n return (\n <React.Suspense fallback={suspenseFallback}>\n <LazyApp />\n </React.Suspense>\n );\n },\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;AAiFO,SAAS,UAAU,OAExB,EAAA;AACA,EAAA,IAAI,mBAAmB,OAAS,EAAA,gBAAA;AAChC,EAAA,IAAI,qBAAqB,KAAW,CAAA,EAAA;AAClC,IAAmB,gBAAA,GAAA,YAAA;AAAA;AAGrB,EAAA,eAAe,SAAY,GAAA;AACzB,IAAM,MAAA,MAAA,GACH,MAAM,OAAA,EAAS,YAAe,IAAA,CAAE,KAAK,CAAK,CAAA,KAAA,CAAA,CAAE,MAAM,CAAA,IACnD,YAAa,CAAA,WAAA;AAAA,MACX,sBAAA,CAAuB,yBAAyB;AAAA,KAClD;AAEF,IAAA,MAAM,EAAE,QAAA,EAAU,kBAAmB,EAAA,GAAI,0BAA0B,MAAM,CAAA;AACzE,IAAA,MAAM,EAAE,QAAA,EAAU,gBAAiB,EAAA,GAAI,MAAM,oBAAqB,CAAA;AAAA,MAChE,MAAA;AAAA,MACA,UAAU,OAAS,EAAA;AAAA,KACpB,CAAA;AAED,IAAA,MAAM,MAAM,oBAAqB,CAAA;AAAA,MAC/B,MAAA;AAAA,MACA,UAAU,CAAC,SAAA,EAAW,GAAG,kBAAA,EAAoB,GAAG,gBAAgB,CAAA;AAAA,MAChE,YAAY,OAAS,EAAA,UAAA;AAAA,MACrB,4BAA4B,OAAS,EAAA;AAAA,KACtC,CAAA;AAED,IAAA,MAAM,MAAS,GAAA,GAAA,CAAI,IAAK,CAAA,IAAA,CAAK,QAAU,CAAA,OAAA;AAAA,MACrC,iBAAkB,CAAA;AAAA,KACpB;AAEA,IAAO,OAAA,EAAE,OAAS,EAAA,MAAM,MAAO,EAAA;AAAA;AAGjC,EAAO,OAAA;AAAA,IACL,UAAa,GAAA;AACX,MAAM,MAAA,OAAA,GAAU,KAAM,CAAA,IAAA,CAAK,SAAS,CAAA;AACpC,MACE,uBAAA,KAAA,CAAA,aAAA,CAAC,MAAM,QAAN,EAAA,EAAe,UAAU,gBACxB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,aAAQ,CACX,CAAA;AAAA;AAEJ,GACF;AACF;;;;"}
|
package/dist/discovery.esm.js
CHANGED
|
@@ -27,30 +27,30 @@ function readPackageDetectionConfig(config) {
|
|
|
27
27
|
exclude: packagesConfig.getOptionalStringArray("exclude")
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
function
|
|
30
|
+
function discoverAvailableFeatures(config) {
|
|
31
31
|
const discovered = window["__@backstage/discovered__"];
|
|
32
32
|
const detection = readPackageDetectionConfig(config);
|
|
33
33
|
if (!detection) {
|
|
34
|
-
return [];
|
|
34
|
+
return { features: [] };
|
|
35
35
|
}
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
return {
|
|
37
|
+
features: discovered?.modules.filter(({ name }) => {
|
|
38
|
+
if (detection.exclude?.includes(name)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (detection.include && !detection.include.includes(name)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}).map((m) => m.default).filter(isBackstageFeature) ?? []
|
|
46
|
+
};
|
|
45
47
|
}
|
|
46
48
|
function isBackstageFeature(obj) {
|
|
47
49
|
if (obj !== null && typeof obj === "object" && "$$type" in obj) {
|
|
48
|
-
return obj.$$type === "@backstage/FrontendPlugin" || obj.$$type === "@backstage/FrontendModule"
|
|
49
|
-
// are no longer supported
|
|
50
|
-
obj.$$type === "@backstage/BackstagePlugin" || obj.$$type === "@backstage/ExtensionOverrides";
|
|
50
|
+
return obj.$$type === "@backstage/FrontendPlugin" || obj.$$type === "@backstage/FrontendModule";
|
|
51
51
|
}
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export {
|
|
55
|
+
export { discoverAvailableFeatures };
|
|
56
56
|
//# sourceMappingURL=discovery.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.esm.js","sources":["../src/discovery.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\nimport { Config, ConfigReader } from '@backstage/config';\nimport { FrontendFeature } from '@backstage/frontend-app-api';\n\ninterface DiscoveryGlobal {\n modules: Array<{ name: string; export?: string; default: unknown }>;\n}\n\nfunction readPackageDetectionConfig(config: Config) {\n const packages = config.getOptional('app.experimental.packages');\n if (packages === undefined || packages === null) {\n return undefined;\n }\n\n if (typeof packages === 'string') {\n if (packages !== 'all') {\n throw new Error(\n `Invalid app.experimental.packages mode, got '${packages}', expected 'all'`,\n );\n }\n return {};\n }\n\n if (typeof packages !== 'object' || Array.isArray(packages)) {\n throw new Error(\n \"Invalid config at 'app.experimental.packages', expected object\",\n );\n }\n const packagesConfig = new ConfigReader(\n packages,\n 'app.experimental.packages',\n );\n\n return {\n include: packagesConfig.getOptionalStringArray('include'),\n exclude: packagesConfig.getOptionalStringArray('exclude'),\n };\n}\n\n/**\n * @
|
|
1
|
+
{"version":3,"file":"discovery.esm.js","sources":["../src/discovery.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\nimport { Config, ConfigReader } from '@backstage/config';\nimport { FrontendFeature } from '@backstage/frontend-app-api';\n\ninterface DiscoveryGlobal {\n modules: Array<{ name: string; export?: string; default: unknown }>;\n}\n\nfunction readPackageDetectionConfig(config: Config) {\n const packages = config.getOptional('app.experimental.packages');\n if (packages === undefined || packages === null) {\n return undefined;\n }\n\n if (typeof packages === 'string') {\n if (packages !== 'all') {\n throw new Error(\n `Invalid app.experimental.packages mode, got '${packages}', expected 'all'`,\n );\n }\n return {};\n }\n\n if (typeof packages !== 'object' || Array.isArray(packages)) {\n throw new Error(\n \"Invalid config at 'app.experimental.packages', expected object\",\n );\n }\n const packagesConfig = new ConfigReader(\n packages,\n 'app.experimental.packages',\n );\n\n return {\n include: packagesConfig.getOptionalStringArray('include'),\n exclude: packagesConfig.getOptionalStringArray('exclude'),\n };\n}\n\n/**\n * @public\n */\nexport function discoverAvailableFeatures(config: Config): {\n features: FrontendFeature[];\n} {\n const discovered = (\n window as { '__@backstage/discovered__'?: DiscoveryGlobal }\n )['__@backstage/discovered__'];\n\n const detection = readPackageDetectionConfig(config);\n if (!detection) {\n return { features: [] };\n }\n\n return {\n features:\n discovered?.modules\n .filter(({ name }) => {\n if (detection.exclude?.includes(name)) {\n return false;\n }\n if (detection.include && !detection.include.includes(name)) {\n return false;\n }\n return true;\n })\n .map(m => m.default)\n .filter(isBackstageFeature) ?? [],\n };\n}\n\nfunction isBackstageFeature(obj: unknown): obj is FrontendFeature {\n if (obj !== null && typeof obj === 'object' && '$$type' in obj) {\n return (\n obj.$$type === '@backstage/FrontendPlugin' ||\n obj.$$type === '@backstage/FrontendModule'\n );\n }\n return false;\n}\n"],"names":[],"mappings":";;AAuBA,SAAS,2BAA2B,MAAgB,EAAA;AAClD,EAAM,MAAA,QAAA,GAAW,MAAO,CAAA,WAAA,CAAY,2BAA2B,CAAA;AAC/D,EAAI,IAAA,QAAA,KAAa,KAAa,CAAA,IAAA,QAAA,KAAa,IAAM,EAAA;AAC/C,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAI,IAAA,OAAO,aAAa,QAAU,EAAA;AAChC,IAAA,IAAI,aAAa,KAAO,EAAA;AACtB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,gDAAgD,QAAQ,CAAA,iBAAA;AAAA,OAC1D;AAAA;AAEF,IAAA,OAAO,EAAC;AAAA;AAGV,EAAA,IAAI,OAAO,QAAa,KAAA,QAAA,IAAY,KAAM,CAAA,OAAA,CAAQ,QAAQ,CAAG,EAAA;AAC3D,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA;AAEF,EAAA,MAAM,iBAAiB,IAAI,YAAA;AAAA,IACzB,QAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,OAAA,EAAS,cAAe,CAAA,sBAAA,CAAuB,SAAS,CAAA;AAAA,IACxD,OAAA,EAAS,cAAe,CAAA,sBAAA,CAAuB,SAAS;AAAA,GAC1D;AACF;AAKO,SAAS,0BAA0B,MAExC,EAAA;AACA,EAAM,MAAA,UAAA,GACJ,OACA,2BAA2B,CAAA;AAE7B,EAAM,MAAA,SAAA,GAAY,2BAA2B,MAAM,CAAA;AACnD,EAAA,IAAI,CAAC,SAAW,EAAA;AACd,IAAO,OAAA,EAAE,QAAU,EAAA,EAAG,EAAA;AAAA;AAGxB,EAAO,OAAA;AAAA,IACL,UACE,UAAY,EAAA,OAAA,CACT,OAAO,CAAC,EAAE,MAAW,KAAA;AACpB,MAAA,IAAI,SAAU,CAAA,OAAA,EAAS,QAAS,CAAA,IAAI,CAAG,EAAA;AACrC,QAAO,OAAA,KAAA;AAAA;AAET,MAAA,IAAI,UAAU,OAAW,IAAA,CAAC,UAAU,OAAQ,CAAA,QAAA,CAAS,IAAI,CAAG,EAAA;AAC1D,QAAO,OAAA,KAAA;AAAA;AAET,MAAO,OAAA,IAAA;AAAA,KACR,CACA,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,OAAO,CAClB,CAAA,MAAA,CAAO,kBAAkB,CAAA,IAAK;AAAC,GACtC;AACF;AAEA,SAAS,mBAAmB,GAAsC,EAAA;AAChE,EAAA,IAAI,QAAQ,IAAQ,IAAA,OAAO,GAAQ,KAAA,QAAA,IAAY,YAAY,GAAK,EAAA;AAC9D,IAAA,OACE,GAAI,CAAA,MAAA,KAAW,2BACf,IAAA,GAAA,CAAI,MAAW,KAAA,2BAAA;AAAA;AAGnB,EAAO,OAAA,KAAA;AACT;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ReactNode, JSX } from 'react';
|
|
2
|
-
import { ConfigApi } from '@backstage/frontend-plugin-api';
|
|
2
|
+
import { ConfigApi, ExtensionFactoryMiddleware } from '@backstage/frontend-plugin-api';
|
|
3
3
|
import { FrontendFeature, CreateAppRouteBinder } from '@backstage/frontend-app-api';
|
|
4
|
+
import { Config } from '@backstage/config';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* A source of dynamically loaded frontend features.
|
|
@@ -41,6 +42,7 @@ interface CreateAppOptions {
|
|
|
41
42
|
* If set to "null" then no loading fallback component is rendered. *
|
|
42
43
|
*/
|
|
43
44
|
loadingComponent?: ReactNode;
|
|
45
|
+
extensionFactoryMiddleware?: ExtensionFactoryMiddleware | ExtensionFactoryMiddleware[];
|
|
44
46
|
}
|
|
45
47
|
/**
|
|
46
48
|
* Creates a new Backstage frontend app instance. See https://backstage.io/docs/frontend-system/building-apps/index
|
|
@@ -75,4 +77,19 @@ declare function createPublicSignInApp(options?: CreateAppOptions): {
|
|
|
75
77
|
createRoot(): React.JSX.Element;
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
/**
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
declare function discoverAvailableFeatures(config: Config): {
|
|
84
|
+
features: FrontendFeature[];
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/** @public */
|
|
88
|
+
declare function resolveAsyncFeatures(options: {
|
|
89
|
+
config: Config;
|
|
90
|
+
features?: (FrontendFeature | CreateAppFeatureLoader)[];
|
|
91
|
+
}): Promise<{
|
|
92
|
+
features: FrontendFeature[];
|
|
93
|
+
}>;
|
|
94
|
+
|
|
95
|
+
export { type CreateAppFeatureLoader, type CreateAppOptions, createApp, createPublicSignInApp, discoverAvailableFeatures, resolveAsyncFeatures };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { createApp } from './createApp.esm.js';
|
|
2
2
|
export { createPublicSignInApp } from './createPublicSignInApp.esm.js';
|
|
3
|
+
export { discoverAvailableFeatures } from './discovery.esm.js';
|
|
4
|
+
export { resolveAsyncFeatures } from './resolution.esm.js';
|
|
3
5
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { stringifyError } from '@backstage/errors';
|
|
2
|
+
|
|
3
|
+
async function resolveAsyncFeatures(options) {
|
|
4
|
+
const features = [];
|
|
5
|
+
for (const entry of options.features ?? []) {
|
|
6
|
+
if ("load" in entry) {
|
|
7
|
+
try {
|
|
8
|
+
const result = await entry.load({ config: options.config });
|
|
9
|
+
features.push(...result.features);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`Failed to read frontend features from loader '${entry.getLoaderName()}', ${stringifyError(
|
|
13
|
+
e
|
|
14
|
+
)}`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
features.push(entry);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { features };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { resolveAsyncFeatures };
|
|
25
|
+
//# sourceMappingURL=resolution.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolution.esm.js","sources":["../src/resolution.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { stringifyError } from '@backstage/errors';\nimport { FrontendFeature } from '@backstage/frontend-app-api';\nimport { CreateAppFeatureLoader } from './createApp';\n\n/** @public */\nexport async function resolveAsyncFeatures(options: {\n config: Config;\n features?: (FrontendFeature | CreateAppFeatureLoader)[];\n}): Promise<{ features: FrontendFeature[] }> {\n const features = [];\n for (const entry of options.features ?? []) {\n if ('load' in entry) {\n try {\n const result = await entry.load({ config: options.config });\n features.push(...result.features);\n } catch (e) {\n throw new Error(\n `Failed to read frontend features from loader '${entry.getLoaderName()}', ${stringifyError(\n e,\n )}`,\n );\n }\n } else {\n features.push(entry);\n }\n }\n return { features };\n}\n"],"names":[],"mappings":";;AAsBA,eAAsB,qBAAqB,OAGE,EAAA;AAC3C,EAAA,MAAM,WAAW,EAAC;AAClB,EAAA,KAAA,MAAW,KAAS,IAAA,OAAA,CAAQ,QAAY,IAAA,EAAI,EAAA;AAC1C,IAAA,IAAI,UAAU,KAAO,EAAA;AACnB,MAAI,IAAA;AACF,QAAM,MAAA,MAAA,GAAS,MAAM,KAAM,CAAA,IAAA,CAAK,EAAE,MAAQ,EAAA,OAAA,CAAQ,QAAQ,CAAA;AAC1D,QAAS,QAAA,CAAA,IAAA,CAAK,GAAG,MAAA,CAAO,QAAQ,CAAA;AAAA,eACzB,CAAG,EAAA;AACV,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAiD,8CAAA,EAAA,KAAA,CAAM,aAAc,EAAC,CAAM,GAAA,EAAA,cAAA;AAAA,YAC1E;AAAA,WACD,CAAA;AAAA,SACH;AAAA;AACF,KACK,MAAA;AACL,MAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AAAA;AACrB;AAEF,EAAA,OAAO,EAAE,QAAS,EAAA;AACpB;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-defaults",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-next.2",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -33,15 +33,15 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@backstage/config": "1.3.2",
|
|
35
35
|
"@backstage/errors": "1.2.7",
|
|
36
|
-
"@backstage/frontend-app-api": "0.
|
|
37
|
-
"@backstage/frontend-plugin-api": "0.
|
|
38
|
-
"@backstage/plugin-app": "0.1.7-next.
|
|
36
|
+
"@backstage/frontend-app-api": "0.11.0-next.2",
|
|
37
|
+
"@backstage/frontend-plugin-api": "0.10.0-next.2",
|
|
38
|
+
"@backstage/plugin-app": "0.1.7-next.2",
|
|
39
39
|
"@react-hookz/web": "^24.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@backstage/cli": "0.
|
|
42
|
+
"@backstage/cli": "0.31.0-next.1",
|
|
43
43
|
"@backstage/core-plugin-api": "1.10.4",
|
|
44
|
-
"@backstage/test-utils": "1.7.
|
|
44
|
+
"@backstage/test-utils": "1.7.6-next.0",
|
|
45
45
|
"@testing-library/jest-dom": "^6.0.0",
|
|
46
46
|
"@testing-library/react": "^16.0.0",
|
|
47
47
|
"@types/react": "^18.0.0",
|
|
@@ -60,12 +60,5 @@
|
|
|
60
60
|
"optional": true
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
|
-
"typesVersions": {
|
|
64
|
-
"*": {
|
|
65
|
-
"index": [
|
|
66
|
-
"dist/index.d.ts"
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
63
|
"module": "./dist/index.esm.js"
|
|
71
64
|
}
|