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

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

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,575 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var backendPluginApi = require('@backstage/backend-plugin-api');
5
+ var http = require('http');
6
+ var https = require('https');
7
+ var stoppableServer = require('stoppable');
8
+ var fs = require('fs-extra');
9
+ var path = require('path');
10
+ var forge = require('node-forge');
11
+ var cors = require('cors');
12
+ var helmet = require('helmet');
13
+ var morgan = require('morgan');
14
+ var compression = require('compression');
15
+ var minimatch = require('minimatch');
6
16
  var errors = require('@backstage/errors');
17
+ var backendPluginApi = require('@backstage/backend-plugin-api');
18
+ var express = require('express');
7
19
  var backendCommon = require('@backstage/backend-common');
8
20
  var pluginPermissionNode = require('@backstage/plugin-permission-node');
9
21
  var backendTasks = require('@backstage/backend-tasks');
10
- var Router = require('express-promise-router');
11
22
 
12
23
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
24
 
14
- var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
25
+ function _interopNamespace(e) {
26
+ if (e && e.__esModule) return e;
27
+ var n = Object.create(null);
28
+ if (e) {
29
+ Object.keys(e).forEach(function (k) {
30
+ if (k !== 'default') {
31
+ var d = Object.getOwnPropertyDescriptor(e, k);
32
+ Object.defineProperty(n, k, d.get ? d : {
33
+ enumerable: true,
34
+ get: function () { return e[k]; }
35
+ });
36
+ }
37
+ });
38
+ }
39
+ n["default"] = e;
40
+ return Object.freeze(n);
41
+ }
15
42
 
