@zudojs/runtime 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -6
  3. package/dist/dependencyGraph/dependencyGraph.core.d.ts +11 -5
  4. package/dist/dependencyGraph/dependencyGraph.core.js +13 -12
  5. package/dist/dependencyGraph/dependencyGraph.type.d.ts +0 -7
  6. package/dist/dependencyGraph/index.d.ts +2 -2
  7. package/dist/dependencyGraph/index.js +1 -1
  8. package/dist/health/health.core.d.ts +12 -0
  9. package/dist/health/health.core.js +55 -0
  10. package/dist/health/index.d.ts +5 -0
  11. package/dist/health/index.js +5 -0
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +4 -1
  14. package/dist/lifecycle/index.d.ts +1 -1
  15. package/dist/lifecycle/lifecycle.core.d.ts +41 -10
  16. package/dist/lifecycle/lifecycle.core.js +238 -61
  17. package/dist/lifecycle/lifecycle.type.d.ts +48 -1
  18. package/dist/readiness/index.d.ts +1 -1
  19. package/dist/readiness/readiness.core.d.ts +36 -4
  20. package/dist/readiness/readiness.core.js +122 -6
  21. package/dist/readiness/readiness.type.d.ts +15 -1
  22. package/dist/registry/registry.core.d.ts +14 -1
  23. package/dist/registry/registry.core.js +41 -2
  24. package/dist/runtime/runtime.core.d.ts +75 -5
  25. package/dist/runtime/runtime.core.js +210 -43
  26. package/dist/runtimeContext/index.d.ts +2 -2
  27. package/dist/runtimeContext/index.js +1 -1
  28. package/dist/runtimeContext/runtimeContext.core.d.ts +13 -4
  29. package/dist/runtimeContext/runtimeContext.core.js +22 -11
  30. package/dist/runtimeContext/runtimeContext.type.d.ts +12 -13
  31. package/dist/runtimeError/runtimeError.base.js +1 -1
  32. package/dist/runtimeEvents/index.d.ts +2 -2
  33. package/dist/runtimeEvents/index.js +1 -1
  34. package/dist/runtimeEvents/runtimeEvents.core.d.ts +15 -1
  35. package/dist/runtimeEvents/runtimeEvents.core.js +26 -0
  36. package/dist/runtimeEvents/runtimeEvents.type.d.ts +19 -4
  37. package/dist/runtimeOptions/runtimeOptions.core.d.ts +5 -0
  38. package/dist/runtimeOptions/runtimeOptions.core.js +14 -1
  39. package/dist/runtimeOptions/runtimeOptions.type.d.ts +29 -1
  40. package/dist/runtimeOptions/runtimeOptions.type.js +6 -0
  41. package/dist/runtimeState/index.d.ts +1 -1
  42. package/dist/runtimeState/runtimeState.core.d.ts +4 -0
  43. package/dist/runtimeState/runtimeState.core.js +17 -4
  44. package/dist/runtimeState/runtimeState.type.d.ts +14 -17
  45. package/dist/shutdown/shutdown.core.d.ts +20 -1
  46. package/dist/shutdown/shutdown.core.js +55 -29
  47. package/dist/signalHandler/signalHandler.core.d.ts +53 -13
  48. package/dist/signalHandler/signalHandler.core.js +97 -27
  49. package/dist/startup/startup.core.d.ts +3 -2
  50. package/dist/startup/startup.core.js +52 -46
  51. package/dist/testRuntime/index.d.ts +6 -1
  52. package/dist/testRuntime/index.js +5 -1
  53. package/dist/testRuntime/testRuntime.core.d.ts +21 -2
  54. package/dist/testRuntime/testRuntime.core.js +23 -6
  55. package/package.json +33 -22
  56. package/dist/.tsbuildinfo +0 -1
  57. package/dist/dependencyGraph/dependencyGraph.core.d.ts.map +0 -1
  58. package/dist/dependencyGraph/dependencyGraph.core.js.map +0 -1
  59. package/dist/dependencyGraph/dependencyGraph.type.d.ts.map +0 -1
  60. package/dist/dependencyGraph/dependencyGraph.type.js.map +0 -1
  61. package/dist/dependencyGraph/index.d.ts.map +0 -1
  62. package/dist/dependencyGraph/index.js.map +0 -1
  63. package/dist/index.d.ts.map +0 -1
  64. package/dist/index.js.map +0 -1
  65. package/dist/lifecycle/index.d.ts.map +0 -1
  66. package/dist/lifecycle/index.js.map +0 -1
  67. package/dist/lifecycle/lifecycle.core.d.ts.map +0 -1
  68. package/dist/lifecycle/lifecycle.core.js.map +0 -1
  69. package/dist/lifecycle/lifecycle.type.d.ts.map +0 -1
  70. package/dist/lifecycle/lifecycle.type.js.map +0 -1
  71. package/dist/readiness/index.d.ts.map +0 -1
  72. package/dist/readiness/index.js.map +0 -1
  73. package/dist/readiness/readiness.core.d.ts.map +0 -1
  74. package/dist/readiness/readiness.core.js.map +0 -1
  75. package/dist/readiness/readiness.type.d.ts.map +0 -1
  76. package/dist/readiness/readiness.type.js.map +0 -1
  77. package/dist/registry/index.d.ts.map +0 -1
  78. package/dist/registry/index.js.map +0 -1
  79. package/dist/registry/registry.core.d.ts.map +0 -1
  80. package/dist/registry/registry.core.js.map +0 -1
  81. package/dist/runtime/runtime.core.d.ts.map +0 -1
  82. package/dist/runtime/runtime.core.js.map +0 -1
  83. package/dist/runtimeContext/index.d.ts.map +0 -1
  84. package/dist/runtimeContext/index.js.map +0 -1
  85. package/dist/runtimeContext/runtimeContext.core.d.ts.map +0 -1
  86. package/dist/runtimeContext/runtimeContext.core.js.map +0 -1
  87. package/dist/runtimeContext/runtimeContext.factory.d.ts.map +0 -1
  88. package/dist/runtimeContext/runtimeContext.factory.js.map +0 -1
  89. package/dist/runtimeContext/runtimeContext.type.d.ts.map +0 -1
  90. package/dist/runtimeContext/runtimeContext.type.js.map +0 -1
  91. package/dist/runtimeError/index.d.ts.map +0 -1
  92. package/dist/runtimeError/index.js.map +0 -1
  93. package/dist/runtimeError/runtimeError.base.d.ts.map +0 -1
  94. package/dist/runtimeError/runtimeError.base.js.map +0 -1
  95. package/dist/runtimeEvents/index.d.ts.map +0 -1
  96. package/dist/runtimeEvents/index.js.map +0 -1
  97. package/dist/runtimeEvents/runtimeEvents.core.d.ts.map +0 -1
  98. package/dist/runtimeEvents/runtimeEvents.core.js.map +0 -1
  99. package/dist/runtimeEvents/runtimeEvents.type.d.ts.map +0 -1
  100. package/dist/runtimeEvents/runtimeEvents.type.js.map +0 -1
  101. package/dist/runtimeOptions/index.d.ts.map +0 -1
  102. package/dist/runtimeOptions/index.js.map +0 -1
  103. package/dist/runtimeOptions/runtimeOptions.core.d.ts.map +0 -1
  104. package/dist/runtimeOptions/runtimeOptions.core.js.map +0 -1
  105. package/dist/runtimeOptions/runtimeOptions.type.d.ts.map +0 -1
  106. package/dist/runtimeOptions/runtimeOptions.type.js.map +0 -1
  107. package/dist/runtimeState/index.d.ts.map +0 -1
  108. package/dist/runtimeState/index.js.map +0 -1
  109. package/dist/runtimeState/runtimeState.core.d.ts.map +0 -1
  110. package/dist/runtimeState/runtimeState.core.js.map +0 -1
  111. package/dist/runtimeState/runtimeState.type.d.ts.map +0 -1
  112. package/dist/runtimeState/runtimeState.type.js.map +0 -1
  113. package/dist/shutdown/index.d.ts.map +0 -1
  114. package/dist/shutdown/index.js.map +0 -1
  115. package/dist/shutdown/shutdown.core.d.ts.map +0 -1
  116. package/dist/shutdown/shutdown.core.js.map +0 -1
  117. package/dist/signalHandler/index.d.ts.map +0 -1
  118. package/dist/signalHandler/index.js.map +0 -1
  119. package/dist/signalHandler/signalHandler.core.d.ts.map +0 -1
  120. package/dist/signalHandler/signalHandler.core.js.map +0 -1
  121. package/dist/startup/index.d.ts.map +0 -1
  122. package/dist/startup/index.js.map +0 -1
  123. package/dist/startup/startup.core.d.ts.map +0 -1
  124. package/dist/startup/startup.core.js.map +0 -1
  125. package/dist/testRuntime/index.d.ts.map +0 -1
  126. package/dist/testRuntime/index.js.map +0 -1
  127. package/dist/testRuntime/testRuntime.core.d.ts.map +0 -1
  128. package/dist/testRuntime/testRuntime.core.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zudojs Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -10,24 +10,145 @@ npm install @zudojs/runtime
