lifecycleion 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +125 -0
  3. package/dist/index.cjs +7 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +2 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +5 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lib/arrays.cjs +95 -0
  10. package/dist/lib/arrays.cjs.map +1 -0
  11. package/dist/lib/arrays.d.cts +15 -0
  12. package/dist/lib/arrays.d.ts +15 -0
  13. package/dist/lib/arrays.js +63 -0
  14. package/dist/lib/arrays.js.map +1 -0
  15. package/dist/lib/ascii-tables/index.cjs +642 -0
  16. package/dist/lib/ascii-tables/index.cjs.map +1 -0
  17. package/dist/lib/ascii-tables/index.d.cts +66 -0
  18. package/dist/lib/ascii-tables/index.d.ts +66 -0
  19. package/dist/lib/ascii-tables/index.js +603 -0
  20. package/dist/lib/ascii-tables/index.js.map +1 -0
  21. package/dist/lib/clamp.cjs +41 -0
  22. package/dist/lib/clamp.cjs.map +1 -0
  23. package/dist/lib/clamp.d.cts +26 -0
  24. package/dist/lib/clamp.d.ts +26 -0
  25. package/dist/lib/clamp.js +15 -0
  26. package/dist/lib/clamp.js.map +1 -0
  27. package/dist/lib/constants.cjs +73 -0
  28. package/dist/lib/constants.cjs.map +1 -0
  29. package/dist/lib/constants.d.cts +17 -0
  30. package/dist/lib/constants.d.ts +17 -0
  31. package/dist/lib/constants.js +34 -0
  32. package/dist/lib/constants.js.map +1 -0
  33. package/dist/lib/curly-brackets.cjs +77 -0
  34. package/dist/lib/curly-brackets.cjs.map +1 -0
  35. package/dist/lib/curly-brackets.d.cts +17 -0
  36. package/dist/lib/curly-brackets.d.ts +17 -0
  37. package/dist/lib/curly-brackets.js +52 -0
  38. package/dist/lib/curly-brackets.js.map +1 -0
  39. package/dist/lib/deep-clone.cjs +87 -0
  40. package/dist/lib/deep-clone.cjs.map +1 -0
  41. package/dist/lib/deep-clone.d.cts +19 -0
  42. package/dist/lib/deep-clone.d.ts +19 -0
  43. package/dist/lib/deep-clone.js +62 -0
  44. package/dist/lib/deep-clone.js.map +1 -0
  45. package/dist/lib/error-to-string.cjs +743 -0
  46. package/dist/lib/error-to-string.cjs.map +1 -0
  47. package/dist/lib/error-to-string.d.cts +3 -0
  48. package/dist/lib/error-to-string.d.ts +3 -0
  49. package/dist/lib/error-to-string.js +706 -0
  50. package/dist/lib/error-to-string.js.map +1 -0
  51. package/dist/lib/event-emitter.cjs +899 -0
  52. package/dist/lib/event-emitter.cjs.map +1 -0
  53. package/dist/lib/event-emitter.d.cts +78 -0
  54. package/dist/lib/event-emitter.d.ts +78 -0
  55. package/dist/lib/event-emitter.js +861 -0
  56. package/dist/lib/event-emitter.js.map +1 -0
  57. package/dist/lib/id-helpers.cjs +205 -0
  58. package/dist/lib/id-helpers.cjs.map +1 -0
  59. package/dist/lib/id-helpers.d.cts +198 -0
  60. package/dist/lib/id-helpers.d.ts +198 -0
  61. package/dist/lib/id-helpers.js +170 -0
  62. package/dist/lib/id-helpers.js.map +1 -0
  63. package/dist/lib/is-boolean.cjs +33 -0
  64. package/dist/lib/is-boolean.cjs.map +1 -0
  65. package/dist/lib/is-boolean.d.cts +19 -0
  66. package/dist/lib/is-boolean.d.ts +19 -0
  67. package/dist/lib/is-boolean.js +8 -0
  68. package/dist/lib/is-boolean.js.map +1 -0
  69. package/dist/lib/is-function.cjs +33 -0
  70. package/dist/lib/is-function.cjs.map +1 -0
  71. package/dist/lib/is-function.d.cts +3 -0
  72. package/dist/lib/is-function.d.ts +3 -0
  73. package/dist/lib/is-function.js +8 -0
  74. package/dist/lib/is-function.js.map +1 -0
  75. package/dist/lib/is-number.cjs +38 -0
  76. package/dist/lib/is-number.cjs.map +1 -0
  77. package/dist/lib/is-number.d.cts +38 -0
  78. package/dist/lib/is-number.d.ts +38 -0
  79. package/dist/lib/is-number.js +12 -0
  80. package/dist/lib/is-number.js.map +1 -0
  81. package/dist/lib/is-plain-object.cjs +33 -0
  82. package/dist/lib/is-plain-object.cjs.map +1 -0
  83. package/dist/lib/is-plain-object.d.cts +20 -0
  84. package/dist/lib/is-plain-object.d.ts +20 -0
  85. package/dist/lib/is-plain-object.js +8 -0
  86. package/dist/lib/is-plain-object.js.map +1 -0
  87. package/dist/lib/is-promise.cjs +34 -0
  88. package/dist/lib/is-promise.cjs.map +1 -0
  89. package/dist/lib/is-promise.d.cts +3 -0
  90. package/dist/lib/is-promise.d.ts +3 -0
  91. package/dist/lib/is-promise.js +9 -0
  92. package/dist/lib/is-promise.js.map +1 -0
  93. package/dist/lib/json-helpers.cjs +49 -0
  94. package/dist/lib/json-helpers.cjs.map +1 -0
  95. package/dist/lib/json-helpers.d.cts +10 -0
  96. package/dist/lib/json-helpers.d.ts +10 -0
  97. package/dist/lib/json-helpers.js +22 -0
  98. package/dist/lib/json-helpers.js.map +1 -0
  99. package/dist/lib/lifecycle-manager/index.cjs +5594 -0
  100. package/dist/lib/lifecycle-manager/index.cjs.map +1 -0
  101. package/dist/lib/lifecycle-manager/index.d.cts +2044 -0
  102. package/dist/lib/lifecycle-manager/index.d.ts +2044 -0
  103. package/dist/lib/lifecycle-manager/index.js +5543 -0
  104. package/dist/lib/lifecycle-manager/index.js.map +1 -0
  105. package/dist/lib/logger/index.cjs +2514 -0
  106. package/dist/lib/logger/index.cjs.map +1 -0
  107. package/dist/lib/logger/index.d.cts +630 -0
  108. package/dist/lib/logger/index.d.ts +630 -0
  109. package/dist/lib/logger/index.js +2470 -0
  110. package/dist/lib/logger/index.js.map +1 -0
  111. package/dist/lib/padding-utils.cjs +77 -0
  112. package/dist/lib/padding-utils.cjs.map +1 -0
  113. package/dist/lib/padding-utils.d.cts +44 -0
  114. package/dist/lib/padding-utils.d.ts +44 -0
  115. package/dist/lib/padding-utils.js +46 -0
  116. package/dist/lib/padding-utils.js.map +1 -0
  117. package/dist/lib/process-signal-manager.cjs +1306 -0
  118. package/dist/lib/process-signal-manager.cjs.map +1 -0
  119. package/dist/lib/process-signal-manager.d.cts +305 -0
  120. package/dist/lib/process-signal-manager.d.ts +305 -0
  121. package/dist/lib/process-signal-manager.js +1269 -0
  122. package/dist/lib/process-signal-manager.js.map +1 -0
  123. package/dist/lib/promise-protected-resolver.cjs +828 -0
  124. package/dist/lib/promise-protected-resolver.cjs.map +1 -0
  125. package/dist/lib/promise-protected-resolver.d.cts +17 -0
  126. package/dist/lib/promise-protected-resolver.d.ts +17 -0
  127. package/dist/lib/promise-protected-resolver.js +791 -0
  128. package/dist/lib/promise-protected-resolver.js.map +1 -0
  129. package/dist/lib/retry-utils/index.cjs +2183 -0
  130. package/dist/lib/retry-utils/index.cjs.map +1 -0
  131. package/dist/lib/retry-utils/index.d.cts +321 -0
  132. package/dist/lib/retry-utils/index.d.ts +321 -0
  133. package/dist/lib/retry-utils/index.js +2133 -0
  134. package/dist/lib/retry-utils/index.js.map +1 -0
  135. package/dist/lib/safe-handle-callback.cjs +818 -0
  136. package/dist/lib/safe-handle-callback.cjs.map +1 -0
  137. package/dist/lib/safe-handle-callback.d.cts +43 -0
  138. package/dist/lib/safe-handle-callback.d.ts +43 -0
  139. package/dist/lib/safe-handle-callback.js +780 -0
  140. package/dist/lib/safe-handle-callback.js.map +1 -0
  141. package/dist/lib/serialize-error/index.cjs +93 -0
  142. package/dist/lib/serialize-error/index.cjs.map +1 -0
  143. package/dist/lib/serialize-error/index.d.cts +26 -0
  144. package/dist/lib/serialize-error/index.d.ts +26 -0
  145. package/dist/lib/serialize-error/index.js +64 -0
  146. package/dist/lib/serialize-error/index.js.map +1 -0
  147. package/dist/lib/single-event-observer.cjs +841 -0
  148. package/dist/lib/single-event-observer.cjs.map +1 -0
  149. package/dist/lib/single-event-observer.d.cts +54 -0
  150. package/dist/lib/single-event-observer.d.ts +54 -0
  151. package/dist/lib/single-event-observer.js +803 -0
  152. package/dist/lib/single-event-observer.js.map +1 -0
  153. package/dist/lib/sleep.cjs +37 -0
  154. package/dist/lib/sleep.cjs.map +1 -0
  155. package/dist/lib/sleep.d.cts +11 -0
  156. package/dist/lib/sleep.d.ts +11 -0
  157. package/dist/lib/sleep.js +12 -0
  158. package/dist/lib/sleep.js.map +1 -0
  159. package/dist/lib/strings.cjs +186 -0
  160. package/dist/lib/strings.cjs.map +1 -0
  161. package/dist/lib/strings.d.cts +107 -0
  162. package/dist/lib/strings.d.ts +107 -0
  163. package/dist/lib/strings.js +149 -0
  164. package/dist/lib/strings.js.map +1 -0
  165. package/dist/lib/tmp-dir.cjs +254 -0
  166. package/dist/lib/tmp-dir.cjs.map +1 -0
  167. package/dist/lib/tmp-dir.d.cts +63 -0
  168. package/dist/lib/tmp-dir.d.ts +63 -0
  169. package/dist/lib/tmp-dir.js +211 -0
  170. package/dist/lib/tmp-dir.js.map +1 -0
  171. package/dist/lib/unix-time-helpers.cjs +53 -0
  172. package/dist/lib/unix-time-helpers.cjs.map +1 -0
  173. package/dist/lib/unix-time-helpers.d.cts +56 -0
  174. package/dist/lib/unix-time-helpers.d.ts +56 -0
  175. package/dist/lib/unix-time-helpers.js +24 -0
  176. package/dist/lib/unix-time-helpers.js.map +1 -0
  177. package/package.json +220 -0
