@backstage/plugin-techdocs-backend 1.10.14-next.0 → 1.10.14-next.2

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,42 @@
1
1
  # @backstage/plugin-techdocs-backend
2
2
 
3
+ ## 1.10.14-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - fbdc631: Allow to pass StorageOptions to GCS Publisher
8
+ - Updated dependencies
9
+ - @backstage/plugin-catalog-node@1.13.1-next.1
10
+ - @backstage/plugin-techdocs-node@1.12.12-next.2
11
+ - @backstage/integration@1.15.1-next.1
12
+ - @backstage/catalog-client@1.7.1-next.0
13
+ - @backstage/backend-plugin-api@1.0.1-next.1
14
+ - @backstage/catalog-model@1.7.0
15
+ - @backstage/config@1.2.0
16
+ - @backstage/errors@1.2.4
17
+ - @backstage/plugin-catalog-common@1.1.0
18
+ - @backstage/plugin-permission-common@0.8.1
19
+ - @backstage/plugin-search-backend-module-techdocs@0.2.3-next.2
20
+ - @backstage/plugin-techdocs-common@0.1.0
21
+
22
+ ## 1.10.14-next.1
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies
27
+ - @backstage/integration@1.15.1-next.0
28
+ - @backstage/backend-plugin-api@1.0.1-next.0
29
+ - @backstage/catalog-client@1.7.0
30
+ - @backstage/catalog-model@1.7.0
31
+ - @backstage/config@1.2.0
32
+ - @backstage/errors@1.2.4
33
+ - @backstage/plugin-catalog-common@1.1.0
34
+ - @backstage/plugin-catalog-node@1.13.1-next.0
35
+ - @backstage/plugin-permission-common@0.8.1
36
+ - @backstage/plugin-search-backend-module-techdocs@0.2.3-next.1
37
+ - @backstage/plugin-techdocs-common@0.1.0
38
+ - @backstage/plugin-techdocs-node@1.12.12-next.1
39
+
3
40
  ## 1.10.14-next.0
4
41
 
5
42
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-techdocs-backend__alpha",
3
- "version": "1.10.14-next.0",
3
+ "version": "1.10.14-next.2",
4
4
  "main": "../dist/alpha.cjs.js",
5
5
  "types": "../dist/alpha.d.ts"
