@backstage/plugin-techdocs-backend 1.10.5 → 1.10.6-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,33 @@
1
1
  # @backstage/plugin-techdocs-backend
2
2
 
3
+ ## 1.10.6-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/backend-plugin-api@0.6.19-next.1
9
+ - @backstage/backend-common@0.23.0-next.1
10
+ - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1
11
+ - @backstage/plugin-techdocs-node@1.12.5-next.1
12
+
13
+ ## 1.10.6-next.0
14
+
15
+ ### Patch Changes
16
+
17
+ - 8869b8e: Updated local development setup.
18
+ - Updated dependencies
19
+ - @backstage/backend-common@0.22.1-next.0
20
+ - @backstage/backend-plugin-api@0.6.19-next.0
21
+ - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0
22
+ - @backstage/plugin-techdocs-node@1.12.5-next.0
23
+ - @backstage/catalog-client@1.6.5
24
+ - @backstage/catalog-model@1.5.0
25
+ - @backstage/config@1.2.0
26
+ - @backstage/errors@1.2.4
27
+ - @backstage/integration@1.11.0
28
+ - @backstage/plugin-catalog-common@1.0.23
29
+ - @backstage/plugin-permission-common@0.7.13
30
+
3
31
  ## 1.10.5
4
32
 
5
33
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-techdocs-backend",
3
- "version": "1.10.5",
3
+ "version": "1.10.6-next.1",
4
4
  "main": "../dist/alpha.cjs.js",
5
5
  "types": "../dist/alpha.d.ts"
6
6
  }
package/dist/index.cjs.js CHANGED
@@ -47,17 +47,11 @@ var os__default = /*#__PURE__*/_interopDefaultCompat(os);
47
47
  var path__default = /*#__PURE__*/_interopDefaultCompat(path);
48
48
  var unescape__default = /*#__PURE__*/_interopDefaultCompat(unescape);
49
49
 
50
- var __defProp$6 = Object.defineProperty;
51
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
52
- var __publicField$6 = (obj, key, value) => {
53
- __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
54
- return value;
55
- };
56
50
  const lastUpdatedRecord = {};
