@backstage-community/plugin-npm-backend 1.1.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/README.md +324 -0
- package/config.d.ts +43 -0
- package/dist/index.cjs.js +10 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/plugin.cjs.js +39 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/router.cjs.js +38 -0
- package/dist/router.cjs.js.map +1 -0
- package/dist/services/NpmRegistryServiceImpl.cjs.js +60 -0
- package/dist/services/NpmRegistryServiceImpl.cjs.js.map +1 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# npm plugin for Backstage
|
|
2
|
+
|
|
3
|
+
A Backstage plugin that shows information and latest releases/versions
|
|
4
|
+
from a npm registry for catalog entities.
|
|
5
|
+
|
|
6
|
+
The current version can show two cards and one additional tab for an catalog entity.
|
|
7
|
+
|
|
8
|
+
1. The "Npm info card" shows general information like the latest version, description, etc.
|
|
9
|
+
2. The "Npm release overview card" shows the latest tags of an npm package.
|
|
10
|
+
3. The "Npm release tab" shows the version hisory in detail.
|
|
11
|
+
|
|
12
|
+
## Screenshots
|
|
13
|
+
|
|
14
|
+
### Npm info card
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
### Npm release overview card
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
### Extended catalog entity overview tab (example)
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
### New catalog entity npm release tab
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Enable npm cards for a catalog entity
|
|
33
|
+
|
|
34
|
+
To enable the different npm cards you must add the `npm/package` annotation
|
|
35
|
+
with the name of the npm package:
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
apiVersion: backstage.io/v1alpha1
|
|
39
|
+
kind: Component
|
|
40
|
+
metadata:
|
|
41
|
+
name: react
|
|
42
|
+
annotations:
|
|
43
|
+
npm/package: react
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Use other npm tag then `latest`
|
|
47
|
+
|
|
48
|
+
The "npm info" card shows the information of the latest 'stable' npm release
|
|
49
|
+
and use the common `latest` tag by default. This could be changed with `npm/stable-tag`:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
# catalog-info.yaml
|
|
53
|
+
apiVersion: backstage.io/v1alpha1
|
|
54
|
+
kind: Component
|
|
55
|
+
metadata:
|
|
56
|
+
name: react
|
|
57
|
+
annotations:
|
|
58
|
+
npm/package: react
|
|
59
|
+
npm/stable-tag: latest, stable, next, etc.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Use a custom registry
|
|
63
|
+
|
|
64
|
+
To use another npm registry you need to specific a registry name in your
|
|
65
|
+
catalog entity that exists in your `app-config.yaml`.
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
# catalog-info.yaml
|
|
69
|
+
apiVersion: backstage.io/v1alpha1
|
|
70
|
+
kind: Component
|
|
71
|
+
metadata:
|
|
72
|
+
name: react
|
|
73
|
+
annotations:
|
|
74
|
+
npm/package: another-package
|
|
75
|
+
npm/registry: github
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# app-config.yaml
|
|
80
|
+
npm:
|
|
81
|
+
registries:
|
|
82
|
+
- name: github
|
|
83
|
+
url: https://npm.pkg.github.com
|
|
84
|
+
token: ghp_...
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
To show information from a private package or an alternative npm registry
|
|
90
|
+
you must install also the backend plugin and [configure it](./registries.md).
|
|
91
|
+
|
|
92
|
+
### Frontend plugin
|
|
93
|
+
|
|
94
|
+
1. Install the frontend dependency:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
yarn workspace app add @backstage-community/plugin-npm
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
2. Add cards based on your needs to `packages/app/src/components/catalog/EntityPage.tsx`:
|
|
101
|
+
|
|
102
|
+
After all other imports:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import {
|
|
106
|
+
isNpmAvailable,
|
|
107
|
+
EntityNpmInfoCard,
|
|
108
|
+
EntityNpmReleaseOverviewCard,
|
|
109
|
+
EntityNpmReleaseTableCard,
|
|
110
|
+
} from '@backstage-community/plugin-npm';
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
3. Add to `const overviewContent` after `EntityAboutCard`:
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
<EntitySwitch>
|
|
117
|
+
<EntitySwitch.Case if={isNpmAvailable}>
|
|
118
|
+
<Grid container item md={6} xs={12}>
|
|
119
|
+
<Grid item md={12}>
|
|
120
|
+
<EntityNpmInfoCard />
|
|
121
|
+
</Grid>
|
|
122
|
+
<Grid item md={12}>
|
|
123
|
+
<EntityNpmReleaseOverviewCard />
|
|
124
|
+
</Grid>
|
|
125
|
+
</Grid>
|
|
126
|
+
</EntitySwitch.Case>
|
|
127
|
+
</EntitySwitch>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
4. Add to `const serviceEntityPage` and `const websiteEntityPage` after the `/ci-cd` case
|
|
131
|
+
and to `const defaultEntityPage` between the `/` and `/docs` routecase.
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
<EntityLayout.Route
|
|
135
|
+
if={isNpmAvailable}
|
|
136
|
+
path="/npm-releases"
|
|
137
|
+
title="NPM Releases"
|
|
138
|
+
>
|
|
139
|
+
<EntityNpmReleaseTableCard />
|
|
140
|
+
</EntityLayout.Route>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Alternative: Use the new frontend system (alpha)
|
|
144
|
+
|
|
145
|
+
For early adaopters of the new frontend system.
|
|
146
|
+
|
|
147
|
+
Your Backstage frontend app must use that new frontend system which isn't the default at the moment.
|
|
148
|
+
|
|
149
|
+
1. Install the frontend dependency:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
yarn workspace app-next add @backstage-community/plugin-npm
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
2. Add the package to your `packages/app[-next]/src/App.tsx`.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import npmPlugin from '@backstage-community/plugin-npm/alpha';
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
And extend your createApp:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
export const app = createApp({
|
|
165
|
+
features: [
|
|
166
|
+
catalogPlugin,
|
|
167
|
+
catalogImportPlugin,
|
|
168
|
+
userSettingsPlugin,
|
|
169
|
+
npmPlugin,
|
|
170
|
+
// ...
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Optional: Backend plugin (req. for private packages or alternative registries)
|
|
176
|
+
|
|
177
|
+
1. Install the backend plugin:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
yarn workspace backend add @backstage-community/plugin-npm
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
2. Add it to `packages/backend/src/index.ts`:
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
backend.add(import('@backstage-community/plugin-npm-backend'));
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
3. The backend is only used for catalog entities with a registry by default.
|
|
190
|
+
|
|
191
|
+
If no `npm/registry` annotation is defined, the npm plugin loads the
|
|
192
|
+
information directly from the frontend.
|
|
193
|
+
(The browser of the user will connect to https://registry.npmjs.com.)
|
|
194
|
+
|
|
195
|
+
You can enforce using the backend by defining a default registry:
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
# app-config.yaml
|
|
199
|
+
# optional to enforce the frontend to use the backend
|
|
200
|
+
npm:
|
|
201
|
+
defaultRegistry: npmjs
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
For more information, please checkout the [Registries](./registries.md) documentation.
|
|
205
|
+
|
|
206
|
+
### Optional: Test with plugin-example catalog entities
|
|
207
|
+
|
|
208
|
+
For testing purpose you can import this catalog entities:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
# catalog-info.yaml
|
|
212
|
+
catalog:
|
|
213
|
+
locations:
|
|
214
|
+
- type: url
|
|
215
|
+
target: https://github.com/backstage/community-plugins/blob/main/workspaces/npm/examples/entities.yaml
|
|
216
|
+
rules:
|
|
217
|
+
- allow: [System, Component]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Registries
|
|
221
|
+
|
|
222
|
+
The npm plugin supports custom and private registries starting with v1.2.
|
|
223
|
+
|
|
224
|
+
### Default Configuration
|
|
225
|
+
|
|
226
|
+
The plugin loads information by default from https://registry.npmjs.com
|
|
227
|
+
|
|
228
|
+
This works without any additional configuration in your `app-config.yaml`
|
|
229
|
+
but only for public npm packages.
|
|
230
|
+
|
|
231
|
+
```yaml
|
|
232
|
+
npm:
|
|
233
|
+
registries:
|
|
234
|
+
- name: npmjs
|
|
235
|
+
url: https://registry.npmjs.com
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Use an auth token for npmjs
|
|
239
|
+
|
|
240
|
+
To load information from another registry or to load information
|
|
241
|
+
from a private package, you must [install the backend](./install.md).
|
|
242
|
+
|
|
243
|
+
The catalog entity `npm/registry` annotation must be defined and match
|
|
244
|
+
one of the registries in the `app-config.yaml`:
|
|
245
|
+
|
|
246
|
+
Example:
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
# catalog-info.yaml
|
|
250
|
+
apiVersion: backstage.io/v1alpha1
|
|
251
|
+
kind: Component
|
|
252
|
+
metadata:
|
|
253
|
+
name: a-component
|
|
254
|
+
annotations:
|
|
255
|
+
npm/package: private-package
|
|
256
|
+
npm/registry: npmjs
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```yaml
|
|
260
|
+
# app-config.yaml
|
|
261
|
+
npm:
|
|
262
|
+
registries:
|
|
263
|
+
- name: npmjs
|
|
264
|
+
url: https://registry.npmjs.com
|
|
265
|
+
token: ...
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
The `npm/registry: npmjs` annotation is required to use the npm backend.
|
|
269
|
+
|
|
270
|
+
Alternativly you can setup a default registry (also for npmjs):
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
# app-config.yaml
|
|
274
|
+
npm:
|
|
275
|
+
defaultRegistry: npmjs
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Use an alternative registry
|
|
279
|
+
|
|
280
|
+
Entity example:
|
|
281
|
+
|
|
282
|
+
```yaml
|
|
283
|
+
# catalog-info.yaml
|
|
284
|
+
apiVersion: backstage.io/v1alpha1
|
|
285
|
+
kind: Component
|
|
286
|
+
metadata:
|
|
287
|
+
name: a-component
|
|
288
|
+
annotations:
|
|
289
|
+
npm/package: private-package
|
|
290
|
+
npm/registry: private-registry
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
```yaml
|
|
294
|
+
# app-config.yaml
|
|
295
|
+
npm:
|
|
296
|
+
registries:
|
|
297
|
+
- name: private-registry
|
|
298
|
+
url: https://...
|
|
299
|
+
token: ...
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Use GitHub npm registry
|
|
303
|
+
|
|
304
|
+
The GitHub npm registry reqires also a GitHub token for public entries.
|
|
305
|
+
|
|
306
|
+
You need to create a token at https://github.com/settings/tokens
|
|
307
|
+
|
|
308
|
+
```yaml
|
|
309
|
+
# app-config.yaml
|
|
310
|
+
npm:
|
|
311
|
+
registries:
|
|
312
|
+
- name: github
|
|
313
|
+
url: https://npm.pkg.github.com
|
|
314
|
+
token: ghp_...
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Other npm registries
|
|
318
|
+
|
|
319
|
+
Other npm registries should work the same way.
|
|
320
|
+
|
|
321
|
+
Please let us know if we should mention here another registry or
|
|
322
|
+
if you find any issue.
|
|
323
|
+
|
|
324
|
+
You can create a new [Issues on GitHub](https://github.com/backstage/community-plugins/issues/new?assignees=&labels=bug&projects=&template=1-bug.yaml&title=🐛+Npm%3A+<Title>)
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
export interface Config {
|
|
17
|
+
npm?: {
|
|
18
|
+
/**
|
|
19
|
+
* Use another default registry. This automatically enforce usage of the backend.
|
|
20
|
+
*
|
|
21
|
+
* @visibility frontend
|
|
22
|
+
*/
|
|
23
|
+
defaultRegistry?: string;
|
|
24
|
+
/**
|
|
25
|
+
* List of registries that can be used to fetch packages from
|
|
26
|
+
*/
|
|
27
|
+
registries?: {
|
|
28
|
+
/**
|
|
29
|
+
* Registry name
|
|
30
|
+
*/
|
|
31
|
+
name?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Registry base url
|
|
34
|
+
*/
|
|
35
|
+
url?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Registry auth token
|
|
38
|
+
* @visibility secret
|
|
39
|
+
*/
|
|
40
|
+
token?: string;
|
|
41
|
+
}[];
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var alpha = require('@backstage/plugin-catalog-node/alpha');
|
|
5
|
+
var router = require('./router.cjs.js');
|
|
6
|
+
var NpmRegistryServiceImpl = require('./services/NpmRegistryServiceImpl.cjs.js');
|
|
7
|
+
|
|
8
|
+
const npmPlugin = backendPluginApi.createBackendPlugin({
|
|
9
|
+
pluginId: "npm",
|
|
10
|
+
register(env) {
|
|
11
|
+
env.registerInit({
|
|
12
|
+
deps: {
|
|
13
|
+
logger: backendPluginApi.coreServices.logger,
|
|
14
|
+
auth: backendPluginApi.coreServices.auth,
|
|
15
|
+
config: backendPluginApi.coreServices.rootConfig,
|
|
16
|
+
httpAuth: backendPluginApi.coreServices.httpAuth,
|
|
17
|
+
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
18
|
+
catalog: alpha.catalogServiceRef
|
|
19
|
+
},
|
|
20
|
+
async init({ logger, auth, config, httpAuth, httpRouter, catalog }) {
|
|
21
|
+
const npmRegistryService = new NpmRegistryServiceImpl.NpmRegistryServiceImpl({
|
|
22
|
+
logger,
|
|
23
|
+
auth,
|
|
24
|
+
config,
|
|
25
|
+
catalog
|
|
26
|
+
});
|
|
27
|
+
httpRouter.use(
|
|
28
|
+
await router.createRouter({
|
|
29
|
+
httpAuth,
|
|
30
|
+
npmRegistryService
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
exports.npmPlugin = npmPlugin;
|
|
39
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.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 */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\n\nimport { createRouter } from './router';\nimport { NpmRegistryServiceImpl } from './services/NpmRegistryServiceImpl';\n\n/**\n * npmPlugin backend plugin\n *\n * @public\n */\nexport const npmPlugin = createBackendPlugin({\n pluginId: 'npm',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n auth: coreServices.auth,\n config: coreServices.rootConfig,\n httpAuth: coreServices.httpAuth,\n httpRouter: coreServices.httpRouter,\n catalog: catalogServiceRef,\n },\n async init({ logger, auth, config, httpAuth, httpRouter, catalog }) {\n const npmRegistryService = new NpmRegistryServiceImpl({\n logger,\n auth,\n config,\n catalog,\n });\n\n httpRouter.use(\n await createRouter({\n httpAuth,\n npmRegistryService,\n }),\n );\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","catalogServiceRef","NpmRegistryServiceImpl","createRouter"],"mappings":";;;;;;;AA6BO,MAAM,YAAYA,oCAAoB,CAAA;AAAA,EAC3C,QAAU,EAAA,KAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,MAAA;AAAA,QACrB,MAAMA,6BAAa,CAAA,IAAA;AAAA,QACnB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,OAAS,EAAAC;AAAA,OACX;AAAA,MACA,MAAM,KAAK,EAAE,MAAA,EAAQ,MAAM,MAAQ,EAAA,QAAA,EAAU,UAAY,EAAA,OAAA,EAAW,EAAA;AAClE,QAAM,MAAA,kBAAA,GAAqB,IAAIC,6CAAuB,CAAA;AAAA,UACpD,MAAA;AAAA,UACA,IAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,QAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AAAA;AACF,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
var express = require('express');
|
|
5
|
+
var Router = require('express-promise-router');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
10
|
+
var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
11
|
+
|
|
12
|
+
async function createRouter({
|
|
13
|
+
httpAuth,
|
|
14
|
+
npmRegistryService
|
|
15
|
+
}) {
|
|
16
|
+
const router = Router__default.default();
|
|
17
|
+
router.use(express__default.default.json());
|
|
18
|
+
router.get("/:entityRef/package-info", async (req, res) => {
|
|
19
|
+
const entityRef = req.params.entityRef;
|
|
20
|
+
const credentials = await httpAuth.credentials(req, { allow: ["user"] });
|
|
21
|
+
try {
|
|
22
|
+
const packageInfo = await npmRegistryService.getPackageInfo(entityRef, {
|
|
23
|
+
credentials
|
|
24
|
+
});
|
|
25
|
+
res.json(packageInfo);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error instanceof errors.ResponseError) {
|
|
28
|
+
res.status(error.statusCode).json(error.response);
|
|
29
|
+
} else {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return router;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.createRouter = createRouter;
|
|
38
|
+
//# sourceMappingURL=router.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../src/router.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 */\nimport { HttpAuthService } from '@backstage/backend-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { NpmRegistryService } from './services';\n\nexport async function createRouter({\n httpAuth,\n npmRegistryService,\n}: {\n httpAuth: HttpAuthService;\n npmRegistryService: NpmRegistryService;\n}): Promise<express.Router> {\n const router = Router();\n router.use(express.json());\n\n router.get('/:entityRef/package-info', async (req, res) => {\n const entityRef = req.params.entityRef;\n const credentials = await httpAuth.credentials(req, { allow: ['user'] });\n try {\n const packageInfo = await npmRegistryService.getPackageInfo(entityRef, {\n credentials,\n });\n res.json(packageInfo);\n } catch (error) {\n if (error instanceof ResponseError) {\n res.status(error.statusCode).json(error.response);\n } else {\n throw error;\n }\n }\n });\n\n return router;\n}\n"],"names":["Router","express","ResponseError"],"mappings":";;;;;;;;;;;AAqBA,eAAsB,YAAa,CAAA;AAAA,EACjC,QAAA;AAAA,EACA;AACF,CAG4B,EAAA;AAC1B,EAAA,MAAM,SAASA,uBAAO,EAAA;AACtB,EAAO,MAAA,CAAA,GAAA,CAAIC,wBAAQ,CAAA,IAAA,EAAM,CAAA;AAEzB,EAAA,MAAA,CAAO,GAAI,CAAA,0BAAA,EAA4B,OAAO,GAAA,EAAK,GAAQ,KAAA;AACzD,IAAM,MAAA,SAAA,GAAY,IAAI,MAAO,CAAA,SAAA;AAC7B,IAAM,MAAA,WAAA,GAAc,MAAM,QAAA,CAAS,WAAY,CAAA,GAAA,EAAK,EAAE,KAAO,EAAA,CAAC,MAAM,CAAA,EAAG,CAAA;AACvE,IAAI,IAAA;AACF,MAAA,MAAM,WAAc,GAAA,MAAM,kBAAmB,CAAA,cAAA,CAAe,SAAW,EAAA;AAAA,QACrE;AAAA,OACD,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,WAAW,CAAA;AAAA,aACb,KAAO,EAAA;AACd,MAAA,IAAI,iBAAiBC,oBAAe,EAAA;AAClC,QAAA,GAAA,CAAI,OAAO,KAAM,CAAA,UAAU,CAAE,CAAA,IAAA,CAAK,MAAM,QAAQ,CAAA;AAAA,OAC3C,MAAA;AACL,QAAM,MAAA,KAAA;AAAA;AACR;AACF,GACD,CAAA;AAED,EAAO,OAAA,MAAA;AACT;;;;"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
var pluginNpmCommon = require('@backstage-community/plugin-npm-common');
|
|
5
|
+
|
|
6
|
+
class NpmRegistryServiceImpl {
|
|
7
|
+
logger;
|
|
8
|
+
auth;
|
|
9
|
+
config;
|
|
10
|
+
catalog;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.logger = options.logger;
|
|
13
|
+
this.auth = options.auth;
|
|
14
|
+
this.config = options.config;
|
|
15
|
+
this.catalog = options.catalog;
|
|
16
|
+
}
|
|
17
|
+
async getPackageInfo(entityRef, options) {
|
|
18
|
+
const { token } = await this.auth.getPluginRequestToken({
|
|
19
|
+
onBehalfOf: options.credentials,
|
|
20
|
+
targetPluginId: "catalog"
|
|
21
|
+
});
|
|
22
|
+
const entity = await this.catalog.getEntityByRef(entityRef, {
|
|
23
|
+
token
|
|
24
|
+
});
|
|
25
|
+
if (!entity) {
|
|
26
|
+
throw new errors.NotFoundError(`No entity found for ref '${entityRef}'`);
|
|
27
|
+
}
|
|
28
|
+
const config = this.config.getOptional("npm");
|
|
29
|
+
const defaultRegistry = config?.defaultRegistry;
|
|
30
|
+
const packageName = entity.metadata.annotations?.[pluginNpmCommon.NpmAnnotation.PACKAGE_NAME];
|
|
31
|
+
const registryName = entity.metadata.annotations?.[pluginNpmCommon.NpmAnnotation.REGISTRY_NAME] || defaultRegistry;
|
|
32
|
+
if (!packageName) {
|
|
33
|
+
throw new errors.NotFoundError(
|
|
34
|
+
`Npm package name not defined at entity '${entityRef}'`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const registry = config?.registries?.find((r) => r.name === registryName);
|
|
38
|
+
if (!registry && registryName !== "default" && registryName !== "npmjs") {
|
|
39
|
+
throw new errors.NotFoundError(
|
|
40
|
+
`Npm registry config '${registryName}' not found as defined in entity '${entityRef}'`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
this.logger.info("Will use npmjs package info:", {
|
|
44
|
+
entityRef,
|
|
45
|
+
packageName,
|
|
46
|
+
registryUrl: registry?.url,
|
|
47
|
+
registryToken: registry?.token ? "yes" : "no"
|
|
48
|
+
});
|
|
49
|
+
const client = new pluginNpmCommon.NpmRegistryClient({
|
|
50
|
+
// TODO pass apiFetch.fetch
|
|
51
|
+
baseUrl: registry?.url,
|
|
52
|
+
token: registry?.token
|
|
53
|
+
});
|
|
54
|
+
const packageInfo = await client.getPackageInfo(packageName);
|
|
55
|
+
return packageInfo;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
exports.NpmRegistryServiceImpl = NpmRegistryServiceImpl;
|
|
60
|
+
//# sourceMappingURL=NpmRegistryServiceImpl.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NpmRegistryServiceImpl.cjs.js","sources":["../../src/services/NpmRegistryServiceImpl.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 */\nimport {\n AuthService,\n BackstageCredentials,\n BackstageUserPrincipal,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { NotFoundError } from '@backstage/errors';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\n\nimport {\n NpmAnnotation,\n NpmRegistryClient,\n NpmRegistryPackageInfo,\n} from '@backstage-community/plugin-npm-common';\n\nimport { NpmRegistryService } from './NpmRegistryService';\nimport { Config } from '../../config';\n\nexport type Options = {\n logger: LoggerService;\n auth: AuthService;\n config: RootConfigService;\n // TODO update CatalogService\n catalog: typeof catalogServiceRef.T;\n};\n\nexport class NpmRegistryServiceImpl implements NpmRegistryService {\n private readonly logger: LoggerService;\n private readonly auth: AuthService;\n private readonly config: RootConfigService;\n private readonly catalog: typeof catalogServiceRef.T;\n\n constructor(options: Options) {\n this.logger = options.logger;\n this.auth = options.auth;\n this.config = options.config;\n this.catalog = options.catalog;\n }\n\n async getPackageInfo(\n entityRef: string,\n options: { credentials: BackstageCredentials<BackstageUserPrincipal> },\n ): Promise<NpmRegistryPackageInfo> {\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: options.credentials,\n targetPluginId: 'catalog',\n });\n const entity = await this.catalog.getEntityByRef(entityRef, {\n token,\n });\n if (!entity) {\n throw new NotFoundError(`No entity found for ref '${entityRef}'`);\n }\n\n const config = this.config.getOptional<Config['npm']>('npm');\n const defaultRegistry = config?.defaultRegistry;\n\n const packageName =\n entity.metadata.annotations?.[NpmAnnotation.PACKAGE_NAME];\n const registryName =\n entity.metadata.annotations?.[NpmAnnotation.REGISTRY_NAME] ||\n defaultRegistry;\n if (!packageName) {\n throw new NotFoundError(\n `Npm package name not defined at entity '${entityRef}'`,\n );\n }\n\n const registry = config?.registries?.find(r => r.name === registryName);\n if (!registry && registryName !== 'default' && registryName !== 'npmjs') {\n throw new NotFoundError(\n `Npm registry config '${registryName}' not found as defined in entity '${entityRef}'`,\n );\n }\n\n this.logger.info('Will use npmjs package info:', {\n entityRef,\n packageName,\n registryUrl: registry?.url,\n registryToken: registry?.token ? 'yes' : 'no',\n });\n\n const client = new NpmRegistryClient({\n // TODO pass apiFetch.fetch\n baseUrl: registry?.url,\n token: registry?.token,\n });\n const packageInfo = await client.getPackageInfo(packageName);\n return packageInfo;\n }\n}\n"],"names":["NotFoundError","NpmAnnotation","NpmRegistryClient"],"mappings":";;;;;AA0CO,MAAM,sBAAqD,CAAA;AAAA,EAC/C,MAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EAEjB,YAAY,OAAkB,EAAA;AAC5B,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,OAAO,OAAQ,CAAA,IAAA;AACpB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,UAAU,OAAQ,CAAA,OAAA;AAAA;AACzB,EAEA,MAAM,cACJ,CAAA,SAAA,EACA,OACiC,EAAA;AACjC,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,KAAK,qBAAsB,CAAA;AAAA,MACtD,YAAY,OAAQ,CAAA,WAAA;AAAA,MACpB,cAAgB,EAAA;AAAA,KACjB,CAAA;AACD,IAAA,MAAM,MAAS,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,eAAe,SAAW,EAAA;AAAA,MAC1D;AAAA,KACD,CAAA;AACD,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAA,MAAM,IAAIA,oBAAA,CAAc,CAA4B,yBAAA,EAAA,SAAS,CAAG,CAAA,CAAA,CAAA;AAAA;AAGlE,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,MAAO,CAAA,WAAA,CAA2B,KAAK,CAAA;AAC3D,IAAA,MAAM,kBAAkB,MAAQ,EAAA,eAAA;AAEhC,IAAA,MAAM,WACJ,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAcC,8BAAc,YAAY,CAAA;AAC1D,IAAA,MAAM,eACJ,MAAO,CAAA,QAAA,CAAS,WAAc,GAAAA,6BAAA,CAAc,aAAa,CACzD,IAAA,eAAA;AACF,IAAA,IAAI,CAAC,WAAa,EAAA;AAChB,MAAA,MAAM,IAAID,oBAAA;AAAA,QACR,2CAA2C,SAAS,CAAA,CAAA;AAAA,OACtD;AAAA;AAGF,IAAA,MAAM,WAAW,MAAQ,EAAA,UAAA,EAAY,KAAK,CAAK,CAAA,KAAA,CAAA,CAAE,SAAS,YAAY,CAAA;AACtE,IAAA,IAAI,CAAC,QAAA,IAAY,YAAiB,KAAA,SAAA,IAAa,iBAAiB,OAAS,EAAA;AACvE,MAAA,MAAM,IAAIA,oBAAA;AAAA,QACR,CAAA,qBAAA,EAAwB,YAAY,CAAA,kCAAA,EAAqC,SAAS,CAAA,CAAA;AAAA,OACpF;AAAA;AAGF,IAAK,IAAA,CAAA,MAAA,CAAO,KAAK,8BAAgC,EAAA;AAAA,MAC/C,SAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAa,QAAU,EAAA,GAAA;AAAA,MACvB,aAAA,EAAe,QAAU,EAAA,KAAA,GAAQ,KAAQ,GAAA;AAAA,KAC1C,CAAA;AAED,IAAM,MAAA,MAAA,GAAS,IAAIE,iCAAkB,CAAA;AAAA;AAAA,MAEnC,SAAS,QAAU,EAAA,GAAA;AAAA,MACnB,OAAO,QAAU,EAAA;AAAA,KAClB,CAAA;AACD,IAAA,MAAM,WAAc,GAAA,MAAM,MAAO,CAAA,cAAA,CAAe,WAAW,CAAA;AAC3D,IAAO,OAAA,WAAA;AAAA;AAEX;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backstage-community/plugin-npm-backend",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"main": "dist/index.cjs.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public",
|
|
9
|
+
"main": "dist/index.cjs.js",
|
|
10
|
+
"types": "dist/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"backstage": {
|
|
13
|
+
"role": "backend-plugin",
|
|
14
|
+
"supported-versions": "1.28.0",
|
|
15
|
+
"pluginId": "npm",
|
|
16
|
+
"pluginPackage": "@backstage-community/plugin-npm-backend",
|
|
17
|
+
"pluginPackages": [
|
|
18
|
+
"@backstage-community/plugin-npm",
|
|
19
|
+
"@backstage-community/plugin-npm-backend",
|
|
20
|
+
"@backstage-community/plugin-npm-common"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"start": "backstage-cli package start",
|
|
25
|
+
"build": "backstage-cli package build",
|
|
26
|
+
"lint": "backstage-cli package lint",
|
|
27
|
+
"test": "backstage-cli package test",
|
|
28
|
+
"clean": "backstage-cli package clean",
|
|
29
|
+
"prepack": "backstage-cli package prepack",
|
|
30
|
+
"postpack": "backstage-cli package postpack"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@backstage-community/plugin-npm-common": "^1.1.0",
|
|
34
|
+
"@backstage/backend-defaults": "^0.5.1",
|
|
35
|
+
"@backstage/backend-plugin-api": "^1.0.1",
|
|
36
|
+
"@backstage/catalog-client": "^1.7.1",
|
|
37
|
+
"@backstage/errors": "^1.2.4",
|
|
38
|
+
"@backstage/plugin-catalog-node": "^1.13.1",
|
|
39
|
+
"express": "^4.17.1",
|
|
40
|
+
"express-promise-router": "^4.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@backstage/backend-test-utils": "^1.0.1",
|
|
44
|
+
"@backstage/cli": "^0.28.0",
|
|
45
|
+
"@types/express": "*",
|
|
46
|
+
"@types/supertest": "^2.0.12",
|
|
47
|
+
"supertest": "^6.2.4"
|
|
48
|
+
},
|
|
49
|
+
"files": [
|
|
50
|
+
"config.d.ts",
|
|
51
|
+
"dist"
|
|
52
|
+
],
|
|
53
|
+
"configSchema": "config.d.ts",
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "https://github.com/backstage/community-plugins",
|
|
57
|
+
"directory": "workspaces/npm/plugins/npm-backend"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"backstage",
|
|
61
|
+
"plugin",
|
|
62
|
+
"npm"
|
|
63
|
+
],
|
|
64
|
+
"homepage": "https://github.com/backstage/community-plugins/tree/main/workspaces/npm/plugins/npm-backend",
|
|
65
|
+
"bugs": "https://github.com/backstage/community-plugins/issues",
|
|
66
|
+
"maintainers": [
|
|
67
|
+
"jerolimov",
|
|
68
|
+
"karthikjeeyar"
|
|
69
|
+
],
|
|
70
|
+
"author": "Christoph Jerolimov"
|
|
71
|
+
}
|