6
6
  }
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ const lastUpdatedRecord = {};
4
+ class BuildMetadataStorage {
5
+ entityUid;
6
+ lastUpdatedRecord;
7
+ constructor(entityUid) {
8
+ this.entityUid = entityUid;
9
+ this.lastUpdatedRecord = lastUpdatedRecord;
10
+ }
11
+ setLastUpdated() {
12
+ this.lastUpdatedRecord[this.entityUid] = Date.now();
13
+ }
14
+ getLastUpdated() {
15
+ return this.lastUpdatedRecord[this.entityUid];
16
+ }
17
+ }
18
+ const shouldCheckForUpdate = (entityUid) => {
19
+ const lastUpdated = new BuildMetadataStorage(entityUid).getLastUpdated();
20
+ if (lastUpdated) {
21
+ if (Date.now() - lastUpdated < 60 * 1e3) {
22
+ return false;
23
+ }
24
+ }
25
+ return true;
26
+ };
27
+
28
+ exports.BuildMetadataStorage = BuildMetadataStorage;
29
+ exports.shouldCheckForUpdate = shouldCheckForUpdate;
30
+ //# sourceMappingURL=BuildMetadataStorage.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BuildMetadataStorage.cjs.js","sources":["../../src/DocsBuilder/BuildMetadataStorage.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\n// Entity uid: unix timestamp\nconst lastUpdatedRecord = {} as Record<string, number>;\n\n/**\n * Store timestamps of the most recent TechDocs update of each Entity. This is\n * used to avoid checking for an update on each and every request to TechDocs.\n */\nexport class BuildMetadataStorage {\n private entityUid: string;\n private lastUpdatedRecord: Record<string, number>;\n\n constructor(entityUid: string) {\n this.entityUid = entityUid;\n this.lastUpdatedRecord = lastUpdatedRecord;\n }\n\n setLastUpdated(): void {\n this.lastUpdatedRecord[this.entityUid] = Date.now();\n }\n\n getLastUpdated(): number | undefined {\n return this.lastUpdatedRecord[this.entityUid];\n }\n}\n\n/**\n * Return false if a check for update has happened in last 60 seconds.\n */\nexport const shouldCheckForUpdate = (entityUid: string) => {\n const lastUpdated = new BuildMetadataStorage(entityUid).getLastUpdated();\n if (lastUpdated) {\n // The difference is in milliseconds\n if (Date.now() - lastUpdated < 60 * 1000) {\n return false;\n }\n }\n return true;\n};\n"],"names":[],"mappings":";;AAiBA,MAAM,oBAAoB,EAAC,CAAA;AAMpB,MAAM,oBAAqB,CAAA;AAAA,EACxB,SAAA,CAAA;AAAA,EACA,iBAAA,CAAA;AAAA,EAER,YAAY,SAAmB,EAAA;AAC7B,IAAA,IAAA,CAAK,SAAY,GAAA,SAAA,CAAA;AACjB,IAAA,IAAA,CAAK,iBAAoB,GAAA,iBAAA,CAAA;AAAA,GAC3B;AAAA,EAEA,cAAuB,GAAA;AACrB,IAAA,IAAA,CAAK,iBAAkB,CAAA,IAAA,CAAK,SAAS,CAAA,GAAI,KAAK,GAAI,EAAA,CAAA;AAAA,GACpD;AAAA,EAEA,cAAqC,GAAA;AACnC,IAAO,OAAA,IAAA,CAAK,iBAAkB,CAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,GAC9C;AACF,CAAA;AAKa,MAAA,oBAAA,GAAuB,CAAC,SAAsB,KAAA;AACzD,EAAA,MAAM,WAAc,GAAA,IAAI,oBAAqB,CAAA,SAAS,EAAE,cAAe,EAAA,CAAA;AACvE,EAAA,IAAI,WAAa,EAAA;AAEf,IAAA,IAAI,IAAK,CAAA,GAAA,EAAQ,GAAA,WAAA,GAAc,KAAK,GAAM,EAAA;AACxC,MAAO,OAAA,KAAA,CAAA;AAAA,KACT;AAAA,GACF;AACA,EAAO,OAAA,IAAA,CAAA;AACT;;;;;"}
@@ -0,0 +1,172 @@
1
+ 'use strict';
2
+
3
+ var catalogModel = require('@backstage/catalog-model');
4
+ var errors = require('@backstage/errors');
5
+ var pluginTechdocsNode = require('@backstage/plugin-techdocs-node');
6
+ var fs = require('fs-extra');
7
+ var os = require('os');
8
+ var path = require('path');
9
+ var BuildMetadataStorage = require('./BuildMetadataStorage.cjs.js');
10
+
11
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
12
+
13
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
14
+ var os__default = /*#__PURE__*/_interopDefaultCompat(os);
15
+ var path__default = /*#__PURE__*/_interopDefaultCompat(path);
16
+
17
+ class DocsBuilder {
18
+ preparer;
19
+ generator;
20
+ publisher;
21
+ entity;
22
+ logger;
23
+ config;
24
+ scmIntegrations;
25
+ logStream;
26
+ cache;
27
+ constructor({
28
+ preparers,
29
+ generators,
30
+ publisher,
31
+ entity,
32
+ logger,
33
+ config,
34
+ scmIntegrations,
35
+ logStream,
36
+ cache
37
+ }) {
38
+ this.preparer = preparers.get(entity);
39
+ this.generator = generators.get(entity);
40
+ this.publisher = publisher;
41
+ this.entity = entity;
42
+ this.logger = logger;
43
+ this.config = config;
44
+ this.scmIntegrations = scmIntegrations;
45
+ this.logStream = logStream;
46
+ this.cache = cache;
47
+ }
48
+ /**
49
+ * Build the docs and return whether they have been newly generated or have been cached
50
+ * @returns true, if the docs have been built. false, if the cached docs are still up-to-date.
51
+ */
52
+ async build() {
53
+ if (!this.entity.metadata.uid) {
54
+ throw new Error(
55
+ "Trying to build documentation for entity not in software catalog"
56
+ );
57
+ }
58
+ this.logger.info(
59
+ `Step 1 of 3: Preparing docs for entity ${catalogModel.stringifyEntityRef(
60
+ this.entity
61
+ )}`
62
+ );
63
+ let storedEtag;
64
+ if (await this.publisher.hasDocsBeenGenerated(this.entity)) {
65
+ try {
66
+ storedEtag = (await this.publisher.fetchTechDocsMetadata({
67
+ namespace: this.entity.metadata.namespace ?? catalogModel.DEFAULT_NAMESPACE,
68
+ kind: this.entity.kind,
69
+ name: this.entity.metadata.name
70
+ })).etag;
71
+ } catch (err) {
72
+ this.logger.warn(
73
+ `Unable to read techdocs_metadata.json, proceeding with fresh build, error ${err}.`
74
+ );
75
+ }
76
+ }
77
+ let preparedDir;
78
+ let newEtag;
79
+ try {
80
+ const preparerResponse = await this.preparer.prepare(this.entity, {
81
+ etag: storedEtag,
82
+ logger: this.logger
83
+ });
84
+ preparedDir = preparerResponse.preparedDir;
85
+ newEtag = preparerResponse.etag;
86
+ } catch (err) {
87
+ if (errors.isError(err) && err.name === "NotModifiedError") {
88
+ new BuildMetadataStorage.BuildMetadataStorage(this.entity.metadata.uid).setLastUpdated();
89
+ this.logger.debug(
90
+ `Docs for ${catalogModel.stringifyEntityRef(
91
+ this.entity
92
+ )} are unmodified. Using cache, skipping generate and prepare`
93
+ );
94
+ return false;
95
+ }
96
+ throw err;
97
+ }
98
+ this.logger.info(
99
+ `Prepare step completed for entity ${catalogModel.stringifyEntityRef(
100
+ this.entity
101
+ )}, stored at ${preparedDir}`
102
+ );
103
+ this.logger.info(
104
+ `Step 2 of 3: Generating docs for entity ${catalogModel.stringifyEntityRef(
105
+ this.entity
106
+ )}`
107
+ );
108
+ const workingDir = this.config.getOptionalString(
109
+ "backend.workingDirectory"
110
+ );
111
+ const tmpdirPath = workingDir || os__default.default.tmpdir();
112
+ const tmpdirResolvedPath = fs__default.default.realpathSync(tmpdirPath);
113
+ const outputDir = await fs__default.default.mkdtemp(
114
+ path__default.default.join(tmpdirResolvedPath, "techdocs-tmp-")
115
+ );
116
+ const parsedLocationAnnotation = pluginTechdocsNode.getLocationForEntity(
117
+ this.entity,
118
+ this.scmIntegrations
119
+ );
120
+ await this.generator.run({
121
+ inputDir: preparedDir,
122
+ outputDir,
123
+ parsedLocationAnnotation,
124
+ etag: newEtag,
125
+ logger: this.logger,
126
+ logStream: this.logStream,
127
+ siteOptions: {
128
+ name: this.entity.metadata.title ?? this.entity.metadata.name
129
+ }
130
+ });
131
+ if (this.preparer.shouldCleanPreparedDirectory()) {
132
+ this.logger.debug(
133
+ `Removing prepared directory ${preparedDir} since the site has been generated`
134
+ );
135
+ try {
136
+ fs__default.default.remove(preparedDir);
137
+ } catch (error) {
138
+ errors.assertError(error);
139
+ this.logger.debug(`Error removing prepared directory ${error.message}`);
140
+ }
141
+ }
142
+ this.logger.info(
143
+ `Step 3 of 3: Publishing docs for entity ${catalogModel.stringifyEntityRef(
144
+ this.entity
145
+ )}`
146
+ );
147
+ const published = await this.publisher.publish({
148
+ entity: this.entity,
149
+ directory: outputDir
150
+ });
151
+ if (this.cache && published && published?.objects?.length) {
152
+ this.logger.debug(
153
+ `Invalidating ${published.objects.length} cache objects`
154
+ );
155
+ await this.cache.invalidateMultiple(published.objects);
156
+ }
157
+ try {
158
+ fs__default.default.remove(outputDir);
159
+ this.logger.debug(
160
+ `Removing generated directory ${outputDir} since the site has been published`
161
+ );
162
+ } catch (error) {
163
+ errors.assertError(error);
164
+ this.logger.debug(`Error removing generated directory ${error.message}`);
165
+ }
166
+ new BuildMetadataStorage.BuildMetadataStorage(this.entity.metadata.uid).setLastUpdated();
167
+ return true;
168
+ }
169
+ }
170
+
171
+ exports.DocsBuilder = DocsBuilder;
172
+ //# sourceMappingURL=builder.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.cjs.js","sources":["../../src/DocsBuilder/builder.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 */\nimport {\n DEFAULT_NAMESPACE,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, isError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport {\n GeneratorBase,\n GeneratorBuilder,\n getLocationForEntity,\n PreparerBase,\n PreparerBuilder,\n PublisherBase,\n} from '@backstage/plugin-techdocs-node';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport path from 'path';\nimport { Writable } from 'stream';\nimport { Logger } from 'winston';\nimport { BuildMetadataStorage } from './BuildMetadataStorage';\nimport { TechDocsCache } from '../cache';\n\ntype DocsBuilderArguments = {\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n publisher: PublisherBase;\n entity: Entity;\n logger: Logger;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n logStream?: Writable;\n cache?: TechDocsCache;\n};\n\nexport class DocsBuilder {\n private preparer: PreparerBase;\n private generator: GeneratorBase;\n private publisher: PublisherBase;\n private entity: Entity;\n private logger: Logger;\n private config: Config;\n private scmIntegrations: ScmIntegrationRegistry;\n private logStream: Writable | undefined;\n private cache?: TechDocsCache;\n\n constructor({\n preparers,\n generators,\n publisher,\n entity,\n logger,\n config,\n scmIntegrations,\n logStream,\n cache,\n }: DocsBuilderArguments) {\n this.preparer = preparers.get(entity);\n this.generator = generators.get(entity);\n this.publisher = publisher;\n this.entity = entity;\n this.logger = logger;\n this.config = config;\n this.scmIntegrations = scmIntegrations;\n this.logStream = logStream;\n this.cache = cache;\n }\n\n /**\n * Build the docs and return whether they have been newly generated or have been cached\n * @returns true, if the docs have been built. false, if the cached docs are still up-to-date.\n */\n public async build(): Promise<boolean> {\n if (!this.entity.metadata.uid) {\n throw new Error(\n 'Trying to build documentation for entity not in software catalog',\n );\n }\n\n /**\n * Prepare (and cache check)\n */\n\n this.logger.info(\n `Step 1 of 3: Preparing docs for entity ${stringifyEntityRef(\n this.entity,\n )}`,\n );\n\n // If available, use the etag stored in techdocs_metadata.json to\n // check if docs are outdated and need to be regenerated.\n let storedEtag: string | undefined;\n if (await this.publisher.hasDocsBeenGenerated(this.entity)) {\n try {\n storedEtag = (\n await this.publisher.fetchTechDocsMetadata({\n namespace: this.entity.metadata.namespace ?? DEFAULT_NAMESPACE,\n kind: this.entity.kind,\n name: this.entity.metadata.name,\n })\n ).etag;\n } catch (err) {\n // Proceed with a fresh build\n this.logger.warn(\n `Unable to read techdocs_metadata.json, proceeding with fresh build, error ${err}.`,\n );\n }\n }\n\n let preparedDir: string;\n let newEtag: string;\n try {\n const preparerResponse = await this.preparer.prepare(this.entity, {\n etag: storedEtag,\n logger: this.logger,\n });\n\n preparedDir = preparerResponse.preparedDir;\n newEtag = preparerResponse.etag;\n } catch (err) {\n if (isError(err) && err.name === 'NotModifiedError') {\n // No need to prepare anymore since cache is valid.\n // Set last check happened to now\n new BuildMetadataStorage(this.entity.metadata.uid).setLastUpdated();\n this.logger.debug(\n `Docs for ${stringifyEntityRef(\n this.entity,\n )} are unmodified. Using cache, skipping generate and prepare`,\n );\n return false;\n }\n throw err;\n }\n\n this.logger.info(\n `Prepare step completed for entity ${stringifyEntityRef(\n this.entity,\n )}, stored at ${preparedDir}`,\n );\n\n /**\n * Generate\n */\n\n this.logger.info(\n `Step 2 of 3: Generating docs for entity ${stringifyEntityRef(\n this.entity,\n )}`,\n );\n\n const workingDir = this.config.getOptionalString(\n 'backend.workingDirectory',\n );\n const tmpdirPath = workingDir || os.tmpdir();\n // Fixes a problem with macOS returning a path that is a symlink\n const tmpdirResolvedPath = fs.realpathSync(tmpdirPath);\n const outputDir = await fs.mkdtemp(\n path.join(tmpdirResolvedPath, 'techdocs-tmp-'),\n );\n\n const parsedLocationAnnotation = getLocationForEntity(\n this.entity,\n this.scmIntegrations,\n );\n await this.generator.run({\n inputDir: preparedDir,\n outputDir,\n parsedLocationAnnotation,\n etag: newEtag,\n logger: this.logger,\n logStream: this.logStream,\n siteOptions: {\n name: this.entity.metadata.title ?? this.entity.metadata.name,\n },\n });\n\n // Remove Prepared directory since it is no longer needed.\n // Caveat: Can not remove prepared directory in case of git preparer since the\n // local git repository is used to get etag on subsequent requests.\n if (this.preparer.shouldCleanPreparedDirectory()) {\n this.logger.debug(\n `Removing prepared directory ${preparedDir} since the site has been generated`,\n );\n try {\n // Not a blocker hence no need to await this.\n fs.remove(preparedDir);\n } catch (error) {\n assertError(error);\n this.logger.debug(`Error removing prepared directory ${error.message}`);\n }\n }\n\n /**\n * Publish\n */\n\n this.logger.info(\n `Step 3 of 3: Publishing docs for entity ${stringifyEntityRef(\n this.entity,\n )}`,\n );\n\n const published = await this.publisher.publish({\n entity: this.entity,\n directory: outputDir,\n });\n\n // Invalidate the cache for any published objects.\n if (this.cache && published && published?.objects?.length) {\n this.logger.debug(\n `Invalidating ${published.objects.length} cache objects`,\n );\n await this.cache.invalidateMultiple(published.objects);\n }\n\n try {\n // Not a blocker hence no need to await this.\n fs.remove(outputDir);\n this.logger.debug(\n `Removing generated directory ${outputDir} since the site has been published`,\n );\n } catch (error) {\n assertError(error);\n this.logger.debug(`Error removing generated directory ${error.message}`);\n }\n\n // Update the last check time for the entity\n new BuildMetadataStorage(this.entity.metadata.uid).setLastUpdated();\n\n return true;\n }\n}\n"],"names":["stringifyEntityRef","DEFAULT_NAMESPACE","isError","BuildMetadataStorage","os","fs","path","getLocationForEntity","assertError"],"mappings":"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"}
package/dist/alpha.cjs.js CHANGED
@@ -2,126 +2,9 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var backendCommon = require('@backstage/backend-common');
6
- var backendPluginApi = require('@backstage/backend-plugin-api');
7
- var pluginTechdocsNode = require('@backstage/plugin-techdocs-node');
8
- var pluginTechdocsBackend = require('@backstage/plugin-techdocs-backend');
9
- var alpha = require('@backstage/plugin-catalog-node/alpha');
5
+ var plugin = require('./plugin.cjs.js');
10
6
 
