@backstage/backend-dynamic-feature-service 0.7.5-next.1 → 0.7.6-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/dist/index.d.ts +4 -4
- package/dist/loader/CommonJSModuleLoader.cjs.js +2 -1
- package/dist/loader/CommonJSModuleLoader.cjs.js.map +1 -1
- package/dist/manager/plugin-manager.cjs.js +11 -7
- package/dist/manager/plugin-manager.cjs.js.map +1 -1
- package/dist/scanner/plugin-scanner.cjs.js +8 -4
- package/dist/scanner/plugin-scanner.cjs.js.map +1 -1
- package/package.json +22 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# @backstage/backend-dynamic-feature-service
|
|
2
2
|
|
|
3
|
+
## 0.7.6-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/backend-defaults@0.13.1-next.0
|
|
10
|
+
- @backstage/plugin-catalog-backend@3.1.3-next.0
|
|
11
|
+
- @backstage/plugin-search-backend-node@1.3.17-next.0
|
|
12
|
+
- @backstage/plugin-events-backend@0.5.8-next.0
|
|
13
|
+
- @backstage/plugin-events-node@0.4.17-next.0
|
|
14
|
+
- @backstage/plugin-auth-node@0.6.9-next.0
|
|
15
|
+
- @backstage/config-loader@1.10.6-next.0
|
|
16
|
+
- @backstage/config@1.3.6-next.0
|
|
17
|
+
- @backstage/cli-node@0.2.15-next.0
|
|
18
|
+
- @backstage/plugin-scaffolder-node@0.12.1-next.0
|
|
19
|
+
- @backstage/plugin-permission-node@0.10.6-next.0
|
|
20
|
+
- @backstage/backend-openapi-utils@0.6.3-next.0
|
|
21
|
+
- @backstage/backend-plugin-api@1.4.5-next.0
|
|
22
|
+
- @backstage/cli-common@0.1.15
|
|
23
|
+
- @backstage/errors@1.2.7
|
|
24
|
+
- @backstage/types@1.2.2
|
|
25
|
+
- @backstage/plugin-app-node@0.1.39-next.0
|
|
26
|
+
- @backstage/plugin-permission-common@0.9.3-next.0
|
|
27
|
+
- @backstage/plugin-search-common@1.2.21-next.0
|
|
28
|
+
|
|
29
|
+
## 0.7.5
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- Updated dependencies
|
|
34
|
+
- @backstage/plugin-catalog-backend@3.1.2
|
|
35
|
+
- @backstage/backend-defaults@0.13.0
|
|
36
|
+
- @backstage/plugin-scaffolder-node@0.12.0
|
|
37
|
+
- @backstage/config-loader@1.10.5
|
|
38
|
+
- @backstage/config@1.3.5
|
|
39
|
+
- @backstage/backend-openapi-utils@0.6.2
|
|
40
|
+
- @backstage/backend-plugin-api@1.4.4
|
|
41
|
+
- @backstage/plugin-app-node@0.1.38
|
|
42
|
+
- @backstage/plugin-auth-node@0.6.8
|
|
43
|
+
- @backstage/plugin-events-backend@0.5.7
|
|
44
|
+
- @backstage/plugin-events-node@0.4.16
|
|
45
|
+
- @backstage/plugin-permission-common@0.9.2
|
|
46
|
+
- @backstage/plugin-permission-node@0.10.5
|
|
47
|
+
- @backstage/plugin-search-backend-node@1.3.16
|
|
48
|
+
- @backstage/plugin-search-common@1.2.20
|
|
49
|
+
|
|
3
50
|
## 0.7.5-next.1
|
|
4
51
|
|
|
5
52
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -43,8 +43,8 @@ type CommonJSModuleLoaderOptions = {
|
|
|
43
43
|
* @public
|
|
44
44
|
*/
|
|
45
45
|
declare class CommonJSModuleLoader implements ModuleLoader {
|
|
46
|
-
readonly options: CommonJSModuleLoaderOptions;
|
|
47
46
|
private module;
|
|
47
|
+
readonly options: CommonJSModuleLoaderOptions;
|
|
48
48
|
constructor(options: CommonJSModuleLoaderOptions);
|
|
49
49
|
bootstrap(backstageRoot: string, dynamicPluginsPaths: string[], scannedPluginManifests: Map<string, ScannedPluginManifest>): Promise<void>;
|
|
50
50
|
load(packagePath: string): Promise<any>;
|
|
@@ -131,12 +131,12 @@ interface DynamicPluginManagerOptions {
|
|
|
131
131
|
* @public
|
|
132
132
|
*/
|
|
133
133
|
declare class DynamicPluginManager implements DynamicPluginProvider {
|
|
134
|
-
private readonly logger;
|
|
135
|
-
private readonly packages;
|
|
136
|
-
private readonly moduleLoader;
|
|
137
134
|
static create(options: DynamicPluginManagerOptions): Promise<DynamicPluginManager>;
|
|
138
135
|
private readonly _plugins;
|
|
139
136
|
private _availablePackages;
|
|
137
|
+
private readonly logger;
|
|
138
|
+
private readonly packages;
|
|
139
|
+
private readonly moduleLoader;
|
|
140
140
|
private constructor();
|
|
141
141
|
get availablePackages(): ScannedPluginPackage[];
|
|
142
142
|
addBackendPlugin(plugin: BackendDynamicPlugin): void;
|
|
@@ -7,11 +7,12 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
7
7
|
var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
8
8
|
|
|
9
9
|
class CommonJSModuleLoader {
|
|
10
|
+
module;
|
|
11
|
+
options;
|
|
10
12
|
constructor(options) {
|
|
11
13
|
this.options = options;
|
|
12
14
|
this.module = require("node:module");
|
|
13
15
|
}
|
|
14
|
-
module;
|
|
15
16
|
async bootstrap(backstageRoot, dynamicPluginsPaths, scannedPluginManifests) {
|
|
16
17
|
const backstageRootNodeModulesPath = `${backstageRoot}/node_modules`;
|
|
17
18
|
const dynamicNodeModulesPaths = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommonJSModuleLoader.cjs.js","sources":["../../src/loader/CommonJSModuleLoader.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 { ModuleLoader } from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport path from 'path';\nimport { ScannedPluginManifest } from '../scanner';\n\n/**\n * @public\n */\nexport type CommonJSModuleLoaderOptions = {\n logger: LoggerService;\n dynamicPluginPackageNameSuffixes?: String[];\n customResolveDynamicPackage?: (\n logger: LoggerService,\n searchedPackageName: string,\n scannedPluginManifests: Map<string, ScannedPluginManifest>,\n ) => string | undefined;\n};\n\n/**\n * @public\n */\nexport class CommonJSModuleLoader implements ModuleLoader {\n private module: any;\n
|
|
1
|
+
{"version":3,"file":"CommonJSModuleLoader.cjs.js","sources":["../../src/loader/CommonJSModuleLoader.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 { ModuleLoader } from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport path from 'path';\nimport { ScannedPluginManifest } from '../scanner';\n\n/**\n * @public\n */\nexport type CommonJSModuleLoaderOptions = {\n logger: LoggerService;\n dynamicPluginPackageNameSuffixes?: String[];\n customResolveDynamicPackage?: (\n logger: LoggerService,\n searchedPackageName: string,\n scannedPluginManifests: Map<string, ScannedPluginManifest>,\n ) => string | undefined;\n};\n\n/**\n * @public\n */\nexport class CommonJSModuleLoader implements ModuleLoader {\n private module: any;\n public readonly options: CommonJSModuleLoaderOptions;\n\n constructor(options: CommonJSModuleLoaderOptions) {\n this.options = options;\n this.module = require('node:module');\n }\n\n async bootstrap(\n backstageRoot: string,\n dynamicPluginsPaths: string[],\n scannedPluginManifests: Map<string, ScannedPluginManifest>,\n ): Promise<void> {\n const backstageRootNodeModulesPath = `${backstageRoot}/node_modules`;\n const dynamicNodeModulesPaths = [\n ...dynamicPluginsPaths.map(p => path.resolve(p, 'node_modules')),\n ];\n const oldNodeModulePaths = this.module._nodeModulePaths;\n this.module._nodeModulePaths = (from: string): string[] => {\n const result: string[] = oldNodeModulePaths(from);\n if (!dynamicPluginsPaths.some(p => from.startsWith(p))) {\n return result;\n }\n const filtered = result.filter(nodeModulePath => {\n return (\n nodeModulePath === backstageRootNodeModulesPath ||\n dynamicNodeModulesPaths.some(p => nodeModulePath.startsWith(p))\n );\n });\n this.options.logger.debug(\n `Overriding node_modules search path for dynamic plugin ${from} to: ${filtered}`,\n );\n return filtered;\n };\n\n // The whole piece of code below is a way to accommodate the limitations of\n // the current `resolvePackagePath` implementation, which cannot be provided\n // some custom locations where it should find the assets of some given packages.\n //\n // Since the packages for dynamic plugins are not located in the main backstage\n // monorepo structure, and since dynamic plugins could also be repackaged\n // (typically renamed with a `-dynamic` suffix), for now we have to customize\n // module file name resolution here to support these use-cases.\n //\n // This might not be necessary anymore according to future enhancements to the\n // `resolvePackagePath` feature.\n const oldResolveFileName = this.module._resolveFilename;\n this.module._resolveFilename = (\n request: string,\n mod: NodeModule,\n _: boolean,\n options: any,\n ): any => {\n let errorToThrow: any;\n try {\n return oldResolveFileName(request, mod, _, options);\n } catch (e) {\n errorToThrow = e;\n this.options.logger.debug(\n `Could not resolve '${request}' inside the Core backstage backend application`,\n e instanceof Error ? e : undefined,\n );\n }\n\n // Are we trying to resolve a `package.json` from an originating module of the core backstage application\n // (this is mostly done by calling `@backstage/backend-plugin-api/resolvePackagePath`).\n const resolvingPackageJsonFromBackstageApplication =\n request?.endsWith('/package.json') &&\n mod?.path &&\n !dynamicPluginsPaths.some(p => mod.path.startsWith(p));\n\n // If not, we don't need the dedicated specific case below.\n if (!resolvingPackageJsonFromBackstageApplication) {\n throw errorToThrow;\n }\n\n this.options.logger.info(\n `Resolving '${request}' in the dynamic backend plugins`,\n );\n const searchedPackageName = request.replace(/\\/package.json$/, '');\n\n // First search for a dynamic plugin package matching the expected package name,\n // taking in account accepted dynamic plugin package name suffixes\n // (suffix accepted by default is '-dynamic').\n const searchedPackageNamesWithSuffixes = (\n this.options.dynamicPluginPackageNameSuffixes ?? ['-dynamic']\n ).map(s => `${searchedPackageName}${s}`);\n for (const [realPath, pkg] of scannedPluginManifests.entries()) {\n if (\n [searchedPackageName, ...searchedPackageNamesWithSuffixes].includes(\n pkg.name,\n )\n ) {\n const resolvedPath = path.resolve(realPath, 'package.json');\n this.options.logger.info(`Resolved '${request}' at ${resolvedPath}`);\n return resolvedPath;\n }\n }\n\n // If a custom resolution is provided, use it.\n // This allows accommodating alternate ways to package dynamic plugins:\n // static plugin package wrapped inside a distinct dynamic plugin package for example.\n if (this.options.customResolveDynamicPackage) {\n const resolvedPath = this.options.customResolveDynamicPackage(\n this.options.logger,\n searchedPackageName,\n scannedPluginManifests,\n );\n if (resolvedPath) {\n return resolvedPath;\n }\n }\n throw errorToThrow;\n };\n }\n\n async load(packagePath: string): Promise<any> {\n return await this.module.prototype.require(packagePath);\n }\n}\n"],"names":["path"],"mappings":"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"}
|
|
@@ -31,13 +31,6 @@ var url__namespace = /*#__PURE__*/_interopNamespaceCompat(url);
|
|
|
31
31
|
var fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
|
|
32
32
|
|
|
33
33
|
class DynamicPluginManager {
|
|
34
|
-
constructor(logger, packages, moduleLoader) {
|
|
35
|
-
this.logger = logger;
|
|
36
|
-
this.packages = packages;
|
|
37
|
-
this.moduleLoader = moduleLoader;
|
|
38
|
-
this._plugins = [];
|
|
39
|
-
this._availablePackages = packages;
|
|
40
|
-
}
|
|
41
34
|
static async create(options) {
|
|
42
35
|
const backstageRoot = cliCommon.findPaths(__dirname).targetRoot;
|
|
43
36
|
const scanner = pluginScanner.PluginScanner.create({
|
|
@@ -73,6 +66,16 @@ class DynamicPluginManager {
|
|
|
73
66
|
}
|
|
74
67
|
_plugins;
|
|
75
68
|
_availablePackages;
|
|
69
|
+
logger;
|
|
70
|
+
packages;
|
|
71
|
+
moduleLoader;
|
|
72
|
+
constructor(logger, packages, moduleLoader) {
|
|
73
|
+
this.logger = logger;
|
|
74
|
+
this.packages = packages;
|
|
75
|
+
this.moduleLoader = moduleLoader;
|
|
76
|
+
this._plugins = [];
|
|
77
|
+
this._availablePackages = packages;
|
|
78
|
+
}
|
|
76
79
|
get availablePackages() {
|
|
77
80
|
return this._availablePackages;
|
|
78
81
|
}
|
|
@@ -211,6 +214,7 @@ const dynamicPluginsServiceFactory = Object.assign(
|
|
|
211
214
|
dynamicPluginsServiceFactoryWithOptions()
|
|
212
215
|
);
|
|
213
216
|
class DynamicPluginsEnabledFeatureDiscoveryService {
|
|
217
|
+
dynamicPlugins;
|
|
214
218
|
constructor(dynamicPlugins) {
|
|
215
219
|
this.dynamicPlugins = dynamicPlugins;
|
|
216
220
|
}
|
|
@@ -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 * as fs from 'fs';\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 await scanner.trackChanges();\n const moduleLoader =\n options.moduleLoader ||\n new CommonJSModuleLoader({ logger: options.logger });\n const manager = new DynamicPluginManager(\n options.logger,\n scannedPlugins,\n moduleLoader,\n );\n\n const scannedPluginManifestsPerRealPath = new Map(\n scannedPlugins.map(p => [\n fs.realpathSync(url.fileURLToPath(p.location)),\n p.manifest,\n ]),\n );\n\n await moduleLoader.bootstrap(\n backstageRoot,\n [...scannedPluginManifestsPerRealPath.keys()],\n scannedPluginManifestsPerRealPath,\n );\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 constructor(private readonly dynamicPlugins: DynamicPluginProvider) {}\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n return {\n features: 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 };\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","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';\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 await scanner.trackChanges();\n const moduleLoader =\n options.moduleLoader ||\n new CommonJSModuleLoader({ logger: options.logger });\n const manager = new DynamicPluginManager(\n options.logger,\n scannedPlugins,\n moduleLoader,\n );\n\n const scannedPluginManifestsPerRealPath = new Map(\n scannedPlugins.map(p => [\n fs.realpathSync(url.fileURLToPath(p.location)),\n p.manifest,\n ]),\n );\n\n await moduleLoader.bootstrap(\n backstageRoot,\n [...scannedPluginManifestsPerRealPath.keys()],\n scannedPluginManifestsPerRealPath,\n );\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 readonly logger: LoggerService;\n private readonly packages: ScannedPluginPackage[];\n private readonly moduleLoader: ModuleLoader;\n\n private constructor(\n logger: LoggerService,\n packages: ScannedPluginPackage[],\n moduleLoader: ModuleLoader,\n ) {\n this.logger = logger;\n this.packages = packages;\n this.moduleLoader = moduleLoader;\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 private readonly dynamicPlugins: DynamicPluginProvider;\n\n constructor(dynamicPlugins: DynamicPluginProvider) {\n this.dynamicPlugins = dynamicPlugins;\n }\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n return {\n features: 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 };\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","createBackendFeatureLoader"],"mappings":"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"}
|
|
@@ -36,16 +36,20 @@ var debounce__default = /*#__PURE__*/_interopDefaultCompat(debounce);
|
|
|
36
36
|
|
|
37
37
|
const configKey = "dynamicPlugins";
|
|
38
38
|
class PluginScanner {
|
|
39
|
+
_rootDirectory;
|
|
40
|
+
configUnsubscribe;
|
|
41
|
+
rootDirectoryWatcher;
|
|
42
|
+
subscribers = [];
|
|
43
|
+
config;
|
|
44
|
+
logger;
|
|
45
|
+
backstageRoot;
|
|
46
|
+
preferAlpha;
|
|
39
47
|
constructor(config, logger, backstageRoot, preferAlpha) {
|
|
40
48
|
this.config = config;
|
|
41
49
|
this.logger = logger;
|
|
42
50
|
this.backstageRoot = backstageRoot;
|
|
43
51
|
this.preferAlpha = preferAlpha;
|
|
44
52
|
}
|
|
45
|
-
_rootDirectory;
|
|
46
|
-
configUnsubscribe;
|
|
47
|
-
rootDirectoryWatcher;
|
|
48
|
-
subscribers = [];
|
|
49
53
|
static create(options) {
|
|
50
54
|
const scanner = new PluginScanner(
|
|
51
55
|
options.config,
|
|
@@ -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 { 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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"}
|
|
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 private readonly config: Config;\n private readonly logger: LoggerService;\n private readonly backstageRoot: string;\n private readonly preferAlpha: boolean;\n\n private constructor(\n config: Config,\n logger: LoggerService,\n backstageRoot: string,\n preferAlpha: boolean,\n ) {\n this.config = config;\n this.logger = logger;\n this.backstageRoot = backstageRoot;\n this.preferAlpha = preferAlpha;\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-dynamic-feature-service",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6-next.0",
|
|
4
4
|
"description": "Backstage dynamic feature service",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -52,24 +52,24 @@
|
|
|
52
52
|
"test": "backstage-cli package test"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@backstage/backend-defaults": "0.13.
|
|
56
|
-
"@backstage/backend-openapi-utils": "0.6.
|
|
57
|
-
"@backstage/backend-plugin-api": "1.4.
|
|
55
|
+
"@backstage/backend-defaults": "0.13.1-next.0",
|
|
56
|
+
"@backstage/backend-openapi-utils": "0.6.3-next.0",
|
|
57
|
+
"@backstage/backend-plugin-api": "1.4.5-next.0",
|
|
58
58
|
"@backstage/cli-common": "0.1.15",
|
|
59
|
-
"@backstage/cli-node": "0.2.
|
|
60
|
-
"@backstage/config": "1.3.
|
|
61
|
-
"@backstage/config-loader": "1.10.
|
|
59
|
+
"@backstage/cli-node": "0.2.15-next.0",
|
|
60
|
+
"@backstage/config": "1.3.6-next.0",
|
|
61
|
+
"@backstage/config-loader": "1.10.6-next.0",
|
|
62
62
|
"@backstage/errors": "1.2.7",
|
|
63
|
-
"@backstage/plugin-app-node": "0.1.
|
|
64
|
-
"@backstage/plugin-auth-node": "0.6.
|
|
65
|
-
"@backstage/plugin-catalog-backend": "3.1.
|
|
66
|
-
"@backstage/plugin-events-backend": "0.5.
|
|
67
|
-
"@backstage/plugin-events-node": "0.4.
|
|
68
|
-
"@backstage/plugin-permission-common": "0.9.
|
|
69
|
-
"@backstage/plugin-permission-node": "0.10.
|
|
70
|
-
"@backstage/plugin-scaffolder-node": "0.12.
|
|
71
|
-
"@backstage/plugin-search-backend-node": "1.3.
|
|
72
|
-
"@backstage/plugin-search-common": "1.2.
|
|
63
|
+
"@backstage/plugin-app-node": "0.1.39-next.0",
|
|
64
|
+
"@backstage/plugin-auth-node": "0.6.9-next.0",
|
|
65
|
+
"@backstage/plugin-catalog-backend": "3.1.3-next.0",
|
|
66
|
+
"@backstage/plugin-events-backend": "0.5.8-next.0",
|
|
67
|
+
"@backstage/plugin-events-node": "0.4.17-next.0",
|
|
68
|
+
"@backstage/plugin-permission-common": "0.9.3-next.0",
|
|
69
|
+
"@backstage/plugin-permission-node": "0.10.6-next.0",
|
|
70
|
+
"@backstage/plugin-scaffolder-node": "0.12.1-next.0",
|
|
71
|
+
"@backstage/plugin-search-backend-node": "1.3.17-next.0",
|
|
72
|
+
"@backstage/plugin-search-common": "1.2.21-next.0",
|
|
73
73
|
"@backstage/types": "1.2.2",
|
|
74
74
|
"@manypkg/get-packages": "^1.1.3",
|
|
75
75
|
"@module-federation/sdk": "^0.9.0",
|
|
@@ -81,11 +81,11 @@
|
|
|
81
81
|
"winston": "^3.2.1"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@backstage/backend-app-api": "1.2.
|
|
85
|
-
"@backstage/backend-test-utils": "1.
|
|
86
|
-
"@backstage/cli": "0.34.
|
|
87
|
-
"@backstage/plugin-app-backend": "0.5.
|
|
88
|
-
"@backstage/repo-tools": "0.15.
|
|
84
|
+
"@backstage/backend-app-api": "1.2.9-next.0",
|
|
85
|
+
"@backstage/backend-test-utils": "1.10.0-next.0",
|
|
86
|
+
"@backstage/cli": "0.34.5-next.0",
|
|
87
|
+
"@backstage/plugin-app-backend": "0.5.8-next.0",
|
|
88
|
+
"@backstage/repo-tools": "0.15.4-next.0",
|
|
89
89
|
"@types/express": "^4.17.6",
|
|
90
90
|
"triple-beam": "^1.4.1",
|
|
91
91
|
"wait-for-expect": "^3.0.2"
|