57
51
  class BuildMetadataStorage {
52
+ entityUid;
53
+ lastUpdatedRecord;
58
54
  constructor(entityUid) {
59
- __publicField$6(this, "entityUid");
60
- __publicField$6(this, "lastUpdatedRecord");
61
55
  this.entityUid = entityUid;
62
56
  this.lastUpdatedRecord = lastUpdatedRecord;
63
57
  }
@@ -78,13 +72,16 @@ const shouldCheckForUpdate = (entityUid) => {
78
72
  return true;
79
73
  };
80
74
 
81
- var __defProp$5 = Object.defineProperty;
82
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
83
- var __publicField$5 = (obj, key, value) => {
84
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
85
- return value;
86
- };
87
75
  class DocsBuilder {
76
+ preparer;
77
+ generator;
78
+ publisher;
79
+ entity;
80
+ logger;
81
+ config;
82
+ scmIntegrations;
83
+ logStream;
84
+ cache;
88
85
  constructor({
89
86
  preparers,
90
87
  generators,
@@ -96,15 +93,6 @@ class DocsBuilder {
96
93
  logStream,
97
94
  cache
98
95
  }) {
99
- __publicField$5(this, "preparer");
100
- __publicField$5(this, "generator");
101
- __publicField$5(this, "publisher");
102
- __publicField$5(this, "entity");
103
- __publicField$5(this, "logger");
104
- __publicField$5(this, "config");
105
- __publicField$5(this, "scmIntegrations");
106
- __publicField$5(this, "logStream");
107
- __publicField$5(this, "cache");
108
96
  this.preparer = preparers.get(entity);
109
97
  this.generator = generators.get(entity);
110
98
  this.publisher = publisher;
@@ -120,7 +108,6 @@ class DocsBuilder {
120
108
  * @returns true, if the docs have been built. false, if the cached docs are still up-to-date.
121
109
  */
122
110
  async build() {
123
- var _a, _b, _c;
124
111
  if (!this.entity.metadata.uid) {
125
112
  throw new Error(
126
113
  "Trying to build documentation for entity not in software catalog"
@@ -135,7 +122,7 @@ class DocsBuilder {
135
122
  if (await this.publisher.hasDocsBeenGenerated(this.entity)) {
136
123
  try {
137
124
  storedEtag = (await this.publisher.fetchTechDocsMetadata({
138
- namespace: (_a = this.entity.metadata.namespace) != null ? _a : catalogModel.DEFAULT_NAMESPACE,
125
+ namespace: this.entity.metadata.namespace ?? catalogModel.DEFAULT_NAMESPACE,
139
126
  kind: this.entity.kind,
140
127
  name: this.entity.metadata.name
141
128
  })).etag;
@@ -196,7 +183,7 @@ class DocsBuilder {
196
183
  logger: this.logger,
197
184
  logStream: this.logStream,
198
185
  siteOptions: {
199
- name: (_b = this.entity.metadata.title) != null ? _b : this.entity.metadata.name
186
+ name: this.entity.metadata.title ?? this.entity.metadata.name
200
187
  }
201
188
  });
202
189
  if (this.preparer.shouldCleanPreparedDirectory()) {
@@ -219,7 +206,7 @@ class DocsBuilder {
219
206
  entity: this.entity,
220
207
  directory: outputDir
221
208
  });
222
- if (this.cache && published && ((_c = published == null ? void 0 : published.objects) == null ? void 0 : _c.length)) {
209
+ if (this.cache && published && published?.objects?.length) {
223
210
  this.logger.debug(
224
211
  `Invalidating ${published.objects.length} cache objects`
225
212
  );
@@ -239,13 +226,14 @@ class DocsBuilder {
239
226
  }
240
227
  }
241
228
 
242
- var __defProp$4 = Object.defineProperty;
243
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
244
- var __publicField$4 = (obj, key, value) => {
245
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
246
- return value;
247
- };
248
229
  class DocsSynchronizer {
230
+ publisher;
231
+ logger;
232
+ buildLogTransport;
233
+ config;
234
+ scmIntegrations;
235
+ cache;
236
+ buildLimiter;
249
237
  constructor({
250
238
  publisher,
251
239
  logger,
@@ -254,13 +242,6 @@ class DocsSynchronizer {
254
242
  scmIntegrations,
255
243
  cache
256
244
  }) {
257
- __publicField$4(this, "publisher");
258
- __publicField$4(this, "logger");
259
- __publicField$4(this, "buildLogTransport");
260
- __publicField$4(this, "config");
261
- __publicField$4(this, "scmIntegrations");
262
- __publicField$4(this, "cache");
263
- __publicField$4(this, "buildLimiter");
264
245
  this.config = config;
265
246
  this.logger = logger;
266
247
  this.buildLogTransport = buildLogTransport;
@@ -356,13 +337,12 @@ class DocsSynchronizer {
356
337
  token,
357
338
  entity
358
339
  }) {
359
- var _a;
360
340
  if (!shouldCheckForUpdate(entity.metadata.uid) || !this.cache) {
361
341
  finish({ updated: false });
362
342
  return;
363
343
  }
364
344
  const baseUrl = await discovery.getBaseUrl("techdocs");
365
- const namespace = ((_a = entity.metadata) == null ? void 0 : _a.namespace) || catalogModel.DEFAULT_NAMESPACE;
345
+ const namespace = entity.metadata?.namespace || catalogModel.DEFAULT_NAMESPACE;
366
346
  const kind = entity.kind;
367
347
  const name = entity.metadata.name;
368
348
  const legacyPathCasing = this.config.getOptionalBoolean(
@@ -448,23 +428,17 @@ const createCacheMiddleware = ({
448
428
  return cacheMiddleware;
449
429
  };
450
430
 
451
- var __defProp$3 = Object.defineProperty;
452
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
453
- var __publicField$3 = (obj, key, value) => {
454
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
455
- return value;
456
- };
457
431
  class CacheInvalidationError extends errors.CustomErrorBase {
458
432
  }
459
433
  class TechDocsCache {
434
+ cache;
435
+ logger;
436
+ readTimeout;
460
437
  constructor({
461
438
  cache,
462
439
  logger,
463
440
  readTimeout
464
441
  }) {
465
- __publicField$3(this, "cache");
466
- __publicField$3(this, "logger");
467
- __publicField$3(this, "readTimeout");
468
442
  this.cache = cache;
469
443
  this.logger = logger;
470
444
  this.readTimeout = readTimeout;
@@ -517,17 +491,11 @@ class TechDocsCache {
517
491
  }
518
492
  }
519
493
 
520
- var __defProp$2 = Object.defineProperty;
521
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
522
- var __publicField$2 = (obj, key, value) => {
523
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
524
- return value;
525
- };
526
494
  class CachedEntityLoader {
495
+ catalog;
496
+ cache;
497
+ readTimeout = 1e3;
527
498
  constructor({ catalog, cache }) {
528
- __publicField$2(this, "catalog");
529
- __publicField$2(this, "cache");
530
- __publicField$2(this, "readTimeout", 1e3);
531
499
  this.catalog = catalog;
532
500
  this.cache = cache;
533
501
  }
@@ -558,15 +526,9 @@ class CachedEntityLoader {
558
526
  }
559
527
  }
560
528
 
561
- var __defProp$1 = Object.defineProperty;
562
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
563
- var __publicField$1 = (obj, key, value) => {
564
- __defNormalProp$1(obj, key + "" , value);
565
- return value;
566
- };
567
529
  class DefaultDocsBuildStrategy {
530
+ config;
568
531
  constructor(config) {
569
- __publicField$1(this, "config");
570
532
  this.config = config;
571
533
  }
572
534
  static fromConfig(config) {
@@ -583,12 +545,11 @@ function isOutOfTheBoxOption(opt) {
583
545
  return opt.preparers !== void 0;
584
546
  }
585
547
  async function createRouter(options) {
586
- var _a, _b;
587
548
  const router = router__default.default();
588
549
  const { publisher, config, logger, discovery } = options;
589
550
  const { auth, httpAuth } = backendCommon.createLegacyAuthAdapters(options);
590
- const catalogClient$1 = (_a = options.catalogClient) != null ? _a : new catalogClient.CatalogClient({ discoveryApi: discovery });
591
- const docsBuildStrategy = (_b = options.docsBuildStrategy) != null ? _b : DefaultDocsBuildStrategy.fromConfig(config);
551
+ const catalogClient$1 = options.catalogClient ?? new catalogClient.CatalogClient({ discoveryApi: discovery });
552
+ const docsBuildStrategy = options.docsBuildStrategy ?? DefaultDocsBuildStrategy.fromConfig(config);
592
553
  const buildLogTransport = options.buildLogTransport;
593
554
  const entityLoader = new CachedEntityLoader({
594
555
  catalog: catalogClient$1,
@@ -670,7 +631,6 @@ async function createRouter(options) {
670
631
  }
671
632
  });
672
633
  router.get("/sync/:namespace/:kind/:name", async (req, res) => {
673
- var _a2;
674
634
  const { kind, namespace, name } = req.params;
675
635
  const credentials = await httpAuth.credentials(req);
676
636
  const { token } = await auth.getPluginRequestToken({
@@ -678,7 +638,7 @@ async function createRouter(options) {
678
638
  targetPluginId: "catalog"
679
639
  });
680
640
  const entity = await entityLoader.load({ kind, namespace, name }, token);
681
- if (!((_a2 = entity == null ? void 0 : entity.metadata) == null ? void 0 : _a2.uid)) {
641
+ if (!entity?.metadata?.uid) {
682
642
  throw new errors.NotFoundError("Entity metadata UID missing");
683
643
  }
684
644
  const responseHandler = createEventStream(res);
@@ -742,13 +702,12 @@ async function createRouter(options) {
742
702
  return router;
743
703
  }
744
704
  function createEventStream(res) {
745
- var _a;
746
705
  res.writeHead(200, {
747
706
  Connection: "keep-alive",
748
707
  "Cache-Control": "no-cache",
749
708
  "Content-Type": "text/event-stream"
750
709
  });
751
- (_a = res.socket) == null ? void 0 : _a.on("close", () => {
710
+ res.socket?.on("close", () => {
752
711
  res.end();
753
712
  });
754
713
  const send = (type, data) => {
@@ -775,19 +734,13 @@ data: ${JSON.stringify(data)}
775
734
  };
776
735
  }
777
736
 
778
- var __defProp = Object.defineProperty;
779
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
780
- var __publicField = (obj, key, value) => {
781
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
782
- return value;
783
- };
784
737
  class DefaultTechDocsCollator {
785
738
  constructor(legacyPathCasing, options) {
786
739
  this.legacyPathCasing = legacyPathCasing;
787
740
  this.options = options;
788
- __publicField(this, "type", "techdocs");
789
- __publicField(this, "visibilityPermission", alpha.catalogEntityReadPermission);
790
741
  }
742
+ type = "techdocs";
743
+ visibilityPermission = alpha.catalogEntityReadPermission;
791
744
  static fromConfig(config, options) {
792
745
  const legacyPathCasing = config.getOptionalBoolean(
793
746
  "techdocs.legacyUseCaseSensitiveTripletPaths"
@@ -803,10 +756,10 @@ class DefaultTechDocsCollator {
803
756
  locationTemplate,
804
757
  logger
805
758
  } = this.options;
806
- const limit = pLimit__default.default(parallelismLimit != null ? parallelismLimit : 10);
759
+ const limit = pLimit__default.default(parallelismLimit ?? 10);
807
760
  const techDocsBaseUrl = await discovery.getBaseUrl("techdocs");
808
761
  const { token } = await tokenManager.getToken();
809
- const entities = await (catalogClient$1 != null ? catalogClient$1 : new catalogClient.CatalogClient({ discoveryApi: discovery })).getEntities(
762
+ const entities = await (catalogClient$1 ?? new catalogClient.CatalogClient({ discoveryApi: discovery })).getEntities(
810
763
  {
811
764
  filter: {
812
765
  "metadata.annotations.backstage.io/techdocs-ref": catalogClient.CATALOG_FILTER_EXISTS
@@ -827,9 +780,8 @@ class DefaultTechDocsCollator {
827
780
  );
828
781
  const docPromises = entities.items.map(
829
782
  (entity) => limit(async () => {
830
- var _a;
831
783
  const entityInfo = DefaultTechDocsCollator.handleEntityInfoCasing(
832
- (_a = this.legacyPathCasing) != null ? _a : false,
784
+ this.legacyPathCasing ?? false,
833
785
  {
834
786
  kind: entity.kind,
835
787
  namespace: entity.metadata.namespace || "default",
@@ -850,29 +802,26 @@ class DefaultTechDocsCollator {
850
802
  }
851
803
  );
852
804
  const searchIndex = await searchIndexResponse.json();
853
- return searchIndex.docs.map((doc) => {
854
- var _a2, _b, _c;
855
- return {
856
- title: unescape__default.default(doc.title),
857
- text: unescape__default.default(doc.text || ""),
858
- location: this.applyArgsToFormat(
859
- locationTemplate || "/docs/:namespace/:kind/:name/:path",
860
- {
861
- ...entityInfo,
862
- path: doc.location
863
- }
864
- ),
865
- path: doc.location,
866
- ...entityInfo,
867
- entityTitle: entity.metadata.title,
868
- componentType: ((_b = (_a2 = entity.spec) == null ? void 0 : _a2.type) == null ? void 0 : _b.toString()) || "other",
869
- lifecycle: ((_c = entity.spec) == null ? void 0 : _c.lifecycle) || "",
870
- owner: getSimpleEntityOwnerString(entity),
871
- authorization: {
872
- resourceRef: catalogModel.stringifyEntityRef(entity)
805
+ return searchIndex.docs.map((doc) => ({
806
+ title: unescape__default.default(doc.title),
807
+ text: unescape__default.default(doc.text || ""),
808
+ location: this.applyArgsToFormat(
809
+ locationTemplate || "/docs/:namespace/:kind/:name/:path",
810
+ {
811
+ ...entityInfo,
812
+ path: doc.location
873
813
  }
874
- };
875
- });
814
+ ),
815
+ path: doc.location,
816
+ ...entityInfo,
817
+ entityTitle: entity.metadata.title,
818
+ componentType: entity.spec?.type?.toString() || "other",
819
+ lifecycle: entity.spec?.lifecycle || "",
820
+ owner: getSimpleEntityOwnerString(entity),
821
+ authorization: {
822
+ resourceRef: catalogModel.stringifyEntityRef(entity)
823
+ }
824
+ }));
876
825
  } catch (e) {
877
826
  logger.debug(
878
827
  `Failed to retrieve tech docs search index for entity ${entityInfo.namespace}/${entityInfo.kind}/${entityInfo.name}`,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/DocsBuilder/BuildMetadataStorage.ts","../src/DocsBuilder/builder.ts","../src/service/DocsSynchronizer.ts","../src/cache/cacheMiddleware.ts","../src/cache/TechDocsCache.ts","../src/service/CachedEntityLoader.ts","../src/service/DefaultDocsBuildStrategy.ts","../src/service/router.ts","../src/search/DefaultTechDocsCollator.ts","../src/search/index.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","/*\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","/*\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 */\n\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport {\n DEFAULT_NAMESPACE,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, NotFoundError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport {\n GeneratorBuilder,\n PreparerBuilder,\n PublisherBase,\n} from '@backstage/plugin-techdocs-node';\nimport fetch from 'node-fetch';\nimport pLimit, { Limit } from 'p-limit';\nimport { PassThrough } from 'stream';\nimport * as winston from 'winston';\nimport { TechDocsCache } from '../cache';\nimport {\n BuildMetadataStorage,\n DocsBuilder,\n shouldCheckForUpdate,\n} from '../DocsBuilder';\n\nexport type DocsSynchronizerSyncOpts = {\n log: (message: string) => void;\n error: (e: Error) => void;\n finish: (result: { updated: boolean }) => void;\n};\n\nexport class DocsSynchronizer {\n private readonly publisher: PublisherBase;\n private readonly logger: winston.Logger;\n private readonly buildLogTransport?: winston.transport;\n private readonly config: Config;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n private readonly cache: TechDocsCache | undefined;\n private readonly buildLimiter: Limit;\n\n constructor({\n publisher,\n logger,\n buildLogTransport,\n config,\n scmIntegrations,\n cache,\n }: {\n publisher: PublisherBase;\n logger: winston.Logger;\n buildLogTransport?: winston.transport;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n cache: TechDocsCache | undefined;\n }) {\n this.config = config;\n this.logger = logger;\n this.buildLogTransport = buildLogTransport;\n this.publisher = publisher;\n this.scmIntegrations = scmIntegrations;\n this.cache = cache;\n\n // Single host/process: limit concurrent builds up to 10 at a time.\n this.buildLimiter = pLimit(10);\n }\n\n async doSync({\n responseHandler: { log, error, finish },\n entity,\n preparers,\n generators,\n }: {\n responseHandler: DocsSynchronizerSyncOpts;\n entity: Entity;\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n }) {\n // create a new logger to log data to the caller\n const taskLogger = winston.createLogger({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.timestamp(),\n winston.format.simple(),\n ),\n defaultMeta: {},\n });\n\n // create an in-memory stream to forward logs to the event-stream\n const logStream = new PassThrough();\n logStream.on('data', async data => {\n log(data.toString().trim());\n });\n\n taskLogger.add(new winston.transports.Stream({ stream: logStream }));\n if (this.buildLogTransport) {\n taskLogger.add(this.buildLogTransport);\n }\n\n // check if the last update check was too recent\n if (!shouldCheckForUpdate(entity.metadata.uid!)) {\n finish({ updated: false });\n return;\n }\n\n let foundDocs = false;\n\n try {\n const docsBuilder = new DocsBuilder({\n preparers,\n generators,\n publisher: this.publisher,\n logger: taskLogger,\n entity,\n config: this.config,\n scmIntegrations: this.scmIntegrations,\n logStream,\n cache: this.cache,\n });\n\n const interval = setInterval(() => {\n taskLogger.info(\n 'The docs building process is taking a little bit longer to process this entity. Please bear with us.',\n );\n }, 10000);\n const updated = await this.buildLimiter(() => docsBuilder.build());\n clearInterval(interval);\n\n if (!updated) {\n finish({ updated: false });\n return;\n }\n } catch (e) {\n assertError(e);\n const msg = `Failed to build the docs page for entity ${stringifyEntityRef(\n entity,\n )}: ${e.message}`;\n taskLogger.error(msg);\n this.logger.error(msg, e);\n error(e);\n return;\n }\n\n // With a maximum of ~5 seconds wait, check if the files got published and if docs will be fetched\n // on the user's page. If not, respond with a message asking them to check back later.\n // The delay here is to make sure GCS/AWS/etc. registers newly uploaded files which is usually <1 second\n for (let attempt = 0; attempt < 5; attempt++) {\n if (await this.publisher.hasDocsBeenGenerated(entity)) {\n foundDocs = true;\n break;\n }\n await new Promise(r => setTimeout(r, 1000));\n }\n if (!foundDocs) {\n this.logger.error(\n 'Published files are taking longer to show up in storage. Something went wrong.',\n );\n error(\n new NotFoundError(\n 'Sorry! It took too long for the generated docs to show up in storage. Are you sure the docs project is generating an `index.html` file? Otherwise, check back later.',\n ),\n );\n return;\n }\n\n finish({ updated: true });\n }\n\n async doCacheSync({\n responseHandler: { finish },\n discovery,\n token,\n entity,\n }: {\n responseHandler: DocsSynchronizerSyncOpts;\n discovery: PluginEndpointDiscovery;\n token: string | undefined;\n entity: Entity;\n }) {\n // Check if the last update check was too recent.\n if (!shouldCheckForUpdate(entity.metadata.uid!) || !this.cache) {\n finish({ updated: false });\n return;\n }\n\n // Fetch techdocs_metadata.json from the publisher and from cache.\n const baseUrl = await discovery.getBaseUrl('techdocs');\n const namespace = entity.metadata?.namespace || DEFAULT_NAMESPACE;\n const kind = entity.kind;\n const name = entity.metadata.name;\n const legacyPathCasing =\n this.config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n const tripletPath = `${namespace}/${kind}/${name}`;\n const entityTripletPath = `${\n legacyPathCasing ? tripletPath : tripletPath.toLocaleLowerCase('en-US')\n }`;\n try {\n const [sourceMetadata, cachedMetadata] = await Promise.all([\n this.publisher.fetchTechDocsMetadata({ namespace, kind, name }),\n fetch(\n `${baseUrl}/static/docs/${entityTripletPath}/techdocs_metadata.json`,\n {\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n },\n ).then(\n f =>\n f.json().catch(() => undefined) as ReturnType<\n PublisherBase['fetchTechDocsMetadata']\n >,\n ),\n ]);\n\n // If build timestamps differ, merge their files[] lists and invalidate all objects.\n if (sourceMetadata.build_timestamp !== cachedMetadata.build_timestamp) {\n const files = [\n ...new Set([\n ...(sourceMetadata.files || []),\n ...(cachedMetadata.files || []),\n ]),\n ].map(f => `${entityTripletPath}/${f}`);\n await this.cache.invalidateMultiple(files);\n finish({ updated: true });\n } else {\n finish({ updated: false });\n }\n } catch (e) {\n assertError(e);\n // In case of error, log and allow the user to go about their business.\n this.logger.error(\n `Error syncing cache for ${entityTripletPath}: ${e.message}`,\n );\n finish({ updated: false });\n } finally {\n // Update the last check time for the entity\n new BuildMetadataStorage(entity.metadata.uid!).setLastUpdated();\n }\n }\n}\n","/*\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 { Logger } from 'winston';\nimport { TechDocsCache } from './TechDocsCache';\n\ntype CacheMiddlewareOptions = {\n cache: TechDocsCache;\n logger: Logger;\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","/*\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 { CacheClient } from '@backstage/backend-common';\nimport { assertError, CustomErrorBase } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\n\nexport class CacheInvalidationError extends CustomErrorBase {}\n\nexport class TechDocsCache {\n protected readonly cache: CacheClient;\n protected readonly logger: Logger;\n protected readonly readTimeout: number;\n\n private constructor({\n cache,\n logger,\n readTimeout,\n }: {\n cache: CacheClient;\n logger: Logger;\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: CacheClient; logger: Logger },\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.stack);\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","/*\n * Copyright 2022 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 { CatalogClient } from '@backstage/catalog-client';\nimport { CacheClient } from '@backstage/backend-common';\nimport {\n Entity,\n CompoundEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\n\nexport type CachedEntityLoaderOptions = {\n catalog: CatalogClient;\n cache: CacheClient;\n};\n\nexport class CachedEntityLoader {\n private readonly catalog: CatalogClient;\n private readonly cache: CacheClient;\n private readonly readTimeout = 1000;\n\n constructor({ catalog, cache }: CachedEntityLoaderOptions) {\n this.catalog = catalog;\n this.cache = cache;\n }\n\n async load(\n entityRef: CompoundEntityRef,\n token: string | undefined,\n ): Promise<Entity | undefined> {\n const cacheKey = this.getCacheKey(entityRef, token);\n let result = await this.getFromCache(cacheKey);\n\n if (result) {\n return result;\n }\n\n result = await this.catalog.getEntityByRef(entityRef, { token });\n\n if (result) {\n this.cache.set(cacheKey, result, { ttl: 5000 });\n }\n\n return result;\n }\n\n private async getFromCache(key: string): Promise<Entity | undefined> {\n // Promise.race ensures we don't hang the client for long if the cache is\n // temporarily unreachable.\n return (await Promise.race([\n this.cache.get(key),\n new Promise(cancelAfter => setTimeout(cancelAfter, this.readTimeout)),\n ])) as Entity | undefined;\n }\n\n private getCacheKey(\n entityName: CompoundEntityRef,\n token: string | undefined,\n ): string {\n const key = ['catalog', stringifyEntityRef(entityName)];\n\n if (token) {\n key.push(token);\n }\n\n return key.join(':');\n }\n}\n","/*\n * Copyright 2022 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 { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { DocsBuildStrategy } from '@backstage/plugin-techdocs-node';\n\nexport class DefaultDocsBuildStrategy implements DocsBuildStrategy {\n private readonly config: Config;\n\n private constructor(config: Config) {\n this.config = config;\n }\n\n static fromConfig(config: Config): DefaultDocsBuildStrategy {\n return new DefaultDocsBuildStrategy(config);\n }\n\n async shouldBuild(_: { entity: Entity }): Promise<boolean> {\n return [undefined, 'local'].includes(\n this.config.getOptionalString('techdocs.builder'),\n );\n }\n}\n","/*\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 PluginEndpointDiscovery,\n PluginCacheManager,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\nimport { 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 { AuthService, HttpAuthService } 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 * @public\n */\nexport type OutOfTheBoxDeploymentOptions = {\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n publisher: PublisherBase;\n logger: winston.Logger;\n discovery: PluginEndpointDiscovery;\n database?: Knex; // TODO: Make database required when we're implementing database stuff.\n config: Config;\n cache: PluginCacheManager;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogClient;\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 * @public\n */\nexport type RecommendedDeploymentOptions = {\n publisher: PublisherBase;\n logger: winston.Logger;\n discovery: PluginEndpointDiscovery;\n config: Config;\n cache: PluginCacheManager;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogClient;\n httpAuth?: HttpAuthService;\n auth?: AuthService;\n};\n\n/**\n * One of the two deployment configurations must be provided.\n *\n * @public\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 * * @public\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 * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n const { publisher, config, logger, discovery } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters(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 catalog: catalogClient,\n cache: options.cache.getClient(),\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.getClient({ 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(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(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({ kind, namespace, name }, token);\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 await docsSynchronizer.doCacheSync({\n responseHandler,\n discovery,\n token,\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(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","/*\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 */\n\nimport {\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n Entity,\n parseEntityRef,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport fetch from 'node-fetch';\nimport unescape from 'lodash/unescape';\nimport { Logger } from 'winston';\nimport pLimit from 'p-limit';\nimport { Config } from '@backstage/config';\nimport { catalogEntityReadPermission } from '@backstage/plugin-catalog-common/alpha';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport {\n CatalogApi,\n CatalogClient,\n CATALOG_FILTER_EXISTS,\n} from '@backstage/catalog-client';\nimport { TechDocsDocument } from '@backstage/plugin-techdocs-node';\n\ninterface MkSearchIndexDoc {\n title: string;\n text: string;\n location: string;\n}\n\n/**\n * Options to configure the TechDocs collator\n *\n * @public\n */\nexport type TechDocsCollatorOptions = {\n discovery: PluginEndpointDiscovery;\n logger: Logger;\n tokenManager: TokenManager;\n locationTemplate?: string;\n catalogClient?: CatalogApi;\n parallelismLimit?: number;\n legacyPathCasing?: boolean;\n};\n\ntype EntityInfo = {\n name: string;\n namespace: string;\n kind: string;\n};\n\n/**\n * A search collator responsible for gathering and transforming TechDocs documents.\n *\n * @public\n * @deprecated Upgrade to a more recent `@backstage/plugin-search-backend-node` and\n * use `DefaultTechDocsCollatorFactory` instead.\n */\nexport class DefaultTechDocsCollator {\n public readonly type: string = 'techdocs';\n public readonly visibilityPermission: Permission =\n catalogEntityReadPermission;\n\n private constructor(\n private readonly legacyPathCasing: boolean,\n private readonly options: TechDocsCollatorOptions,\n ) {}\n\n static fromConfig(config: Config, options: TechDocsCollatorOptions) {\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n return new DefaultTechDocsCollator(legacyPathCasing, options);\n }\n\n async execute() {\n const {\n parallelismLimit,\n discovery,\n tokenManager,\n catalogClient,\n locationTemplate,\n logger,\n } = this.options;\n const limit = pLimit(parallelismLimit ?? 10);\n const techDocsBaseUrl = await discovery.getBaseUrl('techdocs');\n const { token } = await tokenManager.getToken();\n const entities = await (\n catalogClient ?? new CatalogClient({ discoveryApi: discovery })\n ).getEntities(\n {\n filter: {\n 'metadata.annotations.backstage.io/techdocs-ref':\n CATALOG_FILTER_EXISTS,\n },\n fields: [\n 'kind',\n 'namespace',\n 'metadata.annotations',\n 'metadata.name',\n 'metadata.title',\n 'metadata.namespace',\n 'spec.type',\n 'spec.lifecycle',\n 'relations',\n ],\n },\n { token },\n );\n const docPromises = entities.items.map((entity: Entity) =>\n limit(async (): Promise<TechDocsDocument[]> => {\n const entityInfo = DefaultTechDocsCollator.handleEntityInfoCasing(\n this.legacyPathCasing ?? false,\n {\n kind: entity.kind,\n namespace: entity.metadata.namespace || 'default',\n name: entity.metadata.name,\n },\n );\n\n try {\n const { token: newToken } = await tokenManager.getToken();\n const searchIndexResponse = await fetch(\n DefaultTechDocsCollator.constructDocsIndexUrl(\n techDocsBaseUrl,\n entityInfo,\n ),\n {\n headers: {\n Authorization: `Bearer ${newToken}`,\n },\n },\n );\n const searchIndex = await searchIndexResponse.json();\n\n return searchIndex.docs.map((doc: MkSearchIndexDoc) => ({\n title: unescape(doc.title),\n text: unescape(doc.text || ''),\n location: this.applyArgsToFormat(\n locationTemplate || '/docs/:namespace/:kind/:name/:path',\n {\n ...entityInfo,\n path: doc.location,\n },\n ),\n path: doc.location,\n ...entityInfo,\n entityTitle: entity.metadata.title,\n componentType: entity.spec?.type?.toString() || 'other',\n lifecycle: (entity.spec?.lifecycle as string) || '',\n owner: getSimpleEntityOwnerString(entity),\n authorization: {\n resourceRef: stringifyEntityRef(entity),\n },\n }));\n } catch (e) {\n logger.debug(\n `Failed to retrieve tech docs search index for entity ${entityInfo.namespace}/${entityInfo.kind}/${entityInfo.name}`,\n e,\n );\n return [];\n }\n }),\n );\n return (await Promise.all(docPromises)).flat();\n }\n\n protected applyArgsToFormat(\n format: string,\n args: Record<string, string>,\n ): string {\n let formatted = format;\n for (const [key, value] of Object.entries(args)) {\n formatted = formatted.replace(`:${key}`, value);\n }\n return formatted;\n }\n\n private static constructDocsIndexUrl(\n techDocsBaseUrl: string,\n entityInfo: { kind: string; namespace: string; name: string },\n ) {\n return `${techDocsBaseUrl}/static/docs/${entityInfo.namespace}/${entityInfo.kind}/${entityInfo.name}/search/search_index.json`;\n }\n\n private static handleEntityInfoCasing(\n legacyPaths: boolean,\n entityInfo: EntityInfo,\n ): EntityInfo {\n return legacyPaths\n ? entityInfo\n : Object.entries(entityInfo).reduce((acc, [key, value]) => {\n return { ...acc, [key]: value.toLocaleLowerCase('en-US') };\n }, {} as EntityInfo);\n }\n}\n\nfunction getSimpleEntityOwnerString(entity: Entity): string {\n if (entity.relations) {\n const owner = entity.relations.find(r => r.type === RELATION_OWNED_BY);\n if (owner) {\n const { name } = parseEntityRef(owner.targetRef);\n return name;\n }\n }\n return '';\n}\n","/*\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 */\n\n/**\n * todo(backstage/techdocs-core): stop exporting these in a future release.\n */\nexport { DefaultTechDocsCollator } from './DefaultTechDocsCollator';\nexport type { TechDocsCollatorOptions } from './DefaultTechDocsCollator';\n\nimport { DefaultTechDocsCollatorFactory as _DefaultTechDocsCollatorFactory } from '@backstage/plugin-search-backend-module-techdocs';\nimport type { TechDocsCollatorFactoryOptions as _TechDocsCollatorFactoryOptions } from '@backstage/plugin-search-backend-module-techdocs';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-techdocs` instead\n */\nexport type TechDocsCollatorFactoryOptions = _TechDocsCollatorFactoryOptions;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-techdocs` instead\n */\nexport const DefaultTechDocsCollatorFactory = _DefaultTechDocsCollatorFactory;\n"],"names":["__publicField","stringifyEntityRef","DEFAULT_NAMESPACE","isError","os","fs","path","getLocationForEntity","assertError","pLimit","winston","PassThrough","NotFoundError","fetch","router","CustomErrorBase","Router","createLegacyAuthAdapters","catalogClient","CatalogClient","ScmIntegrations","_a","catalogEntityReadPermission","CATALOG_FILTER_EXISTS","unescape","RELATION_OWNED_BY","parseEntityRef","_DefaultTechDocsCollatorFactory"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/DocsBuilder/BuildMetadataStorage.ts","../src/DocsBuilder/builder.ts","../src/service/DocsSynchronizer.ts","../src/cache/cacheMiddleware.ts","../src/cache/TechDocsCache.ts","../src/service/CachedEntityLoader.ts","../src/service/DefaultDocsBuildStrategy.ts","../src/service/router.ts","../src/search/DefaultTechDocsCollator.ts","../src/search/index.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","/*\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","/*\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 */\n\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport {\n DEFAULT_NAMESPACE,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, NotFoundError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport {\n GeneratorBuilder,\n PreparerBuilder,\n PublisherBase,\n} from '@backstage/plugin-techdocs-node';\nimport fetch from 'node-fetch';\nimport pLimit, { Limit } from 'p-limit';\nimport { PassThrough } from 'stream';\nimport * as winston from 'winston';\nimport { TechDocsCache } from '../cache';\nimport {\n BuildMetadataStorage,\n DocsBuilder,\n shouldCheckForUpdate,\n} from '../DocsBuilder';\n\nexport type DocsSynchronizerSyncOpts = {\n log: (message: string) => void;\n error: (e: Error) => void;\n finish: (result: { updated: boolean }) => void;\n};\n\nexport class DocsSynchronizer {\n private readonly publisher: PublisherBase;\n private readonly logger: winston.Logger;\n private readonly buildLogTransport?: winston.transport;\n private readonly config: Config;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n private readonly cache: TechDocsCache | undefined;\n private readonly buildLimiter: Limit;\n\n constructor({\n publisher,\n logger,\n buildLogTransport,\n config,\n scmIntegrations,\n cache,\n }: {\n publisher: PublisherBase;\n logger: winston.Logger;\n buildLogTransport?: winston.transport;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n cache: TechDocsCache | undefined;\n }) {\n this.config = config;\n this.logger = logger;\n this.buildLogTransport = buildLogTransport;\n this.publisher = publisher;\n this.scmIntegrations = scmIntegrations;\n this.cache = cache;\n\n // Single host/process: limit concurrent builds up to 10 at a time.\n this.buildLimiter = pLimit(10);\n }\n\n async doSync({\n responseHandler: { log, error, finish },\n entity,\n preparers,\n generators,\n }: {\n responseHandler: DocsSynchronizerSyncOpts;\n entity: Entity;\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n }) {\n // create a new logger to log data to the caller\n const taskLogger = winston.createLogger({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.timestamp(),\n winston.format.simple(),\n ),\n defaultMeta: {},\n });\n\n // create an in-memory stream to forward logs to the event-stream\n const logStream = new PassThrough();\n logStream.on('data', async data => {\n log(data.toString().trim());\n });\n\n taskLogger.add(new winston.transports.Stream({ stream: logStream }));\n if (this.buildLogTransport) {\n taskLogger.add(this.buildLogTransport);\n }\n\n // check if the last update check was too recent\n if (!shouldCheckForUpdate(entity.metadata.uid!)) {\n finish({ updated: false });\n return;\n }\n\n let foundDocs = false;\n\n try {\n const docsBuilder = new DocsBuilder({\n preparers,\n generators,\n publisher: this.publisher,\n logger: taskLogger,\n entity,\n config: this.config,\n scmIntegrations: this.scmIntegrations,\n logStream,\n cache: this.cache,\n });\n\n const interval = setInterval(() => {\n taskLogger.info(\n 'The docs building process is taking a little bit longer to process this entity. Please bear with us.',\n );\n }, 10000);\n const updated = await this.buildLimiter(() => docsBuilder.build());\n clearInterval(interval);\n\n if (!updated) {\n finish({ updated: false });\n return;\n }\n } catch (e) {\n assertError(e);\n const msg = `Failed to build the docs page for entity ${stringifyEntityRef(\n entity,\n )}: ${e.message}`;\n taskLogger.error(msg);\n this.logger.error(msg, e);\n error(e);\n return;\n }\n\n // With a maximum of ~5 seconds wait, check if the files got published and if docs will be fetched\n // on the user's page. If not, respond with a message asking them to check back later.\n // The delay here is to make sure GCS/AWS/etc. registers newly uploaded files which is usually <1 second\n for (let attempt = 0; attempt < 5; attempt++) {\n if (await this.publisher.hasDocsBeenGenerated(entity)) {\n foundDocs = true;\n break;\n }\n await new Promise(r => setTimeout(r, 1000));\n }\n if (!foundDocs) {\n this.logger.error(\n 'Published files are taking longer to show up in storage. Something went wrong.',\n );\n error(\n new NotFoundError(\n 'Sorry! It took too long for the generated docs to show up in storage. Are you sure the docs project is generating an `index.html` file? Otherwise, check back later.',\n ),\n );\n return;\n }\n\n finish({ updated: true });\n }\n\n async doCacheSync({\n responseHandler: { finish },\n discovery,\n token,\n entity,\n }: {\n responseHandler: DocsSynchronizerSyncOpts;\n discovery: PluginEndpointDiscovery;\n token: string | undefined;\n entity: Entity;\n }) {\n // Check if the last update check was too recent.\n if (!shouldCheckForUpdate(entity.metadata.uid!) || !this.cache) {\n finish({ updated: false });\n return;\n }\n\n // Fetch techdocs_metadata.json from the publisher and from cache.\n const baseUrl = await discovery.getBaseUrl('techdocs');\n const namespace = entity.metadata?.namespace || DEFAULT_NAMESPACE;\n const kind = entity.kind;\n const name = entity.metadata.name;\n const legacyPathCasing =\n this.config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n const tripletPath = `${namespace}/${kind}/${name}`;\n const entityTripletPath = `${\n legacyPathCasing ? tripletPath : tripletPath.toLocaleLowerCase('en-US')\n }`;\n try {\n const [sourceMetadata, cachedMetadata] = await Promise.all([\n this.publisher.fetchTechDocsMetadata({ namespace, kind, name }),\n fetch(\n `${baseUrl}/static/docs/${entityTripletPath}/techdocs_metadata.json`,\n {\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n },\n ).then(\n f =>\n f.json().catch(() => undefined) as ReturnType<\n PublisherBase['fetchTechDocsMetadata']\n >,\n ),\n ]);\n\n // If build timestamps differ, merge their files[] lists and invalidate all objects.\n if (sourceMetadata.build_timestamp !== cachedMetadata.build_timestamp) {\n const files = [\n ...new Set([\n ...(sourceMetadata.files || []),\n ...(cachedMetadata.files || []),\n ]),\n ].map(f => `${entityTripletPath}/${f}`);\n await this.cache.invalidateMultiple(files);\n finish({ updated: true });\n } else {\n finish({ updated: false });\n }\n } catch (e) {\n assertError(e);\n // In case of error, log and allow the user to go about their business.\n this.logger.error(\n `Error syncing cache for ${entityTripletPath}: ${e.message}`,\n );\n finish({ updated: false });\n } finally {\n // Update the last check time for the entity\n new BuildMetadataStorage(entity.metadata.uid!).setLastUpdated();\n }\n }\n}\n","/*\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 { Logger } from 'winston';\nimport { TechDocsCache } from './TechDocsCache';\n\ntype CacheMiddlewareOptions = {\n cache: TechDocsCache;\n logger: Logger;\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","/*\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 { CacheClient } from '@backstage/backend-common';\nimport { assertError, CustomErrorBase } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\n\nexport class CacheInvalidationError extends CustomErrorBase {}\n\nexport class TechDocsCache {\n protected readonly cache: CacheClient;\n protected readonly logger: Logger;\n protected readonly readTimeout: number;\n\n private constructor({\n cache,\n logger,\n readTimeout,\n }: {\n cache: CacheClient;\n logger: Logger;\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: CacheClient; logger: Logger },\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.stack);\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","/*\n * Copyright 2022 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 { CatalogClient } from '@backstage/catalog-client';\nimport { CacheClient } from '@backstage/backend-common';\nimport {\n Entity,\n CompoundEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\n\nexport type CachedEntityLoaderOptions = {\n catalog: CatalogClient;\n cache: CacheClient;\n};\n\nexport class CachedEntityLoader {\n private readonly catalog: CatalogClient;\n private readonly cache: CacheClient;\n private readonly readTimeout = 1000;\n\n constructor({ catalog, cache }: CachedEntityLoaderOptions) {\n this.catalog = catalog;\n this.cache = cache;\n }\n\n async load(\n entityRef: CompoundEntityRef,\n token: string | undefined,\n ): Promise<Entity | undefined> {\n const cacheKey = this.getCacheKey(entityRef, token);\n let result = await this.getFromCache(cacheKey);\n\n if (result) {\n return result;\n }\n\n result = await this.catalog.getEntityByRef(entityRef, { token });\n\n if (result) {\n this.cache.set(cacheKey, result, { ttl: 5000 });\n }\n\n return result;\n }\n\n private async getFromCache(key: string): Promise<Entity | undefined> {\n // Promise.race ensures we don't hang the client for long if the cache is\n // temporarily unreachable.\n return (await Promise.race([\n this.cache.get(key),\n new Promise(cancelAfter => setTimeout(cancelAfter, this.readTimeout)),\n ])) as Entity | undefined;\n }\n\n private getCacheKey(\n entityName: CompoundEntityRef,\n token: string | undefined,\n ): string {\n const key = ['catalog', stringifyEntityRef(entityName)];\n\n if (token) {\n key.push(token);\n }\n\n return key.join(':');\n }\n}\n","/*\n * Copyright 2022 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 { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { DocsBuildStrategy } from '@backstage/plugin-techdocs-node';\n\nexport class DefaultDocsBuildStrategy implements DocsBuildStrategy {\n private readonly config: Config;\n\n private constructor(config: Config) {\n this.config = config;\n }\n\n static fromConfig(config: Config): DefaultDocsBuildStrategy {\n return new DefaultDocsBuildStrategy(config);\n }\n\n async shouldBuild(_: { entity: Entity }): Promise<boolean> {\n return [undefined, 'local'].includes(\n this.config.getOptionalString('techdocs.builder'),\n );\n }\n}\n","/*\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 PluginEndpointDiscovery,\n PluginCacheManager,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\nimport { 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 { AuthService, HttpAuthService } 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 * @public\n */\nexport type OutOfTheBoxDeploymentOptions = {\n preparers: PreparerBuilder;\n generators: GeneratorBuilder;\n publisher: PublisherBase;\n logger: winston.Logger;\n discovery: PluginEndpointDiscovery;\n database?: Knex; // TODO: Make database required when we're implementing database stuff.\n config: Config;\n cache: PluginCacheManager;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogClient;\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 * @public\n */\nexport type RecommendedDeploymentOptions = {\n publisher: PublisherBase;\n logger: winston.Logger;\n discovery: PluginEndpointDiscovery;\n config: Config;\n cache: PluginCacheManager;\n docsBuildStrategy?: DocsBuildStrategy;\n buildLogTransport?: winston.transport;\n catalogClient?: CatalogClient;\n httpAuth?: HttpAuthService;\n auth?: AuthService;\n};\n\n/**\n * One of the two deployment configurations must be provided.\n *\n * @public\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 * * @public\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 * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n const { publisher, config, logger, discovery } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters(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 catalog: catalogClient,\n cache: options.cache.getClient(),\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.getClient({ 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(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(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({ kind, namespace, name }, token);\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 await docsSynchronizer.doCacheSync({\n responseHandler,\n discovery,\n token,\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(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","/*\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 */\n\nimport {\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n Entity,\n parseEntityRef,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport fetch from 'node-fetch';\nimport unescape from 'lodash/unescape';\nimport { Logger } from 'winston';\nimport pLimit from 'p-limit';\nimport { Config } from '@backstage/config';\nimport { catalogEntityReadPermission } from '@backstage/plugin-catalog-common/alpha';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport {\n CatalogApi,\n CatalogClient,\n CATALOG_FILTER_EXISTS,\n} from '@backstage/catalog-client';\nimport { TechDocsDocument } from '@backstage/plugin-techdocs-node';\n\ninterface MkSearchIndexDoc {\n title: string;\n text: string;\n location: string;\n}\n\n/**\n * Options to configure the TechDocs collator\n *\n * @public\n */\nexport type TechDocsCollatorOptions = {\n discovery: PluginEndpointDiscovery;\n logger: Logger;\n tokenManager: TokenManager;\n locationTemplate?: string;\n catalogClient?: CatalogApi;\n parallelismLimit?: number;\n legacyPathCasing?: boolean;\n};\n\ntype EntityInfo = {\n name: string;\n namespace: string;\n kind: string;\n};\n\n/**\n * A search collator responsible for gathering and transforming TechDocs documents.\n *\n * @public\n * @deprecated Upgrade to a more recent `@backstage/plugin-search-backend-node` and\n * use `DefaultTechDocsCollatorFactory` instead.\n */\nexport class DefaultTechDocsCollator {\n public readonly type: string = 'techdocs';\n public readonly visibilityPermission: Permission =\n catalogEntityReadPermission;\n\n private constructor(\n private readonly legacyPathCasing: boolean,\n private readonly options: TechDocsCollatorOptions,\n ) {}\n\n static fromConfig(config: Config, options: TechDocsCollatorOptions) {\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n return new DefaultTechDocsCollator(legacyPathCasing, options);\n }\n\n async execute() {\n const {\n parallelismLimit,\n discovery,\n tokenManager,\n catalogClient,\n locationTemplate,\n logger,\n } = this.options;\n const limit = pLimit(parallelismLimit ?? 10);\n const techDocsBaseUrl = await discovery.getBaseUrl('techdocs');\n const { token } = await tokenManager.getToken();\n const entities = await (\n catalogClient ?? new CatalogClient({ discoveryApi: discovery })\n ).getEntities(\n {\n filter: {\n 'metadata.annotations.backstage.io/techdocs-ref':\n CATALOG_FILTER_EXISTS,\n },\n fields: [\n 'kind',\n 'namespace',\n 'metadata.annotations',\n 'metadata.name',\n 'metadata.title',\n 'metadata.namespace',\n 'spec.type',\n 'spec.lifecycle',\n 'relations',\n ],\n },\n { token },\n );\n const docPromises = entities.items.map((entity: Entity) =>\n limit(async (): Promise<TechDocsDocument[]> => {\n const entityInfo = DefaultTechDocsCollator.handleEntityInfoCasing(\n this.legacyPathCasing ?? false,\n {\n kind: entity.kind,\n namespace: entity.metadata.namespace || 'default',\n name: entity.metadata.name,\n },\n );\n\n try {\n const { token: newToken } = await tokenManager.getToken();\n const searchIndexResponse = await fetch(\n DefaultTechDocsCollator.constructDocsIndexUrl(\n techDocsBaseUrl,\n entityInfo,\n ),\n {\n headers: {\n Authorization: `Bearer ${newToken}`,\n },\n },\n );\n const searchIndex = await searchIndexResponse.json();\n\n return searchIndex.docs.map((doc: MkSearchIndexDoc) => ({\n title: unescape(doc.title),\n text: unescape(doc.text || ''),\n location: this.applyArgsToFormat(\n locationTemplate || '/docs/:namespace/:kind/:name/:path',\n {\n ...entityInfo,\n path: doc.location,\n },\n ),\n path: doc.location,\n ...entityInfo,\n entityTitle: entity.metadata.title,\n componentType: entity.spec?.type?.toString() || 'other',\n lifecycle: (entity.spec?.lifecycle as string) || '',\n owner: getSimpleEntityOwnerString(entity),\n authorization: {\n resourceRef: stringifyEntityRef(entity),\n },\n }));\n } catch (e) {\n logger.debug(\n `Failed to retrieve tech docs search index for entity ${entityInfo.namespace}/${entityInfo.kind}/${entityInfo.name}`,\n e,\n );\n return [];\n }\n }),\n );\n return (await Promise.all(docPromises)).flat();\n }\n\n protected applyArgsToFormat(\n format: string,\n args: Record<string, string>,\n ): string {\n let formatted = format;\n for (const [key, value] of Object.entries(args)) {\n formatted = formatted.replace(`:${key}`, value);\n }\n return formatted;\n }\n\n private static constructDocsIndexUrl(\n techDocsBaseUrl: string,\n entityInfo: { kind: string; namespace: string; name: string },\n ) {\n return `${techDocsBaseUrl}/static/docs/${entityInfo.namespace}/${entityInfo.kind}/${entityInfo.name}/search/search_index.json`;\n }\n\n private static handleEntityInfoCasing(\n legacyPaths: boolean,\n entityInfo: EntityInfo,\n ): EntityInfo {\n return legacyPaths\n ? entityInfo\n : Object.entries(entityInfo).reduce((acc, [key, value]) => {\n return { ...acc, [key]: value.toLocaleLowerCase('en-US') };\n }, {} as EntityInfo);\n }\n}\n\nfunction getSimpleEntityOwnerString(entity: Entity): string {\n if (entity.relations) {\n const owner = entity.relations.find(r => r.type === RELATION_OWNED_BY);\n if (owner) {\n const { name } = parseEntityRef(owner.targetRef);\n return name;\n }\n }\n return '';\n}\n","/*\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 */\n\n/**\n * todo(backstage/techdocs-core): stop exporting these in a future release.\n */\nexport { DefaultTechDocsCollator } from './DefaultTechDocsCollator';\nexport type { TechDocsCollatorOptions } from './DefaultTechDocsCollator';\n\nimport { DefaultTechDocsCollatorFactory as _DefaultTechDocsCollatorFactory } from '@backstage/plugin-search-backend-module-techdocs';\nimport type { TechDocsCollatorFactoryOptions as _TechDocsCollatorFactoryOptions } from '@backstage/plugin-search-backend-module-techdocs';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-techdocs` instead\n */\nexport type TechDocsCollatorFactoryOptions = _TechDocsCollatorFactoryOptions;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-techdocs` instead\n */\nexport const DefaultTechDocsCollatorFactory = _DefaultTechDocsCollatorFactory;\n"],"names":["stringifyEntityRef","DEFAULT_NAMESPACE","isError","os","fs","path","getLocationForEntity","assertError","pLimit","winston","PassThrough","NotFoundError","fetch","router","CustomErrorBase","Router","createLegacyAuthAdapters","catalogClient","CatalogClient","ScmIntegrations","catalogEntityReadPermission","CATALOG_FILTER_EXISTS","unescape","RELATION_OWNED_BY","parseEntityRef","_DefaultTechDocsCollatorFactory"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-techdocs-backend",
3
- "version": "1.10.5",
3
+ "version": "1.10.6-next.1",
4
4
  "description": "The Backstage backend plugin that renders technical documentation for your components",
5
5
  "backstage": {
6
6
  "role": "backend-plugin"
@@ -49,8 +49,8 @@
49
49
  "test": "backstage-cli package test"
50
50
  },
51
51
  "dependencies": {
52
- "@backstage/backend-common": "^0.22.0",
53
- "@backstage/backend-plugin-api": "^0.6.18",
52
+ "@backstage/backend-common": "^0.23.0-next.1",
53
+ "@backstage/backend-plugin-api": "^0.6.19-next.1",
54
54
  "@backstage/catalog-client": "^1.6.5",
55
55
  "@backstage/catalog-model": "^1.5.0",
56
56
  "@backstage/config": "^1.2.0",
@@ -58,8 +58,8 @@
58
58
  "@backstage/integration": "^1.11.0",
59
59
  "@backstage/plugin-catalog-common": "^1.0.23",
60
60
  "@backstage/plugin-permission-common": "^0.7.13",
61
- "@backstage/plugin-search-backend-module-techdocs": "^0.1.23",
62
- "@backstage/plugin-techdocs-node": "^1.12.4",
61
+ "@backstage/plugin-search-backend-module-techdocs": "^0.1.24-next.1",
62
+ "@backstage/plugin-techdocs-node": "^1.12.5-next.1",
63
63
  "@types/express": "^4.17.6",
64
64
  "dockerode": "^4.0.0",
65
65
  "express": "^4.17.1",
@@ -72,8 +72,9 @@
72
72
  "winston": "^3.2.1"
73
73
  },
74
74
  "devDependencies": {
75
- "@backstage/backend-test-utils": "^0.3.8",
76
- "@backstage/cli": "^0.26.5",
75
+ "@backstage/backend-defaults": "^0.3.0-next.1",
76
+ "@backstage/backend-test-utils": "^0.4.0-next.1",
77
+ "@backstage/cli": "^0.26.7-next.1",
77
78
  "@types/dockerode": "^3.3.0",
78
79
  "msw": "^1.0.0",
79
80
  "supertest": "^6.1.3"