11
- const techdocsPlugin = backendPluginApi.createBackendPlugin({
12
- pluginId: "techdocs",
13
- register(env) {
14
- let docsBuildStrategy;
15
- let buildLogTransport;
16
- env.registerExtensionPoint(pluginTechdocsNode.techdocsBuildsExtensionPoint, {
17
- setBuildStrategy(buildStrategy) {
18
- if (docsBuildStrategy) {
19
- throw new Error("DocsBuildStrategy may only be set once");
20
- }
21
- docsBuildStrategy = buildStrategy;
22
- },
23
- setBuildLogTransport(transport) {
24
- if (buildLogTransport) {
25
- throw new Error("BuildLogTransport may only be set once");
26
- }
27
- buildLogTransport = transport;
28
- }
29
- });
30
- let customTechdocsGenerator;
31
- env.registerExtensionPoint(pluginTechdocsNode.techdocsGeneratorExtensionPoint, {
32
- setTechdocsGenerator(generator) {
33
- if (customTechdocsGenerator) {
34
- throw new Error("TechdocsGenerator may only be set once");
35
- }
36
- customTechdocsGenerator = generator;
37
- }
38
- });
39
- const customPreparers = /* @__PURE__ */ new Map();
40
- env.registerExtensionPoint(pluginTechdocsNode.techdocsPreparerExtensionPoint, {
41
- registerPreparer(protocol, preparer) {
42
- if (customPreparers.has(protocol)) {
43
- throw new Error(
44
- `Preparer for protocol ${protocol} is already registered`
45
- );
46
- }
47
- customPreparers.set(protocol, preparer);
48
- }
49
- });
50
- let customTechdocsPublisher;
51
- env.registerExtensionPoint(pluginTechdocsNode.techdocsPublisherExtensionPoint, {
52
- registerPublisher(type, publisher) {
53
- if (customTechdocsPublisher) {
54
- throw new Error(`Publisher for type ${type} is already registered`);
55
- }
56
- customTechdocsPublisher = publisher;
57
- }
58
- });
59
- env.registerInit({
60
- deps: {
61
- config: backendPluginApi.coreServices.rootConfig,
62
- logger: backendPluginApi.coreServices.logger,
63
- urlReader: backendPluginApi.coreServices.urlReader,
64
- http: backendPluginApi.coreServices.httpRouter,
65
- discovery: backendPluginApi.coreServices.discovery,
66
- cache: backendPluginApi.coreServices.cache,
67
- httpAuth: backendPluginApi.coreServices.httpAuth,
68
- auth: backendPluginApi.coreServices.auth,
69
- catalog: alpha.catalogServiceRef
70
- },
71
- async init({
72
- config,
73
- logger,
74
- urlReader,
75
- http,
76
- discovery,
77
- cache,
78
- httpAuth,
79
- auth,
80
- catalog
81
- }) {
82
- const winstonLogger = backendCommon.loggerToWinstonLogger(logger);
83
- const preparers = await pluginTechdocsNode.Preparers.fromConfig(config, {
84
- reader: urlReader,
85
- logger: winstonLogger
86
- });
87
- for (const [protocol, preparer] of customPreparers.entries()) {
88
- preparers.register(protocol, preparer);
89
- }
90
- const generators = await pluginTechdocsNode.Generators.fromConfig(config, {
91
- logger: winstonLogger,
92
- customGenerator: customTechdocsGenerator
93
- });
94
- const publisher = await pluginTechdocsNode.Publisher.fromConfig(config, {
95
- logger: winstonLogger,
96
- discovery,
97
- customPublisher: customTechdocsPublisher
98
- });
99
- await publisher.getReadiness();
100
- const cacheManager = backendCommon.cacheToPluginCacheManager(cache);
101
- http.use(
102
- await pluginTechdocsBackend.createRouter({
103
- logger: winstonLogger,
104
- cache: cacheManager,
105
- docsBuildStrategy,
106
- buildLogTransport,
107
- preparers,
108
- generators,
109
- publisher,
110
- config,
111
- discovery,
112
- httpAuth,
113
- auth,
114
- catalogClient: catalog
115
- })
116
- );
117
- http.addAuthPolicy({
118
- path: "/static",
119
- allow: "user-cookie"
120
- });
121
- }
122
- });
123
- }
124
- });
125
7
 
