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.
- package/LICENSE +22 -0
- package/README.md +125 -0
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/arrays.cjs +95 -0
- package/dist/lib/arrays.cjs.map +1 -0
- package/dist/lib/arrays.d.cts +15 -0
- package/dist/lib/arrays.d.ts +15 -0
- package/dist/lib/arrays.js +63 -0
- package/dist/lib/arrays.js.map +1 -0
- package/dist/lib/ascii-tables/index.cjs +642 -0
- package/dist/lib/ascii-tables/index.cjs.map +1 -0
- package/dist/lib/ascii-tables/index.d.cts +66 -0
- package/dist/lib/ascii-tables/index.d.ts +66 -0
- package/dist/lib/ascii-tables/index.js +603 -0
- package/dist/lib/ascii-tables/index.js.map +1 -0
- package/dist/lib/clamp.cjs +41 -0
- package/dist/lib/clamp.cjs.map +1 -0
- package/dist/lib/clamp.d.cts +26 -0
- package/dist/lib/clamp.d.ts +26 -0
- package/dist/lib/clamp.js +15 -0
- package/dist/lib/clamp.js.map +1 -0
- package/dist/lib/constants.cjs +73 -0
- package/dist/lib/constants.cjs.map +1 -0
- package/dist/lib/constants.d.cts +17 -0
- package/dist/lib/constants.d.ts +17 -0
- package/dist/lib/constants.js +34 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/curly-brackets.cjs +77 -0
- package/dist/lib/curly-brackets.cjs.map +1 -0
- package/dist/lib/curly-brackets.d.cts +17 -0
- package/dist/lib/curly-brackets.d.ts +17 -0
- package/dist/lib/curly-brackets.js +52 -0
- package/dist/lib/curly-brackets.js.map +1 -0
- package/dist/lib/deep-clone.cjs +87 -0
- package/dist/lib/deep-clone.cjs.map +1 -0
- package/dist/lib/deep-clone.d.cts +19 -0
- package/dist/lib/deep-clone.d.ts +19 -0
- package/dist/lib/deep-clone.js +62 -0
- package/dist/lib/deep-clone.js.map +1 -0
- package/dist/lib/error-to-string.cjs +743 -0
- package/dist/lib/error-to-string.cjs.map +1 -0
- package/dist/lib/error-to-string.d.cts +3 -0
- package/dist/lib/error-to-string.d.ts +3 -0
- package/dist/lib/error-to-string.js +706 -0
- package/dist/lib/error-to-string.js.map +1 -0
- package/dist/lib/event-emitter.cjs +899 -0
- package/dist/lib/event-emitter.cjs.map +1 -0
- package/dist/lib/event-emitter.d.cts +78 -0
- package/dist/lib/event-emitter.d.ts +78 -0
- package/dist/lib/event-emitter.js +861 -0
- package/dist/lib/event-emitter.js.map +1 -0
- package/dist/lib/id-helpers.cjs +205 -0
- package/dist/lib/id-helpers.cjs.map +1 -0
- package/dist/lib/id-helpers.d.cts +198 -0
- package/dist/lib/id-helpers.d.ts +198 -0
- package/dist/lib/id-helpers.js +170 -0
- package/dist/lib/id-helpers.js.map +1 -0
- package/dist/lib/is-boolean.cjs +33 -0
- package/dist/lib/is-boolean.cjs.map +1 -0
- package/dist/lib/is-boolean.d.cts +19 -0
- package/dist/lib/is-boolean.d.ts +19 -0
- package/dist/lib/is-boolean.js +8 -0
- package/dist/lib/is-boolean.js.map +1 -0
- package/dist/lib/is-function.cjs +33 -0
- package/dist/lib/is-function.cjs.map +1 -0
- package/dist/lib/is-function.d.cts +3 -0
- package/dist/lib/is-function.d.ts +3 -0
- package/dist/lib/is-function.js +8 -0
- package/dist/lib/is-function.js.map +1 -0
- package/dist/lib/is-number.cjs +38 -0
- package/dist/lib/is-number.cjs.map +1 -0
- package/dist/lib/is-number.d.cts +38 -0
- package/dist/lib/is-number.d.ts +38 -0
- package/dist/lib/is-number.js +12 -0
- package/dist/lib/is-number.js.map +1 -0
- package/dist/lib/is-plain-object.cjs +33 -0
- package/dist/lib/is-plain-object.cjs.map +1 -0
- package/dist/lib/is-plain-object.d.cts +20 -0
- package/dist/lib/is-plain-object.d.ts +20 -0
- package/dist/lib/is-plain-object.js +8 -0
- package/dist/lib/is-plain-object.js.map +1 -0
- package/dist/lib/is-promise.cjs +34 -0
- package/dist/lib/is-promise.cjs.map +1 -0
- package/dist/lib/is-promise.d.cts +3 -0
- package/dist/lib/is-promise.d.ts +3 -0
- package/dist/lib/is-promise.js +9 -0
- package/dist/lib/is-promise.js.map +1 -0
- package/dist/lib/json-helpers.cjs +49 -0
- package/dist/lib/json-helpers.cjs.map +1 -0
- package/dist/lib/json-helpers.d.cts +10 -0
- package/dist/lib/json-helpers.d.ts +10 -0
- package/dist/lib/json-helpers.js +22 -0
- package/dist/lib/json-helpers.js.map +1 -0
- package/dist/lib/lifecycle-manager/index.cjs +5594 -0
- package/dist/lib/lifecycle-manager/index.cjs.map +1 -0
- package/dist/lib/lifecycle-manager/index.d.cts +2044 -0
- package/dist/lib/lifecycle-manager/index.d.ts +2044 -0
- package/dist/lib/lifecycle-manager/index.js +5543 -0
- package/dist/lib/lifecycle-manager/index.js.map +1 -0
- package/dist/lib/logger/index.cjs +2514 -0
- package/dist/lib/logger/index.cjs.map +1 -0
- package/dist/lib/logger/index.d.cts +630 -0
- package/dist/lib/logger/index.d.ts +630 -0
- package/dist/lib/logger/index.js +2470 -0
- package/dist/lib/logger/index.js.map +1 -0
- package/dist/lib/padding-utils.cjs +77 -0
- package/dist/lib/padding-utils.cjs.map +1 -0
- package/dist/lib/padding-utils.d.cts +44 -0
- package/dist/lib/padding-utils.d.ts +44 -0
- package/dist/lib/padding-utils.js +46 -0
- package/dist/lib/padding-utils.js.map +1 -0
- package/dist/lib/process-signal-manager.cjs +1306 -0
- package/dist/lib/process-signal-manager.cjs.map +1 -0
- package/dist/lib/process-signal-manager.d.cts +305 -0
- package/dist/lib/process-signal-manager.d.ts +305 -0
- package/dist/lib/process-signal-manager.js +1269 -0
- package/dist/lib/process-signal-manager.js.map +1 -0
- package/dist/lib/promise-protected-resolver.cjs +828 -0
- package/dist/lib/promise-protected-resolver.cjs.map +1 -0
- package/dist/lib/promise-protected-resolver.d.cts +17 -0
- package/dist/lib/promise-protected-resolver.d.ts +17 -0
- package/dist/lib/promise-protected-resolver.js +791 -0
- package/dist/lib/promise-protected-resolver.js.map +1 -0
- package/dist/lib/retry-utils/index.cjs +2183 -0
- package/dist/lib/retry-utils/index.cjs.map +1 -0
- package/dist/lib/retry-utils/index.d.cts +321 -0
- package/dist/lib/retry-utils/index.d.ts +321 -0
- package/dist/lib/retry-utils/index.js +2133 -0
- package/dist/lib/retry-utils/index.js.map +1 -0
- package/dist/lib/safe-handle-callback.cjs +818 -0
- package/dist/lib/safe-handle-callback.cjs.map +1 -0
- package/dist/lib/safe-handle-callback.d.cts +43 -0
- package/dist/lib/safe-handle-callback.d.ts +43 -0
- package/dist/lib/safe-handle-callback.js +780 -0
- package/dist/lib/safe-handle-callback.js.map +1 -0
- package/dist/lib/serialize-error/index.cjs +93 -0
- package/dist/lib/serialize-error/index.cjs.map +1 -0
- package/dist/lib/serialize-error/index.d.cts +26 -0
- package/dist/lib/serialize-error/index.d.ts +26 -0
- package/dist/lib/serialize-error/index.js +64 -0
- package/dist/lib/serialize-error/index.js.map +1 -0
- package/dist/lib/single-event-observer.cjs +841 -0
- package/dist/lib/single-event-observer.cjs.map +1 -0
- package/dist/lib/single-event-observer.d.cts +54 -0
- package/dist/lib/single-event-observer.d.ts +54 -0
- package/dist/lib/single-event-observer.js +803 -0
- package/dist/lib/single-event-observer.js.map +1 -0
- package/dist/lib/sleep.cjs +37 -0
- package/dist/lib/sleep.cjs.map +1 -0
- package/dist/lib/sleep.d.cts +11 -0
- package/dist/lib/sleep.d.ts +11 -0
- package/dist/lib/sleep.js +12 -0
- package/dist/lib/sleep.js.map +1 -0
- package/dist/lib/strings.cjs +186 -0
- package/dist/lib/strings.cjs.map +1 -0
- package/dist/lib/strings.d.cts +107 -0
- package/dist/lib/strings.d.ts +107 -0
- package/dist/lib/strings.js +149 -0
- package/dist/lib/strings.js.map +1 -0
- package/dist/lib/tmp-dir.cjs +254 -0
- package/dist/lib/tmp-dir.cjs.map +1 -0
- package/dist/lib/tmp-dir.d.cts +63 -0
- package/dist/lib/tmp-dir.d.ts +63 -0
- package/dist/lib/tmp-dir.js +211 -0
- package/dist/lib/tmp-dir.js.map +1 -0
- package/dist/lib/unix-time-helpers.cjs +53 -0
- package/dist/lib/unix-time-helpers.cjs.map +1 -0
- package/dist/lib/unix-time-helpers.d.cts +56 -0
- package/dist/lib/unix-time-helpers.d.ts +56 -0
- package/dist/lib/unix-time-helpers.js +24 -0
- package/dist/lib/unix-time-helpers.js.map +1 -0
- 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 };
|