10
10
 
11
11
  ## Quick Start
12
12
 
13
+ `createRuntime` takes the framework services the runtime orchestrates,
14
+ then the runtime's own options.
15
+
13
16
  ```typescript
14
17
  import { createRuntime } from "@zudojs/runtime";
15
18
 
16
- const runtime = createRuntime({
17
- services: [api, database, queue],
18
- });
19
+ const runtime = createRuntime(
20
+ {
21
+ modules: new Map([
22
+ ["database", database],
23
+ ["api", api],
24
+ ]),
25
+ logger,
26
+ container,
27
+ eventBus,
28
+ },
29
+ {
30
+ environment: "production",
31
+ applicationName: "my-app",
32
+ },
33
+ );
19
34
 
20
35
  await runtime.start();
21
36
  await runtime.stop();
22
37
  ```
23
38
 
39
+ Modules start in dependency order and stop in reverse.
40
+
41
+ ## Readiness and health
42
+
43
+ Readiness checks are registered on the runtime and re-evaluated on demand.
44
+ A registered check starts out failing until it is first run, so registering
45
+ one on a running runtime moves it to `degraded` until it passes.
46
+
47
+ ```typescript
48
+ runtime.registerReadinessCheck("database", () => database.isConnected());
49
+
50
+ await runtime.runReadinessChecks();
51
+
52
+ runtime.ready; // false while any check fails
53
+ runtime.health.state; // "healthy" | "degraded" | ...
54
+ runtime.readiness.checks.get("database"); // per-check result and duration
55
+ ```
56
+
57
+ `runtime.health` is derived from the lifecycle state and the readiness
58
+ checks: a running runtime is `healthy` when every check passes and
59
+ `degraded` when any check fails; every other lifecycle state maps onto
60
+ `starting`, `stopping`, `unhealthy` or `unknown`. A change emits
61
+ `runtime.health.changed` on the event bus.
62
+
63
+ `runtime.status` and `runtime.context` are read live, so `state`, `ready`,
64
+ `health`, `startedAt`, `stoppedAt`, `failedAt` and `error` always reflect
65
+ the runtime as it is now — including on the failure path, where
66
+ `context.error` names what went wrong.
67
+
68
+ By default a readiness check that does not settle within 5 seconds is
69
+ recorded as failed; pass `readinessCheckTimeout` to change that bound, or
70
+ `0` to remove it.
71
+
72
+ ## Module context
73
+
74
+ Modules receive a `ModuleContext` giving them the framework services they
75
+ are allowed to reach. Configuration and the application context are
76
+ supplied through the runtime's dependencies:
77
+
78
+ ```typescript
79
+ const runtime = createRuntime(
80
+ { modules, logger, container, eventBus, configuration, application },
81
+ options,
82
+ );
83
+ ```
84
+
85
+ `configuration` backs `context.getConfiguration()`, `context.getConfig()`
86
+ and `context.requireConfig()`; it defaults to an empty manager loaded at
87
+ startup. `application` backs `context.application` — a module that reads
88
+ it when none was supplied gets a clear error rather than an empty object.
89
+ `context.hasModule()` and `context.getModuleContext()` resolve against the
90
+ registered modules, and a module keeps the same context across every
91
+ lifecycle phase.
92
+
93
+ ## Runtime events
94
+
95
+ With `emitEvents` (the default), the runtime publishes on the event bus.
96
+ Subscribe with `bus.on(type, handler)`; the payload types are in
97
+ `RuntimeEventMap`.
98
+
99
+ | Event | Payload |
100
+ | --- | --- |
101
+ | `runtime.initializing`, `runtime.running`, `runtime.stopping`, `runtime.stopped` | `RuntimeEventPayload` |
102
+ | `runtime.failed` | `RuntimeFailureEventPayload` |
103
+ | `runtime.module.initializing` / `initialized` / `starting` / `started` / `stopping` / `stopped` / `failed` | `RuntimeModuleEventPayload` |
104
+ | `runtime.shutdown.drain`, `runtime.shutdown.complete` | `RuntimeEventPayload` |
105
+ | `runtime.health.changed` | `RuntimeHealthEventPayload` |
106
+ | `runtime.readiness.changed` | `RuntimeReadinessEventPayload` |
107
+
108
+ ```typescript
109
+ bus.on("runtime.module.failed", (event) => {
110
+ const { moduleId, moduleName, error, durationMs } = event.payload;
111
+ alert(`${moduleName} (${moduleId}) failed after ${durationMs}ms`, error);
112
+ });
113
+ ```
114
+
115
+ Every `runtime.module.*` event names the module it is about. A listener
116
+ that throws is logged and contained; it never fails the lifecycle phase
117
+ that produced the event.
118
+
119
+ ## Options
120
+
121
+ ```typescript
122
+ createRuntime(dependencies, {
123
+ environment: "production", // required
124
+ applicationName: "my-app", // required
125
+ applicationVersion: "1.4.0",
126
+ runtimeId: "rt_custom", // generated when omitted
127
+ handleSignals: true, // SIGTERM/SIGINT trigger a graceful stop
128
+ handleFatalErrors: true, // uncaughtException/unhandledRejection
129
+ startupTimeout: 60_000,
130
+ shutdownTimeout: 30_000,
131
+ emitEvents: true,
132
+ trackReadiness: true,
133
+ trackHealth: true,
134
+ readinessCheckTimeout: 5_000, // 0 removes the bound
135
+ parallelInitialization: false, // initialize each depth group at once
136
+ metadata: { region: "eu-west-1" },
137
+ });
138
+ ```
139
+
140
+ `parallelInitialization` initializes modules that share a dependency depth
141
+ concurrently. They do not depend on one another by construction, but
142
+ enabling it surfaces any ordering a module assumed without declaring, so
143
+ it is opt-in.
144
+
24
145
  ## Features
