@backstage/backend-app-api 0.5.0-next.1 → 0.5.0

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

Potentially problematic release.


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

package/dist/index.cjs.js CHANGED
@@ -21,6 +21,7 @@ var minimatch = require('minimatch');
21
21
  var errors = require('@backstage/errors');
22
22
  var winston = require('winston');
23
23
  var backendPluginApi = require('@backstage/backend-plugin-api');
24
+ var alpha = require('@backstage/backend-plugin-api/alpha');
24
25
  var backendCommon = require('@backstage/backend-common');
25
26
  var PromiseRouter = require('express-promise-router');
26
27
  var types = require('@backstage/types');
@@ -584,31 +585,31 @@ function createCorsOriginMatcher(allowedOriginPatterns) {
584
585
  };
585
586
  }
586
587
 
587
- var __accessCheck$7 = (obj, member, msg) => {
588
+ var __accessCheck$8 = (obj, member, msg) => {
588
589
  if (!member.has(obj))
589
590
  throw TypeError("Cannot " + msg);
590
591
  };
591
- var __privateGet$7 = (obj, member, getter) => {
592
- __accessCheck$7(obj, member, "read from private field");
592
+ var __privateGet$8 = (obj, member, getter) => {
593
+ __accessCheck$8(obj, member, "read from private field");
593
594
  return getter ? getter.call(obj) : member.get(obj);
594
595
  };
595
- var __privateAdd$7 = (obj, member, value) => {
596
+ var __privateAdd$8 = (obj, member, value) => {
596
597
  if (member.has(obj))
597
598
  throw TypeError("Cannot add the same private member more than once");
598
599
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
599
600
  };
600
- var __privateSet$7 = (obj, member, value, setter) => {
601
- __accessCheck$7(obj, member, "write to private field");
601
+ var __privateSet$8 = (obj, member, value, setter) => {
602
+ __accessCheck$8(obj, member, "write to private field");
602
603
  setter ? setter.call(obj, value) : member.set(obj, value);
603
604
  return value;
604
605
  };
605
606
  var _config, _logger;
606
607
  const _MiddlewareFactory = class _MiddlewareFactory {
607
608
  constructor(options) {
608
- __privateAdd$7(this, _config, void 0);
609
- __privateAdd$7(this, _logger, void 0);
610
- __privateSet$7(this, _config, options.config);
611
- __privateSet$7(this, _logger, options.logger);
609
+ __privateAdd$8(this, _config, void 0);
610
+ __privateAdd$8(this, _logger, void 0);
611
+ __privateSet$8(this, _config, options.config);
612
+ __privateSet$8(this, _logger, options.logger);
612
613
  }
613
614
  /**
614
615
  * Creates a new {@link MiddlewareFactory}.
@@ -654,7 +655,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
654
655
  * @returns An Express request handler
655
656
  */
656
657
  logging() {
657
- const logger = __privateGet$7(this, _logger).child({
658
+ const logger = __privateGet$8(this, _logger).child({
658
659
  type: "incomingRequest"
659
660
  });
660
661
  return morgan__default["default"]("combined", {
@@ -678,7 +679,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
678
679
  * @returns An Express request handler
679
680
  */
680
681
  helmet() {
681
- return helmet__default["default"](readHelmetOptions(__privateGet$7(this, _config).getOptionalConfig("backend")));
682
+ return helmet__default["default"](readHelmetOptions(__privateGet$8(this, _config).getOptionalConfig("backend")));
682
683
  }
683
684
  /**
684
685
  * Returns a middleware that implements the cors library.
@@ -693,7 +694,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
693
694
  * @returns An Express request handler
694
695
  */
695
696
  cors() {
696
- return cors__default["default"](readCorsOptions(__privateGet$7(this, _config).getOptionalConfig("backend")));
697
+ return cors__default["default"](readCorsOptions(__privateGet$8(this, _config).getOptionalConfig("backend")));
697
698
  }
698
699
  /**
699
700
  * Express middleware to handle errors during request processing.
@@ -718,7 +719,7 @@ const _MiddlewareFactory = class _MiddlewareFactory {
718
719
  error(options = {}) {
719
720
  var _a;
720
721
  const showStackTraces = (_a = options.showStackTraces) != null ? _a : process.env.NODE_ENV === "development";
721
- const logger = __privateGet$7(this, _logger).child({
722
+ const logger = __privateGet$8(this, _logger).child({
722
723
  type: "errorHandler"
723
724
  });
724
725
  return (error, req, res, next) => {
@@ -776,31 +777,31 @@ const escapeRegExp = (text) => {
776
777
  return text.replace(/[.*+?^${}(\)|[\]\\]/g, "\\$&");
777
778
  };
778
779
 
779
- var __accessCheck$6 = (obj, member, msg) => {
780
+ var __accessCheck$7 = (obj, member, msg) => {
780
781
  if (!member.has(obj))
781
782
  throw TypeError("Cannot " + msg);
782
783
  };
783
- var __privateGet$6 = (obj, member, getter) => {
784
- __accessCheck$6(obj, member, "read from private field");
784
+ var __privateGet$7 = (obj, member, getter) => {
785
+ __accessCheck$7(obj, member, "read from private field");
785
786
  return getter ? getter.call(obj) : member.get(obj);
786
787
  };
787
- var __privateAdd$6 = (obj, member, value) => {
788
+ var __privateAdd$7 = (obj, member, value) => {
788
789
  if (member.has(obj))
789
790
  throw TypeError("Cannot add the same private member more than once");
790
791
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
791
792
  };
792
- var __privateSet$6 = (obj, member, value, setter) => {
793
- __accessCheck$6(obj, member, "write to private field");
793
+ var __privateSet$7 = (obj, member, value, setter) => {
794
+ __accessCheck$7(obj, member, "write to private field");
794
795
  setter ? setter.call(obj, value) : member.set(obj, value);
795
796
  return value;
796
797
  };
797
798
  var _winston, _addRedactions;
798
799
  const _WinstonLogger = class _WinstonLogger {
799
800
  constructor(winston, addRedactions) {
800
- __privateAdd$6(this, _winston, void 0);
801
- __privateAdd$6(this, _addRedactions, void 0);
802
- __privateSet$6(this, _winston, winston);
803
- __privateSet$6(this, _addRedactions, addRedactions);
801
+ __privateAdd$7(this, _winston, void 0);
802
+ __privateAdd$7(this, _addRedactions, void 0);
803
+ __privateSet$7(this, _winston, winston);
804
+ __privateSet$7(this, _addRedactions, addRedactions);
804
805
  }
805
806
  /**
806
807
  * Creates a {@link WinstonLogger} instance.
@@ -877,44 +878,44 @@ const _WinstonLogger = class _WinstonLogger {
877
878
  );
878
879
  }
879
880
  error(message, meta) {
880
- __privateGet$6(this, _winston).error(message, meta);
881
+ __privateGet$7(this, _winston).error(message, meta);
881
882
  }
882
883
  warn(message, meta) {
883
- __privateGet$6(this, _winston).warn(message, meta);
884
+ __privateGet$7(this, _winston).warn(message, meta);
884
885
  }
885
886
  info(message, meta) {
886
- __privateGet$6(this, _winston).info(message, meta);
887
+ __privateGet$7(this, _winston).info(message, meta);
887
888
  }
888
889
  debug(message, meta) {
889
- __privateGet$6(this, _winston).debug(message, meta);
890
+ __privateGet$7(this, _winston).debug(message, meta);
890
891
  }
891
892
  child(meta) {
892
- return new _WinstonLogger(__privateGet$6(this, _winston).child(meta));
893
+ return new _WinstonLogger(__privateGet$7(this, _winston).child(meta));
893
894
  }
894
895
  addRedactions(redactions) {
895
896
  var _a;
896
- (_a = __privateGet$6(this, _addRedactions)) == null ? void 0 : _a.call(this, redactions);
897
+ (_a = __privateGet$7(this, _addRedactions)) == null ? void 0 : _a.call(this, redactions);
897
898
  }
898
899
  };
899
900
  _winston = new WeakMap();
900
901
  _addRedactions = new WeakMap();
901
902
  let WinstonLogger = _WinstonLogger;
902
903
 
903
- var __accessCheck$5 = (obj, member, msg) => {
904
+ var __accessCheck$6 = (obj, member, msg) => {
904
905
  if (!member.has(obj))
905
906
  throw TypeError("Cannot " + msg);
906
907
  };
907
- var __privateGet$5 = (obj, member, getter) => {
908
- __accessCheck$5(obj, member, "read from private field");
908
+ var __privateGet$6 = (obj, member, getter) => {
909
+ __accessCheck$6(obj, member, "read from private field");
909
910
  return getter ? getter.call(obj) : member.get(obj);
910
911
  };
911
- var __privateAdd$5 = (obj, member, value) => {
912
+ var __privateAdd$6 = (obj, member, value) => {
912
913
  if (member.has(obj))
913
914
  throw TypeError("Cannot add the same private member more than once");
914
915
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
915
916
  };
916
- var __privateSet$5 = (obj, member, value, setter) => {
917
- __accessCheck$5(obj, member, "write to private field");
917
+ var __privateSet$6 = (obj, member, value, setter) => {
918
+ __accessCheck$6(obj, member, "write to private field");
918
919
  setter ? setter.call(obj, value) : member.set(obj, value);
919
920
  return value;
920
921
  };
@@ -922,25 +923,25 @@ var _hasStarted$1, _startupTasks$1, _hasShutdown, _shutdownTasks;
922
923
  class BackendLifecycleImpl {
923
924
  constructor(logger) {
924
925
  this.logger = logger;
925
- __privateAdd$5(this, _hasStarted$1, false);
926
- __privateAdd$5(this, _startupTasks$1, []);
927
- __privateAdd$5(this, _hasShutdown, false);
928
- __privateAdd$5(this, _shutdownTasks, []);
926
+ __privateAdd$6(this, _hasStarted$1, false);
927
+ __privateAdd$6(this, _startupTasks$1, []);
928
+ __privateAdd$6(this, _hasShutdown, false);
929
+ __privateAdd$6(this, _shutdownTasks, []);
929
930
  }
930
931
  addStartupHook(hook, options) {
931
- if (__privateGet$5(this, _hasStarted$1)) {
932
+ if (__privateGet$6(this, _hasStarted$1)) {
932
933
  throw new Error("Attempted to add startup hook after startup");
933
934
  }
934
- __privateGet$5(this, _startupTasks$1).push({ hook, options });
935
+ __privateGet$6(this, _startupTasks$1).push({ hook, options });
935
936
  }
936
937
  async startup() {
937
- if (__privateGet$5(this, _hasStarted$1)) {
938
+ if (__privateGet$6(this, _hasStarted$1)) {
938
939
  return;
939
940
  }
940
- __privateSet$5(this, _hasStarted$1, true);
941
- this.logger.debug(`Running ${__privateGet$5(this, _startupTasks$1).length} startup tasks...`);
941
+ __privateSet$6(this, _hasStarted$1, true);
942
+ this.logger.debug(`Running ${__privateGet$6(this, _startupTasks$1).length} startup tasks...`);
942
943
  await Promise.all(
943
- __privateGet$5(this, _startupTasks$1).map(async ({ hook, options }) => {
944
+ __privateGet$6(this, _startupTasks$1).map(async ({ hook, options }) => {
944
945
  var _a;
945
946
  const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
946
947
  try {
@@ -953,21 +954,21 @@ class BackendLifecycleImpl {
953
954
  );
954
955
  }
955
956
  addShutdownHook(hook, options) {
956
- if (__privateGet$5(this, _hasShutdown)) {
957
+ if (__privateGet$6(this, _hasShutdown)) {
957
958
  throw new Error("Attempted to add shutdown hook after shutdown");
958
959
  }
959
- __privateGet$5(this, _shutdownTasks).push({ hook, options });
960
+ __privateGet$6(this, _shutdownTasks).push({ hook, options });
960
961
  }
961
962
  async shutdown() {
962
- if (__privateGet$5(this, _hasShutdown)) {
963
+ if (__privateGet$6(this, _hasShutdown)) {
963
964
  return;
964
965
  }
965
- __privateSet$5(this, _hasShutdown, true);
966
+ __privateSet$6(this, _hasShutdown, true);
966
967
  this.logger.debug(
967
- `Running ${__privateGet$5(this, _shutdownTasks).length} shutdown tasks...`
968
+ `Running ${__privateGet$6(this, _shutdownTasks).length} shutdown tasks...`
968
969
  );
969
970
  await Promise.all(
970
- __privateGet$5(this, _shutdownTasks).map(async ({ hook, options }) => {
971
+ __privateGet$6(this, _shutdownTasks).map(async ({ hook, options }) => {
971
972
  var _a;
972
973
  const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
973
974
  try {
@@ -994,21 +995,21 @@ const rootLifecycleServiceFactory = backendPluginApi.createServiceFactory({
994
995
  }
995
996
  });
996
997
 
997
- var __accessCheck$4 = (obj, member, msg) => {
998
+ var __accessCheck$5 = (obj, member, msg) => {
998
999
  if (!member.has(obj))
999
1000
  throw TypeError("Cannot " + msg);
1000
1001
  };
1001
- var __privateGet$4 = (obj, member, getter) => {
1002
- __accessCheck$4(obj, member, "read from private field");
1002
+ var __privateGet$5 = (obj, member, getter) => {
1003
+ __accessCheck$5(obj, member, "read from private field");
1003
1004
  return getter ? getter.call(obj) : member.get(obj);
1004
1005
  };
1005
- var __privateAdd$4 = (obj, member, value) => {
1006
+ var __privateAdd$5 = (obj, member, value) => {
1006
1007
  if (member.has(obj))
1007
1008
  throw TypeError("Cannot add the same private member more than once");
1008
1009
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1009
1010
  };
1010
- var __privateSet$4 = (obj, member, value, setter) => {
1011
- __accessCheck$4(obj, member, "write to private field");
1011
+ var __privateSet$5 = (obj, member, value, setter) => {
1012
+ __accessCheck$5(obj, member, "write to private field");
1012
1013
  setter ? setter.call(obj, value) : member.set(obj, value);
1013
1014
  return value;
1014
1015
  };
@@ -1018,25 +1019,25 @@ class BackendPluginLifecycleImpl {
1018
1019
  this.logger = logger;
1019
1020
  this.rootLifecycle = rootLifecycle;
1020
1021
  this.pluginMetadata = pluginMetadata;
1021
- __privateAdd$4(this, _hasStarted, false);
1022
- __privateAdd$4(this, _startupTasks, []);
1022
+ __privateAdd$5(this, _hasStarted, false);
1023
+ __privateAdd$5(this, _startupTasks, []);
1023
1024
  }
1024
1025
  addStartupHook(hook, options) {
1025
- if (__privateGet$4(this, _hasStarted)) {
1026
+ if (__privateGet$5(this, _hasStarted)) {
1026
1027
  throw new Error("Attempted to add startup hook after startup");
1027
1028
  }
1028
- __privateGet$4(this, _startupTasks).push({ hook, options });
1029
+ __privateGet$5(this, _startupTasks).push({ hook, options });
1029
1030
  }
1030
1031
  async startup() {
1031
- if (__privateGet$4(this, _hasStarted)) {
1032
+ if (__privateGet$5(this, _hasStarted)) {
1032
1033
  return;
1033
1034
  }
1034
- __privateSet$4(this, _hasStarted, true);
1035
+ __privateSet$5(this, _hasStarted, true);
1035
1036
  this.logger.debug(
1036
- `Running ${__privateGet$4(this, _startupTasks).length} plugin startup tasks...`
1037
+ `Running ${__privateGet$5(this, _startupTasks).length} plugin startup tasks...`
1037
1038
  );
1038
1039
  await Promise.all(
1039
- __privateGet$4(this, _startupTasks).map(async ({ hook, options }) => {
1040
+ __privateGet$5(this, _startupTasks).map(async ({ hook, options }) => {
1040
1041
  var _a;
1041
1042
  const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
1042
1043
  try {
@@ -1074,273 +1075,195 @@ const lifecycleServiceFactory = backendPluginApi.createServiceFactory({
1074
1075
  }
1075
1076
  });
1076
1077
 
1077
- var __accessCheck$3 = (obj, member, msg) => {
1078
+ var __accessCheck$4 = (obj, member, msg) => {
1078
1079
  if (!member.has(obj))
1079
1080
  throw TypeError("Cannot " + msg);
1080
1081
  };
1081
- var __privateGet$3 = (obj, member, getter) => {
1082
- __accessCheck$3(obj, member, "read from private field");
1082
+ var __privateGet$4 = (obj, member, getter) => {
1083
+ __accessCheck$4(obj, member, "read from private field");
1083
1084
  return getter ? getter.call(obj) : member.get(obj);
1084
1085
  };
1085
- var __privateAdd$3 = (obj, member, value) => {
1086
+ var __privateAdd$4 = (obj, member, value) => {
1086
1087
  if (member.has(obj))
1087
1088
  throw TypeError("Cannot add the same private member more than once");
1088
1089
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1089
1090
  };
1090
- var __privateSet$3 = (obj, member, value, setter) => {
1091
- __accessCheck$3(obj, member, "write to private field");
1091
+ var __privateSet$4 = (obj, member, value, setter) => {
1092
+ __accessCheck$4(obj, member, "write to private field");
1092
1093
  setter ? setter.call(obj, value) : member.set(obj, value);
1093
1094
  return value;
1094
1095
  };
1095
- var __privateMethod$2 = (obj, member, method) => {
1096
- __accessCheck$3(obj, member, "access private method");
1097
- return method;
1098
- };
1099
- var _startPromise, _features, _extensionPoints, _serviceHolder, _getInitDeps, getInitDeps_fn, _doStart, doStart_fn, _getRootLifecycleImpl, getRootLifecycleImpl_fn, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn;
1100
- class BackendInitializer {
1101
- constructor(serviceHolder) {
1102
- __privateAdd$3(this, _getInitDeps);
1103
- __privateAdd$3(this, _doStart);
1104
- // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this
1105
- __privateAdd$3(this, _getRootLifecycleImpl);
1106
- __privateAdd$3(this, _getPluginLifecycleImpl);
1107
- __privateAdd$3(this, _startPromise, void 0);
1108
- __privateAdd$3(this, _features, new Array());
1109
- __privateAdd$3(this, _extensionPoints, /* @__PURE__ */ new Map());
1110
- __privateAdd$3(this, _serviceHolder, void 0);
1111
- __privateSet$3(this, _serviceHolder, serviceHolder);
1112
- }
1113
- add(feature) {
1114
- if (__privateGet$3(this, _startPromise)) {
1115
- throw new Error("feature can not be added after the backend has started");
1116
- }
1117
- if (feature.$$type !== "@backstage/BackendFeature") {
1118
- throw new Error(
1119
- `Failed to add feature, invalid type '${feature.$$type}'`
1120
- );
1121
- }
1122
- const internalFeature = feature;
1123
- if (internalFeature.version !== "v1") {
1124
- throw new Error(
1125
- `Failed to add feature, invalid version '${internalFeature.version}'`
1126
- );
1127
- }
1128
- __privateGet$3(this, _features).push(internalFeature);
1129
- }
1130
- async start() {
1131
- if (__privateGet$3(this, _startPromise)) {
1132
- throw new Error("Backend has already started");
1133
- }
1134
- const exitHandler = async () => {
1135
- process.removeListener("SIGTERM", exitHandler);
1136
- process.removeListener("SIGINT", exitHandler);
1137
- process.removeListener("beforeExit", exitHandler);
1138
- try {
1139
- await this.stop();
1140
- process.exit(0);
1141
- } catch (error) {
1142
- console.error(error);
1143
- process.exit(1);
1144
- }
1145
- };
1146
- process.addListener("SIGTERM", exitHandler);
1147
- process.addListener("SIGINT", exitHandler);
1148
- process.addListener("beforeExit", exitHandler);
1149
- __privateSet$3(this, _startPromise, __privateMethod$2(this, _doStart, doStart_fn).call(this));
1150
- await __privateGet$3(this, _startPromise);
1151
- }
1152
- async stop() {
1153
- if (!__privateGet$3(this, _startPromise)) {
1154
- return;
1155
- }
1156
- await __privateGet$3(this, _startPromise);
1157
- const lifecycleService = await __privateMethod$2(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1158
- await lifecycleService.shutdown();
1096
+ var _nodes, _allProvided;
1097
+ class Node {
1098
+ constructor(value, consumes, provides) {
1099
+ this.value = value;
1100
+ this.consumes = consumes;
1101
+ this.provides = provides;
1102
+ }
1103
+ static from(input) {
1104
+ return new Node(
1105
+ input.value,
1106
+ input.consumes ? new Set(input.consumes) : /* @__PURE__ */ new Set(),
1107
+ input.provides ? new Set(input.provides) : /* @__PURE__ */ new Set()
1108
+ );
1159
1109
  }
1160
1110
  }
1161
- _startPromise = new WeakMap();
1162
- _features = new WeakMap();
1163
- _extensionPoints = new WeakMap();
1164
- _serviceHolder = new WeakMap();
1165
- _getInitDeps = new WeakSet();
1166
- getInitDeps_fn = async function(deps, pluginId) {
1167
- const result = /* @__PURE__ */ new Map();
1168
- const missingRefs = /* @__PURE__ */ new Set();
1169
- for (const [name, ref] of Object.entries(deps)) {
1170
- const extensionPoint = __privateGet$3(this, _extensionPoints).get(
1171
- ref
1172
- );
1173
- if (extensionPoint) {
1174
- result.set(name, extensionPoint);
1175
- } else {
1176
- const impl = await __privateGet$3(this, _serviceHolder).get(
1177
- ref,
1178
- pluginId
1179
- );
1180
- if (impl) {
1181
- result.set(name, impl);
1182
- } else {
1183
- missingRefs.add(ref);
1111
+ const _DependencyGraph = class _DependencyGraph {
1112
+ constructor(nodes) {
1113
+ __privateAdd$4(this, _nodes, void 0);
1114
+ __privateAdd$4(this, _allProvided, void 0);
1115
+ __privateSet$4(this, _nodes, nodes);
1116
+ __privateSet$4(this, _allProvided, /* @__PURE__ */ new Set());
1117
+ for (const node of __privateGet$4(this, _nodes).values()) {
1118
+ for (const produced of node.provides) {
1119
+ __privateGet$4(this, _allProvided).add(produced);
1184
1120
  }
1185
1121
  }
1186
1122
  }
1187
- if (missingRefs.size > 0) {
1188
- const missing = Array.from(missingRefs).join(", ");
1189
- throw new Error(
1190
- `No extension point or service available for the following ref(s): ${missing}`
1123
+ static fromMap(nodes) {
1124
+ return this.fromIterable(
1125
+ Object.entries(nodes).map(([key, node]) => ({
1126
+ value: String(key),
1127
+ ...node
1128
+ }))
1191
1129
  );
1192
1130
  }
1193
- return Object.fromEntries(result);
1194
- };
1195
- _doStart = new WeakSet();
1196
- doStart_fn = async function() {
1197
- for (const ref of __privateGet$3(this, _serviceHolder).getServiceRefs()) {
1198
- if (ref.scope === "root") {
1199
- await __privateGet$3(this, _serviceHolder).get(ref, "root");
1131
+ static fromIterable(nodeInputs) {
1132
+ const nodes = new Array();
1133
+ for (const nodeInput of nodeInputs) {
1134
+ nodes.push(Node.from(nodeInput));
1200
1135
  }
1201
- }
1202
- const pluginInits = /* @__PURE__ */ new Map();
1203
- const moduleInits = /* @__PURE__ */ new Map();
1204
- for (const feature of __privateGet$3(this, _features)) {
1205
- for (const r of feature.getRegistrations()) {
1206
- const provides = /* @__PURE__ */ new Set();
1207
- if (r.type === "plugin") {
1208
- for (const [extRef, extImpl] of r.extensionPoints) {
1209
- if (__privateGet$3(this, _extensionPoints).has(extRef)) {
1210
- throw new Error(
1211
- `ExtensionPoint with ID '${extRef.id}' is already registered`
1212
- );
1213
- }
1214
- __privateGet$3(this, _extensionPoints).set(extRef, extImpl);
1215
- provides.add(extRef);
1216
- }
1136
+ return new _DependencyGraph(nodes);
1137
+ }
1138
+ // Find all nodes that consume dependencies that are not provided by any other node
1139
+ findUnsatisfiedDeps() {
1140
+ const unsatisfiedDependencies = [];
1141
+ for (const node of __privateGet$4(this, _nodes).values()) {
1142
+ const unsatisfied = Array.from(node.consumes).filter(
1143
+ (id) => !__privateGet$4(this, _allProvided).has(id)
1144
+ );
1145
+ if (unsatisfied.length > 0) {
1146
+ unsatisfiedDependencies.push({ value: node.value, unsatisfied });
1217
1147
  }
1218
- if (r.type === "plugin") {
1219
- if (pluginInits.has(r.pluginId)) {
1220
- throw new Error(`Plugin '${r.pluginId}' is already registered`);
1221
- }
1222
- pluginInits.set(r.pluginId, {
1223
- provides,
1224
- consumes: new Set(Object.values(r.init.deps)),
1225
- init: r.init
1226
- });
1227
- } else {
1228
- let modules = moduleInits.get(r.pluginId);
1229
- if (!modules) {
1230
- modules = /* @__PURE__ */ new Map();
1231
- moduleInits.set(r.pluginId, modules);
1148
+ }
1149
+ return unsatisfiedDependencies;
1150
+ }
1151
+ // Detect circular dependencies within the graph, returning the path of nodes that
1152
+ // form a cycle, with the same node as the first and last element of the array.
1153
+ detectCircularDependency() {
1154
+ for (const startNode of __privateGet$4(this, _nodes)) {
1155
+ const visited = /* @__PURE__ */ new Set();
1156
+ const stack = new Array([
1157
+ startNode,
1158
+ [startNode.value]
1159
+ ]);
1160
+ while (stack.length > 0) {
1161
+ const [node, path] = stack.pop();
1162
+ if (visited.has(node)) {
1163
+ continue;
1232
1164
  }
1233
- if (modules.has(r.moduleId)) {
1234
- throw new Error(
1235
- `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`
1165
+ visited.add(node);
1166
+ for (const produced of node.provides) {
1167
+ const consumerNodes = __privateGet$4(this, _nodes).filter(
1168
+ (other) => other.consumes.has(produced)
1236
1169
  );
1170
+ for (const consumer of consumerNodes) {
1171
+ if (consumer === startNode) {
1172
+ return [...path, startNode.value];
1173
+ }
1174
+ if (!visited.has(consumer)) {
1175
+ stack.push([consumer, [...path, consumer.value]]);
1176
+ }
1177
+ }
1237
1178
  }
1238
- modules.set(r.moduleId, {
1239
- provides,
1240
- consumes: new Set(Object.values(r.init.deps)),
1241
- init: r.init
1242
- });
1243
1179
  }
1244
1180
  }
1181
+ return void 0;
1245
1182
  }
1246
- const allPluginIds = [
1247
- .../* @__PURE__ */ new Set([...pluginInits.keys(), ...moduleInits.keys()])
1248
- ];
1249
- await Promise.all(
1250
- allPluginIds.map(async (pluginId) => {
1251
- var _a;
1252
- const modules = (_a = moduleInits.get(pluginId)) != null ? _a : [];
1253
- await Promise.all(
1254
- Array.from(modules).map(async ([moduleId, moduleInit]) => {
1255
- const moduleDeps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, moduleInit.init.deps, pluginId);
1256
- await moduleInit.init.func(moduleDeps).catch((error) => {
1257
- throw new errors.ForwardedError(
1258
- `Module '${moduleId}' for plugin '${pluginId}' startup failed`,
1259
- error
1260
- );
1261
- });
1262
- })
1263
- );
1264
- const pluginInit = pluginInits.get(pluginId);
1265
- if (pluginInit) {
1266
- const pluginDeps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, pluginInit.init.deps, pluginId);
1267
- await pluginInit.init.func(pluginDeps).catch((error) => {
1268
- throw new errors.ForwardedError(
1269
- `Plugin '${pluginId}' startup failed`,
1270
- error
1271
- );
1272
- });
1183
+ /**
1184
+ * Traverses the dependency graph in topological order, calling the provided
1185
+ * function for each node and waiting for it to resolve.
1186
+ *
1187
+ * The nodes are traversed in parallel, but in such a way that no node is
1188
+ * visited before all of its dependencies.
1189
+ *
1190
+ * Dependencies of nodes that are not produced by any other nodes will be ignored.
1191
+ */
1192
+ async parallelTopologicalTraversal(fn) {
1193
+ const allProvided = __privateGet$4(this, _allProvided);
1194
+ const producedSoFar = /* @__PURE__ */ new Set();
1195
+ const waiting = new Set(__privateGet$4(this, _nodes).values());
1196
+ const visited = /* @__PURE__ */ new Set();
1197
+ const results = new Array();
1198
+ let inFlight = 0;
1199
+ async function processMoreNodes() {
1200
+ if (waiting.size === 0) {
1201
+ return;
1273
1202
  }
1274
- const lifecycleService2 = await __privateMethod$2(this, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn).call(this, pluginId);
1275
- await lifecycleService2.startup();
1276
- })
1277
- );
1278
- const lifecycleService = await __privateMethod$2(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1279
- await lifecycleService.startup();
1280
- if (process.env.NODE_ENV !== "test") {
1281
- const rootLogger = await __privateGet$3(this, _serviceHolder).get(
1282
- backendPluginApi.coreServices.rootLogger,
1283
- "root"
1284
- );
1285
- process.on("unhandledRejection", (reason) => {
1286
- var _a;
1287
- (_a = rootLogger == null ? void 0 : rootLogger.child({ type: "unhandledRejection" })) == null ? void 0 : _a.error("Unhandled rejection", reason);
1288
- });
1289
- process.on("uncaughtException", (error) => {
1290
- var _a;
1291
- (_a = rootLogger == null ? void 0 : rootLogger.child({ type: "uncaughtException" })) == null ? void 0 : _a.error("Uncaught exception", error);
1292
- });
1293
- }
1294
- };
1295
- _getRootLifecycleImpl = new WeakSet();
1296
- getRootLifecycleImpl_fn = async function() {
1297
- const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
1298
- backendPluginApi.coreServices.rootLifecycle,
1299
- "root"
1300
- );
1301
- if (lifecycleService instanceof BackendLifecycleImpl) {
1302
- return lifecycleService;
1303
- }
1304
- throw new Error("Unexpected root lifecycle service implementation");
1305
- };
1306
- _getPluginLifecycleImpl = new WeakSet();
1307
- getPluginLifecycleImpl_fn = async function(pluginId) {
1308
- const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
1309
- backendPluginApi.coreServices.lifecycle,
1310
- pluginId
1311
- );
1312
- if (lifecycleService instanceof BackendPluginLifecycleImpl) {
1313
- return lifecycleService;
1203
+ const nodesToProcess = [];
1204
+ for (const node of waiting) {
1205
+ let ready = true;
1206
+ for (const consumed of node.consumes) {
1207
+ if (allProvided.has(consumed) && !producedSoFar.has(consumed)) {
1208
+ ready = false;
1209
+ continue;
1210
+ }
1211
+ }
1212
+ if (ready) {
1213
+ nodesToProcess.push(node);
1214
+ }
1215
+ }
1216
+ for (const node of nodesToProcess) {
1217
+ waiting.delete(node);
1218
+ }
1219
+ if (nodesToProcess.length === 0 && inFlight === 0) {
1220
+ throw new Error("Circular dependency detected");
1221
+ }
1222
+ await Promise.all(nodesToProcess.map(processNode));
1223
+ }
1224
+ async function processNode(node) {
1225
+ visited.add(node);
1226
+ inFlight += 1;
1227
+ const result = await fn(node.value);
1228
+ results.push(result);
1229
+ node.provides.forEach((produced) => producedSoFar.add(produced));
1230
+ inFlight -= 1;
1231
+ await processMoreNodes();
1232
+ }
1233
+ await processMoreNodes();
1234
+ return results;
1314
1235
  }
1315
- throw new Error("Unexpected plugin lifecycle service implementation");
1316
1236
  };
1237
+ _nodes = new WeakMap();
1238
+ _allProvided = new WeakMap();
1239
+ let DependencyGraph = _DependencyGraph;
1317
1240
 
1318
- var __accessCheck$2 = (obj, member, msg) => {
1241
+ var __accessCheck$3 = (obj, member, msg) => {
1319
1242
  if (!member.has(obj))
1320
1243
  throw TypeError("Cannot " + msg);
1321
1244
  };
1322
- var __privateGet$2 = (obj, member, getter) => {
1323
- __accessCheck$2(obj, member, "read from private field");
1245
+ var __privateGet$3 = (obj, member, getter) => {
1246
+ __accessCheck$3(obj, member, "read from private field");
1324
1247
  return getter ? getter.call(obj) : member.get(obj);
1325
1248
  };
1326
- var __privateAdd$2 = (obj, member, value) => {
1249
+ var __privateAdd$3 = (obj, member, value) => {
1327
1250
  if (member.has(obj))
1328
1251
  throw TypeError("Cannot add the same private member more than once");
1329
1252
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1330
1253
  };
1331
- var __privateSet$2 = (obj, member, value, setter) => {
1332
- __accessCheck$2(obj, member, "write to private field");
1254
+ var __privateSet$3 = (obj, member, value, setter) => {
1255
+ __accessCheck$3(obj, member, "write to private field");
1333
1256
  setter ? setter.call(obj, value) : member.set(obj, value);
1334
1257
  return value;
1335
1258
  };
1336
- var __privateMethod$1 = (obj, member, method) => {
1337
- __accessCheck$2(obj, member, "access private method");
1259
+ var __privateMethod$2 = (obj, member, method) => {
1260
+ __accessCheck$3(obj, member, "access private method");
1338
1261
  return method;
1339
1262
  };
1340
1263
  var _providedFactories, _loadedDefaultFactories, _implementations, _rootServiceImplementations, _resolveFactory, resolveFactory_fn, _checkForMissingDeps, checkForMissingDeps_fn;
1341
1264
  function toInternalServiceFactory(factory) {
1342
1265
  const f = factory;
1343
- if (f.$$type !== "@backstage/ServiceFactory") {
1266
+ if (f.$$type !== "@backstage/BackendFeature") {
1344
1267
  throw new Error(`Invalid service factory, bad type '${f.$$type}'`);
1345
1268
  }
1346
1269
  if (f.version !== "v1") {
@@ -1352,33 +1275,33 @@ const pluginMetadataServiceFactory = backendPluginApi.createServiceFactory(
1352
1275
  (options) => ({
1353
1276
  service: backendPluginApi.coreServices.pluginMetadata,
1354
1277
  deps: {},
1355
- factory: async () => ({ getId: () => options.pluginId })
1278
+ factory: async () => ({ getId: () => options == null ? void 0 : options.pluginId })
1356
1279
  })
1357
1280
  );
1358
1281
  class ServiceRegistry {
1359
1282
  constructor(factories) {
1360
- __privateAdd$2(this, _resolveFactory);
1361
- __privateAdd$2(this, _checkForMissingDeps);
1362
- __privateAdd$2(this, _providedFactories, void 0);
1363
- __privateAdd$2(this, _loadedDefaultFactories, void 0);
1364
- __privateAdd$2(this, _implementations, void 0);
1365
- __privateAdd$2(this, _rootServiceImplementations, /* @__PURE__ */ new Map());
1366
- __privateSet$2(this, _providedFactories, new Map(
1283
+ __privateAdd$3(this, _resolveFactory);
1284
+ __privateAdd$3(this, _checkForMissingDeps);
1285
+ __privateAdd$3(this, _providedFactories, void 0);
1286
+ __privateAdd$3(this, _loadedDefaultFactories, void 0);
1287
+ __privateAdd$3(this, _implementations, void 0);
1288
+ __privateAdd$3(this, _rootServiceImplementations, /* @__PURE__ */ new Map());
1289
+ __privateSet$3(this, _providedFactories, new Map(
1367
1290
  factories.map((sf) => [sf.service.id, toInternalServiceFactory(sf)])
1368
1291
  ));
1369
- __privateSet$2(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
1370
- __privateSet$2(this, _implementations, /* @__PURE__ */ new Map());
1292
+ __privateSet$3(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
1293
+ __privateSet$3(this, _implementations, /* @__PURE__ */ new Map());
1371
1294
  }
1372
1295
  getServiceRefs() {
1373
- return Array.from(__privateGet$2(this, _providedFactories).values()).map((f) => f.service);
1296
+ return Array.from(__privateGet$3(this, _providedFactories).values()).map((f) => f.service);
1374
1297
  }
1375
1298
  get(ref, pluginId) {
1376
1299
  var _a;
1377
- return (_a = __privateMethod$1(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
1300
+ return (_a = __privateMethod$2(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
1378
1301
  if (factory.service.scope === "root") {
1379
- let existing = __privateGet$2(this, _rootServiceImplementations).get(factory);
1302
+ let existing = __privateGet$3(this, _rootServiceImplementations).get(factory);
1380
1303
  if (!existing) {
1381
- __privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1304
+ __privateMethod$2(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1382
1305
  const rootDeps = new Array();
1383
1306
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
1384
1307
  if (serviceRef.scope !== "root") {
@@ -1392,13 +1315,13 @@ class ServiceRegistry {
1392
1315
  existing = Promise.all(rootDeps).then(
1393
1316
  (entries) => factory.factory(Object.fromEntries(entries), void 0)
1394
1317
  );
1395
- __privateGet$2(this, _rootServiceImplementations).set(factory, existing);
1318
+ __privateGet$3(this, _rootServiceImplementations).set(factory, existing);
1396
1319
  }
1397
1320
  return existing;
1398
1321
  }
1399
- let implementation = __privateGet$2(this, _implementations).get(factory);
1322
+ let implementation = __privateGet$3(this, _implementations).get(factory);
1400
1323
  if (!implementation) {
1401
- __privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1324
+ __privateMethod$2(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
1402
1325
  const rootDeps = new Array();
1403
1326
  for (const [name, serviceRef] of Object.entries(factory.deps)) {
1404
1327
  if (serviceRef.scope === "root") {
@@ -1420,7 +1343,7 @@ class ServiceRegistry {
1420
1343
  }),
1421
1344
  byPlugin: /* @__PURE__ */ new Map()
1422
1345
  };
1423
- __privateGet$2(this, _implementations).set(factory, implementation);
1346
+ __privateGet$3(this, _implementations).set(factory, implementation);
1424
1347
  }
1425
1348
  let result = implementation.byPlugin.get(pluginId);
1426
1349
  if (!result) {
@@ -1456,18 +1379,18 @@ resolveFactory_fn = function(ref, pluginId) {
1456
1379
  toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId }))
1457
1380
  );
1458
1381
  }
1459
- let resolvedFactory = __privateGet$2(this, _providedFactories).get(ref.id);
1382
+ let resolvedFactory = __privateGet$3(this, _providedFactories).get(ref.id);
1460
1383
  const { __defaultFactory: defaultFactory } = ref;
1461
1384
  if (!resolvedFactory && !defaultFactory) {
1462
1385
  return void 0;
1463
1386
  }
1464
1387
  if (!resolvedFactory) {
1465
- let loadedFactory = __privateGet$2(this, _loadedDefaultFactories).get(defaultFactory);
1388
+ let loadedFactory = __privateGet$3(this, _loadedDefaultFactories).get(defaultFactory);
1466
1389
  if (!loadedFactory) {
1467
1390
  loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
1468
1391
  (f) => toInternalServiceFactory(typeof f === "function" ? f() : f)
1469
1392
  );
1470
- __privateGet$2(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
1393
+ __privateGet$3(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
1471
1394
  }
1472
1395
  resolvedFactory = loadedFactory.catch((error) => {
1473
1396
  throw new Error(
@@ -1485,7 +1408,7 @@ checkForMissingDeps_fn = function(factory, pluginId) {
1485
1408
  if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
1486
1409
  return false;
1487
1410
  }
1488
- if (__privateGet$2(this, _providedFactories).get(ref.id)) {
1411
+ if (__privateGet$3(this, _providedFactories).get(ref.id)) {
1489
1412
  return false;
1490
1413
  }
1491
1414
  return !ref.__defaultFactory;
@@ -1498,6 +1421,321 @@ checkForMissingDeps_fn = function(factory, pluginId) {
1498
1421
  }
1499
1422
  };
1500
1423
 
1424
+ var __accessCheck$2 = (obj, member, msg) => {
1425
+ if (!member.has(obj))
1426
+ throw TypeError("Cannot " + msg);
1427
+ };
1428
+ var __privateGet$2 = (obj, member, getter) => {
1429
+ __accessCheck$2(obj, member, "read from private field");
1430
+ return getter ? getter.call(obj) : member.get(obj);
1431
+ };
1432
+ var __privateAdd$2 = (obj, member, value) => {
1433
+ if (member.has(obj))
1434
+ throw TypeError("Cannot add the same private member more than once");
1435
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1436
+ };
1437
+ var __privateSet$2 = (obj, member, value, setter) => {
1438
+ __accessCheck$2(obj, member, "write to private field");
1439
+ setter ? setter.call(obj, value) : member.set(obj, value);
1440
+ return value;
1441
+ };
1442
+ var __privateMethod$1 = (obj, member, method) => {
1443
+ __accessCheck$2(obj, member, "access private method");
1444
+ return method;
1445
+ };
1446
+ var _startPromise, _features, _extensionPoints, _serviceHolder, _providedServiceFactories, _defaultApiFactories, _getInitDeps, getInitDeps_fn, _addFeature, addFeature_fn, _doStart, doStart_fn, _getRootLifecycleImpl, getRootLifecycleImpl_fn, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn;
1447
+ class BackendInitializer {
1448
+ constructor(defaultApiFactories) {
1449
+ __privateAdd$2(this, _getInitDeps);
1450
+ __privateAdd$2(this, _addFeature);
1451
+ __privateAdd$2(this, _doStart);
1452
+ // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this
1453
+ __privateAdd$2(this, _getRootLifecycleImpl);
1454
+ __privateAdd$2(this, _getPluginLifecycleImpl);
1455
+ __privateAdd$2(this, _startPromise, void 0);
1456
+ __privateAdd$2(this, _features, new Array());
1457
+ __privateAdd$2(this, _extensionPoints, /* @__PURE__ */ new Map());
1458
+ __privateAdd$2(this, _serviceHolder, void 0);
1459
+ __privateAdd$2(this, _providedServiceFactories, new Array());
1460
+ __privateAdd$2(this, _defaultApiFactories, void 0);
1461
+ __privateSet$2(this, _defaultApiFactories, defaultApiFactories);
1462
+ }
1463
+ add(feature) {
1464
+ if (__privateGet$2(this, _startPromise)) {
1465
+ throw new Error("feature can not be added after the backend has started");
1466
+ }
1467
+ __privateMethod$1(this, _addFeature, addFeature_fn).call(this, feature);
1468
+ }
1469
+ async start() {
1470
+ if (__privateGet$2(this, _startPromise)) {
1471
+ throw new Error("Backend has already started");
1472
+ }
1473
+ const exitHandler = async () => {
1474
+ process.removeListener("SIGTERM", exitHandler);
1475
+ process.removeListener("SIGINT", exitHandler);
1476
+ process.removeListener("beforeExit", exitHandler);
1477
+ try {
1478
+ await this.stop();
1479
+ process.exit(0);
1480
+ } catch (error) {
1481
+ console.error(error);
1482
+ process.exit(1);
1483
+ }
1484
+ };
1485
+ process.addListener("SIGTERM", exitHandler);
1486
+ process.addListener("SIGINT", exitHandler);
1487
+ process.addListener("beforeExit", exitHandler);
1488
+ __privateSet$2(this, _startPromise, __privateMethod$1(this, _doStart, doStart_fn).call(this));
1489
+ await __privateGet$2(this, _startPromise);
1490
+ }
1491
+ async stop() {
1492
+ if (!__privateGet$2(this, _startPromise)) {
1493
+ return;
1494
+ }
1495
+ try {
1496
+ await __privateGet$2(this, _startPromise);
1497
+ } catch (error) {
1498
+ }
1499
+ const lifecycleService = await __privateMethod$1(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1500
+ await lifecycleService.shutdown();
1501
+ }
1502
+ }
1503
+ _startPromise = new WeakMap();
1504
+ _features = new WeakMap();
1505
+ _extensionPoints = new WeakMap();
1506
+ _serviceHolder = new WeakMap();
1507
+ _providedServiceFactories = new WeakMap();
1508
+ _defaultApiFactories = new WeakMap();
1509
+ _getInitDeps = new WeakSet();
1510
+ getInitDeps_fn = async function(deps, pluginId) {
1511
+ const result = /* @__PURE__ */ new Map();
1512
+ const missingRefs = /* @__PURE__ */ new Set();
1513
+ for (const [name, ref] of Object.entries(deps)) {
1514
+ const ep = __privateGet$2(this, _extensionPoints).get(ref);
1515
+ if (ep) {
1516
+ if (ep.pluginId !== pluginId) {
1517
+ throw new Error(
1518
+ `Extension point registered for plugin '${ep.pluginId}' may not be used by module for plugin '${pluginId}'`
1519
+ );
1520
+ }
1521
+ result.set(name, ep.impl);
1522
+ } else {
1523
+ const impl = await __privateGet$2(this, _serviceHolder).get(
1524
+ ref,
1525
+ pluginId
1526
+ );
1527
+ if (impl) {
1528
+ result.set(name, impl);
1529
+ } else {
1530
+ missingRefs.add(ref);
1531
+ }
1532
+ }
1533
+ }
1534
+ if (missingRefs.size > 0) {
1535
+ const missing = Array.from(missingRefs).join(", ");
1536
+ throw new Error(
1537
+ `No extension point or service available for the following ref(s): ${missing}`
1538
+ );
1539
+ }
1540
+ return Object.fromEntries(result);
1541
+ };
1542
+ _addFeature = new WeakSet();
1543
+ addFeature_fn = function(feature) {
1544
+ if (feature.$$type !== "@backstage/BackendFeature") {
1545
+ throw new Error(
1546
+ `Failed to add feature, invalid type '${feature.$$type}'`
1547
+ );
1548
+ }
1549
+ if (isServiceFactory(feature)) {
1550
+ if (feature.service.id === backendPluginApi.coreServices.pluginMetadata.id) {
1551
+ throw new Error(
1552
+ `The ${backendPluginApi.coreServices.pluginMetadata.id} service cannot be overridden`
1553
+ );
1554
+ }
1555
+ if (__privateGet$2(this, _providedServiceFactories).find(
1556
+ (sf) => sf.service.id === feature.service.id
1557
+ )) {
1558
+ throw new Error(
1559
+ `Duplicate service implementations provided for ${feature.service.id}`
1560
+ );
1561
+ }
1562
+ __privateGet$2(this, _providedServiceFactories).push(feature);
1563
+ } else if (isInternalBackendFeature(feature)) {
1564
+ if (feature.version !== "v1") {
1565
+ throw new Error(
1566
+ `Failed to add feature, invalid version '${feature.version}'`
1567
+ );
1568
+ }
1569
+ __privateGet$2(this, _features).push(feature);
1570
+ } else {
1571
+ throw new Error(
1572
+ `Failed to add feature, invalid feature ${JSON.stringify(feature)}`
1573
+ );
1574
+ }
1575
+ };
1576
+ _doStart = new WeakSet();
1577
+ doStart_fn = async function() {
1578
+ __privateSet$2(this, _serviceHolder, new ServiceRegistry([
1579
+ ...__privateGet$2(this, _defaultApiFactories),
1580
+ ...__privateGet$2(this, _providedServiceFactories)
1581
+ ]));
1582
+ const featureDiscovery = await __privateGet$2(this, _serviceHolder).get(
1583
+ alpha.featureDiscoveryServiceRef,
1584
+ "root"
1585
+ );
1586
+ if (featureDiscovery) {
1587
+ const { features } = await featureDiscovery.getBackendFeatures();
1588
+ for (const feature of features) {
1589
+ __privateMethod$1(this, _addFeature, addFeature_fn).call(this, feature);
1590
+ }
1591
+ }
1592
+ for (const ref of __privateGet$2(this, _serviceHolder).getServiceRefs()) {
1593
+ if (ref.scope === "root") {
1594
+ await __privateGet$2(this, _serviceHolder).get(ref, "root");
1595
+ }
1596
+ }
1597
+ const pluginInits = /* @__PURE__ */ new Map();
1598
+ const moduleInits = /* @__PURE__ */ new Map();
1599
+ for (const feature of __privateGet$2(this, _features)) {
1600
+ for (const r of feature.getRegistrations()) {
1601
+ const provides = /* @__PURE__ */ new Set();
1602
+ if (r.type === "plugin" || r.type === "module") {
1603
+ for (const [extRef, extImpl] of r.extensionPoints) {
1604
+ if (__privateGet$2(this, _extensionPoints).has(extRef)) {
1605
+ throw new Error(
1606
+ `ExtensionPoint with ID '${extRef.id}' is already registered`
1607
+ );
1608
+ }
1609
+ __privateGet$2(this, _extensionPoints).set(extRef, {
1610
+ impl: extImpl,
1611
+ pluginId: r.pluginId
1612
+ });
1613
+ provides.add(extRef);
1614
+ }
1615
+ }
1616
+ if (r.type === "plugin") {
1617
+ if (pluginInits.has(r.pluginId)) {
1618
+ throw new Error(`Plugin '${r.pluginId}' is already registered`);
1619
+ }
1620
+ pluginInits.set(r.pluginId, {
1621
+ provides,
1622
+ consumes: new Set(Object.values(r.init.deps)),
1623
+ init: r.init
1624
+ });
1625
+ } else {
1626
+ let modules = moduleInits.get(r.pluginId);
1627
+ if (!modules) {
1628
+ modules = /* @__PURE__ */ new Map();
1629
+ moduleInits.set(r.pluginId, modules);
1630
+ }
1631
+ if (modules.has(r.moduleId)) {
1632
+ throw new Error(
1633
+ `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`
1634
+ );
1635
+ }
1636
+ modules.set(r.moduleId, {
1637
+ provides,
1638
+ consumes: new Set(Object.values(r.init.deps)),
1639
+ init: r.init
1640
+ });
1641
+ }
1642
+ }
1643
+ }
1644
+ const allPluginIds = [
1645
+ .../* @__PURE__ */ new Set([...pluginInits.keys(), ...moduleInits.keys()])
1646
+ ];
1647
+ await Promise.all(
1648
+ allPluginIds.map(async (pluginId) => {
1649
+ const modules = moduleInits.get(pluginId);
1650
+ if (modules) {
1651
+ const tree = DependencyGraph.fromIterable(
1652
+ Array.from(modules).map(([moduleId, moduleInit]) => ({
1653
+ value: { moduleId, moduleInit },
1654
+ // Relationships are reversed at this point since we're only interested in the extension points.
1655
+ // If a modules provides extension point A we want it to be initialized AFTER all modules
1656
+ // that depend on extension point A, so that they can provide their extensions.
1657
+ consumes: Array.from(moduleInit.provides).map((p) => p.id),
1658
+ provides: Array.from(moduleInit.consumes).map((c) => c.id)
1659
+ }))
1660
+ );
1661
+ const circular = tree.detectCircularDependency();
1662
+ if (circular) {
1663
+ throw new errors.ConflictError(
1664
+ `Circular dependency detected for modules of plugin '${pluginId}', ${circular.map(({ moduleId }) => `'${moduleId}'`).join(" -> ")}`
1665
+ );
1666
+ }
1667
+ await tree.parallelTopologicalTraversal(
1668
+ async ({ moduleId, moduleInit }) => {
1669
+ const moduleDeps = await __privateMethod$1(this, _getInitDeps, getInitDeps_fn).call(this, moduleInit.init.deps, pluginId);
1670
+ await moduleInit.init.func(moduleDeps).catch((error) => {
1671
+ throw new errors.ForwardedError(
1672
+ `Module '${moduleId}' for plugin '${pluginId}' startup failed`,
1673
+ error
1674
+ );
1675
+ });
1676
+ }
1677
+ );
1678
+ }
1679
+ const pluginInit = pluginInits.get(pluginId);
1680
+ if (pluginInit) {
1681
+ const pluginDeps = await __privateMethod$1(this, _getInitDeps, getInitDeps_fn).call(this, pluginInit.init.deps, pluginId);
1682
+ await pluginInit.init.func(pluginDeps).catch((error) => {
1683
+ throw new errors.ForwardedError(
1684
+ `Plugin '${pluginId}' startup failed`,
1685
+ error
1686
+ );
1687
+ });
1688
+ }
1689
+ const lifecycleService2 = await __privateMethod$1(this, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn).call(this, pluginId);
1690
+ await lifecycleService2.startup();
1691
+ })
1692
+ );
1693
+ const lifecycleService = await __privateMethod$1(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1694
+ await lifecycleService.startup();
1695
+ if (process.env.NODE_ENV !== "test") {
1696
+ const rootLogger = await __privateGet$2(this, _serviceHolder).get(
1697
+ backendPluginApi.coreServices.rootLogger,
1698
+ "root"
1699
+ );
1700
+ process.on("unhandledRejection", (reason) => {
1701
+ var _a;
1702
+ (_a = rootLogger == null ? void 0 : rootLogger.child({ type: "unhandledRejection" })) == null ? void 0 : _a.error("Unhandled rejection", reason);
1703
+ });
1704
+ process.on("uncaughtException", (error) => {
1705
+ var _a;
1706
+ (_a = rootLogger == null ? void 0 : rootLogger.child({ type: "uncaughtException" })) == null ? void 0 : _a.error("Uncaught exception", error);
1707
+ });
1708
+ }
1709
+ };
1710
+ _getRootLifecycleImpl = new WeakSet();
1711
+ getRootLifecycleImpl_fn = async function() {
1712
+ const lifecycleService = await __privateGet$2(this, _serviceHolder).get(
1713
+ backendPluginApi.coreServices.rootLifecycle,
1714
+ "root"
1715
+ );
1716
+ if (lifecycleService instanceof BackendLifecycleImpl) {
1717
+ return lifecycleService;
1718
+ }
1719
+ throw new Error("Unexpected root lifecycle service implementation");
1720
+ };
1721
+ _getPluginLifecycleImpl = new WeakSet();
1722
+ getPluginLifecycleImpl_fn = async function(pluginId) {
1723
+ const lifecycleService = await __privateGet$2(this, _serviceHolder).get(
1724
+ backendPluginApi.coreServices.lifecycle,
1725
+ pluginId
1726
+ );
1727
+ if (lifecycleService instanceof BackendPluginLifecycleImpl) {
1728
+ return lifecycleService;
1729
+ }
1730
+ throw new Error("Unexpected plugin lifecycle service implementation");
1731
+ };
1732
+ function isServiceFactory(feature) {
1733
+ return !!feature.service;
1734
+ }
1735
+ function isInternalBackendFeature(feature) {
1736
+ return typeof feature.getRegistrations === "function";
1737
+ }
1738
+
1501
1739
  var __accessCheck$1 = (obj, member, msg) => {
1502
1740
  if (!member.has(obj))
1503
1741
  throw TypeError("Cannot " + msg);
@@ -1516,16 +1754,14 @@ var __privateSet$1 = (obj, member, value, setter) => {
1516
1754
  setter ? setter.call(obj, value) : member.set(obj, value);
1517
1755
  return value;
1518
1756
  };
1519
- var _services, _initializer;
1757
+ var _initializer;
1520
1758
  class BackstageBackend {
1521
- constructor(apiFactories) {
1522
- __privateAdd$1(this, _services, void 0);
1759
+ constructor(defaultServiceFactories) {
1523
1760
  __privateAdd$1(this, _initializer, void 0);
1524
- __privateSet$1(this, _services, new ServiceRegistry(apiFactories));
1525
- __privateSet$1(this, _initializer, new BackendInitializer(__privateGet$1(this, _services)));
1761
+ __privateSet$1(this, _initializer, new BackendInitializer(defaultServiceFactories));
1526
1762
  }
1527
1763
  add(feature) {
1528
- __privateGet$1(this, _initializer).add(feature);
1764
+ __privateGet$1(this, _initializer).add(typeof feature === "function" ? feature() : feature);
1529
1765
  }
1530
1766
  async start() {
1531
1767
  await __privateGet$1(this, _initializer).start();
@@ -1534,11 +1770,10 @@ class BackstageBackend {
1534
1770
  await __privateGet$1(this, _initializer).stop();
1535
1771
  }
1536
1772
  }
1537
- _services = new WeakMap();
1538
1773
  _initializer = new WeakMap();
1539
1774
 
1540
1775
  function createSpecializedBackend(options) {
1541
- const services = options.services.map(
1776
+ const services = options.defaultServiceFactories.map(
1542
1777
  (sf) => typeof sf === "function" ? sf() : sf
1543
1778
  );
1544
1779
  const exists = /* @__PURE__ */ new Set();