@backstage/backend-app-api 0.7.4 → 0.7.6-next.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.
package/dist/index.cjs.js CHANGED
@@ -20,6 +20,7 @@ var minimatch = require('minimatch');
20
20
  var errors = require('@backstage/errors');
21
21
  var crypto = require('crypto');
22
22
  var winston = require('winston');
23
+ var tripleBeam = require('triple-beam');
23
24
  var backendPluginApi = require('@backstage/backend-plugin-api');
24
25
  var alpha = require('@backstage/backend-plugin-api/alpha');
25
26
  var luxon = require('luxon');
@@ -72,22 +73,16 @@ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
72
73
  var express__default = /*#__PURE__*/_interopDefaultCompat(express);
73
74
  var trimEnd__default = /*#__PURE__*/_interopDefaultCompat(trimEnd);
74
75
 
75
- var __defProp$1 = Object.defineProperty;
76
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
77
- var __publicField$1 = (obj, key, value) => {
78
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
79
- return value;
80
- };
81
76
  class ObservableConfigProxy {
82
77
  constructor(parent, parentKey) {
83
78
  this.parent = parent;
84
79
  this.parentKey = parentKey;
85
- __publicField$1(this, "config", new config.ConfigReader({}));
86
- __publicField$1(this, "subscribers", []);
87
80
  if (parent && !parentKey) {
88
81
  throw new Error("parentKey is required if parent is set");
89
82
  }
90
83
  }
84
+ config = new config.ConfigReader({});
85
+ subscribers = [];
91
86
  setConfig(config) {
92
87
  if (this.parent) {
93
88
  throw new Error("immutable");
@@ -116,36 +111,31 @@ class ObservableConfigProxy {
116
111
  };
117
112
  }
118
113
  select(required) {
119
- var _a;
120
114
  if (this.parent && this.parentKey) {
121
115
  if (required) {
122
116
  return this.parent.select(true).getConfig(this.parentKey);
123
117
  }
124
- return (_a = this.parent.select(false)) == null ? void 0 : _a.getOptionalConfig(this.parentKey);
118
+ return this.parent.select(false)?.getOptionalConfig(this.parentKey);
125
119
  }
126
120
  return this.config;
127
121
  }
128
122
  has(key) {
129
- var _a, _b;
130
- return (_b = (_a = this.select(false)) == null ? void 0 : _a.has(key)) != null ? _b : false;
123
+ return this.select(false)?.has(key) ?? false;
131
124
  }
132
125
  keys() {
133
- var _a, _b;
134
- return (_b = (_a = this.select(false)) == null ? void 0 : _a.keys()) != null ? _b : [];
126
+ return this.select(false)?.keys() ?? [];
135
127
  }
136
128
  get(key) {
137
129
  return this.select(true).get(key);
138
130
  }
139
131
  getOptional(key) {
140
- var _a;
141
- return (_a = this.select(false)) == null ? void 0 : _a.getOptional(key);
132
+ return this.select(false)?.getOptional(key);
142
133
  }
143
134
  getConfig(key) {
144
135
  return new ObservableConfigProxy(this, key);
145
136
  }
146
137
  getOptionalConfig(key) {
147
- var _a;
148
- if ((_a = this.select(false)) == null ? void 0 : _a.has(key)) {
138
+ if (this.select(false)?.has(key)) {
149
139
  return new ObservableConfigProxy(this, key);
150
140
  }
151
141
  return void 0;
@@ -154,36 +144,31 @@ class ObservableConfigProxy {
154
144
  return this.select(true).getConfigArray(key);
155
145
  }
156
146
  getOptionalConfigArray(key) {
157
- var _a;
158
- return (_a = this.select(false)) == null ? void 0 : _a.getOptionalConfigArray(key);
147
+ return this.select(false)?.getOptionalConfigArray(key);
159
148
  }
160
149
  getNumber(key) {
161
150
  return this.select(true).getNumber(key);
162
151
  }
163
152
  getOptionalNumber(key) {
164
- var _a;
165
- return (_a = this.select(false)) == null ? void 0 : _a.getOptionalNumber(key);
153
+ return this.select(false)?.getOptionalNumber(key);
166
154
  }
167
155
  getBoolean(key) {
168
156
  return this.select(true).getBoolean(key);
169
157
  }
170
158
  getOptionalBoolean(key) {
171
- var _a;
172
- return (_a = this.select(false)) == null ? void 0 : _a.getOptionalBoolean(key);
159
+ return this.select(false)?.getOptionalBoolean(key);
173
160
  }
174
161
  getString(key) {
175
162
  return this.select(true).getString(key);
176
163
  }
177
164
  getOptionalString(key) {
178
- var _a;
179
- return (_a = this.select(false)) == null ? void 0 : _a.getOptionalString(key);
165
+ return this.select(false)?.getOptionalString(key);
180
166
  }
181
167
  getStringArray(key) {
182
168
  return this.select(true).getStringArray(key);
183
169
  }
184
170
  getOptionalStringArray(key) {
185
- var _a;
186
- return (_a = this.select(false)) == null ? void 0 : _a.getOptionalStringArray(key);
171
+ return this.select(false)?.getOptionalStringArray(key);
187
172
  }
188
173
  }
189
174
 
@@ -197,16 +182,14 @@ function isValidUrl(url) {
197
182
  }
198
183
 
199
184
  async function createConfigSecretEnumerator(options) {
200
- var _a;
201
185
  const { logger, dir = process.cwd() } = options;
202
186
  const { packages } = await getPackages.getPackages(dir);
203
- const schema = (_a = options.schema) != null ? _a : await configLoader.loadConfigSchema({
187
+ const schema = options.schema ?? await configLoader.loadConfigSchema({
204
188
  dependencies: packages.map((p) => p.packageJson.name)
205
189
  });
206
190
  return (config) => {
207
- var _a2;
208
191
  const [secretsData] = schema.process(
209
- [{ data: (_a2 = config.getOptional()) != null ? _a2 : {}, context: "schema-enumerator" }],
192
+ [{ data: config.getOptional() ?? {}, context: "schema-enumerator" }],
210
193
  {
211
194
  visibility: ["secret"],
212
195
  ignoreSchemaErrors: true
@@ -224,9 +207,8 @@ async function createConfigSecretEnumerator(options) {
224
207
  };
225
208
  }
226
209
  async function loadBackendConfig(options) {
227
- var _a, _b;
228
210
  const args = parseArgs__default.default(options.argv);
229
- const configTargets = [(_a = args.config) != null ? _a : []].flat().map((arg) => isValidUrl(arg) ? { url: arg } : { path: path.resolve(arg) });
211
+ const configTargets = [args.config ?? []].flat().map((arg) => isValidUrl(arg) ? { url: arg } : { path: path.resolve(arg) });
230
212
  const paths = cliCommon.findPaths(__dirname);
231
213
  let currentCancelFunc = void 0;
232
214
  const config$1 = new ObservableConfigProxy();
@@ -234,7 +216,7 @@ async function loadBackendConfig(options) {
234
216
  configRoot: paths.targetRoot,
235
217
  configTargets,
236
218
  remote: options.remote,
237
- watch: ((_b = options.watch) != null ? _b : true) ? {
219
+ watch: options.watch ?? true ? {
238
220
  onChange(newConfigs) {
239
221
  console.info(
240
222
  `Reloaded config from ${newConfigs.map((c) => c.context).join(", ")}`
@@ -276,8 +258,7 @@ function readHttpServerOptions(config) {
276
258
  };
277
259
  }
278
260
  function readHttpListenOptions(config) {
279
- var _a, _b;
280
- const listen = config == null ? void 0 : config.getOptional("listen");
261
+ const listen = config?.getOptional("listen");
281
262
  if (typeof listen === "string") {
282
263
  const parts = String(listen).split(":");
283
264
  const port = parseInt(parts[parts.length - 1], 10);
@@ -293,18 +274,18 @@ function readHttpListenOptions(config) {
293
274
  `Unable to parse listen address ${listen}, expected <port> or <host>:<port>`
294
275
  );
295
276
  }
296
- const host = (_a = config == null ? void 0 : config.getOptional("listen.host")) != null ? _a : DEFAULT_HOST;
277
+ const host = config?.getOptional("listen.host") ?? DEFAULT_HOST;
297
278
  if (typeof host !== "string") {
298
- config == null ? void 0 : config.getOptionalString("listen.host");
279
+ config?.getOptionalString("listen.host");
299
280
  throw new Error("unreachable");
300
281
  }
301
282
  return {
302
- port: (_b = config == null ? void 0 : config.getOptionalNumber("listen.port")) != null ? _b : DEFAULT_PORT,
283
+ port: config?.getOptionalNumber("listen.port") ?? DEFAULT_PORT,
303
284
  host
304
285
  };
305
286
  }
306
287
  function readHttpsOptions(config) {
307
- const https = config == null ? void 0 : config.getOptional("https");
288
+ const https = config?.getOptional("https");
308
289
  if (https === true) {
309
290
  const baseUrl = config.getString("baseUrl");
310
291
  let hostname;
@@ -315,7 +296,7 @@ function readHttpsOptions(config) {
315
296
  }
316
297
  return { certificate: { type: "generated", hostname } };
317
298
  }
318
- const cc = config == null ? void 0 : config.getOptionalConfig("https");
299
+ const cc = config?.getOptionalConfig("https");
319
300
  if (!cc) {
320
301
  return void 0;
321
302
  }
@@ -518,7 +499,7 @@ function readHelmetOptions(config) {
518
499
  };
519
500
  }
520
501
  function readCspDirectives(config) {
521
- const cc = config == null ? void 0 : config.getOptionalConfig("csp");
502
+ const cc = config?.getOptionalConfig("csp");
522
503
  if (!cc) {
523
504
  return void 0;
524
505
  }
@@ -550,7 +531,7 @@ function applyCspDirectives(directives) {
550
531
  }
551
532
 
552
533
  function readCorsOptions(config) {
553
- const cc = config == null ? void 0 : config.getOptionalConfig("cors");
534
+ const cc = config?.getOptionalConfig("cors");
554
535
  if (!cc) {
555
536
  return { origin: false };
556
537
  }
@@ -589,7 +570,7 @@ function createCorsOriginMatcher(allowedOriginPatterns) {
589
570
  return (origin, callback) => {
590
571
  return callback(
591
572
  null,
592
- allowedOriginMatchers.some((pattern) => pattern.match(origin != null ? origin : ""))
573
+ allowedOriginMatchers.some((pattern) => pattern.match(origin ?? ""))
593
574
  );
594
575
  };
595
576
  }
@@ -615,37 +596,18 @@ function applyInternalErrorFilter(error, logger) {
615
596
  return error;
616
597
  }
617
598
 
618
- var __accessCheck$e = (obj, member, msg) => {
619
- if (!member.has(obj))
620
- throw TypeError("Cannot " + msg);
621
- };
622
- var __privateGet$c = (obj, member, getter) => {
623
- __accessCheck$e(obj, member, "read from private field");
624
- return member.get(obj);
625
- };
626
- var __privateAdd$e = (obj, member, value) => {
627
- if (member.has(obj))
628
- throw TypeError("Cannot add the same private member more than once");
629
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
630
- };
631
- var __privateSet$a = (obj, member, value, setter) => {
632
- __accessCheck$e(obj, member, "write to private field");
633
- member.set(obj, value);
634
- return value;
635
- };
636
- var _config, _logger;
637
- const _MiddlewareFactory = class _MiddlewareFactory {
638
- constructor(options) {
639
- __privateAdd$e(this, _config, void 0);
640
- __privateAdd$e(this, _logger, void 0);
641
- __privateSet$a(this, _config, options.config);
642
- __privateSet$a(this, _logger, options.logger);
643
- }
599
+ class MiddlewareFactory {
600
+ #config;
601
+ #logger;
644
602
  /**
645
603
  * Creates a new {@link MiddlewareFactory}.
646
604
  */
647
605
  static create(options) {
648
- return new _MiddlewareFactory(options);
606
+ return new MiddlewareFactory(options);
607
+ }
608
+ constructor(options) {
609
+ this.#config = options.config;
610
+ this.#logger = options.logger;
649
611
  }
650
612
  /**
651
613
  * Returns a middleware that unconditionally produces a 404 error response.
@@ -685,7 +647,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
685
647
  * @returns An Express request handler
686
648
  */
687
649
  logging() {
688
- const logger = __privateGet$c(this, _logger).child({
650
+ const logger = this.#logger.child({
689
651
  type: "incomingRequest"
690
652
  });
691
653
  return morgan__default.default("combined", {
@@ -709,7 +671,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
709
671
  * @returns An Express request handler
710
672
  */
711
673
  helmet() {
712
- return helmet__default.default(readHelmetOptions(__privateGet$c(this, _config).getOptionalConfig("backend")));
674
+ return helmet__default.default(readHelmetOptions(this.#config.getOptionalConfig("backend")));
713
675
  }
714
676
  /**
715
677
  * Returns a middleware that implements the cors library.
@@ -724,7 +686,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
724
686
  * @returns An Express request handler
725
687
  */
726
688
  cors() {
727
- return cors__default.default(readCorsOptions(__privateGet$c(this, _config).getOptionalConfig("backend")));
689
+ return cors__default.default(readCorsOptions(this.#config.getOptionalConfig("backend")));
728
690
  }
729
691
  /**
730
692
  * Express middleware to handle errors during request processing.
@@ -747,9 +709,8 @@ const _MiddlewareFactory = class _MiddlewareFactory {
747
709
  * @returns An Express error request handler
748
710
  */
749
711
  error(options = {}) {
750
- var _a;
751
- const showStackTraces = (_a = options.showStackTraces) != null ? _a : process.env.NODE_ENV === "development";
752
- const logger = __privateGet$c(this, _logger).child({
712
+ const showStackTraces = options.showStackTraces ?? process.env.NODE_ENV === "development";
713
+ const logger = this.#logger.child({
753
714
  type: "errorHandler"
754
715
  });
755
716
  return (rawError, req, res, next) => {
@@ -770,10 +731,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
770
731
  res.status(statusCode).json(body);
771
732
  };
772
733
  }
773
- };
774
- _config = new WeakMap();
775
- _logger = new WeakMap();
776
- let MiddlewareFactory = _MiddlewareFactory;
734
+ }
777
735
  function getStatusCode(error) {
778
736
  const knownStatusCodeFields = ["statusCode", "status"];
779
737
  for (const field of knownStatusCodeFields) {
@@ -808,51 +766,27 @@ const escapeRegExp = (text) => {
808
766
  return text.replace(/[.*+?^${}(\)|[\]\\]/g, "\\$&");
809
767
  };
810
768
 
811
- var __accessCheck$d = (obj, member, msg) => {
812
- if (!member.has(obj))
813
- throw TypeError("Cannot " + msg);
814
- };
815
- var __privateGet$b = (obj, member, getter) => {
816
- __accessCheck$d(obj, member, "read from private field");
817
- return member.get(obj);
818
- };
819
- var __privateAdd$d = (obj, member, value) => {
820
- if (member.has(obj))
821
- throw TypeError("Cannot add the same private member more than once");
822
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
823
- };
824
- var __privateSet$9 = (obj, member, value, setter) => {
825
- __accessCheck$d(obj, member, "write to private field");
826
- member.set(obj, value);
827
- return value;
828
- };
829
- var _winston, _addRedactions;
830
- const _WinstonLogger = class _WinstonLogger {
831
- constructor(winston, addRedactions) {
832
- __privateAdd$d(this, _winston, void 0);
833
- __privateAdd$d(this, _addRedactions, void 0);
834
- __privateSet$9(this, _winston, winston);
835
- __privateSet$9(this, _addRedactions, addRedactions);
836
- }
769
+ class WinstonLogger {
770
+ #winston;
771
+ #addRedactions;
837
772
  /**
838
773
  * Creates a {@link WinstonLogger} instance.
839
774
  */
840
775
  static create(options) {
841
- var _a, _b;
842
- const redacter = _WinstonLogger.redacter();
843
- const defaultFormatter = process.env.NODE_ENV === "production" ? winston.format.json() : _WinstonLogger.colorFormat();
776
+ const redacter = WinstonLogger.redacter();
777
+ const defaultFormatter = process.env.NODE_ENV === "production" ? winston.format.json() : WinstonLogger.colorFormat();
844
778
  let logger = winston.createLogger({
845
779
  level: process.env.LOG_LEVEL || options.level || "info",
846
780
  format: winston.format.combine(
847
- redacter.format,
848
- (_a = options.format) != null ? _a : defaultFormatter
781
+ options.format ?? defaultFormatter,
782
+ redacter.format
849
783
  ),
850
- transports: (_b = options.transports) != null ? _b : new winston.transports.Console()
784
+ transports: options.transports ?? new winston.transports.Console()
851
785
  });
852
786
  if (options.meta) {
853
787
  logger = logger.child(options.meta);
854
788
  }
855
- return new _WinstonLogger(logger, redacter.add);
789
+ return new WinstonLogger(logger, redacter.add);
856
790
  }
857
791
  /**
858
792
  * Creates a winston log formatter for redacting secrets.
@@ -860,24 +794,14 @@ const _WinstonLogger = class _WinstonLogger {
860
794
  static redacter() {
861
795
  const redactionSet = /* @__PURE__ */ new Set();
862
796
  let redactionPattern = void 0;
863
- const replace = (obj) => {
864
- var _a;
865
- for (const key in obj) {
866
- if (Object.hasOwn(obj, key)) {
867
- if (typeof obj[key] === "object") {
868
- obj[key] = replace(obj[key]);
869
- } else if (typeof obj[key] === "string") {
870
- try {
871
- obj[key] = (_a = obj[key]) == null ? void 0 : _a.replace(redactionPattern, "[REDACTED]");
872
- } catch {
873
- }
874
- }
875
- }
876
- }
877
- return obj;
878
- };
879
797
  return {
880
- format: winston.format(replace)(),
798
+ format: winston.format((obj) => {
799
+ if (!redactionPattern || !obj) {
800
+ return obj;
801
+ }
802
+ obj[tripleBeam.MESSAGE] = obj[tripleBeam.MESSAGE]?.replace?.(redactionPattern, "***");
803
+ return obj;
804
+ })(),
881
805
  add(newRedactions) {
882
806
  let added = 0;
883
807
  for (const redactionToTrim of newRedactions) {
@@ -924,227 +848,30 @@ const _WinstonLogger = class _WinstonLogger {
924
848
  })
925
849
  );
926
850
  }
851
+ constructor(winston, addRedactions) {
852
+ this.#winston = winston;
853
+ this.#addRedactions = addRedactions;
854
+ }
927
855
  error(message, meta) {
928
- __privateGet$b(this, _winston).error(message, meta);
856
+ this.#winston.error(message, meta);
929
857
  }
930
858
  warn(message, meta) {
931
- __privateGet$b(this, _winston).warn(message, meta);
859
+ this.#winston.warn(message, meta);
932
860
  }
933
861
  info(message, meta) {
934
- __privateGet$b(this, _winston).info(message, meta);
862
+ this.#winston.info(message, meta);
935
863
  }
936
864
  debug(message, meta) {
937
- __privateGet$b(this, _winston).debug(message, meta);
865
+ this.#winston.debug(message, meta);
938
866
  }
939
867
  child(meta) {
940
- return new _WinstonLogger(__privateGet$b(this, _winston).child(meta));
868
+ return new WinstonLogger(this.#winston.child(meta));
941
869
  }
942
870
  addRedactions(redactions) {
943
- var _a;
944
- (_a = __privateGet$b(this, _addRedactions)) == null ? void 0 : _a.call(this, redactions);
945
- }
946
- };
947
- _winston = new WeakMap();
948
- _addRedactions = new WeakMap();
949
- let WinstonLogger = _WinstonLogger;
950
-
951
- var __accessCheck$c = (obj, member, msg) => {
952
- if (!member.has(obj))
953
- throw TypeError("Cannot " + msg);
954
- };
955
- var __privateGet$a = (obj, member, getter) => {
956
- __accessCheck$c(obj, member, "read from private field");
957
- return member.get(obj);
958
- };
959
- var __privateAdd$c = (obj, member, value) => {
960
- if (member.has(obj))
961
- throw TypeError("Cannot add the same private member more than once");
962
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
963
- };
964
- var __privateSet$8 = (obj, member, value, setter) => {
965
- __accessCheck$c(obj, member, "write to private field");
966
- member.set(obj, value);
967
- return value;
968
- };
969
- var _hasStarted$1, _startupTasks$1, _hasShutdown, _shutdownTasks;
970
- class BackendLifecycleImpl {
971
- constructor(logger) {
972
- this.logger = logger;
973
- __privateAdd$c(this, _hasStarted$1, false);
974
- __privateAdd$c(this, _startupTasks$1, []);
975
- __privateAdd$c(this, _hasShutdown, false);
976
- __privateAdd$c(this, _shutdownTasks, []);
977
- }
978
- addStartupHook(hook, options) {
979
- if (__privateGet$a(this, _hasStarted$1)) {
980
- throw new Error("Attempted to add startup hook after startup");
981
- }
982
- __privateGet$a(this, _startupTasks$1).push({ hook, options });
983
- }
984
- async startup() {
985
- if (__privateGet$a(this, _hasStarted$1)) {
986
- return;
987
- }
988
- __privateSet$8(this, _hasStarted$1, true);
989
- this.logger.debug(`Running ${__privateGet$a(this, _startupTasks$1).length} startup tasks...`);
990
- await Promise.all(
991
- __privateGet$a(this, _startupTasks$1).map(async ({ hook, options }) => {
992
- var _a;
993
- const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
994
- try {
995
- await hook();
996
- logger.debug(`Startup hook succeeded`);
997
- } catch (error) {
998
- logger.error(`Startup hook failed, ${error}`);
999
- }
1000
- })
1001
- );
1002
- }
1003
- addShutdownHook(hook, options) {
1004
- if (__privateGet$a(this, _hasShutdown)) {
1005
- throw new Error("Attempted to add shutdown hook after shutdown");
1006
- }
1007
- __privateGet$a(this, _shutdownTasks).push({ hook, options });
1008
- }
1009
- async shutdown() {
1010
- if (__privateGet$a(this, _hasShutdown)) {
1011
- return;
1012
- }
1013
- __privateSet$8(this, _hasShutdown, true);
1014
- this.logger.debug(
1015
- `Running ${__privateGet$a(this, _shutdownTasks).length} shutdown tasks...`
1016
- );
1017
- await Promise.all(
1018
- __privateGet$a(this, _shutdownTasks).map(async ({ hook, options }) => {
1019
- var _a;
1020
- const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
1021
- try {
1022
- await hook();
1023
- logger.debug(`Shutdown hook succeeded`);
1024
- } catch (error) {
1025
- logger.error(`Shutdown hook failed, ${error}`);
1026
- }
1027
- })
1028
- );
1029
- }
1030
- }
1031
- _hasStarted$1 = new WeakMap();
1032
- _startupTasks$1 = new WeakMap();
1033
- _hasShutdown = new WeakMap();
1034
- _shutdownTasks = new WeakMap();
1035
- const rootLifecycleServiceFactory = backendPluginApi.createServiceFactory({
1036
- service: backendPluginApi.coreServices.rootLifecycle,
1037
- deps: {
1038
- logger: backendPluginApi.coreServices.rootLogger
1039
- },
1040
- async factory({ logger }) {
1041
- return new BackendLifecycleImpl(logger);
1042
- }
1043
- });
1044
-
1045
- var __accessCheck$b = (obj, member, msg) => {
1046
- if (!member.has(obj))
1047
- throw TypeError("Cannot " + msg);
1048
- };
1049
- var __privateGet$9 = (obj, member, getter) => {
1050
- __accessCheck$b(obj, member, "read from private field");
1051
- return member.get(obj);
1052
- };
1053
- var __privateAdd$b = (obj, member, value) => {
1054
- if (member.has(obj))
1055
- throw TypeError("Cannot add the same private member more than once");
1056
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1057
- };
1058
- var __privateSet$7 = (obj, member, value, setter) => {
1059
- __accessCheck$b(obj, member, "write to private field");
1060
- member.set(obj, value);
1061
- return value;
1062
- };
1063
- var _hasStarted, _startupTasks;
1064
- class BackendPluginLifecycleImpl {
1065
- constructor(logger, rootLifecycle, pluginMetadata) {
1066
- this.logger = logger;
1067
- this.rootLifecycle = rootLifecycle;
1068
- this.pluginMetadata = pluginMetadata;
1069
- __privateAdd$b(this, _hasStarted, false);
1070
- __privateAdd$b(this, _startupTasks, []);
1071
- }
1072
- addStartupHook(hook, options) {
1073
- if (__privateGet$9(this, _hasStarted)) {
1074
- throw new Error("Attempted to add startup hook after startup");
1075
- }
1076
- __privateGet$9(this, _startupTasks).push({ hook, options });
1077
- }
1078
- async startup() {
1079
- if (__privateGet$9(this, _hasStarted)) {
1080
- return;
1081
- }
1082
- __privateSet$7(this, _hasStarted, true);
1083
- this.logger.debug(
1084
- `Running ${__privateGet$9(this, _startupTasks).length} plugin startup tasks...`
1085
- );
1086
- await Promise.all(
1087
- __privateGet$9(this, _startupTasks).map(async ({ hook, options }) => {
1088
- var _a;
1089
- const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
1090
- try {
1091
- await hook();
1092
- logger.debug(`Plugin startup hook succeeded`);
1093
- } catch (error) {
1094
- logger.error(`Plugin startup hook failed, ${error}`);
1095
- }
1096
- })
1097
- );
1098
- }
1099
- addShutdownHook(hook, options) {
1100
- var _a, _b;
1101
- const plugin = this.pluginMetadata.getId();
1102
- this.rootLifecycle.addShutdownHook(hook, {
1103
- logger: (_b = (_a = options == null ? void 0 : options.logger) == null ? void 0 : _a.child({ plugin })) != null ? _b : this.logger
1104
- });
871
+ this.#addRedactions?.(redactions);
1105
872
  }
1106
873
  }
1107
- _hasStarted = new WeakMap();
1108
- _startupTasks = new WeakMap();
1109
- const lifecycleServiceFactory = backendPluginApi.createServiceFactory({
1110
- service: backendPluginApi.coreServices.lifecycle,
1111
- deps: {
1112
- logger: backendPluginApi.coreServices.logger,
1113
- rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
1114
- pluginMetadata: backendPluginApi.coreServices.pluginMetadata
1115
- },
1116
- async factory({ rootLifecycle, logger, pluginMetadata }) {
1117
- return new BackendPluginLifecycleImpl(
1118
- logger,
1119
- rootLifecycle,
1120
- pluginMetadata
1121
- );
1122
- }
1123
- });
1124
874
 
1125
- var __accessCheck$a = (obj, member, msg) => {
1126
- if (!member.has(obj))
1127
- throw TypeError("Cannot " + msg);
1128
- };
1129
- var __privateGet$8 = (obj, member, getter) => {
1130
- __accessCheck$a(obj, member, "read from private field");
1131
- return member.get(obj);
1132
- };
1133
- var __privateAdd$a = (obj, member, value) => {
1134
- if (member.has(obj))
1135
- throw TypeError("Cannot add the same private member more than once");
1136
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1137
- };
1138
- var __privateSet$6 = (obj, member, value, setter) => {
1139
- __accessCheck$a(obj, member, "write to private field");
1140
- member.set(obj, value);
1141
- return value;
1142
- };
1143
- var __privateMethod$7 = (obj, member, method) => {
1144
- __accessCheck$a(obj, member, "access private method");
1145
- return method;
1146
- };
1147
- var _nodeIds, _cycleKeys, _getCycleKey, getCycleKey_fn, _nodes, _allProvided;
1148
875
  class Node {
1149
876
  constructor(value, consumes, provides) {
1150
877
  this.value = value;
@@ -1159,45 +886,29 @@ class Node {
1159
886
  );
1160
887
  }
1161
888
  }
1162
- const _CycleKeySet = class _CycleKeySet {
1163
- constructor(nodes) {
1164
- __privateAdd$a(this, _getCycleKey);
1165
- __privateAdd$a(this, _nodeIds, void 0);
1166
- __privateAdd$a(this, _cycleKeys, void 0);
1167
- __privateSet$6(this, _nodeIds, new Map(nodes.map((n, i) => [n.value, i])));
1168
- __privateSet$6(this, _cycleKeys, /* @__PURE__ */ new Set());
1169
- }
889
+ class CycleKeySet {
1170
890
  static from(nodes) {
1171
- return new _CycleKeySet(nodes);
891
+ return new CycleKeySet(nodes);
892
+ }
893
+ #nodeIds;
894
+ #cycleKeys;
895
+ constructor(nodes) {
896
+ this.#nodeIds = new Map(nodes.map((n, i) => [n.value, i]));
897
+ this.#cycleKeys = /* @__PURE__ */ new Set();
1172
898
  }
1173
899
  tryAdd(path) {
1174
- const cycleKey = __privateMethod$7(this, _getCycleKey, getCycleKey_fn).call(this, path);
1175
- if (__privateGet$8(this, _cycleKeys).has(cycleKey)) {
900
+ const cycleKey = this.#getCycleKey(path);
901
+ if (this.#cycleKeys.has(cycleKey)) {
1176
902
  return false;
1177
903
  }
1178
- __privateGet$8(this, _cycleKeys).add(cycleKey);
904
+ this.#cycleKeys.add(cycleKey);
1179
905
  return true;
1180
906
  }
1181
- };
1182
- _nodeIds = new WeakMap();
1183
- _cycleKeys = new WeakMap();
1184
- _getCycleKey = new WeakSet();
1185
- getCycleKey_fn = function(path) {
1186
- return path.map((n) => __privateGet$8(this, _nodeIds).get(n)).sort().join(",");
1187
- };
1188
- let CycleKeySet = _CycleKeySet;
1189
- const _DependencyGraph = class _DependencyGraph {
1190
- constructor(nodes) {
1191
- __privateAdd$a(this, _nodes, void 0);
1192
- __privateAdd$a(this, _allProvided, void 0);
1193
- __privateSet$6(this, _nodes, nodes);
1194
- __privateSet$6(this, _allProvided, /* @__PURE__ */ new Set());
1195
- for (const node of __privateGet$8(this, _nodes).values()) {
1196
- for (const produced of node.provides) {
1197
- __privateGet$8(this, _allProvided).add(produced);
1198
- }
1199
- }
907
+ #getCycleKey(path) {
908
+ return path.map((n) => this.#nodeIds.get(n)).sort().join(",");
1200
909
  }
910
+ }
911
+ class DependencyGraph {
1201
912
  static fromMap(nodes) {
1202
913
  return this.fromIterable(
1203
914
  Object.entries(nodes).map(([key, node]) => ({
@@ -1211,16 +922,27 @@ const _DependencyGraph = class _DependencyGraph {
1211
922
  for (const nodeInput of nodeInputs) {
1212
923
  nodes.push(Node.from(nodeInput));
1213
924
  }
1214
- return new _DependencyGraph(nodes);
925
+ return new DependencyGraph(nodes);
926
+ }
927
+ #nodes;
928
+ #allProvided;
929
+ constructor(nodes) {
930
+ this.#nodes = nodes;
931
+ this.#allProvided = /* @__PURE__ */ new Set();
932
+ for (const node of this.#nodes.values()) {
933
+ for (const produced of node.provides) {
934
+ this.#allProvided.add(produced);
935
+ }
936
+ }
1215
937
  }
1216
938
  /**
1217
939
  * Find all nodes that consume dependencies that are not provided by any other node.
1218
940
  */
1219
941
  findUnsatisfiedDeps() {
1220
942
  const unsatisfiedDependencies = [];
1221
- for (const node of __privateGet$8(this, _nodes).values()) {
943
+ for (const node of this.#nodes.values()) {
1222
944
  const unsatisfied = Array.from(node.consumes).filter(
1223
- (id) => !__privateGet$8(this, _allProvided).has(id)
945
+ (id) => !this.#allProvided.has(id)
1224
946
  );
1225
947
  if (unsatisfied.length > 0) {
1226
948
  unsatisfiedDependencies.push({ value: node.value, unsatisfied });
@@ -1240,8 +962,8 @@ const _DependencyGraph = class _DependencyGraph {
1240
962
  * form a cycle, with the same node as the first and last element of the array.
1241
963
  */
1242
964
  *detectCircularDependencies() {
1243
- const cycleKeys = CycleKeySet.from(__privateGet$8(this, _nodes));
1244
- for (const startNode of __privateGet$8(this, _nodes)) {
965
+ const cycleKeys = CycleKeySet.from(this.#nodes);
966
+ for (const startNode of this.#nodes) {
1245
967
  const visited = /* @__PURE__ */ new Set();
1246
968
  const stack = new Array([
1247
969
  startNode,
@@ -1254,7 +976,7 @@ const _DependencyGraph = class _DependencyGraph {
1254
976
  }
1255
977
  visited.add(node);
1256
978
  for (const consumed of node.consumes) {
1257
- const providerNodes = __privateGet$8(this, _nodes).filter(
979
+ const providerNodes = this.#nodes.filter(
1258
980
  (other) => other.provides.has(consumed)
1259
981
  );
1260
982
  for (const provider of providerNodes) {
@@ -1283,9 +1005,9 @@ const _DependencyGraph = class _DependencyGraph {
1283
1005
  * Dependencies of nodes that are not produced by any other nodes will be ignored.
1284
1006
  */
1285
1007
  async parallelTopologicalTraversal(fn) {
1286
- const allProvided = __privateGet$8(this, _allProvided);
1008
+ const allProvided = this.#allProvided;
1287
1009
  const producedSoFar = /* @__PURE__ */ new Set();
1288
- const waiting = new Set(__privateGet$8(this, _nodes).values());
1010
+ const waiting = new Set(this.#nodes.values());
1289
1011
  const visited = /* @__PURE__ */ new Set();
1290
1012
  const results = new Array();
1291
1013
  let inFlight = 0;
@@ -1326,34 +1048,8 @@ const _DependencyGraph = class _DependencyGraph {
1326
1048
  await processMoreNodes();
1327
1049
  return results;
1328
1050
  }
1329
- };
1330
- _nodes = new WeakMap();
1331
- _allProvided = new WeakMap();
1332
- let DependencyGraph = _DependencyGraph;
1051
+ }
1333
1052
 
1334
- var __accessCheck$9 = (obj, member, msg) => {
1335
- if (!member.has(obj))
1336
- throw TypeError("Cannot " + msg);
1337
- };
1338
- var __privateGet$7 = (obj, member, getter) => {
1339
- __accessCheck$9(obj, member, "read from private field");
1340
- return member.get(obj);
1341
- };
1342
- var __privateAdd$9 = (obj, member, value) => {
1343
- if (member.has(obj))
1344
- throw TypeError("Cannot add the same private member more than once");
1345
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1346
- };
1347
- var __privateSet$5 = (obj, member, value, setter) => {
1348
- __accessCheck$9(obj, member, "write to private field");
1349
- member.set(obj, value);
1350
- return value;
1351
- };
1352
- var __privateMethod$6 = (obj, member, method) => {
1353
- __accessCheck$9(obj, member, "access private method");
1354
- return method;
1355
- };
1356
- var _providedFactories, _loadedDefaultFactories, _implementations, _rootServiceImplementations, _addedFactoryIds, _instantiatedFactories, _resolveFactory, resolveFactory_fn, _checkForMissingDeps, checkForMissingDeps_fn;
1357
1053
  function toInternalServiceFactory(factory) {
1358
1054
  const f = factory;
1359
1055
  if (f.$$type !== "@backstage/BackendFeature") {
@@ -1368,33 +1064,77 @@ const pluginMetadataServiceFactory = backendPluginApi.createServiceFactory(
1368
1064
  (options) => ({
1369
1065
  service: backendPluginApi.coreServices.pluginMetadata,
1370
1066
  deps: {},
1371
- factory: async () => ({ getId: () => options == null ? void 0 : options.pluginId })
1067
+ factory: async () => ({ getId: () => options?.pluginId })
1372
1068
  })
1373
1069
  );
1374
- const _ServiceRegistry = class _ServiceRegistry {
1375
- constructor(factories) {
1376
- __privateAdd$9(this, _resolveFactory);
1377
- __privateAdd$9(this, _checkForMissingDeps);
1378
- __privateAdd$9(this, _providedFactories, void 0);
1379
- __privateAdd$9(this, _loadedDefaultFactories, void 0);
1380
- __privateAdd$9(this, _implementations, void 0);
1381
- __privateAdd$9(this, _rootServiceImplementations, /* @__PURE__ */ new Map());
1382
- __privateAdd$9(this, _addedFactoryIds, /* @__PURE__ */ new Set());
1383
- __privateAdd$9(this, _instantiatedFactories, /* @__PURE__ */ new Set());
1384
- __privateSet$5(this, _providedFactories, new Map(
1385
- factories.map((sf) => [sf.service.id, toInternalServiceFactory(sf)])
1386
- ));
1387
- __privateSet$5(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
1388
- __privateSet$5(this, _implementations, /* @__PURE__ */ new Map());
1389
- }
1070
+ class ServiceRegistry {
1390
1071
  static create(factories) {
1391
- const registry = new _ServiceRegistry(factories);
1072
+ const registry = new ServiceRegistry(factories);
1392
1073
  registry.checkForCircularDeps();
1393
1074
  return registry;
1394
1075
  }
1076
+ #providedFactories;
1077
+ #loadedDefaultFactories;
1078
+ #implementations;
1079
+ #rootServiceImplementations = /* @__PURE__ */ new Map();
1080
+ #addedFactoryIds = /* @__PURE__ */ new Set();
1081
+ #instantiatedFactories = /* @__PURE__ */ new Set();
1082
+ constructor(factories) {
1083
+ this.#providedFactories = new Map(
1084
+ factories.map((sf) => [sf.service.id, toInternalServiceFactory(sf)])
1085
+ );
1086
+ this.#loadedDefaultFactories = /* @__PURE__ */ new Map();
1087
+ this.#implementations = /* @__PURE__ */ new Map();
1088
+ }
1089
+ #resolveFactory(ref, pluginId) {
1090
+ if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
1091
+ return Promise.resolve(
1092
+ toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId }))
1093
+ );
1094
+ }
1095
+ let resolvedFactory = this.#providedFactories.get(ref.id);
1096
+ const { __defaultFactory: defaultFactory } = ref;
1097
+ if (!resolvedFactory && !defaultFactory) {
1098
+ return void 0;
1099
+ }
1100
+ if (!resolvedFactory) {
1101
+ let loadedFactory = this.#loadedDefaultFactories.get(defaultFactory);
1102
+ if (!loadedFactory) {
1103
+ loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
1104
+ (f) => toInternalServiceFactory(typeof f === "function" ? f() : f)
1105
+ );
1106
+ this.#loadedDefaultFactories.set(defaultFactory, loadedFactory);
1107
+ }
1108
+ resolvedFactory = loadedFactory.catch((error) => {
1109
+ throw new Error(
1110
+ `Failed to instantiate service '${ref.id}' because the default factory loader threw an error, ${errors.stringifyError(
1111
+ error
1112
+ )}`
1113
+ );
1114
+ });
1115
+ }
1116
+ return Promise.resolve(resolvedFactory);
1117
+ }
1118
+ #checkForMissingDeps(factory, pluginId) {
1119
+ const missingDeps = Object.values(factory.deps).filter((ref) => {
1120
+ if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
1121
+ return false;
1122
+ }
1123
+ if (this.#providedFactories.get(ref.id)) {
1124
+ return false;
1125
+ }
1126
+ return !ref.__defaultFactory;
1127
+ });
1128
+ if (missingDeps.length) {
1129
+ const missing = missingDeps.map((r) => `'${r.id}'`).join(", ");
1130
+ throw new Error(
1131
+ `Failed to instantiate service '${factory.service.id}' for '${pluginId}' because the following dependent services are missing: ${missing}`
1132
+ );
1133
+ }
1134
+ }
1395
1135
  checkForCircularDeps() {
1396
1136
  const graph = DependencyGraph.fromIterable(
1397
- Array.from(__privateGet$7(this, _providedFactories)).map(
1137
+ Array.from(this.#providedFactories).map(
1398
1138
  ([serviceId, serviceFactory]) => ({
1399
1139
  value: serviceId,
1400
1140
  provides: [serviceId],
@@ -1416,21 +1156,21 @@ const _ServiceRegistry = class _ServiceRegistry {
1416
1156
  `The ${backendPluginApi.coreServices.pluginMetadata.id} service cannot be overridden`
1417
1157
  );
1418
1158
  }
1419
- if (__privateGet$7(this, _addedFactoryIds).has(factoryId)) {
1159
+ if (this.#addedFactoryIds.has(factoryId)) {
1420
1160
  throw new Error(
1421
1161
  `Duplicate service implementations provided for ${factoryId}`
1422
1162
  );
1423
1163
  }
1424
- if (__privateGet$7(this, _instantiatedFactories).has(factoryId)) {
1164
+ if (this.#instantiatedFactories.has(factoryId)) {
1425
1165
  throw new Error(
1426
1166
  `Unable to set service factory with id ${factoryId}, service has already been instantiated`
1427
1167
  );
1428
1168
  }
1429
- __privateGet$7(this, _addedFactoryIds).add(factoryId);
1430
- __privateGet$7(this, _providedFactories).set(factoryId, toInternalServiceFactory(factory));
1169
+ this.#addedFactoryIds.add(factoryId);
1170
+ this.#providedFactories.set(factoryId, toInternalServiceFactory(factory));
1431
1171
  }
1432
1172
  async initializeEagerServicesWithScope(scope, pluginId = "root") {
1433
- for (const factory of __privateGet$7(this, _providedFactories).values()) {
1173
+ for (const factory of this.#providedFactories.values()) {
1434
1174
  if (factory.service.scope === scope) {
1435
1175
  if (scope === "root" && factory.initialization !== "lazy") {
1436
1176
  await this.get(factory.service, pluginId);
@@ -1441,13 +1181,12 @@ const _ServiceRegistry = class _ServiceRegistry {
1441
1181
  }
1442
1182
  }
1443
1183
  get(ref, pluginId) {
1444
- var _a;
1445
- __privateGet$7(this, _instantiatedFactories).add(ref.id);
1446
- return (_a = __privateMethod$6(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
1184
+ this.#instantiatedFactories.add(ref.id);
1185
+ return this.#resolveFactory(ref, pluginId)?.then((factory) => {
1447
1186
  if (factory.service.scope === "root") {
1448
- let existing = __privateGet$7(this, _rootServiceImplementations).get(factory);
1187
+ let existing = this.#rootServiceImplementations.get(factory);
1449
1188
  if (!existing) {
1450
- __privateMethod$6(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1189
+ this.#checkForMissingDeps(factory, pluginId);
1451
1190
  const rootDeps = new Array();
1452
1191
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
1453
1192
  if (serviceRef.scope !== "root") {
@@ -1461,13 +1200,13 @@ const _ServiceRegistry = class _ServiceRegistry {
1461
1200
  existing = Promise.all(rootDeps).then(
1462
1201
  (entries) => factory.factory(Object.fromEntries(entries), void 0)
1463
1202
  );
1464
- __privateGet$7(this, _rootServiceImplementations).set(factory, existing);
1203
+ this.#rootServiceImplementations.set(factory, existing);
1465
1204
  }
1466
1205
  return existing;
1467
1206
  }
1468
- let implementation = __privateGet$7(this, _implementations).get(factory);
1207
+ let implementation = this.#implementations.get(factory);
1469
1208
  if (!implementation) {
1470
- __privateMethod$6(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1209
+ this.#checkForMissingDeps(factory, pluginId);
1471
1210
  const rootDeps = new Array();
1472
1211
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
1473
1212
  if (serviceRef.scope === "root") {
@@ -1477,10 +1216,7 @@ const _ServiceRegistry = class _ServiceRegistry {
1477
1216
  }
1478
1217
  implementation = {
1479
1218
  context: Promise.all(rootDeps).then(
1480
- (entries) => {
1481
- var _a2;
1482
- return (_a2 = factory.createRootContext) == null ? void 0 : _a2.call(factory, Object.fromEntries(entries));
1483
- }
1219
+ (entries) => factory.createRootContext?.(Object.fromEntries(entries))
1484
1220
  ).catch((error) => {
1485
1221
  const cause = errors.stringifyError(error);
1486
1222
  throw new Error(
@@ -1489,7 +1225,7 @@ const _ServiceRegistry = class _ServiceRegistry {
1489
1225
  }),
1490
1226
  byPlugin: /* @__PURE__ */ new Map()
1491
1227
  };
1492
- __privateGet$7(this, _implementations).set(factory, implementation);
1228
+ this.#implementations.set(factory, implementation);
1493
1229
  }
1494
1230
  let result = implementation.byPlugin.get(pluginId);
1495
1231
  if (!result) {
@@ -1513,72 +1249,17 @@ const _ServiceRegistry = class _ServiceRegistry {
1513
1249
  return result;
1514
1250
  });
1515
1251
  }
1516
- };
1517
- _providedFactories = new WeakMap();
1518
- _loadedDefaultFactories = new WeakMap();
1519
- _implementations = new WeakMap();
1520
- _rootServiceImplementations = new WeakMap();
1521
- _addedFactoryIds = new WeakMap();
1522
- _instantiatedFactories = new WeakMap();
1523
- _resolveFactory = new WeakSet();
1524
- resolveFactory_fn = function(ref, pluginId) {
1525
- if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
1526
- return Promise.resolve(
1527
- toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId }))
1528
- );
1529
- }
1530
- let resolvedFactory = __privateGet$7(this, _providedFactories).get(ref.id);
1531
- const { __defaultFactory: defaultFactory } = ref;
1532
- if (!resolvedFactory && !defaultFactory) {
1533
- return void 0;
1534
- }
1535
- if (!resolvedFactory) {
1536
- let loadedFactory = __privateGet$7(this, _loadedDefaultFactories).get(defaultFactory);
1537
- if (!loadedFactory) {
1538
- loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
1539
- (f) => toInternalServiceFactory(typeof f === "function" ? f() : f)
1540
- );
1541
- __privateGet$7(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
1542
- }
1543
- resolvedFactory = loadedFactory.catch((error) => {
1544
- throw new Error(
1545
- `Failed to instantiate service '${ref.id}' because the default factory loader threw an error, ${errors.stringifyError(
1546
- error
1547
- )}`
1548
- );
1549
- });
1550
- }
1551
- return Promise.resolve(resolvedFactory);
1552
- };
1553
- _checkForMissingDeps = new WeakSet();
1554
- checkForMissingDeps_fn = function(factory, pluginId) {
1555
- const missingDeps = Object.values(factory.deps).filter((ref) => {
1556
- if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
1557
- return false;
1558
- }
1559
- if (__privateGet$7(this, _providedFactories).get(ref.id)) {
1560
- return false;
1561
- }
1562
- return !ref.__defaultFactory;
1563
- });
1564
- if (missingDeps.length) {
1565
- const missing = missingDeps.map((r) => `'${r.id}'`).join(", ");
1566
- throw new Error(
1567
- `Failed to instantiate service '${factory.service.id}' for '${pluginId}' because the following dependent services are missing: ${missing}`
1568
- );
1569
- }
1570
- };
1571
- let ServiceRegistry = _ServiceRegistry;
1252
+ }
1572
1253
 
1573
1254
  const LOGGER_INTERVAL_MAX = 6e4;
1574
1255
  function joinIds(ids) {
1575
1256
  return [...ids].map((id) => `'${id}'`).join(", ");
1576
1257
  }
1577
1258
  function createInitializationLogger(pluginIds, rootLogger) {
1578
- const logger = rootLogger == null ? void 0 : rootLogger.child({ type: "initialization" });
1259
+ const logger = rootLogger?.child({ type: "initialization" });
1579
1260
  const starting = new Set(pluginIds);
1580
1261
  const started = /* @__PURE__ */ new Set();
1581
- logger == null ? void 0 : logger.info(`Plugin initialization started: ${joinIds(pluginIds)}`);
1262
+ logger?.info(`Plugin initialization started: ${joinIds(pluginIds)}`);
1582
1263
  const getInitStatus = () => {
1583
1264
  let status = "";
1584
1265
  if (started.size > 0) {
@@ -1594,7 +1275,7 @@ function createInitializationLogger(pluginIds, rootLogger) {
1594
1275
  let prevInterval = 0;
1595
1276
  let timeout;
1596
1277
  const onTimeout = () => {
1597
- logger == null ? void 0 : logger.info(`Plugin initialization in progress${getInitStatus()}`);
1278
+ logger?.info(`Plugin initialization in progress${getInitStatus()}`);
1598
1279
  const nextInterval = Math.min(interval + prevInterval, LOGGER_INTERVAL_MAX);
1599
1280
  prevInterval = interval;
1600
1281
  interval = nextInterval;
@@ -1607,7 +1288,7 @@ function createInitializationLogger(pluginIds, rootLogger) {
1607
1288
  started.add(pluginId);
1608
1289
  },
1609
1290
  onAllStarted() {
1610
- logger == null ? void 0 : logger.info(`Plugin initialization complete${getInitStatus()}`);
1291
+ logger?.info(`Plugin initialization complete${getInitStatus()}`);
1611
1292
  if (timeout) {
1612
1293
  clearTimeout(timeout);
1613
1294
  timeout = void 0;
@@ -1616,52 +1297,76 @@ function createInitializationLogger(pluginIds, rootLogger) {
1616
1297
  };
1617
1298
  }
1618
1299
 
1619
- var __accessCheck$8 = (obj, member, msg) => {
1620
- if (!member.has(obj))
1621
- throw TypeError("Cannot " + msg);
1622
- };
1623
- var __privateGet$6 = (obj, member, getter) => {
1624
- __accessCheck$8(obj, member, "read from private field");
1625
- return member.get(obj);
1626
- };
1627
- var __privateAdd$8 = (obj, member, value) => {
1628
- if (member.has(obj))
1629
- throw TypeError("Cannot add the same private member more than once");
1630
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1631
- };
1632
- var __privateSet$4 = (obj, member, value, setter) => {
1633
- __accessCheck$8(obj, member, "write to private field");
1634
- member.set(obj, value);
1635
- return value;
1636
- };
1637
- var __privateMethod$5 = (obj, member, method) => {
1638
- __accessCheck$8(obj, member, "access private method");
1639
- return method;
1640
- };
1641
- var _startPromise, _features, _extensionPoints, _serviceRegistry, _registeredFeatures, _getInitDeps, getInitDeps_fn, _addFeature, addFeature_fn, _doStart, doStart_fn, _getRootLifecycleImpl, getRootLifecycleImpl_fn, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn;
1642
1300
  class BackendInitializer {
1301
+ #startPromise;
1302
+ #features = new Array();
1303
+ #extensionPoints = /* @__PURE__ */ new Map();
1304
+ #serviceRegistry;
1305
+ #registeredFeatures = new Array();
1643
1306
  constructor(defaultApiFactories) {
1644
- __privateAdd$8(this, _getInitDeps);
1645
- __privateAdd$8(this, _addFeature);
1646
- __privateAdd$8(this, _doStart);
1647
- // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this
1648
- __privateAdd$8(this, _getRootLifecycleImpl);
1649
- __privateAdd$8(this, _getPluginLifecycleImpl);
1650
- __privateAdd$8(this, _startPromise, void 0);
1651
- __privateAdd$8(this, _features, new Array());
1652
- __privateAdd$8(this, _extensionPoints, /* @__PURE__ */ new Map());
1653
- __privateAdd$8(this, _serviceRegistry, void 0);
1654
- __privateAdd$8(this, _registeredFeatures, new Array());
1655
- __privateSet$4(this, _serviceRegistry, ServiceRegistry.create([...defaultApiFactories]));
1307
+ this.#serviceRegistry = ServiceRegistry.create([...defaultApiFactories]);
1308
+ }
1309
+ async #getInitDeps(deps, pluginId, moduleId) {
1310
+ const result = /* @__PURE__ */ new Map();
1311
+ const missingRefs = /* @__PURE__ */ new Set();
1312
+ for (const [name, ref] of Object.entries(deps)) {
1313
+ const ep = this.#extensionPoints.get(ref.id);
1314
+ if (ep) {
1315
+ if (ep.pluginId !== pluginId) {
1316
+ throw new Error(
1317
+ `Illegal dependency: Module '${moduleId}' for plugin '${pluginId}' attempted to depend on extension point '${ref.id}' for plugin '${ep.pluginId}'. Extension points can only be used within their plugin's scope.`
1318
+ );
1319
+ }
1320
+ result.set(name, ep.impl);
1321
+ } else {
1322
+ const impl = await this.#serviceRegistry.get(
1323
+ ref,
1324
+ pluginId
1325
+ );
1326
+ if (impl) {
1327
+ result.set(name, impl);
1328
+ } else {
1329
+ missingRefs.add(ref);
1330
+ }
1331
+ }
1332
+ }
1333
+ if (missingRefs.size > 0) {
1334
+ const missing = Array.from(missingRefs).join(", ");
1335
+ throw new Error(
1336
+ `No extension point or service available for the following ref(s): ${missing}`
1337
+ );
1338
+ }
1339
+ return Object.fromEntries(result);
1656
1340
  }
1657
1341
  add(feature) {
1658
- if (__privateGet$6(this, _startPromise)) {
1342
+ if (this.#startPromise) {
1659
1343
  throw new Error("feature can not be added after the backend has started");
1660
1344
  }
1661
- __privateGet$6(this, _registeredFeatures).push(Promise.resolve(feature));
1345
+ this.#registeredFeatures.push(Promise.resolve(feature));
1346
+ }
1347
+ #addFeature(feature) {
1348
+ if (feature.$$type !== "@backstage/BackendFeature") {
1349
+ throw new Error(
1350
+ `Failed to add feature, invalid type '${feature.$$type}'`
1351
+ );
1352
+ }
1353
+ if (isServiceFactory(feature)) {
1354
+ this.#serviceRegistry.add(feature);
1355
+ } else if (isInternalBackendFeature(feature)) {
1356
+ if (feature.version !== "v1") {
1357
+ throw new Error(
1358
+ `Failed to add feature, invalid version '${feature.version}'`
1359
+ );
1360
+ }
1361
+ this.#features.push(feature);
1362
+ } else {
1363
+ throw new Error(
1364
+ `Failed to add feature, invalid feature ${JSON.stringify(feature)}`
1365
+ );
1366
+ }
1662
1367
  }
1663
1368
  async start() {
1664
- if (__privateGet$6(this, _startPromise)) {
1369
+ if (this.#startPromise) {
1665
1370
  throw new Error("Backend has already started");
1666
1371
  }
1667
1372
  const exitHandler = async () => {
@@ -1679,242 +1384,187 @@ class BackendInitializer {
1679
1384
  process.addListener("SIGTERM", exitHandler);
1680
1385
  process.addListener("SIGINT", exitHandler);
1681
1386
  process.addListener("beforeExit", exitHandler);
1682
- __privateSet$4(this, _startPromise, __privateMethod$5(this, _doStart, doStart_fn).call(this));
1683
- await __privateGet$6(this, _startPromise);
1387
+ this.#startPromise = this.#doStart();
1388
+ await this.#startPromise;
1684
1389
  }
1685
- async stop() {
1686
- if (!__privateGet$6(this, _startPromise)) {
1687
- return;
1390
+ async #doStart() {
1391
+ this.#serviceRegistry.checkForCircularDeps();
1392
+ for (const feature of this.#registeredFeatures) {
1393
+ this.#addFeature(await feature);
1688
1394
  }
1689
- try {
1690
- await __privateGet$6(this, _startPromise);
1691
- } catch (error) {
1692
- }
1693
- const lifecycleService = await __privateMethod$5(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1694
- await lifecycleService.shutdown();
1695
- }
1696
- }
1697
- _startPromise = new WeakMap();
1698
- _features = new WeakMap();
1699
- _extensionPoints = new WeakMap();
1700
- _serviceRegistry = new WeakMap();
1701
- _registeredFeatures = new WeakMap();
1702
- _getInitDeps = new WeakSet();
1703
- getInitDeps_fn = async function(deps, pluginId, moduleId) {
1704
- const result = /* @__PURE__ */ new Map();
1705
- const missingRefs = /* @__PURE__ */ new Set();
1706
- for (const [name, ref] of Object.entries(deps)) {
1707
- const ep = __privateGet$6(this, _extensionPoints).get(ref.id);
1708
- if (ep) {
1709
- if (ep.pluginId !== pluginId) {
1710
- throw new Error(
1711
- `Illegal dependency: Module '${moduleId}' for plugin '${pluginId}' attempted to depend on extension point '${ref.id}' for plugin '${ep.pluginId}'. Extension points can only be used within their plugin's scope.`
1712
- );
1395
+ const featureDiscovery = await this.#serviceRegistry.get(
1396
+ alpha.featureDiscoveryServiceRef,
1397
+ "root"
1398
+ );
1399
+ if (featureDiscovery) {
1400
+ const { features } = await featureDiscovery.getBackendFeatures();
1401
+ for (const feature of features) {
1402
+ this.#addFeature(feature);
1713
1403
  }
1714
- result.set(name, ep.impl);
1715
- } else {
1716
- const impl = await __privateGet$6(this, _serviceRegistry).get(
1717
- ref,
1718
- pluginId
1719
- );
1720
- if (impl) {
1721
- result.set(name, impl);
1722
- } else {
1723
- missingRefs.add(ref);
1724
- }
1725
- }
1726
- }
1727
- if (missingRefs.size > 0) {
1728
- const missing = Array.from(missingRefs).join(", ");
1729
- throw new Error(
1730
- `No extension point or service available for the following ref(s): ${missing}`
1731
- );
1732
- }
1733
- return Object.fromEntries(result);
1734
- };
1735
- _addFeature = new WeakSet();
1736
- addFeature_fn = function(feature) {
1737
- if (feature.$$type !== "@backstage/BackendFeature") {
1738
- throw new Error(
1739
- `Failed to add feature, invalid type '${feature.$$type}'`
1740
- );
1741
- }
1742
- if (isServiceFactory(feature)) {
1743
- __privateGet$6(this, _serviceRegistry).add(feature);
1744
- } else if (isInternalBackendFeature(feature)) {
1745
- if (feature.version !== "v1") {
1746
- throw new Error(
1747
- `Failed to add feature, invalid version '${feature.version}'`
1748
- );
1749
- }
1750
- __privateGet$6(this, _features).push(feature);
1751
- } else {
1752
- throw new Error(
1753
- `Failed to add feature, invalid feature ${JSON.stringify(feature)}`
1754
- );
1755
- }
1756
- };
1757
- _doStart = new WeakSet();
1758
- doStart_fn = async function() {
1759
- __privateGet$6(this, _serviceRegistry).checkForCircularDeps();
1760
- for (const feature of __privateGet$6(this, _registeredFeatures)) {
1761
- __privateMethod$5(this, _addFeature, addFeature_fn).call(this, await feature);
1762
- }
1763
- const featureDiscovery = await __privateGet$6(this, _serviceRegistry).get(
1764
- alpha.featureDiscoveryServiceRef,
1765
- "root"
1766
- );
1767
- if (featureDiscovery) {
1768
- const { features } = await featureDiscovery.getBackendFeatures();
1769
- for (const feature of features) {
1770
- __privateMethod$5(this, _addFeature, addFeature_fn).call(this, feature);
1771
- }
1772
- __privateGet$6(this, _serviceRegistry).checkForCircularDeps();
1773
- }
1774
- await __privateGet$6(this, _serviceRegistry).initializeEagerServicesWithScope("root");
1775
- const pluginInits = /* @__PURE__ */ new Map();
1776
- const moduleInits = /* @__PURE__ */ new Map();
1777
- for (const feature of __privateGet$6(this, _features)) {
1778
- for (const r of feature.getRegistrations()) {
1779
- const provides = /* @__PURE__ */ new Set();
1780
- if (r.type === "plugin" || r.type === "module") {
1781
- for (const [extRef, extImpl] of r.extensionPoints) {
1782
- if (__privateGet$6(this, _extensionPoints).has(extRef.id)) {
1404
+ this.#serviceRegistry.checkForCircularDeps();
1405
+ }
1406
+ await this.#serviceRegistry.initializeEagerServicesWithScope("root");
1407
+ const pluginInits = /* @__PURE__ */ new Map();
1408
+ const moduleInits = /* @__PURE__ */ new Map();
1409
+ for (const feature of this.#features) {
1410
+ for (const r of feature.getRegistrations()) {
1411
+ const provides = /* @__PURE__ */ new Set();
1412
+ if (r.type === "plugin" || r.type === "module") {
1413
+ for (const [extRef, extImpl] of r.extensionPoints) {
1414
+ if (this.#extensionPoints.has(extRef.id)) {
1415
+ throw new Error(
1416
+ `ExtensionPoint with ID '${extRef.id}' is already registered`
1417
+ );
1418
+ }
1419
+ this.#extensionPoints.set(extRef.id, {
1420
+ impl: extImpl,
1421
+ pluginId: r.pluginId
1422
+ });
1423
+ provides.add(extRef);
1424
+ }
1425
+ }
1426
+ if (r.type === "plugin") {
1427
+ if (pluginInits.has(r.pluginId)) {
1428
+ throw new Error(`Plugin '${r.pluginId}' is already registered`);
1429
+ }
1430
+ pluginInits.set(r.pluginId, {
1431
+ provides,
1432
+ consumes: new Set(Object.values(r.init.deps)),
1433
+ init: r.init
1434
+ });
1435
+ } else {
1436
+ let modules = moduleInits.get(r.pluginId);
1437
+ if (!modules) {
1438
+ modules = /* @__PURE__ */ new Map();
1439
+ moduleInits.set(r.pluginId, modules);
1440
+ }
1441
+ if (modules.has(r.moduleId)) {
1783
1442
  throw new Error(
1784
- `ExtensionPoint with ID '${extRef.id}' is already registered`
1443
+ `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`
1785
1444
  );
1786
1445
  }
1787
- __privateGet$6(this, _extensionPoints).set(extRef.id, {
1788
- impl: extImpl,
1789
- pluginId: r.pluginId
1446
+ modules.set(r.moduleId, {
1447
+ provides,
1448
+ consumes: new Set(Object.values(r.init.deps)),
1449
+ init: r.init
1790
1450
  });
1791
- provides.add(extRef);
1792
1451
  }
1793
1452
  }
1794
- if (r.type === "plugin") {
1795
- if (pluginInits.has(r.pluginId)) {
1796
- throw new Error(`Plugin '${r.pluginId}' is already registered`);
1797
- }
1798
- pluginInits.set(r.pluginId, {
1799
- provides,
1800
- consumes: new Set(Object.values(r.init.deps)),
1801
- init: r.init
1802
- });
1803
- } else {
1804
- let modules = moduleInits.get(r.pluginId);
1805
- if (!modules) {
1806
- modules = /* @__PURE__ */ new Map();
1807
- moduleInits.set(r.pluginId, modules);
1808
- }
1809
- if (modules.has(r.moduleId)) {
1810
- throw new Error(
1811
- `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`
1812
- );
1813
- }
1814
- modules.set(r.moduleId, {
1815
- provides,
1816
- consumes: new Set(Object.values(r.init.deps)),
1817
- init: r.init
1818
- });
1819
- }
1820
1453
  }
1821
- }
1822
- const allPluginIds = [...pluginInits.keys()];
1823
- const initLogger = createInitializationLogger(
1824
- allPluginIds,
1825
- await __privateGet$6(this, _serviceRegistry).get(backendPluginApi.coreServices.rootLogger, "root")
1826
- );
1827
- await Promise.all(
1828
- allPluginIds.map(async (pluginId) => {
1829
- await __privateGet$6(this, _serviceRegistry).initializeEagerServicesWithScope(
1830
- "plugin",
1831
- pluginId
1832
- );
1833
- const modules = moduleInits.get(pluginId);
1834
- if (modules) {
1835
- const tree = DependencyGraph.fromIterable(
1836
- Array.from(modules).map(([moduleId, moduleInit]) => ({
1837
- value: { moduleId, moduleInit },
1838
- // Relationships are reversed at this point since we're only interested in the extension points.
1839
- // If a modules provides extension point A we want it to be initialized AFTER all modules
1840
- // that depend on extension point A, so that they can provide their extensions.
1841
- consumes: Array.from(moduleInit.provides).map((p) => p.id),
1842
- provides: Array.from(moduleInit.consumes).map((c) => c.id)
1843
- }))
1454
+ const allPluginIds = [...pluginInits.keys()];
1455
+ const initLogger = createInitializationLogger(
1456
+ allPluginIds,
1457
+ await this.#serviceRegistry.get(backendPluginApi.coreServices.rootLogger, "root")
1458
+ );
1459
+ await Promise.all(
1460
+ allPluginIds.map(async (pluginId) => {
1461
+ await this.#serviceRegistry.initializeEagerServicesWithScope(
1462
+ "plugin",
1463
+ pluginId
1844
1464
  );
1845
- const circular = tree.detectCircularDependency();
1846
- if (circular) {
1847
- throw new errors.ConflictError(
1848
- `Circular dependency detected for modules of plugin '${pluginId}', ${circular.map(({ moduleId }) => `'${moduleId}'`).join(" -> ")}`
1465
+ const modules = moduleInits.get(pluginId);
1466
+ if (modules) {
1467
+ const tree = DependencyGraph.fromIterable(
1468
+ Array.from(modules).map(([moduleId, moduleInit]) => ({
1469
+ value: { moduleId, moduleInit },
1470
+ // Relationships are reversed at this point since we're only interested in the extension points.
1471
+ // If a modules provides extension point A we want it to be initialized AFTER all modules
1472
+ // that depend on extension point A, so that they can provide their extensions.
1473
+ consumes: Array.from(moduleInit.provides).map((p) => p.id),
1474
+ provides: Array.from(moduleInit.consumes).map((c) => c.id)
1475
+ }))
1849
1476
  );
1850
- }
1851
- await tree.parallelTopologicalTraversal(
1852
- async ({ moduleId, moduleInit }) => {
1853
- const moduleDeps = await __privateMethod$5(this, _getInitDeps, getInitDeps_fn).call(this, moduleInit.init.deps, pluginId, moduleId);
1854
- await moduleInit.init.func(moduleDeps).catch((error) => {
1855
- throw new errors.ForwardedError(
1856
- `Module '${moduleId}' for plugin '${pluginId}' startup failed`,
1857
- error
1858
- );
1859
- });
1477
+ const circular = tree.detectCircularDependency();
1478
+ if (circular) {
1479
+ throw new errors.ConflictError(
1480
+ `Circular dependency detected for modules of plugin '${pluginId}', ${circular.map(({ moduleId }) => `'${moduleId}'`).join(" -> ")}`
1481
+ );
1860
1482
  }
1861
- );
1862
- }
1863
- const pluginInit = pluginInits.get(pluginId);
1864
- if (pluginInit) {
1865
- const pluginDeps = await __privateMethod$5(this, _getInitDeps, getInitDeps_fn).call(this, pluginInit.init.deps, pluginId);
1866
- await pluginInit.init.func(pluginDeps).catch((error) => {
1867
- throw new errors.ForwardedError(
1868
- `Plugin '${pluginId}' startup failed`,
1869
- error
1483
+ await tree.parallelTopologicalTraversal(
1484
+ async ({ moduleId, moduleInit }) => {
1485
+ const moduleDeps = await this.#getInitDeps(
1486
+ moduleInit.init.deps,
1487
+ pluginId,
1488
+ moduleId
1489
+ );
1490
+ await moduleInit.init.func(moduleDeps).catch((error) => {
1491
+ throw new errors.ForwardedError(
1492
+ `Module '${moduleId}' for plugin '${pluginId}' startup failed`,
1493
+ error
1494
+ );
1495
+ });
1496
+ }
1870
1497
  );
1871
- });
1872
- }
1873
- initLogger.onPluginStarted(pluginId);
1874
- const lifecycleService2 = await __privateMethod$5(this, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn).call(this, pluginId);
1875
- await lifecycleService2.startup();
1876
- })
1877
- );
1878
- const lifecycleService = await __privateMethod$5(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1879
- await lifecycleService.startup();
1880
- initLogger.onAllStarted();
1881
- if (process.env.NODE_ENV !== "test") {
1882
- const rootLogger = await __privateGet$6(this, _serviceRegistry).get(
1883
- backendPluginApi.coreServices.rootLogger,
1884
- "root"
1498
+ }
1499
+ const pluginInit = pluginInits.get(pluginId);
1500
+ if (pluginInit) {
1501
+ const pluginDeps = await this.#getInitDeps(
1502
+ pluginInit.init.deps,
1503
+ pluginId
1504
+ );
1505
+ await pluginInit.init.func(pluginDeps).catch((error) => {
1506
+ throw new errors.ForwardedError(
1507
+ `Plugin '${pluginId}' startup failed`,
1508
+ error
1509
+ );
1510
+ });
1511
+ }
1512
+ initLogger.onPluginStarted(pluginId);
1513
+ const lifecycleService2 = await this.#getPluginLifecycleImpl(pluginId);
1514
+ await lifecycleService2.startup();
1515
+ })
1885
1516
  );
1886
- process.on("unhandledRejection", (reason) => {
1887
- var _a;
1888
- (_a = rootLogger == null ? void 0 : rootLogger.child({ type: "unhandledRejection" })) == null ? void 0 : _a.error("Unhandled rejection", reason);
1889
- });
1890
- process.on("uncaughtException", (error) => {
1891
- var _a;
1892
- (_a = rootLogger == null ? void 0 : rootLogger.child({ type: "uncaughtException" })) == null ? void 0 : _a.error("Uncaught exception", error);
1893
- });
1517
+ const lifecycleService = await this.#getRootLifecycleImpl();
1518
+ await lifecycleService.startup();
1519
+ initLogger.onAllStarted();
1520
+ if (process.env.NODE_ENV !== "test") {
1521
+ const rootLogger = await this.#serviceRegistry.get(
1522
+ backendPluginApi.coreServices.rootLogger,
1523
+ "root"
1524
+ );
1525
+ process.on("unhandledRejection", (reason) => {
1526
+ rootLogger?.child({ type: "unhandledRejection" })?.error("Unhandled rejection", reason);
1527
+ });
1528
+ process.on("uncaughtException", (error) => {
1529
+ rootLogger?.child({ type: "uncaughtException" })?.error("Uncaught exception", error);
1530
+ });
1531
+ }
1894
1532
  }
1895
- };
1896
- _getRootLifecycleImpl = new WeakSet();
1897
- getRootLifecycleImpl_fn = async function() {
1898
- const lifecycleService = await __privateGet$6(this, _serviceRegistry).get(
1899
- backendPluginApi.coreServices.rootLifecycle,
1900
- "root"
1901
- );
1902
- if (lifecycleService instanceof BackendLifecycleImpl) {
1903
- return lifecycleService;
1533
+ async stop() {
1534
+ if (!this.#startPromise) {
1535
+ return;
1536
+ }
1537
+ try {
1538
+ await this.#startPromise;
1539
+ } catch (error) {
1540
+ }
1541
+ const lifecycleService = await this.#getRootLifecycleImpl();
1542
+ await lifecycleService.shutdown();
1904
1543
  }
1905
- throw new Error("Unexpected root lifecycle service implementation");
1906
- };
1907
- _getPluginLifecycleImpl = new WeakSet();
1908
- getPluginLifecycleImpl_fn = async function(pluginId) {
1909
- const lifecycleService = await __privateGet$6(this, _serviceRegistry).get(
1910
- backendPluginApi.coreServices.lifecycle,
1911
- pluginId
1912
- );
1913
- if (lifecycleService instanceof BackendPluginLifecycleImpl) {
1914
- return lifecycleService;
1544
+ // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this
1545
+ async #getRootLifecycleImpl() {
1546
+ const lifecycleService = await this.#serviceRegistry.get(
1547
+ backendPluginApi.coreServices.rootLifecycle,
1548
+ "root"
1549
+ );
1550
+ const service = lifecycleService;
1551
+ if (service && typeof service.startup === "function" && typeof service.shutdown === "function") {
1552
+ return service;
1553
+ }
1554
+ throw new Error("Unexpected root lifecycle service implementation");
1915
1555
  }
1916
- throw new Error("Unexpected plugin lifecycle service implementation");
1917
- };
1556
+ async #getPluginLifecycleImpl(pluginId) {
1557
+ const lifecycleService = await this.#serviceRegistry.get(
1558
+ backendPluginApi.coreServices.lifecycle,
1559
+ pluginId
1560
+ );
1561
+ const service = lifecycleService;
1562
+ if (service && typeof service.startup === "function") {
1563
+ return service;
1564
+ }
1565
+ throw new Error("Unexpected plugin lifecycle service implementation");
1566
+ }
1567
+ }
1918
1568
  function isServiceFactory(feature) {
1919
1569
  return !!feature.service;
1920
1570
  }
@@ -1922,45 +1572,25 @@ function isInternalBackendFeature(feature) {
1922
1572
  return typeof feature.getRegistrations === "function";
1923
1573
  }
1924
1574
 
1925
- var __accessCheck$7 = (obj, member, msg) => {
1926
- if (!member.has(obj))
1927
- throw TypeError("Cannot " + msg);
1928
- };
1929
- var __privateGet$5 = (obj, member, getter) => {
1930
- __accessCheck$7(obj, member, "read from private field");
1931
- return member.get(obj);
1932
- };
1933
- var __privateAdd$7 = (obj, member, value) => {
1934
- if (member.has(obj))
1935
- throw TypeError("Cannot add the same private member more than once");
1936
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1937
- };
1938
- var __privateSet$3 = (obj, member, value, setter) => {
1939
- __accessCheck$7(obj, member, "write to private field");
1940
- member.set(obj, value);
1941
- return value;
1942
- };
1943
- var _initializer;
1944
1575
  class BackstageBackend {
1576
+ #initializer;
1945
1577
  constructor(defaultServiceFactories) {
1946
- __privateAdd$7(this, _initializer, void 0);
1947
- __privateSet$3(this, _initializer, new BackendInitializer(defaultServiceFactories));
1578
+ this.#initializer = new BackendInitializer(defaultServiceFactories);
1948
1579
  }
1949
1580
  add(feature) {
1950
1581
  if (isPromise(feature)) {
1951
- __privateGet$5(this, _initializer).add(feature.then((f) => unwrapFeature(f.default)));
1582
+ this.#initializer.add(feature.then((f) => unwrapFeature(f.default)));
1952
1583
  } else {
1953
- __privateGet$5(this, _initializer).add(unwrapFeature(feature));
1584
+ this.#initializer.add(unwrapFeature(feature));
1954
1585
  }
1955
1586
  }
1956
1587
  async start() {
1957
- await __privateGet$5(this, _initializer).start();
1588
+ await this.#initializer.start();
1958
1589
  }
1959
1590
  async stop() {
1960
- await __privateGet$5(this, _initializer).stop();
1591
+ await this.#initializer.stop();
1961
1592
  }
1962
1593
  }
1963
- _initializer = new WeakMap();
1964
1594
  function isPromise(value) {
1965
1595
  return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
1966
1596
  }
@@ -2021,10 +1651,9 @@ class DatabaseKeyStore {
2021
1651
  this.logger = logger;
2022
1652
  }
2023
1653
  static async create(options) {
2024
- var _a;
2025
1654
  const { database, logger } = options;
2026
1655
  const client = await database.getClient();
2027
- if (!((_a = database.migrations) == null ? void 0 : _a.skip)) {
1656
+ if (!database.migrations?.skip) {
2028
1657
  await applyDatabaseMigrations(client);
2029
1658
  }
2030
1659
  return new DatabaseKeyStore(client, logger);
@@ -2113,20 +1742,6 @@ function toInternalBackstageCredentials(credentials) {
2113
1742
  return internalCredentials;
2114
1743
  }
2115
1744
 
2116
- var __accessCheck$6 = (obj, member, msg) => {
2117
- if (!member.has(obj))
2118
- throw TypeError("Cannot " + msg);
2119
- };
2120
- var __privateAdd$6 = (obj, member, value) => {
2121
- if (member.has(obj))
2122
- throw TypeError("Cannot add the same private member more than once");
2123
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2124
- };
2125
- var __privateMethod$4 = (obj, member, method) => {
2126
- __accessCheck$6(obj, member, "access private method");
2127
- return method;
2128
- };
2129
- var _getJwtExpiration, getJwtExpiration_fn;
2130
1745
  class DefaultAuthService {
2131
1746
  constructor(userTokenHandler, pluginTokenHandler, externalTokenHandler, tokenManager, pluginId, disableDefaultAuthPolicy, publicKeyStore) {
2132
1747
  this.userTokenHandler = userTokenHandler;
@@ -2136,7 +1751,6 @@ class DefaultAuthService {
2136
1751
  this.pluginId = pluginId;
2137
1752
  this.disableDefaultAuthPolicy = disableDefaultAuthPolicy;
2138
1753
  this.publicKeyStore = publicKeyStore;
2139
- __privateAdd$6(this, _getJwtExpiration);
2140
1754
  }
2141
1755
  // allowLimitedAccess is currently ignored, since we currently always use the full user tokens
2142
1756
  async authenticate(token) {
@@ -2154,7 +1768,7 @@ class DefaultAuthService {
2154
1768
  return createCredentialsWithUserPrincipal(
2155
1769
  userResult2.userEntityRef,
2156
1770
  pluginResult.limitedUserToken,
2157
- __privateMethod$4(this, _getJwtExpiration, getJwtExpiration_fn).call(this, pluginResult.limitedUserToken)
1771
+ this.#getJwtExpiration(pluginResult.limitedUserToken)
2158
1772
  );
2159
1773
  }
2160
1774
  return createCredentialsWithServicePrincipal(pluginResult.subject);
@@ -2164,7 +1778,7 @@ class DefaultAuthService {
2164
1778
  return createCredentialsWithUserPrincipal(
2165
1779
  userResult.userEntityRef,
2166
1780
  token,
2167
- __privateMethod$4(this, _getJwtExpiration, getJwtExpiration_fn).call(this, token)
1781
+ this.#getJwtExpiration(token)
2168
1782
  );
2169
1783
  }
2170
1784
  const externalResult = await this.externalTokenHandler.verifyToken(token);
@@ -2252,49 +1866,29 @@ class DefaultAuthService {
2252
1866
  const { keys } = await this.publicKeyStore.listKeys();
2253
1867
  return { keys: keys.map(({ key }) => key) };
2254
1868
  }
2255
- }
2256
- _getJwtExpiration = new WeakSet();
2257
- getJwtExpiration_fn = function(token) {
2258
- const { exp } = jose.decodeJwt(token);
2259
- if (!exp) {
2260
- throw new errors.AuthenticationError("User token is missing expiration");
1869
+ #getJwtExpiration(token) {
1870
+ const { exp } = jose.decodeJwt(token);
1871
+ if (!exp) {
1872
+ throw new errors.AuthenticationError("User token is missing expiration");
1873
+ }
1874
+ return new Date(exp * 1e3);
2261
1875
  }
2262
- return new Date(exp * 1e3);
2263
- };
1876
+ }
2264
1877
 
2265
- var __accessCheck$5 = (obj, member, msg) => {
2266
- if (!member.has(obj))
2267
- throw TypeError("Cannot " + msg);
2268
- };
2269
- var __privateGet$4 = (obj, member, getter) => {
2270
- __accessCheck$5(obj, member, "read from private field");
2271
- return member.get(obj);
2272
- };
2273
- var __privateAdd$5 = (obj, member, value) => {
2274
- if (member.has(obj))
2275
- throw TypeError("Cannot add the same private member more than once");
2276
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2277
- };
2278
- var __privateSet$2 = (obj, member, value, setter) => {
2279
- __accessCheck$5(obj, member, "write to private field");
2280
- member.set(obj, value);
2281
- return value;
2282
- };
2283
- var _keyStore, _keyStoreUpdated;
2284
1878
  const CLOCK_MARGIN_S = 10;
2285
1879
  class JwksClient {
2286
1880
  constructor(getEndpoint) {
2287
1881
  this.getEndpoint = getEndpoint;
2288
- __privateAdd$5(this, _keyStore, void 0);
2289
- __privateAdd$5(this, _keyStoreUpdated, 0);
2290
1882
  }
1883
+ #keyStore;
1884
+ #keyStoreUpdated = 0;
2291
1885
  get getKey() {
2292
- if (!__privateGet$4(this, _keyStore)) {
1886
+ if (!this.#keyStore) {
2293
1887
  throw new errors.AuthenticationError(
2294
1888
  "refreshKeyStore must be called before jwksClient.getKey"
2295
1889
  );
2296
1890
  }
2297
- return __privateGet$4(this, _keyStore);
1891
+ return this.#keyStore;
2298
1892
  }
2299
1893
  /**
2300
1894
  * If the last keystore refresh is stale, update the keystore URL to the latest
@@ -2304,9 +1898,9 @@ class JwksClient {
2304
1898
  const header = await jose.decodeProtectedHeader(rawJwtToken);
2305
1899
  let keyStoreHasKey;
2306
1900
  try {
2307
- if (__privateGet$4(this, _keyStore)) {
1901
+ if (this.#keyStore) {
2308
1902
  const [_, rawPayload, rawSignature] = rawJwtToken.split(".");
2309
- keyStoreHasKey = await __privateGet$4(this, _keyStore).call(this, header, {
1903
+ keyStoreHasKey = await this.#keyStore(header, {
2310
1904
  payload: rawPayload,
2311
1905
  signature: rawSignature
2312
1906
  });
@@ -2314,23 +1908,15 @@ class JwksClient {
2314
1908
  } catch (error) {
2315
1909
  keyStoreHasKey = false;
2316
1910
  }
2317
- const issuedAfterLastRefresh = (payload == null ? void 0 : payload.iat) && payload.iat > __privateGet$4(this, _keyStoreUpdated) - CLOCK_MARGIN_S;
2318
- if (!__privateGet$4(this, _keyStore) || !keyStoreHasKey && issuedAfterLastRefresh) {
1911
+ const issuedAfterLastRefresh = payload?.iat && payload.iat > this.#keyStoreUpdated - CLOCK_MARGIN_S;
1912
+ if (!this.#keyStore || !keyStoreHasKey && issuedAfterLastRefresh) {
2319
1913
  const endpoint = await this.getEndpoint();
2320
- __privateSet$2(this, _keyStore, jose.createRemoteJWKSet(endpoint));
2321
- __privateSet$2(this, _keyStoreUpdated, Date.now() / 1e3);
1914
+ this.#keyStore = jose.createRemoteJWKSet(endpoint);
1915
+ this.#keyStoreUpdated = Date.now() / 1e3;
2322
1916
  }
2323
1917
  }
2324
1918
  }
2325
- _keyStore = new WeakMap();
2326
- _keyStoreUpdated = new WeakMap();
2327
1919
 
2328
- var __defProp = Object.defineProperty;
2329
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2330
- var __publicField = (obj, key, value) => {
2331
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
2332
- return value;
2333
- };
2334
1920
  const KEY_EXPIRATION_MARGIN_FACTOR = 3;
2335
1921
  const SECONDS_IN_MS = 1e3;
2336
1922
  const ALLOWED_PLUGIN_ID_PATTERN = /^[a-z0-9_-]+$/i;
@@ -2342,21 +1928,20 @@ class PluginTokenHandler {
2342
1928
  this.keyDurationSeconds = keyDurationSeconds;
2343
1929
  this.algorithm = algorithm;
2344
1930
  this.discovery = discovery;
2345
- __publicField(this, "privateKeyPromise");
2346
- __publicField(this, "keyExpiry");
2347
- __publicField(this, "jwksMap", /* @__PURE__ */ new Map());
2348
- // Tracking state for isTargetPluginSupported
2349
- __publicField(this, "supportedTargetPlugins", /* @__PURE__ */ new Set());
2350
- __publicField(this, "targetPluginInflightChecks", /* @__PURE__ */ new Map());
2351
1931
  }
1932
+ privateKeyPromise;
1933
+ keyExpiry;
1934
+ jwksMap = /* @__PURE__ */ new Map();
1935
+ // Tracking state for isTargetPluginSupported
1936
+ supportedTargetPlugins = /* @__PURE__ */ new Set();
1937
+ targetPluginInflightChecks = /* @__PURE__ */ new Map();
2352
1938
  static create(options) {
2353
- var _a;
2354
1939
  return new PluginTokenHandler(
2355
1940
  options.logger,
2356
1941
  options.ownPluginId,
2357
1942
  options.publicKeyStore,
2358
1943
  Math.round(types.durationToMilliseconds(options.keyDuration) / 1e3),
2359
- (_a = options.algorithm) != null ? _a : "ES256",
1944
+ options.algorithm ?? "ES256",
2360
1945
  options.discovery
2361
1946
  );
2362
1947
  }
@@ -2404,7 +1989,7 @@ class PluginTokenHandler {
2404
1989
  ourExp,
2405
1990
  Math.floor(onBehalfOf.expiresAt.getTime() / SECONDS_IN_MS)
2406
1991
  ) : ourExp;
2407
- const claims = { sub, aud, iat, exp, obo: onBehalfOf == null ? void 0 : onBehalfOf.token };
1992
+ const claims = { sub, aud, iat, exp, obo: onBehalfOf?.token };
2408
1993
  const token = await new jose.SignJWT(claims).setProtectedHeader({
2409
1994
  typ: pluginAuthNode.tokenTypes.plugin.typParam,
2410
1995
  alg: this.algorithm,
@@ -2510,34 +2095,19 @@ class PluginTokenHandler {
2510
2095
  }
2511
2096
  }
2512
2097
 
2513
- var __accessCheck$4 = (obj, member, msg) => {
2514
- if (!member.has(obj))
2515
- throw TypeError("Cannot " + msg);
2516
- };
2517
- var __privateAdd$4 = (obj, member, value) => {
2518
- if (member.has(obj))
2519
- throw TypeError("Cannot add the same private member more than once");
2520
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2521
- };
2522
- var __privateMethod$3 = (obj, member, method) => {
2523
- __accessCheck$4(obj, member, "access private method");
2524
- return method;
2525
- };
2526
- var _getTokenVerificationOptions, getTokenVerificationOptions_fn;
2527
- const _UserTokenHandler = class _UserTokenHandler {
2098
+ class UserTokenHandler {
2528
2099
  constructor(jwksClient) {
2529
2100
  this.jwksClient = jwksClient;
2530
- __privateAdd$4(this, _getTokenVerificationOptions);
2531
2101
  }
2532
2102
  static create(options) {
2533
2103
  const jwksClient = new JwksClient(async () => {
2534
2104
  const url = await options.discovery.getBaseUrl("auth");
2535
2105
  return new URL(`${url}/.well-known/jwks.json`);
2536
2106
  });
2537
- return new _UserTokenHandler(jwksClient);
2107
+ return new UserTokenHandler(jwksClient);
2538
2108
  }
2539
2109
  async verifyToken(token) {
2540
- const verifyOpts = __privateMethod$3(this, _getTokenVerificationOptions, getTokenVerificationOptions_fn).call(this, token);
2110
+ const verifyOpts = this.#getTokenVerificationOptions(token);
2541
2111
  if (!verifyOpts) {
2542
2112
  return void 0;
2543
2113
  }
@@ -2555,6 +2125,31 @@ const _UserTokenHandler = class _UserTokenHandler {
2555
2125
  }
2556
2126
  return { userEntityRef };
2557
2127
  }
2128
+ #getTokenVerificationOptions(token) {
2129
+ try {
2130
+ const { typ } = jose.decodeProtectedHeader(token);
2131
+ if (typ === pluginAuthNode.tokenTypes.user.typParam) {
2132
+ return {
2133
+ requiredClaims: ["iat", "exp", "sub"],
2134
+ typ: pluginAuthNode.tokenTypes.user.typParam
2135
+ };
2136
+ }
2137
+ if (typ === pluginAuthNode.tokenTypes.limitedUser.typParam) {
2138
+ return {
2139
+ requiredClaims: ["iat", "exp", "sub"],
2140
+ typ: pluginAuthNode.tokenTypes.limitedUser.typParam
2141
+ };
2142
+ }
2143
+ const { aud } = jose.decodeJwt(token);
2144
+ if (aud === pluginAuthNode.tokenTypes.user.audClaim) {
2145
+ return {
2146
+ audience: pluginAuthNode.tokenTypes.user.audClaim
2147
+ };
2148
+ }
2149
+ } catch {
2150
+ }
2151
+ return void 0;
2152
+ }
2558
2153
  createLimitedUserToken(backstageToken) {
2559
2154
  const [headerRaw, payloadRaw] = backstageToken.split(".");
2560
2155
  const header = JSON.parse(
@@ -2600,64 +2195,31 @@ const _UserTokenHandler = class _UserTokenHandler {
2600
2195
  return false;
2601
2196
  }
2602
2197
  }
2603
- };
2604
- _getTokenVerificationOptions = new WeakSet();
2605
- getTokenVerificationOptions_fn = function(token) {
2606
- try {
2607
- const { typ } = jose.decodeProtectedHeader(token);
2608
- if (typ === pluginAuthNode.tokenTypes.user.typParam) {
2609
- return {
2610
- requiredClaims: ["iat", "exp", "sub"],
2611
- typ: pluginAuthNode.tokenTypes.user.typParam
2612
- };
2613
- }
2614
- if (typ === pluginAuthNode.tokenTypes.limitedUser.typParam) {
2615
- return {
2616
- requiredClaims: ["iat", "exp", "sub"],
2617
- typ: pluginAuthNode.tokenTypes.limitedUser.typParam
2618
- };
2619
- }
2620
- const { aud } = jose.decodeJwt(token);
2621
- if (aud === pluginAuthNode.tokenTypes.user.audClaim) {
2622
- return {
2623
- audience: pluginAuthNode.tokenTypes.user.audClaim
2624
- };
2625
- }
2626
- } catch {
2627
- }
2628
- return void 0;
2629
- };
2630
- let UserTokenHandler = _UserTokenHandler;
2198
+ }
2631
2199
 
2632
- var __accessCheck$3 = (obj, member, msg) => {
2633
- if (!member.has(obj))
2634
- throw TypeError("Cannot " + msg);
2635
- };
2636
- var __privateGet$3 = (obj, member, getter) => {
2637
- __accessCheck$3(obj, member, "read from private field");
2638
- return member.get(obj);
2639
- };
2640
- var __privateAdd$3 = (obj, member, value) => {
2641
- if (member.has(obj))
2642
- throw TypeError("Cannot add the same private member more than once");
2643
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2644
- };
2645
- var __privateMethod$2 = (obj, member, method) => {
2646
- __accessCheck$3(obj, member, "access private method");
2647
- return method;
2648
- };
2649
- var _entries$1, _doAdd, doAdd_fn;
2650
2200
  class LegacyTokenHandler {
2651
- constructor() {
2652
- __privateAdd$3(this, _doAdd);
2653
- __privateAdd$3(this, _entries$1, []);
2654
- }
2201
+ #entries = [];
2655
2202
  add(options) {
2656
- __privateMethod$2(this, _doAdd, doAdd_fn).call(this, options.getString("secret"), options.getString("subject"));
2203
+ this.#doAdd(options.getString("secret"), options.getString("subject"));
2657
2204
  }
2658
2205
  // used only for the old backend.auth.keys array
2659
2206
  addOld(options) {
2660
- __privateMethod$2(this, _doAdd, doAdd_fn).call(this, options.getString("secret"), "external:backstage-plugin");
2207
+ this.#doAdd(options.getString("secret"), "external:backstage-plugin");
2208
+ }
2209
+ #doAdd(secret, subject) {
2210
+ if (!secret.match(/^\S+$/)) {
2211
+ throw new Error("Illegal secret, must be a valid base64 string");
2212
+ }
2213
+ let key;
2214
+ try {
2215
+ key = jose.base64url.decode(secret);
2216
+ } catch {
2217
+ throw new Error("Illegal secret, must be a valid base64 string");
2218
+ }
2219
+ if (!subject.match(/^\S+$/)) {
2220
+ throw new Error("Illegal subject, must be a set of non-space characters");
2221
+ }
2222
+ this.#entries.push({ key, subject });
2661
2223
  }
2662
2224
  async verifyToken(token) {
2663
2225
  try {
@@ -2672,7 +2234,7 @@ class LegacyTokenHandler {
2672
2234
  } catch (e) {
2673
2235
  return void 0;
2674
2236
  }
2675
- for (const entry of __privateGet$3(this, _entries$1)) {
2237
+ for (const entry of this.#entries) {
2676
2238
  try {
2677
2239
  await jose.jwtVerify(token, entry.key);
2678
2240
  return { subject: entry.subject };
@@ -2685,43 +2247,10 @@ class LegacyTokenHandler {
2685
2247
  return void 0;
2686
2248
  }
2687
2249
  }
2688
- _entries$1 = new WeakMap();
2689
- _doAdd = new WeakSet();
2690
- doAdd_fn = function(secret, subject) {
2691
- if (!secret.match(/^\S+$/)) {
2692
- throw new Error("Illegal secret, must be a valid base64 string");
2693
- }
2694
- let key;
2695
- try {
2696
- key = jose.base64url.decode(secret);
2697
- } catch {
2698
- throw new Error("Illegal secret, must be a valid base64 string");
2699
- }
2700
- if (!subject.match(/^\S+$/)) {
2701
- throw new Error("Illegal subject, must be a set of non-space characters");
2702
- }
2703
- __privateGet$3(this, _entries$1).push({ key, subject });
2704
- };
2705
2250
 
2706
- var __accessCheck$2 = (obj, member, msg) => {
2707
- if (!member.has(obj))
2708
- throw TypeError("Cannot " + msg);
2709
- };
2710
- var __privateGet$2 = (obj, member, getter) => {
2711
- __accessCheck$2(obj, member, "read from private field");
2712
- return member.get(obj);
2713
- };
2714
- var __privateAdd$2 = (obj, member, value) => {
2715
- if (member.has(obj))
2716
- throw TypeError("Cannot add the same private member more than once");
2717
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2718
- };
2719
- var _entries;
2720
2251
  const MIN_TOKEN_LENGTH = 8;
2721
2252
  class StaticTokenHandler {
2722
- constructor() {
2723
- __privateAdd$2(this, _entries, []);
2724
- }
2253
+ #entries = [];
2725
2254
  add(options) {
2726
2255
  const token = options.getString("token");
2727
2256
  if (!token.match(/^\S+$/)) {
@@ -2736,17 +2265,16 @@ class StaticTokenHandler {
2736
2265
  if (!subject.match(/^\S+$/)) {
2737
2266
  throw new Error("Illegal subject, must be a set of non-space characters");
2738
2267
  }
2739
- __privateGet$2(this, _entries).push({ token, subject });
2268
+ this.#entries.push({ token, subject });
2740
2269
  }
2741
2270
  async verifyToken(token) {
2742
- const entry = __privateGet$2(this, _entries).find((e) => e.token === token);
2271
+ const entry = this.#entries.find((e) => e.token === token);
2743
2272
  if (!entry) {
2744
2273
  return void 0;
2745
2274
  }
2746
2275
  return { subject: entry.subject };
2747
2276
  }
2748
2277
  }
2749
- _entries = new WeakMap();
2750
2278
 
2751
2279
  const NEW_CONFIG_KEY = "backend.auth.externalAccess";
2752
2280
  const OLD_CONFIG_KEY = "backend.auth.keys";
@@ -2755,7 +2283,6 @@ class ExternalTokenHandler {
2755
2283
  this.handlers = handlers;
2756
2284
  }
2757
2285
  static create(options) {
2758
- var _a, _b;
2759
2286
  const { config, logger } = options;
2760
2287
  const staticHandler = new StaticTokenHandler();
2761
2288
  const legacyHandler = new LegacyTokenHandler();
@@ -2763,7 +2290,7 @@ class ExternalTokenHandler {
2763
2290
  static: staticHandler,
2764
2291
  legacy: legacyHandler
2765
2292
  };
2766
- const handlerConfigs = (_a = config.getOptionalConfigArray(NEW_CONFIG_KEY)) != null ? _a : [];
2293
+ const handlerConfigs = config.getOptionalConfigArray(NEW_CONFIG_KEY) ?? [];
2767
2294
  for (const handlerConfig of handlerConfigs) {
2768
2295
  const type = handlerConfig.getString("type");
2769
2296
  const handler = handlers[type];
@@ -2775,7 +2302,7 @@ class ExternalTokenHandler {
2775
2302
  }
2776
2303
  handler.add(handlerConfig.getConfig("options"));
2777
2304
  }
2778
- const legacyConfigs = (_b = config.getOptionalConfigArray(OLD_CONFIG_KEY)) != null ? _b : [];
2305
+ const legacyConfigs = config.getOptionalConfigArray(OLD_CONFIG_KEY) ?? [];
2779
2306
  if (legacyConfigs.length) {
2780
2307
  logger.warn(
2781
2308
  `DEPRECATION WARNING: The ${OLD_CONFIG_KEY} config has been replaced by ${NEW_CONFIG_KEY}, see https://backstage.io/docs/auth/service-to-service-auth`
@@ -2856,10 +2383,11 @@ const cacheServiceFactory = backendPluginApi.createServiceFactory({
2856
2383
  service: backendPluginApi.coreServices.cache,
2857
2384
  deps: {
2858
2385
  config: backendPluginApi.coreServices.rootConfig,
2386
+ logger: backendPluginApi.coreServices.rootLogger,
2859
2387
  plugin: backendPluginApi.coreServices.pluginMetadata
2860
2388
  },
2861
- async createRootContext({ config }) {
2862
- return backendCommon.CacheManager.fromConfig(config);
2389
+ async createRootContext({ config, logger }) {
2390
+ return backendCommon.CacheManager.fromConfig(config, { logger });
2863
2391
  },
2864
2392
  async factory({ plugin }, manager) {
2865
2393
  return manager.forPlugin(plugin.getId()).getClient();
@@ -2872,9 +2400,9 @@ const rootConfigServiceFactory = backendPluginApi.createServiceFactory(
2872
2400
  deps: {},
2873
2401
  async factory() {
2874
2402
  const source = configLoader.ConfigSources.default({
2875
- argv: options == null ? void 0 : options.argv,
2876
- remote: options == null ? void 0 : options.remote,
2877
- watch: options == null ? void 0 : options.watch
2403
+ argv: options?.argv,
2404
+ remote: options?.remote,
2405
+ watch: options?.watch
2878
2406
  });
2879
2407
  console.log(`Loading config from ${source}`);
2880
2408
  return await configLoader.ConfigSources.toConfig(source);
@@ -2937,8 +2465,7 @@ class HostDiscovery {
2937
2465
  * path for the `catalog` plugin will be `http://localhost:7007/api/catalog`.
2938
2466
  */
2939
2467
  static fromConfig(config, options) {
2940
- var _a;
2941
- const basePath = (_a = options == null ? void 0 : options.basePath) != null ? _a : "/api";
2468
+ const basePath = options?.basePath ?? "/api";
2942
2469
  const externalBaseUrl = config.getString("backend.baseUrl").replace(/\/+$/, "");
2943
2470
  const {
2944
2471
  listen: { host: listenHost = "::", port: listenPort }
@@ -2961,9 +2488,8 @@ class HostDiscovery {
2961
2488
  );
2962
2489
  }
2963
2490
  getTargetFromConfig(pluginId, type) {
2964
- var _a, _b;
2965
- const endpoints = (_a = this.discoveryConfig) == null ? void 0 : _a.getOptionalConfigArray("endpoints");
2966
- const target = (_b = endpoints == null ? void 0 : endpoints.find((endpoint) => endpoint.getStringArray("plugins").includes(pluginId))) == null ? void 0 : _b.get("target");
2491
+ const endpoints = this.discoveryConfig?.getOptionalConfigArray("endpoints");
2492
+ const target = endpoints?.find((endpoint) => endpoint.getStringArray("plugins").includes(pluginId))?.get("target");
2967
2493
  if (!target) {
2968
2494
  const baseUrl = type === "external" ? this.externalBaseUrl : this.internalBaseUrl;
2969
2495
  return `${baseUrl}/${encodeURIComponent(pluginId)}`;
@@ -2997,36 +2523,13 @@ const discoveryServiceFactory = backendPluginApi.createServiceFactory({
2997
2523
  }
2998
2524
  });
2999
2525
 
3000
- var __accessCheck$1 = (obj, member, msg) => {
3001
- if (!member.has(obj))
3002
- throw TypeError("Cannot " + msg);
3003
- };
3004
- var __privateGet$1 = (obj, member, getter) => {
3005
- __accessCheck$1(obj, member, "read from private field");
3006
- return member.get(obj);
3007
- };
3008
- var __privateAdd$1 = (obj, member, value) => {
3009
- if (member.has(obj))
3010
- throw TypeError("Cannot add the same private member more than once");
3011
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
3012
- };
3013
- var __privateSet$1 = (obj, member, value, setter) => {
3014
- __accessCheck$1(obj, member, "write to private field");
3015
- member.set(obj, value);
3016
- return value;
3017
- };
3018
- var __privateMethod$1 = (obj, member, method) => {
3019
- __accessCheck$1(obj, member, "access private method");
3020
- return method;
3021
- };
3022
- var _auth, _discovery, _pluginId, _extractCredentialsFromRequest, extractCredentialsFromRequest_fn, _extractLimitedCredentialsFromRequest, extractLimitedCredentialsFromRequest_fn, _getCredentials, getCredentials_fn, _getLimitedCredentials, getLimitedCredentials_fn, _getCookieOptions, getCookieOptions_fn, _existingCookieExpiration, existingCookieExpiration_fn;
3023
2526
  const FIVE_MINUTES_MS = 5 * 60 * 1e3;
3024
2527
  const BACKSTAGE_AUTH_COOKIE = "backstage-auth";
3025
2528
  function getTokenFromRequest(req) {
3026
2529
  const authHeader = req.headers.authorization;
3027
2530
  if (typeof authHeader === "string") {
3028
2531
  const matches = authHeader.match(/^Bearer[ ]+(\S+)$/i);
3029
- const token = matches == null ? void 0 : matches[1];
2532
+ const token = matches?.[1];
3030
2533
  if (token) {
3031
2534
  return token;
3032
2535
  }
@@ -3050,39 +2553,61 @@ function willExpireSoon(expiresAt) {
3050
2553
  const credentialsSymbol = Symbol("backstage-credentials");
3051
2554
  const limitedCredentialsSymbol = Symbol("backstage-limited-credentials");
3052
2555
  class DefaultHttpAuthService {
2556
+ #auth;
2557
+ #discovery;
2558
+ #pluginId;
3053
2559
  constructor(auth, discovery, pluginId) {
3054
- __privateAdd$1(this, _extractCredentialsFromRequest);
3055
- __privateAdd$1(this, _extractLimitedCredentialsFromRequest);
3056
- __privateAdd$1(this, _getCredentials);
3057
- __privateAdd$1(this, _getLimitedCredentials);
3058
- __privateAdd$1(this, _getCookieOptions);
3059
- __privateAdd$1(this, _existingCookieExpiration);
3060
- __privateAdd$1(this, _auth, void 0);
3061
- __privateAdd$1(this, _discovery, void 0);
3062
- __privateAdd$1(this, _pluginId, void 0);
3063
- __privateSet$1(this, _auth, auth);
3064
- __privateSet$1(this, _discovery, discovery);
3065
- __privateSet$1(this, _pluginId, pluginId);
2560
+ this.#auth = auth;
2561
+ this.#discovery = discovery;
2562
+ this.#pluginId = pluginId;
2563
+ }
2564
+ async #extractCredentialsFromRequest(req) {
2565
+ const token = getTokenFromRequest(req);
2566
+ if (!token) {
2567
+ return await this.#auth.getNoneCredentials();
2568
+ }
2569
+ return await this.#auth.authenticate(token);
2570
+ }
2571
+ async #extractLimitedCredentialsFromRequest(req) {
2572
+ const token = getTokenFromRequest(req);
2573
+ if (token) {
2574
+ return await this.#auth.authenticate(token, {
2575
+ allowLimitedAccess: true
2576
+ });
2577
+ }
2578
+ const cookie = getCookieFromRequest(req);
2579
+ if (cookie) {
2580
+ return await this.#auth.authenticate(cookie, {
2581
+ allowLimitedAccess: true
2582
+ });
2583
+ }
2584
+ return await this.#auth.getNoneCredentials();
2585
+ }
2586
+ async #getCredentials(req) {
2587
+ return req[credentialsSymbol] ??= this.#extractCredentialsFromRequest(req);
2588
+ }
2589
+ async #getLimitedCredentials(req) {
2590
+ return req[limitedCredentialsSymbol] ??= this.#extractLimitedCredentialsFromRequest(req);
3066
2591
  }
3067
2592
  async credentials(req, options) {
3068
- const credentials = (options == null ? void 0 : options.allowLimitedAccess) ? await __privateMethod$1(this, _getLimitedCredentials, getLimitedCredentials_fn).call(this, req) : await __privateMethod$1(this, _getCredentials, getCredentials_fn).call(this, req);
3069
- const allowed = options == null ? void 0 : options.allow;
2593
+ const credentials = options?.allowLimitedAccess ? await this.#getLimitedCredentials(req) : await this.#getCredentials(req);
2594
+ const allowed = options?.allow;
3070
2595
  if (!allowed) {
3071
2596
  return credentials;
3072
2597
  }
3073
- if (__privateGet$1(this, _auth).isPrincipal(credentials, "none")) {
2598
+ if (this.#auth.isPrincipal(credentials, "none")) {
3074
2599
  if (allowed.includes("none")) {
3075
2600
  return credentials;
3076
2601
  }
3077
2602
  throw new errors.AuthenticationError("Missing credentials");
3078
- } else if (__privateGet$1(this, _auth).isPrincipal(credentials, "user")) {
2603
+ } else if (this.#auth.isPrincipal(credentials, "user")) {
3079
2604
  if (allowed.includes("user")) {
3080
2605
  return credentials;
3081
2606
  }
3082
2607
  throw new errors.NotAllowedError(
3083
2608
  `This endpoint does not allow 'user' credentials`
3084
2609
  );
3085
- } else if (__privateGet$1(this, _auth).isPrincipal(credentials, "service")) {
2610
+ } else if (this.#auth.isPrincipal(credentials, "service")) {
3086
2611
  if (allowed.includes("service")) {
3087
2612
  return credentials;
3088
2613
  }
@@ -3099,15 +2624,15 @@ class DefaultHttpAuthService {
3099
2624
  throw new Error("Failed to issue user cookie, headers were already sent");
3100
2625
  }
3101
2626
  let credentials;
3102
- if (options == null ? void 0 : options.credentials) {
3103
- if (__privateGet$1(this, _auth).isPrincipal(options.credentials, "none")) {
2627
+ if (options?.credentials) {
2628
+ if (this.#auth.isPrincipal(options.credentials, "none")) {
3104
2629
  res.clearCookie(
3105
2630
  BACKSTAGE_AUTH_COOKIE,
3106
- await __privateMethod$1(this, _getCookieOptions, getCookieOptions_fn).call(this, res.req)
2631
+ await this.#getCookieOptions(res.req)
3107
2632
  );
3108
2633
  return { expiresAt: /* @__PURE__ */ new Date() };
3109
2634
  }
3110
- if (!__privateGet$1(this, _auth).isPrincipal(options.credentials, "user")) {
2635
+ if (!this.#auth.isPrincipal(options.credentials, "user")) {
3111
2636
  throw new errors.AuthenticationError(
3112
2637
  "Refused to issue cookie for non-user principal"
3113
2638
  );
@@ -3116,99 +2641,60 @@ class DefaultHttpAuthService {
3116
2641
  } else {
3117
2642
  credentials = await this.credentials(res.req, { allow: ["user"] });
3118
2643
  }
3119
- const existingExpiresAt = await __privateMethod$1(this, _existingCookieExpiration, existingCookieExpiration_fn).call(this, res.req);
2644
+ const existingExpiresAt = await this.#existingCookieExpiration(res.req);
3120
2645
  if (existingExpiresAt && !willExpireSoon(existingExpiresAt)) {
3121
2646
  return { expiresAt: existingExpiresAt };
3122
2647
  }
3123
- const { token, expiresAt } = await __privateGet$1(this, _auth).getLimitedUserToken(
2648
+ const { token, expiresAt } = await this.#auth.getLimitedUserToken(
3124
2649
  credentials
3125
2650
  );
3126
2651
  if (!token) {
3127
2652
  throw new Error("User credentials is unexpectedly missing token");
3128
2653
  }
3129
2654
  res.cookie(BACKSTAGE_AUTH_COOKIE, token, {
3130
- ...await __privateMethod$1(this, _getCookieOptions, getCookieOptions_fn).call(this, res.req),
2655
+ ...await this.#getCookieOptions(res.req),
3131
2656
  expires: expiresAt
3132
2657
  });
3133
2658
  return { expiresAt };
3134
2659
  }
3135
- }
3136
- _auth = new WeakMap();
3137
- _discovery = new WeakMap();
3138
- _pluginId = new WeakMap();
3139
- _extractCredentialsFromRequest = new WeakSet();
3140
- extractCredentialsFromRequest_fn = async function(req) {
3141
- const token = getTokenFromRequest(req);
3142
- if (!token) {
3143
- return await __privateGet$1(this, _auth).getNoneCredentials();
3144
- }
3145
- return await __privateGet$1(this, _auth).authenticate(token);
3146
- };
3147
- _extractLimitedCredentialsFromRequest = new WeakSet();
3148
- extractLimitedCredentialsFromRequest_fn = async function(req) {
3149
- const token = getTokenFromRequest(req);
3150
- if (token) {
3151
- return await __privateGet$1(this, _auth).authenticate(token, {
3152
- allowLimitedAccess: true
3153
- });
3154
- }
3155
- const cookie = getCookieFromRequest(req);
3156
- if (cookie) {
3157
- return await __privateGet$1(this, _auth).authenticate(cookie, {
3158
- allowLimitedAccess: true
3159
- });
3160
- }
3161
- return await __privateGet$1(this, _auth).getNoneCredentials();
3162
- };
3163
- _getCredentials = new WeakSet();
3164
- getCredentials_fn = async function(req) {
3165
- var _a;
3166
- return (_a = req[credentialsSymbol]) != null ? _a : req[credentialsSymbol] = __privateMethod$1(this, _extractCredentialsFromRequest, extractCredentialsFromRequest_fn).call(this, req);
3167
- };
3168
- _getLimitedCredentials = new WeakSet();
3169
- getLimitedCredentials_fn = async function(req) {
3170
- var _a;
3171
- return (_a = req[limitedCredentialsSymbol]) != null ? _a : req[limitedCredentialsSymbol] = __privateMethod$1(this, _extractLimitedCredentialsFromRequest, extractLimitedCredentialsFromRequest_fn).call(this, req);
3172
- };
3173
- _getCookieOptions = new WeakSet();
3174
- getCookieOptions_fn = async function(_req) {
3175
- const externalBaseUrlStr = await __privateGet$1(this, _discovery).getExternalBaseUrl(
3176
- __privateGet$1(this, _pluginId)
3177
- );
3178
- const externalBaseUrl = new URL(externalBaseUrlStr);
3179
- const secure = externalBaseUrl.protocol === "https:" || externalBaseUrl.hostname === "localhost";
3180
- return {
3181
- domain: externalBaseUrl.hostname,
3182
- httpOnly: true,
3183
- secure,
3184
- priority: "high",
3185
- sameSite: secure ? "none" : "lax"
3186
- };
3187
- };
3188
- _existingCookieExpiration = new WeakSet();
3189
- existingCookieExpiration_fn = async function(req) {
3190
- const existingCookie = getCookieFromRequest(req);
3191
- if (!existingCookie) {
3192
- return void 0;
3193
- }
3194
- try {
3195
- const existingCredentials = await __privateGet$1(this, _auth).authenticate(
3196
- existingCookie,
3197
- {
3198
- allowLimitedAccess: true
3199
- }
2660
+ async #getCookieOptions(_req) {
2661
+ const externalBaseUrlStr = await this.#discovery.getExternalBaseUrl(
2662
+ this.#pluginId
3200
2663
  );
3201
- if (!__privateGet$1(this, _auth).isPrincipal(existingCredentials, "user")) {
2664
+ const externalBaseUrl = new URL(externalBaseUrlStr);
2665
+ const secure = externalBaseUrl.protocol === "https:" || externalBaseUrl.hostname === "localhost";
2666
+ return {
2667
+ domain: externalBaseUrl.hostname,
2668
+ httpOnly: true,
2669
+ secure,
2670
+ priority: "high",
2671
+ sameSite: secure ? "none" : "lax"
2672
+ };
2673
+ }
2674
+ async #existingCookieExpiration(req) {
2675
+ const existingCookie = getCookieFromRequest(req);
2676
+ if (!existingCookie) {
3202
2677
  return void 0;
3203
2678
  }
3204
- return existingCredentials.expiresAt;
3205
- } catch (error) {
3206
- if (error.name === "AuthenticationError") {
3207
- return void 0;
2679
+ try {
2680
+ const existingCredentials = await this.#auth.authenticate(
2681
+ existingCookie,
2682
+ {
2683
+ allowLimitedAccess: true
2684
+ }
2685
+ );
2686
+ if (!this.#auth.isPrincipal(existingCredentials, "user")) {
2687
+ return void 0;
2688
+ }
2689
+ return existingCredentials.expiresAt;
2690
+ } catch (error) {
2691
+ if (error.name === "AuthenticationError") {
2692
+ return void 0;
2693
+ }
2694
+ throw error;
3208
2695
  }
3209
- throw error;
3210
2696
  }
3211
- };
2697
+ }
3212
2698
  const httpAuthServiceFactory = backendPluginApi.createServiceFactory({
3213
2699
  service: backendPluginApi.coreServices.httpAuth,
3214
2700
  deps: {
@@ -3368,13 +2854,12 @@ const httpRouterServiceFactory = backendPluginApi.createServiceFactory(
3368
2854
  rootHttpRouter,
3369
2855
  lifecycle
3370
2856
  }) {
3371
- var _a;
3372
- if (options == null ? void 0 : options.getPath) {
2857
+ if (options?.getPath) {
3373
2858
  logger.warn(
3374
2859
  `DEPRECATION WARNING: The 'getPath' option for HttpRouterService is deprecated. The ability to reconfigure the '/api/' path prefix for plugins will be removed in the future.`
3375
2860
  );
3376
2861
  }
3377
- const getPath = (_a = options == null ? void 0 : options.getPath) != null ? _a : (id) => `/api/${id}`;
2862
+ const getPath = options?.getPath ?? ((id) => `/api/${id}`);
3378
2863
  const path = getPath(plugin.getId());
3379
2864
  const router = Router__default.default();
3380
2865
  rootHttpRouter.use(path, router);
@@ -3410,6 +2895,63 @@ const identityServiceFactory = backendPluginApi.createServiceFactory(
3410
2895
  })
3411
2896
  );
3412
2897
 
2898
+ class BackendPluginLifecycleImpl {
2899
+ constructor(logger, rootLifecycle, pluginMetadata) {
2900
+ this.logger = logger;
2901
+ this.rootLifecycle = rootLifecycle;
2902
+ this.pluginMetadata = pluginMetadata;
2903
+ }
2904
+ #hasStarted = false;
2905
+ #startupTasks = [];
2906
+ addStartupHook(hook, options) {
2907
+ if (this.#hasStarted) {
2908
+ throw new Error("Attempted to add startup hook after startup");
2909
+ }
2910
+ this.#startupTasks.push({ hook, options });
2911
+ }
2912
+ async startup() {
2913
+ if (this.#hasStarted) {
2914
+ return;
2915
+ }
2916
+ this.#hasStarted = true;
2917
+ this.logger.debug(
2918
+ `Running ${this.#startupTasks.length} plugin startup tasks...`
2919
+ );
2920
+ await Promise.all(
2921
+ this.#startupTasks.map(async ({ hook, options }) => {
2922
+ const logger = options?.logger ?? this.logger;
2923
+ try {
2924
+ await hook();
2925
+ logger.debug(`Plugin startup hook succeeded`);
2926
+ } catch (error) {
2927
+ logger.error(`Plugin startup hook failed, ${error}`);
2928
+ }
2929
+ })
2930
+ );
2931
+ }
2932
+ addShutdownHook(hook, options) {
2933
+ const plugin = this.pluginMetadata.getId();
2934
+ this.rootLifecycle.addShutdownHook(hook, {
2935
+ logger: options?.logger?.child({ plugin }) ?? this.logger
2936
+ });
2937
+ }
2938
+ }
2939
+ const lifecycleServiceFactory = backendPluginApi.createServiceFactory({
2940
+ service: backendPluginApi.coreServices.lifecycle,
2941
+ deps: {
2942
+ logger: backendPluginApi.coreServices.logger,
2943
+ rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
2944
+ pluginMetadata: backendPluginApi.coreServices.pluginMetadata
2945
+ },
2946
+ async factory({ rootLifecycle, logger, pluginMetadata }) {
2947
+ return new BackendPluginLifecycleImpl(
2948
+ logger,
2949
+ rootLifecycle,
2950
+ pluginMetadata
2951
+ );
2952
+ }
2953
+ });
2954
+
3413
2955
  const loggerServiceFactory = backendPluginApi.createServiceFactory({
3414
2956
  service: backendPluginApi.coreServices.logger,
3415
2957
  deps: {
@@ -3438,102 +2980,71 @@ const permissionsServiceFactory = backendPluginApi.createServiceFactory({
3438
2980
  }
3439
2981
  });
3440
2982
 
3441
- var __accessCheck = (obj, member, msg) => {
3442
- if (!member.has(obj))
3443
- throw TypeError("Cannot " + msg);
3444
- };
3445
- var __privateGet = (obj, member, getter) => {
3446
- __accessCheck(obj, member, "read from private field");
3447
- return member.get(obj);
3448
- };
3449
- var __privateAdd = (obj, member, value) => {
3450
- if (member.has(obj))
3451
- throw TypeError("Cannot add the same private member more than once");
3452
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
3453
- };
3454
- var __privateSet = (obj, member, value, setter) => {
3455
- __accessCheck(obj, member, "write to private field");
3456
- member.set(obj, value);
3457
- return value;
3458
- };
3459
- var __privateMethod = (obj, member, method) => {
3460
- __accessCheck(obj, member, "access private method");
3461
- return method;
3462
- };
3463
- var _indexPath, _router, _namedRoutes, _indexRouter, _existingPaths, _findConflictingPath, findConflictingPath_fn;
3464
2983
  function normalizePath(path) {
3465
2984
  return `${trimEnd__default.default(path, "/")}/`;
3466
2985
  }
3467
- const _DefaultRootHttpRouter = class _DefaultRootHttpRouter {
3468
- constructor(indexPath) {
3469
- __privateAdd(this, _findConflictingPath);
3470
- __privateAdd(this, _indexPath, void 0);
3471
- __privateAdd(this, _router, express.Router());
3472
- __privateAdd(this, _namedRoutes, express.Router());
3473
- __privateAdd(this, _indexRouter, express.Router());
3474
- __privateAdd(this, _existingPaths, new Array());
3475
- __privateSet(this, _indexPath, indexPath);
3476
- __privateGet(this, _router).use(__privateGet(this, _namedRoutes));
3477
- __privateGet(this, _router).use("/api/", (_req, _res, next) => {
3478
- next("router");
3479
- });
3480
- if (__privateGet(this, _indexPath)) {
3481
- __privateGet(this, _router).use(__privateGet(this, _indexRouter));
3482
- }
3483
- }
2986
+ class DefaultRootHttpRouter {
2987
+ #indexPath;
2988
+ #router = express.Router();
2989
+ #namedRoutes = express.Router();
2990
+ #indexRouter = express.Router();
2991
+ #existingPaths = new Array();
3484
2992
  static create(options) {
3485
2993
  let indexPath;
3486
- if ((options == null ? void 0 : options.indexPath) === false) {
2994
+ if (options?.indexPath === false) {
3487
2995
  indexPath = void 0;
3488
- } else if ((options == null ? void 0 : options.indexPath) === void 0) {
2996
+ } else if (options?.indexPath === void 0) {
3489
2997
  indexPath = "/api/app";
3490
- } else if ((options == null ? void 0 : options.indexPath) === "") {
2998
+ } else if (options?.indexPath === "") {
3491
2999
  throw new Error("indexPath option may not be an empty string");
3492
3000
  } else {
3493
3001
  indexPath = options.indexPath;
3494
3002
  }
3495
- return new _DefaultRootHttpRouter(indexPath);
3003
+ return new DefaultRootHttpRouter(indexPath);
3004
+ }
3005
+ constructor(indexPath) {
3006
+ this.#indexPath = indexPath;
3007
+ this.#router.use(this.#namedRoutes);
3008
+ this.#router.use("/api/", (_req, _res, next) => {
3009
+ next("router");
3010
+ });
3011
+ if (this.#indexPath) {
3012
+ this.#router.use(this.#indexRouter);
3013
+ }
3496
3014
  }
3497
3015
  use(path, handler) {
3498
3016
  if (path.match(/^[/\s]*$/)) {
3499
3017
  throw new Error(`Root router path may not be empty`);
3500
3018
  }
3501
- const conflictingPath = __privateMethod(this, _findConflictingPath, findConflictingPath_fn).call(this, path);
3019
+ const conflictingPath = this.#findConflictingPath(path);
3502
3020
  if (conflictingPath) {
3503
3021
  throw new Error(
3504
3022
  `Path ${path} conflicts with the existing path ${conflictingPath}`
3505
3023
  );
3506
3024
  }
3507
- __privateGet(this, _existingPaths).push(path);
3508
- __privateGet(this, _namedRoutes).use(path, handler);
3509
- if (__privateGet(this, _indexPath) === path) {
3510
- __privateGet(this, _indexRouter).use(handler);
3025
+ this.#existingPaths.push(path);
3026
+ this.#namedRoutes.use(path, handler);
3027
+ if (this.#indexPath === path) {
3028
+ this.#indexRouter.use(handler);
3511
3029
  }
3512
3030
  }
3513
3031
  handler() {
3514
- return __privateGet(this, _router);
3515
- }
3516
- };
3517
- _indexPath = new WeakMap();
3518
- _router = new WeakMap();
3519
- _namedRoutes = new WeakMap();
3520
- _indexRouter = new WeakMap();
3521
- _existingPaths = new WeakMap();
3522
- _findConflictingPath = new WeakSet();
3523
- findConflictingPath_fn = function(newPath) {
3524
- const normalizedNewPath = normalizePath(newPath);
3525
- for (const path of __privateGet(this, _existingPaths)) {
3526
- const normalizedPath = normalizePath(path);
3527
- if (normalizedPath.startsWith(normalizedNewPath)) {
3528
- return path;
3529
- }
3530
- if (normalizedNewPath.startsWith(normalizedPath)) {
3531
- return path;
3032
+ return this.#router;
3033
+ }
3034
+ #findConflictingPath(newPath) {
3035
+ const normalizedNewPath = normalizePath(newPath);
3036
+ for (const path of this.#existingPaths) {
3037
+ const normalizedPath = normalizePath(path);
3038
+ if (normalizedPath.startsWith(normalizedNewPath)) {
3039
+ return path;
3040
+ }
3041
+ if (normalizedNewPath.startsWith(normalizedPath)) {
3042
+ return path;
3043
+ }
3532
3044
  }
3045
+ return void 0;
3533
3046
  }
3534
- return void 0;
3535
- };
3536
- let DefaultRootHttpRouter = _DefaultRootHttpRouter;
3047
+ }
3537
3048
 
3538
3049
  function defaultConfigure({ applyDefaults }) {
3539
3050
  applyDefaults();
@@ -3547,7 +3058,7 @@ const rootHttpRouterServiceFactory = backendPluginApi.createServiceFactory(
3547
3058
  lifecycle: backendPluginApi.coreServices.rootLifecycle
3548
3059
  },
3549
3060
  async factory({ config, rootLogger, lifecycle }) {
3550
- const { indexPath, configure = defaultConfigure } = options != null ? options : {};
3061
+ const { indexPath, configure = defaultConfigure } = options ?? {};
3551
3062
  const logger = rootLogger.child({ service: "rootHttpRouter" });
3552
3063
  const app = express__default.default();
3553
3064
  const router = DefaultRootHttpRouter.create({ indexPath });
@@ -3583,13 +3094,81 @@ const rootHttpRouterServiceFactory = backendPluginApi.createServiceFactory(
3583
3094
  })
3584
3095
  );
3585
3096
 
3097
+ class BackendLifecycleImpl {
3098
+ constructor(logger) {
3099
+ this.logger = logger;
3100
+ }
3101
+ #hasStarted = false;
3102
+ #startupTasks = [];
3103
+ addStartupHook(hook, options) {
3104
+ if (this.#hasStarted) {
3105
+ throw new Error("Attempted to add startup hook after startup");
3106
+ }
3107
+ this.#startupTasks.push({ hook, options });
3108
+ }
3109
+ async startup() {
3110
+ if (this.#hasStarted) {
3111
+ return;
3112
+ }
3113
+ this.#hasStarted = true;
3114
+ this.logger.debug(`Running ${this.#startupTasks.length} startup tasks...`);
3115
+ await Promise.all(
3116
+ this.#startupTasks.map(async ({ hook, options }) => {
3117
+ const logger = options?.logger ?? this.logger;
3118
+ try {
3119
+ await hook();
3120
+ logger.debug(`Startup hook succeeded`);
3121
+ } catch (error) {
3122
+ logger.error(`Startup hook failed, ${error}`);
3123
+ }
3124
+ })
3125
+ );
3126
+ }
3127
+ #hasShutdown = false;
3128
+ #shutdownTasks = [];
3129
+ addShutdownHook(hook, options) {
3130
+ if (this.#hasShutdown) {
3131
+ throw new Error("Attempted to add shutdown hook after shutdown");
3132
+ }
3133
+ this.#shutdownTasks.push({ hook, options });
3134
+ }
3135
+ async shutdown() {
3136
+ if (this.#hasShutdown) {
3137
+ return;
3138
+ }
3139
+ this.#hasShutdown = true;
3140
+ this.logger.debug(
3141
+ `Running ${this.#shutdownTasks.length} shutdown tasks...`
3142
+ );
3143
+ await Promise.all(
3144
+ this.#shutdownTasks.map(async ({ hook, options }) => {
3145
+ const logger = options?.logger ?? this.logger;
3146
+ try {
3147
+ await hook();
3148
+ logger.debug(`Shutdown hook succeeded`);
3149
+ } catch (error) {
3150
+ logger.error(`Shutdown hook failed, ${error}`);
3151
+ }
3152
+ })
3153
+ );
3154
+ }
3155
+ }
3156
+ const rootLifecycleServiceFactory = backendPluginApi.createServiceFactory({
3157
+ service: backendPluginApi.coreServices.rootLifecycle,
3158
+ deps: {
3159
+ logger: backendPluginApi.coreServices.rootLogger
3160
+ },
3161
+ async factory({ logger }) {
3162
+ return new BackendLifecycleImpl(logger);
3163
+ }
3164
+ });
3165
+
3586
3166
  const rootLoggerServiceFactory = backendPluginApi.createServiceFactory({
3587
3167
  service: backendPluginApi.coreServices.rootLogger,
3588
3168
  deps: {
3589
3169
  config: backendPluginApi.coreServices.rootConfig
3590
3170
  },
3591
3171
  async factory({ config }) {
3592
- var _a;
3593
3172
  const logger = WinstonLogger.create({
3594
3173
  meta: {
3595
3174
  service: "backstage"
@@ -3600,27 +3179,11 @@ const rootLoggerServiceFactory = backendPluginApi.createServiceFactory({
3600
3179
  });
3601
3180
  const secretEnumerator = await createConfigSecretEnumerator({ logger });
3602
3181
  logger.addRedactions(secretEnumerator(config));
3603
- (_a = config.subscribe) == null ? void 0 : _a.call(config, () => logger.addRedactions(secretEnumerator(config)));
3182
+ config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));
3604
3183
  return logger;
3605
3184
  }
3606
3185
  });
3607
3186
 
3608
- const schedulerServiceFactory = backendPluginApi.createServiceFactory({
3609
- service: backendPluginApi.coreServices.scheduler,
3610
- deps: {
3611
- plugin: backendPluginApi.coreServices.pluginMetadata,
3612
- databaseManager: backendPluginApi.coreServices.database,
3613
- logger: backendPluginApi.coreServices.logger
3614
- },
3615
- async factory({ plugin, databaseManager, logger }) {
3616
- return backendTasks.TaskScheduler.forPlugin({
3617
- pluginId: plugin.getId(),
3618
- databaseManager,
3619
- logger
3620
- });
3621
- }
3622
- });
3623
-
3624
3187
  const tokenManagerServiceFactory = backendPluginApi.createServiceFactory({
3625
3188
  service: backendPluginApi.coreServices.tokenManager,
3626
3189
  deps: {
@@ -3681,6 +3244,22 @@ const userInfoServiceFactory = backendPluginApi.createServiceFactory({
3681
3244
  }
3682
3245
  });
3683
3246
 
3247
+ const schedulerServiceFactory = backendPluginApi.createServiceFactory({
3248
+ service: backendPluginApi.coreServices.scheduler,
3249
+ deps: {
3250
+ plugin: backendPluginApi.coreServices.pluginMetadata,
3251
+ databaseManager: backendPluginApi.coreServices.database,
3252
+ logger: backendPluginApi.coreServices.logger
3253
+ },
3254
+ async factory({ plugin, databaseManager, logger }) {
3255
+ return backendTasks.TaskScheduler.forPlugin({
3256
+ pluginId: plugin.getId(),
3257
+ databaseManager,
3258
+ logger
3259
+ });
3260
+ }
3261
+ });
3262
+
3684
3263
  exports.DefaultRootHttpRouter = DefaultRootHttpRouter;
3685
3264
  exports.HostDiscovery = HostDiscovery;
3686
3265
  exports.MiddlewareFactory = MiddlewareFactory;