25
146
 
26
- - Service dependency ordering
147
+ - Module dependency ordering
27
148
  - Graceful shutdown with rollback
28
149
  - Signal handling (SIGINT, SIGTERM)
29
- - Readiness and health checks
30
- - Lifecycle hooks (onStart, onStop, onReady)
150
+ - Readiness checks and derived health
151
+ - Lifecycle hooks (onInitialize, onReady, onShutdown, onDestroy)
31
152
 
32
153
  ## Use Cases
33
154
 
@@ -1,18 +1,24 @@
1
- import type { DependencyGraph, DependencyResolutionResult, ParallelModuleGroup } from "./dependencyGraph.type.js";
1
+ import type { DependencyGraph, DependencyResolutionResult } from "./dependencyGraph.type.js";
2
2
  /**
3
3
  * Builds a dependency graph from module IDs and their dependencies.
4
4
  */
5
5
  export declare function buildDependencyGraph(modules: ReadonlyMap<string, readonly string[]>): DependencyGraph;
6
6
  /**
7
7
  * Resolves module dependencies into an initialization order.
8
+ *
9
+ * Missing dependencies are rejected before ordering. Previously an
10
+ * unregistered dependency contributed depth `0` and was silently
11
+ * dropped, so a typo in a module's `dependencies` degraded into an
12
+ * unordered start that failed later inside `onInitialize`.
8
13
  */
