@axis-backstage/plugin-readme-backend 0.9.1 → 0.10.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/dist/index.cjs.js CHANGED
@@ -2,12 +2,15 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
6
+ var cache = require('@backstage/backend-defaults/cache');
5
7
  var backendCommon = require('@backstage/backend-common');
6
- var express = require('express');
7
- var Router = require('express-promise-router');
8
8
  var integration = require('@backstage/integration');
9
9
  var catalogModel = require('@backstage/catalog-model');
10
10
  var catalogClient = require('@backstage/catalog-client');
11
+ var errors = require('@backstage/errors');
12
+ var express = require('express');
13
+ var Router = require('express-promise-router');
11
14
  var backendPluginApi = require('@backstage/backend-plugin-api');
12
15
 
13
16
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -37,8 +40,8 @@ async function createRouter(options) {
37
40
  const { logger, config, reader, discovery } = options;
38
41
  const { auth } = backendCommon.createLegacyAuthAdapters(options);
39
42
  const catalogClient$1 = new catalogClient.CatalogClient({ discoveryApi: discovery });
40
- const pluginCache = backendCommon.CacheManager.fromConfig(config).forPlugin("readme");
41
- const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });
43
+ const pluginCache = cache.CacheManager.fromConfig(config).forPlugin("readme");
44
+ const cache$1 = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });
42
45
  logger.info("Initializing readme backend");
43
46
  const integrations = integration.ScmIntegrations.fromConfig(config);
44
47
  const router = Router__default.default();
