@backstage/backend-app-api 0.4.4-next.0 → 0.4.4-next.2

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

Potentially problematic release.


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

package/dist/index.cjs.js CHANGED
@@ -22,6 +22,7 @@ var errors = require('@backstage/errors');
22
22
  var winston = require('winston');
23
23
  var backendPluginApi = require('@backstage/backend-plugin-api');
24
24
  var backendCommon = require('@backstage/backend-common');
25
+ var PromiseRouter = require('express-promise-router');
25
26
  var pluginAuthNode = require('@backstage/plugin-auth-node');
26
27
  var pluginPermissionNode = require('@backstage/plugin-permission-node');
27
28
  var express = require('express');
@@ -58,6 +59,7 @@ var cors__default = /*#__PURE__*/_interopDefaultLegacy(cors);
58
59
  var helmet__default = /*#__PURE__*/_interopDefaultLegacy(helmet);
59
60
  var morgan__default = /*#__PURE__*/_interopDefaultLegacy(morgan);
60
61
  var compression__default = /*#__PURE__*/_interopDefaultLegacy(compression);
62
+ var PromiseRouter__default = /*#__PURE__*/_interopDefaultLegacy(PromiseRouter);
61
63
  var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
62
64
  var trimEnd__default = /*#__PURE__*/_interopDefaultLegacy(trimEnd);
63
65
 
@@ -575,31 +577,31 @@ function createCorsOriginMatcher(allowedOriginPatterns) {
575
577
  };
576
578
  }
577
579
 