126
- exports.default = techdocsPlugin;
8
+
9
+ exports.default = plugin.techdocsPlugin;
127
10
  //# sourceMappingURL=alpha.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n cacheToPluginCacheManager,\n loggerToWinstonLogger,\n} from '@backstage/backend-common';\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport {\n DocsBuildStrategy,\n Generators,\n PreparerBase,\n Preparers,\n Publisher,\n PublisherBase,\n PublisherType,\n RemoteProtocol,\n techdocsBuildsExtensionPoint,\n TechdocsGenerator,\n techdocsGeneratorExtensionPoint,\n techdocsPreparerExtensionPoint,\n techdocsPublisherExtensionPoint,\n} from '@backstage/plugin-techdocs-node';\nimport { createRouter } from '@backstage/plugin-techdocs-backend';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport * as winston from 'winston';\n\n/**\n * The TechDocs plugin is responsible for serving and building documentation for any entity.\n * @alpha\n */\nexport const techdocsPlugin = createBackendPlugin({\n pluginId: 'techdocs',\n register(env) {\n let docsBuildStrategy: DocsBuildStrategy | undefined;\n let buildLogTransport: winston.transport | undefined;\n env.registerExtensionPoint(techdocsBuildsExtensionPoint, {\n setBuildStrategy(buildStrategy: DocsBuildStrategy) {\n if (docsBuildStrategy) {\n throw new Error('DocsBuildStrategy may only be set once');\n }\n docsBuildStrategy = buildStrategy;\n },\n setBuildLogTransport(transport: winston.transport) {\n if (buildLogTransport) {\n throw new Error('BuildLogTransport may only be set once');\n }\n buildLogTransport = transport;\n },\n });\n\n let customTechdocsGenerator: TechdocsGenerator | undefined;\n env.registerExtensionPoint(techdocsGeneratorExtensionPoint, {\n setTechdocsGenerator(generator: TechdocsGenerator) {\n if (customTechdocsGenerator) {\n throw new Error('TechdocsGenerator may only be set once');\n }\n\n customTechdocsGenerator = generator;\n },\n });\n\n const customPreparers = new Map<RemoteProtocol, PreparerBase>();\n env.registerExtensionPoint(techdocsPreparerExtensionPoint, {\n registerPreparer(protocol: RemoteProtocol, preparer: PreparerBase) {\n if (customPreparers.has(protocol)) {\n throw new Error(\n `Preparer for protocol ${protocol} is already registered`,\n );\n }\n customPreparers.set(protocol, preparer);\n },\n });\n\n let customTechdocsPublisher: PublisherBase | undefined;\n env.registerExtensionPoint(techdocsPublisherExtensionPoint, {\n registerPublisher(type: PublisherType, publisher: PublisherBase) {\n if (customTechdocsPublisher) {\n throw new Error(`Publisher for type ${type} is already registered`);\n }\n customTechdocsPublisher = publisher;\n },\n });\n\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n urlReader: coreServices.urlReader,\n http: coreServices.httpRouter,\n discovery: coreServices.discovery,\n cache: coreServices.cache,\n httpAuth: coreServices.httpAuth,\n auth: coreServices.auth,\n catalog: catalogServiceRef,\n },\n async init({\n config,\n logger,\n urlReader,\n http,\n discovery,\n cache,\n httpAuth,\n auth,\n catalog,\n }) {\n const winstonLogger = loggerToWinstonLogger(logger);\n // Preparers are responsible for fetching source files for documentation.\n const preparers = await Preparers.fromConfig(config, {\n reader: urlReader,\n logger: winstonLogger,\n });\n for (const [protocol, preparer] of customPreparers.entries()) {\n preparers.register(protocol, preparer);\n }\n\n // Generators are used for generating documentation sites.\n const generators = await Generators.fromConfig(config, {\n logger: winstonLogger,\n customGenerator: customTechdocsGenerator,\n });\n\n // Publisher is used for\n // 1. Publishing generated files to storage\n // 2. Fetching files from storage and passing them to TechDocs frontend.\n const publisher = await Publisher.fromConfig(config, {\n logger: winstonLogger,\n discovery: discovery,\n customPublisher: customTechdocsPublisher,\n });\n\n // checks if the publisher is working and logs the result\n await publisher.getReadiness();\n\n const cacheManager = cacheToPluginCacheManager(cache);\n http.use(\n await createRouter({\n logger: winstonLogger,\n cache: cacheManager,\n docsBuildStrategy,\n buildLogTransport,\n preparers,\n generators,\n publisher,\n config,\n discovery,\n httpAuth,\n auth,\n catalogClient: catalog,\n }),\n );\n\n http.addAuthPolicy({\n path: '/static',\n allow: 'user-cookie',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","techdocsBuildsExtensionPoint","techdocsGeneratorExtensionPoint","techdocsPreparerExtensionPoint","techdocsPublisherExtensionPoint","coreServices","catalogServiceRef","loggerToWinstonLogger","Preparers","Generators","Publisher","cacheToPluginCacheManager","createRouter"],"mappings":"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"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@backstage/errors');
