@backstage/backend-app-api 0.2.5-next.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @backstage/backend-app-api might be problematic. Click here for more details.

package/dist/index.cjs.js CHANGED
@@ -2,32 +2,896 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var backendPluginApi = require('@backstage/backend-plugin-api');
5
+ var path = require('path');
6
+ var parseArgs = require('minimist');
7
+ var cliCommon = require('@backstage/cli-common');
8
+ var configLoader = require('@backstage/config-loader');
9
+ var config = require('@backstage/config');
10
+ var getPackages = require('@manypkg/get-packages');
11
+ var http = require('http');
12
+ var https = require('https');
13
+ var stoppableServer = require('stoppable');
14
+ var fs = require('fs-extra');
15
+ var forge = require('node-forge');
16
+ var cors = require('cors');
17
+ var helmet = require('helmet');
18
+ var morgan = require('morgan');
19
+ var compression = require('compression');
20
+ var minimatch = require('minimatch');
6
21
  var errors = require('@backstage/errors');
22
+ var winston = require('winston');
23
+ var backendPluginApi = require('@backstage/backend-plugin-api');
7
24
  var backendCommon = require('@backstage/backend-common');
25
+ var pluginAuthNode = require('@backstage/plugin-auth-node');
8
26
  var pluginPermissionNode = require('@backstage/plugin-permission-node');
27
+ var express = require('express');
28
+ var trimEnd = require('lodash/trimEnd');
9
29
  var backendTasks = require('@backstage/backend-tasks');
10
- var Router = require('express-promise-router');
11
30
 
12
31
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
32
 
14
- var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
33
+ function _interopNamespace(e) {
34
+ if (e && e.__esModule) return e;
35
+ var n = Object.create(null);
36
+ if (e) {
37
+ Object.keys(e).forEach(function (k) {
38
+ if (k !== 'default') {
39
+ var d = Object.getOwnPropertyDescriptor(e, k);
40
+ Object.defineProperty(n, k, d.get ? d : {
41
+ enumerable: true,
42
+ get: function () { return e[k]; }
43
+ });
44
+ }
45
+ });
46
+ }
47
+ n["default"] = e;
48
+ return Object.freeze(n);
49
+ }
50
+
51
+ var parseArgs__default = /*#__PURE__*/_interopDefaultLegacy(parseArgs);
52
+ var http__namespace = /*#__PURE__*/_interopNamespace(http);
53
+ var https__namespace = /*#__PURE__*/_interopNamespace(https);
54
+ var stoppableServer__default = /*#__PURE__*/_interopDefaultLegacy(stoppableServer);
55
+ var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
56
+ var forge__default = /*#__PURE__*/_interopDefaultLegacy(forge);
57
+ var cors__default = /*#__PURE__*/_interopDefaultLegacy(cors);
58
+ var helmet__default = /*#__PURE__*/_interopDefaultLegacy(helmet);
59
+ var morgan__default = /*#__PURE__*/_interopDefaultLegacy(morgan);
60
+ var compression__default = /*#__PURE__*/_interopDefaultLegacy(compression);
61
+ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
62
+ var trimEnd__default = /*#__PURE__*/_interopDefaultLegacy(trimEnd);
15
63
 