@@ -0,0 +1,2044 @@
1
+ import { EventEmitterProtected } from '../event-emitter.js';
2
+ import { Logger, LoggerService } from '../logger/index.js';
3
+ import { ProcessSignalManagerStatus, ShutdownSignal } from '../process-signal-manager.js';
4
+
5
+ /**
6
+ * Component configuration options passed to BaseComponent constructor
7
+ */
8
+ interface ComponentOptions {
9
+ /** Unique component name (must be kebab-case) */
10
+ name: string;
11
+ /** Names of components this one depends on (default: []) */
12
+ dependencies?: string[];
13
+ /** If true, startup failure doesn't trigger rollback (default: false) */
14
+ optional?: boolean;
15
+ /** Time to wait for start() in milliseconds (default: 30000, 0 = disabled) */
16
+ startupTimeoutMS?: number;
17
+ /** Time to wait for graceful shutdown in milliseconds (default: 5000, minimum: 1000) */
18
+ shutdownGracefulTimeoutMS?: number;
19
+ /** Time to wait for force shutdown in milliseconds (default: 2000, minimum: 500) */
20
+ shutdownForceTimeoutMS?: number;
21
+ /** Time to wait for healthCheck() in milliseconds (default: 5000) */
22
+ healthCheckTimeoutMS?: number;
23
+ /** Time to wait for onReload/onInfo/onDebug in milliseconds (default: 5000, 0 = disabled) */
24
+ signalTimeoutMS?: number;
25
+ }
26
+ /**
27
+ * Possible states a component can be in
28
+ */
29
+ type ComponentState = 'registered' | 'starting' | 'starting-timed-out' | 'running' | 'failed' | 'stopping' | 'force-stopping' | 'stopped' | 'stalled';
30
+ /**
31
+ * Detailed status information for a component
32
+ */
33
+ interface ComponentStatus {
34
+ /** Component name */
35
+ name: string;
36
+ /** Current state */
37
+ state: ComponentState;
38
+ /** Unix timestamp (ms) when start() completed */
39
+ startedAt: number | null;
40
+ /** Unix timestamp (ms) when stop() completed */
41
+ stoppedAt: number | null;
42
+ /** Last error from start/stop/message */
43
+ lastError: Error | null;
44
+ /** If stalled, details about why */
45
+ stallInfo: ComponentStallInfo | null;
46
+ }
47
+ /**
48
+ * Information about why a component is stalled
49
+ */
50
+ interface ComponentStallInfo {
51
+ /** Component name */
52
+ name: string;
53
+ /** Which shutdown phase failed */
54
+ phase: 'graceful' | 'force';
55
+ /** Reason for stall */
56
+ reason: 'timeout' | 'error' | 'both';
57
+ /** When shutdown started for this component */
58
+ startedAt: number;
59
+ /** When the stall occurred */
60
+ stalledAt: number;
61
+ /** Error that caused the stall (if applicable) */
62
+ error?: Error;
63
+ }
64
+ /**
65
+ * How shutdown was triggered
66
+ */
67
+ type ShutdownMethod = 'manual' | 'SIGINT' | 'SIGTERM' | 'SIGTRAP';
68
+ /**
69
+ * Base interface for all operation results
70
+ *
71
+ * Provides consistent structure across all operations with common fields
72
+ * for success status, error handling, and optional component status.
73
+ */
74
+ interface BaseOperationResult {
75
+ /** Whether the operation succeeded */
76
+ success: boolean;
77
+ /** Human-readable explanation if !success */
78
+ reason?: string;
79
+ /** Machine-readable failure code if !success */
80
+ code?: string;
81
+ /** Underlying error if applicable */
82
+ error?: Error;
83
+ /** Component status after the operation (if applicable) */
84
+ status?: ComponentStatus;
85
+ }
86
+ /**
87
+ * Result of an individual component operation (start/stop/restart)
88
+ */
89
+ interface ComponentOperationResult extends BaseOperationResult {
90
+ /** Component name */
91
+ componentName: string;
92
+ /** Machine-readable failure code if !success */
93
+ code?: ComponentOperationFailureCode;
94
+ }
95
+ /**
96
+ * Options for manually starting a component
97
+ */
98
+ interface StartComponentOptions {
99
+ /**
100
+ * If true, allow starting even when required dependencies are registered
101
+ * but not running. Missing dependencies still cause failure.
102
+ * This is an explicit override that bypasses normal dependency checks.
103
+ */
104
+ allowNonRunningDependencies?: boolean;
105
+ /**
106
+ * If true, allow starting a component during bulk startup (startAllComponents).
107
+ * By default, startComponent() is blocked during bulk operations to prevent
108
+ * interference with dependency ordering. However, if the component's dependencies
109
+ * are already running, this option allows you to start it dynamically.
110
+ *
111
+ * Note: Starting during shutdown is NEVER allowed, regardless of this option.
112
+ *
113
+ * Default: false
114
+ */
115
+ allowDuringBulkStartup?: boolean;
116
+ /**
117
+ * If true, force starting this component even if it's stalled without requiring
118
+ * it to be unregistered or retried via stopAllComponents({ retryStalled: true }) first.
119
+ *
120
+ * Default: false
121
+ */
122
+ forceStalled?: boolean;
123
+ }
124
+ /**
125
+ * Options for manually stopping a component
126
+ */
127
+ interface StopComponentOptions {
128
+ /**
129
+ * If true, force immediate shutdown without graceful period
130
+ * Calls onShutdownForce() directly, bypassing normal stop() flow
131
+ * (default: false)
132
+ */
133
+ forceImmediate?: boolean;
134
+ /**
135
+ * Override the component's configured shutdown timeout in milliseconds
136
+ * If not specified, uses the component's shutdownGracefulTimeoutMS
137
+ * Only applies when forceImmediate is false
138
+ */
139
+ timeout?: number;
140
+ /**
141
+ * If true, allows stopping a component even if other running components depend on it
142
+ * Without this flag, stopping a component with running dependents will fail
143
+ * (default: false)
144
+ */
145
+ allowStopWithRunningDependents?: boolean;
146
+ }
147
+ /**
148
+ * Options for restarting a component (stop + start)
149
+ *
150
+ * Combines options for both stop and start phases.
151
+ */
152
+ interface RestartComponentOptions {
153
+ /** Options for the stop phase */
154
+ stopOptions?: StopComponentOptions;
155
+ /** Options for the start phase */
156
+ startOptions?: StartComponentOptions;
157
+ }
158
+ /**
159
+ * Stable, machine-readable failure codes for individual component operations
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';
162
+ /**
163
+ * Failure codes for unregister operations
164
+ */
165
+ type UnregisterFailureCode = 'component_not_found' | 'component_running' | 'stop_failed' | 'bulk_operation_in_progress';
166
+ /**
167
+ * Additional details for why unregister stop failed
168
+ */
169
+ type UnregisterStopFailureReason = 'stalled' | 'timeout' | 'error';
170
+ /**
171
+ * Result of unregistering a component
172
+ */
173
+ interface UnregisterComponentResult extends BaseOperationResult {
174
+ /** Component name */
175
+ componentName: string;
176
+ /** Machine-readable failure code if !success */
177
+ code?: UnregisterFailureCode;
178
+ /** More detail when stop_failed occurs */
179
+ stopFailureReason?: UnregisterStopFailureReason;
180
+ /** Whether the component was stopped before unregistering */
181
+ wasStopped: boolean;
182
+ /** Whether the component was found in registry */
183
+ wasRegistered: boolean;
184
+ }
185
+ /**
186
+ * Result of starting all components
187
+ */
188
+ interface StartupResult {
189
+ /** True if all required components started */
190
+ success: boolean;
191
+ /** Names of components that started successfully */
192
+ startedComponents: string[];
193
+ /** Optional components that failed (app continues) */
194
+ failedOptionalComponents: Array<{
195
+ name: string;
196
+ error: Error;
197
+ }>;
198
+ /** Components skipped because their optional dependency failed */
199
+ skippedDueToDependency: string[];
200
+ /** Present if stalled components blocked startup */
201
+ blockedByStalledComponents?: string[];
202
+ /** Reason for failure (when success is false) */
203
+ reason?: string;
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';
206
+ /** Error object (when success is false due to dependency cycle or unknown error) */
207
+ error?: Error;
208
+ /** Total startup duration in milliseconds */
209
+ durationMS?: number;
210
+ /** Present if startup timed out */
211
+ timedOut?: boolean;
212
+ }
213
+ /**
214
+ * Result of stopping all components
215
+ */
216
+ interface ShutdownResult {
217
+ /** True if all components stopped cleanly */
218
+ success: boolean;
219
+ /** Names of components that stopped successfully */
220
+ stoppedComponents: string[];
221
+ /** Components that failed to stop */
222
+ stalledComponents: ComponentStallInfo[];
223
+ /** How long shutdown took */
224
+ durationMS: number;
225
+ /** True if shutdown exceeded the timeout and returned partial results */
226
+ timedOut?: boolean;
227
+ /** Reason for failure (when success is false) */
228
+ reason?: string;
229
+ /** Error code (when success is false) */
230
+ code?: 'already_in_progress' | 'shutdown_timeout';
231
+ }
232
+ /**
233
+ * Options for stopping all components
234
+ */
235
+ interface StopAllOptions {
236
+ /** Global timeout for entire shutdown process in milliseconds (default: 30000, 0 = disabled) */
237
+ timeoutMS?: number;
238
+ /** Retry stalled components during stopAllComponents (default: true) */
239
+ retryStalled?: boolean;
240
+ /** Stop processing further components after a stall (default: true) */
241
+ haltOnStall?: boolean;
242
+ }
243
+ /**
244
+ * Result of restarting all components (stop + start)
245
+ */
246
+ interface RestartResult {
247
+ /** Shutdown phase result */
248
+ shutdownResult: ShutdownResult;
249
+ /** Startup phase result */
250
+ startupResult: StartupResult;
251
+ /** True only if both shutdown and startup succeeded */
252
+ success: boolean;
253
+ }
254
+ /**
255
+ * Result of sending a message to a component
256
+ */
257
+ interface MessageResult {
258
+ /** Was message delivered to handler */
259
+ sent: boolean;
260
+ /** Does component exist */
261
+ componentFound: boolean;
262
+ /** Is component currently running */
263
+ componentRunning: boolean;
264
+ /** Does component have onMessage() method */
265
+ handlerImplemented: boolean;
266
+ /** Data returned from onMessage handler (undefined if handler returned nothing) */
267
+ data: unknown;
268
+ /** Error if handler threw */
269
+ error: Error | null;
270
+ /** True if handler timed out before responding */
271
+ timedOut: boolean;
272
+ /** Machine-readable outcome code */
273
+ code: 'sent' | 'not_found' | 'stopped' | 'stalled' | 'no_handler' | 'timeout' | 'error';
274
+ }
275
+ /**
276
+ * Options for sending a message to a component
277
+ */
278
+ interface SendMessageOptions {
279
+ /**
280
+ * Timeout in milliseconds for awaiting a response
281
+ * (default: manager messageTimeoutMS, 0 = disabled)
282
+ */
283
+ timeout?: number;
284
+ /**
285
+ * Include stopped (not running, not stalled) components (default: false)
286
+ */
287
+ includeStopped?: boolean;
288
+ /**
289
+ * Include stalled components (default: false)
290
+ */
291
+ includeStalled?: boolean;
292
+ }
293
+ /**
294
+ * Options for requesting a value from a component
295
+ */
296
+ interface GetValueOptions {
297
+ /**
298
+ * Include stopped (not running, not stalled) components (default: false)
299
+ */
300
+ includeStopped?: boolean;
301
+ /**
302
+ * Include stalled components (default: false)
303
+ */
304
+ includeStalled?: boolean;
305
+ }
306
+ /**
307
+ * Options for broadcasting messages to components
308
+ */
309
+ interface BroadcastOptions extends SendMessageOptions {
310
+ /** Filter to specific component names (default: all components) */
311
+ componentNames?: string[];
312
+ }
313
+ /**
314
+ * Result of broadcasting a message to multiple components
315
+ */
316
+ interface BroadcastResult {
317
+ /** Component name */
318
+ name: string;
319
+ /** Was message delivered */
320
+ sent: boolean;
321
+ /** Was component running */
322
+ running: boolean;
323
+ /** Data returned from onMessage handler (undefined if not sent or no return) */
324
+ data: unknown;
325
+ /** Error if handler threw */
326
+ error: Error | null;
327
+ /** True if handler timed out before responding */
328
+ timedOut: boolean;
329
+ /** Machine-readable outcome code */
330
+ code: 'sent' | 'stopped' | 'stalled' | 'no_handler' | 'timeout' | 'error';
331
+ }
332
+ /**
333
+ * Component health check result (simple or rich)
334
+ */
335
+ interface ComponentHealthResult {
336
+ /** Is the component healthy */
337
+ healthy: boolean;
338
+ /** Human-readable status message */
339
+ message?: string;
340
+ /** Arbitrary metrics/metadata */
341
+ details?: Record<string, unknown>;
342
+ }
343
+ /**
344
+ * Result of checking a single component's health
345
+ */
346
+ interface HealthCheckResult {
347
+ /** Component name */
348
+ name: string;
349
+ /** Is the component healthy */
350
+ healthy: boolean;
351
+ /** Status message from component */
352
+ message?: string;
353
+ /** Details from component */
354
+ details?: Record<string, unknown>;
355
+ /** When the check was performed */
356
+ checkedAt: number;
357
+ /** How long the check took */
358
+ durationMS: number;
359
+ /** Error if health check threw */
360
+ error: Error | null;
361
+ /** True if health check timed out */
362
+ timedOut: boolean;
363
+ /** Machine-readable outcome code */
364
+ code: 'ok' | 'not_found' | 'stopped' | 'stalled' | 'no_handler' | 'timeout' | 'error';
365
+ }
366
+ /**
367
+ * Aggregate health report for all components
368
+ */
369
+ interface HealthReport {
370
+ /** True only if ALL components are healthy */
371
+ healthy: boolean;
372
+ /** Health check results for each component */
373
+ components: HealthCheckResult[];
374
+ /** When the check was performed */
375
+ checkedAt: number;
376
+ /** How long the check took */
377
+ durationMS: number;
378
+ /** True if any component timed out */
379
+ timedOut: boolean;
380
+ /** Machine-readable outcome code */
381
+ code: 'ok' | 'degraded' | 'timeout' | 'error';
382
+ }
383
+ /**
384
+ * Result of broadcasting a signal (reload/info/debug)
385
+ */
386
+ interface SignalBroadcastResult {
387
+ /** Which signal was broadcast */
388
+ signal: 'reload' | 'info' | 'debug';
389
+ /** Results for each component */
390
+ results: ComponentSignalResult[];
391
+ /** True if any component timed out */
392
+ timedOut: boolean;
393
+ /** Machine-readable outcome code */
394
+ code: 'ok' | 'partial_timeout' | 'timeout' | 'partial_error' | 'error';
395
+ }
396
+ /**
397
+ * Result of a signal handler on a specific component
398
+ */
399
+ interface ComponentSignalResult {
400
+ /** Component name */
401
+ name: string;
402
+ /** True if handler was called (component implements it) */
403
+ called: boolean;
404
+ /** Error if handler threw */
405
+ error: Error | null;
406
+ /** True if handler timed out before completing */
407
+ timedOut: boolean;
408
+ /** Machine-readable outcome code */
409
+ code: 'called' | 'no_handler' | 'timeout' | 'error';
410
+ }
411
+ /**
412
+ * Simple result type for component getValue() methods
413
+ * Components return this, and LifecycleManager wraps it with additional metadata
414
+ */
415
+ interface ComponentValueResult<T = unknown> {
416
+ /** True if component has a value for the requested key */
417
+ found: boolean;
418
+ /** The value (undefined when not found) */
419
+ value: T | undefined;
420
+ }
421
+ /**
422
+ * Result of requesting a value from a component
423
+ */
424
+ interface ValueResult<T = unknown> {
425
+ /** True if getValue returned non-undefined */
426
+ found: boolean;
427
+ /** The returned value */
428
+ value: T | undefined;
429
+ /** Component exists in registry */
430
+ componentFound: boolean;
431
+ /** Component is in 'running' state */
432
+ componentRunning: boolean;
433
+ /** Component has getValue() method */
434
+ handlerImplemented: boolean;
435
+ /** Who requested (for logging) */
436
+ requestedBy: string | null;
437
+ /** Machine-readable outcome code */
438
+ code: 'found' | 'not_found' | 'stopped' | 'stalled' | 'no_handler' | 'error';
439
+ }
440
+ type EventEmitterSurface = Pick<EventEmitterProtected, 'on' | 'once' | 'hasListener' | 'hasListeners' | 'listenerCount'>;
441
+ /**
442
+ * Common lifecycle interface shared by LifecycleManager and ComponentLifecycle
443
+ *
444
+ * Keep in sync with public LifecycleManager API and ComponentLifecycle proxy.
445
+ * Purpose: define the shared surface both expose to avoid drift across the two.
446
+ */
447
+ interface LifecycleCommon extends EventEmitterSurface {
448
+ hasComponent(name: string): boolean;
449
+ isComponentRunning(name: string): boolean;
450
+ getComponentNames(): string[];
451
+ getRunningComponentNames(): string[];
452
+ getComponentCount(): number;
453
+ getRunningComponentCount(): number;
454
+ getStalledComponentCount(): number;
455
+ getStoppedComponentCount(): number;
456
+ getComponentStatus(name: string): ComponentStatus | undefined;
457
+ getAllComponentStatuses(): ComponentStatus[];
458
+ getSystemState(): SystemState;
459
+ getStatus(): LifecycleManagerStatus;
460
+ getStalledComponents(): ComponentStallInfo[];
461
+ getStalledComponentNames(): string[];
462
+ getStoppedComponentNames(): string[];
463
+ getStartupOrder(): StartupOrderResult;
464
+ validateDependencies(): DependencyValidationResult;
465
+ startAllComponents(options?: StartupOptions): Promise<StartupResult>;
466
+ stopAllComponents(options?: StopAllOptions): Promise<ShutdownResult>;
467
+ restartAllComponents(options?: RestartAllOptions): Promise<RestartResult>;
468
+ startComponent(name: string, options?: StartComponentOptions): Promise<ComponentOperationResult>;
469
+ stopComponent(name: string, options?: StopComponentOptions): Promise<ComponentOperationResult>;
470
+ restartComponent(name: string, options?: RestartComponentOptions): Promise<ComponentOperationResult>;
471
+ attachSignals(): void;
472
+ detachSignals(): void;
473
+ getSignalStatus(): LifecycleSignalStatus;
474
+ triggerReload(): Promise<SignalBroadcastResult>;
475
+ triggerInfo(): Promise<SignalBroadcastResult>;
476
+ triggerDebug(): Promise<SignalBroadcastResult>;
477
+ sendMessageToComponent(componentName: string, payload: unknown, options?: SendMessageOptions): Promise<MessageResult>;
478
+ broadcastMessage(payload: unknown, options?: BroadcastOptions): Promise<BroadcastResult[]>;
479
+ checkComponentHealth(name: string): Promise<HealthCheckResult>;
480
+ checkAllHealth(): Promise<HealthReport>;
481
+ getValue<T = unknown>(componentName: string, key: string, options?: GetValueOptions): ValueResult<T>;
482
+ }
483
+ /**
484
+ * Component-scoped lifecycle interface injected into BaseComponent
485
+ * This is a restricted view of LifecycleManager suitable for components.
486
+ */
487
+ type ComponentLifecycleRef = LifecycleCommon;
488
+ /**
489
+ * Overall system state
490
+ */
491
+ type SystemState = 'no-components' | 'ready' | 'starting' | 'running' | 'stalled' | 'shutting-down';
492
+ /**
493
+ * Aggregated status snapshot for the lifecycle manager.
494
+ */
495
+ interface LifecycleManagerStatus {
496
+ /** Overall system state derived from manager flags and component state */
497
+ systemState: SystemState;
498
+ /** True if any component is running (or stalled) */
499
+ isStarted: boolean;
500
+ /** True while startAllComponents() is running */
501
+ isStarting: boolean;
502
+ /** True while stopAllComponents() is running */
503
+ isShuttingDown: boolean;
504
+ /** Counts of registered, running, stopped, and stalled components */
505
+ counts: {
506
+ total: number;
507
+ running: number;
508
+ stopped: number;
509
+ stalled: number;
510
+ startTimedOut: number;
511
+ };
512
+ /** Component name lists for quick inspection */
513
+ components: {
514
+ registered: string[];
515
+ running: string[];
516
+ stopped: string[];
517
+ stalled: string[];
518
+ startTimedOut: string[];
519
+ };
520
+ }
521
+ /**
522
+ * Options for registering a component
523
+ */
524
+ interface RegisterOptions {
525
+ /** Auto-start if manager is running/starting (default: false) */
526
+ autoStart?: boolean;
527
+ }
528
+ /**
529
+ * Options for unregistering a component
530
+ */
531
+ interface UnregisterOptions {
532
+ /**
533
+ * Stop the component first if it's running (default: true)
534
+ * Set to false to require manual stop before unregister
535
+ */
536
+ stopIfRunning?: boolean;
537
+ /**
538
+ * If true (along with stopIfRunning), allows stopping a component even if
539
+ * other components depend on it before unregistering
540
+ * (default: false)
541
+ */
542
+ forceStop?: boolean;
543
+ }
544
+ /**
545
+ * Options for starting all components
546
+ */
547
+ interface StartupOptions {
548
+ /** Allow start even if stalled components exist (default: false) */
549
+ ignoreStalledComponents?: boolean;
550
+ /** Global timeout for entire startup process in milliseconds (default: constructor's startupTimeoutMS) */
551
+ timeoutMS?: number;
552
+ }
553
+ /**
554
+ * Options for restarting all components (stop + start)
555
+ */
556
+ interface RestartAllOptions {
557
+ /** Startup options for the start phase */
558
+ startupOptions?: StartupOptions;
559
+ /** Timeout for the shutdown phase in milliseconds (default: shutdownOptions.timeoutMS) */
560
+ shutdownTimeoutMS?: number;
561
+ }
562
+ /**
563
+ * Insert position for registering a component relative to the current registry list
564
+ */
565
+ type InsertPosition = 'start' | 'end' | 'before' | 'after';
566
+ /**
567
+ * Stable, machine-readable failure codes for registration operations
568
+ */
569
+ type RegistrationFailureCode = 'duplicate_name' | 'duplicate_instance' | 'shutdown_in_progress' | 'startup_in_progress' | 'target_not_found' | 'invalid_position' | 'dependency_cycle' | 'unknown_error';
570
+ /**
571
+ * Common result shape for component registration operations
572
+ */
573
+ interface RegistrationResultBase extends BaseOperationResult {
574
+ /** Whether the component was added to the registry */
575
+ registered: boolean;
576
+ /** Component name */
577
+ componentName: string;
578
+ /** Machine-readable failure code if !success */
579
+ code?: RegistrationFailureCode;
580
+ /** Registration index before the operation (null if not previously registered) */
581
+ registrationIndexBefore: number | null;
582
+ /** Registration index after the operation (null if not registered) */
583
+ registrationIndexAfter: number | null;
584
+ /** Resolved startup order after applying dependency constraints */
585
+ startupOrder: string[];
586
+ /** Whether registration occurred during startup */
587
+ duringStartup?: boolean;
588
+ /** Whether auto-start was attempted after registration */
589
+ autoStartAttempted?: boolean;
590
+ /** Whether auto-start succeeded (only present when autoStartAttempted is true) */
591
+ autoStartSucceeded?: boolean;
592
+ /** Result of auto-start operation (only present when autoStartAttempted is true) */
593
+ startResult?: ComponentOperationResult;
594
+ }
595
+ /**
596
+ * Stable, machine-readable failure codes for getStartupOrder()
597
+ */
598
+ type StartupOrderFailureCode = 'dependency_cycle' | 'unknown_error';
599
+ /**
600
+ * Result of getStartupOrder()
601
+ */
602
+ interface StartupOrderResult extends BaseOperationResult {
603
+ /** Resolved startup order after applying dependency constraints */
604
+ startupOrder: string[];
605
+ /** Machine-readable failure code if !success */
606
+ code?: StartupOrderFailureCode;
607
+ }
608
+ /**
609
+ * Result of registerComponent()
610
+ */
611
+ interface RegisterComponentResult extends RegistrationResultBase {
612
+ action: 'register';
613
+ }
614
+ /**
615
+ * Result of insertComponentAt()
616
+ */
617
+ interface InsertComponentAtResult extends RegistrationResultBase {
618
+ action: 'insert';
619
+ /** Requested insertion position */
620
+ requestedPosition: {
621
+ /**
622
+ * The requested position.
623
+ *
624
+ * Note: This is `string` (not just `InsertPosition`) so untyped/JS callers can
625
+ * still get back the original invalid value when the operation fails with
626
+ * `code: 'invalid_position'`.
627
+ */
628
+ position: InsertPosition | (string & {});
629
+ targetComponentName?: string;
630
+ };
631
+ /** Actual position where component was inserted (after dependency resolution) */
632
+ actualPosition?: {
633
+ /** The actual registry index where the component was inserted */
634
+ index: number;
635
+ /** Human-readable description of position (e.g., "at start", "after database, before api") */
636
+ description?: string;
637
+ };
638
+ /** True if requested relative positioning was achievable under dependency constraints */
639
+ manualPositionRespected: boolean;
640
+ /** Present when inserting before/after a target */
641
+ targetFound?: boolean;
642
+ }
643
+ /**
644
+ * Result of validateDependencies()
645
+ *
646
+ * Provides a report of dependency issues without throwing.
647
+ * Reports all issues regardless of whether components are optional - the optional
648
+ * flag affects startup behavior, not whether dependencies must exist.
649
+ */
650
+ interface DependencyValidationResult {
651
+ /** True if all dependencies are valid (no circular cycles, no missing dependencies) */
652
+ valid: boolean;
653
+ /** Missing dependencies: components that depend on non-registered components */
654
+ missingDependencies: Array<{
655
+ componentName: string;
656
+ /** Whether the component with the missing dependency is optional */
657
+ componentIsOptional: boolean;
658
+ missingDependency: string;
659
+ }>;
660
+ /**
661
+ * Detected circular dependency cycles.
662
+ * Each cycle is an array of component names forming a circle (e.g., ['A', 'B', 'C'] means A→B→C→A).
663
+ */
664
+ circularCycles: string[][];
665
+ /** Summary counts for quick overview */
666
+ summary: {
667
+ /** Total number of missing dependencies */
668
+ totalMissingDependencies: number;
669
+ /** Missing dependencies from required components */
670
+ requiredMissingDependencies: number;
671
+ /** Missing dependencies from optional components */
672
+ optionalMissingDependencies: number;
673
+ /** Total number of circular dependency cycles detected */
674
+ totalCircularCycles: number;
675
+ };
676
+ }
677
+ /**
678
+ * Extended signal status with lifecycle-specific information
679
+ */
680
+ interface LifecycleSignalStatus extends ProcessSignalManagerStatus {
681
+ /** How shutdown was triggered (null if not shut down) */
682
+ shutdownMethod: ShutdownMethod | null;
683
+ }
684
+ /**
685
+ * Configuration options for LifecycleManager
686
+ */
687
+ interface LifecycleManagerOptions {
688
+ /** Name for logger scope (default: 'lifecycle-manager') */
689
+ name?: string;
690
+ /** Root logger instance (required) */
691
+ logger: Logger;
692
+ /** Global timeout for startup in ms (default: 60000, 0 = disabled) */
693
+ startupTimeoutMS?: number;
694
+ /** Default stopAllComponents options used by signal and logger hooks */
695
+ shutdownOptions?: StopAllOptions;
696
+ /** Global warning phase timeout in ms (default: 500, 0 = fire-and-forget, <0 = skip) */
697
+ shutdownWarningTimeoutMS?: number;
698
+ /** Default message timeout in ms (default: 5000, 0 = disabled) */
699
+ messageTimeoutMS?: number;
700
+ /** Auto-attach signals when first component starts (default: false) */
701
+ attachSignalsOnStart?: boolean;
702
+ /** Auto-detach signals when last component stops (default: false) */
703
+ detachSignalsOnStop?: boolean;
704
+ /** Enable Logger exit hook integration (default: false). When enabled, logger.exit() triggers graceful component shutdown before process exit. */
705
+ enableLoggerExitHook?: boolean;
706
+ /** Custom reload signal handler (called instead of default broadcast, receives broadcast function you can optionally call) */
707
+ onReloadRequested?: (broadcastReload: () => Promise<SignalBroadcastResult>) => void | Promise<void>;
708
+ /** Custom info signal handler (called instead of default broadcast, receives broadcast function you can optionally call) */
709
+ onInfoRequested?: (broadcastInfo: () => Promise<SignalBroadcastResult>) => void | Promise<void>;
710
+ /** Custom debug signal handler (called instead of default broadcast, receives broadcast function you can optionally call) */
711
+ onDebugRequested?: (broadcastDebug: () => Promise<SignalBroadcastResult>) => void | Promise<void>;
712
+ }
713
+
714
+ /**
715
+ * Abstract base class for all lifecycle-managed components
716
+ *
717
+ * Components extend this class and implement the required start() and stop() methods.
718
+ * They can optionally implement lifecycle hooks for shutdown phases, signal handling,
719
+ * health checks, messaging, and value sharing.
720
+ *
721
+ * The component's lifecycle is managed by a LifecycleManager instance which:
722
+ * - Calls start() during startup (with dependency ordering)
723
+ * - Calls stop() and optional shutdown hooks during shutdown
724
+ * - Provides messaging and value sharing between components
725
+ * - Handles signals (SIGINT, SIGTERM, SIGHUP, etc.)
726
+ *
727
+ * @example
728
+ * ```typescript
729
+ * class DatabaseComponent extends BaseComponent {
730
+ * private pool?: Pool;
731
+ *
732
+ * constructor(logger: Logger) {
733
+ * super(logger, {
734
+ * name: 'database',
735
+ * dependencies: [],
736
+ * startupTimeoutMS: 10000,
737
+ * shutdownGracefulTimeoutMS: 5000,
738
+ * });
739
+ * }
740
+ *
741
+ * async start() {
742
+ * this.logger.info('Connecting to database...');
743
+ * this.pool = await createPool(config);
744
+ * this.logger.success('Connected to database');
745
+ * }
746
+ *
747
+ * async stop() {
748
+ * this.logger.info('Closing database connections...');
749
+ * await this.pool?.end();
750
+ * this.logger.success('Database connections closed');
751
+ * }
752
+ *
753
+ * // Optional: handle graceful shutdown warning
754
+ * async onShutdownWarning() {
755
+ * this.logger.info('Shutdown warning - stopping new connections');
756
+ * this.pool?.stopAcceptingConnections();
757
+ * }
758
+ *
759
+ * // Optional: handle reload signal
760
+ * async onReload() {
761
+ * this.logger.info('Reloading database configuration');
762
+ * await this.reloadConfig();
763
+ * }
764
+ *
765
+ * // Optional: health check
766
+ * async healthCheck() {
767
+ * const isHealthy = await this.pool?.ping();
768
+ * return { healthy: isHealthy, message: 'Database connection active' };
769
+ * }
770
+ * }
771
+ * ```
772
+ */
773
+ declare abstract class BaseComponent {
774
+ /** Names of components this one depends on */
775
+ readonly dependencies: string[];
776
+ /** If true, startup failure doesn't trigger rollback */
777
+ readonly optional: boolean;
778
+ /** Time to wait for start() in milliseconds */
779
+ readonly startupTimeoutMS: number;
780
+ /** Time to wait for graceful shutdown in milliseconds */
781
+ readonly shutdownGracefulTimeoutMS: number;
782
+ /** Time to wait for force shutdown in milliseconds */
783
+ readonly shutdownForceTimeoutMS: number;
784
+ /** Time to wait for healthCheck() in milliseconds */
785
+ readonly healthCheckTimeoutMS: number;
786
+ /** Time to wait for onReload/onInfo/onDebug in milliseconds */
787
+ readonly signalTimeoutMS: number;
788
+ /** Component logger (scoped to component name) */
789
+ protected logger: LoggerService;
790
+ /** Component name (kebab-case) */
791
+ protected name: string;
792
+ /** Reference to component-scoped lifecycle (set by manager when registered) */
793
+ protected lifecycle: ComponentLifecycleRef;
794
+ /**
795
+ * Create a new component
796
+ *
797
+ * @param rootLogger - Root logger instance (component will create scoped logger)
798
+ * @param options - Component configuration
799
+ * @throws {InvalidComponentNameError} If name doesn't match kebab-case pattern
800
+ */
801
+ constructor(rootLogger: Logger, options: ComponentOptions);
802
+ /**
803
+ * Start the component
804
+ *
805
+ * Called by the LifecycleManager when starting components.
806
+ * Should perform all initialization, connection setup, etc.
807
+ * Dependencies are guaranteed to have started before this is called.
808
+ *
809
+ * Can be sync or async - manager will await if Promise is returned.
810
+ *
811
+ * @throws Should throw an error if startup fails
812
+ */
813
+ abstract start(): Promise<void> | void;
814
+ /**
815
+ * Stop the component (graceful shutdown)
816
+ *
817
+ * Called by the LifecycleManager when stopping components.
818
+ * Should perform graceful cleanup, close connections, save state, etc.
819
+ * Dependents are guaranteed to have stopped before this is called.
820
+ *
821
+ * Can be sync or async - manager will await if Promise is returned.
822
+ *
823
+ * @throws Should throw an error if stop fails (will trigger force phase)
824
+ */
825
+ abstract stop(): Promise<void> | void;
826
+ /**
827
+ * Called when start() times out
828
+ *
829
+ * Invoked when start() exceeds startupTimeoutMS before rollback begins.
830
+ * Use this to set flags, abort pending work, or cleanup resources.
831
+ * Must be synchronous and fast - manager won't wait for it to complete.
832
+ */
833
+ onStartupAborted?(): void;
834
+ /**
835
+ * Called when stop() times out
836
+ *
837
+ * Invoked when stop() exceeds shutdownGracefulTimeoutMS before force shutdown begins.
838
+ * Use this to set flags or prepare for more aggressive cleanup in onShutdownForce().
839
+ * Must be synchronous and fast - manager won't wait for it to complete.
840
+ */
841
+ onGracefulStopTimeout?(): void;
842
+ /**
843
+ * Called before graceful shutdown to warn component
844
+ *
845
+ * Optional lifecycle hook called before stopAllComponents() begins stopping components.
846
+ * Use this to prepare for shutdown (stop accepting new work, drain queues, etc.)
847
+ *
848
+ * Can be sync or async - manager will await if Promise is returned.
849
+ */
850
+ onShutdownWarning?(): Promise<void> | void;
851
+ /**
852
+ * Called for force shutdown if graceful shutdown times out or throws
853
+ *
854
+ * Optional lifecycle hook called after stop() fails.
855
+ * Use this for more aggressive cleanup (kill connections, abandon work, etc.)
856
+ *
857
+ * Can be sync or async - manager will await if Promise is returned.
858
+ */
859
+ onShutdownForce?(): Promise<void> | void;
860
+ /**
861
+ * Called when onShutdownForce() times out
862
+ *
863
+ * Invoked when onShutdownForce() exceeds shutdownForceTimeoutMS before component is marked stalled.
864
+ * Must be synchronous and fast - manager won't wait for it to complete.
865
+ */
866
+ onShutdownForceAborted?(): void;
867
+ /**
868
+ * Called when reload signal (SIGHUP, R key) is received
869
+ *
870
+ * Optional signal handler for runtime reload.
871
+ * Use this to reload configuration, reconnect, etc. without full restart.
872
+ *
873
+ * Can be sync or async - manager will await if Promise is returned.
874
+ * Errors are caught and logged but don't stop the broadcast.
875
+ */
876
+ onReload?(): Promise<void> | void;
877
+ /**
878
+ * Called when info signal (SIGUSR1, I key) is received
879
+ *
880
+ * Optional signal handler for info requests.
881
+ * Use this to log status, metrics, or other runtime information.
882
+ *
883
+ * Can be sync or async - manager will await if Promise is returned.
884
+ * Errors are caught and logged but don't stop the broadcast.
885
+ */
886
+ onInfo?(): Promise<void> | void;
887
+ /**
888
+ * Called when debug signal (SIGUSR2, D key) is received
889
+ *
890
+ * Optional signal handler for debug requests.
891
+ * Use this to toggle debug mode, dump state, etc.
892
+ *
893
+ * Can be sync or async - manager will await if Promise is returned.
894
+ * Errors are caught and logged but don't stop the broadcast.
895
+ */
896
+ onDebug?(): Promise<void> | void;
897
+ /**
898
+ * Optional health check for runtime monitoring
899
+ *
900
+ * Return a simple boolean or a rich result with metadata.
901
+ * Called by the manager when checking component health.
902
+ * Only called on 'running' components.
903
+ *
904
+ * @returns boolean (healthy/unhealthy) or rich result with details
905
+ *
906
+ * @example
907
+ * ```typescript
908
+ * // Simple boolean
909
+ * healthCheck() {
910
+ * return this.isConnected;
911
+ * }
912
+ *
913
+ * // Rich result with metadata
914
+ * async healthCheck() {
915
+ * const stats = await this.getStats();
916
+ * return {
917
+ * healthy: stats.errorRate < 0.05,
918
+ * message: stats.errorRate < 0.05 ? 'Healthy' : 'High error rate',
919
+ * details: { errorRate: stats.errorRate, requestsPerSec: stats.rps }
920
+ * };
921
+ * }
922
+ * ```
923
+ */
924
+ healthCheck?(): Promise<boolean | ComponentHealthResult> | boolean | ComponentHealthResult;
925
+ /**
926
+ * Optional message handler for arbitrary component messaging
927
+ *
928
+ * Receives messages from other components or external code.
929
+ * Can return data which will be included in MessageResult.data.
930
+ *
931
+ * @param payload - The message content (any type)
932
+ * @param from - Sender component name (null if external)
933
+ * @returns Optional data to include in response
934
+ *
935
+ * @example
936
+ * ```typescript
937
+ * async onMessage(payload: unknown, from: string | null) {
938
+ * const msg = payload as { action: string; data?: unknown };
939
+ *
940
+ * if (msg.action === 'reset') {
941
+ * await this.reset();
942
+ * return { success: true };
943
+ * }
944
+ *
945
+ * if (msg.action === 'getStats') {
946
+ * return { connections: this.pool.size, uptime: this.uptime };
947
+ * }
948
+ * }
949
+ * ```
950
+ */
951
+ onMessage?<TData = unknown>(payload: unknown, from: string | null): TData | Promise<TData>;
952
+ /**
953
+ * Optional value provider - return values on-demand for other components
954
+ *
955
+ * Called when other components or external code request a value by key.
956
+ * Return a structured result indicating if the value was found.
957
+ *
958
+ * @param key - The value key being requested
959
+ * @param from - Component name if another component requested, null if external
960
+ * @returns Structured result with found status and value
961
+ *
962
+ * @example
963
+ * ```typescript
964
+ * getValue(key: string, from: string | null): ComponentValueResult {
965
+ * if (key === 'pool') return { found: true, value: this.pool };
966
+ * else if (key === 'config') return { found: true, value: this.config };
967
+ * return { found: false, value: undefined }; // Key not found
968
+ * }
969
+ * ```
970
+ */
971
+ getValue?<T = unknown>(key: string, from: string | null): ComponentValueResult<T>;
972
+ /**
973
+ * Get component name
974
+ */
975
+ getName(): string;
976
+ /**
977
+ * Get component dependencies
978
+ */
979
+ getDependencies(): string[];
980
+ /**
981
+ * Check if component is optional
982
+ */
983
+ isOptional(): boolean;
984
+ }
985
+
986
+ /**
987
+ * LifecycleManager - Comprehensive lifecycle orchestration system
988
+ *
989
+ * Manages startup, shutdown, and runtime control of application components.
990
+ * Features:
991
+ * - Multi-phase shutdown (global warning -> per-component graceful -> force)
992
+ * - Dependency-ordered component startup
993
+ * - Process signal integration
994
+ * - Component messaging and value sharing
995
+ * - Health checks and monitoring
996
+ * - Event-driven architecture
997
+ */
998
+ declare class LifecycleManager extends EventEmitterProtected implements LifecycleCommon {
999
+ private readonly name;
1000
+ private readonly logger;
1001
+ private readonly rootLogger;
1002
+ private readonly shutdownWarningTimeoutMS;
1003
+ private readonly messageTimeoutMS;
1004
+ private readonly startupTimeoutMS;
1005
+ private readonly shutdownOptions?;
1006
+ private readonly attachSignalsOnStart;
1007
+ private readonly detachSignalsOnStop;
1008
+ private components;
1009
+ private runningComponents;
1010
+ private componentStates;
1011
+ private stalledComponents;
1012
+ private componentTimestamps;
1013
+ private componentErrors;
1014
+ private isStarting;
1015
+ private isStarted;
1016
+ private isShuttingDown;
1017
+ private shutdownMethod;
1018
+ private lastShutdownResult;
1019
+ private processSignalManager;
1020
+ private readonly onReloadRequested?;
1021
+ private readonly onInfoRequested?;
1022
+ private readonly onDebugRequested?;
1023
+ private readonly lifecycleEvents;
1024
+ constructor(options: LifecycleManagerOptions & {
1025
+ logger: Logger;
1026
+ });
1027
+ /**
1028
+ * Register a component at the end of the registry list.
1029
+ */
1030
+ registerComponent(component: BaseComponent, options?: RegisterOptions): Promise<RegisterComponentResult>;
1031
+ /**
1032
+ * Insert a component at a specific position within the registry list.
1033
+ *
1034
+ * Notes:
1035
+ * - The registry list is a manual ordering preference only.
1036
+ * - Dependencies may override this preference; the result object includes `startupOrder`
1037
+ * and `manualPositionRespected` so callers can see if the request was achievable.
1038
+ */
1039
+ insertComponentAt(component: BaseComponent, position: InsertPosition, targetComponentName?: string, options?: RegisterOptions): Promise<InsertComponentAtResult>;
1040
+ /**
1041
+ * Unregister a component
1042
+ *
1043
+ * @param name - Component name to unregister
1044
+ * @param options - Unregister options (stopIfRunning defaults to true)
1045
+ *
1046
+ * Notes:
1047
+ * - Stopped or stalled components can be unregistered directly
1048
+ * - Running components are stopped first by default (stopIfRunning: true)
1049
+ * - Set stopIfRunning: false to require manual stop before unregister
1050
+ * - If stopIfRunning is true and stop fails, unregister is aborted
1051
+ * - If stopIfRunning is true and the component is stalled, unregister is aborted
1052
+ * @returns True if component was unregistered, false otherwise
1053
+ */
1054
+ unregisterComponent(name: string, options?: UnregisterOptions): Promise<UnregisterComponentResult>;
1055
+ /**
1056
+ * Check if a component is registered
1057
+ */
1058
+ hasComponent(name: string): boolean;
1059
+ /**
1060
+ * Check if a component is currently running
1061
+ */
1062
+ isComponentRunning(name: string): boolean;
1063
+ /**
1064
+ * Get all registered component names
1065
+ */
1066
+ getComponentNames(): string[];
1067
+ /**
1068
+ * Get all running component names
1069
+ */
1070
+ getRunningComponentNames(): string[];
1071
+ /**
1072
+ * Get the actual component instance by name.
1073
+ *
1074
+ * Note: This returns the live instance registered with the manager. Mutating it
1075
+ * directly can bypass lifecycle invariants, so treat it as read-only unless you
1076
+ * fully control the component and understand the implications.
1077
+ */
1078
+ getComponentInstance(name: string): BaseComponent | undefined;
1079
+ /**
1080
+ * Get total component count
1081
+ */
1082
+ getComponentCount(): number;
1083
+ /**
1084
+ * Get running component count
1085
+ */
1086
+ getRunningComponentCount(): number;
1087
+ /**
1088
+ * Get stalled component count
1089
+ */
1090
+ getStalledComponentCount(): number;
1091
+ /**
1092
+ * Get stopped (not running, not stalled) component count
1093
+ */
1094
+ getStoppedComponentCount(): number;
1095
+ /**
1096
+ * Get components whose last start attempt timed out
1097
+ */
1098
+ getStartTimedOutComponentCount(): number;
1099
+ /**
1100
+ * Get detailed status for a specific component
1101
+ */
1102
+ getComponentStatus(name: string): ComponentStatus | undefined;
1103
+ /**
1104
+ * Get statuses for all components
1105
+ */
1106
+ getAllComponentStatuses(): ComponentStatus[];
1107
+ /**
1108
+ * Get overall system state
1109
+ */
1110
+ getSystemState(): SystemState;
1111
+ /**
1112
+ * Get aggregated status snapshot for the manager.
1113
+ */
1114
+ getStatus(): LifecycleManagerStatus;
1115
+ /**
1116
+ * Get information about components that are stalled (failed to stop)
1117
+ */
1118
+ getStalledComponents(): ComponentStallInfo[];
1119
+ /**
1120
+ * Get stalled component names
1121
+ */
1122
+ getStalledComponentNames(): string[];
1123
+ /**
1124
+ * Get components whose last start attempt timed out
1125
+ */
1126
+ getStartTimedOutComponentNames(): string[];
1127
+ /**
1128
+ * Get stopped (not running, not stalled) component names
1129
+ */
1130
+ getStoppedComponentNames(): string[];
1131
+ /**
1132
+ * Get resolved startup order after applying dependency constraints.
1133
+ */
1134
+ getStartupOrder(): StartupOrderResult;
1135
+ /**
1136
+ * Validate all component dependencies without throwing.
1137
+ *
1138
+ * Returns a report of dependency issues:
1139
+ * - Missing dependencies (components that depend on non-registered components)
1140
+ * - Circular dependency cycles (e.g., A→B→C→A)
1141
+ *
1142
+ * Reports all issues regardless of whether components are optional.
1143
+ * The optional flag affects startup behavior (whether failures trigger rollback),
1144
+ * not whether dependencies must exist in the registry.
1145
+ *
1146
+ * This is useful for pre-flight checks before starting components.
1147
+ */
1148
+ validateDependencies(): DependencyValidationResult;
1149
+ /**
1150
+ * Get the result of the last shutdown operation.
1151
+ * Useful for debugging stalled components or tracking shutdown metrics.
1152
+ * Returns null if no shutdown has occurred yet or after a successful restart.
1153
+ *
1154
+ * @returns The last shutdown result or null
1155
+ */
1156
+ getLastShutdownResult(): ShutdownResult | null;
1157
+ /**
1158
+ * Start all registered components in dependency order.
1159
+ *
1160
+ * Components start in topological order (dependencies before dependents).
1161
+ * Shutdown occurs in reverse topological order.
1162
+ *
1163
+ * Behavior:
1164
+ * - Rejects if some components are already running (partial state)
1165
+ * - Sets isStarting flag during operation
1166
+ * - On failure: triggers rollback (stops all started components)
1167
+ * - Optional components don't trigger rollback on failure
1168
+ * - Dependents still attempt to start if an optional dependency fails
1169
+ * - Handles shutdown signal during startup (aborts and rolls back)
1170
+ */
1171
+ startAllComponents(options?: StartupOptions): Promise<StartupResult>;
1172
+ /**
1173
+ * Stop all running components in reverse dependency order
1174
+ *
1175
+ * Components stop in reverse topological order (dependents before dependencies).
1176
+ *
1177
+ * @param options - Optional shutdown options
1178
+ */
1179
+ stopAllComponents(options?: StopAllOptions): Promise<ShutdownResult>;
1180
+ /**
1181
+ * Restart all components (stop then start)
1182
+ */
1183
+ restartAllComponents(options?: RestartAllOptions): Promise<RestartResult>;
1184
+ /**
1185
+ * Start a specific component
1186
+ */
1187
+ startComponent(name: string, options?: StartComponentOptions): Promise<ComponentOperationResult>;
1188
+ /**
1189
+ * Stop a specific component
1190
+ */
1191
+ stopComponent(name: string, options?: StopComponentOptions): Promise<ComponentOperationResult>;
1192
+ /**
1193
+ * Restart a component (stop then start)
1194
+ */
1195
+ restartComponent(name: string, options?: RestartComponentOptions): Promise<ComponentOperationResult>;
1196
+ /**
1197
+ * Attach signal handlers for graceful shutdown, reload, info, and debug.
1198
+ * Creates ProcessSignalManager instance if needed and attaches it.
1199
+ * Idempotent - calling multiple times has no effect.
1200
+ */
1201
+ attachSignals(): void;
1202
+ /**
1203
+ * Detach signal handlers.
1204
+ * Idempotent - calling multiple times has no effect.
1205
+ */
1206
+ detachSignals(): void;
1207
+ /**
1208
+ * Get status information about signal handling.
1209
+ */
1210
+ getSignalStatus(): LifecycleSignalStatus;
1211
+ /**
1212
+ * Enable Logger exit hook integration
1213
+ *
1214
+ * Sets up the logger's beforeExit callback to trigger graceful component shutdown.
1215
+ * When `logger.exit(code)` is called (or `logger.error('msg', { exitCode: 1 })`),
1216
+ * the LifecycleManager will stop all components before the process exits.
1217
+ *
1218
+ * The shutdown is subject to the configured shutdown timeout (default: 30000ms).
1219
+ * If shutdown exceeds this timeout, the process will exit anyway to prevent hanging.
1220
+ *
1221
+ * This method is idempotent and can be called multiple times safely.
1222
+ *
1223
+ * **Note:** This overwrites any existing beforeExit callback on the logger.
1224
+ * If you need custom exit logic, set it up manually with `logger.setBeforeExitCallback()`.
1225
+ *
1226
+ * @example
1227
+ * ```typescript
1228
+ * const logger = new Logger();
1229
+ * const lifecycle = new LifecycleManager({
1230
+ * logger,
1231
+ * enableLoggerExitHook: true, // Auto-enable
1232
+ * shutdownOptions: { timeoutMS: 30000 }, // Max 30s for shutdown
1233
+ * });
1234
+ *
1235
+ * // Or enable manually later
1236
+ * lifecycle.enableLoggerExitHook();
1237
+ *
1238
+ * // Now logger.exit() will trigger graceful shutdown
1239
+ * logger.error('Fatal error', { exitCode: 1 });
1240
+ * // Components stop gracefully (up to shutdown timeout) before process exits
1241
+ * ```
1242
+ */
1243
+ enableLoggerExitHook(): void;
1244
+ /**
1245
+ * Manually trigger a reload event.
1246
+ * @returns Result of broadcasting reload to components
1247
+ */
1248
+ triggerReload(): Promise<SignalBroadcastResult>;
1249
+ /**
1250
+ * Manually trigger an info event.
1251
+ * @returns Result of broadcasting info to components
1252
+ */
1253
+ triggerInfo(): Promise<SignalBroadcastResult>;
1254
+ /**
1255
+ * Manually trigger a debug event.
1256
+ * @returns Result of broadcasting debug to components
1257
+ */
1258
+ triggerDebug(): Promise<SignalBroadcastResult>;
1259
+ /**
1260
+ * Send a message to a specific component
1261
+ *
1262
+ * Delivers a message to the component's onMessage handler if implemented.
1263
+ * The 'from' parameter is automatically tracked based on calling context.
1264
+ *
1265
+ * @param componentName - Name of target component
1266
+ * @param payload - Message payload (any type)
1267
+ * @param options - Optional message options (timeout override)
1268
+ * @returns Result with sent status, data returned from handler, and any errors
1269
+ */
1270
+ sendMessageToComponent(componentName: string, payload: unknown, options?: SendMessageOptions): Promise<MessageResult>;
1271
+ /**
1272
+ * Broadcast a message to multiple components
1273
+ *
1274
+ * Sends the same message to multiple components (by default, all running components).
1275
+ * The 'from' parameter is automatically tracked based on calling context.
1276
+ *
1277
+ * @param payload - Message payload (any type)
1278
+ * @param options - Filtering options and message timeout override
1279
+ * @returns Array of results, one per component
1280
+ */
1281
+ broadcastMessage(payload: unknown, options?: BroadcastOptions): Promise<BroadcastResult[]>;
1282
+ /**
1283
+ * Check the health of a specific component
1284
+ *
1285
+ * Calls the component's healthCheck() method if implemented.
1286
+ * Times out after component's healthCheckTimeoutMS.
1287
+ *
1288
+ * @param name - Component name
1289
+ * @returns Health check result with status, message, details, and timing
1290
+ */
1291
+ checkComponentHealth(name: string): Promise<HealthCheckResult>;
1292
+ /**
1293
+ * Check the health of all running components
1294
+ *
1295
+ * Runs health checks on all running components in parallel.
1296
+ * Overall health is true only if ALL components are healthy.
1297
+ *
1298
+ * @returns Aggregate health report with individual component results
1299
+ */
1300
+ checkAllHealth(): Promise<HealthReport>;
1301
+ /**
1302
+ * Request a value from a component by key
1303
+ *
1304
+ * Calls the component's getValue(key, from) method if implemented.
1305
+ * The 'from' parameter is automatically tracked based on calling context.
1306
+ *
1307
+ * @param componentName - Name of component to request value from
1308
+ * @param key - Value key to request
1309
+ * @returns Result with found status, value, and metadata
1310
+ */
1311
+ getValue<T = unknown>(componentName: string, key: string, options?: GetValueOptions): ValueResult<T>;
1312
+ /**
1313
+ * Internal message sending with explicit 'from' parameter
1314
+ *
1315
+ * @param componentName - Target component name
1316
+ * @param payload - Message payload
1317
+ * @param from - Sender component name (null if external)
1318
+ */
1319
+ private sendMessageInternal;
1320
+ /**
1321
+ * Internal broadcast with explicit 'from' parameter
1322
+ *
1323
+ * @param payload - Message payload
1324
+ * @param from - Sender component name (null if external)
1325
+ * @param options - Filtering options
1326
+ */
1327
+ private broadcastMessageInternal;
1328
+ /**
1329
+ * Internal getValue with explicit 'from' parameter
1330
+ *
1331
+ * @param componentName - Target component name
1332
+ * @param key - Value key
1333
+ * @param from - Requester component name (null if external)
1334
+ */
1335
+ private getValueInternal;
1336
+ private updateStartedFlag;
1337
+ /**
1338
+ * Internal method that handles component registration logic.
1339
+ * Used by both registerComponent and insertComponentAt.
1340
+ */
1341
+ private registerComponentInternal;
1342
+ private stopAllComponentsInternal;
1343
+ /**
1344
+ * Retry shutdown for a stalled component.
1345
+ * Attempts the force phase directly to avoid re-running a failing stop().
1346
+ */
1347
+ private retryStalledComponent;
1348
+ /**
1349
+ * Internal start component method - bypasses bulk operation checks
1350
+ * Used by both startComponent() and startAllComponents()
1351
+ */
1352
+ private startComponentInternal;
1353
+ /**
1354
+ * Internal stop component method - bypasses bulk operation checks
1355
+ * Implements individual component graceful -> force shutdown (global warning handled elsewhere)
1356
+ */
1357
+ private stopComponentInternal;
1358
+ /**
1359
+ * Two-phase shutdown: graceful -> force (global warning handled by stopAllComponents)
1360
+ *
1361
+ * Phase 1: Graceful (always - calls stop())
1362
+ * Phase 2: Force (if Phase 1 failed - calls onShutdownForce())
1363
+ */
1364
+ private shutdownComponent;
1365
+ /**
1366
+ * Global warning phase (stopAllComponents only)
1367
+ * Calls onShutdownWarning() on running components with a global timeout
1368
+ */
1369
+ private runShutdownWarningPhase;
1370
+ /**
1371
+ * Phase 2: Graceful shutdown
1372
+ * Calls stop() with timeout
1373
+ */
1374
+ private shutdownComponentGraceful;
1375
+ /**
1376
+ * Phase 3: Force shutdown
1377
+ * Calls onShutdownForce() with timeout, or marks as stalled if not implemented
1378
+ */
1379
+ private shutdownComponentForce;
1380
+ /**
1381
+ * Get a component by name
1382
+ */
1383
+ private getComponent;
1384
+ /**
1385
+ * Get all components that depend on the specified component (reverse lookup)
1386
+ * @param name - Component name to find dependents for
1387
+ * @returns Array of component names that depend on this component
1388
+ */
1389
+ private getDependents;
1390
+ /**
1391
+ * Get running components that depend on the specified component
1392
+ * @param name - Component name to check
1393
+ * @returns Array of running component names that depend on this component
1394
+ */
1395
+ private getRunningDependents;
1396
+ /**
1397
+ * Check if a component is a required dependency during startup
1398
+ * Used to prevent registering dependencies mid-startup which would break ordering
1399
+ * @param componentName - Component name to check
1400
+ * @returns true if this component would be a required dependency
1401
+ */
1402
+ private isRequiredDependencyDuringStartup;
1403
+ /**
1404
+ * Check if a component instance is already registered
1405
+ */
1406
+ private hasComponentInstance;
1407
+ /**
1408
+ * Rollback startup by stopping all started components in reverse order
1409
+ * Used when a required component fails to start during startAllComponents()
1410
+ */
1411
+ private rollbackStartup;
1412
+ /**
1413
+ * Safe emit wrapper - prevents event handler errors from breaking lifecycle
1414
+ */
1415
+ private safeEmit;
1416
+ private buildRegisterResultFailure;
1417
+ private buildInsertResultFailure;
1418
+ private getComponentIndex;
1419
+ private isInsertPosition;
1420
+ private getInsertIndex;
1421
+ private isManualPositionRespected;
1422
+ /**
1423
+ * Dependency-aware startup order.
1424
+ *
1425
+ * - Only registered components are included.
1426
+ * - Missing dependencies are ignored for ordering (they are validated at start time).
1427
+ * - Cycles throw DependencyCycleError (programmer error).
1428
+ */
1429
+ private getStartupOrderInternal;
1430
+ /**
1431
+ * Find a single dependency cycle (for error reporting during registration)
1432
+ * Returns the first cycle found, or empty array if no cycle exists
1433
+ *
1434
+ * Performance note: This method exits early after finding the first cycle,
1435
+ * which is optimal for hot paths (registration, startup order resolution).
1436
+ * For comprehensive validation that needs ALL cycles, use findAllCircularCycles().
1437
+ */
1438
+ private findDependencyCycle;
1439
+ /**
1440
+ * Find circular dependency cycles using Depth-First Search (DFS) with cycle detection.
1441
+ *
1442
+ * Algorithm: DFS with visited set and recursion stack tracking
1443
+ * - Uses 'visited' set to ensure each node is processed exactly once (prevents infinite loops)
1444
+ * - Uses 'inStack' set to track the current DFS recursion path
1445
+ * - When a node in the current path is encountered again, a cycle is detected
1446
+ * - Extracts the cycle from the path and continues searching for more cycles
1447
+ *
1448
+ * Time Complexity: O(V + E) where V = components, E = dependency edges
1449
+ * Space Complexity: O(V) for visited/inStack sets and recursion stack
1450
+ *
1451
+ * Performance note: This method finds a representative set of cycles while ensuring
1452
+ * each node is visited once (prevents infinite loops). For hot paths that only need
1453
+ * one cycle, use findDependencyCycle() which exits early.
1454
+ *
1455
+ * Returns an array of detected cycles, where each cycle is an array of component names.
1456
+ */
1457
+ private findAllCircularCycles;
1458
+ /**
1459
+ * Handle shutdown signal - initiates stopAllComponents().
1460
+ * Double signal protection: if already shutting down, log warning and ignore.
1461
+ */
1462
+ private handleShutdownRequest;
1463
+ /**
1464
+ * Handle reload request - calls custom callback or broadcasts to components.
1465
+ *
1466
+ * When called from signal handlers (source='signal'), the Promise is started
1467
+ * but not awaited due to Node.js signal handler constraints. Components are
1468
+ * still notified and the work completes, but return values are not accessible.
1469
+ *
1470
+ * When called from manual triggers (source='trigger'), the Promise is awaited
1471
+ * and results are returned for programmatic use.
1472
+ *
1473
+ * @param source - Whether triggered from signal manager or manual trigger
1474
+ */
1475
+ private handleReloadRequest;
1476
+ /**
1477
+ * Handle info request - calls custom callback or broadcasts to components.
1478
+ *
1479
+ * When called from signal handlers, the Promise executes but return values
1480
+ * are not accessible due to Node.js signal handler constraints.
1481
+ *
1482
+ * @param source - Whether triggered from signal manager or manual trigger
1483
+ */
1484
+ private handleInfoRequest;
1485
+ /**
1486
+ * Handle debug request - calls custom callback or broadcasts to components.
1487
+ *
1488
+ * When called from signal handlers, the Promise executes but return values
1489
+ * are not accessible due to Node.js signal handler constraints.
1490
+ *
1491
+ * @param source - Whether triggered from signal manager or manual trigger
1492
+ */
1493
+ private handleDebugRequest;
1494
+ /**
1495
+ * Broadcast reload signal to all running components.
1496
+ * Calls onReload() on components that implement it.
1497
+ * Continues on errors - collects all results.
1498
+ */
1499
+ private broadcastReload;
1500
+ /**
1501
+ * Broadcast info signal to all running components.
1502
+ * Calls onInfo() on components that implement it.
1503
+ * Continues on errors - collects all results.
1504
+ */
1505
+ private broadcastInfo;
1506
+ /**
1507
+ * Broadcast debug signal to all running components.
1508
+ * Calls onDebug() on components that implement it.
1509
+ * Continues on errors - collects all results.
1510
+ */
1511
+ private broadcastDebug;
1512
+ }
1513
+
1514
+ interface LifecycleManagerEventMap {
1515
+ 'component:unregistered': {
1516
+ name: string;
1517
+ duringShutdown?: boolean;
1518
+ };
1519
+ 'component:start-skipped': {
1520
+ name: string;
1521
+ reason: string;
1522
+ };
1523
+ 'component:start-failed-optional': {
1524
+ name: string;
1525
+ error?: Error;
1526
+ };
1527
+ 'lifecycle-manager:started': {
1528
+ startedComponents: string[];
1529
+ failedOptionalComponents: StartupResult['failedOptionalComponents'];
1530
+ skippedComponents: string[];
1531
+ };
1532
+ 'lifecycle-manager:signals-attached': undefined;
1533
+ 'lifecycle-manager:signals-detached': undefined;
1534
+ 'component:health-check-started': {
1535
+ name: string;
1536
+ };
1537
+ 'component:health-check-completed': {
1538
+ name: string;
1539
+ healthy: boolean;
1540
+ message?: string;
1541
+ details?: ComponentHealthResult['details'];
1542
+ durationMS: number;
1543
+ timedOut: boolean;
1544
+ };
1545
+ 'component:health-check-failed': {
1546
+ name: string;
1547
+ error: Error;
1548
+ };
1549
+ 'component:message-sent': {
1550
+ componentName: string;
1551
+ from: string | null;
1552
+ payload: unknown;
1553
+ };
1554
+ 'component:message-failed': {
1555
+ componentName: string;
1556
+ from: string | null;
1557
+ error: Error;
1558
+ timedOut: boolean;
1559
+ code: MessageResult['code'];
1560
+ componentFound?: boolean;
1561
+ componentRunning?: boolean;
1562
+ handlerImplemented?: boolean;
1563
+ data?: unknown;
1564
+ };
1565
+ 'component:broadcast-started': {
1566
+ from: string | null;
1567
+ payload: unknown;
1568
+ };
1569
+ 'component:broadcast-completed': {
1570
+ from: string | null;
1571
+ resultsCount: number;
1572
+ results: BroadcastResult[];
1573
+ };
1574
+ 'component:value-requested': {
1575
+ componentName: string;
1576
+ key: string;
1577
+ from: string | null;
1578
+ };
1579
+ 'component:value-returned': {
1580
+ componentName: string;
1581
+ key: string;
1582
+ from: string | null;
1583
+ found: boolean;
1584
+ value: unknown;
1585
+ componentFound: boolean;
1586
+ componentRunning: boolean;
1587
+ handlerImplemented: boolean;
1588
+ requestedBy: string | null;
1589
+ code: ValueResult['code'];
1590
+ };
1591
+ 'component:registration-rejected': {
1592
+ name: string;
1593
+ reason: RegistrationFailureCode;
1594
+ message?: string;
1595
+ target?: string | null;
1596
+ cycle?: string[];
1597
+ registrationIndexBefore?: number | null;
1598
+ registrationIndexAfter?: number | null;
1599
+ startupOrder?: string[];
1600
+ requestedPosition?: InsertComponentAtResult['requestedPosition'];
1601
+ manualPositionRespected?: boolean;
1602
+ targetFound?: boolean;
1603
+ };
1604
+ 'component:registered': {
1605
+ name: string;
1606
+ index: number | null;
1607
+ action: RegisterComponentResult['action'] | InsertComponentAtResult['action'];
1608
+ registrationIndexBefore: number | null;
1609
+ registrationIndexAfter: number | null;
1610
+ startupOrder: string[];
1611
+ requestedPosition?: InsertComponentAtResult['requestedPosition'];
1612
+ actualPosition?: InsertComponentAtResult['actualPosition'];
1613
+ manualPositionRespected?: boolean;
1614
+ targetFound?: boolean;
1615
+ duringStartup?: boolean;
1616
+ autoStartAttempted?: boolean;
1617
+ autoStartSucceeded?: boolean;
1618
+ };
1619
+ 'lifecycle-manager:shutdown-initiated': {
1620
+ method: ShutdownMethod;
1621
+ duringStartup: boolean;
1622
+ };
1623
+ 'lifecycle-manager:shutdown-completed': {
1624
+ durationMS: number;
1625
+ stoppedComponents: string[];
1626
+ stalledComponents: ComponentStallInfo[];
1627
+ method: ShutdownMethod;
1628
+ duringStartup: boolean;
1629
+ };
1630
+ 'component:starting': {
1631
+ name: string;
1632
+ };
1633
+ 'component:started': {
1634
+ name: string;
1635
+ status?: ComponentStatus;
1636
+ };
1637
+ 'component:start-timeout': {
1638
+ name: string;
1639
+ error: Error;
1640
+ timeoutMS?: number;
1641
+ reason?: string;
1642
+ };
1643
+ 'component:start-failed': {
1644
+ name: string;
1645
+ error: Error;
1646
+ reason?: string;
1647
+ };
1648
+ 'lifecycle-manager:shutdown-warning': {
1649
+ timeoutMS: number;
1650
+ };
1651
+ 'component:shutdown-warning': {
1652
+ name: string;
1653
+ };
1654
+ 'component:shutdown-warning-completed': {
1655
+ name: string;
1656
+ };
1657
+ 'lifecycle-manager:shutdown-warning-completed': {
1658
+ timeoutMS: number;
1659
+ };
1660
+ 'component:shutdown-warning-timeout': {
1661
+ name: string;
1662
+ timeoutMS: number;
1663
+ };
1664
+ 'lifecycle-manager:shutdown-warning-timeout': {
1665
+ timeoutMS: number;
1666
+ pending: string[];
1667
+ };
1668
+ 'component:stopping': {
1669
+ name: string;
1670
+ };
1671
+ 'component:stopped': {
1672
+ name: string;
1673
+ status?: ComponentStatus;
1674
+ };
1675
+ 'component:stop-timeout': {
1676
+ name: string;
1677
+ error: Error;
1678
+ timeoutMS?: number;
1679
+ reason?: string;
1680
+ };
1681
+ 'component:shutdown-force': {
1682
+ name: string;
1683
+ context: {
1684
+ gracefulPhaseRan: boolean;
1685
+ gracefulTimedOut: boolean;
1686
+ };
1687
+ };
1688
+ 'component:stalled': {
1689
+ name: string;
1690
+ stallInfo: ComponentStallInfo;
1691
+ reason?: string;
1692
+ code?: string;
1693
+ };
1694
+ 'component:shutdown-force-completed': {
1695
+ name: string;
1696
+ };
1697
+ 'component:shutdown-force-timeout': {
1698
+ name: string;
1699
+ timeoutMS: number;
1700
+ };
1701
+ 'component:startup-rollback': {
1702
+ name: string;
1703
+ };
1704
+ 'signal:shutdown': {
1705
+ method: ShutdownSignal;
1706
+ };
1707
+ 'signal:reload': undefined;
1708
+ 'signal:info': undefined;
1709
+ 'signal:debug': undefined;
1710
+ 'component:reload-started': {
1711
+ name: string;
1712
+ };
1713
+ 'component:reload-completed': {
1714
+ name: string;
1715
+ };
1716
+ 'component:reload-failed': {
1717
+ name: string;
1718
+ error: Error;
1719
+ };
1720
+ 'component:info-started': {
1721
+ name: string;
1722
+ };
1723
+ 'component:info-completed': {
1724
+ name: string;
1725
+ };
1726
+ 'component:info-failed': {
1727
+ name: string;
1728
+ error: Error;
1729
+ };
1730
+ 'component:debug-started': {
1731
+ name: string;
1732
+ };
1733
+ 'component:debug-completed': {
1734
+ name: string;
1735
+ };
1736
+ 'component:debug-failed': {
1737
+ name: string;
1738
+ error: Error;
1739
+ };
1740
+ }
1741
+ type LifecycleManagerEventName = keyof LifecycleManagerEventMap;
1742
+ type LifecycleManagerEmit = <K extends LifecycleManagerEventName>(event: K, data: LifecycleManagerEventMap[K]) => void;
1743
+ declare class LifecycleManagerEvents {
1744
+ private readonly emit;
1745
+ constructor(emit: LifecycleManagerEmit);
1746
+ componentUnregistered(name: string, wasDuringShutdown?: boolean): void;
1747
+ componentStartSkipped(name: string, reason: string): void;
1748
+ componentStartFailedOptional(name: string, error?: Error): void;
1749
+ lifecycleManagerStarted(startedComponents: string[], failedOptionalComponents: StartupResult['failedOptionalComponents'], skippedComponents: string[]): void;
1750
+ lifecycleManagerSignalsAttached(): void;
1751
+ lifecycleManagerSignalsDetached(): void;
1752
+ componentHealthCheckStarted(name: string): void;
1753
+ componentHealthCheckCompleted(input: {
1754
+ name: string;
1755
+ healthy: boolean;
1756
+ message?: string;
1757
+ details?: ComponentHealthResult['details'];
1758
+ durationMS: number;
1759
+ timedOut: boolean;
1760
+ }): void;
1761
+ componentHealthCheckFailed(name: string, error: Error): void;
1762
+ componentMessageSent(input: {
1763
+ componentName: string;
1764
+ from: string | null;
1765
+ payload: unknown;
1766
+ }): void;
1767
+ componentMessageFailed(componentName: string, from: string | null, error: Error, info?: {
1768
+ timedOut?: boolean;
1769
+ code?: MessageResult['code'];
1770
+ componentFound?: boolean;
1771
+ componentRunning?: boolean;
1772
+ handlerImplemented?: boolean;
1773
+ data?: unknown;
1774
+ }): void;
1775
+ componentBroadcastStarted(from: string | null, payload: unknown): void;
1776
+ componentBroadcastCompleted(from: string | null, resultsCount: number, results: BroadcastResult[]): void;
1777
+ componentValueRequested(componentName: string, key: string, from: string | null): void;
1778
+ componentValueReturned(componentName: string, key: string, from: string | null, input: {
1779
+ found: boolean;
1780
+ value: unknown;
1781
+ componentFound: boolean;
1782
+ componentRunning: boolean;
1783
+ handlerImplemented: boolean;
1784
+ requestedBy: string | null;
1785
+ code: ValueResult['code'];
1786
+ }): void;
1787
+ componentRegistrationRejected(input: {
1788
+ name: string;
1789
+ reason: RegistrationFailureCode;
1790
+ message?: string;
1791
+ target?: string | null;
1792
+ cycle?: string[];
1793
+ registrationIndexBefore?: number | null;
1794
+ registrationIndexAfter?: number | null;
1795
+ startupOrder?: string[];
1796
+ requestedPosition?: InsertComponentAtResult['requestedPosition'];
1797
+ manualPositionRespected?: boolean;
1798
+ targetFound?: boolean;
1799
+ }): void;
1800
+ componentRegistered(input: {
1801
+ name: string;
1802
+ index: number | null;
1803
+ action: RegisterComponentResult['action'] | InsertComponentAtResult['action'];
1804
+ registrationIndexBefore: number | null;
1805
+ registrationIndexAfter: number | null;
1806
+ startupOrder: string[];
1807
+ requestedPosition?: InsertComponentAtResult['requestedPosition'];
1808
+ actualPosition?: InsertComponentAtResult['actualPosition'];
1809
+ manualPositionRespected?: boolean;
1810
+ targetFound?: boolean;
1811
+ duringStartup?: boolean;
1812
+ autoStartAttempted?: boolean;
1813
+ autoStartSucceeded?: boolean;
1814
+ }): void;
1815
+ lifecycleManagerShutdownInitiated(method: ShutdownMethod, isDuringStartup: boolean): void;
1816
+ lifecycleManagerShutdownCompleted(input: {
1817
+ durationMS: number;
1818
+ stoppedComponents: string[];
1819
+ stalledComponents: ComponentStallInfo[];
1820
+ method: ShutdownMethod;
1821
+ duringStartup: boolean;
1822
+ }): void;
1823
+ componentStarting(name: string): void;
1824
+ componentStarted(name: string, status?: ComponentStatus): void;
1825
+ componentStartTimeout(name: string, error: Error, info?: {
1826
+ timeoutMS?: number;
1827
+ reason?: string;
1828
+ }): void;
1829
+ componentStartFailed(name: string, error: Error, info?: {
1830
+ reason?: string;
1831
+ }): void;
1832
+ lifecycleManagerShutdownWarning(timeoutMS: number): void;
1833
+ componentShutdownWarning(name: string): void;
1834
+ componentShutdownWarningCompleted(name: string): void;
1835
+ lifecycleManagerShutdownWarningCompleted(timeoutMS: number): void;
1836
+ componentShutdownWarningTimeout(name: string, timeoutMS: number): void;
1837
+ lifecycleManagerShutdownWarningTimeout(timeoutMS: number, pending: string[]): void;
1838
+ componentStopping(name: string): void;
1839
+ componentStopped(name: string, status?: ComponentStatus): void;
1840
+ componentStopTimeout(name: string, error: Error, info?: {
1841
+ timeoutMS?: number;
1842
+ reason?: string;
1843
+ }): void;
1844
+ componentShutdownForce(input: {
1845
+ name: string;
1846
+ context: {
1847
+ gracefulPhaseRan: boolean;
1848
+ gracefulTimedOut: boolean;
1849
+ };
1850
+ }): void;
1851
+ componentStalled(name: string, stallInfo: ComponentStallInfo, info?: {
1852
+ reason?: string;
1853
+ code?: string;
1854
+ }): void;
1855
+ componentShutdownForceCompleted(name: string): void;
1856
+ componentShutdownForceTimeout(name: string, timeoutMS: number): void;
1857
+ componentStartupRollback(name: string): void;
1858
+ signalShutdown(method: ShutdownSignal): void;
1859
+ signalReload(): void;
1860
+ signalInfo(): void;
1861
+ signalDebug(): void;
1862
+ componentReloadStarted(name: string): void;
1863
+ componentReloadCompleted(name: string): void;
1864
+ componentReloadFailed(name: string, error: Error): void;
1865
+ componentInfoStarted(name: string): void;
1866
+ componentInfoCompleted(name: string): void;
1867
+ componentInfoFailed(name: string, error: Error): void;
1868
+ componentDebugStarted(name: string): void;
1869
+ componentDebugCompleted(name: string): void;
1870
+ componentDebugFailed(name: string, error: Error): void;
1871
+ }
1872
+
1873
+ /**
1874
+ * Error thrown when a component name doesn't match kebab-case validation
1875
+ *
1876
+ * Component names must match the pattern: `/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/`
1877
+ *
1878
+ * Valid names: 'database', 'web-server', 'api-gateway-v2'
1879
+ * Invalid names: 'Database', 'web_server', 'WebServer', '', 'my server'
1880
+ */
1881
+ declare class InvalidComponentNameError extends Error {
1882
+ errPrefix: string;
1883
+ errType: string;
1884
+ errCode: string;
1885
+ additionalInfo: {
1886
+ name: string;
1887
+ };
1888
+ constructor(additionalInfo: {
1889
+ name: string;
1890
+ });
1891
+ }
1892
+ /**
1893
+ * Error thrown when component registration fails
1894
+ *
1895
+ * Common causes:
1896
+ * - Duplicate component name
1897
+ * - Registration attempted during shutdown
1898
+ * - Invalid registration options
1899
+ */
1900
+ declare class ComponentRegistrationError extends Error {
1901
+ errPrefix: string;
1902
+ errType: string;
1903
+ errCode: string;
1904
+ additionalInfo: Record<string, unknown>;
1905
+ constructor(message: string, additionalInfo?: Record<string, unknown>);
1906
+ }
1907
+ /**
1908
+ * Error thrown when a circular dependency is detected
1909
+ *
1910
+ * Example: Component A depends on B, B depends on C, C depends on A
1911
+ */
1912
+ declare class DependencyCycleError extends Error {
1913
+ errPrefix: string;
1914
+ errType: string;
1915
+ errCode: string;
1916
+ additionalInfo: {
1917
+ cycle: string[];
1918
+ };
1919
+ constructor(additionalInfo: {
1920
+ cycle: string[];
1921
+ });
1922
+ }
1923
+ /**
1924
+ * Error thrown when a component depends on another component that doesn't exist
1925
+ */
1926
+ declare class MissingDependencyError extends Error {
1927
+ errPrefix: string;
1928
+ errType: string;
1929
+ errCode: string;
1930
+ additionalInfo: {
1931
+ componentName: string;
1932
+ missingDependency: string;
1933
+ };
1934
+ constructor(additionalInfo: {
1935
+ componentName: string;
1936
+ missingDependency: string;
1937
+ });
1938
+ }
1939
+ /**
1940
+ * Error thrown when a component fails to start
1941
+ *
1942
+ * This wraps the underlying error and provides context about which component failed
1943
+ */
1944
+ declare class ComponentStartupError extends Error {
1945
+ errPrefix: string;
1946
+ errType: string;
1947
+ errCode: string;
1948
+ additionalInfo: {
1949
+ componentName: string;
1950
+ };
1951
+ cause?: Error;
1952
+ constructor(additionalInfo: {
1953
+ componentName: string;
1954
+ }, cause?: Error);
1955
+ }
1956
+ /**
1957
+ * Error thrown when a component start operation times out
1958
+ */
1959
+ declare class ComponentStartTimeoutError extends Error {
1960
+ errPrefix: string;
1961
+ errType: string;
1962
+ errCode: string;
1963
+ additionalInfo: {
1964
+ componentName: string;
1965
+ timeoutMS: number;
1966
+ };
1967
+ constructor(additionalInfo: {
1968
+ componentName: string;
1969
+ timeoutMS: number;
1970
+ });
1971
+ }
1972
+ /**
1973
+ * Error thrown when a component stop operation times out
1974
+ */
1975
+ declare class ComponentStopTimeoutError extends Error {
1976
+ errPrefix: string;
1977
+ errType: string;
1978
+ errCode: string;
1979
+ additionalInfo: {
1980
+ componentName: string;
1981
+ timeoutMS: number;
1982
+ };
1983
+ constructor(additionalInfo: {
1984
+ componentName: string;
1985
+ timeoutMS: number;
1986
+ });
1987
+ }
1988
+ /**
1989
+ * Error thrown when the global startup timeout is exceeded
1990
+ */
1991
+ declare class StartupTimeoutError extends Error {
1992
+ errPrefix: string;
1993
+ errType: string;
1994
+ errCode: string;
1995
+ additionalInfo: {
1996
+ timeoutMS: number;
1997
+ startedCount: number;
1998
+ };
1999
+ constructor(additionalInfo: {
2000
+ timeoutMS: number;
2001
+ startedCount: number;
2002
+ });
2003
+ }
2004
+ /**
2005
+ * Error thrown when a component is not found in the registry
2006
+ */
2007
+ declare class ComponentNotFoundError extends Error {
2008
+ errPrefix: string;
2009
+ errType: string;
2010
+ errCode: string;
2011
+ additionalInfo: {
2012
+ componentName: string;
2013
+ };
2014
+ constructor(additionalInfo: {
2015
+ componentName: string;
2016
+ });
2017
+ }
2018
+ /**
2019
+ * Error prefix constant for all lifecycle manager errors
2020
+ */
2021
+ declare const lifecycleManagerErrPrefix = "LifecycleManagerErr";
2022
+ /**
2023
+ * Error type constants
2024
+ */
2025
+ declare const lifecycleManagerErrTypes: {
2026
+ readonly Component: "Component";
2027
+ readonly Dependency: "Dependency";
2028
+ readonly Lifecycle: "Lifecycle";
2029
+ };
2030
+ /**
2031
+ * Error code constants
2032
+ */
2033
+ declare const lifecycleManagerErrCodes: {
2034
+ readonly InvalidName: "InvalidName";
2035
+ readonly RegistrationFailed: "RegistrationFailed";
2036
+ readonly CyclicDependency: "CyclicDependency";
2037
+ readonly NotFound: "NotFound";
2038
+ readonly StartupFailed: "StartupFailed";
2039
+ readonly StartupTimeout: "StartupTimeout";
2040
+ readonly StartTimeout: "StartTimeout";
2041
+ readonly StopTimeout: "StopTimeout";
2042
+ };
2043
+
2044
+ 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 };