@backstage/backend-dynamic-feature-service 0.4.2-next.2 → 0.4.3
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 +56 -0
- package/README.md +1 -2
- package/dist/features/features.cjs.js +35 -0
- package/dist/features/features.cjs.js.map +1 -0
- package/dist/index.cjs.js +6 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +93 -53
- package/dist/loader/CommonJSModuleLoader.cjs.js +5 -7
- package/dist/loader/CommonJSModuleLoader.cjs.js.map +1 -1
- package/dist/manager/plugin-manager.cjs.js +78 -61
- package/dist/manager/plugin-manager.cjs.js.map +1 -1
- package/dist/manager/types.cjs.js.map +1 -1
- package/dist/scanner/plugin-scanner.cjs.js +7 -5
- package/dist/scanner/plugin-scanner.cjs.js.map +1 -1
- package/dist/schemas/{appBackendModule.cjs.js → frontend.cjs.js} +1 -1
- package/dist/schemas/frontend.cjs.js.map +1 -0
- package/dist/schemas/{rootLoggerServiceFactory.cjs.js → rootLogger.cjs.js} +13 -8
- package/dist/schemas/rootLogger.cjs.js.map +1 -0
- package/dist/schemas/schemas.cjs.js +4 -2
- package/dist/schemas/schemas.cjs.js.map +1 -1
- package/package.json +24 -22
- package/dist/schemas/appBackendModule.cjs.js.map +0 -1
- package/dist/schemas/rootLoggerServiceFactory.cjs.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# @backstage/backend-dynamic-feature-service
|
|
2
2
|
|
|
3
|
+
## 0.4.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/plugin-events-node@0.4.2
|
|
9
|
+
- @backstage/backend-defaults@0.5.2
|
|
10
|
+
- @backstage/plugin-catalog-backend@1.27.1
|
|
11
|
+
- @backstage/plugin-events-backend@0.3.14
|
|
12
|
+
- @backstage/backend-app-api@1.0.1
|
|
13
|
+
- @backstage/plugin-search-backend-node@1.3.4
|
|
14
|
+
- @backstage/backend-plugin-api@1.0.1
|
|
15
|
+
- @backstage/cli-node@0.2.9
|
|
16
|
+
- @backstage/config-loader@1.9.1
|
|
17
|
+
- @backstage/plugin-auth-node@0.5.3
|
|
18
|
+
- @backstage/plugin-permission-node@0.8.4
|
|
19
|
+
- @backstage/plugin-scaffolder-node@0.5.0
|
|
20
|
+
|
|
21
|
+
## 0.4.2
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- d18d494: Enhance and simplify the activation of the dynamic plugins feature:
|
|
26
|
+
|
|
27
|
+
- The dynamic plugins service (which implements the `DynamicPluginsProvider`) is restored, since it is required for plugins to depend on it in order to get the details of loaded dynamic plugins (possibly with loading errors to be surfaced in some UI).
|
|
28
|
+
- A new all-in-one feature loader (`dynamicPluginsFeatureLoader`) is provided that allows a 1-liner activation of both the dynamic features and additional services or plugins required to have the dynamic plugins work correctly with dynamic plugins config schemas. Previous service factories or feature loaders are deprecated.
|
|
29
|
+
|
|
30
|
+
- e6c0550: Enhance the API of the `DynamicPluginProvider` (available as a service) to:
|
|
31
|
+
|
|
32
|
+
- expose the new `getScannedPackage()` method that returns the `ScannedPluginPackage` from which a given plugin has been loaded,
|
|
33
|
+
- add an optional `includeFailed` argument in the plugins list retrieval methods, to include the plugins that could be successfully loaded (`false` by default).
|
|
34
|
+
|
|
35
|
+
- 4c89e47: Allow passing an async module loader in the `DynamicPluginsFeatureLoaderOptions`.
|
|
36
|
+
- 094eaa3: Remove references to in-repo backend-common
|
|
37
|
+
- 2f88f88: Updated backend installation instructions.
|
|
38
|
+
- Updated dependencies
|
|
39
|
+
- @backstage/backend-defaults@0.5.1
|
|
40
|
+
- @backstage/cli-node@0.2.9
|
|
41
|
+
- @backstage/backend-app-api@1.0.1
|
|
42
|
+
- @backstage/plugin-scaffolder-node@0.5.0
|
|
43
|
+
- @backstage/plugin-auth-node@0.5.3
|
|
44
|
+
- @backstage/plugin-search-backend-node@1.3.3
|
|
45
|
+
- @backstage/plugin-catalog-backend@1.27.0
|
|
46
|
+
- @backstage/plugin-permission-node@0.8.4
|
|
47
|
+
- @backstage/plugin-events-backend@0.3.13
|
|
48
|
+
- @backstage/plugin-events-node@0.4.1
|
|
49
|
+
- @backstage/backend-plugin-api@1.0.1
|
|
50
|
+
- @backstage/cli-common@0.1.14
|
|
51
|
+
- @backstage/config@1.2.0
|
|
52
|
+
- @backstage/config-loader@1.9.1
|
|
53
|
+
- @backstage/errors@1.2.4
|
|
54
|
+
- @backstage/types@1.1.1
|
|
55
|
+
- @backstage/plugin-app-node@0.1.26
|
|
56
|
+
- @backstage/plugin-permission-common@0.8.1
|
|
57
|
+
- @backstage/plugin-search-common@1.2.14
|
|
58
|
+
|
|
3
59
|
## 0.4.2-next.2
|
|
4
60
|
|
|
5
61
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -15,8 +15,7 @@ In the `backend` application, it can be enabled by adding the `backend-dynamic-f
|
|
|
15
15
|
```ts
|
|
16
16
|
const backend = createBackend();
|
|
17
17
|
+
|
|
18
|
-
+ backend.add(
|
|
19
|
-
+ backend.add(dynamicPluginsServiceFactory)
|
|
18
|
+
+ backend.add(dynamicPluginsFeatureLoader) // provides features loaded by dynamic plugins
|
|
20
19
|
+
|
|
21
20
|
```
|
|
22
21
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var schemas = require('../schemas/schemas.cjs.js');
|
|
5
|
+
var frontend = require('../schemas/frontend.cjs.js');
|
|
6
|
+
var rootLogger = require('../schemas/rootLogger.cjs.js');
|
|
7
|
+
var pluginManager = require('../manager/plugin-manager.cjs.js');
|
|
8
|
+
var pluginScanner = require('../scanner/plugin-scanner.cjs.js');
|
|
9
|
+
|
|
10
|
+
const dynamicPluginsFeatureLoaderWithOptions = (options) => backendPluginApi.createBackendFeatureLoader({
|
|
11
|
+
deps: {
|
|
12
|
+
config: backendPluginApi.coreServices.rootConfig
|
|
13
|
+
},
|
|
14
|
+
*loader({ config }) {
|
|
15
|
+
const dynamicPluginsEnabled = config.has(pluginScanner.configKey);
|
|
16
|
+
yield* [
|
|
17
|
+
schemas.dynamicPluginsSchemasServiceFactory(options),
|
|
18
|
+
pluginManager.dynamicPluginsServiceFactory(options)
|
|
19
|
+
];
|
|
20
|
+
if (dynamicPluginsEnabled) {
|
|
21
|
+
yield* [
|
|
22
|
+
rootLogger.dynamicPluginsRootLoggerServiceFactory(options),
|
|
23
|
+
frontend.dynamicPluginsFrontendSchemas,
|
|
24
|
+
pluginManager.dynamicPluginsFeatureDiscoveryLoader
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
const dynamicPluginsFeatureLoader = Object.assign(
|
|
30
|
+
dynamicPluginsFeatureLoaderWithOptions,
|
|
31
|
+
dynamicPluginsFeatureLoaderWithOptions()
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
exports.dynamicPluginsFeatureLoader = dynamicPluginsFeatureLoader;
|
|
35
|
+
//# sourceMappingURL=features.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.cjs.js","sources":["../../src/features/features.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 {\n coreServices,\n createBackendFeatureLoader,\n} from '@backstage/backend-plugin-api';\nimport {\n DynamicPluginsSchemasOptions,\n dynamicPluginsFrontendSchemas,\n dynamicPluginsRootLoggerServiceFactory,\n dynamicPluginsSchemasServiceFactory,\n} from '../schemas';\nimport {\n DynamicPluginsFactoryOptions,\n dynamicPluginsFeatureDiscoveryLoader,\n dynamicPluginsServiceFactory,\n} from '../manager';\nimport { DynamicPluginsRootLoggerFactoryOptions } from '../schemas';\nimport { configKey } from '../scanner/plugin-scanner';\n\n/**\n * @public\n */\nexport type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions &\n DynamicPluginsSchemasOptions &\n DynamicPluginsRootLoggerFactoryOptions;\n\nconst dynamicPluginsFeatureLoaderWithOptions = (\n options?: DynamicPluginsFeatureLoaderOptions,\n) =>\n createBackendFeatureLoader({\n deps: {\n config: coreServices.rootConfig,\n },\n *loader({ config }) {\n const dynamicPluginsEnabled = config.has(configKey);\n\n yield* [\n dynamicPluginsSchemasServiceFactory(options),\n dynamicPluginsServiceFactory(options),\n ];\n if (dynamicPluginsEnabled) {\n yield* [\n dynamicPluginsRootLoggerServiceFactory(options),\n dynamicPluginsFrontendSchemas,\n dynamicPluginsFeatureDiscoveryLoader,\n ];\n }\n },\n });\n\n/**\n * A backend feature loader that fully enable backend dynamic plugins.\n * More precisely it:\n * - adds the dynamic plugins root service (typically depended upon by plugins),\n * - adds additional required features to allow supporting dynamic plugins config schemas\n * in the frontend application and the backend root logger,\n * - uses the dynamic plugins service to discover and expose dynamic plugins as features.\n *\n * @public\n *\n * @example\n * Using the `dynamicPluginsFeatureLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureLoader);\n * //...\n * backend.start();\n * ```\n *\n * @example\n * Passing options to the `dynamicPluginsFeatureLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';\n * import { myCustomModuleLoader } from './myCustomModuleLoader';\n * import { myCustomSchemaLocator } from './myCustomSchemaLocator';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureLoader({\n * moduleLoader: myCustomModuleLoader,\n * schemaLocator: myCustomSchemaLocator,\n *\n * }));\n * //...\n * backend.start();\n * ```\n */\nexport const dynamicPluginsFeatureLoader = Object.assign(\n dynamicPluginsFeatureLoaderWithOptions,\n dynamicPluginsFeatureLoaderWithOptions(),\n);\n"],"names":["createBackendFeatureLoader","coreServices","configKey","dynamicPluginsSchemasServiceFactory","dynamicPluginsServiceFactory","dynamicPluginsRootLoggerServiceFactory","dynamicPluginsFrontendSchemas","dynamicPluginsFeatureDiscoveryLoader"],"mappings":";;;;;;;;;AAyCA,MAAM,sCAAA,GAAyC,CAC7C,OAAA,KAEAA,2CAA2B,CAAA;AAAA,EACzB,IAAM,EAAA;AAAA,IACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,GACvB;AAAA,EACA,CAAC,MAAA,CAAO,EAAE,MAAA,EAAU,EAAA;AAClB,IAAM,MAAA,qBAAA,GAAwB,MAAO,CAAA,GAAA,CAAIC,uBAAS,CAAA,CAAA;AAElD,IAAO,OAAA;AAAA,MACLC,4CAAoC,OAAO,CAAA;AAAA,MAC3CC,2CAA6B,OAAO,CAAA;AAAA,KACtC,CAAA;AACA,IAAA,IAAI,qBAAuB,EAAA;AACzB,MAAO,OAAA;AAAA,QACLC,kDAAuC,OAAO,CAAA;AAAA,QAC9CC,sCAAA;AAAA,QACAC,kDAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,GACF;AACF,CAAC,CAAA,CAAA;AA4CI,MAAM,8BAA8B,MAAO,CAAA,MAAA;AAAA,EAChD,sCAAA;AAAA,EACA,sCAAuC,EAAA;AACzC;;;;"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
var types = require('./manager/types.cjs.js');
|
|
4
4
|
var pluginManager = require('./manager/plugin-manager.cjs.js');
|
|
5
5
|
var schemas = require('./schemas/schemas.cjs.js');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var frontend = require('./schemas/frontend.cjs.js');
|
|
7
|
+
var rootLogger = require('./schemas/rootLogger.cjs.js');
|
|
8
|
+
var features = require('./features/features.cjs.js');
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
|
|
@@ -16,7 +17,7 @@ exports.dynamicPluginsServiceFactory = pluginManager.dynamicPluginsServiceFactor
|
|
|
16
17
|
exports.dynamicPluginsServiceFactoryWithOptions = pluginManager.dynamicPluginsServiceFactoryWithOptions;
|
|
17
18
|
exports.dynamicPluginsServiceRef = pluginManager.dynamicPluginsServiceRef;
|
|
18
19
|
exports.dynamicPluginsSchemasServiceFactory = schemas.dynamicPluginsSchemasServiceFactory;
|
|
19
|
-
exports.
|
|
20
|
-
exports.
|
|
21
|
-
exports.
|
|
20
|
+
exports.dynamicPluginsFrontendSchemas = frontend.dynamicPluginsFrontendSchemas;
|
|
21
|
+
exports.dynamicPluginsRootLoggerServiceFactory = rootLogger.dynamicPluginsRootLoggerServiceFactory;
|
|
22
|
+
exports.dynamicPluginsFeatureLoader = features.dynamicPluginsFeatureLoader;
|
|
22
23
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { EventsBackend } from '@backstage/plugin-events-backend';
|
|
|
15
15
|
import { PermissionPolicy } from '@backstage/plugin-permission-node';
|
|
16
16
|
import { FeatureDiscoveryService } from '@backstage/backend-plugin-api/alpha';
|
|
17
17
|
import { ConfigSchema } from '@backstage/config-loader';
|
|
18
|
+
import { WinstonLoggerOptions } from '@backstage/backend-defaults/rootLogger';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* @public
|
|
@@ -71,19 +72,26 @@ type LegacyPluginEnvironment = {
|
|
|
71
72
|
* @public
|
|
72
73
|
*/
|
|
73
74
|
interface DynamicPluginProvider extends FrontendPluginProvider, BackendPluginProvider {
|
|
74
|
-
plugins(
|
|
75
|
+
plugins(options?: {
|
|
76
|
+
includeFailed?: boolean;
|
|
77
|
+
}): DynamicPlugin[];
|
|
78
|
+
getScannedPackage(plugin: DynamicPlugin): ScannedPluginPackage;
|
|
75
79
|
}
|
|
76
80
|
/**
|
|
77
81
|
* @public
|
|
78
82
|
*/
|
|
79
83
|
interface BackendPluginProvider {
|
|
80
|
-
backendPlugins(
|
|
84
|
+
backendPlugins(options?: {
|
|
85
|
+
includeFailed?: boolean;
|
|
86
|
+
}): BackendDynamicPlugin[];
|
|
81
87
|
}
|
|
82
88
|
/**
|
|
83
89
|
* @public
|
|
84
90
|
*/
|
|
85
91
|
interface FrontendPluginProvider {
|
|
86
|
-
frontendPlugins(
|
|
92
|
+
frontendPlugins(options?: {
|
|
93
|
+
includeFailed?: boolean;
|
|
94
|
+
}): FrontendDynamicPlugin[];
|
|
87
95
|
}
|
|
88
96
|
/**
|
|
89
97
|
* @public
|
|
@@ -93,6 +101,7 @@ interface BaseDynamicPlugin {
|
|
|
93
101
|
version: string;
|
|
94
102
|
role: PackageRole;
|
|
95
103
|
platform: PackagePlatform;
|
|
104
|
+
failure?: string;
|
|
96
105
|
}
|
|
97
106
|
/**
|
|
98
107
|
* @public
|
|
@@ -109,7 +118,7 @@ interface FrontendDynamicPlugin extends BaseDynamicPlugin {
|
|
|
109
118
|
*/
|
|
110
119
|
interface BackendDynamicPlugin extends BaseDynamicPlugin {
|
|
111
120
|
platform: 'node';
|
|
112
|
-
installer
|
|
121
|
+
installer?: BackendDynamicPluginInstaller;
|
|
113
122
|
}
|
|
114
123
|
/**
|
|
115
124
|
* @public
|
|
@@ -166,7 +175,7 @@ interface DynamicPluginManagerOptions {
|
|
|
166
175
|
*/
|
|
167
176
|
declare class DynamicPluginManager implements DynamicPluginProvider {
|
|
168
177
|
private readonly logger;
|
|
169
|
-
private packages;
|
|
178
|
+
private readonly packages;
|
|
170
179
|
private readonly moduleLoader;
|
|
171
180
|
static create(options: DynamicPluginManagerOptions): Promise<DynamicPluginManager>;
|
|
172
181
|
private readonly _plugins;
|
|
@@ -176,71 +185,47 @@ declare class DynamicPluginManager implements DynamicPluginProvider {
|
|
|
176
185
|
addBackendPlugin(plugin: BackendDynamicPlugin): void;
|
|
177
186
|
private loadPlugins;
|
|
178
187
|
private loadBackendPlugin;
|
|
179
|
-
backendPlugins(
|
|
180
|
-
|
|
181
|
-
|
|
188
|
+
backendPlugins(options?: {
|
|
189
|
+
includeFailed?: boolean;
|
|
190
|
+
}): BackendDynamicPlugin[];
|
|
191
|
+
frontendPlugins(options?: {
|
|
192
|
+
includeFailed?: boolean;
|
|
193
|
+
}): FrontendDynamicPlugin[];
|
|
194
|
+
plugins(options?: {
|
|
195
|
+
includeFailed?: boolean;
|
|
196
|
+
}): DynamicPlugin[];
|
|
197
|
+
getScannedPackage(plugin: DynamicPlugin): ScannedPluginPackage;
|
|
182
198
|
}
|
|
183
199
|
/**
|
|
184
200
|
* @public
|
|
185
|
-
* @deprecated The `featureDiscoveryService` is deprecated in favor of using {@link dynamicPluginsFeatureDiscoveryLoader} instead.
|
|
186
201
|
*/
|
|
187
202
|
declare const dynamicPluginsServiceRef: _backstage_backend_plugin_api.ServiceRef<DynamicPluginProvider, "root", "singleton">;
|
|
188
203
|
/**
|
|
189
204
|
* @public
|
|
190
205
|
*/
|
|
191
206
|
interface DynamicPluginsFactoryOptions {
|
|
192
|
-
moduleLoader?(logger: LoggerService): ModuleLoader
|
|
207
|
+
moduleLoader?(logger: LoggerService): ModuleLoader | Promise<ModuleLoader>;
|
|
193
208
|
}
|
|
194
209
|
/**
|
|
195
210
|
* @public
|
|
196
|
-
* @deprecated Use {@link
|
|
211
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
197
212
|
*/
|
|
198
213
|
declare const dynamicPluginsServiceFactoryWithOptions: (options?: DynamicPluginsFactoryOptions) => _backstage_backend_plugin_api.ServiceFactory<DynamicPluginProvider, "root", "singleton">;
|
|
199
214
|
/**
|
|
200
215
|
* @public
|
|
201
|
-
* @deprecated Use {@link
|
|
216
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
202
217
|
*/
|
|
203
|
-
declare const dynamicPluginsServiceFactory: _backstage_backend_plugin_api.ServiceFactory<DynamicPluginProvider, "root", "singleton">;
|
|
218
|
+
declare const dynamicPluginsServiceFactory: ((options?: DynamicPluginsFactoryOptions) => _backstage_backend_plugin_api.ServiceFactory<DynamicPluginProvider, "root", "singleton">) & _backstage_backend_plugin_api.ServiceFactory<DynamicPluginProvider, "root", "singleton">;
|
|
204
219
|
/**
|
|
205
220
|
* @public
|
|
206
|
-
* @deprecated
|
|
221
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
207
222
|
*/
|
|
208
223
|
declare const dynamicPluginsFeatureDiscoveryServiceFactory: _backstage_backend_plugin_api.ServiceFactory<FeatureDiscoveryService, "root", "singleton">;
|
|
209
224
|
/**
|
|
210
|
-
* A backend feature loader that uses the dynamic plugins system to discover features.
|
|
211
|
-
*
|
|
212
225
|
* @public
|
|
213
|
-
*
|
|
214
|
-
* @example
|
|
215
|
-
* Using the `dynamicPluginsFeatureDiscoveryLoader` loader in a backend instance:
|
|
216
|
-
* ```ts
|
|
217
|
-
* //...
|
|
218
|
-
* import { createBackend } from '@backstage/backend-defaults';
|
|
219
|
-
* import { dynamicPluginsFeatureDiscoveryLoader } from '@backstage/backend-dynamic-feature-service';
|
|
220
|
-
*
|
|
221
|
-
* const backend = createBackend();
|
|
222
|
-
* backend.add(dynamicPluginsFeatureDiscoveryLoader);
|
|
223
|
-
* //...
|
|
224
|
-
* backend.start();
|
|
225
|
-
* ```
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* Passing options to the `dynamicPluginsFeatureDiscoveryLoader` loader in a backend instance:
|
|
229
|
-
* ```ts
|
|
230
|
-
* //...
|
|
231
|
-
* import { createBackend } from '@backstage/backend-defaults';
|
|
232
|
-
* import { dynamicPluginsFeatureDiscoveryLoader } from '@backstage/backend-dynamic-feature-service';
|
|
233
|
-
* import { myCustomModuleLoader } from './myCustomModuleLoader';
|
|
234
|
-
*
|
|
235
|
-
* const backend = createBackend();
|
|
236
|
-
* backend.add(dynamicPluginsFeatureDiscoveryLoader({
|
|
237
|
-
* moduleLoader: myCustomModuleLoader
|
|
238
|
-
* }));
|
|
239
|
-
* //...
|
|
240
|
-
* backend.start();
|
|
241
|
-
* ```
|
|
226
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
242
227
|
*/
|
|
243
|
-
declare const dynamicPluginsFeatureDiscoveryLoader:
|
|
228
|
+
declare const dynamicPluginsFeatureDiscoveryLoader: BackendFeature;
|
|
244
229
|
|
|
245
230
|
/**
|
|
246
231
|
*
|
|
@@ -268,17 +253,72 @@ interface DynamicPluginsSchemasOptions {
|
|
|
268
253
|
}
|
|
269
254
|
/**
|
|
270
255
|
* @public
|
|
256
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
271
257
|
*/
|
|
272
|
-
declare const
|
|
258
|
+
declare const dynamicPluginsSchemasServiceFactory: ((options?: DynamicPluginsSchemasOptions) => _backstage_backend_plugin_api.ServiceFactory<DynamicPluginsSchemasService, "root", "singleton">) & _backstage_backend_plugin_api.ServiceFactory<DynamicPluginsSchemasService, "root", "singleton">;
|
|
259
|
+
|
|
273
260
|
/**
|
|
274
261
|
* @public
|
|
262
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
275
263
|
*/
|
|
276
|
-
declare const dynamicPluginsSchemasServiceFactory: _backstage_backend_plugin_api.ServiceFactory<DynamicPluginsSchemasService, "root", "singleton">;
|
|
277
|
-
|
|
278
|
-
/** @public */
|
|
279
264
|
declare const dynamicPluginsFrontendSchemas: _backstage_backend_plugin_api.BackendFeature;
|
|
280
265
|
|
|
281
|
-
/**
|
|
282
|
-
|
|
266
|
+
/**
|
|
267
|
+
* @public
|
|
268
|
+
*/
|
|
269
|
+
type DynamicPluginsRootLoggerFactoryOptions = Omit<WinstonLoggerOptions, 'meta'>;
|
|
270
|
+
/**
|
|
271
|
+
* @public
|
|
272
|
+
* @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.
|
|
273
|
+
*/
|
|
274
|
+
declare const dynamicPluginsRootLoggerServiceFactory: ((options?: DynamicPluginsRootLoggerFactoryOptions) => _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.RootLoggerService, "root", "singleton">) & _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.RootLoggerService, "root", "singleton">;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @public
|
|
278
|
+
*/
|
|
279
|
+
type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions & DynamicPluginsSchemasOptions & DynamicPluginsRootLoggerFactoryOptions;
|
|
280
|
+
/**
|
|
281
|
+
* A backend feature loader that fully enable backend dynamic plugins.
|
|
282
|
+
* More precisely it:
|
|
283
|
+
* - adds the dynamic plugins root service (typically depended upon by plugins),
|
|
284
|
+
* - adds additional required features to allow supporting dynamic plugins config schemas
|
|
285
|
+
* in the frontend application and the backend root logger,
|
|
286
|
+
* - uses the dynamic plugins service to discover and expose dynamic plugins as features.
|
|
287
|
+
*
|
|
288
|
+
* @public
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* Using the `dynamicPluginsFeatureLoader` loader in a backend instance:
|
|
292
|
+
* ```ts
|
|
293
|
+
* //...
|
|
294
|
+
* import { createBackend } from '@backstage/backend-defaults';
|
|
295
|
+
* import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';
|
|
296
|
+
*
|
|
297
|
+
* const backend = createBackend();
|
|
298
|
+
* backend.add(dynamicPluginsFeatureLoader);
|
|
299
|
+
* //...
|
|
300
|
+
* backend.start();
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* Passing options to the `dynamicPluginsFeatureLoader` loader in a backend instance:
|
|
305
|
+
* ```ts
|
|
306
|
+
* //...
|
|
307
|
+
* import { createBackend } from '@backstage/backend-defaults';
|
|
308
|
+
* import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';
|
|
309
|
+
* import { myCustomModuleLoader } from './myCustomModuleLoader';
|
|
310
|
+
* import { myCustomSchemaLocator } from './myCustomSchemaLocator';
|
|
311
|
+
*
|
|
312
|
+
* const backend = createBackend();
|
|
313
|
+
* backend.add(dynamicPluginsFeatureLoader({
|
|
314
|
+
* moduleLoader: myCustomModuleLoader,
|
|
315
|
+
* schemaLocator: myCustomSchemaLocator,
|
|
316
|
+
*
|
|
317
|
+
* }));
|
|
318
|
+
* //...
|
|
319
|
+
* backend.start();
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
declare const dynamicPluginsFeatureLoader: ((options?: DynamicPluginsFeatureLoaderOptions) => _backstage_backend_plugin_api.BackendFeature) & _backstage_backend_plugin_api.BackendFeature;
|
|
283
323
|
|
|
284
|
-
export { type BackendDynamicPlugin, type BackendDynamicPluginInstaller, type BackendPluginProvider, type BaseDynamicPlugin, type DynamicPlugin, DynamicPluginManager, type DynamicPluginManagerOptions, type DynamicPluginProvider, type DynamicPluginsFactoryOptions, type DynamicPluginsSchemasOptions, type DynamicPluginsSchemasService, type FrontendDynamicPlugin, type FrontendPluginProvider, type LegacyBackendPluginInstaller, type LegacyPluginEnvironment, type ModuleLoader, type NewBackendPluginInstaller, type ScannedPluginManifest, type ScannedPluginPackage, dynamicPluginsFeatureDiscoveryLoader, dynamicPluginsFeatureDiscoveryServiceFactory, dynamicPluginsFrontendSchemas, dynamicPluginsRootLoggerServiceFactory, dynamicPluginsSchemasServiceFactory,
|
|
324
|
+
export { type BackendDynamicPlugin, type BackendDynamicPluginInstaller, type BackendPluginProvider, type BaseDynamicPlugin, type DynamicPlugin, DynamicPluginManager, type DynamicPluginManagerOptions, type DynamicPluginProvider, type DynamicPluginsFactoryOptions, type DynamicPluginsFeatureLoaderOptions, type DynamicPluginsRootLoggerFactoryOptions, type DynamicPluginsSchemasOptions, type DynamicPluginsSchemasService, type FrontendDynamicPlugin, type FrontendPluginProvider, type LegacyBackendPluginInstaller, type LegacyPluginEnvironment, type ModuleLoader, type NewBackendPluginInstaller, type ScannedPluginManifest, type ScannedPluginPackage, dynamicPluginsFeatureDiscoveryLoader, dynamicPluginsFeatureDiscoveryServiceFactory, dynamicPluginsFeatureLoader, dynamicPluginsFrontendSchemas, dynamicPluginsRootLoggerServiceFactory, dynamicPluginsSchemasServiceFactory, dynamicPluginsServiceFactory, dynamicPluginsServiceFactoryWithOptions, dynamicPluginsServiceRef, isBackendDynamicPluginInstaller };
|
|
@@ -9,15 +9,16 @@ var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
|
9
9
|
class CommonJSModuleLoader {
|
|
10
10
|
constructor(logger) {
|
|
11
11
|
this.logger = logger;
|
|
12
|
+
this.module = require("node:module");
|
|
12
13
|
}
|
|
14
|
+
module;
|
|
13
15
|
async bootstrap(backstageRoot, dynamicPluginsPaths) {
|
|
14
16
|
const backstageRootNodeModulesPath = `${backstageRoot}/node_modules`;
|
|
15
17
|
const dynamicNodeModulesPaths = [
|
|
16
18
|
...dynamicPluginsPaths.map((p) => path__default.default.resolve(p, "node_modules"))
|
|
17
19
|
];
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
Module._nodeModulePaths = (from) => {
|
|
20
|
+
const oldNodeModulePaths = this.module._nodeModulePaths;
|
|
21
|
+
this.module._nodeModulePaths = (from) => {
|
|
21
22
|
const result = oldNodeModulePaths(from);
|
|
22
23
|
if (!dynamicPluginsPaths.some((p) => from.startsWith(p))) {
|
|
23
24
|
return result;
|
|
@@ -32,10 +33,7 @@ class CommonJSModuleLoader {
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
async load(packagePath) {
|
|
35
|
-
return await require(
|
|
36
|
-
/* webpackIgnore: true */
|
|
37
|
-
packagePath
|
|
38
|
-
);
|
|
36
|
+
return await this.module.prototype.require(packagePath);
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
|
|
@@ -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';\n\nexport class CommonJSModuleLoader implements ModuleLoader {\n constructor(public readonly logger: LoggerService) {}\n\n async bootstrap(\n backstageRoot: string,\n dynamicPluginsPaths: string[],\n ): Promise<void> {\n const backstageRootNodeModulesPath = `${backstageRoot}/node_modules`;\n const dynamicNodeModulesPaths = [\n ...dynamicPluginsPaths.map(p => path.resolve(p, 'node_modules')),\n ];\n const
|
|
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';\n\nexport class CommonJSModuleLoader implements ModuleLoader {\n private module: any;\n\n constructor(public readonly logger: LoggerService) {\n this.module = require('node:module');\n }\n\n async bootstrap(\n backstageRoot: string,\n dynamicPluginsPaths: string[],\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.logger.debug(\n `Overriding node_modules search path for dynamic plugin ${from} to: ${filtered}`,\n );\n return filtered;\n };\n }\n\n async load(packagePath: string): Promise<any> {\n return await this.module.prototype.require(packagePath);\n }\n}\n"],"names":["path"],"mappings":";;;;;;;;AAmBO,MAAM,oBAA6C,CAAA;AAAA,EAGxD,YAA4B,MAAuB,EAAA;AAAvB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAC1B,IAAK,IAAA,CAAA,MAAA,GAAS,QAAQ,aAAa,CAAA,CAAA;AAAA,GACrC;AAAA,EAJQ,MAAA,CAAA;AAAA,EAMR,MAAM,SACJ,CAAA,aAAA,EACA,mBACe,EAAA;AACf,IAAM,MAAA,4BAAA,GAA+B,GAAG,aAAa,CAAA,aAAA,CAAA,CAAA;AACrD,IAAA,MAAM,uBAA0B,GAAA;AAAA,MAC9B,GAAG,oBAAoB,GAAI,CAAA,CAAA,CAAA,KAAKA,sBAAK,OAAQ,CAAA,CAAA,EAAG,cAAc,CAAC,CAAA;AAAA,KACjE,CAAA;AACA,IAAM,MAAA,kBAAA,GAAqB,KAAK,MAAO,CAAA,gBAAA,CAAA;AACvC,IAAK,IAAA,CAAA,MAAA,CAAO,gBAAmB,GAAA,CAAC,IAA2B,KAAA;AACzD,MAAM,MAAA,MAAA,GAAmB,mBAAmB,IAAI,CAAA,CAAA;AAChD,MAAI,IAAA,CAAC,oBAAoB,IAAK,CAAA,CAAA,CAAA,KAAK,KAAK,UAAW,CAAA,CAAC,CAAC,CAAG,EAAA;AACtD,QAAO,OAAA,MAAA,CAAA;AAAA,OACT;AACA,MAAM,MAAA,QAAA,GAAW,MAAO,CAAA,MAAA,CAAO,CAAkB,cAAA,KAAA;AAC/C,QACE,OAAA,cAAA,KAAmB,gCACnB,uBAAwB,CAAA,IAAA,CAAK,OAAK,cAAe,CAAA,UAAA,CAAW,CAAC,CAAC,CAAA,CAAA;AAAA,OAEjE,CAAA,CAAA;AACD,MAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,QACV,CAAA,uDAAA,EAA0D,IAAI,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAA;AAAA,OAChF,CAAA;AACA,MAAO,OAAA,QAAA,CAAA;AAAA,KACT,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,KAAK,WAAmC,EAAA;AAC5C,IAAA,OAAO,MAAM,IAAA,CAAK,MAAO,CAAA,SAAA,CAAU,QAAQ,WAAW,CAAA,CAAA;AAAA,GACxD;AACF;;;;"}
|
|
@@ -68,7 +68,7 @@ class DynamicPluginManager {
|
|
|
68
68
|
)
|
|
69
69
|
)
|
|
70
70
|
);
|
|
71
|
-
moduleLoader.bootstrap(backstageRoot, dynamicPluginsPaths);
|
|
71
|
+
await moduleLoader.bootstrap(backstageRoot, dynamicPluginsPaths);
|
|
72
72
|
scanner.subscribeToRootDirectoryChange(async () => {
|
|
73
73
|
manager._availablePackages = (await scanner.scanRoot()).packages;
|
|
74
74
|
});
|
|
@@ -86,22 +86,32 @@ class DynamicPluginManager {
|
|
|
86
86
|
async loadPlugins() {
|
|
87
87
|
const loadedPlugins = [];
|
|
88
88
|
for (const scannedPlugin of this.packages) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
).
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
89
|
+
const role = scannedPlugin.manifest.backstage.role;
|
|
90
|
+
const platform = cliNode.PackageRoles.getRoleInfo(role).platform;
|
|
91
|
+
const isPlugin = role.endsWith("-plugin") || role.endsWith("-plugin-module") || role === "frontend-dynamic-container";
|
|
92
|
+
if (!isPlugin) {
|
|
93
|
+
this.logger.info(
|
|
94
|
+
`skipping dynamic plugin package '${scannedPlugin.manifest.name}' from '${scannedPlugin.location}': incompatible role '${role}'`
|
|
95
|
+
);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
switch (platform) {
|
|
99
|
+
case "node":
|
|
100
|
+
loadedPlugins.push(await this.loadBackendPlugin(scannedPlugin));
|
|
101
|
+
break;
|
|
102
|
+
case "web":
|
|
103
|
+
loadedPlugins.push({
|
|
104
|
+
name: scannedPlugin.manifest.name,
|
|
105
|
+
version: scannedPlugin.manifest.version,
|
|
106
|
+
role: scannedPlugin.manifest.backstage.role,
|
|
107
|
+
platform: "web"
|
|
108
|
+
// TODO(davidfestal): add required front-end plugin information here.
|
|
109
|
+
});
|
|
110
|
+
break;
|
|
111
|
+
default:
|
|
112
|
+
this.logger.info(
|
|
113
|
+
`skipping dynamic plugin package '${scannedPlugin.manifest.name}' from '${scannedPlugin.location}': unrelated platform '${platform}'`
|
|
114
|
+
);
|
|
105
115
|
}
|
|
106
116
|
}
|
|
107
117
|
return loadedPlugins;
|
|
@@ -110,58 +120,71 @@ class DynamicPluginManager {
|
|
|
110
120
|
const packagePath = url__namespace.fileURLToPath(
|
|
111
121
|
`${plugin.location}/${plugin.manifest.main}`
|
|
112
122
|
);
|
|
123
|
+
const dynamicPlugin = {
|
|
124
|
+
name: plugin.manifest.name,
|
|
125
|
+
version: plugin.manifest.version,
|
|
126
|
+
platform: "node",
|
|
127
|
+
role: plugin.manifest.backstage.role
|
|
128
|
+
};
|
|
113
129
|
try {
|
|
114
130
|
const pluginModule = await this.moduleLoader.load(packagePath);
|
|
115
|
-
let dynamicPluginInstaller;
|
|
116
131
|
if (isBackendFeature(pluginModule.default)) {
|
|
117
|
-
|
|
132
|
+
dynamicPlugin.installer = {
|
|
118
133
|
kind: "new",
|
|
119
134
|
install: () => pluginModule.default
|
|
120
135
|
};
|
|
121
136
|
} else if (isBackendFeatureFactory(pluginModule.default)) {
|
|
122
|
-
|
|
137
|
+
dynamicPlugin.installer = {
|
|
123
138
|
kind: "new",
|
|
124
139
|
install: pluginModule.default
|
|
125
140
|
};
|
|
126
|
-
} else {
|
|
127
|
-
|
|
141
|
+
} else if (types.isBackendDynamicPluginInstaller(pluginModule.dynamicPluginInstaller)) {
|
|
142
|
+
dynamicPlugin.installer = pluginModule.dynamicPluginInstaller;
|
|
128
143
|
}
|
|
129
|
-
if (
|
|
144
|
+
if (dynamicPlugin.installer) {
|
|
145
|
+
this.logger.info(
|
|
146
|
+
`loaded dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`
|
|
147
|
+
);
|
|
148
|
+
} else {
|
|
149
|
+
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.`;
|
|
130
150
|
this.logger.error(
|
|
131
|
-
`dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}':
|
|
151
|
+
`dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': ${dynamicPlugin.failure}`
|
|
132
152
|
);
|
|
133
|
-
return void 0;
|
|
134
153
|
}
|
|
135
|
-
|
|
136
|
-
`loaded dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`
|
|
137
|
-
);
|
|
138
|
-
return {
|
|
139
|
-
name: plugin.manifest.name,
|
|
140
|
-
version: plugin.manifest.version,
|
|
141
|
-
platform: "node",
|
|
142
|
-
role: plugin.manifest.backstage.role,
|
|
143
|
-
installer: dynamicPluginInstaller
|
|
144
|
-
};
|
|
154
|
+
return dynamicPlugin;
|
|
145
155
|
} catch (error) {
|
|
156
|
+
const typedError = typeof error === "object" && "message" in error && "name" in error ? error : new Error(error);
|
|
157
|
+
dynamicPlugin.failure = `${typedError.name}: ${typedError.message}`;
|
|
146
158
|
this.logger.error(
|
|
147
159
|
`an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`,
|
|
148
|
-
|
|
160
|
+
typedError
|
|
149
161
|
);
|
|
150
|
-
return
|
|
162
|
+
return dynamicPlugin;
|
|
151
163
|
}
|
|
152
164
|
}
|
|
153
|
-
backendPlugins() {
|
|
154
|
-
return this.
|
|
165
|
+
backendPlugins(options) {
|
|
166
|
+
return this.plugins(options).filter(
|
|
155
167
|
(p) => p.platform === "node"
|
|
156
168
|
);
|
|
157
169
|
}
|
|
158
|
-
frontendPlugins() {
|
|
159
|
-
return this.
|
|
170
|
+
frontendPlugins(options) {
|
|
171
|
+
return this.plugins(options).filter(
|
|
160
172
|
(p) => p.platform === "web"
|
|
161
173
|
);
|
|
162
174
|
}
|
|
163
|
-
plugins() {
|
|
164
|
-
return this._plugins;
|
|
175
|
+
plugins(options) {
|
|
176
|
+
return this._plugins.filter((p) => options?.includeFailed || !p.failure);
|
|
177
|
+
}
|
|
178
|
+
getScannedPackage(plugin) {
|
|
179
|
+
const pkg = this.packages.find(
|
|
180
|
+
(p) => p.manifest.name === plugin.name && p.manifest.version === plugin.version
|
|
181
|
+
);
|
|
182
|
+
if (pkg === void 0) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`The scanned package of a dynamic plugin should always be available: ${plugin.name}/${plugin.version}`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
return pkg;
|
|
165
188
|
}
|
|
166
189
|
}
|
|
167
190
|
const dynamicPluginsServiceRef = backendPluginApi.createServiceRef(
|
|
@@ -181,11 +204,14 @@ const dynamicPluginsServiceFactoryWithOptions = (options) => backendPluginApi.cr
|
|
|
181
204
|
config,
|
|
182
205
|
logger,
|
|
183
206
|
preferAlpha: true,
|
|
184
|
-
moduleLoader: options?.moduleLoader?.(logger)
|
|
207
|
+
moduleLoader: await options?.moduleLoader?.(logger)
|
|
185
208
|
});
|
|
186
209
|
}
|
|
187
210
|
});
|
|
188
|
-
const dynamicPluginsServiceFactory =
|
|
211
|
+
const dynamicPluginsServiceFactory = Object.assign(
|
|
212
|
+
dynamicPluginsServiceFactoryWithOptions,
|
|
213
|
+
dynamicPluginsServiceFactoryWithOptions()
|
|
214
|
+
);
|
|
189
215
|
class DynamicPluginsEnabledFeatureDiscoveryService {
|
|
190
216
|
constructor(dynamicPlugins, featureDiscoveryService) {
|
|
191
217
|
this.dynamicPlugins = dynamicPlugins;
|
|
@@ -196,7 +222,7 @@ class DynamicPluginsEnabledFeatureDiscoveryService {
|
|
|
196
222
|
return {
|
|
197
223
|
features: [
|
|
198
224
|
...this.dynamicPlugins.backendPlugins().flatMap((plugin) => {
|
|
199
|
-
if (plugin.installer
|
|
225
|
+
if (plugin.installer?.kind === "new") {
|
|
200
226
|
const installed = plugin.installer.install();
|
|
201
227
|
if (Array.isArray(installed)) {
|
|
202
228
|
return installed;
|
|
@@ -220,27 +246,18 @@ const dynamicPluginsFeatureDiscoveryServiceFactory = backendPluginApi.createServ
|
|
|
220
246
|
return new DynamicPluginsEnabledFeatureDiscoveryService(dynamicPlugins);
|
|
221
247
|
}
|
|
222
248
|
});
|
|
223
|
-
const
|
|
249
|
+
const dynamicPluginsFeatureDiscoveryLoader = backendPluginApi.createBackendFeatureLoader({
|
|
224
250
|
deps: {
|
|
225
|
-
|
|
226
|
-
logger: backendPluginApi.coreServices.rootLogger
|
|
251
|
+
dynamicPlugins: dynamicPluginsServiceRef
|
|
227
252
|
},
|
|
228
|
-
async loader({
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
preferAlpha: true,
|
|
233
|
-
moduleLoader: options?.moduleLoader?.(logger)
|
|
234
|
-
});
|
|
235
|
-
const service = new DynamicPluginsEnabledFeatureDiscoveryService(manager);
|
|
253
|
+
async loader({ dynamicPlugins }) {
|
|
254
|
+
const service = new DynamicPluginsEnabledFeatureDiscoveryService(
|
|
255
|
+
dynamicPlugins
|
|
256
|
+
);
|
|
236
257
|
const { features } = await service.getBackendFeatures();
|
|
237
258
|
return features;
|
|
238
259
|
}
|
|
239
260
|
});
|
|
240
|
-
const dynamicPluginsFeatureDiscoveryLoader = Object.assign(
|
|
241
|
-
dynamicPluginsFeatureDiscoveryLoaderWithOptions,
|
|
242
|
-
dynamicPluginsFeatureDiscoveryLoaderWithOptions()
|
|
243
|
-
);
|
|
244
261
|
function isBackendFeature(value) {
|
|
245
262
|
return !!value && (typeof value === "object" || typeof value === "function") && value.$$type === "@backstage/BackendFeature";
|
|
246
263
|
}
|
|
@@ -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 { 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 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 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 platform = PackageRoles.getRoleInfo(\n scannedPlugin.manifest.backstage.role,\n ).platform;\n\n if (\n platform === 'node' &&\n scannedPlugin.manifest.backstage.role.includes('-plugin')\n ) {\n const plugin = await this.loadBackendPlugin(scannedPlugin);\n if (plugin !== undefined) {\n loadedPlugins.push(plugin);\n }\n } else {\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 }\n }\n return loadedPlugins;\n }\n\n private async loadBackendPlugin(\n plugin: ScannedPluginPackage,\n ): Promise<BackendDynamicPlugin | undefined> {\n const packagePath = url.fileURLToPath(\n `${plugin.location}/${plugin.manifest.main}`,\n );\n try {\n const pluginModule = await this.moduleLoader.load(packagePath);\n\n let dynamicPluginInstaller;\n if (isBackendFeature(pluginModule.default)) {\n dynamicPluginInstaller = {\n kind: 'new',\n install: () => pluginModule.default,\n };\n } else if (isBackendFeatureFactory(pluginModule.default)) {\n dynamicPluginInstaller = {\n kind: 'new',\n install: pluginModule.default,\n };\n } else {\n dynamicPluginInstaller = pluginModule.dynamicPluginInstaller;\n }\n if (!isBackendDynamicPluginInstaller(dynamicPluginInstaller)) {\n this.logger.error(\n `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`,\n );\n return undefined;\n }\n this.logger.info(\n `loaded dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`,\n );\n return {\n name: plugin.manifest.name,\n version: plugin.manifest.version,\n platform: 'node',\n role: plugin.manifest.backstage.role,\n installer: dynamicPluginInstaller,\n };\n } catch (error) {\n this.logger.error(\n `an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`,\n error,\n );\n return undefined;\n }\n }\n\n backendPlugins(): BackendDynamicPlugin[] {\n return this._plugins.filter(\n (p): p is BackendDynamicPlugin => p.platform === 'node',\n );\n }\n\n frontendPlugins(): FrontendDynamicPlugin[] {\n return this._plugins.filter(\n (p): p is FrontendDynamicPlugin => p.platform === 'web',\n );\n }\n\n plugins(): DynamicPlugin[] {\n return this._plugins;\n }\n}\n\n/**\n * @public\n * @deprecated The `featureDiscoveryService` is deprecated in favor of using {@link dynamicPluginsFeatureDiscoveryLoader} instead.\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;\n}\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureDiscoveryLoader} instead.\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: options?.moduleLoader?.(logger),\n });\n },\n });\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureDiscoveryLoader} instead.\n */\nexport const dynamicPluginsServiceFactory =\n dynamicPluginsServiceFactoryWithOptions();\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 The `featureDiscoveryService` is deprecated in favor of using {@link dynamicPluginsFeatureDiscoveryLoader} instead.\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\nconst dynamicPluginsFeatureDiscoveryLoaderWithOptions = (\n options?: DynamicPluginsFactoryOptions,\n) =>\n createBackendFeatureLoader({\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.rootLogger,\n },\n async loader({ config, logger }) {\n const manager = await DynamicPluginManager.create({\n config,\n logger,\n preferAlpha: true,\n moduleLoader: options?.moduleLoader?.(logger),\n });\n const service = new DynamicPluginsEnabledFeatureDiscoveryService(manager);\n const { features } = await service.getBackendFeatures();\n return features;\n },\n });\n\n/**\n * A backend feature loader that uses the dynamic plugins system to discover features.\n *\n * @public\n *\n * @example\n * Using the `dynamicPluginsFeatureDiscoveryLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureDiscoveryLoader } from '@backstage/backend-dynamic-feature-service';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureDiscoveryLoader);\n * //...\n * backend.start();\n * ```\n *\n * @example\n * Passing options to the `dynamicPluginsFeatureDiscoveryLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureDiscoveryLoader } from '@backstage/backend-dynamic-feature-service';\n * import { myCustomModuleLoader } from './myCustomModuleLoader';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureDiscoveryLoader({\n * moduleLoader: myCustomModuleLoader\n * }));\n * //...\n * backend.start();\n * ```\n */\nexport const dynamicPluginsFeatureDiscoveryLoader = Object.assign(\n dynamicPluginsFeatureDiscoveryLoaderWithOptions,\n dynamicPluginsFeatureDiscoveryLoaderWithOptions(),\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 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs.js","sources":["../../src/manager/types.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from 'winston';\nimport { Config } from '@backstage/config';\nimport {\n PluginCacheManager,\n PluginDatabaseManager,\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport { Router } from 'express';\nimport { IdentityApi } from '@backstage/plugin-auth-node';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n EventBroker,\n EventsService,\n HttpPostIngressOptions,\n} from '@backstage/plugin-events-node';\n\nimport {\n BackendFeature,\n UrlReaderService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport { PackagePlatform, PackageRole } from '@backstage/cli-node';\nimport { CatalogBuilder } from '@backstage/plugin-catalog-backend';\nimport { TemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { IndexBuilder } from '@backstage/plugin-search-backend-node';\nimport { EventsBackend } from '@backstage/plugin-events-backend';\nimport { PermissionPolicy } from '@backstage/plugin-permission-node';\n\n/**\n * @public\n *\n * @deprecated\n *\n * Support for the legacy backend system will be removed in the future.\n *\n * When adding a legacy plugin installer entrypoint in your plugin,\n * you should always take the opportunity to also implement support\n * for the new backend system if not already done.\n *\n */\nexport type LegacyPluginEnvironment = {\n logger: Logger;\n cache: PluginCacheManager;\n database: PluginDatabaseManager;\n config: Config;\n reader: UrlReaderService;\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n permissions: PermissionEvaluator;\n scheduler: SchedulerService;\n identity: IdentityApi;\n eventBroker: EventBroker;\n events: EventsService;\n pluginProvider: BackendPluginProvider;\n};\n\n/**\n * @public\n */\nexport interface DynamicPluginProvider\n extends FrontendPluginProvider,\n BackendPluginProvider {\n plugins(): DynamicPlugin[];\n}\n\n/**\n * @public\n */\nexport interface BackendPluginProvider {\n backendPlugins(): BackendDynamicPlugin[];\n}\n\n/**\n * @public\n */\nexport interface FrontendPluginProvider {\n frontendPlugins(): FrontendDynamicPlugin[];\n}\n\n/**\n * @public\n */\nexport interface BaseDynamicPlugin {\n name: string;\n version: string;\n role: PackageRole;\n platform: PackagePlatform;\n}\n\n/**\n * @public\n */\nexport type DynamicPlugin = FrontendDynamicPlugin | BackendDynamicPlugin;\n\n/**\n * @public\n */\nexport interface FrontendDynamicPlugin extends BaseDynamicPlugin {\n platform: 'web';\n}\n\n/**\n * @public\n */\nexport interface BackendDynamicPlugin extends BaseDynamicPlugin {\n platform: 'node';\n installer
|
|
1
|
+
{"version":3,"file":"types.cjs.js","sources":["../../src/manager/types.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from 'winston';\nimport { Config } from '@backstage/config';\nimport {\n PluginCacheManager,\n PluginDatabaseManager,\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport { Router } from 'express';\nimport { IdentityApi } from '@backstage/plugin-auth-node';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n EventBroker,\n EventsService,\n HttpPostIngressOptions,\n} from '@backstage/plugin-events-node';\n\nimport {\n BackendFeature,\n UrlReaderService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport { PackagePlatform, PackageRole } from '@backstage/cli-node';\nimport { CatalogBuilder } from '@backstage/plugin-catalog-backend';\nimport { TemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { IndexBuilder } from '@backstage/plugin-search-backend-node';\nimport { EventsBackend } from '@backstage/plugin-events-backend';\nimport { PermissionPolicy } from '@backstage/plugin-permission-node';\nimport { ScannedPluginPackage } from '../scanner';\n\n/**\n * @public\n *\n * @deprecated\n *\n * Support for the legacy backend system will be removed in the future.\n *\n * When adding a legacy plugin installer entrypoint in your plugin,\n * you should always take the opportunity to also implement support\n * for the new backend system if not already done.\n *\n */\nexport type LegacyPluginEnvironment = {\n logger: Logger;\n cache: PluginCacheManager;\n database: PluginDatabaseManager;\n config: Config;\n reader: UrlReaderService;\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n permissions: PermissionEvaluator;\n scheduler: SchedulerService;\n identity: IdentityApi;\n eventBroker: EventBroker;\n events: EventsService;\n pluginProvider: BackendPluginProvider;\n};\n\n/**\n * @public\n */\nexport interface DynamicPluginProvider\n extends FrontendPluginProvider,\n BackendPluginProvider {\n plugins(options?: { includeFailed?: boolean }): DynamicPlugin[];\n getScannedPackage(plugin: DynamicPlugin): ScannedPluginPackage;\n}\n\n/**\n * @public\n */\nexport interface BackendPluginProvider {\n backendPlugins(options?: { includeFailed?: boolean }): BackendDynamicPlugin[];\n}\n\n/**\n * @public\n */\nexport interface FrontendPluginProvider {\n frontendPlugins(options?: {\n includeFailed?: boolean;\n }): FrontendDynamicPlugin[];\n}\n\n/**\n * @public\n */\nexport interface BaseDynamicPlugin {\n name: string;\n version: string;\n role: PackageRole;\n platform: PackagePlatform;\n failure?: string;\n}\n\n/**\n * @public\n */\nexport type DynamicPlugin = FrontendDynamicPlugin | BackendDynamicPlugin;\n\n/**\n * @public\n */\nexport interface FrontendDynamicPlugin extends BaseDynamicPlugin {\n platform: 'web';\n}\n\n/**\n * @public\n */\nexport interface BackendDynamicPlugin extends BaseDynamicPlugin {\n platform: 'node';\n installer?: BackendDynamicPluginInstaller;\n}\n\n/**\n * @public\n */\nexport type BackendDynamicPluginInstaller =\n | LegacyBackendPluginInstaller\n | NewBackendPluginInstaller;\n\n/**\n * @public\n */\nexport interface NewBackendPluginInstaller {\n kind: 'new';\n\n install(): BackendFeature | BackendFeature[];\n}\n\n/**\n * @public\n * @deprecated\n *\n * Support for the legacy backend system will be removed in the future.\n *\n * When adding a legacy plugin installer entrypoint in your plugin,\n * you should always take the opportunity to also implement support\n * for the new backend system if not already done.\n *\n */\nexport interface LegacyBackendPluginInstaller {\n kind: 'legacy';\n\n router?: {\n pluginID: string;\n createPlugin(env: LegacyPluginEnvironment): Promise<Router>;\n };\n\n catalog?(builder: CatalogBuilder, env: LegacyPluginEnvironment): void;\n scaffolder?(env: LegacyPluginEnvironment): TemplateAction<any>[];\n search?(\n indexBuilder: IndexBuilder,\n schedule: SchedulerServiceTaskRunner,\n env: LegacyPluginEnvironment,\n ): void;\n events?(\n eventsBackend: EventsBackend,\n env: LegacyPluginEnvironment,\n ): HttpPostIngressOptions[];\n permissions?: {\n policy?: PermissionPolicy;\n };\n}\n\n/**\n * @public\n */\nexport function isBackendDynamicPluginInstaller(\n obj: any,\n): obj is BackendDynamicPluginInstaller {\n return (\n obj !== undefined &&\n 'kind' in obj &&\n (obj.kind === 'new' || obj.kind === 'legacy')\n );\n}\n"],"names":[],"mappings":";;AA0LO,SAAS,gCACd,GACsC,EAAA;AACtC,EACE,OAAA,GAAA,KAAQ,UACR,MAAU,IAAA,GAAA,KACT,IAAI,IAAS,KAAA,KAAA,IAAS,IAAI,IAAS,KAAA,QAAA,CAAA,CAAA;AAExC;;;;"}
|
|
@@ -34,6 +34,7 @@ var path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
|
34
34
|
var url__namespace = /*#__PURE__*/_interopNamespaceCompat(url);
|
|
35
35
|
var debounce__default = /*#__PURE__*/_interopDefaultCompat(debounce);
|
|
36
36
|
|
|
37
|
+
const configKey = "dynamicPlugins";
|
|
37
38
|
class PluginScanner {
|
|
38
39
|
constructor(config, logger, backstageRoot, preferAlpha) {
|
|
39
40
|
this.config = config;
|
|
@@ -62,27 +63,27 @@ class PluginScanner {
|
|
|
62
63
|
return this._rootDirectory;
|
|
63
64
|
}
|
|
64
65
|
applyConfig() {
|
|
65
|
-
const dynamicPlugins = this.config.getOptional(
|
|
66
|
+
const dynamicPlugins = this.config.getOptional(configKey);
|
|
66
67
|
if (!dynamicPlugins) {
|
|
67
|
-
this.logger.info(
|
|
68
|
+
this.logger.info(`'${configKey}' config entry not found.`);
|
|
68
69
|
this._rootDirectory = void 0;
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
72
|
if (typeof dynamicPlugins !== "object") {
|
|
72
|
-
this.logger.warn(
|
|
73
|
+
this.logger.warn(`'${configKey}' config entry should be an object.`);
|
|
73
74
|
this._rootDirectory = void 0;
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
76
77
|
if (!("rootDirectory" in dynamicPlugins)) {
|
|
77
78
|
this.logger.warn(
|
|
78
|
-
|
|
79
|
+
`'${configKey}' config entry does not contain the 'rootDirectory' field.`
|
|
79
80
|
);
|
|
80
81
|
this._rootDirectory = void 0;
|
|
81
82
|
return;
|
|
82
83
|
}
|
|
83
84
|
if (typeof dynamicPlugins.rootDirectory !== "string") {
|
|
84
85
|
this.logger.warn(
|
|
85
|
-
|
|
86
|
+
`'${configKey}.rootDirectory' config entry should be a string.`
|
|
86
87
|
);
|
|
87
88
|
this._rootDirectory = void 0;
|
|
88
89
|
return;
|
|
@@ -278,4 +279,5 @@ Please add '${backstageNodeModules}' to the 'NODE_PATH' when running the backsta
|
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
exports.PluginScanner = PluginScanner;
|
|
282
|
+
exports.configKey = configKey;
|
|
281
283
|
//# sourceMappingURL=plugin-scanner.cjs.js.map
|
|
@@ -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 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('dynamicPlugins');\n if (!dynamicPlugins) {\n this.logger.info(\"'dynamicPlugins' config entry not found.\");\n this._rootDirectory = undefined;\n return;\n }\n if (typeof dynamicPlugins !== 'object') {\n this.logger.warn(\"'dynamicPlugins' config entry should be an object.\");\n this._rootDirectory = undefined;\n return;\n }\n if (!('rootDirectory' in dynamicPlugins)) {\n this.logger.warn(\n \"'dynamicPlugins' 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 \"'dynamicPlugins.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 { 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCO,MAAM,SAAY,GAAA,iBAAA;AAElB,MAAM,aAAc,CAAA;AAAA,EAMjB,WACW,CAAA,MAAA,EACA,MACA,EAAA,aAAA,EACA,WACjB,EAAA;AAJiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AAAA,GAChB;AAAA,EAVK,cAAA,CAAA;AAAA,EACA,iBAAA,CAAA;AAAA,EACA,oBAAA,CAAA;AAAA,EACA,cAA8B,EAAC,CAAA;AAAA,EASvC,OAAO,OAAO,OAAqD,EAAA;AACjE,IAAA,MAAM,UAAU,IAAI,aAAA;AAAA,MAClB,OAAQ,CAAA,MAAA;AAAA,MACR,OAAQ,CAAA,MAAA;AAAA,MACR,OAAQ,CAAA,aAAA;AAAA,MACR,QAAQ,WAAe,IAAA,KAAA;AAAA,KACzB,CAAA;AACA,IAAA,OAAA,CAAQ,WAAY,EAAA,CAAA;AACpB,IAAO,OAAA,OAAA,CAAA;AAAA,GACT;AAAA,EAEA,+BAA+B,UAAwB,EAAA;AACrD,IAAK,IAAA,CAAA,WAAA,CAAY,KAAK,UAAU,CAAA,CAAA;AAAA,GAClC;AAAA,EAEA,IAAI,aAAoC,GAAA;AACtC,IAAA,OAAO,IAAK,CAAA,cAAA,CAAA;AAAA,GACd;AAAA,EAEQ,WAA4B,GAAA;AAClC,IAAA,MAAM,cAAiB,GAAA,IAAA,CAAK,MAAO,CAAA,WAAA,CAAY,SAAS,CAAA,CAAA;AACxD,IAAA,IAAI,CAAC,cAAgB,EAAA;AACnB,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAI,CAAA,EAAA,SAAS,CAA2B,yBAAA,CAAA,CAAA,CAAA;AACzD,MAAA,IAAA,CAAK,cAAiB,GAAA,KAAA,CAAA,CAAA;AACtB,MAAA,OAAA;AAAA,KACF;AACA,IAAI,IAAA,OAAO,mBAAmB,QAAU,EAAA;AACtC,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAI,CAAA,EAAA,SAAS,CAAqC,mCAAA,CAAA,CAAA,CAAA;AACnE,MAAA,IAAA,CAAK,cAAiB,GAAA,KAAA,CAAA,CAAA;AACtB,MAAA,OAAA;AAAA,KACF;AACA,IAAI,IAAA,EAAE,mBAAmB,cAAiB,CAAA,EAAA;AACxC,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,QACV,IAAI,SAAS,CAAA,0DAAA,CAAA;AAAA,OACf,CAAA;AACA,MAAA,IAAA,CAAK,cAAiB,GAAA,KAAA,CAAA,CAAA;AACtB,MAAA,OAAA;AAAA,KACF;AACA,IAAI,IAAA,OAAO,cAAe,CAAA,aAAA,KAAkB,QAAU,EAAA;AACpD,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,QACV,IAAI,SAAS,CAAA,gDAAA,CAAA;AAAA,OACf,CAAA;AACA,MAAA,IAAA,CAAK,cAAiB,GAAA,KAAA,CAAA,CAAA;AACtB,MAAA,OAAA;AAAA,KACF;AAEA,IAAA,MAAM,yBAAyBA,eAAK,CAAA,UAAA,CAAW,cAAe,CAAA,aAAa,IACvEA,eAAK,CAAA,OAAA,CAAQ,cAAe,CAAA,aAAa,IACzCA,eAAK,CAAA,OAAA,CAAQ,IAAK,CAAA,aAAA,EAAe,eAAe,aAAa,CAAA,CAAA;AAEjE,IACE,IAAA,CAACA,eACE,CAAA,OAAA,CAAQ,sBAAsB,CAAA,CAC9B,UAAW,CAAAA,eAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,aAAa,CAAC,CAC9C,EAAA;AACA,MAAM,MAAA,QAAA,GAAW,QAAQ,GAAI,CAAA,SAAA,CAAA;AAC7B,MAAA,MAAM,uBAAuBA,eAAK,CAAA,OAAA;AAAA,QAChC,IAAK,CAAA,aAAA;AAAA,QACL,cAAA;AAAA,OACF,CAAA;AACA,MACE,IAAA,CAAC,QACD,IAAA,CAAC,QAAS,CAAA,KAAA,CAAMA,gBAAK,SAAS,CAAA,CAAE,QAAS,CAAA,oBAAoB,CAC7D,EAAA;AACA,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,uBAAA,EAA0B,sBAAsB,CAAA,sCAAA,EAAyC,oBAAoB,CAAA;AAAA,YAAA,EAC5F,oBAAoB,CAAA,wDAAA,CAAA;AAAA,SACvC,CAAA;AAAA,OACF;AAAA,KACF;AACA,IAAA,IAAI,CAACC,YAAA,CAAU,sBAAsB,CAAA,CAAE,aAAe,EAAA;AACpD,MAAM,MAAA,IAAI,MAAM,iBAAiB,CAAA,CAAA;AAAA,KACnC;AAEA,IAAA,IAAA,CAAK,cAAiB,GAAA,sBAAA,CAAA;AAAA,GACxB;AAAA,EAEA,MAAM,QAAsC,GAAA;AAC1C,IAAI,IAAA,CAAC,KAAK,cAAgB,EAAA;AACxB,MAAO,OAAA,EAAE,QAAU,EAAA,EAAG,EAAA,CAAA;AAAA,KACxB;AAEA,IAAA,MAAM,yBAAyB,IAAK,CAAA,cAAA,CAAA;AACpC,IAAA,MAAM,iBAAyC,EAAC,CAAA;AAChD,IAAA,KAAA,MAAW,MAAU,IAAA,MAAMC,aAAG,CAAA,OAAA,CAAQ,sBAAwB,EAAA;AAAA,MAC5D,aAAe,EAAA,IAAA;AAAA,KAChB,CAAG,EAAA;AACF,MAAA,MAAM,SAAY,GAAA,MAAA,CAAA;AAElB,MAAI,IAAA,SAAA,CAAU,SAAS,YAAc,EAAA;AACnC,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,CAAa,UAAA,EAAA,SAAA,CAAU,IAAI,CAAoB,kBAAA,CAAA,CAAA,CAAA;AACjE,QAAA,SAAA;AAAA,OACF;AACA,MAAA,MAAM,aAAaF,eAAK,CAAA,SAAA;AAAA,QACtBA,eAAK,CAAA,OAAA,CAAQ,sBAAwB,EAAA,SAAA,CAAU,IAAI,CAAA;AAAA,OACrD,CAAA;AACA,MAAI,IAAA,MAAA,CAAO,gBAAkB,EAAA;AAC3B,QAAI,IAAA,CAAA,CAAE,MAAME,aAAA,CAAG,KAAM,CAAA,MAAMA,aAAG,CAAA,QAAA,CAAS,UAAU,CAAC,CAAG,EAAA,WAAA,EAAe,EAAA;AAClE,UAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,YACV,aAAa,UAAU,CAAA,6BAAA,CAAA;AAAA,WACzB,CAAA;AACA,UAAA,SAAA;AAAA,SACF;AAAA,OACS,MAAA,IAAA,CAAC,MAAO,CAAA,WAAA,EAAe,EAAA;AAChC,QAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,UACV,aAAa,UAAU,CAAA,6BAAA,CAAA;AAAA,SACzB,CAAA;AACA,QAAA,SAAA;AAAA,OACF;AAEA,MAAI,IAAA,aAAA,CAAA;AACJ,MAAI,IAAA,QAAA,CAAA;AACJ,MAAI,IAAA;AACF,QAAgB,aAAA,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAC7C,QAAI,IAAA,CAAC,aAAc,CAAA,QAAA,CAAS,IAAM,EAAA;AAChC,UAAM,MAAA,IAAI,MAAM,0CAA0C,CAAA,CAAA;AAAA,SAC5D;AACA,QAAI,IAAA,aAAA,CAAc,QAAS,CAAA,SAAA,EAAW,IAAM,EAAA;AAC1C,UAAA,QAAA,GAAWC,oBAAa,CAAA,WAAA;AAAA,YACtB,aAAA,CAAc,SAAS,SAAU,CAAA,IAAA;AAAA,WACjC,CAAA,QAAA,CAAA;AAAA,SACG,MAAA;AACL,UAAM,MAAA,IAAI,MAAM,oDAAoD,CAAA,CAAA;AAAA,SACtE;AAAA,eACO,CAAG,EAAA;AACV,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,UACV,gDAAgD,UAAU,CAAA,CAAA,CAAA;AAAA,UAC1D,CAAA;AAAA,SACF,CAAA;AACA,QAAA,SAAA;AAAA,OACF;AAEA,MAAA,IAAI,aAAa,MAAQ,EAAA;AACvB,QAAA,IAAI,KAAK,WAAa,EAAA;AACpB,UAAA,MAAM,eAAkB,GAAAH,eAAA,CAAK,OAAQ,CAAA,UAAA,EAAY,OAAO,CAAA,CAAA;AACxD,UAAI,IAAAI,aAAA,CAAW,eAAe,CAAG,EAAA;AAC/B,YAAA,IAAA,CAAK,MAAMF,aAAG,CAAA,KAAA,CAAM,eAAe,CAAA,EAAG,aAAe,EAAA;AACnD,cAAM,MAAA,SAAA,GAAY,cAAc,QAAS,CAAA,SAAA,CAAA;AACzC,cAAI,IAAA;AACF,gBAAgB,aAAA,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,eAAe,CAAA,CAAA;AAAA,uBAC3C,CAAG,EAAA;AACV,gBAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,kBACV,gDAAgD,eAAe,CAAA,CAAA,CAAA;AAAA,kBAC/D,CAAA;AAAA,iBACF,CAAA;AACA,gBAAA,SAAA;AAAA,eACF;AACA,cAAA,aAAA,CAAc,SAAS,SAAY,GAAA,SAAA,CAAA;AAAA,aAC9B,MAAA;AACL,cAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,gBACV,aAAa,eAAe,CAAA,6BAAA,CAAA;AAAA,eAC9B,CAAA;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAEA,MAAA,cAAA,CAAe,KAAK,aAAa,CAAA,CAAA;AAAA,KACnC;AACA,IAAO,OAAA,EAAE,UAAU,cAAe,EAAA,CAAA;AAAA,GACpC;AAAA,EAEA,MAAc,QAAQ,UAAmD,EAAA;AACvE,IAAA,MAAM,YAAe,GAAAF,eAAA,CAAK,OAAQ,CAAA,UAAA,EAAY,cAAc,CAAA,CAAA;AAC5D,IAAA,MAAM,OAAU,GAAA,MAAME,aAAG,CAAA,QAAA,CAAS,YAAY,CAAA,CAAA;AAC9C,IAAA,MAAM,QAAkC,GAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AACrE,IAAO,OAAA;AAAA,MACL,QAAA,EAAUG,cAAI,CAAA,aAAA,CAAc,UAAU,CAAA;AAAA,MACtC,QAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,YAA8B,GAAA;AAClC,IAAA,MAAM,4BAA4B,YAA2B;AAC3D,MAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAW,KAAA;AACtC,QAAI,IAAA,CAAC,KAAK,cAAgB,EAAA;AACxB,UAAQ,OAAA,EAAA,CAAA;AACR,UAAA,OAAA;AAAA,SACF;AACA,QAAM,MAAA,eAAA,GAAkBC,0BAAS,MAAM;AACrC,UAAA,IAAA,CAAK,WAAY,CAAA,OAAA,CAAQ,CAAK,CAAA,KAAA,CAAA,EAAG,CAAA,CAAA;AAAA,WAChC,GAAG,CAAA,CAAA;AACN,QAAA,IAAI,KAAQ,GAAA,KAAA,CAAA;AACZ,QAAA,IAAA,CAAK,oBAAuB,GAAAC,mBAAA,CACzB,KAAM,CAAA,IAAA,CAAK,cAAgB,EAAA;AAAA,UAC1B,aAAe,EAAA,IAAA;AAAA,UACf,cAAgB,EAAA,IAAA;AAAA,UAChB,KAAO,EAAA,CAAA;AAAA,UACP,eAAiB,EAAA,IAAA;AAAA,SAClB,CACA,CAAA,EAAA;AAAA,UACC,KAAA;AAAA,UACA,CACE,KACA,EAAA,SAAA,EACA,CACS,KAAA;AACT,YAAA,IACG,CAAC,QAAA,EAAU,WAAW,CAAA,CAAE,SAAS,KAAK,CAAA,IACrCP,eAAK,CAAA,OAAA,CAAQ,SAAS,CAAM,KAAA,IAAA,CAAK,cAClC,IAAA,CAAC,OAAO,QAAU,EAAA,QAAQ,CAAE,CAAA,QAAA,CAAS,KAAK,CAAA,IACzCA,eAAK,CAAA,OAAA,CAAQA,gBAAK,OAAQ,CAAA,SAAS,CAAC,CAAA,KAClC,KAAK,cACP,IAAAA,eAAA,CAAK,QAAS,CAAA,SAAS,MAAM,cAC/B,EAAA;AACA,cAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,gBACV,CAAA,uBAAA,EAA0B,KAAK,CAAA,GAAA,EAAM,SAAS,CAAA,yBAAA,CAAA;AAAA,eAChD,CAAA;AACA,cAAgB,eAAA,EAAA,CAAA;AAAA,aACX,MAAA;AACL,cAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,gBACV,CAAA,uBAAA,EAA0B,KAAK,CAAA,GAAA,EAAM,SAAS,CAAA,gCAAA,CAAA;AAAA,eAChD,CAAA;AAAA,aACF;AAAA,WACF;AAAA,SAED,CAAA,EAAA,CAAG,OAAS,EAAA,CAAC,KAAiB,KAAA;AAC7B,UAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,YACV,CAAA,sBAAA,EAAyB,KAAK,aAAa,CAAA,CAAA,CAAA;AAAA,YAC3C,KAAA;AAAA,WACF,CAAA;AACA,UAAA,IAAI,CAAC,KAAO,EAAA;AACV,YAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AAAA,WACd;AAAA,SACD,CAAA,CACA,EAAG,CAAA,OAAA,EAAS,MAAM;AACjB,UAAQ,KAAA,GAAA,IAAA,CAAA;AACR,UAAQ,OAAA,EAAA,CAAA;AAAA,SACT,CAAA,CAAA;AAAA,OACJ,CAAA,CAAA;AAAA,KACH,CAAA;AAEA,IAAA,MAAM,yBAA0B,EAAA,CAAA;AAChC,IAAI,IAAA,IAAA,CAAK,OAAO,SAAW,EAAA;AACzB,MAAA,MAAM,EAAE,WAAY,EAAA,GAAI,IAAK,CAAA,MAAA,CAAO,UAAU,YAA2B;AACvE,QAAA,MAAM,mBAAmB,IAAK,CAAA,cAAA,CAAA;AAC9B,QAAI,IAAA;AACF,UAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,iBACV,CAAG,EAAA;AACV,UAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,YACV,gDAAA;AAAA,YACA,CAAA;AAAA,WACF,CAAA;AAAA,SACF;AACA,QAAI,IAAA,gBAAA,KAAqB,KAAK,cAAgB,EAAA;AAC5C,UAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,YACV,CAAyC,sCAAA,EAAA,gBAAgB,CAAS,MAAA,EAAA,IAAA,CAAK,cAAc,CAAA,CAAA,CAAA;AAAA,WACvF,CAAA;AACA,UAAA,IAAA,CAAK,WAAY,CAAA,OAAA,CAAQ,CAAK,CAAA,KAAA,CAAA,EAAG,CAAA,CAAA;AACjC,UAAA,IAAI,KAAK,oBAAsB,EAAA;AAC7B,YAAM,MAAA,IAAA,CAAK,qBAAqB,KAAM,EAAA,CAAA;AAAA,WACxC;AACA,UAAA,MAAM,yBAA0B,EAAA,CAAA;AAAA,SAClC;AAAA,OACD,CAAA,CAAA;AACD,MAAA,IAAA,CAAK,iBAAoB,GAAA,WAAA,CAAA;AAAA,KAC3B;AAAA,GACF;AAAA,EAEA,MAAM,cAAiB,GAAA;AACrB,IAAA,IAAI,KAAK,oBAAsB,EAAA;AAC7B,MAAA,IAAA,CAAK,qBAAqB,KAAM,EAAA,CAAA;AAAA,KAClC;AACA,IAAA,IAAI,KAAK,iBAAmB,EAAA;AAC1B,MAAA,IAAA,CAAK,iBAAkB,EAAA,CAAA;AAAA,KACzB;AAAA,GACF;AAAA,EAEA,UAAa,GAAA;AACX,IAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AAAA,GACtB;AACF;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontend.cjs.js","sources":["../../src/schemas/frontend.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 {\n coreServices,\n createBackendModule,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { dynamicPluginsSchemasServiceRef } from './schemas';\nimport {\n configSchemaExtensionPoint,\n loadCompiledConfigSchema,\n} from '@backstage/plugin-app-node';\n\n/**\n * @public\n * @deprecated Use {@link dynamicPluginsFeatureLoader} instead, which gathers all services and features required for dynamic plugins.\n */\nexport const dynamicPluginsFrontendSchemas = createBackendModule({\n pluginId: 'app',\n moduleId: 'core.dynamicplugins.frontendSchemas',\n register(reg) {\n reg.registerInit({\n deps: {\n config: coreServices.rootConfig,\n schemas: dynamicPluginsSchemasServiceRef,\n configSchemaExtension: configSchemaExtensionPoint,\n },\n async init({ config, schemas, configSchemaExtension }) {\n const appPackageName =\n config.getOptionalString('app.packageName') ?? 'app';\n const appDistDir = resolvePackagePath(appPackageName, 'dist');\n const compiledConfigSchema = await loadCompiledConfigSchema(appDistDir);\n // TODO(davidfestal): Add dynamic pliugin config schemas even if the compiled schemas are empty.\n if (compiledConfigSchema) {\n configSchemaExtension.setConfigSchema(\n (await schemas.addDynamicPluginsSchemas(compiledConfigSchema))\n .schema,\n );\n }\n },\n });\n },\n});\n"],"names":["createBackendModule","coreServices","dynamicPluginsSchemasServiceRef","configSchemaExtensionPoint","resolvePackagePath","loadCompiledConfigSchema"],"mappings":";;;;;;AA+BO,MAAM,gCAAgCA,oCAAoB,CAAA;AAAA,EAC/D,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,qCAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,OAAS,EAAAC,uCAAA;AAAA,QACT,qBAAuB,EAAAC,wCAAA;AAAA,OACzB;AAAA,MACA,MAAM,IAAK,CAAA,EAAE,MAAQ,EAAA,OAAA,EAAS,uBAAyB,EAAA;AACrD,QAAA,MAAM,cACJ,GAAA,MAAA,CAAO,iBAAkB,CAAA,iBAAiB,CAAK,IAAA,KAAA,CAAA;AACjD,QAAM,MAAA,UAAA,GAAaC,mCAAmB,CAAA,cAAA,EAAgB,MAAM,CAAA,CAAA;AAC5D,QAAM,MAAA,oBAAA,GAAuB,MAAMC,sCAAA,CAAyB,UAAU,CAAA,CAAA;AAEtE,QAAA,IAAI,oBAAsB,EAAA;AACxB,UAAsB,qBAAA,CAAA,eAAA;AAAA,YAAA,CACnB,MAAM,OAAA,CAAQ,wBAAyB,CAAA,oBAAoB,CACzD,EAAA,MAAA;AAAA,WACL,CAAA;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var rootLogger = require('@backstage/backend-defaults/rootLogger');
|
|
5
|
+
var rootConfig = require('@backstage/backend-defaults/rootConfig');
|
|
5
6
|
var winston = require('winston');
|
|
6
|
-
var backendCommon = require('@backstage/backend-common');
|
|
7
7
|
var configLoader = require('@backstage/config-loader');
|
|
8
8
|
var getPackages = require('@manypkg/get-packages');
|
|
9
9
|
var schemas = require('./schemas.cjs.js');
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const dynamicPluginsRootLoggerServiceFactoryWithOptions = (options) => backendPluginApi.createServiceFactory({
|
|
12
12
|
service: backendPluginApi.coreServices.rootLogger,
|
|
13
13
|
deps: {
|
|
14
14
|
config: backendPluginApi.coreServices.rootConfig,
|
|
@@ -16,17 +16,18 @@ const dynamicPluginsRootLoggerServiceFactory = backendPluginApi.createServiceFac
|
|
|
16
16
|
},
|
|
17
17
|
async factory({ config, schemas }) {
|
|
18
18
|
const logger = rootLogger.WinstonLogger.create({
|
|
19
|
-
meta: {
|
|
20
|
-
service: "backstage"
|
|
21
|
-
},
|
|
22
19
|
level: process.env.LOG_LEVEL || "info",
|
|
23
20
|
format: process.env.NODE_ENV === "production" ? winston.format.json() : rootLogger.WinstonLogger.colorFormat(),
|
|
24
|
-
transports: [new winston.transports.Console()]
|
|
21
|
+
transports: [new winston.transports.Console()],
|
|
22
|
+
...options,
|
|
23
|
+
meta: {
|
|
24
|
+
service: "backstage"
|
|
25
|
+
}
|
|
25
26
|
});
|
|
26
27
|
const configSchema = await configLoader.loadConfigSchema({
|
|
27
28
|
dependencies: (await getPackages.getPackages(process.cwd())).packages.map((p) => p.packageJson.name)
|
|
28
29
|
});
|
|
29
|
-
const secretEnumerator = await
|
|
30
|
+
const secretEnumerator = await rootConfig.createConfigSecretEnumerator({
|
|
30
31
|
logger,
|
|
31
32
|
schema: (await schemas.addDynamicPluginsSchemas(configSchema)).schema
|
|
32
33
|
});
|
|
@@ -35,6 +36,10 @@ const dynamicPluginsRootLoggerServiceFactory = backendPluginApi.createServiceFac
|
|
|
35
36
|
return logger;
|
|
36
37
|
}
|
|
37
38
|
});
|
|
39
|
+
const dynamicPluginsRootLoggerServiceFactory = Object.assign(
|
|
40
|
+
dynamicPluginsRootLoggerServiceFactoryWithOptions,
|
|
41
|
+
dynamicPluginsRootLoggerServiceFactoryWithOptions()
|
|
42
|
+
);
|
|
38
43
|
|
|
39
44
|
exports.dynamicPluginsRootLoggerServiceFactory = dynamicPluginsRootLoggerServiceFactory;
|
|
40
|
-
//# sourceMappingURL=
|
|
45
|
+
//# sourceMappingURL=rootLogger.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rootLogger.cjs.js","sources":["../../src/schemas/rootLogger.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 {\n createServiceFactory,\n coreServices,\n} from '@backstage/backend-plugin-api';\nimport {\n WinstonLogger,\n WinstonLoggerOptions,\n} from '@backstage/backend-defaults/rootLogger';\nimport { createConfigSecretEnumerator } from '@backstage/backend-defaults/rootConfig';\nimport { transports, format } from 'winston';\nimport { loadConfigSchema } from '@backstage/config-loader';\nimport { getPackages } from '@manypkg/get-packages';\nimport { dynamicPluginsSchemasServiceRef } from './schemas';\n\n/**\n * @public\n */\nexport type DynamicPluginsRootLoggerFactoryOptions = Omit<\n WinstonLoggerOptions,\n 'meta'\n>;\n\nconst dynamicPluginsRootLoggerServiceFactoryWithOptions = (\n options?: DynamicPluginsRootLoggerFactoryOptions,\n) =>\n createServiceFactory({\n service: coreServices.rootLogger,\n deps: {\n config: coreServices.rootConfig,\n schemas: dynamicPluginsSchemasServiceRef,\n },\n async factory({ config, schemas }) {\n const logger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format:\n process.env.NODE_ENV === 'production'\n ? format.json()\n : WinstonLogger.colorFormat(),\n transports: [new transports.Console()],\n ...options,\n meta: {\n service: 'backstage',\n },\n });\n\n const configSchema = await loadConfigSchema({\n dependencies: (\n await getPackages(process.cwd())\n ).packages.map(p => p.packageJson.name),\n });\n\n const secretEnumerator = await createConfigSecretEnumerator({\n logger,\n schema: (await schemas.addDynamicPluginsSchemas(configSchema)).schema,\n });\n logger.addRedactions(secretEnumerator(config));\n config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));\n\n return logger;\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 dynamicPluginsRootLoggerServiceFactory = Object.assign(\n dynamicPluginsRootLoggerServiceFactoryWithOptions,\n dynamicPluginsRootLoggerServiceFactoryWithOptions(),\n);\n"],"names":["createServiceFactory","coreServices","dynamicPluginsSchemasServiceRef","WinstonLogger","format","transports","loadConfigSchema","getPackages","createConfigSecretEnumerator"],"mappings":";;;;;;;;;;AAsCA,MAAM,iDAAA,GAAoD,CACxD,OAAA,KAEAA,qCAAqB,CAAA;AAAA,EACnB,SAASC,6BAAa,CAAA,UAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,OAAS,EAAAC,uCAAA;AAAA,GACX;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,MAAA,EAAQ,SAAW,EAAA;AACjC,IAAM,MAAA,MAAA,GAASC,yBAAc,MAAO,CAAA;AAAA,MAClC,KAAA,EAAO,OAAQ,CAAA,GAAA,CAAI,SAAa,IAAA,MAAA;AAAA,MAChC,MAAA,EACE,QAAQ,GAAI,CAAA,QAAA,KAAa,eACrBC,cAAO,CAAA,IAAA,EACP,GAAAD,wBAAA,CAAc,WAAY,EAAA;AAAA,MAChC,UAAY,EAAA,CAAC,IAAIE,kBAAA,CAAW,SAAS,CAAA;AAAA,MACrC,GAAG,OAAA;AAAA,MACH,IAAM,EAAA;AAAA,QACJ,OAAS,EAAA,WAAA;AAAA,OACX;AAAA,KACD,CAAA,CAAA;AAED,IAAM,MAAA,YAAA,GAAe,MAAMC,6BAAiB,CAAA;AAAA,MAC1C,YACE,EAAA,CAAA,MAAMC,uBAAY,CAAA,OAAA,CAAQ,GAAI,EAAC,CAC/B,EAAA,QAAA,CAAS,GAAI,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,WAAA,CAAY,IAAI,CAAA;AAAA,KACvC,CAAA,CAAA;AAED,IAAM,MAAA,gBAAA,GAAmB,MAAMC,uCAA6B,CAAA;AAAA,MAC1D,MAAA;AAAA,MACA,MAAS,EAAA,CAAA,MAAM,OAAQ,CAAA,wBAAA,CAAyB,YAAY,CAAG,EAAA,MAAA;AAAA,KAChE,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,aAAA,CAAc,gBAAiB,CAAA,MAAM,CAAC,CAAA,CAAA;AAC7C,IAAA,MAAA,CAAO,YAAY,MAAM,MAAA,CAAO,cAAc,gBAAiB,CAAA,MAAM,CAAC,CAAC,CAAA,CAAA;AAEvE,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AACF,CAAC,CAAA,CAAA;AAMI,MAAM,yCAAyC,MAAO,CAAA,MAAA;AAAA,EAC3D,iDAAA;AAAA,EACA,iDAAkD,EAAA;AACpD;;;;"}
|
|
@@ -92,7 +92,10 @@ const dynamicPluginsSchemasServiceFactoryWithOptions = (options) => backendPlugi
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
|
-
const dynamicPluginsSchemasServiceFactory =
|
|
95
|
+
const dynamicPluginsSchemasServiceFactory = Object.assign(
|
|
96
|
+
dynamicPluginsSchemasServiceFactoryWithOptions,
|
|
97
|
+
dynamicPluginsSchemasServiceFactoryWithOptions()
|
|
98
|
+
);
|
|
96
99
|
async function gatherDynamicPluginsSchemas(packages, logger, schemaLocator = () => path__namespace.join("dist", "configSchema.json")) {
|
|
97
100
|
const allSchemas = {};
|
|
98
101
|
for (const pluginPackage of packages) {
|
|
@@ -126,6 +129,5 @@ async function gatherDynamicPluginsSchemas(packages, logger, schemaLocator = ()
|
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
exports.dynamicPluginsSchemasServiceFactory = dynamicPluginsSchemasServiceFactory;
|
|
129
|
-
exports.dynamicPluginsSchemasServiceFactoryWithOptions = dynamicPluginsSchemasServiceFactoryWithOptions;
|
|
130
132
|
exports.dynamicPluginsSchemasServiceRef = dynamicPluginsSchemasServiceRef;
|
|
131
133
|
//# sourceMappingURL=schemas.cjs.js.map
|
|
@@ -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';\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\
|
|
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 let pluginLocation = url.fileURLToPath(pluginPackage.location);\n if (path.basename(pluginLocation) === 'alpha') {\n pluginLocation = path.dirname(pluginLocation);\n }\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.3",
|
|
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": "1.0.1
|
|
45
|
+
"@backstage/backend-app-api": "^1.0.1",
|
|
46
46
|
"@backstage/backend-common": "^0.25.0",
|
|
47
|
-
"@backstage/backend-defaults": "0.5.
|
|
48
|
-
"@backstage/backend-plugin-api": "1.0.1
|
|
49
|
-
"@backstage/cli-common": "0.1.14",
|
|
50
|
-
"@backstage/cli-node": "0.2.9
|
|
51
|
-
"@backstage/config": "1.2.0",
|
|
52
|
-
"@backstage/config-loader": "1.9.1",
|
|
53
|
-
"@backstage/errors": "1.2.4",
|
|
54
|
-
"@backstage/plugin-app-node": "0.1.26
|
|
55
|
-
"@backstage/plugin-auth-node": "0.5.3
|
|
56
|
-
"@backstage/plugin-catalog-backend": "1.
|
|
57
|
-
"@backstage/plugin-events-backend": "0.3.
|
|
58
|
-
"@backstage/plugin-events-node": "0.4.
|
|
59
|
-
"@backstage/plugin-permission-common": "0.8.1",
|
|
60
|
-
"@backstage/plugin-permission-node": "0.8.4
|
|
61
|
-
"@backstage/plugin-scaffolder-node": "0.5.0
|
|
62
|
-
"@backstage/plugin-search-backend-node": "1.3.
|
|
63
|
-
"@backstage/plugin-search-common": "1.2.14",
|
|
64
|
-
"@backstage/types": "1.1.1",
|
|
47
|
+
"@backstage/backend-defaults": "^0.5.2",
|
|
48
|
+
"@backstage/backend-plugin-api": "^1.0.1",
|
|
49
|
+
"@backstage/cli-common": "^0.1.14",
|
|
50
|
+
"@backstage/cli-node": "^0.2.9",
|
|
51
|
+
"@backstage/config": "^1.2.0",
|
|
52
|
+
"@backstage/config-loader": "^1.9.1",
|
|
53
|
+
"@backstage/errors": "^1.2.4",
|
|
54
|
+
"@backstage/plugin-app-node": "^0.1.26",
|
|
55
|
+
"@backstage/plugin-auth-node": "^0.5.3",
|
|
56
|
+
"@backstage/plugin-catalog-backend": "^1.27.1",
|
|
57
|
+
"@backstage/plugin-events-backend": "^0.3.14",
|
|
58
|
+
"@backstage/plugin-events-node": "^0.4.2",
|
|
59
|
+
"@backstage/plugin-permission-common": "^0.8.1",
|
|
60
|
+
"@backstage/plugin-permission-node": "^0.8.4",
|
|
61
|
+
"@backstage/plugin-scaffolder-node": "^0.5.0",
|
|
62
|
+
"@backstage/plugin-search-backend-node": "^1.3.4",
|
|
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,8 +71,10 @@
|
|
|
71
71
|
"winston": "^3.2.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@backstage/backend-test-utils": "1.0.
|
|
75
|
-
"@backstage/cli": "0.28.0
|
|
74
|
+
"@backstage/backend-test-utils": "^1.0.2",
|
|
75
|
+
"@backstage/cli": "^0.28.0",
|
|
76
|
+
"@backstage/plugin-app-backend": "^0.3.76",
|
|
77
|
+
"triple-beam": "^1.4.1",
|
|
76
78
|
"wait-for-expect": "^3.0.2"
|
|
77
79
|
}
|
|
78
80
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"appBackendModule.cjs.js","sources":["../../src/schemas/appBackendModule.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 {\n coreServices,\n createBackendModule,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { dynamicPluginsSchemasServiceRef } from './schemas';\nimport {\n configSchemaExtensionPoint,\n loadCompiledConfigSchema,\n} from '@backstage/plugin-app-node';\n\n/** @public */\nexport const dynamicPluginsFrontendSchemas = createBackendModule({\n pluginId: 'app',\n moduleId: 'core.dynamicplugins.frontendSchemas',\n register(reg) {\n reg.registerInit({\n deps: {\n config: coreServices.rootConfig,\n schemas: dynamicPluginsSchemasServiceRef,\n configSchemaExtension: configSchemaExtensionPoint,\n },\n async init({ config, schemas, configSchemaExtension }) {\n const appPackageName =\n config.getOptionalString('app.packageName') ?? 'app';\n const appDistDir = resolvePackagePath(appPackageName, 'dist');\n const compiledConfigSchema = await loadCompiledConfigSchema(appDistDir);\n if (compiledConfigSchema) {\n configSchemaExtension.setConfigSchema(\n (await schemas.addDynamicPluginsSchemas(compiledConfigSchema))\n .schema,\n );\n }\n },\n });\n },\n});\n"],"names":["createBackendModule","coreServices","dynamicPluginsSchemasServiceRef","configSchemaExtensionPoint","resolvePackagePath","loadCompiledConfigSchema"],"mappings":";;;;;;AA4BO,MAAM,gCAAgCA,oCAAoB,CAAA;AAAA,EAC/D,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,qCAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,OAAS,EAAAC,uCAAA;AAAA,QACT,qBAAuB,EAAAC,wCAAA;AAAA,OACzB;AAAA,MACA,MAAM,IAAK,CAAA,EAAE,MAAQ,EAAA,OAAA,EAAS,uBAAyB,EAAA;AACrD,QAAA,MAAM,cACJ,GAAA,MAAA,CAAO,iBAAkB,CAAA,iBAAiB,CAAK,IAAA,KAAA,CAAA;AACjD,QAAM,MAAA,UAAA,GAAaC,mCAAmB,CAAA,cAAA,EAAgB,MAAM,CAAA,CAAA;AAC5D,QAAM,MAAA,oBAAA,GAAuB,MAAMC,sCAAA,CAAyB,UAAU,CAAA,CAAA;AACtE,QAAA,IAAI,oBAAsB,EAAA;AACxB,UAAsB,qBAAA,CAAA,eAAA;AAAA,YAAA,CACnB,MAAM,OAAA,CAAQ,wBAAyB,CAAA,oBAAoB,CACzD,EAAA,MAAA;AAAA,WACL,CAAA;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rootLoggerServiceFactory.cjs.js","sources":["../../src/schemas/rootLoggerServiceFactory.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 {\n createServiceFactory,\n coreServices,\n} from '@backstage/backend-plugin-api';\nimport { WinstonLogger } from '@backstage/backend-defaults/rootLogger';\nimport { transports, format } from 'winston';\nimport { createConfigSecretEnumerator } from '@backstage/backend-common';\nimport { loadConfigSchema } from '@backstage/config-loader';\nimport { getPackages } from '@manypkg/get-packages';\nimport { dynamicPluginsSchemasServiceRef } from './schemas';\n\n/** @public */\nexport const dynamicPluginsRootLoggerServiceFactory = createServiceFactory({\n service: coreServices.rootLogger,\n deps: {\n config: coreServices.rootConfig,\n schemas: dynamicPluginsSchemasServiceRef,\n },\n async factory({ config, schemas }) {\n const logger = WinstonLogger.create({\n meta: {\n service: 'backstage',\n },\n level: process.env.LOG_LEVEL || 'info',\n format:\n process.env.NODE_ENV === 'production'\n ? format.json()\n : WinstonLogger.colorFormat(),\n transports: [new transports.Console()],\n });\n\n const configSchema = await loadConfigSchema({\n dependencies: (\n await getPackages(process.cwd())\n ).packages.map(p => p.packageJson.name),\n });\n\n const secretEnumerator = await createConfigSecretEnumerator({\n logger,\n schema: (await schemas.addDynamicPluginsSchemas(configSchema)).schema,\n });\n logger.addRedactions(secretEnumerator(config));\n config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));\n\n return logger;\n },\n});\n"],"names":["createServiceFactory","coreServices","dynamicPluginsSchemasServiceRef","WinstonLogger","format","transports","loadConfigSchema","getPackages","createConfigSecretEnumerator"],"mappings":";;;;;;;;;;AA4BO,MAAM,yCAAyCA,qCAAqB,CAAA;AAAA,EACzE,SAASC,6BAAa,CAAA,UAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,OAAS,EAAAC,uCAAA;AAAA,GACX;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,MAAA,EAAQ,SAAW,EAAA;AACjC,IAAM,MAAA,MAAA,GAASC,yBAAc,MAAO,CAAA;AAAA,MAClC,IAAM,EAAA;AAAA,QACJ,OAAS,EAAA,WAAA;AAAA,OACX;AAAA,MACA,KAAA,EAAO,OAAQ,CAAA,GAAA,CAAI,SAAa,IAAA,MAAA;AAAA,MAChC,MAAA,EACE,QAAQ,GAAI,CAAA,QAAA,KAAa,eACrBC,cAAO,CAAA,IAAA,EACP,GAAAD,wBAAA,CAAc,WAAY,EAAA;AAAA,MAChC,UAAY,EAAA,CAAC,IAAIE,kBAAA,CAAW,SAAS,CAAA;AAAA,KACtC,CAAA,CAAA;AAED,IAAM,MAAA,YAAA,GAAe,MAAMC,6BAAiB,CAAA;AAAA,MAC1C,YACE,EAAA,CAAA,MAAMC,uBAAY,CAAA,OAAA,CAAQ,GAAI,EAAC,CAC/B,EAAA,QAAA,CAAS,GAAI,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,WAAA,CAAY,IAAI,CAAA;AAAA,KACvC,CAAA,CAAA;AAED,IAAM,MAAA,gBAAA,GAAmB,MAAMC,0CAA6B,CAAA;AAAA,MAC1D,MAAA;AAAA,MACA,MAAS,EAAA,CAAA,MAAM,OAAQ,CAAA,wBAAA,CAAyB,YAAY,CAAG,EAAA,MAAA;AAAA,KAChE,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,aAAA,CAAc,gBAAiB,CAAA,MAAM,CAAC,CAAA,CAAA;AAC7C,IAAA,MAAA,CAAO,YAAY,MAAM,MAAA,CAAO,cAAc,gBAAiB,CAAA,MAAM,CAAC,CAAC,CAAA,CAAA;AAEvE,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AACF,CAAC;;;;"}
|