9
14
  export declare function resolveDependencies(modules: ReadonlyMap<string, readonly string[]>): DependencyResolutionResult;
10
- /**
11
- * Returns parallel module groups for concurrent initialization.
12
- */
13
- export declare function getParallelGroups(modules: ReadonlyMap<string, readonly string[]>): readonly ParallelModuleGroup[];
14
15
  /**
15
16
  * Validates that all module dependencies exist.
17
+ *
18
+ * @throws {RuntimeDependencyError} naming both the module and the
19
+ * dependency it declared. Reporting a missing dependency as a circular
20
+ * one, as this previously did, sends the reader looking for a cycle that
21
+ * does not exist.
16
22
  */
17
23
  export declare function validateDependencies(modules: ReadonlyMap<string, readonly string[]>): void;
18
24
  //# sourceMappingURL=dependencyGraph.core.d.ts.map
@@ -1,4 +1,4 @@
1
- import { RuntimeCircularDependencyError } from "../runtimeError/runtimeError.base.js";
1
+ import { RuntimeCircularDependencyError, RuntimeDependencyError, } from "../runtimeError/runtimeError.base.js";
2
2
  /**
3
3
  * Builds a dependency graph from module IDs and their dependencies.
4
4
  */
@@ -76,8 +76,14 @@ export function buildDependencyGraph(modules) {
76
76
  }
