@rwdocs/backstage-plugin-rw-backend 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config.d.ts CHANGED
@@ -1,24 +1,40 @@
1
1
  export interface Config {
2
2
  /** @visibility backend */
3
3
  rw?: {
4
- /** Local directory containing documentation source files. */
4
+ /**
5
+ * Local directory containing documentation source files.
6
+ * Mutually exclusive with `s3`.
7
+ */
5
8
  projectDir?: string;
6
- /** URL prefix for generated links (e.g. "/rw-docs"). */
7
- linkPrefix?: string;
8
- /** S3 storage configuration for deployed environments. */
9
+ /**
10
+ * Entity ref that the local projectDir serves as (required when projectDir is set).
11
+ * Standard Backstage entity ref format: "kind:namespace/name" (e.g. "component:default/my-docs")
12
+ */
13
+ entity?: string;
14
+ /** Maximum number of cached RwSite instances. Default: 20. */
15
+ cacheSize?: number;
16
+ /**
17
+ * S3 storage configuration. Shared across all entity sites.
18
+ * Mutually exclusive with `projectDir`.
19
+ */
9
20
  s3?: {
10
21
  /** S3 bucket name. */
11
22
  bucket: string;
12
- /** Entity identifier (prefix) within the bucket. */
13
- entity: string;
14
23
  /** AWS region. */
15
24
  region?: string;
16
25
  /** Custom S3 endpoint URL. */
17
26
  endpoint?: string;
18
27
  /** Root path within the bucket. */
19
28
  bucketRootPath?: string;
29
+ /** AWS access key ID. */
30
+ accessKeyId?: string;
31
+ /**
32
+ * AWS secret access key.
33
+ * @visibility secret
34
+ */
35
+ secretAccessKey?: string;
20
36
  };
21
- /** Diagram rendering configuration. */
37
+ /** Diagram rendering configuration. Shared across all sites. */
22
38
  diagrams?: {
23
39
  /** Kroki server URL for rendering diagrams. */
24
40
  krokiUrl?: string;
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ var catalogModel = require('@backstage/catalog-model');
4
+ require('@backstage/errors');
5
+
6
+ function toEntityPath(entityRef) {
7
+ const ref = catalogModel.parseEntityRef(entityRef);
8
+ return `${ref.namespace}/${ref.kind}/${ref.name}`.toLocaleLowerCase("en-US");
9
+ }
10
+
11
+ exports.toEntityPath = toEntityPath;
12
+ //# sourceMappingURL=entityPath.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityPath.cjs.js","sources":["../src/entityPath.ts"],"sourcesContent":["import { parseEntityRef } from \"@backstage/catalog-model\";\nimport { InputError } from \"@backstage/errors\";\n\n/**\n * Converts a Backstage entity ref (e.g. \"component:default/arch\") to the\n * slash-delimited, lowercased path format used in URLs and cache keys\n * (e.g. \"default/component/arch\").\n *\n * Uses namespace/kind/name ordering to match Backstage catalog URL convention.\n *\n * NOTE: The frontend plugin has a similar utility at\n * plugins/rw/src/components/entityPath.ts — keep in sync if changing logic.\n */\nexport function toEntityPath(entityRef: string): string {\n const ref = parseEntityRef(entityRef);\n return `${ref.namespace}/${ref.kind}/${ref.name}`.toLocaleLowerCase(\"en-US\");\n}\n\n/**\n * Converts a slash-delimited entity path (e.g. \"default/component/arch\")\n * back to the standard Backstage entity ref format (e.g. \"component:default/arch\").\n *\n * This is the inverse of `toEntityPath`. Note that the round-trip always\n * produces lowercased refs since `toEntityPath` lowercases its output.\n */\nexport function fromEntityPath(path: string): string {\n const parts = path.split(\"/\");\n if (parts.length !== 3 || parts.some((p) => !p)) {\n throw new InputError(`Invalid entity path: \"${path}\" (expected \"namespace/kind/name\")`);\n }\n const [namespace, kind, name] = parts;\n return `${kind}:${namespace}/${name}`;\n}\n"],"names":["parseEntityRef"],"mappings":";;;;;AAaO,SAAS,aAAa,SAAA,EAA2B;AACtD,EAAA,MAAM,GAAA,GAAMA,4BAAe,SAAS,CAAA;AACpC,EAAA,OAAO,CAAA,EAAG,GAAA,CAAI,SAAS,CAAA,CAAA,EAAI,GAAA,CAAI,IAAI,CAAA,CAAA,EAAI,GAAA,CAAI,IAAI,CAAA,CAAA,CAAG,iBAAA,CAAkB,OAAO,CAAA;AAC7E;;;;"}
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ var core = require('@rwdocs/core');
4
+ var entityPath = require('./entityPath.cjs.js');
5
+
6
+ class Hub {
7
+ options;
8
+ cache = /* @__PURE__ */ new Map();
9
+ maxSize;
10
+ constructor(options) {
11
+ this.options = {
12
+ ...options,
13
+ entity: options.entity ? entityPath.toEntityPath(options.entity) : void 0
14
+ };
15
+ this.maxSize = options.cacheSize ?? 20;
16
+ }
17
+ getSite(entityRef) {
18
+ if (this.options.projectDir) {
19
+ return this.getLocalSite(entityRef);
20
+ }
21
+ return this.getS3Site(entityRef);
22
+ }
23
+ getLocalSite(entityRef) {
24
+ if (entityRef !== this.options.entity) {
25
+ return void 0;
26
+ }
27
+ const cached = this.cache.get(entityRef);
28
+ if (cached) return cached;
29
+ const site = core.createSite({
30
+ projectDir: this.options.projectDir,
31
+ diagrams: this.options.diagrams
32
+ });
33
+ this.cache.set(entityRef, site);
34
+ return site;
35
+ }
36
+ getS3Site(entityRef) {
37
+ const cached = this.cache.get(entityRef);
38
+ if (cached) {
39
+ this.cache.delete(entityRef);
40
+ this.cache.set(entityRef, cached);
41
+ return cached;
42
+ }
43
+ if (this.cache.size >= this.maxSize) {
44
+ const firstKey = this.cache.keys().next().value;
45
+ this.cache.delete(firstKey);
46
+ }
47
+ const s3 = this.options.s3;
48
+ const config = {
49
+ s3: { ...s3, entity: entityRef },
50
+ diagrams: this.options.diagrams
51
+ };
52
+ const site = core.createSite(config);
53
+ this.cache.set(entityRef, site);
54
+ return site;
55
+ }
56
+ }
57
+
58
+ exports.Hub = Hub;
59
+ //# sourceMappingURL=hub.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub.cjs.js","sources":["../src/hub.ts"],"sourcesContent":["import { createSite, type RwSite, type SiteConfig, type DiagramsConfig } from \"@rwdocs/core\";\nimport { toEntityPath } from \"./entityPath\";\n\nexport interface S3SharedConfig {\n bucket: string;\n region?: string;\n endpoint?: string;\n bucketRootPath?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n}\n\nexport interface HubOptions {\n s3?: S3SharedConfig;\n projectDir?: string;\n /** Entity ref in any format accepted by parseEntityRef. Normalized internally. */\n entity?: string;\n diagrams?: DiagramsConfig;\n cacheSize?: number;\n}\n\nexport class Hub {\n private readonly options: HubOptions;\n private readonly cache: Map<string, RwSite> = new Map();\n private readonly maxSize: number;\n\n constructor(options: HubOptions) {\n this.options = {\n ...options,\n entity: options.entity ? toEntityPath(options.entity) : undefined,\n };\n this.maxSize = options.cacheSize ?? 20;\n }\n\n getSite(entityRef: string): RwSite | undefined {\n if (this.options.projectDir) {\n return this.getLocalSite(entityRef);\n }\n return this.getS3Site(entityRef);\n }\n\n private getLocalSite(entityRef: string): RwSite | undefined {\n if (entityRef !== this.options.entity) {\n return undefined;\n }\n\n const cached = this.cache.get(entityRef);\n if (cached) return cached;\n\n const site = createSite({\n projectDir: this.options.projectDir,\n diagrams: this.options.diagrams,\n });\n this.cache.set(entityRef, site);\n return site;\n }\n\n private getS3Site(entityRef: string): RwSite {\n const cached = this.cache.get(entityRef);\n if (cached) {\n this.cache.delete(entityRef);\n this.cache.set(entityRef, cached);\n return cached;\n }\n\n if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value!;\n this.cache.delete(firstKey);\n }\n\n const s3 = this.options.s3!;\n const config: SiteConfig = {\n s3: { ...s3, entity: entityRef },\n diagrams: this.options.diagrams,\n };\n\n const site = createSite(config);\n this.cache.set(entityRef, site);\n return site;\n }\n}\n"],"names":["toEntityPath","createSite"],"mappings":";;;;;AAqBO,MAAM,GAAA,CAAI;AAAA,EACE,OAAA;AAAA,EACA,KAAA,uBAAiC,GAAA,EAAI;AAAA,EACrC,OAAA;AAAA,EAEjB,YAAY,OAAA,EAAqB;AAC/B,IAAA,IAAA,CAAK,OAAA,GAAU;AAAA,MACb,GAAG,OAAA;AAAA,MACH,QAAQ,OAAA,CAAQ,MAAA,GAASA,uBAAA,CAAa,OAAA,CAAQ,MAAM,CAAA,GAAI;AAAA,KAC1D;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,QAAQ,SAAA,IAAa,EAAA;AAAA,EACtC;AAAA,EAEA,QAAQ,SAAA,EAAuC;AAC7C,IAAA,IAAI,IAAA,CAAK,QAAQ,UAAA,EAAY;AAC3B,MAAA,OAAO,IAAA,CAAK,aAAa,SAAS,CAAA;AAAA,IACpC;AACA,IAAA,OAAO,IAAA,CAAK,UAAU,SAAS,CAAA;AAAA,EACjC;AAAA,EAEQ,aAAa,SAAA,EAAuC;AAC1D,IAAA,IAAI,SAAA,KAAc,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ;AACrC,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAS,CAAA;AACvC,IAAA,IAAI,QAAQ,OAAO,MAAA;AAEnB,IAAA,MAAM,OAAOC,eAAA,CAAW;AAAA,MACtB,UAAA,EAAY,KAAK,OAAA,CAAQ,UAAA;AAAA,MACzB,QAAA,EAAU,KAAK,OAAA,CAAQ;AAAA,KACxB,CAAA;AACD,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAA,EAAW,IAAI,CAAA;AAC9B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEQ,UAAU,SAAA,EAA2B;AAC3C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAS,CAAA;AACvC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,SAAS,CAAA;AAC3B,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAA,EAAW,MAAM,CAAA;AAChC,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,IAAA,IAAQ,IAAA,CAAK,OAAA,EAAS;AACnC,MAAA,MAAM,WAAW,IAAA,CAAK,KAAA,CAAM,IAAA,EAAK,CAAE,MAAK,CAAE,KAAA;AAC1C,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,QAAQ,CAAA;AAAA,IAC5B;AAEA,IAAA,MAAM,EAAA,GAAK,KAAK,OAAA,CAAQ,EAAA;AACxB,IAAA,MAAM,MAAA,GAAqB;AAAA,MACzB,EAAA,EAAI,EAAE,GAAG,EAAA,EAAI,QAAQ,SAAA,EAAU;AAAA,MAC/B,QAAA,EAAU,KAAK,OAAA,CAAQ;AAAA,KACzB;AAEA,IAAA,MAAM,IAAA,GAAOA,gBAAW,MAAM,CAAA;AAC9B,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAA,EAAW,IAAI,CAAA;AAC9B,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;;"}
@@ -2,6 +2,8 @@
2
2
 
3
3
  var backendPluginApi = require('@backstage/backend-plugin-api');
4
4
  var router = require('./router.cjs.js');
5
+ var hub = require('./hub.cjs.js');
6
+ var entityPath = require('./entityPath.cjs.js');
5
7
 
6
8
  const rwPlugin = backendPluginApi.createBackendPlugin({
7
9
  pluginId: "rw",
@@ -15,39 +17,44 @@ const rwPlugin = backendPluginApi.createBackendPlugin({
15
17
  },
16
18
  async init({ httpRouter, httpAuth, logger, config }) {
17
19
  const projectDir = config.getOptionalString("rw.projectDir");
18
- let s3;
20
+ const entity = config.getOptionalString("rw.entity");
21
+ const cacheSize = config.getOptionalNumber("rw.cacheSize");
19
22
  const s3Config = config.getOptionalConfig("rw.s3");
20
- if (s3Config) {
21
- s3 = {
22
- bucket: s3Config.getString("bucket"),
23
- entity: s3Config.getString("entity"),
24
- region: s3Config.getOptionalString("region"),
25
- endpoint: s3Config.getOptionalString("endpoint"),
26
- bucketRootPath: s3Config.getOptionalString("bucketRootPath")
27
- };
28
- }
23
+ const s3 = s3Config ? {
24
+ bucket: s3Config.getString("bucket"),
25
+ region: s3Config.getOptionalString("region"),
26
+ endpoint: s3Config.getOptionalString("endpoint"),
27
+ bucketRootPath: s3Config.getOptionalString("bucketRootPath"),
28
+ accessKeyId: s3Config.getOptionalString("accessKeyId"),
29
+ secretAccessKey: s3Config.getOptionalString("secretAccessKey")
30
+ } : void 0;
29
31
  if (!projectDir && !s3) {
30
32
  throw new Error("Either rw.projectDir or rw.s3 must be configured");
31
33
  }
32
- let diagrams;
33
- const diagramsConfig = config.getOptionalConfig("rw.diagrams");
34
- if (diagramsConfig) {
35
- diagrams = {
36
- krokiUrl: diagramsConfig.getOptionalString("krokiUrl"),
37
- dpi: diagramsConfig.getOptionalNumber("dpi")
38
- };
39
- }
40
- const linkPrefix = config.getOptionalString("rw.linkPrefix");
41
- if (linkPrefix) {
42
- logger.info(`Using link prefix: ${linkPrefix}`);
34
+ if (projectDir && !entity) {
35
+ throw new Error("rw.entity is required when rw.projectDir is set");
43
36
  }
44
- const router$1 = await router.createRouter({
45
- logger,
37
+ const diagramsConfig = config.getOptionalConfig("rw.diagrams");
38
+ const diagrams = diagramsConfig ? {
39
+ krokiUrl: diagramsConfig.getOptionalString("krokiUrl"),
40
+ dpi: diagramsConfig.getOptionalNumber("dpi")
41
+ } : void 0;
42
+ const hubOptions = {
46
43
  projectDir,
44
+ entity,
47
45
  s3,
48
- linkPrefix,
49
- diagrams
50
- });
46
+ diagrams,
47
+ cacheSize
48
+ };
49
+ const hub$1 = new hub.Hub(hubOptions);
50
+ if (s3) {
51
+ logger.info(`Hub: S3 mode (bucket: ${s3.bucket}, cache size: ${cacheSize ?? 20})`);
52
+ } else {
53
+ logger.info(
54
+ `Hub: local mode (${projectDir}, entity: ${entity ? entityPath.toEntityPath(entity) : entity})`
55
+ );
56
+ }
57
+ const router$1 = await router.createRouter({ hub: hub$1 });
51
58
  httpRouter.use(router$1);
52
59
  httpRouter.addAuthPolicy({
53
60
  path: "/health",
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import { coreServices, createBackendPlugin } from \"@backstage/backend-plugin-api\";\nimport { createRouter, type S3Options, type DiagramsOptions } from \"./router\";\n\nexport const rwPlugin = createBackendPlugin({\n pluginId: \"rw\",\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n },\n async init({ httpRouter, httpAuth, logger, config }) {\n const projectDir = config.getOptionalString(\"rw.projectDir\");\n\n let s3: S3Options | undefined;\n const s3Config = config.getOptionalConfig(\"rw.s3\");\n if (s3Config) {\n s3 = {\n bucket: s3Config.getString(\"bucket\"),\n entity: s3Config.getString(\"entity\"),\n region: s3Config.getOptionalString(\"region\"),\n endpoint: s3Config.getOptionalString(\"endpoint\"),\n bucketRootPath: s3Config.getOptionalString(\"bucketRootPath\"),\n };\n }\n\n if (!projectDir && !s3) {\n throw new Error(\"Either rw.projectDir or rw.s3 must be configured\");\n }\n\n let diagrams: DiagramsOptions | undefined;\n const diagramsConfig = config.getOptionalConfig(\"rw.diagrams\");\n if (diagramsConfig) {\n diagrams = {\n krokiUrl: diagramsConfig.getOptionalString(\"krokiUrl\"),\n dpi: diagramsConfig.getOptionalNumber(\"dpi\"),\n };\n }\n\n const linkPrefix = config.getOptionalString(\"rw.linkPrefix\");\n if (linkPrefix) {\n logger.info(`Using link prefix: ${linkPrefix}`);\n }\n const router = await createRouter({\n logger,\n httpAuth,\n projectDir,\n s3,\n linkPrefix,\n diagrams,\n });\n httpRouter.use(router);\n httpRouter.addAuthPolicy({\n path: \"/health\",\n allow: \"unauthenticated\",\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","router","createRouter"],"mappings":";;;;;AAGO,MAAM,WAAWA,oCAAA,CAAoB;AAAA,EAC1C,QAAA,EAAU,IAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,YAAYC,6BAAA,CAAa,UAAA;AAAA,QACzB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,QAAQA,6BAAA,CAAa,MAAA;AAAA,QACrB,QAAQA,6BAAA,CAAa;AAAA,OACvB;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,YAAY,QAAA,EAAU,MAAA,EAAQ,QAAO,EAAG;AACnD,QAAA,MAAM,UAAA,GAAa,MAAA,CAAO,iBAAA,CAAkB,eAAe,CAAA;AAE3D,QAAA,IAAI,EAAA;AACJ,QAAA,MAAM,QAAA,GAAW,MAAA,CAAO,iBAAA,CAAkB,OAAO,CAAA;AACjD,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,EAAA,GAAK;AAAA,YACH,MAAA,EAAQ,QAAA,CAAS,SAAA,CAAU,QAAQ,CAAA;AAAA,YACnC,MAAA,EAAQ,QAAA,CAAS,SAAA,CAAU,QAAQ,CAAA;AAAA,YACnC,MAAA,EAAQ,QAAA,CAAS,iBAAA,CAAkB,QAAQ,CAAA;AAAA,YAC3C,QAAA,EAAU,QAAA,CAAS,iBAAA,CAAkB,UAAU,CAAA;AAAA,YAC/C,cAAA,EAAgB,QAAA,CAAS,iBAAA,CAAkB,gBAAgB;AAAA,WAC7D;AAAA,QACF;AAEA,QAAA,IAAI,CAAC,UAAA,IAAc,CAAC,EAAA,EAAI;AACtB,UAAA,MAAM,IAAI,MAAM,kDAAkD,CAAA;AAAA,QACpE;AAEA,QAAA,IAAI,QAAA;AACJ,QAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,iBAAA,CAAkB,aAAa,CAAA;AAC7D,QAAA,IAAI,cAAA,EAAgB;AAClB,UAAA,QAAA,GAAW;AAAA,YACT,QAAA,EAAU,cAAA,CAAe,iBAAA,CAAkB,UAAU,CAAA;AAAA,YACrD,GAAA,EAAK,cAAA,CAAe,iBAAA,CAAkB,KAAK;AAAA,WAC7C;AAAA,QACF;AAEA,QAAA,MAAM,UAAA,GAAa,MAAA,CAAO,iBAAA,CAAkB,eAAe,CAAA;AAC3D,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,mBAAA,EAAsB,UAAU,CAAA,CAAE,CAAA;AAAA,QAChD;AACA,QAAA,MAAMC,QAAA,GAAS,MAAMC,mBAAA,CAAa;AAAA,UAChC,MAAA;AAAA,UAEA,UAAA;AAAA,UACA,EAAA;AAAA,UACA,UAAA;AAAA,UACA;AAAA,SACD,CAAA;AACD,QAAA,UAAA,CAAW,IAAID,QAAM,CAAA;AACrB,QAAA,UAAA,CAAW,aAAA,CAAc;AAAA,UACvB,IAAA,EAAM,SAAA;AAAA,UACN,KAAA,EAAO;AAAA,SACR,CAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import { coreServices, createBackendPlugin } from \"@backstage/backend-plugin-api\";\nimport { createRouter } from \"./router\";\nimport { Hub, type HubOptions } from \"./hub\";\nimport { toEntityPath } from \"./entityPath\";\n\nexport const rwPlugin = createBackendPlugin({\n pluginId: \"rw\",\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n },\n async init({ httpRouter, httpAuth, logger, config }) {\n const projectDir = config.getOptionalString(\"rw.projectDir\");\n const entity = config.getOptionalString(\"rw.entity\");\n const cacheSize = config.getOptionalNumber(\"rw.cacheSize\");\n\n const s3Config = config.getOptionalConfig(\"rw.s3\");\n const s3 = s3Config\n ? {\n bucket: s3Config.getString(\"bucket\"),\n region: s3Config.getOptionalString(\"region\"),\n endpoint: s3Config.getOptionalString(\"endpoint\"),\n bucketRootPath: s3Config.getOptionalString(\"bucketRootPath\"),\n accessKeyId: s3Config.getOptionalString(\"accessKeyId\"),\n secretAccessKey: s3Config.getOptionalString(\"secretAccessKey\"),\n }\n : undefined;\n\n if (!projectDir && !s3) {\n throw new Error(\"Either rw.projectDir or rw.s3 must be configured\");\n }\n\n if (projectDir && !entity) {\n throw new Error(\"rw.entity is required when rw.projectDir is set\");\n }\n\n const diagramsConfig = config.getOptionalConfig(\"rw.diagrams\");\n const diagrams = diagramsConfig\n ? {\n krokiUrl: diagramsConfig.getOptionalString(\"krokiUrl\"),\n dpi: diagramsConfig.getOptionalNumber(\"dpi\"),\n }\n : undefined;\n\n const hubOptions: HubOptions = {\n projectDir,\n entity,\n s3,\n diagrams,\n cacheSize,\n };\n\n const hub = new Hub(hubOptions);\n\n if (s3) {\n logger.info(`Hub: S3 mode (bucket: ${s3.bucket}, cache size: ${cacheSize ?? 20})`);\n } else {\n logger.info(\n `Hub: local mode (${projectDir}, entity: ${entity ? toEntityPath(entity) : entity})`,\n );\n }\n\n const router = await createRouter({ logger, httpAuth, hub });\n httpRouter.use(router);\n httpRouter.addAuthPolicy({\n path: \"/health\",\n allow: \"unauthenticated\",\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","hub","Hub","toEntityPath","router","createRouter"],"mappings":"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"}
@@ -2,37 +2,53 @@
2
2
 
3
3
  var Router = require('express-promise-router');
4
4
  var errors = require('@backstage/errors');
5
- var core = require('@rwdocs/core');
6
5
 
7
6
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
7
 
9
8
  var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
10
9
 
11
10
  async function createRouter(options) {
12
- const { logger, projectDir, s3, linkPrefix, diagrams } = options;
11
+ const { hub } = options;
13
12
  const router = Router__default.default();
14
- const config = { projectDir, s3, linkPrefix, diagrams };
15
- logger.info(
16
- s3 ? `Creating RW site from S3 (${s3.bucket}/${s3.entity})` : `Creating RW site from ${projectDir}`
17
- );
18
- const site = core.createSite(config);
19
13
  router.get("/health", (_req, res) => {
20
14
  res.json({ status: "ok" });
21
15
  });
22
- router.get("/config", (_req, res) => {
16
+ router.use("/site/:namespace/:kind/:name", (req, res, next) => {
17
+ const { namespace, kind, name } = req.params;
18
+ const siteRef = `${namespace}/${kind}/${name}`.toLowerCase();
19
+ const site = hub.getSite(siteRef);
20
+ if (!site) {
21
+ throw new errors.NotFoundError(`No documentation site found for entity: ${siteRef}`);
22
+ }
23
+ res.locals.rwSite = site;
24
+ next();
25
+ });
26
+ router.get("/site/:namespace/:kind/:name/config", (_req, res) => {
23
27
  res.json({ liveReloadEnabled: false });
24
28
  });
25
- router.get("/navigation", (req, res) => {
26
- const scopeParam = req.query.scope;
27
- const scope = typeof scopeParam === "string" ? scopeParam : void 0;
28
- const nav = site.getNavigation(scope ?? null);
29
+ router.get("/site/:namespace/:kind/:name/navigation", (req, res) => {
30
+ const site = res.locals.rwSite;
31
+ const sectionRefParam = req.query.sectionRef;
32
+ const sectionRef = typeof sectionRefParam === "string" ? sectionRefParam : null;
33
+ const nav = site.getNavigation(sectionRef);
29
34
  res.json(nav);
30
35
  });
31
- router.get("/pages/", async (_req, res) => {
32
- const page = await renderPageOrThrow(site, "");
36
+ router.get("/site/:namespace/:kind/:name/pages/", async (req, res) => {
37
+ const site = res.locals.rwSite;
38
+ const sectionRefParam = req.query.sectionRef;
39
+ const sectionRef = typeof sectionRefParam === "string" ? sectionRefParam : void 0;
40
+ let pagePath = "";
41
+ if (sectionRef) {
42
+ const nav = site.getNavigation(sectionRef);
43
+ if (nav.scope?.path) {
44
+ pagePath = nav.scope.path.replace(/^\//, "");
45
+ }
46
+ }
47
+ const page = await renderPageOrThrow(site, pagePath);
33
48
  res.json(page);
34
49
  });
35
- router.get("/pages/:path(*)", async (req, res) => {
50
+ router.get("/site/:namespace/:kind/:name/pages/:path(*)", async (req, res) => {
51
+ const site = res.locals.rwSite;
36
52
  const pagePath = req.params.path || "";
37
53
  if (pagePath.split("/").includes("..")) {
38
54
  throw new errors.InputError("Invalid path");
@@ -1 +1 @@
1
- {"version":3,"file":"router.cjs.js","sources":["../src/router.ts"],"sourcesContent":["import Router from \"express-promise-router\";\nimport type { HttpAuthService, LoggerService } from \"@backstage/backend-plugin-api\";\nimport { InputError, NotFoundError } from \"@backstage/errors\";\nimport { createSite, type RwSite, type SiteConfig } from \"@rwdocs/core\";\n\nexport interface S3Options {\n bucket: string;\n entity: string;\n region?: string;\n endpoint?: string;\n bucketRootPath?: string;\n}\n\nexport interface DiagramsOptions {\n krokiUrl?: string;\n dpi?: number;\n}\n\nexport interface RouterOptions {\n logger: LoggerService;\n httpAuth: HttpAuthService;\n projectDir?: string;\n s3?: S3Options;\n linkPrefix?: string;\n diagrams?: DiagramsOptions;\n}\n\nexport async function createRouter(options: RouterOptions) {\n const { logger, projectDir, s3, linkPrefix, diagrams } = options;\n const router = Router();\n\n const config: SiteConfig = { projectDir, s3, linkPrefix, diagrams };\n logger.info(\n s3\n ? `Creating RW site from S3 (${s3.bucket}/${s3.entity})`\n : `Creating RW site from ${projectDir}`,\n );\n const site: RwSite = createSite(config);\n\n router.get(\"/health\", (_req, res) => {\n res.json({ status: \"ok\" });\n });\n\n router.get(\"/config\", (_req, res) => {\n res.json({ liveReloadEnabled: false });\n });\n\n router.get(\"/navigation\", (req, res) => {\n const scopeParam = req.query.scope;\n const scope = typeof scopeParam === \"string\" ? scopeParam : undefined;\n const nav = site.getNavigation(scope ?? null);\n res.json(nav);\n });\n\n router.get(\"/pages/\", async (_req, res) => {\n const page = await renderPageOrThrow(site, \"\");\n res.json(page);\n });\n\n router.get(\"/pages/:path(*)\", async (req, res) => {\n const pagePath = req.params.path || \"\";\n if (pagePath.split(\"/\").includes(\"..\")) {\n throw new InputError(\"Invalid path\");\n }\n const page = await renderPageOrThrow(site, pagePath);\n res.json(page);\n });\n\n return router;\n}\n\nasync function renderPageOrThrow(site: RwSite, pagePath: string) {\n try {\n return await site.renderPage(pagePath);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.includes(\"Content not found\")) {\n throw new NotFoundError(`Page not found: /${pagePath}`);\n }\n throw err;\n }\n}\n"],"names":["Router","createSite","InputError","NotFoundError"],"mappings":";;;;;;;;;;AA2BA,eAAsB,aAAa,OAAA,EAAwB;AACzD,EAAA,MAAM,EAAE,MAAA,EAAQ,UAAA,EAAY,EAAA,EAAI,UAAA,EAAY,UAAS,GAAI,OAAA;AACzD,EAAA,MAAM,SAASA,uBAAA,EAAO;AAEtB,EAAA,MAAM,MAAA,GAAqB,EAAE,UAAA,EAAY,EAAA,EAAI,YAAY,QAAA,EAAS;AAClE,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,EAAA,GACI,6BAA6B,EAAA,CAAG,MAAM,IAAI,EAAA,CAAG,MAAM,CAAA,CAAA,CAAA,GACnD,CAAA,sBAAA,EAAyB,UAAU,CAAA;AAAA,GACzC;AACA,EAAA,MAAM,IAAA,GAAeC,gBAAW,MAAM,CAAA;AAEtC,EAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,CAAC,IAAA,EAAM,GAAA,KAAQ;AACnC,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,CAAA;AAAA,EAC3B,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,CAAC,IAAA,EAAM,GAAA,KAAQ;AACnC,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,iBAAA,EAAmB,KAAA,EAAO,CAAA;AAAA,EACvC,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,aAAA,EAAe,CAAC,GAAA,EAAK,GAAA,KAAQ;AACtC,IAAA,MAAM,UAAA,GAAa,IAAI,KAAA,CAAM,KAAA;AAC7B,IAAA,MAAM,KAAA,GAAQ,OAAO,UAAA,KAAe,QAAA,GAAW,UAAA,GAAa,MAAA;AAC5D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,aAAA,CAAc,KAAA,IAAS,IAAI,CAAA;AAC5C,IAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AAAA,EACd,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,OAAO,IAAA,EAAM,GAAA,KAAQ;AACzC,IAAA,MAAM,IAAA,GAAO,MAAM,iBAAA,CAAkB,IAAA,EAAM,EAAE,CAAA;AAC7C,IAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,EACf,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,iBAAA,EAAmB,OAAO,GAAA,EAAK,GAAA,KAAQ;AAChD,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,MAAA,CAAO,IAAA,IAAQ,EAAA;AACpC,IAAA,IAAI,SAAS,KAAA,CAAM,GAAG,CAAA,CAAE,QAAA,CAAS,IAAI,CAAA,EAAG;AACtC,MAAA,MAAM,IAAIC,kBAAW,cAAc,CAAA;AAAA,IACrC;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,iBAAA,CAAkB,IAAA,EAAM,QAAQ,CAAA;AACnD,IAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,EACf,CAAC,CAAA;AAED,EAAA,OAAO,MAAA;AACT;AAEA,eAAe,iBAAA,CAAkB,MAAc,QAAA,EAAkB;AAC/D,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA;AAAA,EACvC,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,UAAU,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC/D,IAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,mBAAmB,CAAA,EAAG;AACzC,MAAA,MAAM,IAAIC,oBAAA,CAAc,CAAA,iBAAA,EAAoB,QAAQ,CAAA,CAAE,CAAA;AAAA,IACxD;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;;;;"}
1
+ {"version":3,"file":"router.cjs.js","sources":["../src/router.ts"],"sourcesContent":["import Router from \"express-promise-router\";\nimport type { HttpAuthService, LoggerService } from \"@backstage/backend-plugin-api\";\nimport { InputError, NotFoundError } from \"@backstage/errors\";\nimport type { RwSite } from \"@rwdocs/core\";\nimport type { Hub } from \"./hub\";\n\nexport interface RouterOptions {\n logger: LoggerService;\n httpAuth: HttpAuthService;\n hub: Hub;\n}\n\nexport async function createRouter(options: RouterOptions) {\n const { hub } = options;\n const router = Router();\n\n router.get(\"/health\", (_req, res) => {\n res.json({ status: \"ok\" });\n });\n\n router.use(\"/site/:namespace/:kind/:name\", (req, res, next) => {\n const { namespace, kind, name } = req.params;\n const siteRef = `${namespace}/${kind}/${name}`.toLowerCase();\n\n const site = hub.getSite(siteRef);\n if (!site) {\n throw new NotFoundError(`No documentation site found for entity: ${siteRef}`);\n }\n\n res.locals.rwSite = site;\n next();\n });\n\n router.get(\"/site/:namespace/:kind/:name/config\", (_req, res) => {\n res.json({ liveReloadEnabled: false });\n });\n\n router.get(\"/site/:namespace/:kind/:name/navigation\", (req, res) => {\n const site: RwSite = res.locals.rwSite;\n const sectionRefParam = req.query.sectionRef;\n const sectionRef = typeof sectionRefParam === \"string\" ? sectionRefParam : null;\n const nav = site.getNavigation(sectionRef);\n res.json(nav);\n });\n\n router.get(\"/site/:namespace/:kind/:name/pages/\", async (req, res) => {\n const site: RwSite = res.locals.rwSite;\n const sectionRefParam = req.query.sectionRef;\n const sectionRef = typeof sectionRefParam === \"string\" ? sectionRefParam : undefined;\n\n let pagePath = \"\";\n if (sectionRef) {\n const nav = site.getNavigation(sectionRef);\n if (nav.scope?.path) {\n pagePath = nav.scope.path.replace(/^\\//, \"\");\n }\n }\n\n const page = await renderPageOrThrow(site, pagePath);\n res.json(page);\n });\n\n router.get(\"/site/:namespace/:kind/:name/pages/:path(*)\", async (req, res) => {\n const site: RwSite = res.locals.rwSite;\n const pagePath = req.params.path || \"\";\n if (pagePath.split(\"/\").includes(\"..\")) {\n throw new InputError(\"Invalid path\");\n }\n const page = await renderPageOrThrow(site, pagePath);\n res.json(page);\n });\n\n return router;\n}\n\nasync function renderPageOrThrow(site: RwSite, pagePath: string) {\n try {\n return await site.renderPage(pagePath);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.includes(\"Content not found\")) {\n throw new NotFoundError(`Page not found: /${pagePath}`);\n }\n throw err;\n }\n}\n"],"names":["Router","NotFoundError","InputError"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@rwdocs/backstage-plugin-rw-backend",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "license": "MIT OR Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/rwdocs/backstage-plugins.git",
8
+ "directory": "plugins/rw-backend"
9
+ },
5
10
  "main": "dist/index.cjs.js",
6
11
  "types": "dist/index.d.ts",
7
12
  "exports": {
@@ -48,8 +53,9 @@
48
53
  "postpack": "backstage-cli package postpack"
49
54
  },
50
55
  "dependencies": {
56
+ "@backstage/catalog-model": "^1.7.6",
51
57
  "@backstage/errors": "^1.2.7",
52
- "@rwdocs/core": "^0.1.14",
58
+ "@rwdocs/core": "^0.1.18",
53
59
  "express": "^4.21.0",
54
60
  "express-promise-router": "^4.1.0"
55
61
  },
@@ -59,14 +65,14 @@
59
65
  "devDependencies": {
60
66
  "@backstage/backend-plugin-api": "^1.0.0",
61
67
  "@backstage/backend-test-utils": "^1.11.0",
62
- "@backstage/cli": "^0.35.0",
68
+ "@backstage/cli": "^0.36.0",
63
69
  "@jest/environment-jsdom-abstract": "^30.2.0",
64
70
  "@types/express": "^4.17.0",
65
71
  "@types/jest": "^30.0.0",
66
72
  "@types/jsdom": "^28",
67
73
  "@types/supertest": "^7.2.0",
68
74
  "jest": "^30.2.0",
69
- "jsdom": "^28.1.0",
75
+ "jsdom": "^29.0.0",
70
76
  "prettier": "^3.4.2",
71
77
  "supertest": "^7.2.2",
72
78
  "typescript": "^5.7.0"