@@ -49,7 +52,7 @@ async function createRouter(options) {
49
52
  router.get("/:kind/:namespace/:name", async (request, response) => {
50
53
  const { kind, namespace, name } = request.params;
51
54
  const entityRef = catalogModel.stringifyEntityRef({ kind, namespace, name });
52
- const cacheDoc = await cache.get(entityRef);
55
+ const cacheDoc = await cache$1.get(entityRef);
53
56
  if (cacheDoc) {
54
57
  logger.info(`Loading README for ${entityRef} from cache.`);
55
58
  response.type(cacheDoc.type);
@@ -68,11 +71,9 @@ async function createRouter(options) {
68
71
  }
69
72
  const source = catalogModel.getEntitySourceLocation(entity);
70
73
  if (!source || source.type !== "url") {
71
- logger.info(`Not valid location for ${source.target}`);
72
- response.status(404).json({
73
- error: `Not valid location for ${source.target}`
74
- });
75
- return;
74
+ const errorMessage = `Not valid location for ${source.target}`;
75
+ logger.info(errorMessage);
76
+ throw new errors.NotFoundError(errorMessage);
76
77
  }
77
78
  const integration = integrations.byUrl(source.target);
78
79
  if (!integration) {
@@ -99,7 +100,7 @@ async function createRouter(options) {
99
100
  const symLinkUrlResponse = await reader.readUrl(symLinkUrl);
100
101
  content = (await symLinkUrlResponse.buffer()).toString("utf-8");
101
102
  }
102
- cache.set(entityRef, {
103
+ cache$1.set(entityRef, {
103
104
  name: fileType.name,
104
105
  type: fileType.type,
105
106
  content
@@ -107,7 +108,7 @@ async function createRouter(options) {
107
108
  response.send(content);
108
109
  return;
109
110
  } catch (error) {
110
- if (error instanceof Error && error.name === "NotFoundError") {
111
+ if (errors.isError(error) && error.name === "NotFoundError") {
111
112
  continue;
112
113
  } else {
113
114
  response.status(500).json({
@@ -118,11 +119,10 @@ async function createRouter(options) {
118
119
  }
119
120
  }
120
121
  logger.info(`Readme not found for ${entityRef}`);
121
- response.status(404).json({
122
- error: "Readme not found."
123
- });
122
+ throw new errors.NotFoundError("Readme could not be found");
124
123
  });
125
- router.use(backendCommon.errorHandler());
124
+ const middleware = rootHttpRouter.MiddlewareFactory.create({ logger, config });
125
+ router.use(middleware.error());
126
126
  return router;
127
127
  }
128
128
 
@@ -136,26 +136,16 @@ const readmePlugin = backendPluginApi.createBackendPlugin({
136
136
  reader: backendPluginApi.coreServices.urlReader,
137
137
  discovery: backendPluginApi.coreServices.discovery,
138
138
  auth: backendPluginApi.coreServices.auth,
139
- tokenManager: backendPluginApi.coreServices.tokenManager,
140
139
  httpRouter: backendPluginApi.coreServices.httpRouter
141
140
  },
142
- async init({
143
- auth,
144
- logger,
145
- config,
146
- reader,
147
- discovery,
148
- tokenManager,
149
- httpRouter
150
- }) {
141
+ async init({ auth, logger, config, reader, discovery, httpRouter }) {
151
142
  httpRouter.use(
152
143
  await createRouter({
153
144
  auth,
154
145
  logger,
155
146
  config,
156
147
  reader,
157
- discovery,
158
- tokenManager
148
+ discovery
159
149
  })
160
150
  );
161
151
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/lib.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["const DETECT_SYMLINKS_REGEX = '^(w+|.|/|-)+$';\n\nexport const isSymLink = (content: string): boolean => {\n const lines = content.split('\\n');\n if (lines.length > 1) return false;\n const line = lines[0];\n if (line.includes(' ')) return false;\n\n const regex = RegExp(DETECT_SYMLINKS_REGEX);\n return regex.test(content);\n};\n","import { errorHandler } from '@backstage/backend-common';\nimport {\n AuthService,\n DiscoveryService,\n LoggerService,\n UrlReaderService,\n TokenManagerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport {\n CacheManager,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n getEntitySourceLocation,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { isSymLink } from '../lib';\n\n/**\n * Constructs a readme router.\n * @public\n */\nexport interface RouterOptions {\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Backstage url reader instance\n */\n reader: UrlReaderService;\n /**\n * Backstage discovery service\n */\n discovery: DiscoveryService;\n /**\n * Backstage token manager service\n */\n tokenManager: TokenManagerService;\n /**\n * Backstage auth service\n */\n auth?: AuthService;\n}\n\nconst DEFAULT_TTL = 1800 * 1000;\n\ninterface FileType {\n name: string;\n type: string;\n}\ninterface ReadmeFile extends FileType {\n content: string;\n}\n\nconst README_TYPES: FileType[] = [\n { name: 'README', type: 'text/plain' },\n { name: 'README.md', type: 'text/markdown' },\n { name: 'README.rst', type: 'text/plain' },\n { name: 'README.txt', type: 'text/plain' },\n { name: 'README.MD', type: 'text/markdown' },\n];\n\n/**\n * Constructs a readme router.\n *\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, reader, discovery } = options;\n const { auth } = createLegacyAuthAdapters(options);\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n const pluginCache = CacheManager.fromConfig(config).forPlugin('readme');\n const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });\n\n logger.info('Initializing readme backend');\n const integrations = ScmIntegrations.fromConfig(config);\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n router.get('/:kind/:namespace/:name', async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const cacheDoc = (await cache.get(entityRef)) as ReadmeFile | undefined;\n\n if (cacheDoc) {\n logger.info(`Loading README for ${entityRef} from cache.`);\n response.type(cacheDoc.type);\n response.send(cacheDoc.content);\n return;\n }\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n if (!entity) {\n logger.info(`No integration found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No integration found for ${entityRef}` });\n return;\n }\n const source = getEntitySourceLocation(entity);\n\n if (!source || source.type !== 'url') {\n logger.info(`Not valid location for ${source.target}`);\n response.status(404).json({\n error: `Not valid location for ${source.target}`,\n });\n return;\n }\n const integration = integrations.byUrl(source.target);\n\n if (!integration) {\n logger.info(`No integration found for ${source.target}`);\n response\n .status(500)\n .json({ error: `No integration found for ${source.target}` });\n return;\n }\n\n for (const fileType of README_TYPES) {\n const url = integration.resolveUrl({\n url: fileType.name,\n base: source.target,\n });\n\n let content;\n\n try {\n logger.info(`Fetch README ${entityRef}: ${url}, ${fileType.type} `);\n response.type(fileType.type);\n\n const urlResponse = await reader.readUrl(url);\n content = (await urlResponse.buffer()).toString('utf-8');\n\n if (isSymLink(content)) {\n const symLinkUrl = integration.resolveUrl({\n url: content,\n base: source.target,\n });\n const symLinkUrlResponse = await reader.readUrl(symLinkUrl);\n content = (await symLinkUrlResponse.buffer()).toString('utf-8');\n }\n\n cache.set(entityRef, {\n name: fileType.name,\n type: fileType.type,\n content: content,\n });\n response.send(content);\n return;\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'NotFoundError') {\n // Try the next readme type\n continue;\n } else {\n response.status(500).json({\n error: `Readme failure: ${error}`,\n });\n return;\n }\n }\n }\n logger.info(`Readme not found for ${entityRef}`);\n response.status(404).json({\n error: 'Readme not found.',\n });\n });\n\n router.use(errorHandler());\n return router;\n}\n","import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * The Readme backend plugin.\n *\n * @public\n */\nexport const readmePlugin = createBackendPlugin({\n pluginId: 'readme',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n tokenManager: coreServices.tokenManager,\n httpRouter: coreServices.httpRouter,\n },\n async init({\n auth,\n logger,\n config,\n reader,\n discovery,\n tokenManager,\n httpRouter,\n }) {\n httpRouter.use(\n await createRouter({\n auth,\n logger,\n config,\n reader,\n discovery,\n tokenManager,\n }),\n );\n },\n });\n },\n});\n"],"names":["createLegacyAuthAdapters","catalogClient","CatalogClient","CacheManager","ScmIntegrations","Router","express","stringifyEntityRef","getEntitySourceLocation","errorHandler","createBackendPlugin","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/lib.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["const DETECT_SYMLINKS_REGEX = '^(w+|.|/|-)+$';\n\nexport const isSymLink = (content: string): boolean => {\n const lines = content.split('\\n');\n if (lines.length > 1) return false;\n const line = lines[0];\n if (line.includes(' ')) return false;\n\n const regex = RegExp(DETECT_SYMLINKS_REGEX);\n return regex.test(content);\n};\n","import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { CacheManager } from '@backstage/backend-defaults/cache';\nimport {\n AuthService,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n UrlReaderService,\n TokenManagerService,\n} from '@backstage/backend-plugin-api';\nimport { createLegacyAuthAdapters } from '@backstage/backend-common';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n getEntitySourceLocation,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { isError, NotFoundError } from '@backstage/errors';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { isSymLink } from '../lib';\n\n/**\n * Constructs a readme router.\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport interface RouterOptions {\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n\n /**\n * Backstage config object\n */\n config: RootConfigService;\n\n /**\n * Backstage url reader instance\n */\n reader: UrlReaderService;\n /**\n * Backstage discovery service\n */\n discovery: DiscoveryService;\n /**\n * Backstage token manager service\n */\n tokenManager?: TokenManagerService;\n /**\n * Backstage auth service\n */\n auth?: AuthService;\n}\n\nconst DEFAULT_TTL = 1800 * 1000;\n\ninterface FileType {\n name: string;\n type: string;\n}\ninterface ReadmeFile extends FileType {\n content: string;\n}\n\nconst README_TYPES: FileType[] = [\n { name: 'README', type: 'text/plain' },\n { name: 'README.md', type: 'text/markdown' },\n { name: 'README.rst', type: 'text/plain' },\n { name: 'README.txt', type: 'text/plain' },\n { name: 'README.MD', type: 'text/markdown' },\n];\n\n/**\n * Constructs a readme router.\n *\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, reader, discovery } = options;\n const { auth } = createLegacyAuthAdapters(options);\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n const pluginCache = CacheManager.fromConfig(config).forPlugin('readme');\n const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });\n\n logger.info('Initializing readme backend');\n const integrations = ScmIntegrations.fromConfig(config);\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n router.get('/:kind/:namespace/:name', async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const cacheDoc = (await cache.get(entityRef)) as ReadmeFile | undefined;\n\n if (cacheDoc) {\n logger.info(`Loading README for ${entityRef} from cache.`);\n response.type(cacheDoc.type);\n response.send(cacheDoc.content);\n return;\n }\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n if (!entity) {\n logger.info(`No integration found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No integration found for ${entityRef}` });\n return;\n }\n const source = getEntitySourceLocation(entity);\n\n if (!source || source.type !== 'url') {\n const errorMessage = `Not valid location for ${source.target}`;\n logger.info(errorMessage);\n throw new NotFoundError(errorMessage);\n }\n const integration = integrations.byUrl(source.target);\n\n if (!integration) {\n logger.info(`No integration found for ${source.target}`);\n response\n .status(500)\n .json({ error: `No integration found for ${source.target}` });\n return;\n }\n\n for (const fileType of README_TYPES) {\n const url = integration.resolveUrl({\n url: fileType.name,\n base: source.target,\n });\n\n let content;\n\n try {\n logger.info(`Fetch README ${entityRef}: ${url}, ${fileType.type} `);\n response.type(fileType.type);\n\n const urlResponse = await reader.readUrl(url);\n content = (await urlResponse.buffer()).toString('utf-8');\n\n if (isSymLink(content)) {\n const symLinkUrl = integration.resolveUrl({\n url: content,\n base: source.target,\n });\n const symLinkUrlResponse = await reader.readUrl(symLinkUrl);\n content = (await symLinkUrlResponse.buffer()).toString('utf-8');\n }\n\n cache.set(entityRef, {\n name: fileType.name,\n type: fileType.type,\n content: content,\n });\n response.send(content);\n return;\n } catch (error: unknown) {\n if (isError(error) && error.name === 'NotFoundError') {\n continue;\n } else {\n response.status(500).json({\n error: `Readme failure: ${error}`,\n });\n return;\n }\n }\n }\n logger.info(`Readme not found for ${entityRef}`);\n throw new NotFoundError('Readme could not be found');\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n router.use(middleware.error());\n return router;\n}\n","import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * The Readme backend plugin.\n *\n * @public\n */\nexport const readmePlugin = createBackendPlugin({\n pluginId: 'readme',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n httpRouter: coreServices.httpRouter,\n },\n async init({ auth, logger, config, reader, discovery, httpRouter }) {\n httpRouter.use(\n await createRouter({\n auth,\n logger,\n config,\n reader,\n discovery,\n }),\n );\n },\n });\n },\n});\n"],"names":["createLegacyAuthAdapters","catalogClient","CatalogClient","CacheManager","cache","ScmIntegrations","Router","express","stringifyEntityRef","getEntitySourceLocation","NotFoundError","isError","MiddlewareFactory","createBackendPlugin","coreServices"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
- import { LoggerService, UrlReaderService, DiscoveryService, TokenManagerService, AuthService } from '@backstage/backend-plugin-api';
3
- import { Config } from '@backstage/config';
2
+ import { LoggerService, RootConfigService, UrlReaderService, DiscoveryService, TokenManagerService, AuthService } from '@backstage/backend-plugin-api';
4
3
  import express from 'express';
5
4
 
6
5
  /**
7
6
  * Constructs a readme router.
7
+ * @deprecated Please migrate to the new backend system as this will be removed in the future.
8
8
  * @public
9
9
  */
10
10
  interface RouterOptions {
@@ -15,7 +15,7 @@ interface RouterOptions {
15
15
  /**
16
16
  * Backstage config object
17
17
  */
18
- config: Config;
18
+ config: RootConfigService;
19
19
  /**
20
20
  * Backstage url reader instance
21
21
  */
@@ -27,7 +27,7 @@ interface RouterOptions {
27
27
  /**
28
28
  * Backstage token manager service
29
29
  */
30
- tokenManager: TokenManagerService;
30
+ tokenManager?: TokenManagerService;
31
31
  /**
32
32
  * Backstage auth service
33
33
  */
@@ -36,6 +36,7 @@ interface RouterOptions {
36
36
  /**
37
37
  * Constructs a readme router.
38
38
  *
39
+ * @deprecated Please migrate to the new backend system as this will be removed in the future.
39
40
  * @public
40
41
  */
41
42
  declare function createRouter(options: RouterOptions): Promise<express.Router>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-backstage/plugin-readme-backend",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -33,16 +33,14 @@
33
33
  "@backstage/backend-plugin-api": "^0.8.0",
34
34
  "@backstage/catalog-client": "^1.6.6",
35
35
  "@backstage/catalog-model": "^1.6.0",
36
- "@backstage/config": "^1.2.0",
36
+ "@backstage/errors": "^1.2.4",
37
37
  "@backstage/integration": "^1.14.0",
38
- "@backstage/plugin-permission-common": "^0.8.1",
39
38
  "@types/express": "*",
40
39
  "express": "^4.17.1",
41
- "express-promise-router": "^4.1.0",
42
- "node-fetch": "^2.6.7",
43
- "yn": "^4.0.0"
40
+ "express-promise-router": "^4.1.0"
44
41
  },
45
42
  "devDependencies": {
43
+ "@backstage/backend-test-utils": "^0.5.0",
46
44
  "@backstage/cli": "^0.27.0",
47
45
  "@types/supertest": "^2.0.12",
48
46
  "msw": "^1.0.0",