77
77
  /**
78
78
  * Resolves module dependencies into an initialization order.
79
+ *
80
+ * Missing dependencies are rejected before ordering. Previously an
81
+ * unregistered dependency contributed depth `0` and was silently
82
+ * dropped, so a typo in a module's `dependencies` degraded into an
83
+ * unordered start that failed later inside `onInitialize`.
79
84
  */
80
85
  export function resolveDependencies(modules) {
86
+ validateDependencies(modules);
81
87
  const graph = buildDependencyGraph(modules);
82
88
  if (graph.hasCircularDependency) {
83
89
  throw new RuntimeCircularDependencyError(graph.circularDependencies[0] ?? []);
@@ -99,24 +105,19 @@ export function resolveDependencies(modules) {
99
105
  circularDependencies: [],
100
106
  });
101
107
  }
102
- /**
103
- * Returns parallel module groups for concurrent initialization.
104
- */
105
- export function getParallelGroups(modules) {
106
- const result = resolveDependencies(modules);
107
- return result.parallelGroups.map((group, index) => Object.freeze({
108
- modules: group,
109
- depth: index,
110
- }));
111
- }
112
108
  /**
113
109
  * Validates that all module dependencies exist.
110
+ *
111
+ * @throws {RuntimeDependencyError} naming both the module and the
112
+ * dependency it declared. Reporting a missing dependency as a circular
113
+ * one, as this previously did, sends the reader looking for a cycle that
114
+ * does not exist.
114
115
  */
