@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 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
+ ![Screenshot](https://raw.githubusercontent.com/backstage/community-plugins/main/workspaces/npm/docs/npm-info-card.png)
17
+
18
+ ### Npm release overview card
19
+
20
+ ![Screenshot](https://raw.githubusercontent.com/backstage/community-plugins/main/workspaces/npm/docs/npm-release-overview-card.png)
21
+
22
+ ### Extended catalog entity overview tab (example)
23
+
24
+ ![Screenshot](https://raw.githubusercontent.com/backstage/community-plugins/main/workspaces/npm/docs/catalog-entity-overview-tab.png)
25
+
26
+ ### New catalog entity npm release tab
27
+
28
+ ![Screenshot](https://raw.githubusercontent.com/backstage/community-plugins/main/workspaces/npm/docs/catalog-entity-npm-release-tab.png)
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,10 @@
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.npmPlugin;
10
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -0,0 +1,10 @@
1
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
+
3
+ /**
4
+ * npmPlugin backend plugin
5
+ *
6
+ * @public
7
+ */
8
+ declare const npmPlugin: _backstage_backend_plugin_api.BackendFeature;
9
+
10
+ export { npmPlugin as default };
@@ -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
+ }