578
- var __accessCheck$6 = (obj, member, msg) => {
580
+ var __accessCheck$7 = (obj, member, msg) => {
579
581
  if (!member.has(obj))
580
582
  throw TypeError("Cannot " + msg);
581
583
  };
582
- var __privateGet$6 = (obj, member, getter) => {
583
- __accessCheck$6(obj, member, "read from private field");
584
+ var __privateGet$7 = (obj, member, getter) => {
585
+ __accessCheck$7(obj, member, "read from private field");
584
586
  return getter ? getter.call(obj) : member.get(obj);
585
587
  };
586
- var __privateAdd$6 = (obj, member, value) => {
588
+ var __privateAdd$7 = (obj, member, value) => {
587
589
  if (member.has(obj))
588
590
  throw TypeError("Cannot add the same private member more than once");
589
591
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
590
592
  };
591
- var __privateSet$6 = (obj, member, value, setter) => {
592
- __accessCheck$6(obj, member, "write to private field");
593
+ var __privateSet$7 = (obj, member, value, setter) => {
594
+ __accessCheck$7(obj, member, "write to private field");
593
595
  setter ? setter.call(obj, value) : member.set(obj, value);
594
596
  return value;
595
597
  };
596
598
  var _config, _logger;
597
599
  const _MiddlewareFactory = class {
598
600
  constructor(options) {
599
- __privateAdd$6(this, _config, void 0);
600
- __privateAdd$6(this, _logger, void 0);
601
- __privateSet$6(this, _config, options.config);
602
- __privateSet$6(this, _logger, options.logger);
601
+ __privateAdd$7(this, _config, void 0);
602
+ __privateAdd$7(this, _logger, void 0);
603
+ __privateSet$7(this, _config, options.config);
604
+ __privateSet$7(this, _logger, options.logger);
603
605
  }
604
606
  /**
605
607
  * Creates a new {@link MiddlewareFactory}.
@@ -645,7 +647,7 @@ const _MiddlewareFactory = class {
645
647
  * @returns An Express request handler
646
648
  */
647
649
  logging() {
648
- const logger = __privateGet$6(this, _logger).child({
650
+ const logger = __privateGet$7(this, _logger).child({
649
651
  type: "incomingRequest"
650
652
  });
651
653
  return morgan__default["default"]("combined", {
@@ -669,7 +671,7 @@ const _MiddlewareFactory = class {
669
671
  * @returns An Express request handler
670
672
  */
671
673
  helmet() {
672
- return helmet__default["default"](readHelmetOptions(__privateGet$6(this, _config).getOptionalConfig("backend")));
674
+ return helmet__default["default"](readHelmetOptions(__privateGet$7(this, _config).getOptionalConfig("backend")));
673
675
  }
674
676
  /**
675
677
  * Returns a middleware that implements the cors library.
@@ -684,7 +686,7 @@ const _MiddlewareFactory = class {
684
686
  * @returns An Express request handler
685
687
  */
686
688
  cors() {
687
- return cors__default["default"](readCorsOptions(__privateGet$6(this, _config).getOptionalConfig("backend")));
689
+ return cors__default["default"](readCorsOptions(__privateGet$7(this, _config).getOptionalConfig("backend")));
688
690
  }
689
691
  /**
690
692
  * Express middleware to handle errors during request processing.
@@ -709,7 +711,7 @@ const _MiddlewareFactory = class {
709
711
  error(options = {}) {
710
712
  var _a;
711
713
  const showStackTraces = (_a = options.showStackTraces) != null ? _a : process.env.NODE_ENV === "development";
712
- const logger = __privateGet$6(this, _logger).child({
714
+ const logger = __privateGet$7(this, _logger).child({
713
715
  type: "errorHandler"
714
716
  });
715
717
  return (error, req, res, next) => {
@@ -757,6 +759,8 @@ function getStatusCode(error) {
757
759
  return 409;
758
760
  case errors.NotImplementedError.name:
759
761
  return 501;
762
+ case errors.ServiceUnavailableError.name:
763
+ return 503;
760
764
  }
761
765
  return 500;
762
766
  }
@@ -765,31 +769,31 @@ const escapeRegExp = (text) => {
765
769
  return text.replace(/[.*+?^${}(\)|[\]\\]/g, "\\$&");
766
770
  };
767
771
 
768
- var __accessCheck$5 = (obj, member, msg) => {
772
+ var __accessCheck$6 = (obj, member, msg) => {
769
773
  if (!member.has(obj))
770
774
  throw TypeError("Cannot " + msg);
771
775
  };
772
- var __privateGet$5 = (obj, member, getter) => {
773
- __accessCheck$5(obj, member, "read from private field");
776
+ var __privateGet$6 = (obj, member, getter) => {
777
+ __accessCheck$6(obj, member, "read from private field");
774
778
  return getter ? getter.call(obj) : member.get(obj);
775
779
  };
776
- var __privateAdd$5 = (obj, member, value) => {
780
+ var __privateAdd$6 = (obj, member, value) => {
777
781
  if (member.has(obj))
778
782
  throw TypeError("Cannot add the same private member more than once");
779
783
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
780
784
  };
781
- var __privateSet$5 = (obj, member, value, setter) => {
782
- __accessCheck$5(obj, member, "write to private field");
785
+ var __privateSet$6 = (obj, member, value, setter) => {
786
+ __accessCheck$6(obj, member, "write to private field");
783
787
  setter ? setter.call(obj, value) : member.set(obj, value);
784
788
  return value;
785
789
  };
786
790
  var _winston, _addRedactions;
787
791
  const _WinstonLogger = class {
788
792
  constructor(winston, addRedactions) {
789
- __privateAdd$5(this, _winston, void 0);
790
- __privateAdd$5(this, _addRedactions, void 0);
791
- __privateSet$5(this, _winston, winston);
792
- __privateSet$5(this, _addRedactions, addRedactions);
793
+ __privateAdd$6(this, _winston, void 0);
794
+ __privateAdd$6(this, _addRedactions, void 0);
795
+ __privateSet$6(this, _winston, winston);
796
+ __privateSet$6(this, _addRedactions, addRedactions);
793
797
  }
794
798
  /**
795
799
  * Creates a {@link WinstonLogger} instance.
@@ -866,70 +870,102 @@ const _WinstonLogger = class {
866
870
  );
867
871
  }
868
872
  error(message, meta) {
869
- __privateGet$5(this, _winston).error(message, meta);
873
+ __privateGet$6(this, _winston).error(message, meta);
870
874
  }
871
875
  warn(message, meta) {
872
- __privateGet$5(this, _winston).warn(message, meta);
876
+ __privateGet$6(this, _winston).warn(message, meta);
873
877
  }
874
878
  info(message, meta) {
875
- __privateGet$5(this, _winston).info(message, meta);
879
+ __privateGet$6(this, _winston).info(message, meta);
876
880
  }
877
881
  debug(message, meta) {
878
- __privateGet$5(this, _winston).debug(message, meta);
882
+ __privateGet$6(this, _winston).debug(message, meta);
879
883
  }
880
884
  child(meta) {
881
- return new _WinstonLogger(__privateGet$5(this, _winston).child(meta));
885
+ return new _WinstonLogger(__privateGet$6(this, _winston).child(meta));
882
886
  }
883
887
  addRedactions(redactions) {
884
888
  var _a;
885
- (_a = __privateGet$5(this, _addRedactions)) == null ? void 0 : _a.call(this, redactions);
889
+ (_a = __privateGet$6(this, _addRedactions)) == null ? void 0 : _a.call(this, redactions);
886
890
  }
887
891
  };
888
892
  let WinstonLogger = _WinstonLogger;
889
893
  _winston = new WeakMap();
890
894
  _addRedactions = new WeakMap();
891
895
 
892
- var __accessCheck$4 = (obj, member, msg) => {
896
+ var __accessCheck$5 = (obj, member, msg) => {
893
897
  if (!member.has(obj))
894
898
  throw TypeError("Cannot " + msg);
895
899
  };
896
- var __privateGet$4 = (obj, member, getter) => {
897
- __accessCheck$4(obj, member, "read from private field");
900
+ var __privateGet$5 = (obj, member, getter) => {
901
+ __accessCheck$5(obj, member, "read from private field");
898
902
  return getter ? getter.call(obj) : member.get(obj);
899
903
  };
900
- var __privateAdd$4 = (obj, member, value) => {
904
+ var __privateAdd$5 = (obj, member, value) => {
901
905
  if (member.has(obj))
902
906
  throw TypeError("Cannot add the same private member more than once");
903
907
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
904
908
  };
905
- var __privateSet$4 = (obj, member, value, setter) => {
906
- __accessCheck$4(obj, member, "write to private field");
909
+ var __privateSet$5 = (obj, member, value, setter) => {
910
+ __accessCheck$5(obj, member, "write to private field");
907
911
  setter ? setter.call(obj, value) : member.set(obj, value);
908
912
  return value;
909
913
  };
910
- var _isCalled, _shutdownTasks;
914
+ var _hasStarted$1, _startupTasks$1, _hasShutdown, _shutdownTasks;
911
915
  class BackendLifecycleImpl {
912
916
  constructor(logger) {
913
917
  this.logger = logger;
914
- __privateAdd$4(this, _isCalled, false);
915
- __privateAdd$4(this, _shutdownTasks, []);
918
+ __privateAdd$5(this, _hasStarted$1, false);
919
+ __privateAdd$5(this, _startupTasks$1, []);
920
+ __privateAdd$5(this, _hasShutdown, false);
921
+ __privateAdd$5(this, _shutdownTasks, []);
922
+ }
923
+ addStartupHook(hook, options) {
924
+ if (__privateGet$5(this, _hasStarted$1)) {
925
+ throw new Error("Attempted to add startup hook after startup");
926
+ }
927
+ __privateGet$5(this, _startupTasks$1).push({ hook, options });
928
+ }
929
+ async startup() {
930
+ if (__privateGet$5(this, _hasStarted$1)) {
931
+ return;
932
+ }
933
+ __privateSet$5(this, _hasStarted$1, true);
934
+ this.logger.debug(`Running ${__privateGet$5(this, _startupTasks$1).length} startup tasks...`);
935
+ await Promise.all(
936
+ __privateGet$5(this, _startupTasks$1).map(async ({ hook, options }) => {
937
+ var _a;
938
+ const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
939
+ try {
940
+ await hook();
941
+ logger.debug(`Startup hook succeeded`);
942
+ } catch (error) {
943
+ logger.error(`Startup hook failed, ${error}`);
944
+ }
945
+ })
946
+ );
916
947
  }
917
948
  addShutdownHook(hook, options) {
918
- __privateGet$4(this, _shutdownTasks).push({ hook, options });
949
+ if (__privateGet$5(this, _hasShutdown)) {
950
+ throw new Error("Attempted to add shutdown hook after shutdown");
951
+ }
952
+ __privateGet$5(this, _shutdownTasks).push({ hook, options });
919
953
  }
920
954
  async shutdown() {
921
- if (__privateGet$4(this, _isCalled)) {
955
+ if (__privateGet$5(this, _hasShutdown)) {
922
956
  return;
923
957
  }
924
- __privateSet$4(this, _isCalled, true);
925
- this.logger.info(`Running ${__privateGet$4(this, _shutdownTasks).length} shutdown tasks...`);
958
+ __privateSet$5(this, _hasShutdown, true);
959
+ this.logger.debug(
960
+ `Running ${__privateGet$5(this, _shutdownTasks).length} shutdown tasks...`
961
+ );
926
962
  await Promise.all(
927
- __privateGet$4(this, _shutdownTasks).map(async ({ hook, options }) => {
963
+ __privateGet$5(this, _shutdownTasks).map(async ({ hook, options }) => {
928
964
  var _a;
929
965
  const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
930
966
  try {
931
967
  await hook();
932
- logger.info(`Shutdown hook succeeded`);
968
+ logger.debug(`Shutdown hook succeeded`);
933
969
  } catch (error) {
934
970
  logger.error(`Shutdown hook failed, ${error}`);
935
971
  }
@@ -937,7 +973,9 @@ class BackendLifecycleImpl {
937
973
  );
938
974
  }
939
975
  }
940
- _isCalled = new WeakMap();
976
+ _hasStarted$1 = new WeakMap();
977
+ _startupTasks$1 = new WeakMap();
978
+ _hasShutdown = new WeakMap();
941
979
  _shutdownTasks = new WeakMap();
942
980
  const rootLifecycleServiceFactory = backendPluginApi.createServiceFactory({
943
981
  service: backendPluginApi.coreServices.rootLifecycle,
@@ -949,6 +987,86 @@ const rootLifecycleServiceFactory = backendPluginApi.createServiceFactory({
949
987
  }
950
988
  });
951
989
 
990
+ var __accessCheck$4 = (obj, member, msg) => {
991
+ if (!member.has(obj))
992
+ throw TypeError("Cannot " + msg);
993
+ };
994
+ var __privateGet$4 = (obj, member, getter) => {
995
+ __accessCheck$4(obj, member, "read from private field");
996
+ return getter ? getter.call(obj) : member.get(obj);
997
+ };
998
+ var __privateAdd$4 = (obj, member, value) => {
999
+ if (member.has(obj))
1000
+ throw TypeError("Cannot add the same private member more than once");
1001
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1002
+ };
1003
+ var __privateSet$4 = (obj, member, value, setter) => {
1004
+ __accessCheck$4(obj, member, "write to private field");
1005
+ setter ? setter.call(obj, value) : member.set(obj, value);
1006
+ return value;
1007
+ };
1008
+ var _hasStarted, _startupTasks;
1009
+ class BackendPluginLifecycleImpl {
1010
+ constructor(logger, rootLifecycle, pluginMetadata) {
1011
+ this.logger = logger;
1012
+ this.rootLifecycle = rootLifecycle;
1013
+ this.pluginMetadata = pluginMetadata;
1014
+ __privateAdd$4(this, _hasStarted, false);
1015
+ __privateAdd$4(this, _startupTasks, []);
1016
+ }
1017
+ addStartupHook(hook, options) {
1018
+ if (__privateGet$4(this, _hasStarted)) {
1019
+ throw new Error("Attempted to add startup hook after startup");
1020
+ }
1021
+ __privateGet$4(this, _startupTasks).push({ hook, options });
1022
+ }
1023
+ async startup() {
1024
+ if (__privateGet$4(this, _hasStarted)) {
1025
+ return;
1026
+ }
1027
+ __privateSet$4(this, _hasStarted, true);
1028
+ this.logger.debug(
1029
+ `Running ${__privateGet$4(this, _startupTasks).length} plugin startup tasks...`
1030
+ );
1031
+ await Promise.all(
1032
+ __privateGet$4(this, _startupTasks).map(async ({ hook, options }) => {
1033
+ var _a;
1034
+ const logger = (_a = options == null ? void 0 : options.logger) != null ? _a : this.logger;
1035
+ try {
1036
+ await hook();
1037
+ logger.debug(`Plugin startup hook succeeded`);
1038
+ } catch (error) {
1039
+ logger.error(`Plugin startup hook failed, ${error}`);
1040
+ }
1041
+ })
1042
+ );
1043
+ }
1044
+ addShutdownHook(hook, options) {
1045
+ var _a, _b;
1046
+ const plugin = this.pluginMetadata.getId();
1047
+ this.rootLifecycle.addShutdownHook(hook, {
1048
+ logger: (_b = (_a = options == null ? void 0 : options.logger) == null ? void 0 : _a.child({ plugin })) != null ? _b : this.logger
1049
+ });
1050
+ }
1051
+ }
1052
+ _hasStarted = new WeakMap();
1053
+ _startupTasks = new WeakMap();
1054
+ const lifecycleServiceFactory = backendPluginApi.createServiceFactory({
1055
+ service: backendPluginApi.coreServices.lifecycle,
1056
+ deps: {
1057
+ logger: backendPluginApi.coreServices.logger,
1058
+ rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
1059
+ pluginMetadata: backendPluginApi.coreServices.pluginMetadata
1060
+ },
1061
+ async factory({ rootLifecycle, logger, pluginMetadata }) {
1062
+ return new BackendPluginLifecycleImpl(
1063
+ logger,
1064
+ rootLifecycle,
1065
+ pluginMetadata
1066
+ );
1067
+ }
1068
+ });
1069
+
952
1070
  var __accessCheck$3 = (obj, member, msg) => {
953
1071
  if (!member.has(obj))
954
1072
  throw TypeError("Cannot " + msg);
@@ -971,15 +1089,16 @@ var __privateMethod$2 = (obj, member, method) => {
971
1089
  __accessCheck$3(obj, member, "access private method");
972
1090
  return method;
973
1091
  };
974
- var _startPromise, _features, _registerInits, _extensionPoints, _serviceHolder, _getInitDeps, getInitDeps_fn, _doStart, doStart_fn, _resolveInitOrder, resolveInitOrder_fn;
1092
+ var _startPromise, _features, _extensionPoints, _serviceHolder, _getInitDeps, getInitDeps_fn, _doStart, doStart_fn, _getRootLifecycleImpl, getRootLifecycleImpl_fn, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn;
975
1093
  class BackendInitializer {
976
1094
  constructor(serviceHolder) {
977
1095
  __privateAdd$3(this, _getInitDeps);
978
1096
  __privateAdd$3(this, _doStart);
979
- __privateAdd$3(this, _resolveInitOrder);
1097
+ // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this
1098
+ __privateAdd$3(this, _getRootLifecycleImpl);
1099
+ __privateAdd$3(this, _getPluginLifecycleImpl);
980
1100
  __privateAdd$3(this, _startPromise, void 0);
981
1101
  __privateAdd$3(this, _features, new Array());
982
- __privateAdd$3(this, _registerInits, new Array());
983
1102
  __privateAdd$3(this, _extensionPoints, /* @__PURE__ */ new Map());
984
1103
  __privateAdd$3(this, _serviceHolder, void 0);
985
1104
  __privateSet$3(this, _serviceHolder, serviceHolder);
@@ -1028,20 +1147,12 @@ class BackendInitializer {
1028
1147
  return;
1029
1148
  }
1030
1149
  await __privateGet$3(this, _startPromise);
1031
- const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
1032
- backendPluginApi.coreServices.rootLifecycle,
1033
- "root"
1034
- );
1035
- if (lifecycleService instanceof BackendLifecycleImpl) {
1036
- await lifecycleService.shutdown();
1037
- } else {
1038
- throw new Error("Unexpected lifecycle service implementation");
1039
- }
1150
+ const lifecycleService = await __privateMethod$2(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1151
+ await lifecycleService.shutdown();
1040
1152
  }
1041
1153
  }
1042
1154
  _startPromise = new WeakMap();
1043
1155
  _features = new WeakMap();
1044
- _registerInits = new WeakMap();
1045
1156
  _extensionPoints = new WeakMap();
1046
1157
  _serviceHolder = new WeakMap();
1047
1158
  _getInitDeps = new WeakSet();
@@ -1081,6 +1192,8 @@ doStart_fn = async function() {
1081
1192
  await __privateGet$3(this, _serviceHolder).get(ref, "root");
1082
1193
  }
1083
1194
  }
1195
+ const pluginInits = /* @__PURE__ */ new Map();
1196
+ const moduleInits = /* @__PURE__ */ new Map();
1084
1197
  for (const feature of __privateGet$3(this, _features)) {
1085
1198
  for (const r of feature.getRegistrations()) {
1086
1199
  const provides = /* @__PURE__ */ new Set();
@@ -1095,19 +1208,68 @@ doStart_fn = async function() {
1095
1208
  provides.add(extRef);
1096
1209
  }
1097
1210
  }
1098
- __privateGet$3(this, _registerInits).push({
1099
- id: r.type === "plugin" ? r.pluginId : `${r.pluginId}.${r.moduleId}`,
1100
- provides,
1101
- consumes: new Set(Object.values(r.init.deps)),
1102
- init: r.init
1103
- });
1211
+ if (r.type === "plugin") {
1212
+ if (pluginInits.has(r.pluginId)) {
1213
+ throw new Error(`Plugin '${r.pluginId}' is already registered`);
1214
+ }
1215
+ pluginInits.set(r.pluginId, {
1216
+ provides,
1217
+ consumes: new Set(Object.values(r.init.deps)),
1218
+ init: r.init
1219
+ });
1220
+ } else {
1221
+ let modules = moduleInits.get(r.pluginId);
1222
+ if (!modules) {
1223
+ modules = /* @__PURE__ */ new Map();
1224
+ moduleInits.set(r.pluginId, modules);
1225
+ }
1226
+ if (modules.has(r.moduleId)) {
1227
+ throw new Error(
1228
+ `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`
1229
+ );
1230
+ }
1231
+ modules.set(r.moduleId, {
1232
+ provides,
1233
+ consumes: new Set(Object.values(r.init.deps)),
1234
+ init: r.init
1235
+ });
1236
+ }
1104
1237
  }
1105
1238
  }
1106
- const orderedRegisterResults = __privateMethod$2(this, _resolveInitOrder, resolveInitOrder_fn).call(this, __privateGet$3(this, _registerInits));
1107
- for (const registerInit of orderedRegisterResults) {
1108
- const deps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, registerInit.init.deps, registerInit.id);
1109
- await registerInit.init.func(deps);
1110
- }
1239
+ const allPluginIds = [
1240
+ .../* @__PURE__ */ new Set([...pluginInits.keys(), ...moduleInits.keys()])
1241
+ ];
1242
+ await Promise.all(
1243
+ allPluginIds.map(async (pluginId) => {
1244
+ var _a;
1245
+ const modules = (_a = moduleInits.get(pluginId)) != null ? _a : [];
1246
+ await Promise.all(
1247
+ Array.from(modules).map(async ([moduleId, moduleInit]) => {
1248
+ const moduleDeps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, moduleInit.init.deps, pluginId);
1249
+ await moduleInit.init.func(moduleDeps).catch((error) => {
1250
+ throw new errors.ForwardedError(
1251
+ `Module '${moduleId}' for plugin '${pluginId}' startup failed`,
1252
+ error
1253
+ );
1254
+ });
1255
+ })
1256
+ );
1257
+ const pluginInit = pluginInits.get(pluginId);
1258
+ if (pluginInit) {
1259
+ const pluginDeps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, pluginInit.init.deps, pluginId);
1260
+ await pluginInit.init.func(pluginDeps).catch((error) => {
1261
+ throw new errors.ForwardedError(
1262
+ `Plugin '${pluginId}' startup failed`,
1263
+ error
1264
+ );
1265
+ });
1266
+ }
1267
+ const lifecycleService2 = await __privateMethod$2(this, _getPluginLifecycleImpl, getPluginLifecycleImpl_fn).call(this, pluginId);
1268
+ await lifecycleService2.startup();
1269
+ })
1270
+ );
1271
+ const lifecycleService = await __privateMethod$2(this, _getRootLifecycleImpl, getRootLifecycleImpl_fn).call(this);
1272
+ await lifecycleService.startup();
1111
1273
  if (process.env.NODE_ENV !== "test") {
1112
1274
  const rootLogger = await __privateGet$3(this, _serviceHolder).get(
1113
1275
  backendPluginApi.coreServices.rootLogger,
@@ -1123,29 +1285,27 @@ doStart_fn = async function() {
1123
1285
  });
1124
1286
  }
1125
1287
  };
1126
- _resolveInitOrder = new WeakSet();
1127
- resolveInitOrder_fn = function(registerInits) {
1128
- let registerInitsToOrder = registerInits.slice();
1129
- const orderedRegisterInits = new Array();
1130
- while (registerInitsToOrder.length > 0) {
1131
- const toRemove = /* @__PURE__ */ new Set();
1132
- for (const registerInit of registerInitsToOrder) {
1133
- const unInitializedDependents = [];
1134
- for (const provided of registerInit.provides) {
1135
- if (registerInitsToOrder.some(
1136
- (init) => init !== registerInit && init.consumes.has(provided)
1137
- )) {
1138
- unInitializedDependents.push(provided);
1139
- }
1140
- }
1141
- if (unInitializedDependents.length === 0) {
1142
- orderedRegisterInits.push(registerInit);
1143
- toRemove.add(registerInit);
1144
- }
1145
- }
1146
- registerInitsToOrder = registerInitsToOrder.filter((r) => !toRemove.has(r));
1288
+ _getRootLifecycleImpl = new WeakSet();
1289
+ getRootLifecycleImpl_fn = async function() {
1290
+ const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
1291
+ backendPluginApi.coreServices.rootLifecycle,
1292
+ "root"
1293
+ );
1294
+ if (lifecycleService instanceof BackendLifecycleImpl) {
1295
+ return lifecycleService;
1296
+ }
1297
+ throw new Error("Unexpected root lifecycle service implementation");
1298
+ };
1299
+ _getPluginLifecycleImpl = new WeakSet();
1300
+ getPluginLifecycleImpl_fn = async function(pluginId) {
1301
+ const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
1302
+ backendPluginApi.coreServices.lifecycle,
1303
+ pluginId
1304
+ );
1305
+ if (lifecycleService instanceof BackendPluginLifecycleImpl) {
1306
+ return lifecycleService;
1147
1307
  }
1148
- return orderedRegisterInits;
1308
+ throw new Error("Unexpected plugin lifecycle service implementation");
1149
1309
  };
1150
1310
 
1151
1311
  var __accessCheck$2 = (obj, member, msg) => {
@@ -1458,20 +1618,86 @@ const discoveryServiceFactory = backendPluginApi.createServiceFactory({
1458
1618
  }
1459
1619
  });
1460
1620
 
1621
+ const DEFAULT_TIMEOUT = { seconds: 5 };
1622
+ function durationToMs(duration) {
1623
+ const {
1624
+ years = 0,
1625
+ months = 0,
1626
+ weeks = 0,
1627
+ days = 0,
1628
+ hours = 0,
1629
+ minutes = 0,
1630
+ seconds = 0,
1631
+ milliseconds = 0
1632
+ } = duration;
1633
+ const totalDays = years * 365 + months * 30 + weeks * 7 + days;
1634
+ const totalHours = totalDays * 24 + hours;
1635
+ const totalMinutes = totalHours * 60 + minutes;
1636
+ const totalSeconds = totalMinutes * 60 + seconds;
1637
+ const totalMilliseconds = totalSeconds * 1e3 + milliseconds;
1638
+ return totalMilliseconds;
1639
+ }
1640
+ function createLifecycleMiddleware(options) {
1641
+ const { lifecycle, startupRequestPauseTimeout = DEFAULT_TIMEOUT } = options;
1642
+ let state = "init";
1643
+ const waiting = /* @__PURE__ */ new Set();
1644
+ lifecycle.addStartupHook(async () => {
1645
+ if (state === "init") {
1646
+ state = "up";
1647
+ for (const item of waiting) {
1648
+ clearTimeout(item.timeout);
1649
+ item.next();
1650
+ }
1651
+ waiting.clear();
1652
+ }
1653
+ });
1654
+ lifecycle.addShutdownHook(async () => {
1655
+ state = "down";
1656
+ for (const item of waiting) {
1657
+ clearTimeout(item.timeout);
1658
+ item.next(new errors.ServiceUnavailableError("Service is shutting down"));
1659
+ }
1660
+ waiting.clear();
1661
+ });
1662
+ const timeoutMs = durationToMs(startupRequestPauseTimeout);
1663
+ return (_req, _res, next) => {
1664
+ if (state === "up") {
1665
+ next();
1666
+ return;
1667
+ } else if (state === "down") {
1668
+ next(new errors.ServiceUnavailableError("Service is shutting down"));
1669
+ return;
1670
+ }
1671
+ const item = {
1672
+ next,
1673
+ timeout: setTimeout(() => {
1674
+ if (waiting.delete(item)) {
1675
+ next(new errors.ServiceUnavailableError("Service has not started up yet"));
1676
+ }
1677
+ }, timeoutMs)
1678
+ };
1679
+ waiting.add(item);
1680
+ };
1681
+ }
1682
+
1461
1683
  const httpRouterServiceFactory = backendPluginApi.createServiceFactory(
1462
1684
  (options) => ({
1463
1685
  service: backendPluginApi.coreServices.httpRouter,
1464
1686
  deps: {
1465
1687
  plugin: backendPluginApi.coreServices.pluginMetadata,
1688
+ lifecycle: backendPluginApi.coreServices.lifecycle,
1466
1689
  rootHttpRouter: backendPluginApi.coreServices.rootHttpRouter
1467
1690
  },
1468
- async factory({ plugin, rootHttpRouter }) {
1691
+ async factory({ plugin, rootHttpRouter, lifecycle }) {
1469
1692
  var _a;
1470
1693
  const getPath = (_a = options == null ? void 0 : options.getPath) != null ? _a : (id) => `/api/${id}`;
1471
1694
  const path = getPath(plugin.getId());
1695
+ const router = PromiseRouter__default["default"]();
1696
+ rootHttpRouter.use(path, router);
1697
+ router.use(createLifecycleMiddleware({ lifecycle }));
1472
1698
  return {
1473
1699
  use(handler) {
1474
- rootHttpRouter.use(path, handler);
1700
+ router.use(handler);
1475
1701
  }
1476
1702
  };
1477
1703
  }
@@ -1490,26 +1716,6 @@ const identityServiceFactory = backendPluginApi.createServiceFactory(
1490
1716
  })
1491
1717
  );
1492
1718
 
1493
- const lifecycleServiceFactory = backendPluginApi.createServiceFactory({
1494
- service: backendPluginApi.coreServices.lifecycle,
1495
- deps: {
1496
- logger: backendPluginApi.coreServices.logger,
1497
- rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
1498
- pluginMetadata: backendPluginApi.coreServices.pluginMetadata
1499
- },
1500
- async factory({ rootLifecycle, logger, pluginMetadata }) {
1501
- const plugin = pluginMetadata.getId();
1502
- return {
1503
- addShutdownHook(hook, options) {
1504
- var _a, _b;
1505
- rootLifecycle.addShutdownHook(hook, {
1506
- logger: (_b = (_a = options == null ? void 0 : options.logger) == null ? void 0 : _a.child({ plugin })) != null ? _b : logger
1507
- });
1508
- }
1509
- };
1510
- }
1511
- });
1512
-
1513
1719
  const loggerServiceFactory = backendPluginApi.createServiceFactory({
1514
1720
  service: backendPluginApi.coreServices.logger,
1515
1721
  deps: {
@@ -1749,6 +1955,7 @@ exports.cacheServiceFactory = cacheServiceFactory;
1749
1955
  exports.configServiceFactory = configServiceFactory;
1750
1956
  exports.createConfigSecretEnumerator = createConfigSecretEnumerator;
1751
1957
  exports.createHttpServer = createHttpServer;
1958
+ exports.createLifecycleMiddleware = createLifecycleMiddleware;
1752
1959
  exports.createSpecializedBackend = createSpecializedBackend;
1753
1960
  exports.databaseServiceFactory = databaseServiceFactory;
1754
1961
  exports.discoveryServiceFactory = discoveryServiceFactory;