115
116
  export function validateDependencies(modules) {
116
117
  for (const [moduleId, deps] of modules) {
117
118
  for (const depId of deps) {
118
119
  if (!modules.has(depId)) {
119
- throw new RuntimeCircularDependencyError([moduleId, depId]);
120
+ throw new RuntimeDependencyError(moduleId, depId);
120
121
  }
121
122
  }
122
123
  }
@@ -25,13 +25,6 @@ export interface DependencyResolutionResult {
25
25
  readonly hasCircularDependency: boolean;
26
26
  readonly circularDependencies: readonly (readonly string[])[];
27
27
  }
28
- /**
29
- * A group of modules that can be initialized concurrently.
30
- */
31
- export interface ParallelModuleGroup {
32
- readonly modules: readonly string[];
33
- readonly depth: number;
34
- }
35
28
  /**
36
29
  * Error information for circular dependencies.
37
30
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Module dependency graph and resolution.
3
3
  */
4
- export { buildDependencyGraph, resolveDependencies, getParallelGroups, validateDependencies, } from "./dependencyGraph.core.js";
5
- export type { DependencyNode, DependencyGraph, DependencyResolutionResult, ParallelModuleGroup, CircularDependencyInfo, } from "./dependencyGraph.type.js";
4
+ export { buildDependencyGraph, resolveDependencies, validateDependencies, } from "./dependencyGraph.core.js";
5
+ export type { DependencyNode, DependencyGraph, DependencyResolutionResult, CircularDependencyInfo, } from "./dependencyGraph.type.js";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Module dependency graph and resolution.
3
3
  */
4
- export { buildDependencyGraph, resolveDependencies, getParallelGroups, validateDependencies, } from "./dependencyGraph.core.js";
4
+ export { buildDependencyGraph, resolveDependencies, validateDependencies, } from "./dependencyGraph.core.js";
5
5
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ import type { RuntimeHealth, RuntimeState } from "../runtimeState/runtimeState.type.js";
2
+ import type { ReadinessTrackerState } from "../readiness/readiness.type.js";
3
+ /**
4
+ * Computes runtime health from the lifecycle state and readiness checks.
5
+ *
6
+ * A running runtime is `healthy` when every readiness check passes (a
7
+ * runtime with no checks registered counts as healthy) and `degraded`
8
+ * when at least one check is failing. Every other lifecycle state maps
9
+ * directly onto a health state.
10
+ */
11
+ export declare function computeRuntimeHealth(state: RuntimeState, readiness: ReadinessTrackerState): RuntimeHealth;
12
+ //# sourceMappingURL=health.core.d.ts.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Maps the runtime lifecycle state onto a health state, for the states
3
+ * where health is determined by the lifecycle alone.
4
+ *
5
+ * Returns `undefined` while the runtime is running, because health then
6
+ * depends on the readiness checks rather than on the state.
7
+ */
8
+ function healthStateFor(state) {
9
+ switch (state) {
10
+ case "created":
11
+ case "stopped":
12
+ return "unknown";
13
+ case "initializing":
14
+ case "initialized":
15
+ case "starting":
16
+ return "starting";
17
+ case "stopping":
18
+ return "stopping";
19
+ case "failed":
20
+ return "unhealthy";
21
+ case "running":
22
+ return undefined;
23
+ }
24
+ }
25
+ /**
26
+ * Converts readiness checks into health checks.
27
+ */
28
+ function toHealthChecks(readiness) {
29
+ return Object.freeze([...readiness.checks.values()].map((check) => Object.freeze({
30
+ name: check.name,
31
+ healthy: check.ready,
32
+ durationMs: check.durationMs,
33
+ ...(check.message !== undefined && { message: check.message }),
34
+ })));
35
+ }
36
+ /**
37
+ * Computes runtime health from the lifecycle state and readiness checks.
38
+ *
39
+ * A running runtime is `healthy` when every readiness check passes (a
40
+ * runtime with no checks registered counts as healthy) and `degraded`
41
+ * when at least one check is failing. Every other lifecycle state maps
42
+ * directly onto a health state.
43
+ */
44
+ export function computeRuntimeHealth(state, readiness) {
45
+ const checks = toHealthChecks(readiness);
46
+ const lifecycleState = healthStateFor(state);
47
+ const healthState = lifecycleState ??
48
+ (checks.every((check) => check.healthy) ? "healthy" : "degraded");
49
+ return Object.freeze({
50
+ state: healthState,
51
+ checks,
52
+ timestamp: new Date(),
53
+ });
54
+ }
55
+ //# sourceMappingURL=health.core.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Runtime health computation.
3
+ */
4
+ export { computeRuntimeHealth } from "./health.core.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Runtime health computation.
3
+ */
4
+ export { computeRuntimeHealth } from "./health.core.js";
5
+ //# sourceMappingURL=index.js.map
package/dist/index.d.ts CHANGED
@@ -18,11 +18,11 @@ export * from "./runtimeEvents/index.js";
18
18
  export * from "./runtimeContext/index.js";
19
19
  export * from "./dependencyGraph/index.js";
20
20
  export * from "./readiness/index.js";
21
+ export * from "./health/index.js";
21
22
  export * from "./lifecycle/index.js";
22
23
  export * from "./startup/index.js";
23
24
  export * from "./shutdown/index.js";
24
25
  export * from "./signalHandler/index.js";
25
26
  export * from "./runtimeError/index.js";
26
27
  export * from "./registry/index.js";
27
- export * from "./testRuntime/index.js";
28
28
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -17,11 +17,14 @@ export * from "./runtimeEvents/index.js";
17
17
  export * from "./runtimeContext/index.js";
18
18
  export * from "./dependencyGraph/index.js";
19
19
  export * from "./readiness/index.js";
20
+ export * from "./health/index.js";
20
21
  export * from "./lifecycle/index.js";
21
22
  export * from "./startup/index.js";
22
23
  export * from "./shutdown/index.js";
23
24
  export * from "./signalHandler/index.js";
24
25
  export * from "./runtimeError/index.js";
25
26
  export * from "./registry/index.js";
26
- export * from "./testRuntime/index.js";
27
+ // `testRuntime` is intentionally NOT exported from the package root: it
28
+ // is a testing helper, and re-exporting it here put a test-only module
29
+ // on the main entry point. Import it from "@zudojs/runtime/testing".
27
30
  //# sourceMappingURL=index.js.map
@@ -2,5 +2,5 @@
2
2
  * Module lifecycle management.
3
3
  */
4
4
  export { LifecycleManager } from "./lifecycle.core.js";
5
- export type { LifecyclePhase, LifecycleResult, LifecycleFailure, LifecycleContext, ManagedModule, LifecycleManagerOptions, } from "./lifecycle.type.js";
5
+ export type { LifecyclePhase, LifecycleResult, LifecycleFailure, LifecycleContext, ManagedModule, LifecycleManagerOptions, ModuleContextServices, ModuleEventListener, } from "./lifecycle.type.js";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,24 +1,41 @@
1
1
  import type { Logger } from "@zudojs/logger";
2
- import type { Container } from "@zudojs/container";
3
2
  import type { Module } from "@zudojs/core";
4
- import type { LifecycleResult, LifecycleManagerOptions } from "./lifecycle.type.js";
3
+ import type { LifecycleResult, LifecycleFailure, LifecycleManagerOptions, ModuleContextServices } from "./lifecycle.type.js";
5
4
  /**
6
5
  * Manages the lifecycle of runtime modules.
7
6
  */
8
7
  export declare class LifecycleManager {
9
8
  private readonly modules;
10
9
  private readonly logger;
11
- private readonly container;
12
- private readonly runtimeId;
13
- private readonly environment;
14
10
  private readonly options;
15
- private readonly initializedModules;
16
- private readonly startedModules;
17
- constructor(modules: ReadonlyMap<string, Module>, logger: Logger, container: Container, runtimeId: string, environment: string, options?: LifecycleManagerOptions);
11
+ private readonly onModuleEvent;
12
+ private readonly runtimeId;
13
+ private initializedModules;
14
+ private startedModules;
15
+ private readonly configuration;
16
+ private readonly application;
17
+ private readonly contexts;
18
+ constructor(modules: ReadonlyMap<string, Module>, logger: Logger, options?: LifecycleManagerOptions, services?: ModuleContextServices);
19
+ /**
20
+ * Publishes a per-module lifecycle event.
21
+ *
22
+ * A throwing listener must not fail the phase that produced the event,
23
+ * so delivery failures are contained here.
24
+ */
25
+ private emitModuleEvent;
26
+ /**
27
+ * Loads the configuration manager once, before modules are initialized,
28
+ * so that `context.getConfiguration()` is usable from the first hook.
29
+ */
30
+ private ensureConfigurationReady;
18
31
  /**
19
32
  * Initializes all modules in dependency order.
20
33
  */
21
34
  initialize(): Promise<LifecycleResult>;
35
+ /**
36
+ * Initializes a single module, converting a throw into a failure.
37
+ */
38
+ private initializeModule;
22
39
  /**
23
40
  * Starts all modules in dependency order.
24
41
  */
@@ -32,9 +49,15 @@ export declare class LifecycleManager {
32
49
  */
33
50
  destroy(): Promise<LifecycleResult>;
34
51
  /**
35
- * Rolls back initialization for modules that were started.
52
+ * Rolls back a failed startup.
53
+ *
54
+ * Started modules are shut down, and every module that reached
55
+ * `onInitialize` is then destroyed — including those that never
56
+ * started because an earlier module failed. Rolling back only the
57
+ * started ones leaves everything they had already acquired behind with
58
+ * no route to release it.
36
59
  */
37
- rollback(): Promise<void>;
60
+ rollback(): Promise<readonly LifecycleFailure[]>;
38
61
  /**
39
62
  * Creates a module context for lifecycle hooks.
40
63
  */
@@ -42,6 +65,14 @@ export declare class LifecycleManager {
42
65
  /**
43
66
  * Builds a dependency graph from registered modules.
44
67
  */
68
+ /**
69
+ * Modules that reached `onInitialize`, in initialization order.
70
+ */
71
+ getInitializedModules(): readonly string[];
72
+ /**
73
+ * Modules that reached `onReady`, in start order.
74
+ */
75
+ getStartedModules(): readonly string[];
45
76
  private buildModuleDependencyGraph;
46
77
  }
47
78
  //# sourceMappingURL=lifecycle.core.d.ts.map