4
+
5
+ class CacheInvalidationError extends errors.CustomErrorBase {
6
+ }
7
+ class TechDocsCache {
8
+ cache;
9
+ logger;
10
+ readTimeout;
11
+ constructor({
12
+ cache,
13
+ logger,
14
+ readTimeout
15
+ }) {
16
+ this.cache = cache;
17
+ this.logger = logger;
18
+ this.readTimeout = readTimeout;
19
+ }
20
+ static fromConfig(config, { cache, logger }) {
21
+ const timeout = config.getOptionalNumber("techdocs.cache.readTimeout");
22
+ const readTimeout = timeout === void 0 ? 1e3 : timeout;
23
+ return new TechDocsCache({ cache, logger, readTimeout });
24
+ }
25
+ async get(path) {
26
+ try {
27
+ const response = await Promise.race([
28
+ this.cache.get(path),
29
+ new Promise((cancelAfter) => setTimeout(cancelAfter, this.readTimeout))
30
+ ]);
31
+ if (response !== void 0) {
32
+ this.logger.debug(`Cache hit: ${path}`);
33
+ return Buffer.from(response, "base64");
34
+ }
35
+ this.logger.debug(`Cache miss: ${path}`);
36
+ return response;
37
+ } catch (e) {
38
+ errors.assertError(e);
39
+ this.logger.warn(`Error getting cache entry ${path}: ${e.message}`);
40
+ this.logger.debug(e.message, e);
41
+ return void 0;
42
+ }
43
+ }
44
+ async set(path, data) {
45
+ this.logger.debug(`Writing cache entry for ${path}`);
46
+ this.cache.set(path, data.toString("base64")).catch((e) => this.logger.error("write error", e));
47
+ }
48
+ async invalidate(path) {
49
+ return this.cache.delete(path);
50
+ }
51
+ async invalidateMultiple(paths) {
52
+ const settled = await Promise.allSettled(
53
+ paths.map((path) => this.cache.delete(path))
54
+ );
55
+ const rejected = settled.filter(
56
+ (s) => s.status === "rejected"
57
+ );
58
+ if (rejected.length) {
59
+ throw new CacheInvalidationError(
60
+ "TechDocs cache invalidation error",
61
+ rejected
62
+ );
63
+ }
64
+ return settled;
65
+ }
66
+ }
67
+
68
+ exports.CacheInvalidationError = CacheInvalidationError;
69
+ exports.TechDocsCache = TechDocsCache;
70
+ //# sourceMappingURL=TechDocsCache.cjs.js.map
@@ -0,0 +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 const timeout = config.getOptionalNumber('techdocs.cache.readTimeout');\n const readTimeout = timeout === undefined ? 1000 : timeout;\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","assertError"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ var router = require('express-promise-router');
4
+
5
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
6
+
7
+ var router__default = /*#__PURE__*/_interopDefaultCompat(router);
8
+
9
+ const createCacheMiddleware = ({
10
+ cache
11
+ }) => {
12
+ const cacheMiddleware = router__default.default();
13
+ cacheMiddleware.use(async (req, res, next) => {
14
+ const socket = res.socket;
15
+ const isCacheable = req.path.startsWith("/static/docs/");
16
+ const isGetRequest = req.method === "GET";
17
+ if (!isCacheable || !socket) {
18
+ next();
19
+ return;
20
+ }
21
+ const reqPath = decodeURI(req.path.match(/\/static\/docs\/(.*)$/)[1]);
22
+ const realEnd = socket.end.bind(socket);
23
+ const realWrite = socket.write.bind(socket);
24
+ let writeToCache = true;
25
+ const chunks = [];
26
+ socket.write = (data, encoding, callback) => {
27
+ chunks.push(Buffer.from(data));
28
+ if (typeof encoding === "function") {
29
+ return realWrite(data, encoding);
30
+ }
31
+ return realWrite(data, encoding, callback);
32
+ };
33
+ socket.on("close", async (hadError) => {
34
+ const content = Buffer.concat(chunks);
35
+ const head = content.toString("utf8", 0, 12);
36
+ if (isGetRequest && writeToCache && !hadError && head.match(/HTTP\/\d\.\d 200/)) {
37
+ await cache.set(reqPath, content);
38
+ }
39
+ });
40
+ const cached = await cache.get(reqPath);
41
+ if (cached) {
42
+ writeToCache = false;
43
+ realEnd(cached);
44
+ return;
45
+ }
46
+ next();
47
+ });
48
+ return cacheMiddleware;
49
+ };
50
+
51
+ exports.createCacheMiddleware = createCacheMiddleware;
52
+ //# sourceMappingURL=cacheMiddleware.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheMiddleware.cjs.js","sources":["../../src/cache/cacheMiddleware.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 { Router } from 'express';\nimport router from 'express-promise-router';\nimport { TechDocsCache } from './TechDocsCache';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype CacheMiddlewareOptions = {\n cache: TechDocsCache;\n logger: LoggerService;\n};\n\ntype ErrorCallback = (err?: Error) => void;\n\nexport const createCacheMiddleware = ({\n cache,\n}: CacheMiddlewareOptions): Router => {\n const cacheMiddleware = router();\n\n // Middleware that, through socket monkey patching, captures responses as\n // they're sent over /static/docs/* and caches them. Subsequent requests are\n // loaded from cache. Cache key is the object's path (after `/static/docs/`).\n cacheMiddleware.use(async (req, res, next) => {\n const socket = res.socket;\n const isCacheable = req.path.startsWith('/static/docs/');\n const isGetRequest = req.method === 'GET';\n\n // Continue early if this is non-cacheable, or there's no socket.\n if (!isCacheable || !socket) {\n next();\n return;\n }\n\n // Make concrete references to these things.\n const reqPath = decodeURI(req.path.match(/\\/static\\/docs\\/(.*)$/)![1]);\n const realEnd = socket.end.bind(socket);\n const realWrite = socket.write.bind(socket);\n let writeToCache = true;\n const chunks: Buffer[] = [];\n\n // Monkey-patch the response's socket to keep track of chunks as they are\n // written over the wire.\n socket.write = (\n data: string | Uint8Array,\n encoding?: BufferEncoding | ErrorCallback,\n callback?: ErrorCallback,\n ) => {\n chunks.push(Buffer.from(data));\n if (typeof encoding === 'function') {\n return realWrite(data, encoding);\n }\n return realWrite(data, encoding, callback);\n };\n\n // When a socket is closed, if there were no errors and the data written\n // over the socket should be cached, cache it!\n socket.on('close', async hadError => {\n const content = Buffer.concat(chunks);\n const head = content.toString('utf8', 0, 12);\n if (\n isGetRequest &&\n writeToCache &&\n !hadError &&\n head.match(/HTTP\\/\\d\\.\\d 200/)\n ) {\n await cache.set(reqPath, content);\n }\n });\n\n // Attempt to retrieve data from the cache.\n const cached = await cache.get(reqPath);\n\n // If there is a cache hit, write it out on the socket, ensure we don't re-\n // cache the data, and prevent going back to canonical storage by never\n // calling next().\n if (cached) {\n writeToCache = false;\n realEnd(cached);\n return;\n }\n\n // No data retrieved from cache: allow retrieval from canonical storage.\n next();\n });\n\n return cacheMiddleware;\n};\n"],"names":["router"],"mappings":";;;;;;;;AA2BO,MAAM,wBAAwB,CAAC;AAAA,EACpC,KAAA;AACF,CAAsC,KAAA;AACpC,EAAA,MAAM,kBAAkBA,uBAAO,EAAA,CAAA;AAK/B,EAAA,eAAA,CAAgB,GAAI,CAAA,OAAO,GAAK,EAAA,GAAA,EAAK,IAAS,KAAA;AAC5C,IAAA,MAAM,SAAS,GAAI,CAAA,MAAA,CAAA;AACnB,IAAA,MAAM,WAAc,GAAA,GAAA,CAAI,IAAK,CAAA,UAAA,CAAW,eAAe,CAAA,CAAA;AACvD,IAAM,MAAA,YAAA,GAAe,IAAI,MAAW,KAAA,KAAA,CAAA;AAGpC,IAAI,IAAA,CAAC,WAAe,IAAA,CAAC,MAAQ,EAAA;AAC3B,MAAK,IAAA,EAAA,CAAA;AACL,MAAA,OAAA;AAAA,KACF;AAGA,IAAM,MAAA,OAAA,GAAU,UAAU,GAAI,CAAA,IAAA,CAAK,MAAM,uBAAuB,CAAA,CAAG,CAAC,CAAC,CAAA,CAAA;AACrE,IAAA,MAAM,OAAU,GAAA,MAAA,CAAO,GAAI,CAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AACtC,IAAA,MAAM,SAAY,GAAA,MAAA,CAAO,KAAM,CAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAC1C,IAAA,IAAI,YAAe,GAAA,IAAA,CAAA;AACnB,IAAA,MAAM,SAAmB,EAAC,CAAA;AAI1B,IAAA,MAAA,CAAO,KAAQ,GAAA,CACb,IACA,EAAA,QAAA,EACA,QACG,KAAA;AACH,MAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,IAAK,CAAA,IAAI,CAAC,CAAA,CAAA;AAC7B,MAAI,IAAA,OAAO,aAAa,UAAY,EAAA;AAClC,QAAO,OAAA,SAAA,CAAU,MAAM,QAAQ,CAAA,CAAA;AAAA,OACjC;AACA,MAAO,OAAA,SAAA,CAAU,IAAM,EAAA,QAAA,EAAU,QAAQ,CAAA,CAAA;AAAA,KAC3C,CAAA;AAIA,IAAO,MAAA,CAAA,EAAA,CAAG,OAAS,EAAA,OAAM,QAAY,KAAA;AACnC,MAAM,MAAA,OAAA,GAAU,MAAO,CAAA,MAAA,CAAO,MAAM,CAAA,CAAA;AACpC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,QAAS,CAAA,MAAA,EAAQ,GAAG,EAAE,CAAA,CAAA;AAC3C,MAAA,IACE,gBACA,YACA,IAAA,CAAC,YACD,IAAK,CAAA,KAAA,CAAM,kBAAkB,CAC7B,EAAA;AACA,QAAM,MAAA,KAAA,CAAM,GAAI,CAAA,OAAA,EAAS,OAAO,CAAA,CAAA;AAAA,OAClC;AAAA,KACD,CAAA,CAAA;AAGD,IAAA,MAAM,MAAS,GAAA,MAAM,KAAM,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAKtC,IAAA,IAAI,MAAQ,EAAA;AACV,MAAe,YAAA,GAAA,KAAA,CAAA;AACf,MAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AACd,MAAA,OAAA;AAAA,KACF;AAGA,IAAK,IAAA,EAAA,CAAA;AAAA,GACN,CAAA,CAAA;AAED,EAAO,OAAA,eAAA,CAAA;AACT;;;;"}