@backstage/backend-dynamic-feature-service 0.4.2-next.1 → 0.4.2-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/index.cjs.js +19 -695
- package/dist/index.cjs.js.map +1 -1
- package/dist/loader/CommonJSModuleLoader.cjs.js +43 -0
- package/dist/loader/CommonJSModuleLoader.cjs.js.map +1 -0
- package/dist/manager/plugin-manager.cjs.js +257 -0
- package/dist/manager/plugin-manager.cjs.js.map +1 -0
- package/dist/manager/types.cjs.js +8 -0
- package/dist/manager/types.cjs.js.map +1 -0
- package/dist/scanner/plugin-scanner.cjs.js +281 -0
- package/dist/scanner/plugin-scanner.cjs.js.map +1 -0
- package/dist/schemas/appBackendModule.cjs.js +32 -0
- package/dist/schemas/appBackendModule.cjs.js.map +1 -0
- package/dist/schemas/rootLoggerServiceFactory.cjs.js +40 -0
- package/dist/schemas/rootLoggerServiceFactory.cjs.js.map +1 -0
- package/dist/schemas/schemas.cjs.js +131 -0
- package/dist/schemas/schemas.cjs.js.map +1 -0
- package/package.json +15 -15
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs$1 = require('fs/promises');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var chokidar = require('chokidar');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var url = require('url');
|
|
8
|
+
var debounce = require('lodash/debounce');
|
|
9
|
+
var cliNode = require('@backstage/cli-node');
|
|
10
|
+
|
|
11
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
function _interopNamespaceCompat(e) {
|
|
14
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
15
|
+
var n = Object.create(null);
|
|
16
|
+
if (e) {
|
|
17
|
+
Object.keys(e).forEach(function (k) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return e[k]; }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs$1);
|
|
32
|
+
var chokidar__namespace = /*#__PURE__*/_interopNamespaceCompat(chokidar);
|
|
33
|
+
var path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
34
|
+
var url__namespace = /*#__PURE__*/_interopNamespaceCompat(url);
|
|
35
|
+
var debounce__default = /*#__PURE__*/_interopDefaultCompat(debounce);
|
|
36
|
+
|
|
37
|
+
class PluginScanner {
|
|
38
|
+
constructor(config, logger, backstageRoot, preferAlpha) {
|
|
39
|
+
this.config = config;
|
|
40
|
+
this.logger = logger;
|
|
41
|
+
this.backstageRoot = backstageRoot;
|
|
42
|
+
this.preferAlpha = preferAlpha;
|
|
43
|
+
}
|
|
44
|
+
_rootDirectory;
|
|
45
|
+
configUnsubscribe;
|
|
46
|
+
rootDirectoryWatcher;
|
|
47
|
+
subscribers = [];
|
|
48
|
+
static create(options) {
|
|
49
|
+
const scanner = new PluginScanner(
|
|
50
|
+
options.config,
|
|
51
|
+
options.logger,
|
|
52
|
+
options.backstageRoot,
|
|
53
|
+
options.preferAlpha || false
|
|
54
|
+
);
|
|
55
|
+
scanner.applyConfig();
|
|
56
|
+
return scanner;
|
|
57
|
+
}
|
|
58
|
+
subscribeToRootDirectoryChange(subscriber) {
|
|
59
|
+
this.subscribers.push(subscriber);
|
|
60
|
+
}
|
|
61
|
+
get rootDirectory() {
|
|
62
|
+
return this._rootDirectory;
|
|
63
|
+
}
|
|
64
|
+
applyConfig() {
|
|
65
|
+
const dynamicPlugins = this.config.getOptional("dynamicPlugins");
|
|
66
|
+
if (!dynamicPlugins) {
|
|
67
|
+
this.logger.info("'dynamicPlugins' config entry not found.");
|
|
68
|
+
this._rootDirectory = void 0;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (typeof dynamicPlugins !== "object") {
|
|
72
|
+
this.logger.warn("'dynamicPlugins' config entry should be an object.");
|
|
73
|
+
this._rootDirectory = void 0;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!("rootDirectory" in dynamicPlugins)) {
|
|
77
|
+
this.logger.warn(
|
|
78
|
+
"'dynamicPlugins' config entry does not contain the 'rootDirectory' field."
|
|
79
|
+
);
|
|
80
|
+
this._rootDirectory = void 0;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (typeof dynamicPlugins.rootDirectory !== "string") {
|
|
84
|
+
this.logger.warn(
|
|
85
|
+
"'dynamicPlugins.rootDirectory' config entry should be a string."
|
|
86
|
+
);
|
|
87
|
+
this._rootDirectory = void 0;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const dynamicPluginsRootPath = path__namespace.isAbsolute(dynamicPlugins.rootDirectory) ? path__namespace.resolve(dynamicPlugins.rootDirectory) : path__namespace.resolve(this.backstageRoot, dynamicPlugins.rootDirectory);
|
|
91
|
+
if (!path__namespace.dirname(dynamicPluginsRootPath).startsWith(path__namespace.resolve(this.backstageRoot))) {
|
|
92
|
+
const nodePath = process.env.NODE_PATH;
|
|
93
|
+
const backstageNodeModules = path__namespace.resolve(
|
|
94
|
+
this.backstageRoot,
|
|
95
|
+
"node_modules"
|
|
96
|
+
);
|
|
97
|
+
if (!nodePath || !nodePath.split(path__namespace.delimiter).includes(backstageNodeModules)) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Dynamic plugins under '${dynamicPluginsRootPath}' cannot access backstage modules in '${backstageNodeModules}'.
|
|
100
|
+
Please add '${backstageNodeModules}' to the 'NODE_PATH' when running the backstage backend.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!fs.lstatSync(dynamicPluginsRootPath).isDirectory()) {
|
|
105
|
+
throw new Error("Not a directory");
|
|
106
|
+
}
|
|
107
|
+
this._rootDirectory = dynamicPluginsRootPath;
|
|
108
|
+
}
|
|
109
|
+
async scanRoot() {
|
|
110
|
+
if (!this._rootDirectory) {
|
|
111
|
+
return { packages: [] };
|
|
112
|
+
}
|
|
113
|
+
const dynamicPluginsLocation = this._rootDirectory;
|
|
114
|
+
const scannedPlugins = [];
|
|
115
|
+
for (const dirEnt of await fs__namespace.readdir(dynamicPluginsLocation, {
|
|
116
|
+
withFileTypes: true
|
|
117
|
+
})) {
|
|
118
|
+
const pluginDir = dirEnt;
|
|
119
|
+
if (pluginDir.name === "lost+found") {
|
|
120
|
+
this.logger.debug(`skipping '${pluginDir.name}' system directory`);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const pluginHome = path__namespace.normalize(
|
|
124
|
+
path__namespace.resolve(dynamicPluginsLocation, pluginDir.name)
|
|
125
|
+
);
|
|
126
|
+
if (dirEnt.isSymbolicLink()) {
|
|
127
|
+
if (!(await fs__namespace.lstat(await fs__namespace.readlink(pluginHome))).isDirectory()) {
|
|
128
|
+
this.logger.info(
|
|
129
|
+
`skipping '${pluginHome}' since it is not a directory`
|
|
130
|
+
);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
} else if (!dirEnt.isDirectory()) {
|
|
134
|
+
this.logger.info(
|
|
135
|
+
`skipping '${pluginHome}' since it is not a directory`
|
|
136
|
+
);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
let scannedPlugin;
|
|
140
|
+
let platform;
|
|
141
|
+
try {
|
|
142
|
+
scannedPlugin = await this.scanDir(pluginHome);
|
|
143
|
+
if (!scannedPlugin.manifest.main) {
|
|
144
|
+
throw new Error("field 'main' not found in 'package.json'");
|
|
145
|
+
}
|
|
146
|
+
if (scannedPlugin.manifest.backstage?.role) {
|
|
147
|
+
platform = cliNode.PackageRoles.getRoleInfo(
|
|
148
|
+
scannedPlugin.manifest.backstage.role
|
|
149
|
+
).platform;
|
|
150
|
+
} else {
|
|
151
|
+
throw new Error("field 'backstage.role' not found in 'package.json'");
|
|
152
|
+
}
|
|
153
|
+
} catch (e) {
|
|
154
|
+
this.logger.error(
|
|
155
|
+
`failed to load dynamic plugin manifest from '${pluginHome}'`,
|
|
156
|
+
e
|
|
157
|
+
);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (platform === "node") {
|
|
161
|
+
if (this.preferAlpha) {
|
|
162
|
+
const pluginHomeAlpha = path__namespace.resolve(pluginHome, "alpha");
|
|
163
|
+
if (fs.existsSync(pluginHomeAlpha)) {
|
|
164
|
+
if ((await fs__namespace.lstat(pluginHomeAlpha)).isDirectory()) {
|
|
165
|
+
const backstage = scannedPlugin.manifest.backstage;
|
|
166
|
+
try {
|
|
167
|
+
scannedPlugin = await this.scanDir(pluginHomeAlpha);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
this.logger.error(
|
|
170
|
+
`failed to load dynamic plugin manifest from '${pluginHomeAlpha}'`,
|
|
171
|
+
e
|
|
172
|
+
);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
scannedPlugin.manifest.backstage = backstage;
|
|
176
|
+
} else {
|
|
177
|
+
this.logger.warn(
|
|
178
|
+
`skipping '${pluginHomeAlpha}' since it is not a directory`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
scannedPlugins.push(scannedPlugin);
|
|
185
|
+
}
|
|
186
|
+
return { packages: scannedPlugins };
|
|
187
|
+
}
|
|
188
|
+
async scanDir(pluginHome) {
|
|
189
|
+
const manifestFile = path__namespace.resolve(pluginHome, "package.json");
|
|
190
|
+
const content = await fs__namespace.readFile(manifestFile);
|
|
191
|
+
const manifest = JSON.parse(content.toString());
|
|
192
|
+
return {
|
|
193
|
+
location: url__namespace.pathToFileURL(pluginHome),
|
|
194
|
+
manifest
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async trackChanges() {
|
|
198
|
+
const setupRootDirectoryWatcher = async () => {
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
if (!this._rootDirectory) {
|
|
201
|
+
resolve();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const callSubscribers = debounce__default.default(() => {
|
|
205
|
+
this.subscribers.forEach((s) => s());
|
|
206
|
+
}, 500);
|
|
207
|
+
let ready = false;
|
|
208
|
+
this.rootDirectoryWatcher = chokidar__namespace.watch(this._rootDirectory, {
|
|
209
|
+
ignoreInitial: true,
|
|
210
|
+
followSymlinks: true,
|
|
211
|
+
depth: 1,
|
|
212
|
+
disableGlobbing: true
|
|
213
|
+
}).on(
|
|
214
|
+
"all",
|
|
215
|
+
(event, eventPath, _) => {
|
|
216
|
+
if (["addDir", "unlinkDir"].includes(event) && path__namespace.dirname(eventPath) === this._rootDirectory || ["add", "unlink", "change"].includes(event) && path__namespace.dirname(path__namespace.dirname(eventPath)) === this._rootDirectory && path__namespace.basename(eventPath) === "package.json") {
|
|
217
|
+
this.logger.info(
|
|
218
|
+
`rootDirectory changed (${event} - ${eventPath}): scanning plugins again`
|
|
219
|
+
);
|
|
220
|
+
callSubscribers();
|
|
221
|
+
} else {
|
|
222
|
+
this.logger.debug(
|
|
223
|
+
`rootDirectory changed (${event} - ${eventPath}): no need to scan plugins again`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
).on("error", (error) => {
|
|
228
|
+
this.logger.error(
|
|
229
|
+
`error while watching '${this.rootDirectory}'`,
|
|
230
|
+
error
|
|
231
|
+
);
|
|
232
|
+
if (!ready) {
|
|
233
|
+
reject(error);
|
|
234
|
+
}
|
|
235
|
+
}).on("ready", () => {
|
|
236
|
+
ready = true;
|
|
237
|
+
resolve();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
await setupRootDirectoryWatcher();
|
|
242
|
+
if (this.config.subscribe) {
|
|
243
|
+
const { unsubscribe } = this.config.subscribe(async () => {
|
|
244
|
+
const oldRootDirectory = this._rootDirectory;
|
|
245
|
+
try {
|
|
246
|
+
this.applyConfig();
|
|
247
|
+
} catch (e) {
|
|
248
|
+
this.logger.error(
|
|
249
|
+
"failed to apply new config for dynamic plugins",
|
|
250
|
+
e
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (oldRootDirectory !== this._rootDirectory) {
|
|
254
|
+
this.logger.info(
|
|
255
|
+
`rootDirectory changed in Config from '${oldRootDirectory}' to '${this._rootDirectory}'`
|
|
256
|
+
);
|
|
257
|
+
this.subscribers.forEach((s) => s());
|
|
258
|
+
if (this.rootDirectoryWatcher) {
|
|
259
|
+
await this.rootDirectoryWatcher.close();
|
|
260
|
+
}
|
|
261
|
+
await setupRootDirectoryWatcher();
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
this.configUnsubscribe = unsubscribe;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async untrackChanges() {
|
|
268
|
+
if (this.rootDirectoryWatcher) {
|
|
269
|
+
this.rootDirectoryWatcher.close();
|
|
270
|
+
}
|
|
271
|
+
if (this.configUnsubscribe) {
|
|
272
|
+
this.configUnsubscribe();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
destructor() {
|
|
276
|
+
this.untrackChanges();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
exports.PluginScanner = PluginScanner;
|
|
281
|
+
//# sourceMappingURL=plugin-scanner.cjs.js.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCO,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,gBAAgB,CAAA,CAAA;AAC/D,IAAA,IAAI,CAAC,cAAgB,EAAA;AACnB,MAAK,IAAA,CAAA,MAAA,CAAO,KAAK,0CAA0C,CAAA,CAAA;AAC3D,MAAA,IAAA,CAAK,cAAiB,GAAA,KAAA,CAAA,CAAA;AACtB,MAAA,OAAA;AAAA,KACF;AACA,IAAI,IAAA,OAAO,mBAAmB,QAAU,EAAA;AACtC,MAAK,IAAA,CAAA,MAAA,CAAO,KAAK,oDAAoD,CAAA,CAAA;AACrE,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,2EAAA;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,iEAAA;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,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var schemas = require('./schemas.cjs.js');
|
|
5
|
+
var pluginAppNode = require('@backstage/plugin-app-node');
|
|
6
|
+
|
|
7
|
+
const dynamicPluginsFrontendSchemas = backendPluginApi.createBackendModule({
|
|
8
|
+
pluginId: "app",
|
|
9
|
+
moduleId: "core.dynamicplugins.frontendSchemas",
|
|
10
|
+
register(reg) {
|
|
11
|
+
reg.registerInit({
|
|
12
|
+
deps: {
|
|
13
|
+
config: backendPluginApi.coreServices.rootConfig,
|
|
14
|
+
schemas: schemas.dynamicPluginsSchemasServiceRef,
|
|
15
|
+
configSchemaExtension: pluginAppNode.configSchemaExtensionPoint
|
|
16
|
+
},
|
|
17
|
+
async init({ config, schemas, configSchemaExtension }) {
|
|
18
|
+
const appPackageName = config.getOptionalString("app.packageName") ?? "app";
|
|
19
|
+
const appDistDir = backendPluginApi.resolvePackagePath(appPackageName, "dist");
|
|
20
|
+
const compiledConfigSchema = await pluginAppNode.loadCompiledConfigSchema(appDistDir);
|
|
21
|
+
if (compiledConfigSchema) {
|
|
22
|
+
configSchemaExtension.setConfigSchema(
|
|
23
|
+
(await schemas.addDynamicPluginsSchemas(compiledConfigSchema)).schema
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
exports.dynamicPluginsFrontendSchemas = dynamicPluginsFrontendSchemas;
|
|
32
|
+
//# sourceMappingURL=appBackendModule.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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;;;;"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var rootLogger = require('@backstage/backend-defaults/rootLogger');
|
|
5
|
+
var winston = require('winston');
|
|
6
|
+
var backendCommon = require('@backstage/backend-common');
|
|
7
|
+
var configLoader = require('@backstage/config-loader');
|
|
8
|
+
var getPackages = require('@manypkg/get-packages');
|
|
9
|
+
var schemas = require('./schemas.cjs.js');
|
|
10
|
+
|
|
11
|
+
const dynamicPluginsRootLoggerServiceFactory = backendPluginApi.createServiceFactory({
|
|
12
|
+
service: backendPluginApi.coreServices.rootLogger,
|
|
13
|
+
deps: {
|
|
14
|
+
config: backendPluginApi.coreServices.rootConfig,
|
|
15
|
+
schemas: schemas.dynamicPluginsSchemasServiceRef
|
|
16
|
+
},
|
|
17
|
+
async factory({ config, schemas }) {
|
|
18
|
+
const logger = rootLogger.WinstonLogger.create({
|
|
19
|
+
meta: {
|
|
20
|
+
service: "backstage"
|
|
21
|
+
},
|
|
22
|
+
level: process.env.LOG_LEVEL || "info",
|
|
23
|
+
format: process.env.NODE_ENV === "production" ? winston.format.json() : rootLogger.WinstonLogger.colorFormat(),
|
|
24
|
+
transports: [new winston.transports.Console()]
|
|
25
|
+
});
|
|
26
|
+
const configSchema = await configLoader.loadConfigSchema({
|
|
27
|
+
dependencies: (await getPackages.getPackages(process.cwd())).packages.map((p) => p.packageJson.name)
|
|
28
|
+
});
|
|
29
|
+
const secretEnumerator = await backendCommon.createConfigSecretEnumerator({
|
|
30
|
+
logger,
|
|
31
|
+
schema: (await schemas.addDynamicPluginsSchemas(configSchema)).schema
|
|
32
|
+
});
|
|
33
|
+
logger.addRedactions(secretEnumerator(config));
|
|
34
|
+
config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));
|
|
35
|
+
return logger;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
exports.dynamicPluginsRootLoggerServiceFactory = dynamicPluginsRootLoggerServiceFactory;
|
|
40
|
+
//# sourceMappingURL=rootLoggerServiceFactory.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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;;;;"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var cliCommon = require('@backstage/cli-common');
|
|
5
|
+
var fs = require('fs-extra');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var url = require('url');
|
|
8
|
+
var lodash = require('lodash');
|
|
9
|
+
var pluginScanner = require('../scanner/plugin-scanner.cjs.js');
|
|
10
|
+
var configLoader = require('@backstage/config-loader');
|
|
11
|
+
|
|
12
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
function _interopNamespaceCompat(e) {
|
|
15
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
33
|
+
var path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
34
|
+
var url__namespace = /*#__PURE__*/_interopNamespaceCompat(url);
|
|
35
|
+
|
|
36
|
+
const dynamicPluginsSchemasServiceRef = backendPluginApi.createServiceRef({
|
|
37
|
+
id: "core.dynamicplugins.schemas",
|
|
38
|
+
scope: "root"
|
|
39
|
+
});
|
|
40
|
+
const dynamicPluginsSchemasServiceFactoryWithOptions = (options) => backendPluginApi.createServiceFactory({
|
|
41
|
+
service: dynamicPluginsSchemasServiceRef,
|
|
42
|
+
deps: {
|
|
43
|
+
config: backendPluginApi.coreServices.rootConfig
|
|
44
|
+
},
|
|
45
|
+
factory({ config }) {
|
|
46
|
+
let additionalSchemas;
|
|
47
|
+
return {
|
|
48
|
+
async addDynamicPluginsSchemas(configSchema) {
|
|
49
|
+
if (!additionalSchemas) {
|
|
50
|
+
const logger = {
|
|
51
|
+
...console,
|
|
52
|
+
child() {
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const scanner = pluginScanner.PluginScanner.create({
|
|
57
|
+
config,
|
|
58
|
+
logger,
|
|
59
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
60
|
+
backstageRoot: cliCommon.findPaths(__dirname).targetRoot,
|
|
61
|
+
preferAlpha: true
|
|
62
|
+
});
|
|
63
|
+
const { packages } = await scanner.scanRoot();
|
|
64
|
+
additionalSchemas = await gatherDynamicPluginsSchemas(
|
|
65
|
+
packages,
|
|
66
|
+
logger,
|
|
67
|
+
options?.schemaLocator
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
const serialized = configSchema.serialize();
|
|
71
|
+
if (serialized?.backstageConfigSchemaVersion !== 1) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"Serialized configuration schema is invalid or has an invalid version number"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
const schemas = serialized.schemas;
|
|
77
|
+
schemas.push(
|
|
78
|
+
...Object.keys(additionalSchemas).map((context) => {
|
|
79
|
+
return {
|
|
80
|
+
path: context,
|
|
81
|
+
value: additionalSchemas[context]
|
|
82
|
+
};
|
|
83
|
+
})
|
|
84
|
+
);
|
|
85
|
+
serialized.schemas = schemas;
|
|
86
|
+
return {
|
|
87
|
+
schema: await configLoader.loadConfigSchema({
|
|
88
|
+
serialized
|
|
89
|
+
})
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const dynamicPluginsSchemasServiceFactory = dynamicPluginsSchemasServiceFactoryWithOptions();
|
|
96
|
+
async function gatherDynamicPluginsSchemas(packages, logger, schemaLocator = () => path__namespace.join("dist", "configSchema.json")) {
|
|
97
|
+
const allSchemas = {};
|
|
98
|
+
for (const pluginPackage of packages) {
|
|
99
|
+
let schemaLocation = schemaLocator(pluginPackage);
|
|
100
|
+
if (!path__namespace.isAbsolute(schemaLocation)) {
|
|
101
|
+
let pluginLocation = url__namespace.fileURLToPath(pluginPackage.location);
|
|
102
|
+
if (path__namespace.basename(pluginLocation) === "alpha") {
|
|
103
|
+
pluginLocation = path__namespace.dirname(pluginLocation);
|
|
104
|
+
}
|
|
105
|
+
schemaLocation = path__namespace.resolve(pluginLocation, schemaLocation);
|
|
106
|
+
}
|
|
107
|
+
if (!await fs__default.default.pathExists(schemaLocation)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const serialized = await fs__default.default.readJson(schemaLocation);
|
|
111
|
+
if (!serialized) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (lodash.isEmpty(serialized)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!serialized?.$schema || serialized?.type !== "object") {
|
|
118
|
+
logger.error(
|
|
119
|
+
`Serialized configuration schema is invalid for plugin ${pluginPackage.manifest.name}`
|
|
120
|
+
);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
allSchemas[schemaLocation] = serialized;
|
|
124
|
+
}
|
|
125
|
+
return allSchemas;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
exports.dynamicPluginsSchemasServiceFactory = dynamicPluginsSchemasServiceFactory;
|
|
129
|
+
exports.dynamicPluginsSchemasServiceFactoryWithOptions = dynamicPluginsSchemasServiceFactoryWithOptions;
|
|
130
|
+
exports.dynamicPluginsSchemasServiceRef = dynamicPluginsSchemasServiceRef;
|
|
131
|
+
//# sourceMappingURL=schemas.cjs.js.map
|
|
@@ -0,0 +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\n/**\n * @public\n */\nexport const 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 */\nexport const dynamicPluginsSchemasServiceFactory =\n dynamicPluginsSchemasServiceFactoryWithOptions();\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.2-next.
|
|
3
|
+
"version": "0.4.2-next.2",
|
|
4
4
|
"description": "Backstage dynamic feature service",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -42,24 +42,24 @@
|
|
|
42
42
|
"test": "backstage-cli package test"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@backstage/backend-app-api": "1.0.1-next.
|
|
45
|
+
"@backstage/backend-app-api": "1.0.1-next.1",
|
|
46
46
|
"@backstage/backend-common": "^0.25.0",
|
|
47
|
-
"@backstage/backend-defaults": "0.5.1-next.
|
|
48
|
-
"@backstage/backend-plugin-api": "1.0.1-next.
|
|
47
|
+
"@backstage/backend-defaults": "0.5.1-next.2",
|
|
48
|
+
"@backstage/backend-plugin-api": "1.0.1-next.1",
|
|
49
49
|
"@backstage/cli-common": "0.1.14",
|
|
50
|
-
"@backstage/cli-node": "0.2.
|
|
50
|
+
"@backstage/cli-node": "0.2.9-next.0",
|
|
51
51
|
"@backstage/config": "1.2.0",
|
|
52
52
|
"@backstage/config-loader": "1.9.1",
|
|
53
53
|
"@backstage/errors": "1.2.4",
|
|
54
|
-
"@backstage/plugin-app-node": "0.1.26-next.
|
|
55
|
-
"@backstage/plugin-auth-node": "0.5.3-next.
|
|
56
|
-
"@backstage/plugin-catalog-backend": "1.26.2-next.
|
|
57
|
-
"@backstage/plugin-events-backend": "0.3.13-next.
|
|
58
|
-
"@backstage/plugin-events-node": "0.4.1-next.
|
|
54
|
+
"@backstage/plugin-app-node": "0.1.26-next.1",
|
|
55
|
+
"@backstage/plugin-auth-node": "0.5.3-next.1",
|
|
56
|
+
"@backstage/plugin-catalog-backend": "1.26.2-next.2",
|
|
57
|
+
"@backstage/plugin-events-backend": "0.3.13-next.1",
|
|
58
|
+
"@backstage/plugin-events-node": "0.4.1-next.1",
|
|
59
59
|
"@backstage/plugin-permission-common": "0.8.1",
|
|
60
|
-
"@backstage/plugin-permission-node": "0.8.4-next.
|
|
61
|
-
"@backstage/plugin-scaffolder-node": "0.5.0-next.
|
|
62
|
-
"@backstage/plugin-search-backend-node": "1.3.3-next.
|
|
60
|
+
"@backstage/plugin-permission-node": "0.8.4-next.1",
|
|
61
|
+
"@backstage/plugin-scaffolder-node": "0.5.0-next.2",
|
|
62
|
+
"@backstage/plugin-search-backend-node": "1.3.3-next.2",
|
|
63
63
|
"@backstage/plugin-search-common": "1.2.14",
|
|
64
64
|
"@backstage/types": "1.1.1",
|
|
65
65
|
"@manypkg/get-packages": "^1.1.3",
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
"winston": "^3.2.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@backstage/backend-test-utils": "1.0.1-next.
|
|
75
|
-
"@backstage/cli": "0.28.0-next.
|
|
74
|
+
"@backstage/backend-test-utils": "1.0.1-next.2",
|
|
75
|
+
"@backstage/cli": "0.28.0-next.2",
|
|
76
76
|
"wait-for-expect": "^3.0.2"
|
|
77
77
|
}
|
|
78
78
|
}
|