@red-hat-developer-hub/backstage-plugin-extensions-backend 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +329 -0
- package/README.md +43 -0
- package/dist/errors/ConfigFormatError.cjs.js +10 -0
- package/dist/errors/ConfigFormatError.cjs.js.map +1 -0
- package/dist/errors/InstallationInitError.cjs.js +30 -0
- package/dist/errors/InstallationInitError.cjs.js.map +1 -0
- package/dist/index.cjs.js +11 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/installation/FileInstallationStorage.cjs.js +120 -0
- package/dist/installation/FileInstallationStorage.cjs.js.map +1 -0
- package/dist/installation/InstallationDataService.cjs.js +124 -0
- package/dist/installation/InstallationDataService.cjs.js.map +1 -0
- package/dist/permissions/rules.cjs.js +43 -0
- package/dist/permissions/rules.cjs.js.map +1 -0
- package/dist/plugin.cjs.js +61 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/router.cjs.js +364 -0
- package/dist/router.cjs.js.map +1 -0
- package/dist/utils/createSearchParams.cjs.js +18 -0
- package/dist/utils/createSearchParams.cjs.js.map +1 -0
- package/dist/utils/permissionUtils.cjs.js +25 -0
- package/dist/utils/permissionUtils.cjs.js.map +1 -0
- package/dist/utils/removeVerboseSpecContent.cjs.js +11 -0
- package/dist/utils/removeVerboseSpecContent.cjs.js.map +1 -0
- package/dist/validation/configValidation.cjs.js +76 -0
- package/dist/validation/configValidation.cjs.js.map +1 -0
- package/package.json +75 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# @red-hat-developer-hub/backstage-plugin-extensions-backend
|
|
2
|
+
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4fafdf3: Renamed plugins from marketplace to extensions
|
|
8
|
+
|
|
9
|
+
- Renamed all packages from `backstage-plugin-marketplace-*` to `backstage-plugin-extensions-*`
|
|
10
|
+
- Updated all internal references, exports, and API endpoints
|
|
11
|
+
- lazy load codeEditor to reduce the frontend plugin bundle size
|
|
12
|
+
- Made catalog entities directory path configurable via `extensions.directory` in app-config.yaml with fallback to `extensions` and `marketplace` directories
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [4fafdf3]
|
|
17
|
+
- @red-hat-developer-hub/backstage-plugin-extensions-common@0.14.0
|
|
18
|
+
|
|
19
|
+
## 0.13.2
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.13.2
|
|
24
|
+
|
|
25
|
+
## 0.13.1
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.13.1
|
|
30
|
+
|
|
31
|
+
## 0.13.0
|
|
32
|
+
|
|
33
|
+
### Minor Changes
|
|
34
|
+
|
|
35
|
+
- bee615a: Backstage version bump to v1.45.2
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [bee615a]
|
|
40
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.13.0
|
|
41
|
+
|
|
42
|
+
## 0.12.2
|
|
43
|
+
|
|
44
|
+
### Patch Changes
|
|
45
|
+
|
|
46
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.12.2
|
|
47
|
+
|
|
48
|
+
## 0.12.1
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.12.1
|
|
53
|
+
|
|
54
|
+
## 0.12.0
|
|
55
|
+
|
|
56
|
+
### Minor Changes
|
|
57
|
+
|
|
58
|
+
- f8e6f04: Backstage version bump to v1.44.1
|
|
59
|
+
|
|
60
|
+
### Patch Changes
|
|
61
|
+
|
|
62
|
+
- Updated dependencies [f8e6f04]
|
|
63
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.12.0
|
|
64
|
+
|
|
65
|
+
## 0.11.0
|
|
66
|
+
|
|
67
|
+
### Minor Changes
|
|
68
|
+
|
|
69
|
+
- 36a7d6a: **BREAKING** Replace POST with PATCH `/package/:namespace/:name/configuration/disable` endpoint to update packages disabled status
|
|
70
|
+
|
|
71
|
+
### Patch Changes
|
|
72
|
+
|
|
73
|
+
- 4d79286: added row actions to the installed packages
|
|
74
|
+
updated disablePackage Client API to make PATCH call instead of POST
|
|
75
|
+
- Updated dependencies [4d79286]
|
|
76
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.10.1
|
|
77
|
+
|
|
78
|
+
## 0.10.0
|
|
79
|
+
|
|
80
|
+
### Minor Changes
|
|
81
|
+
|
|
82
|
+
- b33db25: Backstage version bump to v1.42.5
|
|
83
|
+
|
|
84
|
+
### Patch Changes
|
|
85
|
+
|
|
86
|
+
- Updated dependencies [b33db25]
|
|
87
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.10.0
|
|
88
|
+
|
|
89
|
+
## 0.9.0
|
|
90
|
+
|
|
91
|
+
### Minor Changes
|
|
92
|
+
|
|
93
|
+
- fdda9a1: Add internationalization (i18n) support with German, French and Spanish translations in marketplace.
|
|
94
|
+
- dad9806: Integrate plugins-info plugin and add `Installed packages` tab with enhanced UI.
|
|
95
|
+
|
|
96
|
+
BREAKING: The deprecated `InstallationContextProvider` export behavior changed.
|
|
97
|
+
|
|
98
|
+
- We now export a null component `InstallationContextProvider` from `plugin.ts` solely for backward compatibility. It no longer provides context and will be removed in a future release.
|
|
99
|
+
- Migration: There is no replacement API; this was internal-only. Please upgrade to the latest RHDH where features no longer rely on this provider.
|
|
100
|
+
|
|
101
|
+
Also:
|
|
102
|
+
|
|
103
|
+
- New `Installed packages` tab with dual-source mapping and client-side filtering/pagination.
|
|
104
|
+
|
|
105
|
+
### Patch Changes
|
|
106
|
+
|
|
107
|
+
- Updated dependencies [fdda9a1]
|
|
108
|
+
- Updated dependencies [cbe1174]
|
|
109
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.9.0
|
|
110
|
+
|
|
111
|
+
## 0.8.0
|
|
112
|
+
|
|
113
|
+
### Minor Changes
|
|
114
|
+
|
|
115
|
+
- 8887468: Backstage version bump to v1.41.1
|
|
116
|
+
|
|
117
|
+
### Patch Changes
|
|
118
|
+
|
|
119
|
+
- Updated dependencies [8887468]
|
|
120
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.8.0
|
|
121
|
+
|
|
122
|
+
## 0.7.4
|
|
123
|
+
|
|
124
|
+
### Patch Changes
|
|
125
|
+
|
|
126
|
+
- Updated dependencies [171b7fd]
|
|
127
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.7.2
|
|
128
|
+
|
|
129
|
+
## 0.7.3
|
|
130
|
+
|
|
131
|
+
### Patch Changes
|
|
132
|
+
|
|
133
|
+
- fb23720: Introduce `spec.integrity` field for Marketplace package
|
|
134
|
+
- Updated dependencies [fb23720]
|
|
135
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.7.1
|
|
136
|
+
|
|
137
|
+
## 0.7.2
|
|
138
|
+
|
|
139
|
+
### Patch Changes
|
|
140
|
+
|
|
141
|
+
- 7aa3823: Restrict access to configuration endpoints in production
|
|
142
|
+
|
|
143
|
+
## 0.7.1
|
|
144
|
+
|
|
145
|
+
### Patch Changes
|
|
146
|
+
|
|
147
|
+
- 8ada066: Update all plugin packages via PATCH `/plugin/:namespace/:name/configuration/disable`
|
|
148
|
+
|
|
149
|
+
## 0.7.0
|
|
150
|
+
|
|
151
|
+
### Minor Changes
|
|
152
|
+
|
|
153
|
+
- f70ccb1: Use plugin permissions in package configuration endpoints. `AuthorizeResult` for particular package is based upon if user has ALLOW permission for any of plugins that contain this package. Removes unused `extensions-package` permissions.
|
|
154
|
+
|
|
155
|
+
### Patch Changes
|
|
156
|
+
|
|
157
|
+
- Updated dependencies [f70ccb1]
|
|
158
|
+
- Updated dependencies [7aac60c]
|
|
159
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.7.0
|
|
160
|
+
|
|
161
|
+
## 0.6.0
|
|
162
|
+
|
|
163
|
+
### Minor Changes
|
|
164
|
+
|
|
165
|
+
- 3973839: Introduces PUT endpoint for enabling or disabling dynamic plugins: `/plugin/:namespace/:name/configuration/disable` and POST endpoint for enabling or disabling dynamic packages `/package/:namespace/:name/configuration/disable` not already existing in `EXTENSIONS_PLUGIN_CONFIG`.
|
|
166
|
+
|
|
167
|
+
### Patch Changes
|
|
168
|
+
|
|
169
|
+
- ca2e330: Bump to backstage version 1.39.1
|
|
170
|
+
- 58ae1fe: Added an alert for production environment
|
|
171
|
+
Integrated the fetch configuration and install API calls
|
|
172
|
+
Fixed an import error
|
|
173
|
+
- Updated dependencies [ca2e330]
|
|
174
|
+
- Updated dependencies [3973839]
|
|
175
|
+
- Updated dependencies [58ae1fe]
|
|
176
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.6.0
|
|
177
|
+
|
|
178
|
+
## 0.5.0
|
|
179
|
+
|
|
180
|
+
### Minor Changes
|
|
181
|
+
|
|
182
|
+
- 7ae0ca0: Introduces POST endpoints for updating dynamic plugins and packages installation configuration: `/package/:namespace/:name/configuration` and `/plugin/:namespace/:name/configuration`.
|
|
183
|
+
|
|
184
|
+
### Patch Changes
|
|
185
|
+
|
|
186
|
+
- Updated dependencies [7ae0ca0]
|
|
187
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.5.0
|
|
188
|
+
|
|
189
|
+
## 0.4.0
|
|
190
|
+
|
|
191
|
+
### Minor Changes
|
|
192
|
+
|
|
193
|
+
- 7d138e5: Added extension permissions
|
|
194
|
+
- f56908a: Introduces GET endpoints for dynamic plugins configuration: `/package/:namespace/:name/configuration` and `/plugin/:namespace/:name/configuration`. Introduces optional config value `extensions.installation` which is used for installation configuration.
|
|
195
|
+
|
|
196
|
+
### Patch Changes
|
|
197
|
+
|
|
198
|
+
- 4413eef: updated `extension` to `extensions`
|
|
199
|
+
update marketplace pluginId to extensions
|
|
200
|
+
- Updated dependencies [4413eef]
|
|
201
|
+
- Updated dependencies [7d138e5]
|
|
202
|
+
- Updated dependencies [f56908a]
|
|
203
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.4.0
|
|
204
|
+
|
|
205
|
+
## 0.3.1
|
|
206
|
+
|
|
207
|
+
### Patch Changes
|
|
208
|
+
|
|
209
|
+
- 0f6f539: Allows packages API to return 'spec.appConfigExamples' data.
|
|
210
|
+
|
|
211
|
+
## 0.3.0
|
|
212
|
+
|
|
213
|
+
### Minor Changes
|
|
214
|
+
|
|
215
|
+
- 6501387: Backstage version bump to v1.36.1
|
|
216
|
+
|
|
217
|
+
### Patch Changes
|
|
218
|
+
|
|
219
|
+
- Updated dependencies [6501387]
|
|
220
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.3.0
|
|
221
|
+
|
|
222
|
+
## 0.2.0
|
|
223
|
+
|
|
224
|
+
### Minor Changes
|
|
225
|
+
|
|
226
|
+
- d3bcc76: rename apiVersion and annotations to extensions.backstage.io
|
|
227
|
+
|
|
228
|
+
### Patch Changes
|
|
229
|
+
|
|
230
|
+
- Updated dependencies [d3bcc76]
|
|
231
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.2.0
|
|
232
|
+
|
|
233
|
+
## 0.1.2
|
|
234
|
+
|
|
235
|
+
### Patch Changes
|
|
236
|
+
|
|
237
|
+
- a7e38a9: remove core-plugin-api dependency from common
|
|
238
|
+
- Updated dependencies [a7e38a9]
|
|
239
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.1.2
|
|
240
|
+
|
|
241
|
+
## 0.1.1
|
|
242
|
+
|
|
243
|
+
### Patch Changes
|
|
244
|
+
|
|
245
|
+
- fa70a22: remove unused knex and zod dependency from common package
|
|
246
|
+
- Updated dependencies [fa70a22]
|
|
247
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.1.1
|
|
248
|
+
|
|
249
|
+
## 0.1.0
|
|
250
|
+
|
|
251
|
+
### Minor Changes
|
|
252
|
+
|
|
253
|
+
- d39d4e3: Initial tech-preview of the marketplace
|
|
254
|
+
|
|
255
|
+
### Patch Changes
|
|
256
|
+
|
|
257
|
+
- f16dd69: Refactore and update API, UI, and catalog types
|
|
258
|
+
- Updated dependencies [d39d4e3]
|
|
259
|
+
- Updated dependencies [f16dd69]
|
|
260
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.1.0
|
|
261
|
+
|
|
262
|
+
## 0.0.9
|
|
263
|
+
|
|
264
|
+
### Patch Changes
|
|
265
|
+
|
|
266
|
+
- Updated dependencies [f310add]
|
|
267
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.9
|
|
268
|
+
|
|
269
|
+
## 0.0.8
|
|
270
|
+
|
|
271
|
+
### Patch Changes
|
|
272
|
+
|
|
273
|
+
- 4e0ec06: add optional sorting, filtering, pagination to marketplace api
|
|
274
|
+
- Updated dependencies [4e0ec06]
|
|
275
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.8
|
|
276
|
+
|
|
277
|
+
## 0.0.7
|
|
278
|
+
|
|
279
|
+
### Patch Changes
|
|
280
|
+
|
|
281
|
+
- 9a3c185: replace custom aggregation api endpoint with catalog entity-facets api
|
|
282
|
+
- Updated dependencies [9a3c185]
|
|
283
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.7
|
|
284
|
+
|
|
285
|
+
## 0.0.6
|
|
286
|
+
|
|
287
|
+
### Patch Changes
|
|
288
|
+
|
|
289
|
+
- Updated dependencies [0bcb97f]
|
|
290
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.6
|
|
291
|
+
|
|
292
|
+
## 0.0.5
|
|
293
|
+
|
|
294
|
+
### Patch Changes
|
|
295
|
+
|
|
296
|
+
- 381a250: Upgrade Backstage from 1.32.0 to 1.35.0
|
|
297
|
+
- Updated dependencies [381a250]
|
|
298
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.5
|
|
299
|
+
|
|
300
|
+
## 0.0.4
|
|
301
|
+
|
|
302
|
+
### Patch Changes
|
|
303
|
+
|
|
304
|
+
- 113ff0d: Add new aggregation api in marketplace
|
|
305
|
+
- Updated dependencies [113ff0d]
|
|
306
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.4
|
|
307
|
+
|
|
308
|
+
## 0.0.3
|
|
309
|
+
|
|
310
|
+
### Patch Changes
|
|
311
|
+
|
|
312
|
+
- 58c2d47: Add new endpoints in marketplace.
|
|
313
|
+
- Updated dependencies [58c2d47]
|
|
314
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.3
|
|
315
|
+
|
|
316
|
+
## 0.0.2
|
|
317
|
+
|
|
318
|
+
### Patch Changes
|
|
319
|
+
|
|
320
|
+
- Updated dependencies [8c442b6]
|
|
321
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.2
|
|
322
|
+
|
|
323
|
+
## 0.0.1
|
|
324
|
+
|
|
325
|
+
### Patch Changes
|
|
326
|
+
|
|
327
|
+
- 56f9484: release marketplace plugin
|
|
328
|
+
- Updated dependencies [56f9484]
|
|
329
|
+
- @red-hat-developer-hub/backstage-plugin-marketplace-common@0.0.1
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# extensions
|
|
2
|
+
|
|
3
|
+
This plugin backend was templated using the Backstage CLI. You should replace this text with a description of your plugin backend.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
This plugin is installed via the `@red-hat-developer-hub/backstage-plugin-extensions-backend` package. To install it to your backend package, run the following command:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# From your root directory
|
|
11
|
+
yarn --cwd packages/backend add @red-hat-developer-hub/backstage-plugin-extensions-backend
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Then add the plugin to your backend in `packages/backend/src/index.ts`:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
const backend = createBackend();
|
|
18
|
+
// ...
|
|
19
|
+
backend.add(
|
|
20
|
+
import('@red-hat-developer-hub/backstage-plugin-extensions-backend'),
|
|
21
|
+
);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Plugin Configurations
|
|
25
|
+
|
|
26
|
+
Add the following extensions configuration in your `app-config.yaml` file:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
extensions:
|
|
30
|
+
### Example for how to enable installation to a file.
|
|
31
|
+
installation:
|
|
32
|
+
enabled: true
|
|
33
|
+
saveToSingleFile:
|
|
34
|
+
file: <path-to>/dynamic-plugins.yaml
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Development
|
|
38
|
+
|
|
39
|
+
This plugin backend can be started in a standalone mode from directly in this
|
|
40
|
+
package with `yarn start`. It is a limited setup that is most convenient when
|
|
41
|
+
developing the plugin backend itself.
|
|
42
|
+
|
|
43
|
+
If you want to run the entire project, including the frontend, run `yarn start` from the root directory.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigFormatError.cjs.js","sources":["../../src/errors/ConfigFormatError.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { CustomErrorBase } from '@backstage/errors';\n\nexport class ConfigFormatError extends CustomErrorBase {\n name = 'ConfigFormatError' as const;\n}\n"],"names":["CustomErrorBase"],"mappings":";;;;AAiBO,MAAM,0BAA0BA,sBAAgB,CAAA;AAAA,EACrD,IAAO,GAAA,mBAAA;AACT;;;;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
|
|
5
|
+
const InstallationInitErrorReason = {
|
|
6
|
+
INSTALLATION_DISABLED_IN_PRODUCTION: "INSTALLATION_DISABLED_IN_PRODUCTION",
|
|
7
|
+
INSTALLATION_DISABLED: "INSTALLATION_DISABLED",
|
|
8
|
+
FILE_CONFIG_VALUE_MISSING: "FILE_CONFIG_VALUE_MISSING",
|
|
9
|
+
FILE_NOT_EXISTS: "FILE_NOT_EXISTS",
|
|
10
|
+
INVALID_CONFIG: "INVALID_CONFIG",
|
|
11
|
+
UNKNOWN: "UNKNOWN"
|
|
12
|
+
};
|
|
13
|
+
class InstallationInitError extends errors.CustomErrorBase {
|
|
14
|
+
constructor(reason, message, cause) {
|
|
15
|
+
super(message, cause);
|
|
16
|
+
this.reason = reason;
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
if (this.reason === InstallationInitErrorReason.INSTALLATION_DISABLED_IN_PRODUCTION || this.reason === InstallationInitErrorReason.INSTALLATION_DISABLED) {
|
|
19
|
+
this.statusCode = 503;
|
|
20
|
+
} else {
|
|
21
|
+
this.statusCode = 500;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
name = "InstallationInitError";
|
|
25
|
+
statusCode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.InstallationInitError = InstallationInitError;
|
|
29
|
+
exports.InstallationInitErrorReason = InstallationInitErrorReason;
|
|
30
|
+
//# sourceMappingURL=InstallationInitError.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstallationInitError.cjs.js","sources":["../../src/errors/InstallationInitError.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { CustomErrorBase } from '@backstage/errors';\n\nexport const InstallationInitErrorReason = {\n INSTALLATION_DISABLED_IN_PRODUCTION: 'INSTALLATION_DISABLED_IN_PRODUCTION',\n INSTALLATION_DISABLED: 'INSTALLATION_DISABLED',\n FILE_CONFIG_VALUE_MISSING: 'FILE_CONFIG_VALUE_MISSING',\n FILE_NOT_EXISTS: 'FILE_NOT_EXISTS',\n INVALID_CONFIG: 'INVALID_CONFIG',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\nexport type InstallationInitErrorReasonKeys =\n (typeof InstallationInitErrorReason)[keyof typeof InstallationInitErrorReason];\n\nexport class InstallationInitError extends CustomErrorBase {\n name = 'InstallationInitError' as const;\n readonly statusCode: number;\n\n constructor(\n public reason: InstallationInitErrorReasonKeys,\n message: string,\n public cause?: Error,\n ) {\n super(message, cause);\n if (\n this.reason ===\n InstallationInitErrorReason.INSTALLATION_DISABLED_IN_PRODUCTION ||\n this.reason === InstallationInitErrorReason.INSTALLATION_DISABLED\n ) {\n this.statusCode = 503;\n } else {\n this.statusCode = 500;\n }\n }\n}\n"],"names":["CustomErrorBase"],"mappings":";;;;AAiBO,MAAM,2BAA8B,GAAA;AAAA,EACzC,mCAAqC,EAAA,qCAAA;AAAA,EACrC,qBAAuB,EAAA,uBAAA;AAAA,EACvB,yBAA2B,EAAA,2BAAA;AAAA,EAC3B,eAAiB,EAAA,iBAAA;AAAA,EACjB,cAAgB,EAAA,gBAAA;AAAA,EAChB,OAAS,EAAA;AACX;AAKO,MAAM,8BAA8BA,sBAAgB,CAAA;AAAA,EAIzD,WAAA,CACS,MACP,EAAA,OAAA,EACO,KACP,EAAA;AACA,IAAA,KAAA,CAAM,SAAS,KAAK,CAAA;AAJb,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAEA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAGP,IAAA,IACE,KAAK,MACH,KAAA,2BAAA,CAA4B,uCAC9B,IAAK,CAAA,MAAA,KAAW,4BAA4B,qBAC5C,EAAA;AACA,MAAA,IAAA,CAAK,UAAa,GAAA,GAAA;AAAA,KACb,MAAA;AACL,MAAA,IAAA,CAAK,UAAa,GAAA,GAAA;AAAA;AACpB;AACF,EAlBA,IAAO,GAAA,uBAAA;AAAA,EACE,UAAA;AAkBX;;;;;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var plugin = require('./plugin.cjs.js');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
exports.default = plugin.extensionsPlugin;
|
|
10
|
+
exports.extensionsPlugin = plugin.extensionsPlugin;
|
|
11
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extensions backend plugin
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
declare const extensionsPlugin: _backstage_backend_plugin_api.BackendFeature;
|
|
9
|
+
|
|
10
|
+
export { extensionsPlugin as default, extensionsPlugin };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var yaml = require('yaml');
|
|
5
|
+
var configValidation = require('../validation/configValidation.cjs.js');
|
|
6
|
+
var InstallationInitError = require('../errors/InstallationInitError.cjs.js');
|
|
7
|
+
|
|
8
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
11
|
+
|
|
12
|
+
class FileInstallationStorage {
|
|
13
|
+
configFile;
|
|
14
|
+
config;
|
|
15
|
+
constructor(configFile) {
|
|
16
|
+
this.configFile = configFile;
|
|
17
|
+
this.config = new yaml.Document();
|
|
18
|
+
}
|
|
19
|
+
get packages() {
|
|
20
|
+
return this.config.get("plugins");
|
|
21
|
+
}
|
|
22
|
+
toStringYaml(mapNodes) {
|
|
23
|
+
const tempDoc = new yaml.Document(mapNodes);
|
|
24
|
+
return tempDoc.toString({ lineWidth: 0 });
|
|
25
|
+
}
|
|
26
|
+
getPackageYamlMap(packageName) {
|
|
27
|
+
return this.packages.items.find(
|
|
28
|
+
(p) => yaml.isMap(p) && p.get("package") === packageName
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
save() {
|
|
32
|
+
fs__default.default.writeFileSync(this.configFile, this.config.toString({ lineWidth: 0 }));
|
|
33
|
+
}
|
|
34
|
+
initialize() {
|
|
35
|
+
if (!fs__default.default.existsSync(this.configFile)) {
|
|
36
|
+
throw new InstallationInitError.InstallationInitError(
|
|
37
|
+
InstallationInitError.InstallationInitErrorReason.FILE_NOT_EXISTS,
|
|
38
|
+
`The file ${this.configFile} is missing`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const rawContent = fs__default.default.readFileSync(this.configFile, "utf-8");
|
|
42
|
+
const parsedContent = yaml.parseDocument(rawContent);
|
|
43
|
+
configValidation.validateConfigurationFormat(parsedContent);
|
|
44
|
+
this.config = parsedContent;
|
|
45
|
+
}
|
|
46
|
+
getConfigYaml() {
|
|
47
|
+
return this.config.toString({ lineWidth: 0 });
|
|
48
|
+
}
|
|
49
|
+
getPackage(packageName) {
|
|
50
|
+
const res = this.getPackageYamlMap(packageName);
|
|
51
|
+
return res ? this.toStringYaml([res]) : res;
|
|
52
|
+
}
|
|
53
|
+
getPackages(packageNames) {
|
|
54
|
+
const res = [];
|
|
55
|
+
for (const packageName of packageNames) {
|
|
56
|
+
const packageMap = this.getPackageYamlMap(packageName);
|
|
57
|
+
if (packageMap) {
|
|
58
|
+
res.push(packageMap);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return res.length === 0 ? undefined : this.toStringYaml(res);
|
|
62
|
+
}
|
|
63
|
+
updatePackage(packageName, newConfig) {
|
|
64
|
+
const newNode = yaml.parseDocument(newConfig).contents;
|
|
65
|
+
configValidation.validatePackageFormat(newNode, packageName);
|
|
66
|
+
const existingPackage = this.packages.items.find(
|
|
67
|
+
(item) => item.get("package") === packageName
|
|
68
|
+
);
|
|
69
|
+
if (existingPackage) {
|
|
70
|
+
existingPackage.items = newNode.items;
|
|
71
|
+
} else {
|
|
72
|
+
this.packages.items.push(newNode);
|
|
73
|
+
}
|
|
74
|
+
this.save();
|
|
75
|
+
}
|
|
76
|
+
updatePackages(packageNames, newConfig) {
|
|
77
|
+
const newNodes = yaml.parseDocument(newConfig);
|
|
78
|
+
configValidation.validatePluginFormat(newNodes, packageNames);
|
|
79
|
+
const updatedPackages = new yaml.YAMLSeq();
|
|
80
|
+
for (const item of this.packages.items) {
|
|
81
|
+
const name = item.get("package");
|
|
82
|
+
if (!packageNames.has(name)) {
|
|
83
|
+
updatedPackages.items.push(item);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
updatedPackages.items.push(...newNodes.contents.items);
|
|
87
|
+
this.config.set("plugins", updatedPackages);
|
|
88
|
+
this.save();
|
|
89
|
+
}
|
|
90
|
+
setPackageDisabled(packageName, disabled) {
|
|
91
|
+
let pkg = this.getPackageYamlMap(packageName);
|
|
92
|
+
if (!pkg) {
|
|
93
|
+
pkg = new yaml.YAMLMap();
|
|
94
|
+
pkg.set("package", packageName);
|
|
95
|
+
this.packages.add(pkg);
|
|
96
|
+
}
|
|
97
|
+
pkg.set("disabled", disabled);
|
|
98
|
+
this.save();
|
|
99
|
+
}
|
|
100
|
+
setPackagesDisabled(packageNames, disabled) {
|
|
101
|
+
const packages = this.config.get("plugins");
|
|
102
|
+
const packageMap = packages.items.reduce(
|
|
103
|
+
(map, item) => map.set(item.get("package"), item),
|
|
104
|
+
/* @__PURE__ */ new Map()
|
|
105
|
+
);
|
|
106
|
+
for (const packageName of packageNames) {
|
|
107
|
+
let item = packageMap.get(packageName);
|
|
108
|
+
if (!item) {
|
|
109
|
+
item = new yaml.YAMLMap();
|
|
110
|
+
item.set("package", packageName);
|
|
111
|
+
packages.add(item);
|
|
112
|
+
}
|
|
113
|
+
item.set("disabled", disabled);
|
|
114
|
+
}
|
|
115
|
+
this.save();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
exports.FileInstallationStorage = FileInstallationStorage;
|
|
120
|
+
//# sourceMappingURL=FileInstallationStorage.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileInstallationStorage.cjs.js","sources":["../../src/installation/FileInstallationStorage.ts"],"sourcesContent":["/*\n * Copyright 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 fs from 'fs';\n\nimport { Document, isMap, parseDocument, YAMLMap, YAMLSeq } from 'yaml';\nimport {\n validateConfigurationFormat,\n validatePackageFormat,\n validatePluginFormat,\n} from '../validation/configValidation';\nimport {\n InstallationInitError,\n InstallationInitErrorReason,\n} from '../errors/InstallationInitError';\nimport type { JsonValue } from '@backstage/types';\n\nexport interface InstallationStorage {\n initialize?(): void;\n getPackage(packageName: string): string | undefined;\n updatePackage(packageName: string, newConfig: string): void;\n getPackages(packageNames: Set<string>): string | undefined;\n updatePackages(packageNames: Set<string>, newConfig: string): void;\n setPackageDisabled(packageName: string, disabled: boolean): void;\n setPackagesDisabled(packageNames: Set<string>, disabled: boolean): void;\n}\n\nexport class FileInstallationStorage implements InstallationStorage {\n private readonly configFile: string;\n private config: Document;\n\n constructor(configFile: string) {\n this.configFile = configFile;\n this.config = new Document();\n }\n\n private get packages(): YAMLSeq<YAMLMap<string, JsonValue>> {\n return this.config.get('plugins') as YAMLSeq<YAMLMap<string, JsonValue>>;\n }\n\n private toStringYaml(mapNodes: YAMLMap<string, JsonValue>[]): string {\n const tempDoc = new Document(mapNodes);\n return tempDoc.toString({ lineWidth: 0 });\n }\n\n private getPackageYamlMap(\n packageName: string,\n ): YAMLMap<string, JsonValue> | undefined {\n return this.packages.items.find(\n p => isMap(p) && p.get('package') === packageName,\n );\n }\n\n private save() {\n fs.writeFileSync(this.configFile, this.config.toString({ lineWidth: 0 }));\n }\n\n initialize(): void {\n if (!fs.existsSync(this.configFile)) {\n throw new InstallationInitError(\n InstallationInitErrorReason.FILE_NOT_EXISTS,\n `The file ${this.configFile} is missing`,\n );\n }\n const rawContent = fs.readFileSync(this.configFile, 'utf-8');\n const parsedContent = parseDocument(rawContent);\n validateConfigurationFormat(parsedContent);\n this.config = parsedContent;\n }\n\n getConfigYaml(): string {\n return this.config.toString({ lineWidth: 0 });\n }\n\n getPackage(packageName: string): string | undefined {\n const res = this.getPackageYamlMap(packageName);\n return res ? this.toStringYaml([res]) : res;\n }\n\n getPackages(packageNames: Set<string>): string | undefined {\n const res = [];\n for (const packageName of packageNames) {\n const packageMap = this.getPackageYamlMap(packageName);\n if (packageMap) {\n res.push(packageMap);\n }\n }\n return res.length === 0 ? undefined : this.toStringYaml(res);\n }\n\n updatePackage(packageName: string, newConfig: string): void {\n const newNode = parseDocument(newConfig).contents;\n validatePackageFormat(newNode, packageName);\n\n const existingPackage = this.packages.items.find(\n item => item.get('package') === packageName,\n );\n if (existingPackage) {\n existingPackage.items = newNode.items;\n } else {\n this.packages.items.push(newNode);\n }\n this.save();\n }\n\n updatePackages(packageNames: Set<string>, newConfig: string): void {\n const newNodes = parseDocument(newConfig);\n validatePluginFormat(newNodes, packageNames);\n\n const updatedPackages = new YAMLSeq<YAMLMap<string, JsonValue>>();\n for (const item of this.packages.items) {\n const name = item.get('package') as string;\n if (!packageNames.has(name)) {\n updatedPackages.items.push(item); // keep unchanged package of different plugin\n }\n }\n updatedPackages.items.push(...newNodes.contents.items);\n\n this.config.set('plugins', updatedPackages);\n this.save();\n }\n\n setPackageDisabled(packageName: string, disabled: boolean) {\n let pkg = this.getPackageYamlMap(packageName);\n if (!pkg) {\n pkg = new YAMLMap<string, JsonValue>();\n pkg.set('package', packageName);\n this.packages.add(pkg);\n }\n pkg.set('disabled', disabled);\n this.save();\n }\n\n setPackagesDisabled(packageNames: Set<string>, disabled: boolean) {\n const packages = this.config.get('plugins') as YAMLSeq<\n YAMLMap<string, JsonValue>\n >;\n const packageMap = packages.items.reduce(\n (map, item) => map.set(item.get('package') as string, item),\n new Map<string, YAMLMap<string, JsonValue>>(),\n );\n for (const packageName of packageNames) {\n let item = packageMap.get(packageName);\n if (!item) {\n item = new YAMLMap<string, JsonValue>();\n item.set('package', packageName);\n packages.add(item);\n }\n item.set('disabled', disabled);\n }\n\n this.save();\n }\n}\n"],"names":["Document","isMap","fs","InstallationInitError","InstallationInitErrorReason","parseDocument","validateConfigurationFormat","validatePackageFormat","validatePluginFormat","YAMLSeq","YAMLMap"],"mappings":"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"}
|