@backstage/backend-dynamic-feature-service 0.4.3 → 0.4.4-next.1
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 +46 -11
- package/dist/index.d.ts +1 -0
- package/dist/manager/plugin-manager.cjs.js +7 -15
- package/dist/manager/plugin-manager.cjs.js.map +1 -1
- package/dist/scanner/plugin-scanner.cjs.js +36 -36
- package/dist/scanner/plugin-scanner.cjs.js.map +1 -1
- package/dist/schemas/schemas.cjs.js +1 -4
- package/dist/schemas/schemas.cjs.js.map +1 -1
- package/package.json +23 -23
package/CHANGELOG.md
CHANGED
|
@@ -1,22 +1,57 @@
|
|
|
1
1
|
# @backstage/backend-dynamic-feature-service
|
|
2
2
|
|
|
3
|
-
## 0.4.
|
|
3
|
+
## 0.4.4-next.1
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
7
|
- Updated dependencies
|
|
8
|
-
- @backstage/
|
|
9
|
-
- @backstage/backend-
|
|
10
|
-
- @backstage/
|
|
11
|
-
- @backstage/plugin-
|
|
12
|
-
- @backstage/
|
|
13
|
-
- @backstage/
|
|
14
|
-
- @backstage/
|
|
8
|
+
- @backstage/cli-common@0.1.15-next.0
|
|
9
|
+
- @backstage/backend-app-api@1.0.2-next.1
|
|
10
|
+
- @backstage/backend-defaults@0.5.3-next.1
|
|
11
|
+
- @backstage/backend-plugin-api@1.0.2-next.1
|
|
12
|
+
- @backstage/cli-node@0.2.10-next.0
|
|
13
|
+
- @backstage/config@1.2.0
|
|
14
|
+
- @backstage/config-loader@1.9.2-next.0
|
|
15
|
+
- @backstage/errors@1.2.4
|
|
16
|
+
- @backstage/types@1.1.1
|
|
17
|
+
- @backstage/plugin-app-node@0.1.27-next.1
|
|
18
|
+
- @backstage/plugin-auth-node@0.5.4-next.1
|
|
19
|
+
- @backstage/plugin-catalog-backend@1.27.2-next.1
|
|
20
|
+
- @backstage/plugin-events-backend@0.3.16-next.1
|
|
21
|
+
- @backstage/plugin-events-node@0.4.4-next.1
|
|
22
|
+
- @backstage/plugin-permission-common@0.8.1
|
|
23
|
+
- @backstage/plugin-permission-node@0.8.5-next.1
|
|
24
|
+
- @backstage/plugin-scaffolder-node@0.5.1-next.1
|
|
25
|
+
- @backstage/plugin-search-backend-node@1.3.5-next.1
|
|
26
|
+
- @backstage/plugin-search-common@1.2.14
|
|
27
|
+
|
|
28
|
+
## 0.4.4-next.0
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 8593dfa: Improve the way alpha packages are supported when loading dynamic backend plugins.
|
|
33
|
+
The `ScannedPluginPackage` descriptor of dynamic backend plugins loaded from their alpha `package.json` now contain both the main package manifest and the alpha manifest. Previously it used to contain only the content of the alpha `package.json`, which is nearly empty.
|
|
34
|
+
This will make it easier to use or display metadata of loaded dynamic backend plugins, which is contained in the main manifest.
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
- @backstage/plugin-events-node@0.4.3-next.0
|
|
37
|
+
- @backstage/plugin-events-backend@0.3.15-next.0
|
|
38
|
+
- @backstage/plugin-auth-node@0.5.4-next.0
|
|
39
|
+
- @backstage/backend-defaults@0.5.3-next.0
|
|
40
|
+
- @backstage/backend-app-api@1.0.2-next.0
|
|
41
|
+
- @backstage/backend-plugin-api@1.0.2-next.0
|
|
42
|
+
- @backstage/cli-common@0.1.14
|
|
15
43
|
- @backstage/cli-node@0.2.9
|
|
44
|
+
- @backstage/config@1.2.0
|
|
16
45
|
- @backstage/config-loader@1.9.1
|
|
17
|
-
- @backstage/
|
|
18
|
-
- @backstage/
|
|
19
|
-
- @backstage/plugin-
|
|
46
|
+
- @backstage/errors@1.2.4
|
|
47
|
+
- @backstage/types@1.1.1
|
|
48
|
+
- @backstage/plugin-app-node@0.1.27-next.0
|
|
49
|
+
- @backstage/plugin-catalog-backend@1.27.2-next.0
|
|
50
|
+
- @backstage/plugin-permission-common@0.8.1
|
|
51
|
+
- @backstage/plugin-permission-node@0.8.5-next.0
|
|
52
|
+
- @backstage/plugin-scaffolder-node@0.5.1-next.0
|
|
53
|
+
- @backstage/plugin-search-backend-node@1.3.5-next.0
|
|
54
|
+
- @backstage/plugin-search-common@1.2.14
|
|
20
55
|
|
|
21
56
|
## 0.4.2
|
|
22
57
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7,12 +7,9 @@ var url = require('url');
|
|
|
7
7
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
8
8
|
var cliNode = require('@backstage/cli-node');
|
|
9
9
|
var cliCommon = require('@backstage/cli-common');
|
|
10
|
-
var path = require('path');
|
|
11
10
|
var fs = require('fs');
|
|
12
11
|
var alpha = require('@backstage/backend-plugin-api/alpha');
|
|
13
12
|
|
|
14
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
15
|
-
|
|
16
13
|
function _interopNamespaceCompat(e) {
|
|
17
14
|
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
18
15
|
var n = Object.create(null);
|
|
@@ -32,7 +29,6 @@ function _interopNamespaceCompat(e) {
|
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
var url__namespace = /*#__PURE__*/_interopNamespaceCompat(url);
|
|
35
|
-
var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
36
32
|
var fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
|
|
37
33
|
|
|
38
34
|
class DynamicPluginManager {
|
|
@@ -60,13 +56,7 @@ class DynamicPluginManager {
|
|
|
60
56
|
moduleLoader
|
|
61
57
|
);
|
|
62
58
|
const dynamicPluginsPaths = scannedPlugins.map(
|
|
63
|
-
(p) => fs__namespace.realpathSync(
|
|
64
|
-
path__default.default.dirname(
|
|
65
|
-
path__default.default.dirname(
|
|
66
|
-
path__default.default.resolve(url__namespace.fileURLToPath(p.location), p.manifest.main)
|
|
67
|
-
)
|
|
68
|
-
)
|
|
69
|
-
)
|
|
59
|
+
(p) => fs__namespace.realpathSync(url__namespace.fileURLToPath(p.location))
|
|
70
60
|
);
|
|
71
61
|
await moduleLoader.bootstrap(backstageRoot, dynamicPluginsPaths);
|
|
72
62
|
scanner.subscribeToRootDirectoryChange(async () => {
|
|
@@ -117,8 +107,10 @@ class DynamicPluginManager {
|
|
|
117
107
|
return loadedPlugins;
|
|
118
108
|
}
|
|
119
109
|
async loadBackendPlugin(plugin) {
|
|
110
|
+
const usedPluginManifest = plugin.alphaManifest?.main ?? plugin.manifest.main;
|
|
111
|
+
const usedPluginLocation = plugin.alphaManifest?.main ? `${plugin.location}/alpha` : plugin.location;
|
|
120
112
|
const packagePath = url__namespace.fileURLToPath(
|
|
121
|
-
`${
|
|
113
|
+
`${usedPluginLocation}/${usedPluginManifest}`
|
|
122
114
|
);
|
|
123
115
|
const dynamicPlugin = {
|
|
124
116
|
name: plugin.manifest.name,
|
|
@@ -143,12 +135,12 @@ class DynamicPluginManager {
|
|
|
143
135
|
}
|
|
144
136
|
if (dynamicPlugin.installer) {
|
|
145
137
|
this.logger.info(
|
|
146
|
-
`loaded dynamic backend plugin '${plugin.manifest.name}' from '${
|
|
138
|
+
`loaded dynamic backend plugin '${plugin.manifest.name}' from '${usedPluginLocation}'`
|
|
147
139
|
);
|
|
148
140
|
} else {
|
|
149
141
|
dynamicPlugin.failure = `the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`;
|
|
150
142
|
this.logger.error(
|
|
151
|
-
`dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${
|
|
143
|
+
`dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${usedPluginLocation}': ${dynamicPlugin.failure}`
|
|
152
144
|
);
|
|
153
145
|
}
|
|
154
146
|
return dynamicPlugin;
|
|
@@ -156,7 +148,7 @@ class DynamicPluginManager {
|
|
|
156
148
|
const typedError = typeof error === "object" && "message" in error && "name" in error ? error : new Error(error);
|
|
157
149
|
dynamicPlugin.failure = `${typedError.name}: ${typedError.message}`;
|
|
158
150
|
this.logger.error(
|
|
159
|
-
`an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${
|
|
151
|
+
`an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${usedPluginLocation}'`,
|
|
160
152
|
typedError
|
|
161
153
|
);
|
|
162
154
|
return dynamicPlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-manager.cjs.js","sources":["../../src/manager/plugin-manager.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 {\n DynamicPluginProvider,\n BackendDynamicPlugin,\n isBackendDynamicPluginInstaller,\n DynamicPlugin,\n FrontendDynamicPlugin,\n} from './types';\nimport { ScannedPluginPackage } from '../scanner';\nimport { PluginScanner } from '../scanner/plugin-scanner';\nimport { ModuleLoader } from '../loader';\nimport { CommonJSModuleLoader } from '../loader/CommonJSModuleLoader';\nimport * as url from 'url';\nimport {\n BackendFeature,\n LoggerService,\n coreServices,\n createBackendFeatureLoader,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\nimport { PackageRole, PackageRoles } from '@backstage/cli-node';\nimport { findPaths } from '@backstage/cli-common';\nimport path from 'path';\nimport * as fs from 'fs';\nimport {\n FeatureDiscoveryService,\n featureDiscoveryServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * @public\n */\nexport interface DynamicPluginManagerOptions {\n config: Config;\n logger: LoggerService;\n preferAlpha?: boolean;\n moduleLoader?: ModuleLoader;\n}\n\n/**\n * @public\n */\nexport class DynamicPluginManager implements DynamicPluginProvider {\n static async create(\n options: DynamicPluginManagerOptions,\n ): Promise<DynamicPluginManager> {\n /* eslint-disable-next-line no-restricted-syntax */\n const backstageRoot = findPaths(__dirname).targetRoot;\n const scanner = PluginScanner.create({\n config: options.config,\n logger: options.logger,\n backstageRoot,\n preferAlpha: options.preferAlpha,\n });\n const scannedPlugins = (await scanner.scanRoot()).packages;\n scanner.trackChanges();\n const moduleLoader =\n options.moduleLoader || new CommonJSModuleLoader(options.logger);\n const manager = new DynamicPluginManager(\n options.logger,\n scannedPlugins,\n moduleLoader,\n );\n\n const dynamicPluginsPaths = scannedPlugins.map(p =>\n fs.realpathSync(\n path.dirname(\n path.dirname(\n path.resolve(url.fileURLToPath(p.location), p.manifest.main),\n ),\n ),\n ),\n );\n\n await moduleLoader.bootstrap(backstageRoot, dynamicPluginsPaths);\n\n scanner.subscribeToRootDirectoryChange(async () => {\n manager._availablePackages = (await scanner.scanRoot()).packages;\n // TODO: do not store _scannedPlugins again, but instead store a diff of the changes\n });\n manager._plugins.push(...(await manager.loadPlugins()));\n\n return manager;\n }\n\n private readonly _plugins: DynamicPlugin[];\n private _availablePackages: ScannedPluginPackage[];\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly packages: ScannedPluginPackage[],\n private readonly moduleLoader: ModuleLoader,\n ) {\n this._plugins = [];\n this._availablePackages = packages;\n }\n\n get availablePackages(): ScannedPluginPackage[] {\n return this._availablePackages;\n }\n\n addBackendPlugin(plugin: BackendDynamicPlugin): void {\n this._plugins.push(plugin);\n }\n\n private async loadPlugins(): Promise<DynamicPlugin[]> {\n const loadedPlugins: DynamicPlugin[] = [];\n\n for (const scannedPlugin of this.packages) {\n const role = scannedPlugin.manifest.backstage.role;\n const platform = PackageRoles.getRoleInfo(role).platform;\n const isPlugin =\n role.endsWith('-plugin') ||\n role.endsWith('-plugin-module') ||\n role === ('frontend-dynamic-container' as PackageRole);\n\n if (!isPlugin) {\n this.logger.info(\n `skipping dynamic plugin package '${scannedPlugin.manifest.name}' from '${scannedPlugin.location}': incompatible role '${role}'`,\n );\n continue;\n }\n\n switch (platform) {\n case 'node':\n loadedPlugins.push(await this.loadBackendPlugin(scannedPlugin));\n break;\n\n case 'web':\n loadedPlugins.push({\n name: scannedPlugin.manifest.name,\n version: scannedPlugin.manifest.version,\n role: scannedPlugin.manifest.backstage.role,\n platform: 'web',\n // TODO(davidfestal): add required front-end plugin information here.\n });\n break;\n\n default:\n this.logger.info(\n `skipping dynamic plugin package '${scannedPlugin.manifest.name}' from '${scannedPlugin.location}': unrelated platform '${platform}'`,\n );\n }\n }\n return loadedPlugins;\n }\n\n private async loadBackendPlugin(\n plugin: ScannedPluginPackage,\n ): Promise<BackendDynamicPlugin> {\n const packagePath = url.fileURLToPath(\n `${plugin.location}/${plugin.manifest.main}`,\n );\n const dynamicPlugin: BackendDynamicPlugin = {\n name: plugin.manifest.name,\n version: plugin.manifest.version,\n platform: 'node',\n role: plugin.manifest.backstage.role,\n };\n\n try {\n const pluginModule = await this.moduleLoader.load(packagePath);\n\n if (isBackendFeature(pluginModule.default)) {\n dynamicPlugin.installer = {\n kind: 'new',\n install: () => pluginModule.default,\n };\n } else if (isBackendFeatureFactory(pluginModule.default)) {\n dynamicPlugin.installer = {\n kind: 'new',\n install: pluginModule.default,\n };\n } else if (\n isBackendDynamicPluginInstaller(pluginModule.dynamicPluginInstaller)\n ) {\n dynamicPlugin.installer = pluginModule.dynamicPluginInstaller;\n }\n if (dynamicPlugin.installer) {\n this.logger.info(\n `loaded dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`,\n );\n } else {\n dynamicPlugin.failure = `the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`;\n this.logger.error(\n `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': ${dynamicPlugin.failure}`,\n );\n }\n return dynamicPlugin;\n } catch (error) {\n const typedError =\n typeof error === 'object' && 'message' in error && 'name' in error\n ? error\n : new Error(error);\n dynamicPlugin.failure = `${typedError.name}: ${typedError.message}`;\n this.logger.error(\n `an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`,\n typedError,\n );\n return dynamicPlugin;\n }\n }\n\n backendPlugins(options?: {\n includeFailed?: boolean;\n }): BackendDynamicPlugin[] {\n return this.plugins(options).filter(\n (p): p is BackendDynamicPlugin => p.platform === 'node',\n );\n }\n\n frontendPlugins(options?: {\n includeFailed?: boolean;\n }): FrontendDynamicPlugin[] {\n return this.plugins(options).filter(\n (p): p is FrontendDynamicPlugin => p.platform === 'web',\n );\n }\n\n plugins(options?: { includeFailed?: boolean }): DynamicPlugin[] {\n return this._plugins.filter(p => options?.includeFailed || !p.failure);\n }\n\n getScannedPackage(plugin: DynamicPlugin): ScannedPluginPackage {\n const pkg = this.packages.find(\n p =>\n p.manifest.name === plugin.name &&\n p.manifest.version === plugin.version,\n );\n if (pkg === undefined) {\n throw new Error(\n `The scanned package of a dynamic plugin should always be available: ${plugin.name}/${plugin.version}`,\n );\n }\n return pkg;\n }\n}\n\n/**\n * @public\n */\nexport const dynamicPluginsServiceRef = createServiceRef<DynamicPluginProvider>(\n {\n id: 'core.dynamicplugins',\n scope: 'root',\n },\n);\n\n/**\n * @public\n */\nexport interface DynamicPluginsFactoryOptions {\n moduleLoader?(logger: LoggerService): ModuleLoader | Promise<ModuleLoader>;\n}\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsServiceFactoryWithOptions = (\n options?: DynamicPluginsFactoryOptions,\n) =>\n createServiceFactory({\n service: dynamicPluginsServiceRef,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.rootLogger,\n },\n async factory({ config, logger }) {\n return await DynamicPluginManager.create({\n config,\n logger,\n preferAlpha: true,\n moduleLoader: await options?.moduleLoader?.(logger),\n });\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsServiceFactory = Object.assign(\n dynamicPluginsServiceFactoryWithOptions,\n dynamicPluginsServiceFactoryWithOptions(),\n);\n\nclass DynamicPluginsEnabledFeatureDiscoveryService\n implements FeatureDiscoveryService\n{\n constructor(\n private readonly dynamicPlugins: DynamicPluginProvider,\n private readonly featureDiscoveryService?: FeatureDiscoveryService,\n ) {}\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n const staticFeatures =\n (await this.featureDiscoveryService?.getBackendFeatures())?.features ??\n [];\n\n return {\n features: [\n ...this.dynamicPlugins\n .backendPlugins()\n .flatMap((plugin): BackendFeature[] => {\n if (plugin.installer?.kind === 'new') {\n const installed = plugin.installer.install();\n if (Array.isArray(installed)) {\n return installed;\n }\n return [installed];\n }\n return [];\n }),\n ...staticFeatures,\n ],\n };\n }\n}\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsFeatureDiscoveryServiceFactory =\n createServiceFactory({\n service: featureDiscoveryServiceRef,\n deps: {\n config: coreServices.rootConfig,\n dynamicPlugins: dynamicPluginsServiceRef,\n },\n factory({ dynamicPlugins }) {\n return new DynamicPluginsEnabledFeatureDiscoveryService(dynamicPlugins);\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsFeatureDiscoveryLoader = createBackendFeatureLoader({\n deps: {\n dynamicPlugins: dynamicPluginsServiceRef,\n },\n async loader({ dynamicPlugins }) {\n const service = new DynamicPluginsEnabledFeatureDiscoveryService(\n dynamicPlugins,\n );\n const { features } = await service.getBackendFeatures();\n return features;\n },\n});\n\nfunction isBackendFeature(value: unknown): value is BackendFeature {\n return (\n !!value &&\n (typeof value === 'object' || typeof value === 'function') &&\n (value as BackendFeature).$$type === '@backstage/BackendFeature'\n );\n}\n\nfunction isBackendFeatureFactory(\n value: unknown,\n): value is () => BackendFeature {\n return (\n !!value &&\n typeof value === 'function' &&\n (value as any).$$type === '@backstage/BackendFeatureFactory'\n );\n}\n"],"names":["findPaths","PluginScanner","CommonJSModuleLoader","fs","path","url","PackageRoles","isBackendDynamicPluginInstaller","createServiceRef","createServiceFactory","coreServices","featureDiscoveryServiceRef","createBackendFeatureLoader"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin-manager.cjs.js","sources":["../../src/manager/plugin-manager.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 {\n DynamicPluginProvider,\n BackendDynamicPlugin,\n isBackendDynamicPluginInstaller,\n DynamicPlugin,\n FrontendDynamicPlugin,\n} from './types';\nimport { ScannedPluginPackage } from '../scanner';\nimport { PluginScanner } from '../scanner/plugin-scanner';\nimport { ModuleLoader } from '../loader';\nimport { CommonJSModuleLoader } from '../loader/CommonJSModuleLoader';\nimport * as url from 'url';\nimport {\n BackendFeature,\n LoggerService,\n coreServices,\n createBackendFeatureLoader,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\nimport { PackageRole, PackageRoles } from '@backstage/cli-node';\nimport { findPaths } from '@backstage/cli-common';\nimport * as fs from 'fs';\nimport {\n FeatureDiscoveryService,\n featureDiscoveryServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * @public\n */\nexport interface DynamicPluginManagerOptions {\n config: Config;\n logger: LoggerService;\n preferAlpha?: boolean;\n moduleLoader?: ModuleLoader;\n}\n\n/**\n * @public\n */\nexport class DynamicPluginManager implements DynamicPluginProvider {\n static async create(\n options: DynamicPluginManagerOptions,\n ): Promise<DynamicPluginManager> {\n /* eslint-disable-next-line no-restricted-syntax */\n const backstageRoot = findPaths(__dirname).targetRoot;\n const scanner = PluginScanner.create({\n config: options.config,\n logger: options.logger,\n backstageRoot,\n preferAlpha: options.preferAlpha,\n });\n const scannedPlugins = (await scanner.scanRoot()).packages;\n scanner.trackChanges();\n const moduleLoader =\n options.moduleLoader || new CommonJSModuleLoader(options.logger);\n const manager = new DynamicPluginManager(\n options.logger,\n scannedPlugins,\n moduleLoader,\n );\n\n const dynamicPluginsPaths = scannedPlugins.map(p =>\n fs.realpathSync(url.fileURLToPath(p.location)),\n );\n\n await moduleLoader.bootstrap(backstageRoot, dynamicPluginsPaths);\n\n scanner.subscribeToRootDirectoryChange(async () => {\n manager._availablePackages = (await scanner.scanRoot()).packages;\n // TODO: do not store _scannedPlugins again, but instead store a diff of the changes\n });\n manager._plugins.push(...(await manager.loadPlugins()));\n\n return manager;\n }\n\n private readonly _plugins: DynamicPlugin[];\n private _availablePackages: ScannedPluginPackage[];\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly packages: ScannedPluginPackage[],\n private readonly moduleLoader: ModuleLoader,\n ) {\n this._plugins = [];\n this._availablePackages = packages;\n }\n\n get availablePackages(): ScannedPluginPackage[] {\n return this._availablePackages;\n }\n\n addBackendPlugin(plugin: BackendDynamicPlugin): void {\n this._plugins.push(plugin);\n }\n\n private async loadPlugins(): Promise<DynamicPlugin[]> {\n const loadedPlugins: DynamicPlugin[] = [];\n\n for (const scannedPlugin of this.packages) {\n const role = scannedPlugin.manifest.backstage.role;\n const platform = PackageRoles.getRoleInfo(role).platform;\n const isPlugin =\n role.endsWith('-plugin') ||\n role.endsWith('-plugin-module') ||\n role === ('frontend-dynamic-container' as PackageRole);\n\n if (!isPlugin) {\n this.logger.info(\n `skipping dynamic plugin package '${scannedPlugin.manifest.name}' from '${scannedPlugin.location}': incompatible role '${role}'`,\n );\n continue;\n }\n\n switch (platform) {\n case 'node':\n loadedPlugins.push(await this.loadBackendPlugin(scannedPlugin));\n break;\n\n case 'web':\n loadedPlugins.push({\n name: scannedPlugin.manifest.name,\n version: scannedPlugin.manifest.version,\n role: scannedPlugin.manifest.backstage.role,\n platform: 'web',\n // TODO(davidfestal): add required front-end plugin information here.\n });\n break;\n\n default:\n this.logger.info(\n `skipping dynamic plugin package '${scannedPlugin.manifest.name}' from '${scannedPlugin.location}': unrelated platform '${platform}'`,\n );\n }\n }\n return loadedPlugins;\n }\n\n private async loadBackendPlugin(\n plugin: ScannedPluginPackage,\n ): Promise<BackendDynamicPlugin> {\n const usedPluginManifest =\n plugin.alphaManifest?.main ?? plugin.manifest.main;\n const usedPluginLocation = plugin.alphaManifest?.main\n ? `${plugin.location}/alpha`\n : plugin.location;\n const packagePath = url.fileURLToPath(\n `${usedPluginLocation}/${usedPluginManifest}`,\n );\n const dynamicPlugin: BackendDynamicPlugin = {\n name: plugin.manifest.name,\n version: plugin.manifest.version,\n platform: 'node',\n role: plugin.manifest.backstage.role,\n };\n\n try {\n const pluginModule = await this.moduleLoader.load(packagePath);\n\n if (isBackendFeature(pluginModule.default)) {\n dynamicPlugin.installer = {\n kind: 'new',\n install: () => pluginModule.default,\n };\n } else if (isBackendFeatureFactory(pluginModule.default)) {\n dynamicPlugin.installer = {\n kind: 'new',\n install: pluginModule.default,\n };\n } else if (\n isBackendDynamicPluginInstaller(pluginModule.dynamicPluginInstaller)\n ) {\n dynamicPlugin.installer = pluginModule.dynamicPluginInstaller;\n }\n if (dynamicPlugin.installer) {\n this.logger.info(\n `loaded dynamic backend plugin '${plugin.manifest.name}' from '${usedPluginLocation}'`,\n );\n } else {\n dynamicPlugin.failure = `the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`;\n this.logger.error(\n `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${usedPluginLocation}': ${dynamicPlugin.failure}`,\n );\n }\n return dynamicPlugin;\n } catch (error) {\n const typedError =\n typeof error === 'object' && 'message' in error && 'name' in error\n ? error\n : new Error(error);\n dynamicPlugin.failure = `${typedError.name}: ${typedError.message}`;\n this.logger.error(\n `an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${usedPluginLocation}'`,\n typedError,\n );\n return dynamicPlugin;\n }\n }\n\n backendPlugins(options?: {\n includeFailed?: boolean;\n }): BackendDynamicPlugin[] {\n return this.plugins(options).filter(\n (p): p is BackendDynamicPlugin => p.platform === 'node',\n );\n }\n\n frontendPlugins(options?: {\n includeFailed?: boolean;\n }): FrontendDynamicPlugin[] {\n return this.plugins(options).filter(\n (p): p is FrontendDynamicPlugin => p.platform === 'web',\n );\n }\n\n plugins(options?: { includeFailed?: boolean }): DynamicPlugin[] {\n return this._plugins.filter(p => options?.includeFailed || !p.failure);\n }\n\n getScannedPackage(plugin: DynamicPlugin): ScannedPluginPackage {\n const pkg = this.packages.find(\n p =>\n p.manifest.name === plugin.name &&\n p.manifest.version === plugin.version,\n );\n if (pkg === undefined) {\n throw new Error(\n `The scanned package of a dynamic plugin should always be available: ${plugin.name}/${plugin.version}`,\n );\n }\n return pkg;\n }\n}\n\n/**\n * @public\n */\nexport const dynamicPluginsServiceRef = createServiceRef<DynamicPluginProvider>(\n {\n id: 'core.dynamicplugins',\n scope: 'root',\n },\n);\n\n/**\n * @public\n */\nexport interface DynamicPluginsFactoryOptions {\n moduleLoader?(logger: LoggerService): ModuleLoader | Promise<ModuleLoader>;\n}\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsServiceFactoryWithOptions = (\n options?: DynamicPluginsFactoryOptions,\n) =>\n createServiceFactory({\n service: dynamicPluginsServiceRef,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.rootLogger,\n },\n async factory({ config, logger }) {\n return await DynamicPluginManager.create({\n config,\n logger,\n preferAlpha: true,\n moduleLoader: await options?.moduleLoader?.(logger),\n });\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsServiceFactory = Object.assign(\n dynamicPluginsServiceFactoryWithOptions,\n dynamicPluginsServiceFactoryWithOptions(),\n);\n\nclass DynamicPluginsEnabledFeatureDiscoveryService\n implements FeatureDiscoveryService\n{\n constructor(\n private readonly dynamicPlugins: DynamicPluginProvider,\n private readonly featureDiscoveryService?: FeatureDiscoveryService,\n ) {}\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n const staticFeatures =\n (await this.featureDiscoveryService?.getBackendFeatures())?.features ??\n [];\n\n return {\n features: [\n ...this.dynamicPlugins\n .backendPlugins()\n .flatMap((plugin): BackendFeature[] => {\n if (plugin.installer?.kind === 'new') {\n const installed = plugin.installer.install();\n if (Array.isArray(installed)) {\n return installed;\n }\n return [installed];\n }\n return [];\n }),\n ...staticFeatures,\n ],\n };\n }\n}\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsFeatureDiscoveryServiceFactory =\n createServiceFactory({\n service: featureDiscoveryServiceRef,\n deps: {\n config: coreServices.rootConfig,\n dynamicPlugins: dynamicPluginsServiceRef,\n },\n factory({ dynamicPlugins }) {\n return new DynamicPluginsEnabledFeatureDiscoveryService(dynamicPlugins);\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsFeatureDiscoveryLoader = createBackendFeatureLoader({\n deps: {\n dynamicPlugins: dynamicPluginsServiceRef,\n },\n async loader({ dynamicPlugins }) {\n const service = new DynamicPluginsEnabledFeatureDiscoveryService(\n dynamicPlugins,\n );\n const { features } = await service.getBackendFeatures();\n return features;\n },\n});\n\nfunction isBackendFeature(value: unknown): value is BackendFeature {\n return (\n !!value &&\n (typeof value === 'object' || typeof value === 'function') &&\n (value as BackendFeature).$$type === '@backstage/BackendFeature'\n );\n}\n\nfunction isBackendFeatureFactory(\n value: unknown,\n): value is () => BackendFeature {\n return (\n !!value &&\n typeof value === 'function' &&\n (value as any).$$type === '@backstage/BackendFeatureFactory'\n );\n}\n"],"names":["findPaths","PluginScanner","CommonJSModuleLoader","fs","url","PackageRoles","isBackendDynamicPluginInstaller","createServiceRef","createServiceFactory","coreServices","featureDiscoveryServiceRef","createBackendFeatureLoader"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ var chokidar = require('chokidar');
|
|
|
6
6
|
var path = require('path');
|
|
7
7
|
var url = require('url');
|
|
8
8
|
var debounce = require('lodash/debounce');
|
|
9
|
-
var
|
|
9
|
+
var errors = require('@backstage/errors');
|
|
10
10
|
|
|
11
11
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
12
|
|
|
@@ -138,49 +138,24 @@ Please add '${backstageNodeModules}' to the 'NODE_PATH' when running the backsta
|
|
|
138
138
|
continue;
|
|
139
139
|
}
|
|
140
140
|
let scannedPlugin;
|
|
141
|
-
let platform;
|
|
142
141
|
try {
|
|
143
142
|
scannedPlugin = await this.scanDir(pluginHome);
|
|
144
143
|
if (!scannedPlugin.manifest.main) {
|
|
145
144
|
throw new Error("field 'main' not found in 'package.json'");
|
|
146
145
|
}
|
|
147
|
-
if (scannedPlugin.manifest.backstage?.role) {
|
|
148
|
-
platform = cliNode.PackageRoles.getRoleInfo(
|
|
149
|
-
scannedPlugin.manifest.backstage.role
|
|
150
|
-
).platform;
|
|
151
|
-
} else {
|
|
146
|
+
if (!scannedPlugin.manifest.backstage?.role) {
|
|
152
147
|
throw new Error("field 'backstage.role' not found in 'package.json'");
|
|
153
148
|
}
|
|
154
149
|
} catch (e) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (this.preferAlpha) {
|
|
163
|
-
const pluginHomeAlpha = path__namespace.resolve(pluginHome, "alpha");
|
|
164
|
-
if (fs.existsSync(pluginHomeAlpha)) {
|
|
165
|
-
if ((await fs__namespace.lstat(pluginHomeAlpha)).isDirectory()) {
|
|
166
|
-
const backstage = scannedPlugin.manifest.backstage;
|
|
167
|
-
try {
|
|
168
|
-
scannedPlugin = await this.scanDir(pluginHomeAlpha);
|
|
169
|
-
} catch (e) {
|
|
170
|
-
this.logger.error(
|
|
171
|
-
`failed to load dynamic plugin manifest from '${pluginHomeAlpha}'`,
|
|
172
|
-
e
|
|
173
|
-
);
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
scannedPlugin.manifest.backstage = backstage;
|
|
177
|
-
} else {
|
|
178
|
-
this.logger.warn(
|
|
179
|
-
`skipping '${pluginHomeAlpha}' since it is not a directory`
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
150
|
+
if (e instanceof errors.ForwardedError) {
|
|
151
|
+
this.logger.error(e.message, e.cause);
|
|
152
|
+
} else {
|
|
153
|
+
this.logger.error(
|
|
154
|
+
`failed to load dynamic plugin manifest from '${pluginHome}'`,
|
|
155
|
+
e
|
|
156
|
+
);
|
|
183
157
|
}
|
|
158
|
+
continue;
|
|
184
159
|
}
|
|
185
160
|
scannedPlugins.push(scannedPlugin);
|
|
186
161
|
}
|
|
@@ -190,10 +165,35 @@ Please add '${backstageNodeModules}' to the 'NODE_PATH' when running the backsta
|
|
|
190
165
|
const manifestFile = path__namespace.resolve(pluginHome, "package.json");
|
|
191
166
|
const content = await fs__namespace.readFile(manifestFile);
|
|
192
167
|
const manifest = JSON.parse(content.toString());
|
|
193
|
-
|
|
168
|
+
const scannedPluginPackage = {
|
|
194
169
|
location: url__namespace.pathToFileURL(pluginHome),
|
|
195
170
|
manifest
|
|
196
171
|
};
|
|
172
|
+
if (this.preferAlpha) {
|
|
173
|
+
const pluginHomeAlpha = path__namespace.resolve(pluginHome, "alpha");
|
|
174
|
+
if (fs.existsSync(pluginHomeAlpha)) {
|
|
175
|
+
if ((await fs__namespace.lstat(pluginHomeAlpha)).isDirectory()) {
|
|
176
|
+
try {
|
|
177
|
+
const alphaContent = await fs__namespace.readFile(
|
|
178
|
+
path__namespace.resolve(pluginHomeAlpha, "package.json")
|
|
179
|
+
);
|
|
180
|
+
scannedPluginPackage.alphaManifest = JSON.parse(
|
|
181
|
+
alphaContent.toString()
|
|
182
|
+
);
|
|
183
|
+
} catch (e) {
|
|
184
|
+
throw new errors.ForwardedError(
|
|
185
|
+
`failed to load dynamic plugin manifest from '${pluginHome}/alpha'`,
|
|
186
|
+
e
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
this.logger.warn(
|
|
191
|
+
`skipping '${pluginHomeAlpha}' since it is not a directory`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return scannedPluginPackage;
|
|
197
197
|
}
|
|
198
198
|
async trackChanges() {
|
|
199
199
|
const setupRootDirectoryWatcher = async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-scanner.cjs.js","sources":["../../src/scanner/plugin-scanner.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 { ScannedPluginPackage, ScannedPluginManifest } from './types';\nimport * as fs from 'fs/promises';\nimport { Stats, lstatSync, existsSync } from 'fs';\nimport * as chokidar from 'chokidar';\nimport * as path from 'path';\nimport * as url from 'url';\nimport debounce from 'lodash/debounce';\nimport { PackagePlatform, PackageRoles } from '@backstage/cli-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport interface DynamicPluginScannerOptions {\n config: Config;\n backstageRoot: string;\n logger: LoggerService;\n preferAlpha?: boolean;\n}\n\nexport interface ScanRootResponse {\n packages: ScannedPluginPackage[];\n}\n\nexport const configKey = 'dynamicPlugins';\n\nexport class PluginScanner {\n private _rootDirectory?: string;\n private configUnsubscribe?: () => void;\n private rootDirectoryWatcher?: chokidar.FSWatcher;\n private subscribers: (() => void)[] = [];\n\n private constructor(\n private readonly config: Config,\n private readonly logger: LoggerService,\n private readonly backstageRoot: string,\n private readonly preferAlpha: boolean,\n ) {}\n\n static create(options: DynamicPluginScannerOptions): PluginScanner {\n const scanner = new PluginScanner(\n options.config,\n options.logger,\n options.backstageRoot,\n options.preferAlpha || false,\n );\n scanner.applyConfig();\n return scanner;\n }\n\n subscribeToRootDirectoryChange(subscriber: () => void) {\n this.subscribers.push(subscriber);\n }\n\n get rootDirectory(): string | undefined {\n return this._rootDirectory;\n }\n\n private applyConfig(): void | never {\n const dynamicPlugins = this.config.getOptional(configKey);\n if (!dynamicPlugins) {\n this.logger.info(`'${configKey}' config entry not found.`);\n this._rootDirectory = undefined;\n return;\n }\n if (typeof dynamicPlugins !== 'object') {\n this.logger.warn(`'${configKey}' config entry should be an object.`);\n this._rootDirectory = undefined;\n return;\n }\n if (!('rootDirectory' in dynamicPlugins)) {\n this.logger.warn(\n `'${configKey}' config entry does not contain the 'rootDirectory' field.`,\n );\n this._rootDirectory = undefined;\n return;\n }\n if (typeof dynamicPlugins.rootDirectory !== 'string') {\n this.logger.warn(\n `'${configKey}.rootDirectory' config entry should be a string.`,\n );\n this._rootDirectory = undefined;\n return;\n }\n\n const dynamicPluginsRootPath = path.isAbsolute(dynamicPlugins.rootDirectory)\n ? path.resolve(dynamicPlugins.rootDirectory)\n : path.resolve(this.backstageRoot, dynamicPlugins.rootDirectory);\n\n if (\n !path\n .dirname(dynamicPluginsRootPath)\n .startsWith(path.resolve(this.backstageRoot))\n ) {\n const nodePath = process.env.NODE_PATH;\n const backstageNodeModules = path.resolve(\n this.backstageRoot,\n 'node_modules',\n );\n if (\n !nodePath ||\n !nodePath.split(path.delimiter).includes(backstageNodeModules)\n ) {\n throw new Error(\n `Dynamic plugins under '${dynamicPluginsRootPath}' cannot access backstage modules in '${backstageNodeModules}'.\\n` +\n `Please add '${backstageNodeModules}' to the 'NODE_PATH' when running the backstage backend.`,\n );\n }\n }\n if (!lstatSync(dynamicPluginsRootPath).isDirectory()) {\n throw new Error('Not a directory');\n }\n\n this._rootDirectory = dynamicPluginsRootPath;\n }\n\n async scanRoot(): Promise<ScanRootResponse> {\n if (!this._rootDirectory) {\n return { packages: [] };\n }\n\n const dynamicPluginsLocation = this._rootDirectory;\n const scannedPlugins: ScannedPluginPackage[] = [];\n for (const dirEnt of await fs.readdir(dynamicPluginsLocation, {\n withFileTypes: true,\n })) {\n const pluginDir = dirEnt;\n\n if (pluginDir.name === 'lost+found') {\n this.logger.debug(`skipping '${pluginDir.name}' system directory`);\n continue;\n }\n const pluginHome = path.normalize(\n path.resolve(dynamicPluginsLocation, pluginDir.name),\n );\n if (dirEnt.isSymbolicLink()) {\n if (!(await fs.lstat(await fs.readlink(pluginHome))).isDirectory()) {\n this.logger.info(\n `skipping '${pluginHome}' since it is not a directory`,\n );\n continue;\n }\n } else if (!dirEnt.isDirectory()) {\n this.logger.info(\n `skipping '${pluginHome}' since it is not a directory`,\n );\n continue;\n }\n\n let scannedPlugin: ScannedPluginPackage;\n let platform: PackagePlatform;\n try {\n scannedPlugin = await this.scanDir(pluginHome);\n if (!scannedPlugin.manifest.main) {\n throw new Error(\"field 'main' not found in 'package.json'\");\n }\n if (scannedPlugin.manifest.backstage?.role) {\n platform = PackageRoles.getRoleInfo(\n scannedPlugin.manifest.backstage.role,\n ).platform;\n } else {\n throw new Error(\"field 'backstage.role' not found in 'package.json'\");\n }\n } catch (e) {\n this.logger.error(\n `failed to load dynamic plugin manifest from '${pluginHome}'`,\n e,\n );\n continue;\n }\n\n if (platform === 'node') {\n if (this.preferAlpha) {\n const pluginHomeAlpha = path.resolve(pluginHome, 'alpha');\n if (existsSync(pluginHomeAlpha)) {\n if ((await fs.lstat(pluginHomeAlpha)).isDirectory()) {\n const backstage = scannedPlugin.manifest.backstage;\n try {\n scannedPlugin = await this.scanDir(pluginHomeAlpha);\n } catch (e) {\n this.logger.error(\n `failed to load dynamic plugin manifest from '${pluginHomeAlpha}'`,\n e,\n );\n continue;\n }\n scannedPlugin.manifest.backstage = backstage;\n } else {\n this.logger.warn(\n `skipping '${pluginHomeAlpha}' since it is not a directory`,\n );\n }\n }\n }\n }\n\n scannedPlugins.push(scannedPlugin);\n }\n return { packages: scannedPlugins };\n }\n\n private async scanDir(pluginHome: string): Promise<ScannedPluginPackage> {\n const manifestFile = path.resolve(pluginHome, 'package.json');\n const content = await fs.readFile(manifestFile);\n const manifest: ScannedPluginManifest = JSON.parse(content.toString());\n return {\n location: url.pathToFileURL(pluginHome),\n manifest: manifest,\n };\n }\n\n async trackChanges(): Promise<void> {\n const setupRootDirectoryWatcher = async (): Promise<void> => {\n return new Promise((resolve, reject) => {\n if (!this._rootDirectory) {\n resolve();\n return;\n }\n const callSubscribers = debounce(() => {\n this.subscribers.forEach(s => s());\n }, 500);\n let ready = false;\n this.rootDirectoryWatcher = chokidar\n .watch(this._rootDirectory, {\n ignoreInitial: true,\n followSymlinks: true,\n depth: 1,\n disableGlobbing: true,\n })\n .on(\n 'all',\n (\n event: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir',\n eventPath: string,\n _: Stats | undefined,\n ): void => {\n if (\n (['addDir', 'unlinkDir'].includes(event) &&\n path.dirname(eventPath) === this._rootDirectory) ||\n (['add', 'unlink', 'change'].includes(event) &&\n path.dirname(path.dirname(eventPath)) ===\n this._rootDirectory &&\n path.basename(eventPath) === 'package.json')\n ) {\n this.logger.info(\n `rootDirectory changed (${event} - ${eventPath}): scanning plugins again`,\n );\n callSubscribers();\n } else {\n this.logger.debug(\n `rootDirectory changed (${event} - ${eventPath}): no need to scan plugins again`,\n );\n }\n },\n )\n .on('error', (error: Error) => {\n this.logger.error(\n `error while watching '${this.rootDirectory}'`,\n error,\n );\n if (!ready) {\n reject(error);\n }\n })\n .on('ready', () => {\n ready = true;\n resolve();\n });\n });\n };\n\n await setupRootDirectoryWatcher();\n if (this.config.subscribe) {\n const { unsubscribe } = this.config.subscribe(async (): Promise<void> => {\n const oldRootDirectory = this._rootDirectory;\n try {\n this.applyConfig();\n } catch (e) {\n this.logger.error(\n 'failed to apply new config for dynamic plugins',\n e,\n );\n }\n if (oldRootDirectory !== this._rootDirectory) {\n this.logger.info(\n `rootDirectory changed in Config from '${oldRootDirectory}' to '${this._rootDirectory}'`,\n );\n this.subscribers.forEach(s => s());\n if (this.rootDirectoryWatcher) {\n await this.rootDirectoryWatcher.close();\n }\n await setupRootDirectoryWatcher();\n }\n });\n this.configUnsubscribe = unsubscribe;\n }\n }\n\n async untrackChanges() {\n if (this.rootDirectoryWatcher) {\n this.rootDirectoryWatcher.close();\n }\n if (this.configUnsubscribe) {\n this.configUnsubscribe();\n }\n }\n\n destructor() {\n this.untrackChanges();\n }\n}\n"],"names":["path","lstatSync","fs","PackageRoles","existsSync","url","debounce","chokidar"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin-scanner.cjs.js","sources":["../../src/scanner/plugin-scanner.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 { ScannedPluginPackage, ScannedPluginManifest } from './types';\nimport * as fs from 'fs/promises';\nimport { Stats, lstatSync, existsSync } from 'fs';\nimport * as chokidar from 'chokidar';\nimport * as path from 'path';\nimport * as url from 'url';\nimport debounce from 'lodash/debounce';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ForwardedError } from '@backstage/errors';\n\nexport interface DynamicPluginScannerOptions {\n config: Config;\n backstageRoot: string;\n logger: LoggerService;\n preferAlpha?: boolean;\n}\n\nexport interface ScanRootResponse {\n packages: ScannedPluginPackage[];\n}\n\nexport const configKey = 'dynamicPlugins';\n\nexport class PluginScanner {\n private _rootDirectory?: string;\n private configUnsubscribe?: () => void;\n private rootDirectoryWatcher?: chokidar.FSWatcher;\n private subscribers: (() => void)[] = [];\n\n private constructor(\n private readonly config: Config,\n private readonly logger: LoggerService,\n private readonly backstageRoot: string,\n private readonly preferAlpha: boolean,\n ) {}\n\n static create(options: DynamicPluginScannerOptions): PluginScanner {\n const scanner = new PluginScanner(\n options.config,\n options.logger,\n options.backstageRoot,\n options.preferAlpha || false,\n );\n scanner.applyConfig();\n return scanner;\n }\n\n subscribeToRootDirectoryChange(subscriber: () => void) {\n this.subscribers.push(subscriber);\n }\n\n get rootDirectory(): string | undefined {\n return this._rootDirectory;\n }\n\n private applyConfig(): void | never {\n const dynamicPlugins = this.config.getOptional(configKey);\n if (!dynamicPlugins) {\n this.logger.info(`'${configKey}' config entry not found.`);\n this._rootDirectory = undefined;\n return;\n }\n if (typeof dynamicPlugins !== 'object') {\n this.logger.warn(`'${configKey}' config entry should be an object.`);\n this._rootDirectory = undefined;\n return;\n }\n if (!('rootDirectory' in dynamicPlugins)) {\n this.logger.warn(\n `'${configKey}' config entry does not contain the 'rootDirectory' field.`,\n );\n this._rootDirectory = undefined;\n return;\n }\n if (typeof dynamicPlugins.rootDirectory !== 'string') {\n this.logger.warn(\n `'${configKey}.rootDirectory' config entry should be a string.`,\n );\n this._rootDirectory = undefined;\n return;\n }\n\n const dynamicPluginsRootPath = path.isAbsolute(dynamicPlugins.rootDirectory)\n ? path.resolve(dynamicPlugins.rootDirectory)\n : path.resolve(this.backstageRoot, dynamicPlugins.rootDirectory);\n\n if (\n !path\n .dirname(dynamicPluginsRootPath)\n .startsWith(path.resolve(this.backstageRoot))\n ) {\n const nodePath = process.env.NODE_PATH;\n const backstageNodeModules = path.resolve(\n this.backstageRoot,\n 'node_modules',\n );\n if (\n !nodePath ||\n !nodePath.split(path.delimiter).includes(backstageNodeModules)\n ) {\n throw new Error(\n `Dynamic plugins under '${dynamicPluginsRootPath}' cannot access backstage modules in '${backstageNodeModules}'.\\n` +\n `Please add '${backstageNodeModules}' to the 'NODE_PATH' when running the backstage backend.`,\n );\n }\n }\n if (!lstatSync(dynamicPluginsRootPath).isDirectory()) {\n throw new Error('Not a directory');\n }\n\n this._rootDirectory = dynamicPluginsRootPath;\n }\n\n async scanRoot(): Promise<ScanRootResponse> {\n if (!this._rootDirectory) {\n return { packages: [] };\n }\n\n const dynamicPluginsLocation = this._rootDirectory;\n const scannedPlugins: ScannedPluginPackage[] = [];\n for (const dirEnt of await fs.readdir(dynamicPluginsLocation, {\n withFileTypes: true,\n })) {\n const pluginDir = dirEnt;\n\n if (pluginDir.name === 'lost+found') {\n this.logger.debug(`skipping '${pluginDir.name}' system directory`);\n continue;\n }\n const pluginHome = path.normalize(\n path.resolve(dynamicPluginsLocation, pluginDir.name),\n );\n if (dirEnt.isSymbolicLink()) {\n if (!(await fs.lstat(await fs.readlink(pluginHome))).isDirectory()) {\n this.logger.info(\n `skipping '${pluginHome}' since it is not a directory`,\n );\n continue;\n }\n } else if (!dirEnt.isDirectory()) {\n this.logger.info(\n `skipping '${pluginHome}' since it is not a directory`,\n );\n continue;\n }\n\n let scannedPlugin: ScannedPluginPackage;\n try {\n scannedPlugin = await this.scanDir(pluginHome);\n if (!scannedPlugin.manifest.main) {\n throw new Error(\"field 'main' not found in 'package.json'\");\n }\n if (!scannedPlugin.manifest.backstage?.role) {\n throw new Error(\"field 'backstage.role' not found in 'package.json'\");\n }\n } catch (e) {\n if (e instanceof ForwardedError) {\n this.logger.error(e.message, e.cause);\n } else {\n this.logger.error(\n `failed to load dynamic plugin manifest from '${pluginHome}'`,\n e,\n );\n }\n continue;\n }\n scannedPlugins.push(scannedPlugin);\n }\n return { packages: scannedPlugins };\n }\n\n private async scanDir(pluginHome: string): Promise<ScannedPluginPackage> {\n const manifestFile = path.resolve(pluginHome, 'package.json');\n const content = await fs.readFile(manifestFile);\n const manifest: ScannedPluginManifest = JSON.parse(content.toString());\n const scannedPluginPackage: ScannedPluginPackage = {\n location: url.pathToFileURL(pluginHome),\n manifest: manifest,\n };\n\n if (this.preferAlpha) {\n const pluginHomeAlpha = path.resolve(pluginHome, 'alpha');\n if (existsSync(pluginHomeAlpha)) {\n if ((await fs.lstat(pluginHomeAlpha)).isDirectory()) {\n try {\n const alphaContent = await fs.readFile(\n path.resolve(pluginHomeAlpha, 'package.json'),\n );\n scannedPluginPackage.alphaManifest = JSON.parse(\n alphaContent.toString(),\n );\n } catch (e) {\n throw new ForwardedError(\n `failed to load dynamic plugin manifest from '${pluginHome}/alpha'`,\n e,\n );\n }\n } else {\n this.logger.warn(\n `skipping '${pluginHomeAlpha}' since it is not a directory`,\n );\n }\n }\n }\n\n return scannedPluginPackage;\n }\n\n async trackChanges(): Promise<void> {\n const setupRootDirectoryWatcher = async (): Promise<void> => {\n return new Promise((resolve, reject) => {\n if (!this._rootDirectory) {\n resolve();\n return;\n }\n const callSubscribers = debounce(() => {\n this.subscribers.forEach(s => s());\n }, 500);\n let ready = false;\n this.rootDirectoryWatcher = chokidar\n .watch(this._rootDirectory, {\n ignoreInitial: true,\n followSymlinks: true,\n depth: 1,\n disableGlobbing: true,\n })\n .on(\n 'all',\n (\n event: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir',\n eventPath: string,\n _: Stats | undefined,\n ): void => {\n if (\n (['addDir', 'unlinkDir'].includes(event) &&\n path.dirname(eventPath) === this._rootDirectory) ||\n (['add', 'unlink', 'change'].includes(event) &&\n path.dirname(path.dirname(eventPath)) ===\n this._rootDirectory &&\n path.basename(eventPath) === 'package.json')\n ) {\n this.logger.info(\n `rootDirectory changed (${event} - ${eventPath}): scanning plugins again`,\n );\n callSubscribers();\n } else {\n this.logger.debug(\n `rootDirectory changed (${event} - ${eventPath}): no need to scan plugins again`,\n );\n }\n },\n )\n .on('error', (error: Error) => {\n this.logger.error(\n `error while watching '${this.rootDirectory}'`,\n error,\n );\n if (!ready) {\n reject(error);\n }\n })\n .on('ready', () => {\n ready = true;\n resolve();\n });\n });\n };\n\n await setupRootDirectoryWatcher();\n if (this.config.subscribe) {\n const { unsubscribe } = this.config.subscribe(async (): Promise<void> => {\n const oldRootDirectory = this._rootDirectory;\n try {\n this.applyConfig();\n } catch (e) {\n this.logger.error(\n 'failed to apply new config for dynamic plugins',\n e,\n );\n }\n if (oldRootDirectory !== this._rootDirectory) {\n this.logger.info(\n `rootDirectory changed in Config from '${oldRootDirectory}' to '${this._rootDirectory}'`,\n );\n this.subscribers.forEach(s => s());\n if (this.rootDirectoryWatcher) {\n await this.rootDirectoryWatcher.close();\n }\n await setupRootDirectoryWatcher();\n }\n });\n this.configUnsubscribe = unsubscribe;\n }\n }\n\n async untrackChanges() {\n if (this.rootDirectoryWatcher) {\n this.rootDirectoryWatcher.close();\n }\n if (this.configUnsubscribe) {\n this.configUnsubscribe();\n }\n }\n\n destructor() {\n this.untrackChanges();\n }\n}\n"],"names":["path","lstatSync","fs","ForwardedError","url","existsSync","debounce","chokidar"],"mappings":"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"}
|
|
@@ -101,10 +101,7 @@ async function gatherDynamicPluginsSchemas(packages, logger, schemaLocator = ()
|
|
|
101
101
|
for (const pluginPackage of packages) {
|
|
102
102
|
let schemaLocation = schemaLocator(pluginPackage);
|
|
103
103
|
if (!path__namespace.isAbsolute(schemaLocation)) {
|
|
104
|
-
|
|
105
|
-
if (path__namespace.basename(pluginLocation) === "alpha") {
|
|
106
|
-
pluginLocation = path__namespace.dirname(pluginLocation);
|
|
107
|
-
}
|
|
104
|
+
const pluginLocation = url__namespace.fileURLToPath(pluginPackage.location);
|
|
108
105
|
schemaLocation = path__namespace.resolve(pluginLocation, schemaLocation);
|
|
109
106
|
}
|
|
110
107
|
if (!await fs__default.default.pathExists(schemaLocation)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.cjs.js","sources":["../../src/schemas/schemas.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScannedPluginPackage } from '../scanner/types';\nimport {\n coreServices,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\nimport { findPaths } from '@backstage/cli-common';\n\nimport fs from 'fs-extra';\nimport * as path from 'path';\nimport * as url from 'url';\nimport { isEmpty } from 'lodash';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { PluginScanner } from '../scanner/plugin-scanner';\nimport { ConfigSchema, loadConfigSchema } from '@backstage/config-loader';\nimport { dynamicPluginsFeatureLoader } from '../features';\n\n/**\n *\n * @public\n * */\nexport interface DynamicPluginsSchemasService {\n addDynamicPluginsSchemas(configSchema: ConfigSchema): Promise<{\n schema: ConfigSchema;\n }>;\n}\n\n/**\n * A service that provides the config schemas of scanned dynamic plugins.\n *\n * @public\n */\nexport const dynamicPluginsSchemasServiceRef =\n createServiceRef<DynamicPluginsSchemasService>({\n id: 'core.dynamicplugins.schemas',\n scope: 'root',\n });\n\n/**\n * @public\n */\nexport interface DynamicPluginsSchemasOptions {\n /**\n * Function that returns the path to the Json schema file for a given scanned plugin package.\n * The path is either absolute, or relative to the plugin package root directory.\n *\n * Default behavior is to look for the `dist/configSchema.json` relative path.\n *\n * @param pluginPackage - The scanned plugin package.\n * @returns the absolute or plugin-relative path to the Json schema file.\n */\n schemaLocator?: (pluginPackage: ScannedPluginPackage) => string;\n}\n\nconst dynamicPluginsSchemasServiceFactoryWithOptions = (\n options?: DynamicPluginsSchemasOptions,\n) =>\n createServiceFactory({\n service: dynamicPluginsSchemasServiceRef,\n deps: {\n config: coreServices.rootConfig,\n },\n factory({ config }) {\n let additionalSchemas: { [context: string]: JsonObject } | undefined;\n\n return {\n async addDynamicPluginsSchemas(configSchema: ConfigSchema): Promise<{\n schema: ConfigSchema;\n }> {\n if (!additionalSchemas) {\n const logger = {\n ...console,\n child() {\n return this;\n },\n };\n\n const scanner = PluginScanner.create({\n config,\n logger,\n // eslint-disable-next-line no-restricted-syntax\n backstageRoot: findPaths(__dirname).targetRoot,\n preferAlpha: true,\n });\n\n const { packages } = await scanner.scanRoot();\n\n additionalSchemas = await gatherDynamicPluginsSchemas(\n packages,\n logger,\n options?.schemaLocator,\n );\n }\n\n const serialized = configSchema.serialize();\n if (serialized?.backstageConfigSchemaVersion !== 1) {\n throw new Error(\n 'Serialized configuration schema is invalid or has an invalid version number',\n );\n }\n const schemas = serialized.schemas as {\n value: JsonObject;\n path: string;\n }[];\n\n schemas.push(\n ...Object.keys(additionalSchemas).map(context => {\n return {\n path: context,\n value: additionalSchemas![context],\n };\n }),\n );\n serialized.schemas = schemas;\n return {\n schema: await loadConfigSchema({\n serialized,\n }),\n };\n },\n };\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsSchemasServiceFactory = Object.assign(\n dynamicPluginsSchemasServiceFactoryWithOptions,\n dynamicPluginsSchemasServiceFactoryWithOptions(),\n);\n\n/** @internal */\nasync function gatherDynamicPluginsSchemas(\n packages: ScannedPluginPackage[],\n logger: LoggerService,\n schemaLocator: (pluginPackage: ScannedPluginPackage) => string = () =>\n path.join('dist', 'configSchema.json'),\n): Promise<{ [context: string]: JsonObject }> {\n const allSchemas: { [context: string]: JsonObject } = {};\n\n for (const pluginPackage of packages) {\n let schemaLocation = schemaLocator(pluginPackage);\n\n if (!path.isAbsolute(schemaLocation)) {\n
|
|
1
|
+
{"version":3,"file":"schemas.cjs.js","sources":["../../src/schemas/schemas.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScannedPluginPackage } from '../scanner/types';\nimport {\n coreServices,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\nimport { findPaths } from '@backstage/cli-common';\n\nimport fs from 'fs-extra';\nimport * as path from 'path';\nimport * as url from 'url';\nimport { isEmpty } from 'lodash';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { PluginScanner } from '../scanner/plugin-scanner';\nimport { ConfigSchema, loadConfigSchema } from '@backstage/config-loader';\nimport { dynamicPluginsFeatureLoader } from '../features';\n\n/**\n *\n * @public\n * */\nexport interface DynamicPluginsSchemasService {\n addDynamicPluginsSchemas(configSchema: ConfigSchema): Promise<{\n schema: ConfigSchema;\n }>;\n}\n\n/**\n * A service that provides the config schemas of scanned dynamic plugins.\n *\n * @public\n */\nexport const dynamicPluginsSchemasServiceRef =\n createServiceRef<DynamicPluginsSchemasService>({\n id: 'core.dynamicplugins.schemas',\n scope: 'root',\n });\n\n/**\n * @public\n */\nexport interface DynamicPluginsSchemasOptions {\n /**\n * Function that returns the path to the Json schema file for a given scanned plugin package.\n * The path is either absolute, or relative to the plugin package root directory.\n *\n * Default behavior is to look for the `dist/configSchema.json` relative path.\n *\n * @param pluginPackage - The scanned plugin package.\n * @returns the absolute or plugin-relative path to the Json schema file.\n */\n schemaLocator?: (pluginPackage: ScannedPluginPackage) => string;\n}\n\nconst dynamicPluginsSchemasServiceFactoryWithOptions = (\n options?: DynamicPluginsSchemasOptions,\n) =>\n createServiceFactory({\n service: dynamicPluginsSchemasServiceRef,\n deps: {\n config: coreServices.rootConfig,\n },\n factory({ config }) {\n let additionalSchemas: { [context: string]: JsonObject } | undefined;\n\n return {\n async addDynamicPluginsSchemas(configSchema: ConfigSchema): Promise<{\n schema: ConfigSchema;\n }> {\n if (!additionalSchemas) {\n const logger = {\n ...console,\n child() {\n return this;\n },\n };\n\n const scanner = PluginScanner.create({\n config,\n logger,\n // eslint-disable-next-line no-restricted-syntax\n backstageRoot: findPaths(__dirname).targetRoot,\n preferAlpha: true,\n });\n\n const { packages } = await scanner.scanRoot();\n\n additionalSchemas = await gatherDynamicPluginsSchemas(\n packages,\n logger,\n options?.schemaLocator,\n );\n }\n\n const serialized = configSchema.serialize();\n if (serialized?.backstageConfigSchemaVersion !== 1) {\n throw new Error(\n 'Serialized configuration schema is invalid or has an invalid version number',\n );\n }\n const schemas = serialized.schemas as {\n value: JsonObject;\n path: string;\n }[];\n\n schemas.push(\n ...Object.keys(additionalSchemas).map(context => {\n return {\n path: context,\n value: additionalSchemas![context],\n };\n }),\n );\n serialized.schemas = schemas;\n return {\n schema: await loadConfigSchema({\n serialized,\n }),\n };\n },\n };\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsSchemasServiceFactory = Object.assign(\n dynamicPluginsSchemasServiceFactoryWithOptions,\n dynamicPluginsSchemasServiceFactoryWithOptions(),\n);\n\n/** @internal */\nasync function gatherDynamicPluginsSchemas(\n packages: ScannedPluginPackage[],\n logger: LoggerService,\n schemaLocator: (pluginPackage: ScannedPluginPackage) => string = () =>\n path.join('dist', 'configSchema.json'),\n): Promise<{ [context: string]: JsonObject }> {\n const allSchemas: { [context: string]: JsonObject } = {};\n\n for (const pluginPackage of packages) {\n let schemaLocation = schemaLocator(pluginPackage);\n\n if (!path.isAbsolute(schemaLocation)) {\n const pluginLocation = url.fileURLToPath(pluginPackage.location);\n schemaLocation = path.resolve(pluginLocation, schemaLocation);\n }\n\n if (!(await fs.pathExists(schemaLocation))) {\n continue;\n }\n\n const serialized = await fs.readJson(schemaLocation);\n if (!serialized) {\n continue;\n }\n\n if (isEmpty(serialized)) {\n continue;\n }\n\n if (!serialized?.$schema || serialized?.type !== 'object') {\n logger.error(\n `Serialized configuration schema is invalid for plugin ${pluginPackage.manifest.name}`,\n );\n continue;\n }\n\n allSchemas[schemaLocation] = serialized;\n }\n\n return allSchemas;\n}\n"],"names":["createServiceRef","createServiceFactory","coreServices","PluginScanner","findPaths","loadConfigSchema","path","url","fs","isEmpty"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-dynamic-feature-service",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4-next.1",
|
|
4
4
|
"description": "Backstage dynamic feature service",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -42,26 +42,26 @@
|
|
|
42
42
|
"test": "backstage-cli package test"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@backstage/backend-app-api": "
|
|
45
|
+
"@backstage/backend-app-api": "1.0.2-next.1",
|
|
46
46
|
"@backstage/backend-common": "^0.25.0",
|
|
47
|
-
"@backstage/backend-defaults": "
|
|
48
|
-
"@backstage/backend-plugin-api": "
|
|
49
|
-
"@backstage/cli-common": "
|
|
50
|
-
"@backstage/cli-node": "
|
|
51
|
-
"@backstage/config": "
|
|
52
|
-
"@backstage/config-loader": "
|
|
53
|
-
"@backstage/errors": "
|
|
54
|
-
"@backstage/plugin-app-node": "
|
|
55
|
-
"@backstage/plugin-auth-node": "
|
|
56
|
-
"@backstage/plugin-catalog-backend": "
|
|
57
|
-
"@backstage/plugin-events-backend": "
|
|
58
|
-
"@backstage/plugin-events-node": "
|
|
59
|
-
"@backstage/plugin-permission-common": "
|
|
60
|
-
"@backstage/plugin-permission-node": "
|
|
61
|
-
"@backstage/plugin-scaffolder-node": "
|
|
62
|
-
"@backstage/plugin-search-backend-node": "
|
|
63
|
-
"@backstage/plugin-search-common": "
|
|
64
|
-
"@backstage/types": "
|
|
47
|
+
"@backstage/backend-defaults": "0.5.3-next.1",
|
|
48
|
+
"@backstage/backend-plugin-api": "1.0.2-next.1",
|
|
49
|
+
"@backstage/cli-common": "0.1.15-next.0",
|
|
50
|
+
"@backstage/cli-node": "0.2.10-next.0",
|
|
51
|
+
"@backstage/config": "1.2.0",
|
|
52
|
+
"@backstage/config-loader": "1.9.2-next.0",
|
|
53
|
+
"@backstage/errors": "1.2.4",
|
|
54
|
+
"@backstage/plugin-app-node": "0.1.27-next.1",
|
|
55
|
+
"@backstage/plugin-auth-node": "0.5.4-next.1",
|
|
56
|
+
"@backstage/plugin-catalog-backend": "1.27.2-next.1",
|
|
57
|
+
"@backstage/plugin-events-backend": "0.3.16-next.1",
|
|
58
|
+
"@backstage/plugin-events-node": "0.4.4-next.1",
|
|
59
|
+
"@backstage/plugin-permission-common": "0.8.1",
|
|
60
|
+
"@backstage/plugin-permission-node": "0.8.5-next.1",
|
|
61
|
+
"@backstage/plugin-scaffolder-node": "0.5.1-next.1",
|
|
62
|
+
"@backstage/plugin-search-backend-node": "1.3.5-next.1",
|
|
63
|
+
"@backstage/plugin-search-common": "1.2.14",
|
|
64
|
+
"@backstage/types": "1.1.1",
|
|
65
65
|
"@manypkg/get-packages": "^1.1.3",
|
|
66
66
|
"@types/express": "^4.17.6",
|
|
67
67
|
"chokidar": "^3.5.3",
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"winston": "^3.2.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@backstage/backend-test-utils": "
|
|
75
|
-
"@backstage/cli": "
|
|
76
|
-
"@backstage/plugin-app-backend": "
|
|
74
|
+
"@backstage/backend-test-utils": "1.0.3-next.1",
|
|
75
|
+
"@backstage/cli": "0.29.0-next.1",
|
|
76
|
+
"@backstage/plugin-app-backend": "0.3.77-next.1",
|
|
77
77
|
"triple-beam": "^1.4.1",
|
|
78
78
|
"wait-for-expect": "^3.0.2"
|
|
79
79
|
}
|