lifecycleion 0.0.12 → 0.0.14

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.
@@ -158,7 +158,7 @@ interface RestartComponentOptions {
158
158
  /**
159
159
  * Stable, machine-readable failure codes for individual component operations
160
160
  */
161
- type ComponentOperationFailureCode = 'component_not_found' | 'component_already_running' | 'component_already_starting' | 'component_already_stopping' | 'component_not_running' | 'component_stalled' | 'missing_dependency' | 'dependency_not_running' | 'has_running_dependents' | 'startup_in_progress' | 'shutdown_in_progress' | 'component_startup_timeout' | 'component_shutdown_timeout' | 'restart_stop_failed' | 'restart_start_failed' | 'unknown_error';
161
+ type ComponentOperationFailureCode = 'component_not_found' | 'component_already_running' | 'component_already_starting' | 'component_already_stopping' | 'component_not_running' | 'component_stalled' | 'missing_dependency' | 'dependency_not_running' | 'has_running_dependents' | 'startup_in_progress' | 'shutdown_in_progress' | 'component_unexpected_stop' | 'component_startup_timeout' | 'component_shutdown_timeout' | 'restart_stop_failed' | 'restart_start_failed' | 'unknown_error';
162
162
  /**
163
163
  * Failure codes for unregister operations
164
164
  */
@@ -202,7 +202,7 @@ interface StartupResult {
202
202
  /** Reason for failure (when success is false) */
203
203
  reason?: string;
204
204
  /** Error code (when success is false) */
205
- code?: 'already_in_progress' | 'shutdown_in_progress' | 'dependency_cycle' | 'no_components_registered' | 'stalled_components_exist' | 'partial_state' | 'required_component_failed' | 'startup_timeout' | 'unknown_error';
205
+ code?: 'already_in_progress' | 'component_unexpected_stop' | 'shutdown_in_progress' | 'dependency_cycle' | 'no_components_registered' | 'stalled_components_exist' | 'partial_state' | 'required_component_failed' | 'startup_timeout' | 'unknown_error';
206
206
  /** Error object (when success is false due to dependency cycle or unknown error) */
207
207
  error?: Error;
208
208
  /** Total startup duration in milliseconds */
@@ -471,6 +471,7 @@ interface LifecycleCommon extends EventEmitterSurface {
471
471
  attachSignals(): void;
472
472
  detachSignals(): void;
473
473
  getSignalStatus(): LifecycleSignalStatus;
474
+ getShutdownEscalationStatus(): ShutdownEscalationStatus;
474
475
  triggerReload(): Promise<SignalBroadcastResult>;
475
476
  triggerInfo(): Promise<SignalBroadcastResult>;
476
477
  triggerDebug(): Promise<SignalBroadcastResult>;
@@ -681,6 +682,163 @@ interface LifecycleSignalStatus extends ProcessSignalManagerStatus {
681
682
  /** How shutdown was triggered (null if not shut down) */
682
683
  shutdownMethod: ShutdownMethod | null;
683
684
  }
685
+ interface ShutdownEscalationStatusDisabled {
686
+ /** Whether repeated shutdown escalation is configured */
687
+ configured: false;
688
+ /** Whether a shutdown is currently in progress */
689
+ isShuttingDown: boolean;
690
+ /** Escalation cannot be armed when the policy is disabled */
691
+ isArmed: false;
692
+ /** Config fields are unavailable while the policy is disabled */
693
+ forceAfterCount: null;
694
+ withinMS: null;
695
+ armedAfterFailureMS: null;
696
+ armedAfterFailureMSSource: null;
697
+ /** Runtime counters remain empty while the policy is disabled */
698
+ requestCount: 0;
699
+ firstMethod: null;
700
+ latestMethod: null;
701
+ firstRequestAt: null;
702
+ latestRequestAt: null;
703
+ repeatedWindowStartedAt: null;
704
+ armedUntil: null;
705
+ hasTriggeredForceShutdown: false;
706
+ }
707
+ interface ShutdownEscalationStatusEnabled {
708
+ /** Whether repeated shutdown escalation is configured */
709
+ configured: true;
710
+ /** Whether a shutdown is currently in progress */
711
+ isShuttingDown: boolean;
712
+ /** Whether escalation remains armed after an unsuccessful shutdown */
713
+ isArmed: boolean;
714
+ /** Configured force threshold when policy is enabled */
715
+ forceAfterCount: number;
716
+ /** Configured escalation window when policy is enabled */
717
+ withinMS: number;
718
+ /** Effective post-failure armed duration in ms when policy is enabled */
719
+ armedAfterFailureMS: number;
720
+ /** Whether the effective armed duration was explicitly configured or derived from defaults */
721
+ armedAfterFailureMSSource: 'explicit' | 'derived';
722
+ /** Whether manual stopAllComponents() retries continue the armed escalation state */
723
+ countManualRetriesTowardEscalation: boolean;
724
+ /**
725
+ * Number of follow-up shutdown requests counted in the current escalation
726
+ * window (resets when a new window starts). This is a window-local count,
727
+ * not a cumulative total of all requests since shutdown began.
728
+ */
729
+ requestCount: number;
730
+ /** Method that started the current/most recent shutdown escalation cycle */
731
+ firstMethod: ShutdownMethod | null;
732
+ /** Most recent shutdown request method seen by escalation tracking */
733
+ latestMethod: ShutdownMethod | null;
734
+ /** Timestamp of the first shutdown request that seeded this escalation state */
735
+ firstRequestAt: number | null;
736
+ /** Timestamp of the most recent shutdown request counted by escalation tracking */
737
+ latestRequestAt: number | null;
738
+ /** Timestamp when the current post-start escalation window began */
739
+ repeatedWindowStartedAt: number | null;
740
+ /** Timestamp when armed-after-failure escalation will expire */
741
+ armedUntil: number | null;
742
+ /** Whether onForceShutdown() has already been dispatched for this shutdown cycle */
743
+ hasTriggeredForceShutdown: boolean;
744
+ }
745
+ /**
746
+ * Read-only snapshot of repeated shutdown escalation configuration and runtime state.
747
+ */
748
+ type ShutdownEscalationStatus = ShutdownEscalationStatusDisabled | ShutdownEscalationStatusEnabled;
749
+ /**
750
+ * Context passed to repeated shutdown force handlers.
751
+ *
752
+ * The first request starts graceful shutdown. If additional shutdown requests
753
+ * arrive within the configured time window and the threshold is reached, the
754
+ * LifecycleManager invokes `onForceShutdown()` with this snapshot.
755
+ */
756
+ interface ForceShutdownContext {
757
+ /** Number of escalation requests counted after shutdown had already started */
758
+ requestCount: number;
759
+ /** Method that started the current shutdown cycle */
760
+ firstMethod: ShutdownMethod;
761
+ /** Most recent shutdown request method */
762
+ latestMethod: ShutdownMethod;
763
+ /** Unix timestamp in ms for the request that started the current shutdown cycle */
764
+ firstRequestAt: number;
765
+ /** Unix timestamp in ms for the most recent request in the current window */
766
+ latestRequestAt: number;
767
+ /**
768
+ * Whether shutdown is still actively running when the force callback fires.
769
+ *
770
+ * This is `true` when escalation fires during an active shutdown (the normal
771
+ * path: operator pressed the shutdown signal multiple times while
772
+ * `stopAllComponents()` was still running).
773
+ *
774
+ * This is `false` when escalation fires from the post-failure armed window
775
+ * (i.e. a previous shutdown attempt already returned unsuccessfully and the
776
+ * manager kept escalation armed briefly). In that path the force callback
777
+ * fires before the follow-up `stopAllComponents()` call is issued, so no
778
+ * shutdown is actively in progress at the moment the callback runs.
779
+ *
780
+ * Check `wasArmedAfterFailure` to distinguish the two cases.
781
+ */
782
+ isShuttingDown: boolean;
783
+ /**
784
+ * Whether this force-shutdown was triggered from the post-failure armed
785
+ * state rather than during an active shutdown.
786
+ *
787
+ * `true` — a previous shutdown attempt returned unsuccessfully, the manager
788
+ * kept escalation armed, and the force threshold was crossed while
789
+ * that armed window was still open (no shutdown running yet).
790
+ *
791
+ * `false` — the force threshold was crossed while `stopAllComponents()` was
792
+ * actively in progress (the common path).
793
+ *
794
+ * Use this to decide whether your force handler needs to start or re-trigger
795
+ * shutdown, or whether it can assume a shutdown run is already underway.
796
+ */
797
+ wasArmedAfterFailure: boolean;
798
+ }
799
+ /**
800
+ * Optional policy for escalating repeated shutdown requests during an already
801
+ * running shutdown.
802
+ */
803
+ interface RepeatedShutdownRequestPolicy {
804
+ /**
805
+ * Number of shutdown requests required before force escalation runs.
806
+ * Only escalation requests received after shutdown has already started count
807
+ * toward this threshold. The initial request that starts graceful shutdown
808
+ * does not count.
809
+ * @default 3
810
+ */
811
+ forceAfterCount?: number;
812
+ /**
813
+ * Time window in ms for counting follow-up escalation requests received
814
+ * after shutdown has already started.
815
+ * Requests outside the window start a new escalation window.
816
+ * @default 2000
817
+ */
818
+ withinMS?: number;
819
+ /**
820
+ * How long escalation should remain armed after an unsuccessful shutdown
821
+ * returns. When omitted, the manager derives it as `withinMS * forceAfterCount`.
822
+ * Set to `0` to disable post-failure arming entirely — the escalation window
823
+ * will not persist once a shutdown attempt returns, and each new request will
824
+ * start a fresh escalation cycle. (Note: `withinMS = 0` is a separate option
825
+ * that controls the width of the active-shutdown escalation window, not this.)
826
+ */
827
+ armedAfterFailureMS?: number;
828
+ /**
829
+ * If true, manual `stopAllComponents()` retries that happen while the
830
+ * post-failure armed window is still open continue the same escalation state.
831
+ * When false, manual retries always start a fresh escalation cycle.
832
+ * @default false
833
+ */
834
+ countManualRetriesTowardEscalation?: boolean;
835
+ /**
836
+ * Invoked once per shutdown cycle when repeated requests reach the threshold.
837
+ * Typical uses: final logging, telemetry flush, `logger.exit()`, or
838
+ * `process.exit()` by the application.
839
+ */
840
+ onForceShutdown: (context: ForceShutdownContext) => void | Promise<void>;
841
+ }
684
842
  /**
685
843
  * Configuration options for LifecycleManager
686
844
  */
@@ -711,6 +869,11 @@ interface LifecycleManagerOptions {
711
869
  onInfoRequested?: (broadcastInfo: () => Promise<SignalBroadcastResult>) => void | Promise<void>;
712
870
  /** Custom debug signal handler (called instead of default broadcast, receives broadcast function you can optionally call) */
713
871
  onDebugRequested?: (broadcastDebug: () => Promise<SignalBroadcastResult>) => void | Promise<void>;
872
+ /**
873
+ * Optional policy for escalating repeated shutdown requests received while a
874
+ * graceful shutdown is already in progress.
875
+ */
876
+ repeatedShutdownRequestPolicy?: RepeatedShutdownRequestPolicy;
714
877
  }
715
878
 
716
879
  /**
@@ -793,6 +956,10 @@ declare abstract class BaseComponent {
793
956
  protected name: string;
794
957
  /** Reference to component-scoped lifecycle (set by manager when registered) */
795
958
  protected lifecycle: ComponentLifecycleRef;
959
+ /** @internal Set by LifecycleManager while the component is running. */
960
+ private _unexpectedStopHandler?;
961
+ /** @internal Incremented whenever the unexpected-stop handler is re-armed or cleared. */
962
+ private _unexpectedStopGeneration;
796
963
  /**
797
964
  * Create a new component
798
965
  *
@@ -801,6 +968,10 @@ declare abstract class BaseComponent {
801
968
  * @throws {InvalidComponentNameError} If name doesn't match kebab-case pattern
802
969
  */
803
970
  constructor(rootLogger: Logger, options: ComponentOptions);
971
+ /** @internal Called by LifecycleManager after a successful start. */
972
+ _setUnexpectedStopHandler(handler: (error?: Error) => boolean): void;
973
+ /** @internal Called by LifecycleManager when stop begins or component is unregistered. */
974
+ _clearUnexpectedStopHandler(): void;
804
975
  /**
805
976
  * Start the component
806
977
  *
@@ -983,6 +1154,28 @@ declare abstract class BaseComponent {
983
1154
  * Check if component is optional
984
1155
  */
985
1156
  isOptional(): boolean;
1157
+ /**
1158
+ * Run-scoped unexpected-stop callback. Rebound by LifecycleManager on each
1159
+ * successful start so captured references from older runs go stale.
1160
+ */
1161
+ protected reportUnexpectedStop: (error?: Error) => boolean;
1162
+ /**
1163
+ * Get this component's own status from the manager's perspective.
1164
+ *
1165
+ * Equivalent to `this.lifecycle.getComponentStatus(this.getName())` but without
1166
+ * needing to pass the name. Returns `undefined` if the component is not registered.
1167
+ *
1168
+ * Check `status?.state === 'running'` to test whether the component is currently running.
1169
+ */
1170
+ protected getSelfStatus(): ComponentStatus | undefined;
1171
+ /**
1172
+ * Capture a run-scoped unexpected-stop reporter for async listeners created during start().
1173
+ *
1174
+ * Unlike calling `this.reportUnexpectedStop()` later, the returned callback becomes a no-op
1175
+ * once the component is stopped, unregistered, or restarted. This prevents stale listeners
1176
+ * from a previous run from stopping a newer run of the same component instance.
1177
+ */
1178
+ protected getUnexpectedStopReporter(): (error?: Error) => boolean;
986
1179
  }
987
1180
 
988
1181
  /**
@@ -1008,6 +1201,7 @@ declare class LifecycleManager extends EventEmitterProtected implements Lifecycl
1008
1201
  private readonly attachSignalsBeforeStartup;
1009
1202
  private readonly attachSignalsOnStart;
1010
1203
  private readonly detachSignalsOnStop;
1204
+ private readonly repeatedShutdownRequestPolicy?;
1011
1205
  private components;
1012
1206
  private runningComponents;
1013
1207
  private componentStates;
@@ -1015,13 +1209,19 @@ declare class LifecycleManager extends EventEmitterProtected implements Lifecycl
1015
1209
  private componentTimestamps;
1016
1210
  private componentErrors;
1017
1211
  private componentStartAttemptTokens;
1212
+ private componentStopAttemptTokens;
1213
+ private pendingForceStopWaiters;
1214
+ private unexpectedStopsDuringStartup;
1018
1215
  private isStarting;
1216
+ private autoAttachedSignalsDuringStartup;
1019
1217
  private isStarted;
1020
1218
  private isShuttingDown;
1021
1219
  private shutdownToken;
1022
1220
  private pendingLoggerExitResolve;
1023
1221
  private shutdownMethod;
1024
1222
  private lastShutdownResult;
1223
+ private repeatedShutdownExpiryTimer;
1224
+ private repeatedShutdownRequestState;
1025
1225
  private processSignalManager;
1026
1226
  private readonly onReloadRequested?;
1027
1227
  private readonly onInfoRequested?;
@@ -1214,6 +1414,10 @@ declare class LifecycleManager extends EventEmitterProtected implements Lifecycl
1214
1414
  * Get status information about signal handling.
1215
1415
  */
1216
1416
  getSignalStatus(): LifecycleSignalStatus;
1417
+ /**
1418
+ * Get status information about repeated shutdown escalation configuration and runtime state.
1419
+ */
1420
+ getShutdownEscalationStatus(): ShutdownEscalationStatus;
1217
1421
  /**
1218
1422
  * Enable Logger exit hook integration
1219
1423
  *
@@ -1422,6 +1626,45 @@ declare class LifecycleManager extends EventEmitterProtected implements Lifecycl
1422
1626
  private autoAttachSignals;
1423
1627
  private autoDetachSignalsIfIdle;
1424
1628
  private monitorLateStartupCompletion;
1629
+ private consumeUnexpectedStopsDuringStartup;
1630
+ /**
1631
+ * Issues and returns a unique stop attempt token for a component.
1632
+ *
1633
+ * Each stop attempt (graceful or force-retry) gets a unique token.
1634
+ * The late-resolution handler captures this token in its closure so it can
1635
+ * skip any stall entries that were created by a *later* stop attempt — e.g. a
1636
+ * force-retry that also timed out after the original graceful promise floated
1637
+ * in the background.
1638
+ */
1639
+ private issueStopAttemptToken;
1640
+ private createPendingForceStopWaiter;
1641
+ private resolvePendingForceStopWaiters;
1642
+ /**
1643
+ * Called when a stop promise eventually resolves after its timeout path already fired.
1644
+ *
1645
+ * Usually this means a previously stalled component's original stop() or
1646
+ * onShutdownForce() promise finally resolved, so the manager can clear the
1647
+ * stall and transition the component to stopped without a manual retry.
1648
+ *
1649
+ * There is one extra overlap case for graceful stop(): stop() can resolve
1650
+ * after the graceful timeout but before onShutdownForce() itself times out.
1651
+ * In that window no stall entry exists yet, but the component still finished
1652
+ * stopping cleanly, so we finalize it here and let the later force-timeout
1653
+ * path observe the already-stopped state and no-op. This overlap fix is
1654
+ * scoped to the same stop token and will not cross a later retry attempt.
1655
+ *
1656
+ * Two guards prevent stale floating promises from incorrectly clearing state:
1657
+ *
1658
+ * 1. token guard — if a newer stop attempt (e.g. a retryStalled
1659
+ * force-retry) has started since this promise was launched, its token
1660
+ * won't match and we bail out immediately.
1661
+ *
1662
+ * 2. state/stall guard — if the component was unregistered, restarted, or
1663
+ * already cleared by another path, there will be neither a matching stall
1664
+ * entry nor the force-phase overlap state, so we bail out.
1665
+ */
1666
+ private handleLateStopResolution;
1667
+ private handleComponentUnexpectedStop;
1425
1668
  /**
1426
1669
  * Safe emit wrapper - prevents event handler errors from breaking lifecycle
1427
1670
  */
@@ -1470,40 +1713,100 @@ declare class LifecycleManager extends EventEmitterProtected implements Lifecycl
1470
1713
  private findAllCircularCycles;
1471
1714
  /**
1472
1715
  * Handle shutdown signal - initiates stopAllComponents().
1473
- * Double signal protection: if already shutting down, log warning and ignore.
1474
- */
1475
- private handleShutdownRequest;
1476
- /**
1477
- * Handle reload request - calls custom callback or broadcasts to components.
1478
1716
  *
1479
- * When called from signal handlers (source='signal'), the Promise is started
1480
- * but not awaited due to Node.js signal handler constraints. Components are
1481
- * still notified and the work completes, but return values are not accessible.
1717
+ * Four cases depending on the current shutdown state:
1482
1718
  *
1483
- * When called from manual triggers (source='trigger'), the Promise is awaited
1484
- * and results are returned for programmatic use.
1719
+ * 1. **Active shutdown** (`isShuttingDown = true`): escalate through the
1720
+ * repeated-shutdown policy if configured, otherwise log and discard.
1721
+ * Emits `signal:shutdown` with `isAlreadyShuttingDown: true` and returns
1722
+ * without starting another shutdown.
1723
+ *
1724
+ * 2. **Armed post-failure** (previous shutdown finished, armed window still
1725
+ * open): count the request toward the escalation window, emit
1726
+ * `signal:shutdown` with `isAlreadyShuttingDown: false`, then start a
1727
+ * new `stopAllComponents()` run to retry.
1728
+ *
1729
+ * 3. **Armed post-failure expired** (armed window opened but has since
1730
+ * elapsed): expire the stale state, treat the request as a fresh
1731
+ * shutdown (falls through to case 4).
1732
+ *
1733
+ * 4. **Fresh shutdown** (no prior shutdown state): seed escalation tracking
1734
+ * if policy is configured, emit `signal:shutdown` with
1735
+ * `isAlreadyShuttingDown: false`, and start `stopAllComponents()`.
1485
1736
  *
1486
- * @param source - Whether triggered from signal manager or manual trigger
1737
+ * In all cases `signal:shutdown` is emitted exactly once.
1487
1738
  */
1488
- private handleReloadRequest;
1739
+ private handleShutdownRequest;
1489
1740
  /**
1490
- * Handle info request - calls custom callback or broadcasts to components.
1741
+ * Tracks repeated shutdown requests during an active shutdown and optionally
1742
+ * invokes the configured force shutdown callback when the threshold is reached.
1491
1743
  *
1492
- * When called from signal handlers, the Promise executes but return values
1493
- * are not accessible due to Node.js signal handler constraints.
1744
+ * @returns true when the request was consumed as part of the repeated-shutdown
1745
+ * escalation flow, false when the caller should treat it as a fresh shutdown request
1746
+ */
1747
+ private handleRepeatedShutdownRequest;
1748
+ /**
1749
+ * Clears repeated shutdown request tracking so a new shutdown cycle starts fresh.
1750
+ */
1751
+ private resetRepeatedShutdownRequestState;
1752
+ /**
1753
+ * Clear any pending expiration timer for the post-failure escalation window.
1754
+ */
1755
+ private clearRepeatedShutdownExpiryTimer;
1756
+ /**
1757
+ * Returns whether post-failure escalation remains armed after first
1758
+ * normalizing any stale timer-backed state.
1494
1759
  *
1495
- * @param source - Whether triggered from signal manager or manual trigger
1760
+ * The method can expire old armed windows as a side effect because the timer
1761
+ * callback may not have run yet on a delayed event loop. Callers use this
1762
+ * when they need the effective runtime truth, not just the last timer write.
1496
1763
  */
1497
- private handleInfoRequest;
1764
+ private normalizeRepeatedShutdownRequestStateArmedStatus;
1498
1765
  /**
1499
- * Handle debug request - calls custom callback or broadcasts to components.
1766
+ * Transition armed post-failure escalation state into its expired/reset state.
1767
+ */
1768
+ private expireRepeatedShutdownRequestState;
1769
+ /**
1770
+ * Arms or refreshes the post-failure escalation window and its expiration timer.
1771
+ */
1772
+ private refreshRepeatedShutdownArmedWindow;
1773
+ /**
1774
+ * Seeds shutdown escalation tracking for a new shutdown cycle.
1500
1775
  *
1501
- * When called from signal handlers, the Promise executes but return values
1502
- * are not accessible due to Node.js signal handler constraints.
1776
+ * The first shutdown trigger starts graceful shutdown and arms escalation with
1777
+ * an effective post-start count of 0. Later shutdown requests can then count
1778
+ * toward the configured force threshold regardless of whether the shutdown
1779
+ * started from a signal, keyboard shortcut, or direct API call.
1780
+ */
1781
+ private seedRepeatedShutdownRequestState;
1782
+ /**
1783
+ * Preserves a short-lived post-failure escalation window after shutdown
1784
+ * returns unsuccessfully so operators can keep pressing shutdown without
1785
+ * losing the existing force count the moment the graceful attempt finishes.
1786
+ */
1787
+ private armRepeatedShutdownAfterFailure;
1788
+ /**
1789
+ * Shared dispatch path for reload/info/debug requests. Logs the dispatch,
1790
+ * emits the signal event, then either invokes the user-supplied callback
1791
+ * (passing the broadcast function so the user controls when/whether to
1792
+ * broadcast) or broadcasts directly when no callback is configured.
1503
1793
  *
1504
- * @param source - Whether triggered from signal manager or manual trigger
1794
+ * When called from signal handlers (source='signal'), the Promise is started
1795
+ * but not awaited — Node.js signal handlers cannot return values, so results
1796
+ * are not accessible. Components are still notified and the work completes.
1797
+ * When called from manual triggers (source='trigger'), the Promise is awaited
1798
+ * and results are returned for programmatic use.
1505
1799
  */
1800
+ private handleSignalRequest;
1801
+ private handleReloadRequest;
1802
+ private handleInfoRequest;
1506
1803
  private handleDebugRequest;
1804
+ /**
1805
+ * Shared signal broadcast pipeline used by reload/info/debug.
1806
+ * Iterates running components, runs the picked handler with timeout, and
1807
+ * aggregates per-component results into a SignalBroadcastResult.
1808
+ */
1809
+ private runSignalBroadcast;
1507
1810
  /**
1508
1811
  * Broadcast reload signal to all running components.
1509
1812
  * Calls onReload() on components that implement it.
@@ -1637,6 +1940,28 @@ interface LifecycleManagerEventMap {
1637
1940
  method: ShutdownMethod;
1638
1941
  duringStartup: boolean;
1639
1942
  };
1943
+ /** Failed/timed-out shutdown left escalation armed briefly for follow-up force presses. */
1944
+ 'lifecycle-manager:shutdown-escalation-armed': {
1945
+ firstMethod: ShutdownMethod;
1946
+ requestCount: number;
1947
+ armedUntil: number;
1948
+ };
1949
+ /** Armed escalation window expired and the manager cleared that old escalation state. */
1950
+ 'lifecycle-manager:shutdown-escalation-expired': {
1951
+ firstMethod: ShutdownMethod;
1952
+ latestMethod: ShutdownMethod | null;
1953
+ requestCount: number;
1954
+ armedUntil: number;
1955
+ };
1956
+ /** Repeated shutdown requests crossed the force threshold and onForceShutdown() was invoked. */
1957
+ 'lifecycle-manager:shutdown-escalation-forced': {
1958
+ firstMethod: ShutdownMethod;
1959
+ latestMethod: ShutdownMethod;
1960
+ requestCount: number;
1961
+ firstRequestAt: number;
1962
+ latestRequestAt: number;
1963
+ wasArmedAfterFailure: boolean;
1964
+ };
1640
1965
  'component:starting': {
1641
1966
  name: string;
1642
1967
  };
@@ -1701,6 +2026,15 @@ interface LifecycleManagerEventMap {
1701
2026
  reason?: string;
1702
2027
  code?: string;
1703
2028
  };
2029
+ 'component:stalled-resolved': {
2030
+ name: string;
2031
+ stallInfo: ComponentStallInfo;
2032
+ stalledDurationMS: number;
2033
+ };
2034
+ 'component:unexpected-stop': {
2035
+ name: string;
2036
+ error?: Error;
2037
+ };
1704
2038
  'component:shutdown-force-completed': {
1705
2039
  name: string;
1706
2040
  };
@@ -1713,6 +2047,7 @@ interface LifecycleManagerEventMap {
1713
2047
  };
1714
2048
  'signal:shutdown': {
1715
2049
  method: ShutdownSignal;
2050
+ isAlreadyShuttingDown: boolean;
1716
2051
  };
1717
2052
  'signal:reload': undefined;
1718
2053
  'signal:info': undefined;
@@ -1827,6 +2162,25 @@ declare class LifecycleManagerEvents {
1827
2162
  method: ShutdownMethod;
1828
2163
  duringStartup: boolean;
1829
2164
  }): void;
2165
+ lifecycleManagerShutdownEscalationArmed(input: {
2166
+ firstMethod: ShutdownMethod;
2167
+ requestCount: number;
2168
+ armedUntil: number;
2169
+ }): void;
2170
+ lifecycleManagerShutdownEscalationExpired(input: {
2171
+ firstMethod: ShutdownMethod;
2172
+ latestMethod: ShutdownMethod | null;
2173
+ requestCount: number;
2174
+ armedUntil: number;
2175
+ }): void;
2176
+ lifecycleManagerShutdownEscalationForced(input: {
2177
+ firstMethod: ShutdownMethod;
2178
+ latestMethod: ShutdownMethod;
2179
+ requestCount: number;
2180
+ firstRequestAt: number;
2181
+ latestRequestAt: number;
2182
+ wasArmedAfterFailure: boolean;
2183
+ }): void;
1830
2184
  componentStarting(name: string): void;
1831
2185
  componentStarted(name: string, status?: ComponentStatus): void;
1832
2186
  componentStartTimeout(name: string, error: Error, info?: {
@@ -1859,10 +2213,12 @@ declare class LifecycleManagerEvents {
1859
2213
  reason?: string;
1860
2214
  code?: string;
1861
2215
  }): void;
2216
+ componentStalledResolved(name: string, stallInfo: ComponentStallInfo, stalledDurationMS: number): void;
2217
+ componentUnexpectedStop(name: string, error?: Error): void;
1862
2218
  componentShutdownForceCompleted(name: string): void;
1863
2219
  componentShutdownForceTimeout(name: string, timeoutMS: number): void;
1864
2220
  componentStartupRollback(name: string): void;
1865
- signalShutdown(method: ShutdownSignal): void;
2221
+ signalShutdown(method: ShutdownSignal, isAlreadyShuttingDown?: boolean): void;
1866
2222
  signalReload(): void;
1867
2223
  signalInfo(): void;
1868
2224
  signalDebug(): void;
@@ -2048,4 +2404,4 @@ declare const lifecycleManagerErrCodes: {
2048
2404
  readonly StopTimeout: "StopTimeout";
2049
2405
  };
2050
2406
 
2051
- export { BaseComponent, type BaseOperationResult, type BroadcastOptions, type BroadcastResult, type ComponentHealthResult, ComponentNotFoundError, type ComponentOperationFailureCode, type ComponentOperationResult, type ComponentOptions, ComponentRegistrationError, type ComponentSignalResult, type ComponentStallInfo, ComponentStartTimeoutError, ComponentStartupError, type ComponentState, type ComponentStatus, ComponentStopTimeoutError, type ComponentValueResult, DependencyCycleError, type DependencyValidationResult, type GetValueOptions, type HealthCheckResult, type HealthReport, type InsertComponentAtResult, type InsertPosition, InvalidComponentNameError, LifecycleManager, type LifecycleManagerEmit, type LifecycleManagerEventMap, type LifecycleManagerEventName, LifecycleManagerEvents, type LifecycleManagerOptions, type LifecycleManagerStatus, type MessageResult, MissingDependencyError, type RegisterComponentResult, type RegisterOptions, type RegistrationFailureCode, type RestartComponentOptions, type RestartResult, type SendMessageOptions, type ShutdownMethod, type ShutdownResult, type SignalBroadcastResult, type StartComponentOptions, type StartupOptions, type StartupOrderFailureCode, type StartupOrderResult, type StartupResult, StartupTimeoutError, type StopAllOptions, type StopComponentOptions, type SystemState, type UnregisterComponentResult, type UnregisterFailureCode, type UnregisterOptions, type ValueResult, lifecycleManagerErrCodes, lifecycleManagerErrPrefix, lifecycleManagerErrTypes };
2407
+ export { BaseComponent, type BaseOperationResult, type BroadcastOptions, type BroadcastResult, type ComponentHealthResult, ComponentNotFoundError, type ComponentOperationFailureCode, type ComponentOperationResult, type ComponentOptions, ComponentRegistrationError, type ComponentSignalResult, type ComponentStallInfo, ComponentStartTimeoutError, ComponentStartupError, type ComponentState, type ComponentStatus, ComponentStopTimeoutError, type ComponentValueResult, DependencyCycleError, type DependencyValidationResult, type ForceShutdownContext, type GetValueOptions, type HealthCheckResult, type HealthReport, type InsertComponentAtResult, type InsertPosition, InvalidComponentNameError, LifecycleManager, type LifecycleManagerEmit, type LifecycleManagerEventMap, type LifecycleManagerEventName, LifecycleManagerEvents, type LifecycleManagerOptions, type LifecycleManagerStatus, type MessageResult, MissingDependencyError, type RegisterComponentResult, type RegisterOptions, type RegistrationFailureCode, type RepeatedShutdownRequestPolicy, type RestartComponentOptions, type RestartResult, type SendMessageOptions, type ShutdownEscalationStatus, type ShutdownMethod, type ShutdownResult, type SignalBroadcastResult, type StartComponentOptions, type StartupOptions, type StartupOrderFailureCode, type StartupOrderResult, type StartupResult, StartupTimeoutError, type StopAllOptions, type StopComponentOptions, type SystemState, type UnregisterComponentResult, type UnregisterFailureCode, type UnregisterOptions, type ValueResult, lifecycleManagerErrCodes, lifecycleManagerErrPrefix, lifecycleManagerErrTypes };