@backstage/plugin-techdocs-backend 2.0.5 → 2.1.0-next.1
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
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @backstage/plugin-techdocs-backend
|
|
2
2
|
|
|
3
|
+
## 2.1.0-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-defaults@0.12.1-next.1
|
|
9
|
+
- @backstage/catalog-client@1.12.0-next.0
|
|
10
|
+
- @backstage/plugin-catalog-node@1.19.0-next.1
|
|
11
|
+
- @backstage/integration@1.18.0-next.0
|
|
12
|
+
- @backstage/plugin-search-backend-module-techdocs@0.4.6-next.1
|
|
13
|
+
|
|
14
|
+
## 2.1.0-next.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 063cdc5: Techdocs: support HumanDuration for cache TTL and timeout configuration
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @backstage/integration@1.18.0-next.0
|
|
24
|
+
- @backstage/backend-defaults@0.12.1-next.0
|
|
25
|
+
- @backstage/plugin-techdocs-node@1.13.7-next.0
|
|
26
|
+
- @backstage/backend-plugin-api@1.4.3-next.0
|
|
27
|
+
- @backstage/plugin-search-backend-module-techdocs@0.4.6-next.0
|
|
28
|
+
- @backstage/plugin-catalog-node@1.18.1-next.0
|
|
29
|
+
|
|
3
30
|
## 2.0.5
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/config.d.ts
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { HumanDuration } from '@backstage/types';
|
|
18
|
+
|
|
17
19
|
export interface Config {
|
|
18
20
|
/**
|
|
19
21
|
* Configuration options for the techdocs-backend plugin
|
|
@@ -277,7 +279,7 @@ export interface Config {
|
|
|
277
279
|
*/
|
|
278
280
|
cache?: {
|
|
279
281
|
/**
|
|
280
|
-
* The cache time-to-live for TechDocs sites
|
|
282
|
+
* The cache time-to-live for TechDocs sites, in milliseconds for a number or a human duration. Set this
|
|
281
283
|
* to a non-zero value to cache TechDocs sites and assets as they are
|
|
282
284
|
* read from storage.
|
|
283
285
|
*
|
|
@@ -285,16 +287,16 @@ export interface Config {
|
|
|
285
287
|
* and to pass a PluginCacheManager instance to TechDocs Backend's
|
|
286
288
|
* createRouter method in your backend.
|
|
287
289
|
*/
|
|
288
|
-
ttl: number;
|
|
290
|
+
ttl: number | HumanDuration | string;
|
|
289
291
|
|
|
290
292
|
/**
|
|
291
|
-
* The time (in milliseconds) that the TechDocs backend will wait for
|
|
293
|
+
* The time (in milliseconds for a number or a human duration) that the TechDocs backend will wait for
|
|
292
294
|
* a cache service to respond before continuing on as though the cached
|
|
293
295
|
* object was not found (e.g. when the cache sercice is unavailable).
|
|
294
296
|
*
|
|
295
297
|
* Defaults to 1000 milliseconds.
|
|
296
298
|
*/
|
|
297
|
-
readTimeout?: number;
|
|
299
|
+
readTimeout?: number | HumanDuration | string;
|
|
298
300
|
};
|
|
299
301
|
|
|
300
302
|
/**
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var errors = require('@backstage/errors');
|
|
4
|
+
var config = require('@backstage/config');
|
|
5
|
+
var types = require('@backstage/types');
|
|
4
6
|
|
|
5
7
|
class CacheInvalidationError extends errors.CustomErrorBase {
|
|
6
8
|
}
|
|
@@ -17,9 +19,21 @@ class TechDocsCache {
|
|
|
17
19
|
this.logger = logger;
|
|
18
20
|
this.readTimeout = readTimeout;
|
|
19
21
|
}
|
|
20
|
-
static fromConfig(config, { cache, logger }) {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
static fromConfig(config$1, { cache, logger }) {
|
|
23
|
+
let readTimeout;
|
|
24
|
+
if (config$1.has("techdocs.cache.readTimeout")) {
|
|
25
|
+
if (typeof config$1.get("techdocs.cache.readTimeout") === "number") {
|
|
26
|
+
readTimeout = config$1.getNumber("techdocs.cache.readTimeout");
|
|
27
|
+
} else {
|
|
28
|
+
readTimeout = types.durationToMilliseconds(
|
|
29
|
+
config.readDurationFromConfig(config$1, {
|
|
30
|
+
key: "techdocs.cache.readTimeout"
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
readTimeout = 1e3;
|
|
36
|
+
}
|
|
23
37
|
return new TechDocsCache({ cache, logger, readTimeout });
|
|
24
38
|
}
|
|
25
39
|
async get(path) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TechDocsCache.cjs.js","sources":["../../src/cache/TechDocsCache.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { assertError, CustomErrorBase } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { CacheService, LoggerService } from '@backstage/backend-plugin-api';\n\nexport class CacheInvalidationError extends CustomErrorBase {}\n\nexport class TechDocsCache {\n protected readonly cache: CacheService;\n protected readonly logger: LoggerService;\n protected readonly readTimeout: number;\n\n private constructor({\n cache,\n logger,\n readTimeout,\n }: {\n cache: CacheService;\n logger: LoggerService;\n readTimeout: number;\n }) {\n this.cache = cache;\n this.logger = logger;\n this.readTimeout = readTimeout;\n }\n\n static fromConfig(\n config: Config,\n { cache, logger }: { cache: CacheService; logger: LoggerService },\n ) {\n
|
|
1
|
+
{"version":3,"file":"TechDocsCache.cjs.js","sources":["../../src/cache/TechDocsCache.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { assertError, CustomErrorBase } from '@backstage/errors';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { CacheService, LoggerService } from '@backstage/backend-plugin-api';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport class CacheInvalidationError extends CustomErrorBase {}\n\nexport class TechDocsCache {\n protected readonly cache: CacheService;\n protected readonly logger: LoggerService;\n protected readonly readTimeout: number;\n\n private constructor({\n cache,\n logger,\n readTimeout,\n }: {\n cache: CacheService;\n logger: LoggerService;\n readTimeout: number;\n }) {\n this.cache = cache;\n this.logger = logger;\n this.readTimeout = readTimeout;\n }\n\n static fromConfig(\n config: Config,\n { cache, logger }: { cache: CacheService; logger: LoggerService },\n ) {\n let readTimeout: number;\n if (config.has('techdocs.cache.readTimeout')) {\n if (typeof config.get('techdocs.cache.readTimeout') === 'number') {\n readTimeout = config.getNumber('techdocs.cache.readTimeout');\n } else {\n readTimeout = durationToMilliseconds(\n readDurationFromConfig(config, {\n key: 'techdocs.cache.readTimeout',\n }),\n );\n }\n } else {\n readTimeout = 1000;\n }\n return new TechDocsCache({ cache, logger, readTimeout });\n }\n\n async get(path: string): Promise<Buffer | undefined> {\n try {\n // Promise.race ensures we don't hang the client for long if the cache is\n // temporarily unreachable.\n const response = (await Promise.race([\n this.cache.get(path),\n new Promise(cancelAfter => setTimeout(cancelAfter, this.readTimeout)),\n ])) as string | undefined;\n\n if (response !== undefined) {\n this.logger.debug(`Cache hit: ${path}`);\n return Buffer.from(response, 'base64');\n }\n\n this.logger.debug(`Cache miss: ${path}`);\n return response;\n } catch (e) {\n assertError(e);\n this.logger.warn(`Error getting cache entry ${path}: ${e.message}`);\n this.logger.debug(e.message, e);\n return undefined;\n }\n }\n\n async set(path: string, data: Buffer): Promise<void> {\n this.logger.debug(`Writing cache entry for ${path}`);\n this.cache\n .set(path, data.toString('base64'))\n .catch(e => this.logger.error('write error', e));\n }\n\n async invalidate(path: string): Promise<void> {\n return this.cache.delete(path);\n }\n\n async invalidateMultiple(\n paths: string[],\n ): Promise<PromiseSettledResult<void>[]> {\n const settled = await Promise.allSettled(\n paths.map(path => this.cache.delete(path)),\n );\n const rejected = settled.filter(\n s => s.status === 'rejected',\n ) as PromiseRejectedResult[];\n\n if (rejected.length) {\n throw new CacheInvalidationError(\n 'TechDocs cache invalidation error',\n rejected,\n );\n }\n\n return settled;\n }\n}\n"],"names":["CustomErrorBase","config","durationToMilliseconds","readDurationFromConfig","assertError"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var catalogClient = require('@backstage/catalog-client');
|
|
4
4
|
var catalogModel = require('@backstage/catalog-model');
|
|
5
|
+
var config = require('@backstage/config');
|
|
5
6
|
var errors = require('@backstage/errors');
|
|
6
7
|
var pluginTechdocsNode = require('@backstage/plugin-techdocs-node');
|
|
7
8
|
var router = require('express-promise-router');
|
|
@@ -11,6 +12,7 @@ var cacheMiddleware = require('../cache/cacheMiddleware.cjs.js');
|
|
|
11
12
|
var TechDocsCache = require('../cache/TechDocsCache.cjs.js');
|
|
12
13
|
var CachedEntityLoader = require('./CachedEntityLoader.cjs.js');
|
|
13
14
|
var DefaultDocsBuildStrategy = require('./DefaultDocsBuildStrategy.cjs.js');
|
|
15
|
+
var types = require('@backstage/types');
|
|
14
16
|
|
|
15
17
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
16
18
|
|
|
@@ -21,9 +23,9 @@ function isOutOfTheBoxOption(opt) {
|
|
|
21
23
|
}
|
|
22
24
|
async function createRouter(options) {
|
|
23
25
|
const router = router__default.default();
|
|
24
|
-
const { publisher, config, logger, discovery, httpAuth, auth } = options;
|
|
26
|
+
const { publisher, config: config$1, logger, discovery, httpAuth, auth } = options;
|
|
25
27
|
const catalogClient$1 = options.catalogClient ?? new catalogClient.CatalogClient({ discoveryApi: discovery });
|
|
26
|
-
const docsBuildStrategy = options.docsBuildStrategy ?? DefaultDocsBuildStrategy.DefaultDocsBuildStrategy.fromConfig(config);
|
|
28
|
+
const docsBuildStrategy = options.docsBuildStrategy ?? DefaultDocsBuildStrategy.DefaultDocsBuildStrategy.fromConfig(config$1);
|
|
27
29
|
const buildLogTransport = options.buildLogTransport;
|
|
28
30
|
const entityLoader = new CachedEntityLoader.CachedEntityLoader({
|
|
29
31
|
auth,
|
|
@@ -31,17 +33,26 @@ async function createRouter(options) {
|
|
|
31
33
|
cache: options.cache
|
|
32
34
|
});
|
|
33
35
|
let cache;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
if (config$1.has("techdocs.cache.ttl")) {
|
|
37
|
+
let ttlMs;
|
|
38
|
+
if (typeof config$1.get("techdocs.cache.ttl") === "number") {
|
|
39
|
+
ttlMs = config$1.getNumber("techdocs.cache.ttl");
|
|
40
|
+
} else {
|
|
41
|
+
ttlMs = types.durationToMilliseconds(
|
|
42
|
+
config.readDurationFromConfig(config$1, {
|
|
43
|
+
key: "techdocs.cache.ttl"
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
const cacheClient = options.cache.withOptions({ defaultTtl: ttlMs });
|
|
48
|
+
cache = TechDocsCache.TechDocsCache.fromConfig(config$1, { cache: cacheClient, logger });
|
|
38
49
|
}
|
|
39
|
-
const scmIntegrations = integration.ScmIntegrations.fromConfig(config);
|
|
50
|
+
const scmIntegrations = integration.ScmIntegrations.fromConfig(config$1);
|
|
40
51
|
const docsSynchronizer = new DocsSynchronizer.DocsSynchronizer({
|
|
41
52
|
publisher,
|
|
42
53
|
logger,
|
|
43
54
|
buildLogTransport,
|
|
44
|
-
config,
|
|
55
|
+
config: config$1,
|
|
45
56
|
scmIntegrations,
|
|
46
57
|
cache
|
|
47
58
|
});
|
|
@@ -155,7 +166,7 @@ async function createRouter(options) {
|
|
|
155
166
|
)
|
|
156
167
|
);
|
|
157
168
|
});
|
|
158
|
-
if (config.getOptionalBoolean("permission.enabled")) {
|
|
169
|
+
if (config$1.getOptionalBoolean("permission.enabled")) {
|
|
159
170
|
router.use(
|
|
160
171
|
"/static/docs/:namespace/:kind/:name",
|
|
161
172
|
async (req, _res, next) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { CatalogApi, CatalogClient } from '@backstage/catalog-client';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { NotFoundError } from '@backstage/errors';\nimport {\n DocsBuildStrategy,\n GeneratorBuilder,\n getLocationForEntity,\n PreparerBuilder,\n PublisherBase,\n} from '@backstage/plugin-techdocs-node';\nimport express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { Knex } from 'knex';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer';\nimport { createCacheMiddleware, TechDocsCache } from '../cache';\nimport { CachedEntityLoader } from './CachedEntityLoader';\nimport { DefaultDocsBuildStrategy } from './DefaultDocsBuildStrategy';\nimport * as winston from 'winston';\nimport {\n AuthService,\n CacheService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Required dependencies for running TechDocs in the \"out-of-the-box\"\n * deployment configuration (prepare/generate/publish all in the Backend).\n *\n * @internal\n */\nexport type OutOfTheBoxDeploymentOptions = {\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n publisher: PublisherBase;\n logger: LoggerService;\n discovery: DiscoveryService;\n database?: Knex; // TODO: Make database required when we're implementing database stuff.\n config: Config;\n cache: CacheService;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogApi;\n httpAuth: HttpAuthService;\n auth: AuthService;\n};\n\n/**\n * Required dependencies for running TechDocs in the \"recommended\" deployment\n * configuration (prepare/generate handled externally in CI/CD).\n *\n * @internal\n */\nexport type RecommendedDeploymentOptions = {\n publisher: PublisherBase;\n logger: LoggerService;\n discovery: DiscoveryService;\n config: Config;\n cache: CacheService;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogApi;\n httpAuth: HttpAuthService;\n auth: AuthService;\n};\n\n/**\n * One of the two deployment configurations must be provided.\n *\n * @internal\n */\nexport type RouterOptions =\n | RecommendedDeploymentOptions\n | OutOfTheBoxDeploymentOptions;\n\n/**\n * Typeguard to help createRouter() understand when we are in a \"recommended\"\n * deployment vs. when we are in an out-of-the-box deployment configuration.\n *\n * @internal\n */\nfunction isOutOfTheBoxOption(\n opt: RouterOptions,\n): opt is OutOfTheBoxDeploymentOptions {\n return (opt as OutOfTheBoxDeploymentOptions).preparers !== undefined;\n}\n\n/**\n * Creates a techdocs router.\n *\n * @internal\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n const { publisher, config, logger, discovery, httpAuth, auth } = options;\n\n const catalogClient =\n options.catalogClient ?? new CatalogClient({ discoveryApi: discovery });\n const docsBuildStrategy =\n options.docsBuildStrategy ?? DefaultDocsBuildStrategy.fromConfig(config);\n const buildLogTransport = options.buildLogTransport;\n\n // Entities are cached to optimize the /static/docs request path, which can be called many times\n // when loading a single techdocs page.\n const entityLoader = new CachedEntityLoader({\n auth,\n catalog: catalogClient,\n cache: options.cache,\n });\n\n // Set up a cache client if configured.\n let cache: TechDocsCache | undefined;\n const defaultTtl = config.getOptionalNumber('techdocs.cache.ttl');\n if (defaultTtl) {\n const cacheClient = options.cache.withOptions({ defaultTtl });\n cache = TechDocsCache.fromConfig(config, { cache: cacheClient, logger });\n }\n\n const scmIntegrations = ScmIntegrations.fromConfig(config);\n const docsSynchronizer = new DocsSynchronizer({\n publisher,\n logger,\n buildLogTransport,\n config,\n scmIntegrations,\n cache,\n });\n\n router.get('/metadata/techdocs/:namespace/:kind/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityName = { kind, namespace, name };\n\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // Verify that the related entity exists and the current user has permission to view it.\n const entity = await entityLoader.load(credentials, entityName, token);\n\n if (!entity) {\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n );\n }\n\n try {\n const techdocsMetadata = await publisher.fetchTechDocsMetadata(\n entityName,\n );\n\n res.json(techdocsMetadata);\n } catch (err) {\n logger.info(\n `Unable to get metadata for '${stringifyEntityRef(\n entityName,\n )}' with error ${err}`,\n );\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n err,\n );\n }\n });\n\n router.get('/metadata/entity/:namespace/:kind/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityName = { kind, namespace, name };\n\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entity = await entityLoader.load(credentials, entityName, token);\n\n if (!entity) {\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n );\n }\n\n try {\n const locationMetadata = getLocationForEntity(entity, scmIntegrations);\n res.json({ ...entity, locationMetadata });\n } catch (err) {\n logger.info(\n `Unable to get metadata for '${stringifyEntityRef(\n entityName,\n )}' with error ${err}`,\n );\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n err,\n );\n }\n });\n\n // Check if docs are the latest version and trigger rebuilds if not\n // Responds with an event-stream that closes after the build finished\n // Responds with an immediate success if rebuild not needed\n // If a build is required, responds with a success when finished\n router.get('/sync/:namespace/:kind/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entity = await entityLoader.load(\n credentials,\n { kind, namespace, name },\n token,\n );\n\n if (!entity?.metadata?.uid) {\n throw new NotFoundError('Entity metadata UID missing');\n }\n\n const responseHandler: DocsSynchronizerSyncOpts = createEventStream(res);\n\n // By default, techdocs-backend will only try to build documentation for an entity if techdocs.builder is set to\n // 'local'. If set to 'external', it will assume that an external process (e.g. CI/CD pipeline\n // of the repository) is responsible for building and publishing documentation to the storage provider.\n // Altering the implementation of the injected docsBuildStrategy allows for more complex behaviours, based on\n // either config or the properties of the entity (e.g. annotations, labels, spec fields etc.).\n const shouldBuild = await docsBuildStrategy.shouldBuild({ entity });\n if (!shouldBuild) {\n // However, if caching is enabled, take the opportunity to check and\n // invalidate stale cache entries.\n if (cache) {\n const { token: techDocsToken } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'techdocs',\n });\n await docsSynchronizer.doCacheSync({\n responseHandler,\n discovery,\n token: techDocsToken,\n entity,\n });\n return;\n }\n responseHandler.finish({ updated: false });\n return;\n }\n\n // Set the synchronization and build process if \"out-of-the-box\" configuration is provided.\n if (isOutOfTheBoxOption(options)) {\n const { preparers, generators } = options;\n\n await docsSynchronizer.doSync({\n responseHandler,\n entity,\n preparers,\n generators,\n });\n return;\n }\n\n responseHandler.error(\n new Error(\n \"Invalid configuration. docsBuildStrategy.shouldBuild returned 'true', but no 'preparer' was provided to the router initialization.\",\n ),\n );\n });\n\n // Ensures that the related entity exists and the current user has permission to view it.\n if (config.getOptionalBoolean('permission.enabled')) {\n router.use(\n '/static/docs/:namespace/:kind/:name',\n async (req, _res, next) => {\n const { kind, namespace, name } = req.params;\n const entityName = { kind, namespace, name };\n\n const credentials = await httpAuth.credentials(req, {\n allowLimitedAccess: true,\n });\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entity = await entityLoader.load(credentials, entityName, token);\n\n if (!entity) {\n throw new NotFoundError(\n `Entity not found for ${stringifyEntityRef(entityName)}`,\n );\n }\n\n next();\n },\n );\n }\n\n // If a cache manager was provided, attach the cache middleware.\n if (cache) {\n router.use(createCacheMiddleware({ logger, cache }));\n }\n\n // Route middleware which serves files from the storage set in the publisher.\n router.use('/static/docs', publisher.docsRouter());\n\n return router;\n}\n\n/**\n * Create an event-stream response that emits the events 'log', 'error', and 'finish'.\n *\n * @param res - the response to write the event-stream to\n * @returns A tuple of <log, error, finish> callbacks to emit messages. A call to 'error' or 'finish'\n * will close the event-stream.\n */\nexport function createEventStream(\n res: Response<any, any>,\n): DocsSynchronizerSyncOpts {\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // client closes connection\n res.socket?.on('close', () => {\n res.end();\n });\n\n // write the event to the stream\n const send = (type: 'error' | 'finish' | 'log', data: any) => {\n res.write(`event: ${type}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n\n // res.flush() is only available with the compression middleware\n if (res.flush) {\n res.flush();\n }\n };\n\n return {\n log: data => {\n send('log', data);\n },\n\n error: e => {\n send('error', e.message);\n res.end();\n },\n\n finish: result => {\n send('finish', result);\n res.end();\n },\n };\n}\n"],"names":["Router","catalogClient","CatalogClient","DefaultDocsBuildStrategy","CachedEntityLoader","TechDocsCache","ScmIntegrations","DocsSynchronizer","NotFoundError","stringifyEntityRef","getLocationForEntity","createCacheMiddleware"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { CatalogApi, CatalogClient } from '@backstage/catalog-client';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { NotFoundError } from '@backstage/errors';\nimport {\n DocsBuildStrategy,\n GeneratorBuilder,\n getLocationForEntity,\n PreparerBuilder,\n PublisherBase,\n} from '@backstage/plugin-techdocs-node';\nimport express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { Knex } from 'knex';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer';\nimport { createCacheMiddleware, TechDocsCache } from '../cache';\nimport { CachedEntityLoader } from './CachedEntityLoader';\nimport { DefaultDocsBuildStrategy } from './DefaultDocsBuildStrategy';\nimport * as winston from 'winston';\nimport {\n AuthService,\n CacheService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { durationToMilliseconds } from '@backstage/types';\n\n/**\n * Required dependencies for running TechDocs in the \"out-of-the-box\"\n * deployment configuration (prepare/generate/publish all in the Backend).\n *\n * @internal\n */\nexport type OutOfTheBoxDeploymentOptions = {\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n publisher: PublisherBase;\n logger: LoggerService;\n discovery: DiscoveryService;\n database?: Knex; // TODO: Make database required when we're implementing database stuff.\n config: Config;\n cache: CacheService;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogApi;\n httpAuth: HttpAuthService;\n auth: AuthService;\n};\n\n/**\n * Required dependencies for running TechDocs in the \"recommended\" deployment\n * configuration (prepare/generate handled externally in CI/CD).\n *\n * @internal\n */\nexport type RecommendedDeploymentOptions = {\n publisher: PublisherBase;\n logger: LoggerService;\n discovery: DiscoveryService;\n config: Config;\n cache: CacheService;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogApi;\n httpAuth: HttpAuthService;\n auth: AuthService;\n};\n\n/**\n * One of the two deployment configurations must be provided.\n *\n * @internal\n */\nexport type RouterOptions =\n | RecommendedDeploymentOptions\n | OutOfTheBoxDeploymentOptions;\n\n/**\n * Typeguard to help createRouter() understand when we are in a \"recommended\"\n * deployment vs. when we are in an out-of-the-box deployment configuration.\n *\n * @internal\n */\nfunction isOutOfTheBoxOption(\n opt: RouterOptions,\n): opt is OutOfTheBoxDeploymentOptions {\n return (opt as OutOfTheBoxDeploymentOptions).preparers !== undefined;\n}\n\n/**\n * Creates a techdocs router.\n *\n * @internal\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n const { publisher, config, logger, discovery, httpAuth, auth } = options;\n\n const catalogClient =\n options.catalogClient ?? new CatalogClient({ discoveryApi: discovery });\n const docsBuildStrategy =\n options.docsBuildStrategy ?? DefaultDocsBuildStrategy.fromConfig(config);\n const buildLogTransport = options.buildLogTransport;\n\n // Entities are cached to optimize the /static/docs request path, which can be called many times\n // when loading a single techdocs page.\n const entityLoader = new CachedEntityLoader({\n auth,\n catalog: catalogClient,\n cache: options.cache,\n });\n\n // Set up a cache client if configured.\n let cache: TechDocsCache | undefined;\n if (config.has('techdocs.cache.ttl')) {\n let ttlMs: number;\n if (typeof config.get('techdocs.cache.ttl') === 'number') {\n ttlMs = config.getNumber('techdocs.cache.ttl');\n } else {\n ttlMs = durationToMilliseconds(\n readDurationFromConfig(config, {\n key: 'techdocs.cache.ttl',\n }),\n );\n }\n const cacheClient = options.cache.withOptions({ defaultTtl: ttlMs });\n cache = TechDocsCache.fromConfig(config, { cache: cacheClient, logger });\n }\n\n const scmIntegrations = ScmIntegrations.fromConfig(config);\n const docsSynchronizer = new DocsSynchronizer({\n publisher,\n logger,\n buildLogTransport,\n config,\n scmIntegrations,\n cache,\n });\n\n router.get('/metadata/techdocs/:namespace/:kind/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityName = { kind, namespace, name };\n\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // Verify that the related entity exists and the current user has permission to view it.\n const entity = await entityLoader.load(credentials, entityName, token);\n\n if (!entity) {\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n );\n }\n\n try {\n const techdocsMetadata = await publisher.fetchTechDocsMetadata(\n entityName,\n );\n\n res.json(techdocsMetadata);\n } catch (err) {\n logger.info(\n `Unable to get metadata for '${stringifyEntityRef(\n entityName,\n )}' with error ${err}`,\n );\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n err,\n );\n }\n });\n\n router.get('/metadata/entity/:namespace/:kind/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityName = { kind, namespace, name };\n\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entity = await entityLoader.load(credentials, entityName, token);\n\n if (!entity) {\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n );\n }\n\n try {\n const locationMetadata = getLocationForEntity(entity, scmIntegrations);\n res.json({ ...entity, locationMetadata });\n } catch (err) {\n logger.info(\n `Unable to get metadata for '${stringifyEntityRef(\n entityName,\n )}' with error ${err}`,\n );\n throw new NotFoundError(\n `Unable to get metadata for '${stringifyEntityRef(entityName)}'`,\n err,\n );\n }\n });\n\n // Check if docs are the latest version and trigger rebuilds if not\n // Responds with an event-stream that closes after the build finished\n // Responds with an immediate success if rebuild not needed\n // If a build is required, responds with a success when finished\n router.get('/sync/:namespace/:kind/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entity = await entityLoader.load(\n credentials,\n { kind, namespace, name },\n token,\n );\n\n if (!entity?.metadata?.uid) {\n throw new NotFoundError('Entity metadata UID missing');\n }\n\n const responseHandler: DocsSynchronizerSyncOpts = createEventStream(res);\n\n // By default, techdocs-backend will only try to build documentation for an entity if techdocs.builder is set to\n // 'local'. If set to 'external', it will assume that an external process (e.g. CI/CD pipeline\n // of the repository) is responsible for building and publishing documentation to the storage provider.\n // Altering the implementation of the injected docsBuildStrategy allows for more complex behaviours, based on\n // either config or the properties of the entity (e.g. annotations, labels, spec fields etc.).\n const shouldBuild = await docsBuildStrategy.shouldBuild({ entity });\n if (!shouldBuild) {\n // However, if caching is enabled, take the opportunity to check and\n // invalidate stale cache entries.\n if (cache) {\n const { token: techDocsToken } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'techdocs',\n });\n await docsSynchronizer.doCacheSync({\n responseHandler,\n discovery,\n token: techDocsToken,\n entity,\n });\n return;\n }\n responseHandler.finish({ updated: false });\n return;\n }\n\n // Set the synchronization and build process if \"out-of-the-box\" configuration is provided.\n if (isOutOfTheBoxOption(options)) {\n const { preparers, generators } = options;\n\n await docsSynchronizer.doSync({\n responseHandler,\n entity,\n preparers,\n generators,\n });\n return;\n }\n\n responseHandler.error(\n new Error(\n \"Invalid configuration. docsBuildStrategy.shouldBuild returned 'true', but no 'preparer' was provided to the router initialization.\",\n ),\n );\n });\n\n // Ensures that the related entity exists and the current user has permission to view it.\n if (config.getOptionalBoolean('permission.enabled')) {\n router.use(\n '/static/docs/:namespace/:kind/:name',\n async (req, _res, next) => {\n const { kind, namespace, name } = req.params;\n const entityName = { kind, namespace, name };\n\n const credentials = await httpAuth.credentials(req, {\n allowLimitedAccess: true,\n });\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entity = await entityLoader.load(credentials, entityName, token);\n\n if (!entity) {\n throw new NotFoundError(\n `Entity not found for ${stringifyEntityRef(entityName)}`,\n );\n }\n\n next();\n },\n );\n }\n\n // If a cache manager was provided, attach the cache middleware.\n if (cache) {\n router.use(createCacheMiddleware({ logger, cache }));\n }\n\n // Route middleware which serves files from the storage set in the publisher.\n router.use('/static/docs', publisher.docsRouter());\n\n return router;\n}\n\n/**\n * Create an event-stream response that emits the events 'log', 'error', and 'finish'.\n *\n * @param res - the response to write the event-stream to\n * @returns A tuple of <log, error, finish> callbacks to emit messages. A call to 'error' or 'finish'\n * will close the event-stream.\n */\nexport function createEventStream(\n res: Response<any, any>,\n): DocsSynchronizerSyncOpts {\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // client closes connection\n res.socket?.on('close', () => {\n res.end();\n });\n\n // write the event to the stream\n const send = (type: 'error' | 'finish' | 'log', data: any) => {\n res.write(`event: ${type}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n\n // res.flush() is only available with the compression middleware\n if (res.flush) {\n res.flush();\n }\n };\n\n return {\n log: data => {\n send('log', data);\n },\n\n error: e => {\n send('error', e.message);\n res.end();\n },\n\n finish: result => {\n send('finish', result);\n res.end();\n },\n };\n}\n"],"names":["Router","config","catalogClient","CatalogClient","DefaultDocsBuildStrategy","CachedEntityLoader","durationToMilliseconds","readDurationFromConfig","TechDocsCache","ScmIntegrations","DocsSynchronizer","NotFoundError","stringifyEntityRef","getLocationForEntity","createCacheMiddleware"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-techdocs-backend",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.1.0-next.1",
|
|
4
4
|
"description": "The Backstage backend plugin that renders technical documentation for your components",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin",
|
|
@@ -72,19 +72,20 @@
|
|
|
72
72
|
"test": "backstage-cli package test"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@backstage/backend-defaults": "
|
|
76
|
-
"@backstage/backend-plugin-api": "
|
|
77
|
-
"@backstage/catalog-client": "
|
|
78
|
-
"@backstage/catalog-model": "
|
|
79
|
-
"@backstage/config": "
|
|
80
|
-
"@backstage/errors": "
|
|
81
|
-
"@backstage/integration": "
|
|
82
|
-
"@backstage/plugin-catalog-common": "
|
|
83
|
-
"@backstage/plugin-catalog-node": "
|
|
84
|
-
"@backstage/plugin-permission-common": "
|
|
85
|
-
"@backstage/plugin-search-backend-module-techdocs": "
|
|
86
|
-
"@backstage/plugin-techdocs-common": "
|
|
87
|
-
"@backstage/plugin-techdocs-node": "
|
|
75
|
+
"@backstage/backend-defaults": "0.12.1-next.1",
|
|
76
|
+
"@backstage/backend-plugin-api": "1.4.3-next.0",
|
|
77
|
+
"@backstage/catalog-client": "1.12.0-next.0",
|
|
78
|
+
"@backstage/catalog-model": "1.7.5",
|
|
79
|
+
"@backstage/config": "1.3.3",
|
|
80
|
+
"@backstage/errors": "1.2.7",
|
|
81
|
+
"@backstage/integration": "1.18.0-next.0",
|
|
82
|
+
"@backstage/plugin-catalog-common": "1.1.5",
|
|
83
|
+
"@backstage/plugin-catalog-node": "1.19.0-next.1",
|
|
84
|
+
"@backstage/plugin-permission-common": "0.9.1",
|
|
85
|
+
"@backstage/plugin-search-backend-module-techdocs": "0.4.6-next.1",
|
|
86
|
+
"@backstage/plugin-techdocs-common": "0.1.1",
|
|
87
|
+
"@backstage/plugin-techdocs-node": "1.13.7-next.0",
|
|
88
|
+
"@backstage/types": "1.2.1",
|
|
88
89
|
"express": "^4.17.1",
|
|
89
90
|
"express-promise-router": "^4.1.0",
|
|
90
91
|
"fs-extra": "^11.2.0",
|
|
@@ -94,9 +95,9 @@
|
|
|
94
95
|
"winston": "^3.2.1"
|
|
95
96
|
},
|
|
96
97
|
"devDependencies": {
|
|
97
|
-
"@backstage/backend-defaults": "
|
|
98
|
-
"@backstage/backend-test-utils": "
|
|
99
|
-
"@backstage/cli": "
|
|
98
|
+
"@backstage/backend-defaults": "0.12.1-next.1",
|
|
99
|
+
"@backstage/backend-test-utils": "1.9.0-next.1",
|
|
100
|
+
"@backstage/cli": "0.34.2-next.2",
|
|
100
101
|
"@types/express": "^4.17.6",
|
|
101
102
|
"msw": "^2.0.0",
|
|
102
103
|
"supertest": "^7.0.0"
|