16
- var __accessCheck$3 = (obj, member, msg) => {
64
+ class ObservableConfigProxy {
65
+ constructor(parent, parentKey) {
66
+ this.parent = parent;
67
+ this.parentKey = parentKey;
68
+ this.config = new config.ConfigReader({});
69
+ this.subscribers = [];
70
+ if (parent && !parentKey) {
71
+ throw new Error("parentKey is required if parent is set");
72
+ }
73
+ }
74
+ setConfig(config) {
75
+ if (this.parent) {
76
+ throw new Error("immutable");
77
+ }
78
+ this.config = config;
79
+ for (const subscriber of this.subscribers) {
80
+ try {
81
+ subscriber();
82
+ } catch (error) {
83
+ console.error(`Config subscriber threw error, ${error}`);
84
+ }
85
+ }
86
+ }
87
+ subscribe(onChange) {
88
+ if (this.parent) {
89
+ return this.parent.subscribe(onChange);
90
+ }
91
+ this.subscribers.push(onChange);
92
+ return {
93
+ unsubscribe: () => {
94
+ const index = this.subscribers.indexOf(onChange);
95
+ if (index >= 0) {
96
+ this.subscribers.splice(index, 1);
97
+ }
98
+ }
99
+ };
100
+ }
101
+ select(required) {
102
+ var _a;
103
+ if (this.parent && this.parentKey) {
104
+ if (required) {
105
+ return this.parent.select(true).getConfig(this.parentKey);
106
+ }
107
+ return (_a = this.parent.select(false)) == null ? void 0 : _a.getOptionalConfig(this.parentKey);
108
+ }
109
+ return this.config;
110
+ }
111
+ has(key) {
112
+ var _a, _b;
113
+ return (_b = (_a = this.select(false)) == null ? void 0 : _a.has(key)) != null ? _b : false;
114
+ }
115
+ keys() {
116
+ var _a, _b;
117
+ return (_b = (_a = this.select(false)) == null ? void 0 : _a.keys()) != null ? _b : [];
118
+ }
119
+ get(key) {
120
+ return this.select(true).get(key);
121
+ }
122
+ getOptional(key) {
123
+ var _a;
124
+ return (_a = this.select(false)) == null ? void 0 : _a.getOptional(key);
125
+ }
126
+ getConfig(key) {
127
+ return new ObservableConfigProxy(this, key);
128
+ }
129
+ getOptionalConfig(key) {
130
+ var _a;
131
+ if ((_a = this.select(false)) == null ? void 0 : _a.has(key)) {
132
+ return new ObservableConfigProxy(this, key);
133
+ }
134
+ return void 0;
135
+ }
136
+ getConfigArray(key) {
137
+ return this.select(true).getConfigArray(key);
138
+ }
139
+ getOptionalConfigArray(key) {
140
+ var _a;
141
+ return (_a = this.select(false)) == null ? void 0 : _a.getOptionalConfigArray(key);
142
+ }
143
+ getNumber(key) {
144
+ return this.select(true).getNumber(key);
145
+ }
146
+ getOptionalNumber(key) {
147
+ var _a;
148
+ return (_a = this.select(false)) == null ? void 0 : _a.getOptionalNumber(key);
149
+ }
150
+ getBoolean(key) {
151
+ return this.select(true).getBoolean(key);
152
+ }
153
+ getOptionalBoolean(key) {
154
+ var _a;
155
+ return (_a = this.select(false)) == null ? void 0 : _a.getOptionalBoolean(key);
156
+ }
157
+ getString(key) {
158
+ return this.select(true).getString(key);
159
+ }
160
+ getOptionalString(key) {
161
+ var _a;
162
+ return (_a = this.select(false)) == null ? void 0 : _a.getOptionalString(key);
163
+ }
164
+ getStringArray(key) {
165
+ return this.select(true).getStringArray(key);
166
+ }
167
+ getOptionalStringArray(key) {
168
+ var _a;
169
+ return (_a = this.select(false)) == null ? void 0 : _a.getOptionalStringArray(key);
170
+ }
171
+ }
172
+
173
+ function isValidUrl(url) {
174
+ try {
175
+ new URL(url);
176
+ return true;
177
+ } catch {
178
+ return false;
179
+ }
180
+ }
181
+
182
+ async function createConfigSecretEnumerator(options) {
183
+ const { logger, dir = process.cwd() } = options;
184
+ const { packages } = await getPackages.getPackages(dir);
185
+ const schema = await configLoader.loadConfigSchema({
186
+ dependencies: packages.map((p) => p.packageJson.name)
187
+ });
188
+ return (config) => {
189
+ var _a;
190
+ const [secretsData] = schema.process(
191
+ [{ data: (_a = config.getOptional()) != null ? _a : {}, context: "schema-enumerator" }],
192
+ {
193
+ visibility: ["secret"],
194
+ ignoreSchemaErrors: true
195
+ }
196
+ );
197
+ const secrets = /* @__PURE__ */ new Set();
198
+ JSON.parse(
199
+ JSON.stringify(secretsData),
200
+ (_, v) => typeof v === "string" && secrets.add(v)
201
+ );
202
+ logger.info(
203
+ `Found ${secrets.size} new secrets in config that will be redacted`
204
+ );
205
+ return secrets;
206
+ };
207
+ }
208
+ async function loadBackendConfig(options) {
209
+ var _a;
210
+ const args = parseArgs__default["default"](options.argv);
211
+ const configTargets = [(_a = args.config) != null ? _a : []].flat().map((arg) => isValidUrl(arg) ? { url: arg } : { path: path.resolve(arg) });
212
+ const paths = cliCommon.findPaths(__dirname);
213
+ let currentCancelFunc = void 0;
214
+ const config$1 = new ObservableConfigProxy();
215
+ const { appConfigs } = await configLoader.loadConfig({
216
+ configRoot: paths.targetRoot,
217
+ configTargets,
218
+ remote: options.remote,
219
+ watch: {
220
+ onChange(newConfigs) {
221
+ console.info(
222
+ `Reloaded config from ${newConfigs.map((c) => c.context).join(", ")}`
223
+ );
224
+ config$1.setConfig(config.ConfigReader.fromConfigs(newConfigs));
225
+ },
226
+ stopSignal: new Promise((resolve) => {
227
+ if (currentCancelFunc) {
228
+ currentCancelFunc();
229
+ }
230
+ currentCancelFunc = resolve;
231
+ if (module.hot) {
232
+ module.hot.addDisposeHandler(resolve);
233
+ }
234
+ })
235
+ }
236
+ });
237
+ console.info(
238
+ `Loaded config from ${appConfigs.map((c) => c.context).join(", ")}`
239
+ );
240
+ config$1.setConfig(config.ConfigReader.fromConfigs(appConfigs));
241
+ return { config: config$1 };
242
+ }
243
+
244
+ const DEFAULT_PORT = 7007;
245
+ const DEFAULT_HOST = "";
246
+ function readHttpServerOptions(config) {
247
+ return {
248
+ listen: readHttpListenOptions(config),
249
+ https: readHttpsOptions(config)
250
+ };
251
+ }
252
+ function readHttpListenOptions(config) {
253
+ var _a, _b;
254
+ const listen = config == null ? void 0 : config.getOptional("listen");
255
+ if (typeof listen === "string") {
256
+ const parts = String(listen).split(":");
257
+ const port = parseInt(parts[parts.length - 1], 10);
258
+ if (!isNaN(port)) {
259
+ if (parts.length === 1) {
260
+ return { port, host: DEFAULT_HOST };
261
+ }
262
+ if (parts.length === 2) {
263
+ return { host: parts[0], port };
264
+ }
265
+ }
266
+ throw new Error(
267
+ `Unable to parse listen address ${listen}, expected <port> or <host>:<port>`
268
+ );
269
+ }
270
+ const host = (_a = config == null ? void 0 : config.getOptional("listen.host")) != null ? _a : DEFAULT_HOST;
271
+ if (typeof host !== "string") {
272
+ config == null ? void 0 : config.getOptionalString("listen.host");
273
+ throw new Error("unreachable");
274
+ }
275
+ return {
276
+ port: (_b = config == null ? void 0 : config.getOptionalNumber("listen.port")) != null ? _b : DEFAULT_PORT,
277
+ host
278
+ };
279
+ }
280
+ function readHttpsOptions(config) {
281
+ const https = config == null ? void 0 : config.getOptional("https");
282
+ if (https === true) {
283
+ const baseUrl = config.getString("baseUrl");
284
+ let hostname;
285
+ try {
286
+ hostname = new URL(baseUrl).hostname;
287
+ } catch (error) {
288
+ throw new Error(`Invalid baseUrl "${baseUrl}"`);
289
+ }
290
+ return { certificate: { type: "generated", hostname } };
291
+ }
292
+ const cc = config == null ? void 0 : config.getOptionalConfig("https");
293
+ if (!cc) {
294
+ return void 0;
295
+ }
296
+ return {
297
+ certificate: {
298
+ type: "plain",
299
+ cert: cc.getString("certificate.cert"),
300
+ key: cc.getString("certificate.key")
301
+ }
302
+ };
303
+ }
304
+
305
+ const FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1e3;
306
+ const IP_HOSTNAME_REGEX = /:|^\d+\.\d+\.\d+\.\d+$/;
307
+ async function getGeneratedCertificate(hostname, logger) {
308
+ const hasModules = await fs__default["default"].pathExists("node_modules");
309
+ let certPath;
310
+ if (hasModules) {
311
+ certPath = path.resolve(
312
+ "node_modules/.cache/backstage-backend/dev-cert.pem"
313
+ );
314
+ await fs__default["default"].ensureDir(path.dirname(certPath));
315
+ } else {
316
+ certPath = path.resolve(".dev-cert.pem");
317
+ }
318
+ if (await fs__default["default"].pathExists(certPath)) {
319
+ try {
320
+ const cert = await fs__default["default"].readFile(certPath);
321
+ const crt = forge__default["default"].pki.certificateFromPem(cert.toString());
322
+ const remainingMs = crt.validity.notAfter.getTime() - Date.now();
323
+ if (remainingMs > FIVE_DAYS_IN_MS) {
324
+ logger.info("Using existing self-signed certificate");
325
+ return {
326
+ key: cert,
327
+ cert
328
+ };
329
+ }
330
+ } catch (error) {
331
+ logger.warn(`Unable to use existing self-signed certificate, ${error}`);
332
+ }
333
+ }
334
+ logger.info("Generating new self-signed certificate");
335
+ const newCert = await generateCertificate(hostname);
336
+ await fs__default["default"].writeFile(certPath, newCert.cert + newCert.key, "utf8");
337
+ return newCert;
338
+ }
339
+ async function generateCertificate(hostname) {
340
+ const attributes = [
341
+ {
342
+ name: "commonName",
343
+ value: "dev-cert"
344
+ }
345
+ ];
346
+ const sans = [
347
+ {
348
+ type: 2,
349
+ // DNS
350
+ value: "localhost"
351
+ },
352
+ {
353
+ type: 2,
354
+ value: "localhost.localdomain"
355
+ },
356
+ {
357
+ type: 2,
358
+ value: "[::1]"
359
+ },
360
+ {
361
+ type: 7,
362
+ // IP
363
+ ip: "127.0.0.1"
364
+ },
365
+ {
366
+ type: 7,
367
+ ip: "fe80::1"
368
+ }
369
+ ];
370
+ if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {
371
+ sans.push(
372
+ IP_HOSTNAME_REGEX.test(hostname) ? {
373
+ type: 7,
374
+ ip: hostname
375
+ } : {
376
+ type: 2,
377
+ value: hostname
378
+ }
379
+ );
380
+ }
381
+ const params = {
382
+ algorithm: "sha256",
383
+ keySize: 2048,
384
+ days: 30,
385
+ extensions: [
386
+ {
387
+ name: "keyUsage",
388
+ keyCertSign: true,
389
+ digitalSignature: true,
390
+ nonRepudiation: true,
391
+ keyEncipherment: true,
392
+ dataEncipherment: true
393
+ },
394
+ {
395
+ name: "extKeyUsage",
396
+ serverAuth: true,
397
+ clientAuth: true,
398
+ codeSigning: true,
399
+ timeStamping: true
400
+ },
401
+ {
402
+ name: "subjectAltName",
403
+ altNames: sans
404
+ }
405
+ ]
406
+ };
407
+ return new Promise(
408
+ (resolve, reject) => require("selfsigned").generate(
409
+ attributes,
410
+ params,
411
+ (err, bundle) => {
412
+ if (err) {
413
+ reject(err);
414
+ } else {
415
+ resolve({ key: bundle.private, cert: bundle.cert });
416
+ }
417
+ }
418
+ )
419
+ );
420
+ }
421
+
422
+ async function createHttpServer(listener, options, deps) {
423
+ const server = await createServer(listener, options, deps);
424
+ const stopper = stoppableServer__default["default"](server, 0);
425
+ const stopServer = stopper.stop.bind(stopper);
426
+ return Object.assign(server, {
427
+ start() {
428
+ return new Promise((resolve, reject) => {
429
+ const handleStartupError = (error) => {
430
+ server.close();
431
+ reject(error);
432
+ };
433
+ server.on("error", handleStartupError);
434
+ const { host, port } = options.listen;
435
+ server.listen(port, host, () => {
436
+ server.off("error", handleStartupError);
437
+ deps.logger.info(`Listening on ${host}:${port}`);
438
+ resolve();
439
+ });
440
+ });
441
+ },
442
+ stop() {
443
+ return new Promise((resolve, reject) => {
444
+ stopServer((error) => {
445
+ if (error) {
446
+ reject(error);
447
+ } else {
448
+ resolve();
449
+ }
450
+ });
451
+ });
452
+ },
453
+ port() {
454
+ const address = server.address();
455
+ if (typeof address === "string" || address === null) {
456
+ throw new Error(`Unexpected server address '${address}'`);
457
+ }
458
+ return address.port;
459
+ }
460
+ });
461
+ }
462
+ async function createServer(listener, options, deps) {
463
+ if (options.https) {
464
+ const { certificate } = options.https;
465
+ if (certificate.type === "generated") {
466
+ const credentials = await getGeneratedCertificate(
467
+ certificate.hostname,
468
+ deps.logger
469
+ );
470
+ return https__namespace.createServer(credentials, listener);
471
+ }
472
+ return https__namespace.createServer(certificate, listener);
473
+ }
474
+ return http__namespace.createServer(listener);
475
+ }
476
+
477
+ function readHelmetOptions(config) {
478
+ const cspOptions = readCspDirectives(config);
479
+ return {
480
+ contentSecurityPolicy: {
481
+ useDefaults: false,
482
+ directives: applyCspDirectives(cspOptions)
483
+ },
484
+ // These are all disabled in order to maintain backwards compatibility
485
+ // when bumping helmet v5. We can't enable these by default because
486
+ // there is no way for users to configure them.
487
+ // TODO(Rugvip): We should give control of this setup to consumers
488
+ crossOriginEmbedderPolicy: false,
489
+ crossOriginOpenerPolicy: false,
490
+ crossOriginResourcePolicy: false,
491
+ originAgentCluster: false
492
+ };
493
+ }
494
+ function readCspDirectives(config) {
495
+ const cc = config == null ? void 0 : config.getOptionalConfig("csp");
496
+ if (!cc) {
497
+ return void 0;
498
+ }
499
+ const result = {};
500
+ for (const key of cc.keys()) {
501
+ if (cc.get(key) === false) {
502
+ result[key] = false;
503
+ } else {
504
+ result[key] = cc.getStringArray(key);
505
+ }
506
+ }
507
+ return result;
508
+ }
509
+ function applyCspDirectives(directives) {
510
+ const result = helmet__default["default"].contentSecurityPolicy.getDefaultDirectives();
511
+ result["script-src"] = ["'self'", "'unsafe-eval'"];
512
+ delete result["form-action"];
513
+ if (directives) {
514
+ for (const [key, value] of Object.entries(directives)) {
515
+ if (value === false) {
516
+ delete result[key];
517
+ } else {
518
+ result[key] = value;
519
+ }
520
+ }
521
+ }
522
+ return result;
523
+ }
524
+
525
+ function readCorsOptions(config) {
526
+ const cc = config == null ? void 0 : config.getOptionalConfig("cors");
527
+ if (!cc) {
528
+ return { origin: false };
529
+ }
530
+ return removeUnknown({
531
+ origin: createCorsOriginMatcher(readStringArray(cc, "origin")),
532
+ methods: readStringArray(cc, "methods"),
533
+ allowedHeaders: readStringArray(cc, "allowedHeaders"),
534
+ exposedHeaders: readStringArray(cc, "exposedHeaders"),
535
+ credentials: cc.getOptionalBoolean("credentials"),
536
+ maxAge: cc.getOptionalNumber("maxAge"),
537
+ preflightContinue: cc.getOptionalBoolean("preflightContinue"),
538
+ optionsSuccessStatus: cc.getOptionalNumber("optionsSuccessStatus")
539
+ });
540
+ }
541
+ function removeUnknown(obj) {
542
+ return Object.fromEntries(
543
+ Object.entries(obj).filter(([, v]) => v !== void 0)
544
+ );
545
+ }
546
+ function readStringArray(config, key) {
547
+ const value = config.getOptional(key);
548
+ if (typeof value === "string") {
549
+ return [value];
550
+ } else if (!value) {
551
+ return void 0;
552
+ }
553
+ return config.getStringArray(key);
554
+ }
555
+ function createCorsOriginMatcher(allowedOriginPatterns) {
556
+ if (!allowedOriginPatterns) {
557
+ return void 0;
558
+ }
559
+ const allowedOriginMatchers = allowedOriginPatterns.map(
560
+ (pattern) => new minimatch.Minimatch(pattern, { nocase: true, noglobstar: true })
561
+ );
562
+ return (origin, callback) => {
563
+ return callback(
564
+ null,
565
+ allowedOriginMatchers.some((pattern) => pattern.match(origin != null ? origin : ""))
566
+ );
567
+ };
568
+ }
569
+
570
+ var __accessCheck$6 = (obj, member, msg) => {
17
571
  if (!member.has(obj))
18
572
  throw TypeError("Cannot " + msg);
19
573
  };
20
- var __privateGet$3 = (obj, member, getter) => {
21
- __accessCheck$3(obj, member, "read from private field");
574
+ var __privateGet$6 = (obj, member, getter) => {
575
+ __accessCheck$6(obj, member, "read from private field");
22
576
  return getter ? getter.call(obj) : member.get(obj);
23
577
  };
24
- var __privateAdd$3 = (obj, member, value) => {
578
+ var __privateAdd$6 = (obj, member, value) => {
25
579
  if (member.has(obj))
26
580
  throw TypeError("Cannot add the same private member more than once");
27
581
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
28
582
  };
29
- var __privateSet$3 = (obj, member, value, setter) => {
30
- __accessCheck$3(obj, member, "write to private field");
583
+ var __privateSet$6 = (obj, member, value, setter) => {
584
+ __accessCheck$6(obj, member, "write to private field");
585
+ setter ? setter.call(obj, value) : member.set(obj, value);
586
+ return value;
587
+ };
588
+ var _config, _logger;
589
+ const _MiddlewareFactory = class {
590
+ constructor(options) {
591
+ __privateAdd$6(this, _config, void 0);
592
+ __privateAdd$6(this, _logger, void 0);
593
+ __privateSet$6(this, _config, options.config);
594
+ __privateSet$6(this, _logger, options.logger);
595
+ }
596
+ /**
597
+ * Creates a new {@link MiddlewareFactory}.
598
+ */
599
+ static create(options) {
600
+ return new _MiddlewareFactory(options);
601
+ }
602
+ /**
603
+ * Returns a middleware that unconditionally produces a 404 error response.
604
+ *
605
+ * @remarks
606
+ *
607
+ * Typically you want to place this middleware at the end of the chain, such
608
+ * that it's the last one attempted after no other routes matched.
609
+ *
610
+ * @returns An Express request handler
611
+ */
612
+ notFound() {
613
+ return (_req, res) => {
614
+ res.status(404).end();
615
+ };
616
+ }
617
+ /**
618
+ * Returns the compression middleware.
619
+ *
620
+ * @remarks
621
+ *
622
+ * The middleware will attempt to compress response bodies for all requests
623
+ * that traverse through the middleware.
624
+ */
625
+ compression() {
626
+ return compression__default["default"]();
627
+ }
628
+ /**
629
+ * Returns a request logging middleware.
630
+ *
631
+ * @remarks
632
+ *
633
+ * Typically you want to place this middleware at the start of the chain, such
634
+ * that it always logs requests whether they are "caught" by handlers farther
635
+ * down or not.
636
+ *
637
+ * @returns An Express request handler
638
+ */
639
+ logging() {
640
+ const logger = __privateGet$6(this, _logger).child({
641
+ type: "incomingRequest"
642
+ });
643
+ return morgan__default["default"]("combined", {
644
+ stream: {
645
+ write(message) {
646
+ logger.info(message.trimEnd());
647
+ }
648
+ }
649
+ });
650
+ }
651
+ /**
652
+ * Returns a middleware that implements the helmet library.
653
+ *
654
+ * @remarks
655
+ *
656
+ * This middleware applies security policies to incoming requests and outgoing
657
+ * responses. It is configured using config keys such as `backend.csp`.
658
+ *
659
+ * @see {@link https://helmetjs.github.io/}
660
+ *
661
+ * @returns An Express request handler
662
+ */
663
+ helmet() {
664
+ return helmet__default["default"](readHelmetOptions(__privateGet$6(this, _config).getOptionalConfig("backend")));
665
+ }
666
+ /**
667
+ * Returns a middleware that implements the cors library.
668
+ *
669
+ * @remarks
670
+ *
671
+ * This middleware handles CORS. It is configured using the config key
672
+ * `backend.cors`.
673
+ *
674
+ * @see {@link https://github.com/expressjs/cors}
675
+ *
676
+ * @returns An Express request handler
677
+ */
678
+ cors() {
679
+ return cors__default["default"](readCorsOptions(__privateGet$6(this, _config).getOptionalConfig("backend")));
680
+ }
681
+ /**
682
+ * Express middleware to handle errors during request processing.
683
+ *
684
+ * @remarks
685
+ *
686
+ * This is commonly the very last middleware in the chain.
687
+ *
688
+ * Its primary purpose is not to do translation of business logic exceptions,
689
+ * but rather to be a global catch-all for uncaught "fatal" errors that are
690
+ * expected to result in a 500 error. However, it also does handle some common
691
+ * error types (such as http-error exceptions, and the well-known error types
692
+ * in the `@backstage/errors` package) and returns the enclosed status code
693
+ * accordingly.
694
+ *
695
+ * It will also produce a response body with a serialized form of the error,
696
+ * unless a previous handler already did send a body. See
697
+ * {@link @backstage/errors#ErrorResponseBody} for the response shape used.
698
+ *
699
+ * @returns An Express error request handler
700
+ */
701
+ error(options = {}) {
702
+ var _a;
703
+ const showStackTraces = (_a = options.showStackTraces) != null ? _a : process.env.NODE_ENV === "development";
704
+ const logger = __privateGet$6(this, _logger).child({
705
+ type: "errorHandler"
706
+ });
707
+ return (error, req, res, next) => {
708
+ const statusCode = getStatusCode(error);
709
+ if (options.logAllErrors || statusCode >= 500) {
710
+ logger.error(`Request failed with status ${statusCode}`, error);
711
+ }
712
+ if (res.headersSent) {
713
+ next(error);
714
+ return;
715
+ }
716
+ const body = {
717
+ error: errors.serializeError(error, { includeStack: showStackTraces }),
718
+ request: { method: req.method, url: req.url },
719
+ response: { statusCode }
720
+ };
721
+ res.status(statusCode).json(body);
722
+ };
723
+ }
724
+ };
725
+ let MiddlewareFactory = _MiddlewareFactory;
726
+ _config = new WeakMap();
727
+ _logger = new WeakMap();
728
+ function getStatusCode(error) {
729
+ const knownStatusCodeFields = ["statusCode", "status"];
730
+ for (const field of knownStatusCodeFields) {
731
+ const statusCode = error[field];
732
+ if (typeof statusCode === "number" && (statusCode | 0) === statusCode && // is whole integer
733
+ statusCode >= 100 && statusCode <= 599) {
734
+ return statusCode;
735
+ }
736
+ }
737
+ switch (error.name) {
738
+ case errors.NotModifiedError.name:
739
+ return 304;
740
+ case errors.InputError.name:
741
+ return 400;
742
+ case errors.AuthenticationError.name:
743
+ return 401;
744
+ case errors.NotAllowedError.name:
745
+ return 403;
746
+ case errors.NotFoundError.name:
747
+ return 404;
748
+ case errors.ConflictError.name:
749
+ return 409;
750
+ }
751
+ return 500;
752
+ }
753
+
754
+ var __accessCheck$5 = (obj, member, msg) => {
755
+ if (!member.has(obj))
756
+ throw TypeError("Cannot " + msg);
757
+ };
758
+ var __privateGet$5 = (obj, member, getter) => {
759
+ __accessCheck$5(obj, member, "read from private field");
760
+ return getter ? getter.call(obj) : member.get(obj);
761
+ };
762
+ var __privateAdd$5 = (obj, member, value) => {
763
+ if (member.has(obj))
764
+ throw TypeError("Cannot add the same private member more than once");
765
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
766
+ };
767
+ var __privateSet$5 = (obj, member, value, setter) => {
768
+ __accessCheck$5(obj, member, "write to private field");
769
+ setter ? setter.call(obj, value) : member.set(obj, value);
770
+ return value;
771
+ };
772
+ var _winston, _addRedactions;
773
+ const _WinstonLogger = class {
774
+ constructor(winston, addRedactions) {
775
+ __privateAdd$5(this, _winston, void 0);
776
+ __privateAdd$5(this, _addRedactions, void 0);
777
+ __privateSet$5(this, _winston, winston);
778
+ __privateSet$5(this, _addRedactions, addRedactions);
779
+ }
780
+ /**
781
+ * Creates a {@link WinstonLogger} instance.
782
+ */
783
+ static create(options) {
784
+ var _a;
785
+ const redacter = _WinstonLogger.redacter();
786
+ let logger = winston.createLogger({
787
+ level: options.level,
788
+ format: winston.format.combine(redacter.format, options.format),
789
+ transports: (_a = options.transports) != null ? _a : new winston.transports.Console()
790
+ });
791
+ if (options.meta) {
792
+ logger = logger.child(options.meta);
793
+ }
794
+ return new _WinstonLogger(logger, redacter.add);
795
+ }
796
+ /**
797
+ * Creates a winston log formatter for redacting secrets.
798
+ */
799
+ static redacter() {
800
+ const redactionSet = /* @__PURE__ */ new Set();
801
+ let redactionPattern = void 0;
802
+ return {
803
+ format: winston.format((info) => {
804
+ if (redactionPattern && typeof info.message === "string") {
805
+ info.message = info.message.replace(redactionPattern, "[REDACTED]");
806
+ }
807
+ return info;
808
+ })(),
809
+ add(newRedactions) {
810
+ let added = 0;
811
+ for (const redaction of newRedactions) {
812
+ if (redaction.length <= 1) {
813
+ continue;
814
+ }
815
+ if (!redactionSet.has(redaction)) {
816
+ redactionSet.add(redaction);
817
+ added += 1;
818
+ }
819
+ }
820
+ if (added > 0) {
821
+ redactionPattern = new RegExp(
822
+ `(${Array.from(redactionSet).join("|")})`,
823
+ "g"
824
+ );
825
+ }
826
+ }
827
+ };
828
+ }
829
+ /**
830
+ * Creates a pretty printed winston log formatter.
831
+ */
832
+ static colorFormat() {
833
+ const colorizer = winston.format.colorize();
834
+ return winston.format.combine(
835
+ winston.format.timestamp(),
836
+ winston.format.colorize({
837
+ colors: {
838
+ timestamp: "dim",
839
+ prefix: "blue",
840
+ field: "cyan",
841
+ debug: "grey"
842
+ }
843
+ }),
844
+ winston.format.printf((info) => {
845
+ const { timestamp, level, message, plugin, service, ...fields } = info;
846
+ const prefix = plugin || service;
847
+ const timestampColor = colorizer.colorize("timestamp", timestamp);
848
+ const prefixColor = colorizer.colorize("prefix", prefix);
849
+ const extraFields = Object.entries(fields).map(
850
+ ([key, value]) => `${colorizer.colorize("field", `${key}`)}=${value}`
851
+ ).join(" ");
852
+ return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;
853
+ })
854
+ );
855
+ }
856
+ error(message, meta) {
857
+ __privateGet$5(this, _winston).error(message, meta);
858
+ }
859
+ warn(message, meta) {
860
+ __privateGet$5(this, _winston).warn(message, meta);
861
+ }
862
+ info(message, meta) {
863
+ __privateGet$5(this, _winston).info(message, meta);
864
+ }
865
+ debug(message, meta) {
866
+ __privateGet$5(this, _winston).debug(message, meta);
867
+ }
868
+ child(meta) {
869
+ return new _WinstonLogger(__privateGet$5(this, _winston).child(meta));
870
+ }
871
+ addRedactions(redactions) {
872
+ var _a;
873
+ (_a = __privateGet$5(this, _addRedactions)) == null ? void 0 : _a.call(this, redactions);
874
+ }
875
+ };
876
+ let WinstonLogger = _WinstonLogger;
877
+ _winston = new WeakMap();
878
+ _addRedactions = new WeakMap();
879
+
880
+ var __accessCheck$4 = (obj, member, msg) => {
881
+ if (!member.has(obj))
882
+ throw TypeError("Cannot " + msg);
883
+ };
884
+ var __privateGet$4 = (obj, member, getter) => {
885
+ __accessCheck$4(obj, member, "read from private field");
886
+ return getter ? getter.call(obj) : member.get(obj);
887
+ };
888
+ var __privateAdd$4 = (obj, member, value) => {
889
+ if (member.has(obj))
890
+ throw TypeError("Cannot add the same private member more than once");
891
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
892
+ };
893
+ var __privateSet$4 = (obj, member, value, setter) => {
894
+ __accessCheck$4(obj, member, "write to private field");
31
895
  setter ? setter.call(obj, value) : member.set(obj, value);
32
896
  return value;
33
897
  };
@@ -36,26 +900,27 @@ const CALLBACKS = ["SIGTERM", "SIGINT", "beforeExit"];
36
900
  class BackendLifecycleImpl {
37
901
  constructor(logger) {
38
902
  this.logger = logger;
39
- __privateAdd$3(this, _isCalled, false);
40
- __privateAdd$3(this, _shutdownTasks, []);
903
+ __privateAdd$4(this, _isCalled, false);
904
+ __privateAdd$4(this, _shutdownTasks, []);
41
905
  CALLBACKS.map((signal) => process.on(signal, () => this.shutdown()));
42
906
  }
43
907
  addShutdownHook(options) {
44
- __privateGet$3(this, _shutdownTasks).push(options);
908
+ __privateGet$4(this, _shutdownTasks).push(options);
45
909
  }
46
910
  async shutdown() {
47
- if (__privateGet$3(this, _isCalled)) {
911
+ if (__privateGet$4(this, _isCalled)) {
48
912
  return;
49
913
  }
50
- __privateSet$3(this, _isCalled, true);
51
- this.logger.info(`Running ${__privateGet$3(this, _shutdownTasks).length} shutdown tasks...`);
914
+ __privateSet$4(this, _isCalled, true);
915
+ this.logger.info(`Running ${__privateGet$4(this, _shutdownTasks).length} shutdown tasks...`);
52
916
  await Promise.all(
53
- __privateGet$3(this, _shutdownTasks).map(async (hook) => {
917
+ __privateGet$4(this, _shutdownTasks).map(async (hook) => {
918
+ const { logger = this.logger } = hook;
54
919
  try {
55
920
  await hook.fn();
56
- this.logger.info(`Shutdown hook succeeded`, hook.labels);
921
+ logger.info(`Shutdown hook succeeded`);
57
922
  } catch (error) {
58
- this.logger.error(`Shutdown hook failed, ${error}`, hook.labels);
923
+ logger.error(`Shutdown hook failed, ${error}`);
59
924
  }
60
925
  })
61
926
  );
@@ -69,61 +934,61 @@ const rootLifecycleFactory = backendPluginApi.createServiceFactory({
69
934
  logger: backendPluginApi.coreServices.rootLogger
70
935
  },
71
936
  async factory({ logger }) {
72
- return new BackendLifecycleImpl(backendPluginApi.loggerToWinstonLogger(logger));
937
+ return new BackendLifecycleImpl(logger);
73
938
  }
74
939
  });
75
940
 
76
- var __accessCheck$2 = (obj, member, msg) => {
941
+ var __accessCheck$3 = (obj, member, msg) => {
77
942
  if (!member.has(obj))
78
943
  throw TypeError("Cannot " + msg);
79
944
  };
80
- var __privateGet$2 = (obj, member, getter) => {
81
- __accessCheck$2(obj, member, "read from private field");
945
+ var __privateGet$3 = (obj, member, getter) => {
946
+ __accessCheck$3(obj, member, "read from private field");
82
947
  return getter ? getter.call(obj) : member.get(obj);
83
948
  };
84
- var __privateAdd$2 = (obj, member, value) => {
949
+ var __privateAdd$3 = (obj, member, value) => {
85
950
  if (member.has(obj))
86
951
  throw TypeError("Cannot add the same private member more than once");
87
952
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
88
953
  };
89
- var __privateSet$2 = (obj, member, value, setter) => {
90
- __accessCheck$2(obj, member, "write to private field");
954
+ var __privateSet$3 = (obj, member, value, setter) => {
955
+ __accessCheck$3(obj, member, "write to private field");
91
956
  setter ? setter.call(obj, value) : member.set(obj, value);
92
957
  return value;
93
958
  };
94
- var __privateMethod$1 = (obj, member, method) => {
95
- __accessCheck$2(obj, member, "access private method");
959
+ var __privateMethod$2 = (obj, member, method) => {
960
+ __accessCheck$3(obj, member, "access private method");
96
961
  return method;
97
962
  };
98
963
  var _started, _features, _registerInits, _extensionPoints, _serviceHolder, _getInitDeps, getInitDeps_fn, _resolveInitOrder, resolveInitOrder_fn;
99
964
  class BackendInitializer {
100
965
  constructor(serviceHolder) {
101
- __privateAdd$2(this, _getInitDeps);
102
- __privateAdd$2(this, _resolveInitOrder);
103
- __privateAdd$2(this, _started, false);
104
- __privateAdd$2(this, _features, /* @__PURE__ */ new Map());
105
- __privateAdd$2(this, _registerInits, new Array());
106
- __privateAdd$2(this, _extensionPoints, /* @__PURE__ */ new Map());
107
- __privateAdd$2(this, _serviceHolder, void 0);
108
- __privateSet$2(this, _serviceHolder, serviceHolder);
966
+ __privateAdd$3(this, _getInitDeps);
967
+ __privateAdd$3(this, _resolveInitOrder);
968
+ __privateAdd$3(this, _started, false);
969
+ __privateAdd$3(this, _features, /* @__PURE__ */ new Map());
970
+ __privateAdd$3(this, _registerInits, new Array());
971
+ __privateAdd$3(this, _extensionPoints, /* @__PURE__ */ new Map());
972
+ __privateAdd$3(this, _serviceHolder, void 0);
973
+ __privateSet$3(this, _serviceHolder, serviceHolder);
109
974
  }
110
975
  add(feature, options) {
111
- if (__privateGet$2(this, _started)) {
976
+ if (__privateGet$3(this, _started)) {
112
977
  throw new Error("feature can not be added after the backend has started");
113
978
  }
114
- __privateGet$2(this, _features).set(feature, options);
979
+ __privateGet$3(this, _features).set(feature, options);
115
980
  }
116
981
  async start() {
117
- if (__privateGet$2(this, _started)) {
982
+ if (__privateGet$3(this, _started)) {
118
983
  throw new Error("Backend has already started");
119
984
  }
120
- __privateSet$2(this, _started, true);
121
- for (const ref of __privateGet$2(this, _serviceHolder).getServiceRefs()) {
985
+ __privateSet$3(this, _started, true);
986
+ for (const ref of __privateGet$3(this, _serviceHolder).getServiceRefs()) {
122
987
  if (ref.scope === "root") {
123
- await __privateGet$2(this, _serviceHolder).get(ref, "root");
988
+ await __privateGet$3(this, _serviceHolder).get(ref, "root");
124
989
  }
125
990
  }
126
- for (const [feature] of __privateGet$2(this, _features)) {
991
+ for (const [feature] of __privateGet$3(this, _features)) {
127
992
  const provides = /* @__PURE__ */ new Set();
128
993
  let registerInit = void 0;
129
994
  feature.register({
@@ -131,10 +996,10 @@ class BackendInitializer {
131
996
  if (registerInit) {
132
997
  throw new Error("registerExtensionPoint called after registerInit");
133
998
  }
134
- if (__privateGet$2(this, _extensionPoints).has(extensionPointRef)) {
999
+ if (__privateGet$3(this, _extensionPoints).has(extensionPointRef)) {
135
1000
  throw new Error(`API ${extensionPointRef.id} already registered`);
136
1001
  }
137
- __privateGet$2(this, _extensionPoints).set(extensionPointRef, impl);
1002
+ __privateGet$3(this, _extensionPoints).set(extensionPointRef, impl);
138
1003
  provides.add(extensionPointRef);
139
1004
  },
140
1005
  registerInit: (registerOptions) => {
@@ -155,19 +1020,19 @@ class BackendInitializer {
155
1020
  `registerInit was not called by register in ${feature.id}`
156
1021
  );
157
1022
  }
158
- __privateGet$2(this, _registerInits).push(registerInit);
1023
+ __privateGet$3(this, _registerInits).push(registerInit);
159
1024
  }
160
- const orderedRegisterResults = __privateMethod$1(this, _resolveInitOrder, resolveInitOrder_fn).call(this, __privateGet$2(this, _registerInits));
1025
+ const orderedRegisterResults = __privateMethod$2(this, _resolveInitOrder, resolveInitOrder_fn).call(this, __privateGet$3(this, _registerInits));
161
1026
  for (const registerInit of orderedRegisterResults) {
162
- const deps = await __privateMethod$1(this, _getInitDeps, getInitDeps_fn).call(this, registerInit.deps, registerInit.id);
1027
+ const deps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, registerInit.deps, registerInit.id);
163
1028
  await registerInit.init(deps);
164
1029
  }
165
1030
  }
166
1031
  async stop() {
167
- if (!__privateGet$2(this, _started)) {
1032
+ if (!__privateGet$3(this, _started)) {
168
1033
  return;
169
1034
  }
170
- const lifecycleService = await __privateGet$2(this, _serviceHolder).get(
1035
+ const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
171
1036
  backendPluginApi.coreServices.rootLifecycle,
172
1037
  "root"
173
1038
  );
@@ -188,13 +1053,13 @@ getInitDeps_fn = async function(deps, pluginId) {
188
1053
  const result = /* @__PURE__ */ new Map();
189
1054
  const missingRefs = /* @__PURE__ */ new Set();
190
1055
  for (const [name, ref] of Object.entries(deps)) {
191
- const extensionPoint = __privateGet$2(this, _extensionPoints).get(
1056
+ const extensionPoint = __privateGet$3(this, _extensionPoints).get(
192
1057
  ref
193
1058
  );
194
1059
  if (extensionPoint) {
195
1060
  result.set(name, extensionPoint);
196
1061
  } else {
197
- const impl = await __privateGet$2(this, _serviceHolder).get(
1062
+ const impl = await __privateGet$3(this, _serviceHolder).get(
198
1063
  ref,
199
1064
  pluginId
200
1065
  );
@@ -238,59 +1103,51 @@ resolveInitOrder_fn = function(registerInits) {
238
1103
  return orderedRegisterInits;
239
1104
  };
240
1105
 
241
- var __accessCheck$1 = (obj, member, msg) => {
1106
+ var __accessCheck$2 = (obj, member, msg) => {
242
1107
  if (!member.has(obj))
243
1108
  throw TypeError("Cannot " + msg);
244
1109
  };
245
- var __privateGet$1 = (obj, member, getter) => {
246
- __accessCheck$1(obj, member, "read from private field");
1110
+ var __privateGet$2 = (obj, member, getter) => {
1111
+ __accessCheck$2(obj, member, "read from private field");
247
1112
  return getter ? getter.call(obj) : member.get(obj);
248
1113
  };
249
- var __privateAdd$1 = (obj, member, value) => {
1114
+ var __privateAdd$2 = (obj, member, value) => {
250
1115
  if (member.has(obj))
251
1116
  throw TypeError("Cannot add the same private member more than once");
252
1117
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
253
1118
  };
254
- var __privateSet$1 = (obj, member, value, setter) => {
255
- __accessCheck$1(obj, member, "write to private field");
1119
+ var __privateSet$2 = (obj, member, value, setter) => {
1120
+ __accessCheck$2(obj, member, "write to private field");
256
1121
  setter ? setter.call(obj, value) : member.set(obj, value);
257
1122
  return value;
258
1123
  };
259
- var __privateMethod = (obj, member, method) => {
260
- __accessCheck$1(obj, member, "access private method");
1124
+ var __privateMethod$1 = (obj, member, method) => {
1125
+ __accessCheck$2(obj, member, "access private method");
261
1126
  return method;
262
1127
  };
263
- var _providedFactories, _loadedDefaultFactories, _implementations, _resolveFactory, resolveFactory_fn, _separateMapForTheRootService, _checkForMissingDeps, checkForMissingDeps_fn;
1128
+ var _providedFactories, _loadedDefaultFactories, _implementations, _rootServiceImplementations, _resolveFactory, resolveFactory_fn, _checkForMissingDeps, checkForMissingDeps_fn;
264
1129
  class ServiceRegistry {
265
1130
  constructor(factories) {
266
- __privateAdd$1(this, _resolveFactory);
267
- __privateAdd$1(this, _checkForMissingDeps);
268
- __privateAdd$1(this, _providedFactories, void 0);
269
- __privateAdd$1(this, _loadedDefaultFactories, void 0);
270
- __privateAdd$1(this, _implementations, void 0);
271
- __privateAdd$1(this, _separateMapForTheRootService, /* @__PURE__ */ new Map());
272
- __privateSet$1(this, _providedFactories, new Map(
273
- factories.map((f) => {
274
- if (typeof f === "function") {
275
- const cf = f();
276
- return [cf.service.id, cf];
277
- }
278
- return [f.service.id, f];
279
- })
280
- ));
281
- __privateSet$1(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
282
- __privateSet$1(this, _implementations, /* @__PURE__ */ new Map());
1131
+ __privateAdd$2(this, _resolveFactory);
1132
+ __privateAdd$2(this, _checkForMissingDeps);
1133
+ __privateAdd$2(this, _providedFactories, void 0);
1134
+ __privateAdd$2(this, _loadedDefaultFactories, void 0);
1135
+ __privateAdd$2(this, _implementations, void 0);
1136
+ __privateAdd$2(this, _rootServiceImplementations, /* @__PURE__ */ new Map());
1137
+ __privateSet$2(this, _providedFactories, new Map(factories.map((f) => [f.service.id, f])));
1138
+ __privateSet$2(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
1139
+ __privateSet$2(this, _implementations, /* @__PURE__ */ new Map());
283
1140
  }
284
1141
  getServiceRefs() {
285
- return Array.from(__privateGet$1(this, _providedFactories).values()).map((f) => f.service);
1142
+ return Array.from(__privateGet$2(this, _providedFactories).values()).map((f) => f.service);
286
1143
  }
287
1144
  get(ref, pluginId) {
288
1145
  var _a;
289
- return (_a = __privateMethod(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
1146
+ return (_a = __privateMethod$1(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
290
1147
  if (factory.scope === "root") {
291
- let existing = __privateGet$1(this, _separateMapForTheRootService).get(factory);
1148
+ let existing = __privateGet$2(this, _rootServiceImplementations).get(factory);
292
1149
  if (!existing) {
293
- __privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1150
+ __privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
294
1151
  const rootDeps = new Array();
295
1152
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
296
1153
  if (serviceRef.scope !== "root") {
@@ -304,13 +1161,13 @@ class ServiceRegistry {
304
1161
  existing = Promise.all(rootDeps).then(
305
1162
  (entries) => factory.factory(Object.fromEntries(entries))
306
1163
  );
307
- __privateGet$1(this, _separateMapForTheRootService).set(factory, existing);
1164
+ __privateGet$2(this, _rootServiceImplementations).set(factory, existing);
308
1165
  }
309
1166
  return existing;
310
1167
  }
311
- let implementation = __privateGet$1(this, _implementations).get(factory);
1168
+ let implementation = __privateGet$2(this, _implementations).get(factory);
312
1169
  if (!implementation) {
313
- __privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1170
+ __privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
314
1171
  const rootDeps = new Array();
315
1172
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
316
1173
  if (serviceRef.scope === "root") {
@@ -319,15 +1176,20 @@ class ServiceRegistry {
319
1176
  }
320
1177
  }
321
1178
  implementation = {
322
- factoryFunc: Promise.all(rootDeps).then((entries) => factory.factory(Object.fromEntries(entries))).catch((error) => {
1179
+ context: Promise.all(rootDeps).then(
1180
+ (entries) => {
1181
+ var _a2;
1182
+ return (_a2 = factory.createRootContext) == null ? void 0 : _a2.call(factory, Object.fromEntries(entries));
1183
+ }
1184
+ ).catch((error) => {
323
1185
  const cause = errors.stringifyError(error);
324
1186
  throw new Error(
325
- `Failed to instantiate service '${ref.id}' because the top-level factory function threw an error, ${cause}`
1187
+ `Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`
326
1188
  );
327
1189
  }),
328
1190
  byPlugin: /* @__PURE__ */ new Map()
329
1191
  };
330
- __privateGet$1(this, _implementations).set(factory, implementation);
1192
+ __privateGet$2(this, _implementations).set(factory, implementation);
331
1193
  }
332
1194
  let result = implementation.byPlugin.get(pluginId);
333
1195
  if (!result) {
@@ -336,9 +1198,9 @@ class ServiceRegistry {
336
1198
  const target = this.get(serviceRef, pluginId);
337
1199
  allDeps.push(target.then((impl) => [name, impl]));
338
1200
  }
339
- result = implementation.factoryFunc.then(
340
- (func) => Promise.all(allDeps).then(
341
- (entries) => func(Object.fromEntries(entries))
1201
+ result = implementation.context.then(
1202
+ (context) => Promise.all(allDeps).then(
1203
+ (entries) => factory.factory(Object.fromEntries(entries), context)
342
1204
  )
343
1205
  ).catch((error) => {
344
1206
  const cause = errors.stringifyError(error);
@@ -355,6 +1217,7 @@ class ServiceRegistry {
355
1217
  _providedFactories = new WeakMap();
356
1218
  _loadedDefaultFactories = new WeakMap();
357
1219
  _implementations = new WeakMap();
1220
+ _rootServiceImplementations = new WeakMap();
358
1221
  _resolveFactory = new WeakSet();
359
1222
  resolveFactory_fn = function(ref, pluginId) {
360
1223
  if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
@@ -362,25 +1225,21 @@ resolveFactory_fn = function(ref, pluginId) {
362
1225
  scope: "plugin",
363
1226
  service: backendPluginApi.coreServices.pluginMetadata,
364
1227
  deps: {},
365
- factory: async () => async () => ({
366
- getId() {
367
- return pluginId;
368
- }
369
- })
1228
+ factory: async () => ({ getId: () => pluginId })
370
1229
  });
371
1230
  }
372
- let resolvedFactory = __privateGet$1(this, _providedFactories).get(ref.id);
1231
+ let resolvedFactory = __privateGet$2(this, _providedFactories).get(ref.id);
373
1232
  const { __defaultFactory: defaultFactory } = ref;
374
1233
  if (!resolvedFactory && !defaultFactory) {
375
1234
  return void 0;
376
1235
  }
377
1236
  if (!resolvedFactory) {
378
- let loadedFactory = __privateGet$1(this, _loadedDefaultFactories).get(defaultFactory);
1237
+ let loadedFactory = __privateGet$2(this, _loadedDefaultFactories).get(defaultFactory);
379
1238
  if (!loadedFactory) {
380
1239
  loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
381
1240
  (f) => typeof f === "function" ? f() : f
382
1241
  );
383
- __privateGet$1(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
1242
+ __privateGet$2(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
384
1243
  }
385
1244
  resolvedFactory = loadedFactory.catch((error) => {
386
1245
  throw new Error(
@@ -392,14 +1251,13 @@ resolveFactory_fn = function(ref, pluginId) {
392
1251
  }
393
1252
  return Promise.resolve(resolvedFactory);
394
1253
  };
395
- _separateMapForTheRootService = new WeakMap();
396
1254
  _checkForMissingDeps = new WeakSet();
397
1255
  checkForMissingDeps_fn = function(factory, pluginId) {
398
1256
  const missingDeps = Object.values(factory.deps).filter((ref) => {
399
1257
  if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
400
1258
  return false;
401
1259
  }
402
- if (__privateGet$1(this, _providedFactories).get(ref.id)) {
1260
+ if (__privateGet$2(this, _providedFactories).get(ref.id)) {
403
1261
  return false;
404
1262
  }
405
1263
  return !ref.__defaultFactory;
@@ -412,49 +1270,68 @@ checkForMissingDeps_fn = function(factory, pluginId) {
412
1270
  }
413
1271
  };
414
1272
 
415
- var __accessCheck = (obj, member, msg) => {
1273
+ var __accessCheck$1 = (obj, member, msg) => {
416
1274
  if (!member.has(obj))
417
1275
  throw TypeError("Cannot " + msg);
418
1276
  };
419
- var __privateGet = (obj, member, getter) => {
420
- __accessCheck(obj, member, "read from private field");
1277
+ var __privateGet$1 = (obj, member, getter) => {
1278
+ __accessCheck$1(obj, member, "read from private field");
421
1279
  return getter ? getter.call(obj) : member.get(obj);
422
1280
  };
423
- var __privateAdd = (obj, member, value) => {
1281
+ var __privateAdd$1 = (obj, member, value) => {
424
1282
  if (member.has(obj))
425
1283
  throw TypeError("Cannot add the same private member more than once");
426
1284
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
427
1285
  };
428
- var __privateSet = (obj, member, value, setter) => {
429
- __accessCheck(obj, member, "write to private field");
1286
+ var __privateSet$1 = (obj, member, value, setter) => {
1287
+ __accessCheck$1(obj, member, "write to private field");
430
1288
  setter ? setter.call(obj, value) : member.set(obj, value);
431
1289
  return value;
432
1290
  };
433
1291
  var _services, _initializer;
434
1292
  class BackstageBackend {
435
1293
  constructor(apiFactories) {
436
- __privateAdd(this, _services, void 0);
437
- __privateAdd(this, _initializer, void 0);
438
- __privateSet(this, _services, new ServiceRegistry(apiFactories));
439
- __privateSet(this, _initializer, new BackendInitializer(__privateGet(this, _services)));
1294
+ __privateAdd$1(this, _services, void 0);
1295
+ __privateAdd$1(this, _initializer, void 0);
1296
+ __privateSet$1(this, _services, new ServiceRegistry(apiFactories));
1297
+ __privateSet$1(this, _initializer, new BackendInitializer(__privateGet$1(this, _services)));
440
1298
  }
441
1299
  add(feature) {
442
- __privateGet(this, _initializer).add(feature);
1300
+ __privateGet$1(this, _initializer).add(feature);
443
1301
  }
444
1302
  async start() {
445
- await __privateGet(this, _initializer).start();
1303
+ await __privateGet$1(this, _initializer).start();
446
1304
  }
447
1305
  async stop() {
448
- await __privateGet(this, _initializer).stop();
1306
+ await __privateGet$1(this, _initializer).stop();
449
1307
  }
450
1308
  }
451
1309
  _services = new WeakMap();
452
1310
  _initializer = new WeakMap();
453
1311
 
454
1312
  function createSpecializedBackend(options) {
455
- return new BackstageBackend(
456
- options.services.map((s) => typeof s === "function" ? s() : s)
1313
+ const services = options.services.map(
1314
+ (sf) => typeof sf === "function" ? sf() : sf
457
1315
  );
1316
+ const exists = /* @__PURE__ */ new Set();
1317
+ const duplicates = /* @__PURE__ */ new Set();
1318
+ for (const { service } of services) {
1319
+ if (exists.has(service.id)) {
1320
+ duplicates.add(service.id);
1321
+ } else {
1322
+ exists.add(service.id);
1323
+ }
1324
+ }
1325
+ if (duplicates.size > 0) {
1326
+ const ids = Array.from(duplicates).join(", ");
1327
+ throw new Error(`Duplicate service implementations provided for ${ids}`);
1328
+ }
1329
+ if (exists.has(backendPluginApi.coreServices.pluginMetadata.id)) {
1330
+ throw new Error(
1331
+ `The ${backendPluginApi.coreServices.pluginMetadata.id} service cannot be overridden`
1332
+ );
1333
+ }
1334
+ return new BackstageBackend(services);
458
1335
  }
459
1336
 
460
1337
  const cacheFactory = backendPluginApi.createServiceFactory({
@@ -463,24 +1340,20 @@ const cacheFactory = backendPluginApi.createServiceFactory({
463
1340
  config: backendPluginApi.coreServices.config,
464
1341
  plugin: backendPluginApi.coreServices.pluginMetadata
465
1342
  },
466
- async factory({ config }) {
467
- const cacheManager = backendCommon.CacheManager.fromConfig(config);
468
- return async ({ plugin }) => {
469
- return cacheManager.forPlugin(plugin.getId());
470
- };
1343
+ async createRootContext({ config }) {
1344
+ return backendCommon.CacheManager.fromConfig(config);
1345
+ },
1346
+ async factory({ plugin }, manager) {
1347
+ return manager.forPlugin(plugin.getId());
471
1348
  }
472
1349
  });
473
1350
 
474
1351
  const configFactory = backendPluginApi.createServiceFactory({
475
1352
  service: backendPluginApi.coreServices.config,
476
- deps: {
477
- logger: backendPluginApi.coreServices.rootLogger
478
- },
479
- async factory({ logger }) {
480
- const config = await backendCommon.loadBackendConfig({
481
- argv: process.argv,
482
- logger: backendPluginApi.loggerToWinstonLogger(logger)
483
- });
1353
+ deps: {},
1354
+ async factory({}, options) {
1355
+ const { argv = process.argv, remote } = options != null ? options : {};
1356
+ const { config } = await loadBackendConfig({ argv, remote });
484
1357
  return config;
485
1358
  }
486
1359
  });
@@ -491,11 +1364,17 @@ const databaseFactory = backendPluginApi.createServiceFactory({
491
1364
  config: backendPluginApi.coreServices.config,
492
1365
  plugin: backendPluginApi.coreServices.pluginMetadata
493
1366
  },
494
- async factory({ config }) {
495
- const databaseManager = backendCommon.DatabaseManager.fromConfig(config);
496
- return async ({ plugin }) => {
497
- return databaseManager.forPlugin(plugin.getId());
498
- };
1367
+ async createRootContext({ config: config$1 }) {
1368
+ return config$1.getOptional("backend.database") ? backendCommon.DatabaseManager.fromConfig(config$1) : backendCommon.DatabaseManager.fromConfig(
1369
+ new config.ConfigReader({
1370
+ backend: {
1371
+ database: { client: "better-sqlite3", connection: ":memory:" }
1372
+ }
1373
+ })
1374
+ );
1375
+ },
1376
+ async factory({ plugin }, databaseManager) {
1377
+ return databaseManager.forPlugin(plugin.getId());
499
1378
  }
500
1379
  });
501
1380
 
@@ -505,9 +1384,59 @@ const discoveryFactory = backendPluginApi.createServiceFactory({
505
1384
  config: backendPluginApi.coreServices.config
506
1385
  },
507
1386
  async factory({ config }) {
508
- const discovery = backendCommon.SingleHostDiscovery.fromConfig(config);
509
- return async () => {
510
- return discovery;
1387
+ return backendCommon.SingleHostDiscovery.fromConfig(config);
1388
+ }
1389
+ });
1390
+
1391
+ const httpRouterFactory = backendPluginApi.createServiceFactory(
1392
+ (options) => ({
1393
+ service: backendPluginApi.coreServices.httpRouter,
1394
+ deps: {
1395
+ plugin: backendPluginApi.coreServices.pluginMetadata,
1396
+ rootHttpRouter: backendPluginApi.coreServices.rootHttpRouter
1397
+ },
1398
+ async factory({ plugin, rootHttpRouter }) {
1399
+ var _a;
1400
+ const getPath = (_a = options == null ? void 0 : options.getPath) != null ? _a : (id) => `/api/${id}`;
1401
+ const path = getPath(plugin.getId());
1402
+ return {
1403
+ use(handler) {
1404
+ rootHttpRouter.use(path, handler);
1405
+ }
1406
+ };
1407
+ }
1408
+ })
1409
+ );
1410
+
1411
+ const identityFactory = backendPluginApi.createServiceFactory(
1412
+ (options) => ({
1413
+ service: backendPluginApi.coreServices.identity,
1414
+ deps: {
1415
+ discovery: backendPluginApi.coreServices.discovery
1416
+ },
1417
+ async factory({ discovery }) {
1418
+ return pluginAuthNode.DefaultIdentityClient.create({ discovery, ...options });
1419
+ }
1420
+ })
1421
+ );
1422
+
1423
+ const lifecycleFactory = backendPluginApi.createServiceFactory({
1424
+ service: backendPluginApi.coreServices.lifecycle,
1425
+ deps: {
1426
+ logger: backendPluginApi.coreServices.logger,
1427
+ rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
1428
+ pluginMetadata: backendPluginApi.coreServices.pluginMetadata
1429
+ },
1430
+ async factory({ rootLifecycle, logger, pluginMetadata }) {
1431
+ const plugin = pluginMetadata.getId();
1432
+ return {
1433
+ addShutdownHook(options) {
1434
+ var _a, _b;
1435
+ rootLifecycle.addShutdownHook({
1436
+ ...options,
1437
+ logger: (_b = (_a = options.logger) == null ? void 0 : _a.child({ plugin })) != null ? _b : logger
1438
+ });
1439
+ }
511
1440
  };
512
1441
  }
513
1442
  });
@@ -518,72 +1447,207 @@ const loggerFactory = backendPluginApi.createServiceFactory({
518
1447
  rootLogger: backendPluginApi.coreServices.rootLogger,
519
1448
  plugin: backendPluginApi.coreServices.pluginMetadata
520
1449
  },
521
- async factory({ rootLogger }) {
522
- return async ({ plugin }) => {
523
- return rootLogger.child({ pluginId: plugin.getId() });
524
- };
1450
+ factory({ rootLogger, plugin }) {
1451
+ return rootLogger.child({ plugin: plugin.getId() });
525
1452
  }
526
1453
  });
527
1454
 
528
- class BackstageLogger {
529
- constructor(winston) {
530
- this.winston = winston;
531
- }
532
- static fromWinston(logger) {
533
- return new BackstageLogger(logger);
1455
+ const permissionsFactory = backendPluginApi.createServiceFactory({
1456
+ service: backendPluginApi.coreServices.permissions,
1457
+ deps: {
1458
+ config: backendPluginApi.coreServices.config,
1459
+ discovery: backendPluginApi.coreServices.discovery,
1460
+ tokenManager: backendPluginApi.coreServices.tokenManager
1461
+ },
1462
+ async factory({ config, discovery, tokenManager }) {
1463
+ return pluginPermissionNode.ServerPermissionClient.fromConfig(config, {
1464
+ discovery,
1465
+ tokenManager
1466
+ });
534
1467
  }
535
- error(message, meta) {
536
- this.winston.error(message, meta);
1468
+ });
1469
+
1470
+ var __accessCheck = (obj, member, msg) => {
1471
+ if (!member.has(obj))
1472
+ throw TypeError("Cannot " + msg);
1473
+ };
1474
+ var __privateGet = (obj, member, getter) => {
1475
+ __accessCheck(obj, member, "read from private field");
1476
+ return getter ? getter.call(obj) : member.get(obj);
1477
+ };
1478
+ var __privateAdd = (obj, member, value) => {
1479
+ if (member.has(obj))
1480
+ throw TypeError("Cannot add the same private member more than once");
1481
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1482
+ };
1483
+ var __privateSet = (obj, member, value, setter) => {
1484
+ __accessCheck(obj, member, "write to private field");
1485
+ setter ? setter.call(obj, value) : member.set(obj, value);
1486
+ return value;
1487
+ };
1488
+ var __privateMethod = (obj, member, method) => {
1489
+ __accessCheck(obj, member, "access private method");
1490
+ return method;
1491
+ };
1492
+ var _indexPath, _router, _namedRoutes, _indexRouter, _existingPaths, _findConflictingPath, findConflictingPath_fn;
1493
+ function normalizePath(path) {
1494
+ return `${trimEnd__default["default"](path, "/")}/`;
1495
+ }
1496
+ const _DefaultRootHttpRouter = class {
1497
+ constructor(indexPath) {
1498
+ __privateAdd(this, _findConflictingPath);
1499
+ __privateAdd(this, _indexPath, void 0);
1500
+ __privateAdd(this, _router, express.Router());
1501
+ __privateAdd(this, _namedRoutes, express.Router());
1502
+ __privateAdd(this, _indexRouter, express.Router());
1503
+ __privateAdd(this, _existingPaths, new Array());
1504
+ __privateSet(this, _indexPath, indexPath);
1505
+ __privateGet(this, _router).use(__privateGet(this, _namedRoutes));
1506
+ if (__privateGet(this, _indexPath)) {
1507
+ __privateGet(this, _router).use(__privateGet(this, _indexRouter));
1508
+ }
537
1509
  }
538
- warn(message, meta) {
539
- this.winston.warn(message, meta);
1510
+ static create(options) {
1511
+ let indexPath;
1512
+ if ((options == null ? void 0 : options.indexPath) === false) {
1513
+ indexPath = void 0;
1514
+ } else if ((options == null ? void 0 : options.indexPath) === void 0) {
1515
+ indexPath = "/api/app";
1516
+ } else if ((options == null ? void 0 : options.indexPath) === "") {
1517
+ throw new Error("indexPath option may not be an empty string");
1518
+ } else {
1519
+ indexPath = options.indexPath;
1520
+ }
1521
+ return new _DefaultRootHttpRouter(indexPath);
540
1522
  }
541
- info(message, meta) {
542
- this.winston.info(message, meta);
1523
+ use(path, handler) {
1524
+ if (path.match(/^[/\s]*$/)) {
1525
+ throw new Error(`Root router path may not be empty`);
1526
+ }
1527
+ const conflictingPath = __privateMethod(this, _findConflictingPath, findConflictingPath_fn).call(this, path);
1528
+ if (conflictingPath) {
1529
+ throw new Error(
1530
+ `Path ${path} conflicts with the existing path ${conflictingPath}`
1531
+ );
1532
+ }
1533
+ __privateGet(this, _existingPaths).push(path);
1534
+ __privateGet(this, _namedRoutes).use(path, handler);
1535
+ if (__privateGet(this, _indexPath) === path) {
1536
+ __privateGet(this, _indexRouter).use(handler);
1537
+ }
543
1538
  }
544
- debug(message, meta) {
545
- this.winston.debug(message, meta);
1539
+ handler() {
1540
+ return __privateGet(this, _router);
546
1541
  }
547
- child(meta) {
548
- return new BackstageLogger(this.winston.child(meta));
1542
+ };
1543
+ let DefaultRootHttpRouter = _DefaultRootHttpRouter;
1544
+ _indexPath = new WeakMap();
1545
+ _router = new WeakMap();
1546
+ _namedRoutes = new WeakMap();
1547
+ _indexRouter = new WeakMap();
1548
+ _existingPaths = new WeakMap();
1549
+ _findConflictingPath = new WeakSet();
1550
+ findConflictingPath_fn = function(newPath) {
1551
+ const normalizedNewPath = normalizePath(newPath);
1552
+ for (const path of __privateGet(this, _existingPaths)) {
1553
+ const normalizedPath = normalizePath(path);
1554
+ if (normalizedPath.startsWith(normalizedNewPath)) {
1555
+ return path;
1556
+ }
1557
+ if (normalizedNewPath.startsWith(normalizedPath)) {
1558
+ return path;
1559
+ }
549
1560
  }
1561
+ return void 0;
1562
+ };
1563
+
1564
+ function defaultConfigure({
1565
+ app,
1566
+ routes,
1567
+ middleware
1568
+ }) {
1569
+ app.use(middleware.helmet());
1570
+ app.use(middleware.cors());
1571
+ app.use(middleware.compression());
1572
+ app.use(middleware.logging());
1573
+ app.use(routes);
1574
+ app.use(middleware.notFound());
1575
+ app.use(middleware.error());
550
1576
  }
551
- const rootLoggerFactory = backendPluginApi.createServiceFactory({
552
- service: backendPluginApi.coreServices.rootLogger,
553
- deps: {},
554
- async factory() {
555
- return BackstageLogger.fromWinston(backendCommon.createRootLogger());
1577
+ const rootHttpRouterFactory = backendPluginApi.createServiceFactory({
1578
+ service: backendPluginApi.coreServices.rootHttpRouter,
1579
+ deps: {
1580
+ config: backendPluginApi.coreServices.config,
1581
+ rootLogger: backendPluginApi.coreServices.rootLogger,
1582
+ lifecycle: backendPluginApi.coreServices.rootLifecycle
1583
+ },
1584
+ async factory({ config, rootLogger, lifecycle }, {
1585
+ indexPath,
1586
+ configure = defaultConfigure
1587
+ } = {}) {
1588
+ const logger = rootLogger.child({ service: "rootHttpRouter" });
1589
+ const app = express__default["default"]();
1590
+ const router = DefaultRootHttpRouter.create({ indexPath });
1591
+ const middleware = MiddlewareFactory.create({ config, logger });
1592
+ configure({
1593
+ app,
1594
+ routes: router.handler(),
1595
+ middleware,
1596
+ config,
1597
+ logger,
1598
+ lifecycle
1599
+ });
1600
+ const server = await createHttpServer(
1601
+ app,
1602
+ readHttpServerOptions(config.getOptionalConfig("backend")),
1603
+ { logger }
1604
+ );
1605
+ lifecycle.addShutdownHook({
1606
+ async fn() {
1607
+ await server.stop();
1608
+ },
1609
+ logger
1610
+ });
1611
+ await server.start();
1612
+ return router;
556
1613
  }
557
1614
  });
558
1615
 
559
- const permissionsFactory = backendPluginApi.createServiceFactory({
560
- service: backendPluginApi.coreServices.permissions,
1616
+ const rootLoggerFactory = backendPluginApi.createServiceFactory({
1617
+ service: backendPluginApi.coreServices.rootLogger,
561
1618
  deps: {
562
- config: backendPluginApi.coreServices.config,
563
- discovery: backendPluginApi.coreServices.discovery,
564
- tokenManager: backendPluginApi.coreServices.tokenManager
1619
+ config: backendPluginApi.coreServices.config
565
1620
  },
566
1621
  async factory({ config }) {
567
- return async ({ discovery, tokenManager }) => {
568
- return pluginPermissionNode.ServerPermissionClient.fromConfig(config, {
569
- discovery,
570
- tokenManager
571
- });
572
- };
1622
+ var _a;
1623
+ const logger = WinstonLogger.create({
1624
+ meta: {
1625
+ service: "backstage"
1626
+ },
1627
+ level: process.env.LOG_LEVEL || "info",
1628
+ format: process.env.NODE_ENV === "production" ? winston.format.json() : WinstonLogger.colorFormat(),
1629
+ transports: [new winston.transports.Console()]
1630
+ });
1631
+ const secretEnumerator = await createConfigSecretEnumerator({ logger });
1632
+ logger.addRedactions(secretEnumerator(config));
1633
+ (_a = config.subscribe) == null ? void 0 : _a.call(config, () => logger.addRedactions(secretEnumerator(config)));
1634
+ return logger;
573
1635
  }
574
1636
  });
575
1637
 
576
1638
  const schedulerFactory = backendPluginApi.createServiceFactory({
577
1639
  service: backendPluginApi.coreServices.scheduler,
578
1640
  deps: {
579
- config: backendPluginApi.coreServices.config,
580
- plugin: backendPluginApi.coreServices.pluginMetadata
1641
+ plugin: backendPluginApi.coreServices.pluginMetadata,
1642
+ databaseManager: backendPluginApi.coreServices.database,
1643
+ logger: backendPluginApi.coreServices.logger
581
1644
  },
582
- async factory({ config }) {
583
- const taskScheduler = backendTasks.TaskScheduler.fromConfig(config);
584
- return async ({ plugin }) => {
585
- return taskScheduler.forPlugin(plugin.getId());
586
- };
1645
+ async factory({ plugin, databaseManager, logger }) {
1646
+ return backendTasks.TaskScheduler.forPlugin({
1647
+ pluginId: plugin.getId(),
1648
+ databaseManager,
1649
+ logger: backendCommon.loggerToWinstonLogger(logger)
1650
+ });
587
1651
  }
588
1652
  });
589
1653
 
@@ -591,14 +1655,15 @@ const tokenManagerFactory = backendPluginApi.createServiceFactory({
591
1655
  service: backendPluginApi.coreServices.tokenManager,
592
1656
  deps: {
593
1657
  config: backendPluginApi.coreServices.config,
594
- logger: backendPluginApi.coreServices.logger
1658
+ logger: backendPluginApi.coreServices.rootLogger
595
1659
  },
596
- async factory() {
597
- return async ({ config, logger }) => {
598
- return backendCommon.ServerTokenManager.fromConfig(config, {
599
- logger: backendPluginApi.loggerToWinstonLogger(logger)
600
- });
601
- };
1660
+ createRootContext({ config, logger }) {
1661
+ return backendCommon.ServerTokenManager.fromConfig(config, {
1662
+ logger
1663
+ });
1664
+ },
1665
+ async factory(_deps, tokenManager) {
1666
+ return tokenManager;
602
1667
  }
603
1668
  });
604
1669
 
@@ -608,74 +1673,34 @@ const urlReaderFactory = backendPluginApi.createServiceFactory({
608
1673
  config: backendPluginApi.coreServices.config,
609
1674
  logger: backendPluginApi.coreServices.logger
610
1675
  },
611
- async factory() {
612
- return async ({ config, logger }) => {
613
- return backendCommon.UrlReaders.default({
614
- config,
615
- logger: backendPluginApi.loggerToWinstonLogger(logger)
616
- });
617
- };
618
- }
619
- });
620
-
621
- const httpRouterFactory = backendPluginApi.createServiceFactory({
622
- service: backendPluginApi.coreServices.httpRouter,
623
- deps: {
624
- config: backendPluginApi.coreServices.config,
625
- plugin: backendPluginApi.coreServices.pluginMetadata
626
- },
627
- async factory({ config }, options) {
628
- var _a;
629
- const defaultPluginId = (_a = options == null ? void 0 : options.indexPlugin) != null ? _a : "app";
630
- const apiRouter = Router__default["default"]();
631
- const rootRouter = Router__default["default"]();
632
- const service = backendCommon.createServiceBuilder(module).loadConfig(config).addRouter("/api", apiRouter).addRouter("", rootRouter);
633
- await service.start();
634
- return async ({ plugin }) => {
635
- const pluginId = plugin.getId();
636
- return {
637
- use(handler) {
638
- if (pluginId === defaultPluginId) {
639
- rootRouter.use(handler);
640
- } else {
641
- apiRouter.use(`/${pluginId}`, handler);
642
- }
643
- }
644
- };
645
- };
646
- }
647
- });
648
-
649
- const lifecycleFactory = backendPluginApi.createServiceFactory({
650
- service: backendPluginApi.coreServices.lifecycle,
651
- deps: {
652
- rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
653
- pluginMetadata: backendPluginApi.coreServices.pluginMetadata
654
- },
655
- async factory({ rootLifecycle }) {
656
- return async ({ pluginMetadata }) => {
657
- const plugin = pluginMetadata.getId();
658
- return {
659
- addShutdownHook(options) {
660
- rootLifecycle.addShutdownHook({
661
- ...options,
662
- labels: { ...options == null ? void 0 : options.labels, plugin }
663
- });
664
- }
665
- };
666
- };
1676
+ async factory({ config, logger }) {
1677
+ return backendCommon.UrlReaders.default({
1678
+ config,
1679
+ logger: backendCommon.loggerToWinstonLogger(logger)
1680
+ });
667
1681
  }
668
1682
  });
669
1683
 
1684
+ exports.DefaultRootHttpRouter = DefaultRootHttpRouter;
1685
+ exports.MiddlewareFactory = MiddlewareFactory;
1686
+ exports.WinstonLogger = WinstonLogger;
670
1687
  exports.cacheFactory = cacheFactory;
671
1688
  exports.configFactory = configFactory;
1689
+ exports.createConfigSecretEnumerator = createConfigSecretEnumerator;
1690
+ exports.createHttpServer = createHttpServer;
672
1691
  exports.createSpecializedBackend = createSpecializedBackend;
673
1692
  exports.databaseFactory = databaseFactory;
674
1693
  exports.discoveryFactory = discoveryFactory;
675
1694
  exports.httpRouterFactory = httpRouterFactory;
1695
+ exports.identityFactory = identityFactory;
676
1696
  exports.lifecycleFactory = lifecycleFactory;
1697
+ exports.loadBackendConfig = loadBackendConfig;
677
1698
  exports.loggerFactory = loggerFactory;
678
1699
  exports.permissionsFactory = permissionsFactory;
1700
+ exports.readCorsOptions = readCorsOptions;
1701
+ exports.readHelmetOptions = readHelmetOptions;
1702
+ exports.readHttpServerOptions = readHttpServerOptions;
1703
+ exports.rootHttpRouterFactory = rootHttpRouterFactory;
679
1704
  exports.rootLifecycleFactory = rootLifecycleFactory;
680
1705
  exports.rootLoggerFactory = rootLoggerFactory;
681
1706
  exports.schedulerFactory = schedulerFactory;