16
- var __accessCheck$3 = (obj, member, msg) => {
43
+ var http__namespace = /*#__PURE__*/_interopNamespace(http);
44
+ var https__namespace = /*#__PURE__*/_interopNamespace(https);
45
+ var stoppableServer__default = /*#__PURE__*/_interopDefaultLegacy(stoppableServer);
46
+ var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
47
+ var forge__default = /*#__PURE__*/_interopDefaultLegacy(forge);
48
+ var cors__default = /*#__PURE__*/_interopDefaultLegacy(cors);
49
+ var helmet__default = /*#__PURE__*/_interopDefaultLegacy(helmet);
50
+ var morgan__default = /*#__PURE__*/_interopDefaultLegacy(morgan);
51
+ var compression__default = /*#__PURE__*/_interopDefaultLegacy(compression);
52
+ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
53
+
54
+ const DEFAULT_PORT = 7007;
55
+ const DEFAULT_HOST = "";
56
+ function readHttpServerOptions(config) {
57
+ return {
58
+ listen: readHttpListenOptions(config),
59
+ https: readHttpsOptions(config)
60
+ };
61
+ }
62
+ function readHttpListenOptions(config) {
63
+ var _a, _b;
64
+ const listen = config == null ? void 0 : config.getOptional("listen");
65
+ if (typeof listen === "string") {
66
+ const parts = String(listen).split(":");
67
+ const port = parseInt(parts[parts.length - 1], 10);
68
+ if (!isNaN(port)) {
69
+ if (parts.length === 1) {
70
+ return { port, host: DEFAULT_HOST };
71
+ }
72
+ if (parts.length === 2) {
73
+ return { host: parts[0], port };
74
+ }
75
+ }
76
+ throw new Error(
77
+ `Unable to parse listen address ${listen}, expected <port> or <host>:<port>`
78
+ );
79
+ }
80
+ const host = (_a = config == null ? void 0 : config.getOptional("listen.host")) != null ? _a : DEFAULT_HOST;
81
+ if (typeof host !== "string") {
82
+ config == null ? void 0 : config.getOptionalString("listen.host");
83
+ throw new Error("unreachable");
84
+ }
85
+ return {
86
+ port: (_b = config == null ? void 0 : config.getOptionalNumber("listen.port")) != null ? _b : DEFAULT_PORT,
87
+ host
88
+ };
89
+ }
90
+ function readHttpsOptions(config) {
91
+ const https = config == null ? void 0 : config.getOptional("https");
92
+ if (https === true) {
93
+ const baseUrl = config.getString("baseUrl");
94
+ let hostname;
95
+ try {
96
+ hostname = new URL(baseUrl).hostname;
97
+ } catch (error) {
98
+ throw new Error(`Invalid baseUrl "${baseUrl}"`);
99
+ }
100
+ return { certificate: { type: "generated", hostname } };
101
+ }
102
+ const cc = config == null ? void 0 : config.getOptionalConfig("https");
103
+ if (!cc) {
104
+ return void 0;
105
+ }
106
+ return {
107
+ certificate: {
108
+ type: "plain",
109
+ cert: cc.getString("certificate.cert"),
110
+ key: cc.getString("certificate.key")
111
+ }
112
+ };
113
+ }
114
+
115
+ const FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1e3;
116
+ const IP_HOSTNAME_REGEX = /:|^\d+\.\d+\.\d+\.\d+$/;
117
+ async function getGeneratedCertificate(hostname, logger) {
118
+ const hasModules = await fs__default["default"].pathExists("node_modules");
119
+ let certPath;
120
+ if (hasModules) {
121
+ certPath = path.resolve(
122
+ "node_modules/.cache/backstage-backend/dev-cert.pem"
123
+ );
124
+ await fs__default["default"].ensureDir(path.dirname(certPath));
125
+ } else {
126
+ certPath = path.resolve(".dev-cert.pem");
127
+ }
128
+ if (await fs__default["default"].pathExists(certPath)) {
129
+ try {
130
+ const cert = await fs__default["default"].readFile(certPath);
131
+ const crt = forge__default["default"].pki.certificateFromPem(cert.toString());
132
+ const remainingMs = crt.validity.notAfter.getTime() - Date.now();
133
+ if (remainingMs > FIVE_DAYS_IN_MS) {
134
+ logger.info("Using existing self-signed certificate");
135
+ return {
136
+ key: cert,
137
+ cert
138
+ };
139
+ }
140
+ } catch (error) {
141
+ logger.warn(`Unable to use existing self-signed certificate, ${error}`);
142
+ }
143
+ }
144
+ logger.info("Generating new self-signed certificate");
145
+ const newCert = await generateCertificate(hostname);
146
+ await fs__default["default"].writeFile(certPath, newCert.cert + newCert.key, "utf8");
147
+ return newCert;
148
+ }
149
+ async function generateCertificate(hostname) {
150
+ const attributes = [
151
+ {
152
+ name: "commonName",
153
+ value: "dev-cert"
154
+ }
155
+ ];
156
+ const sans = [
157
+ {
158
+ type: 2,
159
+ // DNS
160
+ value: "localhost"
161
+ },
162
+ {
163
+ type: 2,
164
+ value: "localhost.localdomain"
165
+ },
166
+ {
167
+ type: 2,
168
+ value: "[::1]"
169
+ },
170
+ {
171
+ type: 7,
172
+ // IP
173
+ ip: "127.0.0.1"
174
+ },
175
+ {
176
+ type: 7,
177
+ ip: "fe80::1"
178
+ }
179
+ ];
180
+ if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {
181
+ sans.push(
182
+ IP_HOSTNAME_REGEX.test(hostname) ? {
183
+ type: 7,
184
+ ip: hostname
185
+ } : {
186
+ type: 2,
187
+ value: hostname
188
+ }
189
+ );
190
+ }
191
+ const params = {
192
+ algorithm: "sha256",
193
+ keySize: 2048,
194
+ days: 30,
195
+ extensions: [
196
+ {
197
+ name: "keyUsage",
198
+ keyCertSign: true,
199
+ digitalSignature: true,
200
+ nonRepudiation: true,
201
+ keyEncipherment: true,
202
+ dataEncipherment: true
203
+ },
204
+ {
205
+ name: "extKeyUsage",
206
+ serverAuth: true,
207
+ clientAuth: true,
208
+ codeSigning: true,
209
+ timeStamping: true
210
+ },
211
+ {
212
+ name: "subjectAltName",
213
+ altNames: sans
214
+ }
215
+ ]
216
+ };
217
+ return new Promise(
218
+ (resolve, reject) => require("selfsigned").generate(
219
+ attributes,
220
+ params,
221
+ (err, bundle) => {
222
+ if (err) {
223
+ reject(err);
224
+ } else {
225
+ resolve({ key: bundle.private, cert: bundle.cert });
226
+ }
227
+ }
228
+ )
229
+ );
230
+ }
231
+
232
+ async function createHttpServer(listener, options, deps) {
233
+ const server = await createServer(listener, options, deps);
234
+ const stopper = stoppableServer__default["default"](server, 0);
235
+ const stopServer = stopper.stop.bind(stopper);
236
+ return Object.assign(server, {
237
+ start() {
238
+ return new Promise((resolve, reject) => {
239
+ const handleStartupError = (error) => {
240
+ server.close();
241
+ reject(error);
242
+ };
243
+ server.on("error", handleStartupError);
244
+ const { host, port } = options.listen;
245
+ server.listen(port, host, () => {
246
+ server.off("error", handleStartupError);
247
+ deps.logger.info(`Listening on ${host}:${port}`);
248
+ resolve();
249
+ });
250
+ });
251
+ },
252
+ stop() {
253
+ return new Promise((resolve, reject) => {
254
+ stopServer((error) => {
255
+ if (error) {
256
+ reject(error);
257
+ } else {
258
+ resolve();
259
+ }
260
+ });
261
+ });
262
+ },
263
+ port() {
264
+ const address = server.address();
265
+ if (typeof address === "string" || address === null) {
266
+ throw new Error(`Unexpected server address '${address}'`);
267
+ }
268
+ return address.port;
269
+ }
270
+ });
271
+ }
272
+ async function createServer(listener, options, deps) {
273
+ if (options.https) {
274
+ const { certificate } = options.https;
275
+ if (certificate.type === "generated") {
276
+ const credentials = await getGeneratedCertificate(
277
+ certificate.hostname,
278
+ deps.logger
279
+ );
280
+ return https__namespace.createServer(credentials, listener);
281
+ }
282
+ return https__namespace.createServer(certificate, listener);
283
+ }
284
+ return http__namespace.createServer(listener);
285
+ }
286
+
287
+ function readHelmetOptions(config) {
288
+ const cspOptions = readCspDirectives(config);
289
+ return {
290
+ contentSecurityPolicy: {
291
+ useDefaults: false,
292
+ directives: applyCspDirectives(cspOptions)
293
+ },
294
+ // These are all disabled in order to maintain backwards compatibility
295
+ // when bumping helmet v5. We can't enable these by default because
296
+ // there is no way for users to configure them.
297
+ // TODO(Rugvip): We should give control of this setup to consumers
298
+ crossOriginEmbedderPolicy: false,
299
+ crossOriginOpenerPolicy: false,
300
+ crossOriginResourcePolicy: false,
301
+ originAgentCluster: false
302
+ };
303
+ }
304
+ function readCspDirectives(config) {
305
+ const cc = config == null ? void 0 : config.getOptionalConfig("csp");
306
+ if (!cc) {
307
+ return void 0;
308
+ }
309
+ const result = {};
310
+ for (const key of cc.keys()) {
311
+ if (cc.get(key) === false) {
312
+ result[key] = false;
313
+ } else {
314
+ result[key] = cc.getStringArray(key);
315
+ }
316
+ }
317
+ return result;
318
+ }
319
+ function applyCspDirectives(directives) {
320
+ const result = helmet__default["default"].contentSecurityPolicy.getDefaultDirectives();
321
+ result["script-src"] = ["'self'", "'unsafe-eval'"];
322
+ delete result["form-action"];
323
+ if (directives) {
324
+ for (const [key, value] of Object.entries(directives)) {
325
+ if (value === false) {
326
+ delete result[key];
327
+ } else {
328
+ result[key] = value;
329
+ }
330
+ }
331
+ }
332
+ return result;
333
+ }
334
+
335
+ function readCorsOptions(config) {
336
+ const cc = config == null ? void 0 : config.getOptionalConfig("cors");
337
+ if (!cc) {
338
+ return { origin: false };
339
+ }
340
+ return {
341
+ origin: createCorsOriginMatcher(readStringArray(cc, "origin")),
342
+ methods: readStringArray(cc, "methods"),
343
+ allowedHeaders: readStringArray(cc, "allowedHeaders"),
344
+ exposedHeaders: readStringArray(cc, "exposedHeaders"),
345
+ credentials: cc.getOptionalBoolean("credentials"),
346
+ maxAge: cc.getOptionalNumber("maxAge"),
347
+ preflightContinue: cc.getOptionalBoolean("preflightContinue"),
348
+ optionsSuccessStatus: cc.getOptionalNumber("optionsSuccessStatus")
349
+ };
350
+ }
351
+ function readStringArray(config, key) {
352
+ const value = config.getOptional(key);
353
+ if (typeof value === "string") {
354
+ return [value];
355
+ } else if (!value) {
356
+ return void 0;
357
+ }
358
+ return config.getStringArray(key);
359
+ }
360
+ function createCorsOriginMatcher(allowedOriginPatterns) {
361
+ if (!allowedOriginPatterns) {
362
+ return void 0;
363
+ }
364
+ const allowedOriginMatchers = allowedOriginPatterns.map(
365
+ (pattern) => new minimatch.Minimatch(pattern, { nocase: true, noglobstar: true })
366
+ );
367
+ return (origin, callback) => {
368
+ return callback(
369
+ null,
370
+ allowedOriginMatchers.some((pattern) => pattern.match(origin != null ? origin : ""))
371
+ );
372
+ };
373
+ }
374
+
375
+ var __accessCheck$5 = (obj, member, msg) => {
17
376
  if (!member.has(obj))
18
377
  throw TypeError("Cannot " + msg);
19
378
  };
20
- var __privateGet$3 = (obj, member, getter) => {
21
- __accessCheck$3(obj, member, "read from private field");
379
+ var __privateGet$5 = (obj, member, getter) => {
380
+ __accessCheck$5(obj, member, "read from private field");
22
381
  return getter ? getter.call(obj) : member.get(obj);
23
382
  };
24
- var __privateAdd$3 = (obj, member, value) => {
383
+ var __privateAdd$5 = (obj, member, value) => {
25
384
  if (member.has(obj))
26
385
  throw TypeError("Cannot add the same private member more than once");
27
386
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
28
387
  };
29
- var __privateSet$3 = (obj, member, value, setter) => {
30
- __accessCheck$3(obj, member, "write to private field");
388
+ var __privateSet$5 = (obj, member, value, setter) => {
389
+ __accessCheck$5(obj, member, "write to private field");
390
+ setter ? setter.call(obj, value) : member.set(obj, value);
391
+ return value;
392
+ };
393
+ var _config, _logger;
394
+ const _MiddlewareFactory = class {
395
+ constructor(options) {
396
+ __privateAdd$5(this, _config, void 0);
397
+ __privateAdd$5(this, _logger, void 0);
398
+ __privateSet$5(this, _config, options.config);
399
+ __privateSet$5(this, _logger, options.logger);
400
+ }
401
+ /**
402
+ * Creates a new {@link MiddlewareFactory}.
403
+ */
404
+ static create(options) {
405
+ return new _MiddlewareFactory(options);
406
+ }
407
+ /**
408
+ * Returns a middleware that unconditionally produces a 404 error response.
409
+ *
410
+ * @remarks
411
+ *
412
+ * Typically you want to place this middleware at the end of the chain, such
413
+ * that it's the last one attempted after no other routes matched.
414
+ *
415
+ * @returns An Express request handler
416
+ */
417
+ notFound() {
418
+ return (_req, res) => {
419
+ res.status(404).end();
420
+ };
421
+ }
422
+ /**
423
+ * Returns the compression middleware.
424
+ *
425
+ * @remarks
426
+ *
427
+ * The middleware will attempt to compress response bodies for all requests
428
+ * that traverse through the middleware.
429
+ */
430
+ compression() {
431
+ return compression__default["default"]();
432
+ }
433
+ /**
434
+ * Returns a request logging middleware.
435
+ *
436
+ * @remarks
437
+ *
438
+ * Typically you want to place this middleware at the start of the chain, such
439
+ * that it always logs requests whether they are "caught" by handlers farther
440
+ * down or not.
441
+ *
442
+ * @returns An Express request handler
443
+ */
444
+ logging() {
445
+ const logger = __privateGet$5(this, _logger).child({
446
+ type: "incomingRequest"
447
+ });
448
+ return morgan__default["default"]("combined", {
449
+ stream: {
450
+ write(message) {
451
+ logger.info(message.trimEnd());
452
+ }
453
+ }
454
+ });
455
+ }
456
+ /**
457
+ * Returns a middleware that implements the helmet library.
458
+ *
459
+ * @remarks
460
+ *
461
+ * This middleware applies security policies to incoming requests and outgoing
462
+ * responses. It is configured using config keys such as `backend.csp`.
463
+ *
464
+ * @see {@link https://helmetjs.github.io/}
465
+ *
466
+ * @returns An Express request handler
467
+ */
468
+ helmet() {
469
+ return helmet__default["default"](readHelmetOptions(__privateGet$5(this, _config).getOptionalConfig("backend")));
470
+ }
471
+ /**
472
+ * Returns a middleware that implements the cors library.
473
+ *
474
+ * @remarks
475
+ *
476
+ * This middleware handles CORS. It is configured using the config key
477
+ * `backend.cors`.
478
+ *
479
+ * @see {@link https://github.com/expressjs/cors}
480
+ *
481
+ * @returns An Express request handler
482
+ */
483
+ cors() {
484
+ return cors__default["default"](readCorsOptions(__privateGet$5(this, _config).getOptionalConfig("backend")));
485
+ }
486
+ /**
487
+ * Express middleware to handle errors during request processing.
488
+ *
489
+ * @remarks
490
+ *
491
+ * This is commonly the very last middleware in the chain.
492
+ *
493
+ * Its primary purpose is not to do translation of business logic exceptions,
494
+ * but rather to be a global catch-all for uncaught "fatal" errors that are
495
+ * expected to result in a 500 error. However, it also does handle some common
496
+ * error types (such as http-error exceptions, and the well-known error types
497
+ * in the `@backstage/errors` package) and returns the enclosed status code
498
+ * accordingly.
499
+ *
500
+ * It will also produce a response body with a serialized form of the error,
501
+ * unless a previous handler already did send a body. See
502
+ * {@link @backstage/errors#ErrorResponseBody} for the response shape used.
503
+ *
504
+ * @returns An Express error request handler
505
+ */
506
+ error(options = {}) {
507
+ var _a;
508
+ const showStackTraces = (_a = options.showStackTraces) != null ? _a : process.env.NODE_ENV === "development";
509
+ const logger = __privateGet$5(this, _logger).child({
510
+ type: "errorHandler"
511
+ });
512
+ return (error, req, res, next) => {
513
+ const statusCode = getStatusCode(error);
514
+ if (options.logAllErrors || statusCode >= 500) {
515
+ logger.error(`Request failed with status ${statusCode}`, error);
516
+ }
517
+ if (res.headersSent) {
518
+ next(error);
519
+ return;
520
+ }
521
+ const body = {
522
+ error: errors.serializeError(error, { includeStack: showStackTraces }),
523
+ request: { method: req.method, url: req.url },
524
+ response: { statusCode }
525
+ };
526
+ res.status(statusCode).json(body);
527
+ };
528
+ }
529
+ };
530
+ let MiddlewareFactory = _MiddlewareFactory;
531
+ _config = new WeakMap();
532
+ _logger = new WeakMap();
533
+ function getStatusCode(error) {
534
+ const knownStatusCodeFields = ["statusCode", "status"];
535
+ for (const field of knownStatusCodeFields) {
536
+ const statusCode = error[field];
537
+ if (typeof statusCode === "number" && (statusCode | 0) === statusCode && // is whole integer
538
+ statusCode >= 100 && statusCode <= 599) {
539
+ return statusCode;
540
+ }
541
+ }
542
+ switch (error.name) {
543
+ case errors.NotModifiedError.name:
544
+ return 304;
545
+ case errors.InputError.name:
546
+ return 400;
547
+ case errors.AuthenticationError.name:
548
+ return 401;
549
+ case errors.NotAllowedError.name:
550
+ return 403;
551
+ case errors.NotFoundError.name:
552
+ return 404;
553
+ case errors.ConflictError.name:
554
+ return 409;
555
+ }
556
+ return 500;
557
+ }
558
+
559
+ var __accessCheck$4 = (obj, member, msg) => {
560
+ if (!member.has(obj))
561
+ throw TypeError("Cannot " + msg);
562
+ };
563
+ var __privateGet$4 = (obj, member, getter) => {
564
+ __accessCheck$4(obj, member, "read from private field");
565
+ return getter ? getter.call(obj) : member.get(obj);
566
+ };
567
+ var __privateAdd$4 = (obj, member, value) => {
568
+ if (member.has(obj))
569
+ throw TypeError("Cannot add the same private member more than once");
570
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
571
+ };
572
+ var __privateSet$4 = (obj, member, value, setter) => {
573
+ __accessCheck$4(obj, member, "write to private field");
31
574
  setter ? setter.call(obj, value) : member.set(obj, value);
32
575
  return value;
33
576
  };
@@ -36,26 +579,27 @@ const CALLBACKS = ["SIGTERM", "SIGINT", "beforeExit"];
36
579
  class BackendLifecycleImpl {
37
580
  constructor(logger) {
38
581
  this.logger = logger;
39
- __privateAdd$3(this, _isCalled, false);
40
- __privateAdd$3(this, _shutdownTasks, []);
582
+ __privateAdd$4(this, _isCalled, false);
583
+ __privateAdd$4(this, _shutdownTasks, []);
41
584
  CALLBACKS.map((signal) => process.on(signal, () => this.shutdown()));
42
585
  }
43
586
  addShutdownHook(options) {
44
- __privateGet$3(this, _shutdownTasks).push(options);
587
+ __privateGet$4(this, _shutdownTasks).push(options);
45
588
  }
46
589
  async shutdown() {
47
- if (__privateGet$3(this, _isCalled)) {
590
+ if (__privateGet$4(this, _isCalled)) {
48
591
  return;
49
592
  }
50
- __privateSet$3(this, _isCalled, true);
51
- this.logger.info(`Running ${__privateGet$3(this, _shutdownTasks).length} shutdown tasks...`);
593
+ __privateSet$4(this, _isCalled, true);
594
+ this.logger.info(`Running ${__privateGet$4(this, _shutdownTasks).length} shutdown tasks...`);
52
595
  await Promise.all(
53
- __privateGet$3(this, _shutdownTasks).map(async (hook) => {
596
+ __privateGet$4(this, _shutdownTasks).map(async (hook) => {
597
+ const { logger = this.logger } = hook;
54
598
  try {
55
599
  await hook.fn();
56
- this.logger.info(`Shutdown hook succeeded`, hook.labels);
600
+ logger.info(`Shutdown hook succeeded`);
57
601
  } catch (error) {
58
- this.logger.error(`Shutdown hook failed, ${error}`, hook.labels);
602
+ logger.error(`Shutdown hook failed, ${error}`);
59
603
  }
60
604
  })
61
605
  );
@@ -69,61 +613,61 @@ const rootLifecycleFactory = backendPluginApi.createServiceFactory({
69
613
  logger: backendPluginApi.coreServices.rootLogger
70
614
  },
71
615
  async factory({ logger }) {
72
- return new BackendLifecycleImpl(backendPluginApi.loggerToWinstonLogger(logger));
616
+ return new BackendLifecycleImpl(logger);
73
617
  }
74
618
  });
75
619
 
76
- var __accessCheck$2 = (obj, member, msg) => {
620
+ var __accessCheck$3 = (obj, member, msg) => {
77
621
  if (!member.has(obj))
78
622
  throw TypeError("Cannot " + msg);
79
623
  };
80
- var __privateGet$2 = (obj, member, getter) => {
81
- __accessCheck$2(obj, member, "read from private field");
624
+ var __privateGet$3 = (obj, member, getter) => {
625
+ __accessCheck$3(obj, member, "read from private field");
82
626
  return getter ? getter.call(obj) : member.get(obj);
83
627
  };
84
- var __privateAdd$2 = (obj, member, value) => {
628
+ var __privateAdd$3 = (obj, member, value) => {
85
629
  if (member.has(obj))
86
630
  throw TypeError("Cannot add the same private member more than once");
87
631
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
88
632
  };
89
- var __privateSet$2 = (obj, member, value, setter) => {
90
- __accessCheck$2(obj, member, "write to private field");
633
+ var __privateSet$3 = (obj, member, value, setter) => {
634
+ __accessCheck$3(obj, member, "write to private field");
91
635
  setter ? setter.call(obj, value) : member.set(obj, value);
92
636
  return value;
93
637
  };
94
- var __privateMethod$1 = (obj, member, method) => {
95
- __accessCheck$2(obj, member, "access private method");
638
+ var __privateMethod$2 = (obj, member, method) => {
639
+ __accessCheck$3(obj, member, "access private method");
96
640
  return method;
97
641
  };
98
642
  var _started, _features, _registerInits, _extensionPoints, _serviceHolder, _getInitDeps, getInitDeps_fn, _resolveInitOrder, resolveInitOrder_fn;
99
643
  class BackendInitializer {
100
644
  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);
645
+ __privateAdd$3(this, _getInitDeps);
646
+ __privateAdd$3(this, _resolveInitOrder);
647
+ __privateAdd$3(this, _started, false);
648
+ __privateAdd$3(this, _features, /* @__PURE__ */ new Map());
649
+ __privateAdd$3(this, _registerInits, new Array());
650
+ __privateAdd$3(this, _extensionPoints, /* @__PURE__ */ new Map());
651
+ __privateAdd$3(this, _serviceHolder, void 0);
652
+ __privateSet$3(this, _serviceHolder, serviceHolder);
109
653
  }
110
654
  add(feature, options) {
111
- if (__privateGet$2(this, _started)) {
655
+ if (__privateGet$3(this, _started)) {
112
656
  throw new Error("feature can not be added after the backend has started");
113
657
  }
114
- __privateGet$2(this, _features).set(feature, options);
658
+ __privateGet$3(this, _features).set(feature, options);
115
659
  }
116
660
  async start() {
117
- if (__privateGet$2(this, _started)) {
661
+ if (__privateGet$3(this, _started)) {
118
662
  throw new Error("Backend has already started");
119
663
  }
120
- __privateSet$2(this, _started, true);
121
- for (const ref of __privateGet$2(this, _serviceHolder).getServiceRefs()) {
664
+ __privateSet$3(this, _started, true);
665
+ for (const ref of __privateGet$3(this, _serviceHolder).getServiceRefs()) {
122
666
  if (ref.scope === "root") {
123
- await __privateGet$2(this, _serviceHolder).get(ref, "root");
667
+ await __privateGet$3(this, _serviceHolder).get(ref, "root");
124
668
  }
125
669
  }
126
- for (const [feature] of __privateGet$2(this, _features)) {
670
+ for (const [feature] of __privateGet$3(this, _features)) {
127
671
  const provides = /* @__PURE__ */ new Set();
128
672
  let registerInit = void 0;
129
673
  feature.register({
@@ -131,10 +675,10 @@ class BackendInitializer {
131
675
  if (registerInit) {
132
676
  throw new Error("registerExtensionPoint called after registerInit");
133
677
  }
134
- if (__privateGet$2(this, _extensionPoints).has(extensionPointRef)) {
678
+ if (__privateGet$3(this, _extensionPoints).has(extensionPointRef)) {
135
679
  throw new Error(`API ${extensionPointRef.id} already registered`);
136
680
  }
137
- __privateGet$2(this, _extensionPoints).set(extensionPointRef, impl);
681
+ __privateGet$3(this, _extensionPoints).set(extensionPointRef, impl);
138
682
  provides.add(extensionPointRef);
139
683
  },
140
684
  registerInit: (registerOptions) => {
@@ -155,19 +699,19 @@ class BackendInitializer {
155
699
  `registerInit was not called by register in ${feature.id}`
156
700
  );
157
701
  }
158
- __privateGet$2(this, _registerInits).push(registerInit);
702
+ __privateGet$3(this, _registerInits).push(registerInit);
159
703
  }
160
- const orderedRegisterResults = __privateMethod$1(this, _resolveInitOrder, resolveInitOrder_fn).call(this, __privateGet$2(this, _registerInits));
704
+ const orderedRegisterResults = __privateMethod$2(this, _resolveInitOrder, resolveInitOrder_fn).call(this, __privateGet$3(this, _registerInits));
161
705
  for (const registerInit of orderedRegisterResults) {
162
- const deps = await __privateMethod$1(this, _getInitDeps, getInitDeps_fn).call(this, registerInit.deps, registerInit.id);
706
+ const deps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, registerInit.deps, registerInit.id);
163
707
  await registerInit.init(deps);
164
708
  }
165
709
  }
166
710
  async stop() {
167
- if (!__privateGet$2(this, _started)) {
711
+ if (!__privateGet$3(this, _started)) {
168
712
  return;
169
713
  }
170
- const lifecycleService = await __privateGet$2(this, _serviceHolder).get(
714
+ const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
171
715
  backendPluginApi.coreServices.rootLifecycle,
172
716
  "root"
173
717
  );
@@ -188,13 +732,13 @@ getInitDeps_fn = async function(deps, pluginId) {
188
732
  const result = /* @__PURE__ */ new Map();
189
733
  const missingRefs = /* @__PURE__ */ new Set();
190
734
  for (const [name, ref] of Object.entries(deps)) {
191
- const extensionPoint = __privateGet$2(this, _extensionPoints).get(
735
+ const extensionPoint = __privateGet$3(this, _extensionPoints).get(
192
736
  ref
193
737
  );
194
738
  if (extensionPoint) {
195
739
  result.set(name, extensionPoint);
196
740
  } else {
197
- const impl = await __privateGet$2(this, _serviceHolder).get(
741
+ const impl = await __privateGet$3(this, _serviceHolder).get(
198
742
  ref,
199
743
  pluginId
200
744
  );
@@ -238,59 +782,51 @@ resolveInitOrder_fn = function(registerInits) {
238
782
  return orderedRegisterInits;
239
783
  };
240
784
 
241
- var __accessCheck$1 = (obj, member, msg) => {
785
+ var __accessCheck$2 = (obj, member, msg) => {
242
786
  if (!member.has(obj))
243
787
  throw TypeError("Cannot " + msg);
244
788
  };
245
- var __privateGet$1 = (obj, member, getter) => {
246
- __accessCheck$1(obj, member, "read from private field");
789
+ var __privateGet$2 = (obj, member, getter) => {
790
+ __accessCheck$2(obj, member, "read from private field");
247
791
  return getter ? getter.call(obj) : member.get(obj);
248
792
  };
249
- var __privateAdd$1 = (obj, member, value) => {
793
+ var __privateAdd$2 = (obj, member, value) => {
250
794
  if (member.has(obj))
251
795
  throw TypeError("Cannot add the same private member more than once");
252
796
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
253
797
  };
254
- var __privateSet$1 = (obj, member, value, setter) => {
255
- __accessCheck$1(obj, member, "write to private field");
798
+ var __privateSet$2 = (obj, member, value, setter) => {
799
+ __accessCheck$2(obj, member, "write to private field");
256
800
  setter ? setter.call(obj, value) : member.set(obj, value);
257
801
  return value;
258
802
  };
259
- var __privateMethod = (obj, member, method) => {
260
- __accessCheck$1(obj, member, "access private method");
803
+ var __privateMethod$1 = (obj, member, method) => {
804
+ __accessCheck$2(obj, member, "access private method");
261
805
  return method;
262
806
  };
263
807
  var _providedFactories, _loadedDefaultFactories, _implementations, _resolveFactory, resolveFactory_fn, _separateMapForTheRootService, _checkForMissingDeps, checkForMissingDeps_fn;
264
808
  class ServiceRegistry {
265
809
  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());
810
+ __privateAdd$2(this, _resolveFactory);
811
+ __privateAdd$2(this, _checkForMissingDeps);
812
+ __privateAdd$2(this, _providedFactories, void 0);
813
+ __privateAdd$2(this, _loadedDefaultFactories, void 0);
814
+ __privateAdd$2(this, _implementations, void 0);
815
+ __privateAdd$2(this, _separateMapForTheRootService, /* @__PURE__ */ new Map());
816
+ __privateSet$2(this, _providedFactories, new Map(factories.map((f) => [f.service.id, f])));
817
+ __privateSet$2(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
818
+ __privateSet$2(this, _implementations, /* @__PURE__ */ new Map());
283
819
  }
284
820
  getServiceRefs() {
285
- return Array.from(__privateGet$1(this, _providedFactories).values()).map((f) => f.service);
821
+ return Array.from(__privateGet$2(this, _providedFactories).values()).map((f) => f.service);
286
822
  }
287
823
  get(ref, pluginId) {
288
824
  var _a;
289
- return (_a = __privateMethod(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
825
+ return (_a = __privateMethod$1(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
290
826
  if (factory.scope === "root") {
291
- let existing = __privateGet$1(this, _separateMapForTheRootService).get(factory);
827
+ let existing = __privateGet$2(this, _separateMapForTheRootService).get(factory);
292
828
  if (!existing) {
293
- __privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
829
+ __privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
294
830
  const rootDeps = new Array();
295
831
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
296
832
  if (serviceRef.scope !== "root") {
@@ -304,13 +840,13 @@ class ServiceRegistry {
304
840
  existing = Promise.all(rootDeps).then(
305
841
  (entries) => factory.factory(Object.fromEntries(entries))
306
842
  );
307
- __privateGet$1(this, _separateMapForTheRootService).set(factory, existing);
843
+ __privateGet$2(this, _separateMapForTheRootService).set(factory, existing);
308
844
  }
309
845
  return existing;
310
846
  }
311
- let implementation = __privateGet$1(this, _implementations).get(factory);
847
+ let implementation = __privateGet$2(this, _implementations).get(factory);
312
848
  if (!implementation) {
313
- __privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
849
+ __privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
314
850
  const rootDeps = new Array();
315
851
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
316
852
  if (serviceRef.scope === "root") {
@@ -327,7 +863,7 @@ class ServiceRegistry {
327
863
  }),
328
864
  byPlugin: /* @__PURE__ */ new Map()
329
865
  };
330
- __privateGet$1(this, _implementations).set(factory, implementation);
866
+ __privateGet$2(this, _implementations).set(factory, implementation);
331
867
  }
332
868
  let result = implementation.byPlugin.get(pluginId);
333
869
  if (!result) {
@@ -369,18 +905,18 @@ resolveFactory_fn = function(ref, pluginId) {
369
905
  })
370
906
  });
371
907
  }
372
- let resolvedFactory = __privateGet$1(this, _providedFactories).get(ref.id);
908
+ let resolvedFactory = __privateGet$2(this, _providedFactories).get(ref.id);
373
909
  const { __defaultFactory: defaultFactory } = ref;
374
910
  if (!resolvedFactory && !defaultFactory) {
375
911
  return void 0;
376
912
  }
377
913
  if (!resolvedFactory) {
378
- let loadedFactory = __privateGet$1(this, _loadedDefaultFactories).get(defaultFactory);
914
+ let loadedFactory = __privateGet$2(this, _loadedDefaultFactories).get(defaultFactory);
379
915
  if (!loadedFactory) {
380
916
  loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
381
917
  (f) => typeof f === "function" ? f() : f
382
918
  );
383
- __privateGet$1(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
919
+ __privateGet$2(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
384
920
  }
385
921
  resolvedFactory = loadedFactory.catch((error) => {
386
922
  throw new Error(
@@ -399,7 +935,7 @@ checkForMissingDeps_fn = function(factory, pluginId) {
399
935
  if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
400
936
  return false;
401
937
  }
402
- if (__privateGet$1(this, _providedFactories).get(ref.id)) {
938
+ if (__privateGet$2(this, _providedFactories).get(ref.id)) {
403
939
  return false;
404
940
  }
405
941
  return !ref.__defaultFactory;
@@ -412,51 +948,220 @@ checkForMissingDeps_fn = function(factory, pluginId) {
412
948
  }
413
949
  };
414
950
 
415
- var __accessCheck = (obj, member, msg) => {
951
+ var __accessCheck$1 = (obj, member, msg) => {
416
952
  if (!member.has(obj))
417
953
  throw TypeError("Cannot " + msg);
418
954
  };
419
- var __privateGet = (obj, member, getter) => {
420
- __accessCheck(obj, member, "read from private field");
955
+ var __privateGet$1 = (obj, member, getter) => {
956
+ __accessCheck$1(obj, member, "read from private field");
421
957
  return getter ? getter.call(obj) : member.get(obj);
422
958
  };
423
- var __privateAdd = (obj, member, value) => {
959
+ var __privateAdd$1 = (obj, member, value) => {
424
960
  if (member.has(obj))
425
961
  throw TypeError("Cannot add the same private member more than once");
426
962
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
427
963
  };
428
- var __privateSet = (obj, member, value, setter) => {
429
- __accessCheck(obj, member, "write to private field");
964
+ var __privateSet$1 = (obj, member, value, setter) => {
965
+ __accessCheck$1(obj, member, "write to private field");
430
966
  setter ? setter.call(obj, value) : member.set(obj, value);
431
967
  return value;
432
968
  };
433
969
  var _services, _initializer;
434
970
  class BackstageBackend {
435
971
  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)));
972
+ __privateAdd$1(this, _services, void 0);
973
+ __privateAdd$1(this, _initializer, void 0);
974
+ __privateSet$1(this, _services, new ServiceRegistry(apiFactories));
975
+ __privateSet$1(this, _initializer, new BackendInitializer(__privateGet$1(this, _services)));
440
976
  }
441
977
  add(feature) {
442
- __privateGet(this, _initializer).add(feature);
978
+ __privateGet$1(this, _initializer).add(feature);
443
979
  }
444
980
  async start() {
445
- await __privateGet(this, _initializer).start();
981
+ await __privateGet$1(this, _initializer).start();
446
982
  }
447
983
  async stop() {
448
- await __privateGet(this, _initializer).stop();
984
+ await __privateGet$1(this, _initializer).stop();
449
985
  }
450
986
  }
451
987
  _services = new WeakMap();
452
988
  _initializer = new WeakMap();
453
989
 
454
990
  function createSpecializedBackend(options) {
455
- return new BackstageBackend(
456
- options.services.map((s) => typeof s === "function" ? s() : s)
991
+ const services = options.services.map(
992
+ (sf) => typeof sf === "function" ? sf() : sf
457
993
  );
994
+ const exists = /* @__PURE__ */ new Set();
995
+ const duplicates = /* @__PURE__ */ new Set();
996
+ for (const { service } of services) {
997
+ if (exists.has(service.id)) {
998
+ duplicates.add(service.id);
999
+ } else {
1000
+ exists.add(service.id);
1001
+ }
1002
+ }
1003
+ if (duplicates.size > 0) {
1004
+ const ids = Array.from(duplicates).join(", ");
1005
+ throw new Error(`Duplicate service implementations provided for ${ids}`);
1006
+ }
1007
+ if (exists.has(backendPluginApi.coreServices.pluginMetadata.id)) {
1008
+ throw new Error(
1009
+ `The ${backendPluginApi.coreServices.pluginMetadata.id} service cannot be overridden`
1010
+ );
1011
+ }
1012
+ return new BackstageBackend(services);
458
1013
  }
459
1014
 
1015
+ const httpRouterFactory = backendPluginApi.createServiceFactory({
1016
+ service: backendPluginApi.coreServices.httpRouter,
1017
+ deps: {
1018
+ plugin: backendPluginApi.coreServices.pluginMetadata,
1019
+ rootHttpRouter: backendPluginApi.coreServices.rootHttpRouter
1020
+ },
1021
+ async factory({ rootHttpRouter }, options) {
1022
+ var _a;
1023
+ const getPath = (_a = options == null ? void 0 : options.getPath) != null ? _a : (id) => `/api/${id}`;
1024
+ return async ({ plugin }) => {
1025
+ const path = getPath(plugin.getId());
1026
+ return {
1027
+ use(handler) {
1028
+ rootHttpRouter.use(path, handler);
1029
+ }
1030
+ };
1031
+ };
1032
+ }
1033
+ });
1034
+
1035
+ var __accessCheck = (obj, member, msg) => {
1036
+ if (!member.has(obj))
1037
+ throw TypeError("Cannot " + msg);
1038
+ };
1039
+ var __privateGet = (obj, member, getter) => {
1040
+ __accessCheck(obj, member, "read from private field");
1041
+ return getter ? getter.call(obj) : member.get(obj);
1042
+ };
1043
+ var __privateAdd = (obj, member, value) => {
1044
+ if (member.has(obj))
1045
+ throw TypeError("Cannot add the same private member more than once");
1046
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1047
+ };
1048
+ var __privateSet = (obj, member, value, setter) => {
1049
+ __accessCheck(obj, member, "write to private field");
1050
+ setter ? setter.call(obj, value) : member.set(obj, value);
1051
+ return value;
1052
+ };
1053
+ var __privateMethod = (obj, member, method) => {
1054
+ __accessCheck(obj, member, "access private method");
1055
+ return method;
1056
+ };
1057
+ var _indexPath, _router, _namedRoutes, _indexRouter, _existingPaths, _findConflictingPath, findConflictingPath_fn;
1058
+ function normalizePath(path) {
1059
+ return path.replace(/\/*$/, "/");
1060
+ }
1061
+ class RestrictedIndexedRouter {
1062
+ constructor(indexPath) {
1063
+ __privateAdd(this, _findConflictingPath);
1064
+ __privateAdd(this, _indexPath, void 0);
1065
+ __privateAdd(this, _router, express.Router());
1066
+ __privateAdd(this, _namedRoutes, express.Router());
1067
+ __privateAdd(this, _indexRouter, express.Router());
1068
+ __privateAdd(this, _existingPaths, new Array());
1069
+ __privateSet(this, _indexPath, indexPath);
1070
+ __privateGet(this, _router).use(__privateGet(this, _namedRoutes));
1071
+ __privateGet(this, _router).use(__privateGet(this, _indexRouter));
1072
+ }
1073
+ use(path, handler) {
1074
+ if (path.match(/^[/\s]*$/)) {
1075
+ throw new Error(`Root router path may not be empty`);
1076
+ }
1077
+ const conflictingPath = __privateMethod(this, _findConflictingPath, findConflictingPath_fn).call(this, path);
1078
+ if (conflictingPath) {
1079
+ throw new Error(
1080
+ `Path ${path} conflicts with the existing path ${conflictingPath}`
1081
+ );
1082
+ }
1083
+ __privateGet(this, _existingPaths).push(path);
1084
+ __privateGet(this, _namedRoutes).use(path, handler);
1085
+ if (__privateGet(this, _indexPath) === path) {
1086
+ __privateGet(this, _indexRouter).use(handler);
1087
+ }
1088
+ }
1089
+ handler() {
1090
+ return __privateGet(this, _router);
1091
+ }
1092
+ }
1093
+ _indexPath = new WeakMap();
1094
+ _router = new WeakMap();
1095
+ _namedRoutes = new WeakMap();
1096
+ _indexRouter = new WeakMap();
1097
+ _existingPaths = new WeakMap();
1098
+ _findConflictingPath = new WeakSet();
1099
+ findConflictingPath_fn = function(newPath) {
1100
+ const normalizedNewPath = normalizePath(newPath);
1101
+ for (const path of __privateGet(this, _existingPaths)) {
1102
+ const normalizedPath = normalizePath(path);
1103
+ if (normalizedPath.startsWith(normalizedNewPath)) {
1104
+ return path;
1105
+ }
1106
+ if (normalizedNewPath.startsWith(normalizedPath)) {
1107
+ return path;
1108
+ }
1109
+ }
1110
+ return void 0;
1111
+ };
1112
+
1113
+ function defaultConfigure({
1114
+ app,
1115
+ routes,
1116
+ middleware
1117
+ }) {
1118
+ app.use(middleware.helmet());
1119
+ app.use(middleware.cors());
1120
+ app.use(middleware.compression());
1121
+ app.use(middleware.logging());
1122
+ app.use(routes);
1123
+ app.use(middleware.notFound());
1124
+ app.use(middleware.error());
1125
+ }
1126
+ const rootHttpRouterFactory = backendPluginApi.createServiceFactory({
1127
+ service: backendPluginApi.coreServices.rootHttpRouter,
1128
+ deps: {
1129
+ config: backendPluginApi.coreServices.config,
1130
+ rootLogger: backendPluginApi.coreServices.rootLogger,
1131
+ lifecycle: backendPluginApi.coreServices.rootLifecycle
1132
+ },
1133
+ async factory({ config, rootLogger, lifecycle }, {
1134
+ indexPath,
1135
+ configure = defaultConfigure
1136
+ } = {}) {
1137
+ const router = new RestrictedIndexedRouter(indexPath != null ? indexPath : "/api/app");
1138
+ const logger = rootLogger.child({ service: "rootHttpRouter" });
1139
+ const app = express__default["default"]();
1140
+ const middleware = MiddlewareFactory.create({ config, logger });
1141
+ configure({
1142
+ app,
1143
+ routes: router.handler(),
1144
+ middleware,
1145
+ config,
1146
+ logger,
1147
+ lifecycle
1148
+ });
1149
+ const server = await createHttpServer(
1150
+ app,
1151
+ readHttpServerOptions(config.getOptionalConfig("backend")),
1152
+ { logger }
1153
+ );
1154
+ lifecycle.addShutdownHook({
1155
+ async fn() {
1156
+ await server.stop();
1157
+ },
1158
+ logger
1159
+ });
1160
+ await server.start();
1161
+ return router;
1162
+ }
1163
+ });
1164
+
460
1165
  const cacheFactory = backendPluginApi.createServiceFactory({
461
1166
  service: backendPluginApi.coreServices.cache,
462
1167
  deps: {
@@ -479,7 +1184,7 @@ const configFactory = backendPluginApi.createServiceFactory({
479
1184
  async factory({ logger }) {
480
1185
  const config = await backendCommon.loadBackendConfig({
481
1186
  argv: process.argv,
482
- logger: backendPluginApi.loggerToWinstonLogger(logger)
1187
+ logger: backendCommon.loggerToWinstonLogger(logger)
483
1188
  });
484
1189
  return config;
485
1190
  }
@@ -520,7 +1225,7 @@ const loggerFactory = backendPluginApi.createServiceFactory({
520
1225
  },
521
1226
  async factory({ rootLogger }) {
522
1227
  return async ({ plugin }) => {
523
- return rootLogger.child({ pluginId: plugin.getId() });
1228
+ return rootLogger.child({ plugin: plugin.getId() });
524
1229
  };
525
1230
  }
526
1231
  });
@@ -596,7 +1301,7 @@ const tokenManagerFactory = backendPluginApi.createServiceFactory({
596
1301
  async factory() {
597
1302
  return async ({ config, logger }) => {
598
1303
  return backendCommon.ServerTokenManager.fromConfig(config, {
599
- logger: backendPluginApi.loggerToWinstonLogger(logger)
1304
+ logger: backendCommon.loggerToWinstonLogger(logger)
600
1305
  });
601
1306
  };
602
1307
  }
@@ -612,54 +1317,28 @@ const urlReaderFactory = backendPluginApi.createServiceFactory({
612
1317
  return async ({ config, logger }) => {
613
1318
  return backendCommon.UrlReaders.default({
614
1319
  config,
615
- logger: backendPluginApi.loggerToWinstonLogger(logger)
1320
+ logger: backendCommon.loggerToWinstonLogger(logger)
616
1321
  });
617
1322
  };
618
1323
  }
619
1324
  });
620
1325
 
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
1326
  const lifecycleFactory = backendPluginApi.createServiceFactory({
650
1327
  service: backendPluginApi.coreServices.lifecycle,
651
1328
  deps: {
1329
+ logger: backendPluginApi.coreServices.logger,
652
1330
  rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
653
1331
  pluginMetadata: backendPluginApi.coreServices.pluginMetadata
654
1332
  },
655
1333
  async factory({ rootLifecycle }) {
656
- return async ({ pluginMetadata }) => {
1334
+ return async ({ logger, pluginMetadata }) => {
657
1335
  const plugin = pluginMetadata.getId();
658
1336
  return {
659
1337
  addShutdownHook(options) {
1338
+ var _a, _b;
660
1339
  rootLifecycle.addShutdownHook({
661
1340
  ...options,
662
- labels: { ...options == null ? void 0 : options.labels, plugin }
1341
+ logger: (_b = (_a = options.logger) == null ? void 0 : _a.child({ plugin })) != null ? _b : logger
663
1342
  });
664
1343
  }
665
1344
  };
@@ -667,8 +1346,10 @@ const lifecycleFactory = backendPluginApi.createServiceFactory({
667
1346
  }
668
1347
  });
669
1348
 
1349
+ exports.MiddlewareFactory = MiddlewareFactory;
670
1350
  exports.cacheFactory = cacheFactory;
671
1351
  exports.configFactory = configFactory;
1352
+ exports.createHttpServer = createHttpServer;
672
1353
  exports.createSpecializedBackend = createSpecializedBackend;
673
1354
  exports.databaseFactory = databaseFactory;
674
1355
  exports.discoveryFactory = discoveryFactory;
@@ -676,6 +1357,10 @@ exports.httpRouterFactory = httpRouterFactory;
676
1357
  exports.lifecycleFactory = lifecycleFactory;
677
1358
  exports.loggerFactory = loggerFactory;
678
1359
  exports.permissionsFactory = permissionsFactory;
1360
+ exports.readCorsOptions = readCorsOptions;
1361
+ exports.readHelmetOptions = readHelmetOptions;
1362
+ exports.readHttpServerOptions = readHttpServerOptions;
1363
+ exports.rootHttpRouterFactory = rootHttpRouterFactory;
679
1364
  exports.rootLifecycleFactory = rootLifecycleFactory;
680
1365
  exports.rootLoggerFactory = rootLoggerFactory;
681
1366
  exports.schedulerFactory = schedulerFactory;