@zudojs/plugins 1.3.2 → 1.4.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.
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/pluginDependencies/dependencyResolver.core.d.ts +0 -1
- package/dist/pluginDependencies/dependencyResolver.core.js +0 -1
- package/dist/pluginDependencies/index.d.ts +0 -1
- package/dist/pluginDependencies/index.js +0 -1
- package/dist/pluginDependencies/versionCheck.core.d.ts +0 -1
- package/dist/pluginDependencies/versionCheck.core.js +0 -1
- package/dist/pluginDiagnostics/index.d.ts +1 -2
- package/dist/pluginDiagnostics/index.js +1 -2
- package/dist/pluginDiagnostics/pluginDiagnostic.core.d.ts +4 -24
- package/dist/pluginDiagnostics/pluginDiagnostic.core.js +3 -24
- package/dist/pluginDiagnostics/pluginDiagnostic.health.d.ts +32 -0
- package/dist/pluginDiagnostics/pluginDiagnostic.health.js +65 -0
- package/dist/pluginEvents/index.d.ts +0 -1
- package/dist/pluginEvents/index.js +0 -1
- package/dist/pluginEvents/pluginEvent.bus.d.ts +0 -1
- package/dist/pluginEvents/pluginEvent.bus.js +0 -1
- package/dist/pluginEvents/pluginEvent.core.d.ts +0 -1
- package/dist/pluginEvents/pluginEvent.core.js +0 -1
- package/dist/pluginEvents/pluginEvent.deliver.d.ts +0 -1
- package/dist/pluginEvents/pluginEvent.deliver.js +0 -1
- package/dist/pluginIntegration/index.d.ts +0 -1
- package/dist/pluginIntegration/index.js +0 -1
- package/dist/pluginIntegration/pluginContext.core.d.ts +6 -1
- package/dist/pluginIntegration/pluginContext.core.js +1 -1
- package/dist/pluginLifecycle/pluginLifecycle.abandoned.d.ts +0 -1
- package/dist/pluginLifecycle/pluginLifecycle.abandoned.js +0 -1
- package/dist/pluginLifecycle/pluginLifecycle.core.d.ts +5 -1
- package/dist/pluginLifecycle/pluginLifecycle.core.js +9 -3
- package/dist/pluginLifecycle/pluginLifecycle.phaseError.d.ts +21 -0
- package/dist/pluginLifecycle/pluginLifecycle.phaseError.js +43 -0
- package/dist/pluginLifecycle/pluginLifecycle.report.d.ts +0 -1
- package/dist/pluginLifecycle/pluginLifecycle.report.js +0 -1
- package/dist/pluginManager/pluginManager.core.d.ts +6 -2
- package/dist/pluginManager/pluginManager.core.js +9 -1
- package/dist/pluginRegistry/index.d.ts +0 -1
- package/dist/pluginRegistry/index.js +0 -1
- package/dist/pluginRegistry/pluginRegistry.core.d.ts +0 -1
- package/dist/pluginRegistry/pluginRegistry.core.js +0 -1
- package/dist/pluginTypes/index.d.ts +1 -1
- package/dist/pluginTypes/index.js +0 -1
- package/dist/pluginTypes/plugin.type.d.ts +19 -1
- package/dist/pluginTypes/plugin.type.js +0 -1
- package/dist/pluginTypes/pluginContext.type.d.ts +13 -1
- package/dist/pluginTypes/pluginContext.type.js +0 -1
- package/dist/pluginTypes/pluginDependency.type.d.ts +0 -1
- package/dist/pluginTypes/pluginDependency.type.js +0 -1
- package/dist/pluginTypes/pluginMetadata.type.d.ts +0 -1
- package/dist/pluginTypes/pluginMetadata.type.js +0 -1
- package/dist/pluginTypes/pluginState.type.d.ts +0 -1
- package/dist/pluginTypes/pluginState.type.js +0 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -56,11 +56,10 @@ export type { LifecycleControllerOptions } from "./pluginLifecycle/pluginLifecyc
|
|
|
56
56
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvents/pluginEvent.core.js";
|
|
57
57
|
export type { PluginLifecycleEvent } from "./pluginEvents/pluginEvent.core.js";
|
|
58
58
|
export { isPluginEventBus, toPluginEvents, } from "./pluginEvents/pluginEvent.bus.js";
|
|
59
|
-
export { buildDiagnosticReport, createHealthyHealth, createDegradedHealth, createUnhealthyHealth, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
59
|
+
export { buildDiagnosticReport, resolvePluginHealth, createHealthyHealth, createDegradedHealth, createUnhealthyHealth, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
60
60
|
export type { PluginHealth, PluginHealthStatus, PluginDiagnostic, PluginDiagnosticReport, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
61
61
|
export { isValidTransition, VALID_STATE_TRANSITIONS, } from "./pluginTypes/pluginState.type.js";
|
|
62
62
|
export { createPluginContext, createOwnedPluginContext, } from "./pluginIntegration/pluginContext.core.js";
|
|
63
63
|
export type { CreatePluginContextOptions, OwnedPluginContext, } from "./pluginIntegration/pluginContext.core.js";
|
|
64
64
|
export { PluginError, PluginRegistrationError, PluginAlreadyRegisteredError, PluginNotFoundError, PluginDependencyError, PluginDependencyCycleError, PluginInitializationError, PluginStartError, PluginStopError, PluginDisposeError, PluginTimeoutError, PluginStateError, createPluginError, isPluginError, } from "@zudojs/errors";
|
|
65
65
|
export type { PluginState, PluginMetadata, PluginDependency, PluginContext, PluginContainer, PluginConfig, PluginLogger, PluginEvents, PluginEventBus, PluginEventSource, PluginDisposable, Plugin, PluginErrorOptions, } from "./pluginTypes/index.js";
|
|
66
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -50,8 +50,7 @@ export { PluginDependencyVersionError } from "./pluginDependencies/versionCheck.
|
|
|
50
50
|
export { LifecycleController } from "./pluginLifecycle/pluginLifecycle.core.js";
|
|
51
51
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvents/pluginEvent.core.js";
|
|
52
52
|
export { isPluginEventBus, toPluginEvents, } from "./pluginEvents/pluginEvent.bus.js";
|
|
53
|
-
export { buildDiagnosticReport, createHealthyHealth, createDegradedHealth, createUnhealthyHealth, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
53
|
+
export { buildDiagnosticReport, resolvePluginHealth, createHealthyHealth, createDegradedHealth, createUnhealthyHealth, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
54
54
|
export { isValidTransition, VALID_STATE_TRANSITIONS, } from "./pluginTypes/pluginState.type.js";
|
|
55
55
|
export { createPluginContext, createOwnedPluginContext, } from "./pluginIntegration/pluginContext.core.js";
|
|
56
56
|
export { PluginError, PluginRegistrationError, PluginAlreadyRegisteredError, PluginNotFoundError, PluginDependencyError, PluginDependencyCycleError, PluginInitializationError, PluginStartError, PluginStopError, PluginDisposeError, PluginTimeoutError, PluginStateError, createPluginError, isPluginError, } from "@zudojs/errors";
|
|
57
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -9,4 +9,3 @@ export { DependencyResolver, assertResolutionValid, } from "./dependencyResolver
|
|
|
9
9
|
export type { SemVer } from "./versionCheck.core.js";
|
|
10
10
|
export { PluginDependencyVersionError } from "./versionCheck.core.js";
|
|
11
11
|
export { parseVersion, compareVersions, satisfiesVersion, assertDependencyVersions, } from "./versionCheck.core.js";
|
|
12
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -7,4 +7,3 @@
|
|
|
7
7
|
export { DependencyResolver, assertResolutionValid, } from "./dependencyResolver.core.js";
|
|
8
8
|
export { PluginDependencyVersionError } from "./versionCheck.core.js";
|
|
9
9
|
export { parseVersion, compareVersions, satisfiesVersion, assertDependencyVersions, } from "./versionCheck.core.js";
|
|
10
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -64,4 +64,3 @@ export declare function satisfiesVersion(version: string, range: string): boolea
|
|
|
64
64
|
* @throws {PluginDependencyError} on the first unsatisfied constraint.
|
|
65
65
|
*/
|
|
66
66
|
export declare function assertDependencyVersions(plugins: ReadonlyMap<string, Plugin>): void;
|
|
67
|
-
//# sourceMappingURL=versionCheck.core.d.ts.map
|
|
@@ -4,5 +4,4 @@
|
|
|
4
4
|
* Plugin health checks and diagnostic reporting.
|
|
5
5
|
*/
|
|
6
6
|
export type { PluginHealthStatus, PluginHealth, PluginDiagnostic, PluginDiagnosticReport, } from "./pluginDiagnostic.core.js";
|
|
7
|
-
export { createHealthyHealth, createDegradedHealth, createUnhealthyHealth, buildDiagnosticReport, } from "./pluginDiagnostic.core.js";
|
|
8
|
-
//# sourceMappingURL=index.d.ts.map
|
|
7
|
+
export { createHealthyHealth, createDegradedHealth, createUnhealthyHealth, buildDiagnosticReport, resolvePluginHealth, } from "./pluginDiagnostic.core.js";
|
|
@@ -3,5 +3,4 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Plugin health checks and diagnostic reporting.
|
|
5
5
|
*/
|
|
6
|
-
export { createHealthyHealth, createDegradedHealth, createUnhealthyHealth, buildDiagnosticReport, } from "./pluginDiagnostic.core.js";
|
|
7
|
-
//# sourceMappingURL=index.js.map
|
|
6
|
+
export { createHealthyHealth, createDegradedHealth, createUnhealthyHealth, buildDiagnosticReport, resolvePluginHealth, } from "./pluginDiagnostic.core.js";
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import type { Plugin } from "../pluginTypes/plugin.type.js";
|
|
2
|
+
import type { PluginHealth, PluginHealthStatus } from "../pluginTypes/plugin.type.js";
|
|
2
3
|
import type { PluginMetadata } from "../pluginTypes/pluginMetadata.type.js";
|
|
3
4
|
import type { PluginState } from "../pluginTypes/pluginState.type.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type PluginHealthStatus = "healthy" | "degraded" | "unhealthy";
|
|
8
|
-
/**
|
|
9
|
-
* Plugin health information.
|
|
10
|
-
*/
|
|
11
|
-
export interface PluginHealth {
|
|
12
|
-
readonly status: PluginHealthStatus;
|
|
13
|
-
readonly details?: unknown;
|
|
14
|
-
}
|
|
5
|
+
import { createDegradedHealth, createHealthyHealth, createUnhealthyHealth, resolvePluginHealth } from "./pluginDiagnostic.health.js";
|
|
6
|
+
export type { PluginHealth, PluginHealthStatus };
|
|
7
|
+
export { createDegradedHealth, createHealthyHealth, createUnhealthyHealth, resolvePluginHealth, };
|
|
15
8
|
/**
|
|
16
9
|
* Individual plugin diagnostic information.
|
|
17
10
|
*/
|
|
@@ -35,18 +28,6 @@ export interface PluginDiagnosticReport {
|
|
|
35
28
|
readonly unhealthy: number;
|
|
36
29
|
readonly failed: number;
|
|
37
30
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Creates a default healthy status for a plugin.
|
|
40
|
-
*/
|
|
41
|
-
export declare function createHealthyHealth(): PluginHealth;
|
|
42
|
-
/**
|
|
43
|
-
* Creates a degraded health status for a plugin.
|
|
44
|
-
*/
|
|
45
|
-
export declare function createDegradedHealth(details?: unknown): PluginHealth;
|
|
46
|
-
/**
|
|
47
|
-
* Creates an unhealthy health status for a plugin.
|
|
48
|
-
*/
|
|
49
|
-
export declare function createUnhealthyHealth(details?: unknown): PluginHealth;
|
|
50
31
|
/**
|
|
51
32
|
* Builds a diagnostic report from registered plugins.
|
|
52
33
|
*/
|
|
@@ -61,4 +42,3 @@ export declare function buildDiagnosticReport(plugins: Array<{
|
|
|
61
42
|
readonly failed?: boolean;
|
|
62
43
|
readonly error?: unknown;
|
|
63
44
|
}>): PluginDiagnosticReport;
|
|
64
|
-
//# sourceMappingURL=pluginDiagnostic.core.d.ts.map
|
|
@@ -1,21 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
export function createHealthyHealth() {
|
|
5
|
-
return { status: "healthy" };
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Creates a degraded health status for a plugin.
|
|
9
|
-
*/
|
|
10
|
-
export function createDegradedHealth(details) {
|
|
11
|
-
return { status: "degraded", ...(details !== undefined ? { details } : {}) };
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Creates an unhealthy health status for a plugin.
|
|
15
|
-
*/
|
|
16
|
-
export function createUnhealthyHealth(details) {
|
|
17
|
-
return { status: "unhealthy", ...(details !== undefined ? { details } : {}) };
|
|
18
|
-
}
|
|
1
|
+
import { createDegradedHealth, createHealthyHealth, createUnhealthyHealth, resolvePluginHealth, } from "./pluginDiagnostic.health.js";
|
|
2
|
+
export { createDegradedHealth, createHealthyHealth, createUnhealthyHealth, resolvePluginHealth, };
|
|
19
3
|
/**
|
|
20
4
|
* Builds a diagnostic report from registered plugins.
|
|
21
5
|
*/
|
|
@@ -26,11 +10,7 @@ export function buildDiagnosticReport(plugins) {
|
|
|
26
10
|
plugin: plugin.metadata,
|
|
27
11
|
state,
|
|
28
12
|
failed: hasFailed,
|
|
29
|
-
health: hasFailed
|
|
30
|
-
? createUnhealthyHealth(error instanceof Error ? error.message : error)
|
|
31
|
-
: state === "started"
|
|
32
|
-
? createHealthyHealth()
|
|
33
|
-
: createDegradedHealth(),
|
|
13
|
+
health: resolvePluginHealth(plugin, state, hasFailed, error),
|
|
34
14
|
dependencies: plugin.dependencies?.map((d) => d.name) ?? [],
|
|
35
15
|
optionalDependencies: plugin.optionalDependencies?.map((d) => d.name) ?? [],
|
|
36
16
|
};
|
|
@@ -48,4 +28,3 @@ export function buildDiagnosticReport(plugins) {
|
|
|
48
28
|
failed,
|
|
49
29
|
};
|
|
50
30
|
}
|
|
51
|
-
//# sourceMappingURL=pluginDiagnostic.core.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health resolution for one plugin, from its lifecycle state and its own
|
|
3
|
+
* `health()` hook.
|
|
4
|
+
*
|
|
5
|
+
* @module pluginDiagnostics/pluginDiagnostic.health
|
|
6
|
+
*/
|
|
7
|
+
import type { Plugin } from "../pluginTypes/plugin.type.js";
|
|
8
|
+
import type { PluginHealth } from "../pluginTypes/plugin.type.js";
|
|
9
|
+
import type { PluginState } from "../pluginTypes/pluginState.type.js";
|
|
10
|
+
/**
|
|
11
|
+
* Creates a default healthy status for a plugin.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createHealthyHealth(): PluginHealth;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a degraded health status for a plugin.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createDegradedHealth(details?: unknown): PluginHealth;
|
|
18
|
+
/**
|
|
19
|
+
* Creates an unhealthy health status for a plugin.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createUnhealthyHealth(details?: unknown): PluginHealth;
|
|
22
|
+
/**
|
|
23
|
+
* Health of one plugin.
|
|
24
|
+
*
|
|
25
|
+
* A failed plugin is `unhealthy`. A started plugin answers with its own
|
|
26
|
+
* `health()` when it has one (a throwing `health()` is `unhealthy`), else
|
|
27
|
+
* `healthy`. A plugin part-way through boot or a transition is `degraded`.
|
|
28
|
+
* A plugin that is idle — `registered`, or cleanly `stopped` or `disposed`
|
|
29
|
+
* — is `healthy`: before this rule every plugin read `degraded` after a
|
|
30
|
+
* clean `stop()`, which made the report useless during shutdown.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolvePluginHealth(plugin: Plugin, state: PluginState, failed: boolean, error?: unknown): PluginHealth;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health resolution for one plugin, from its lifecycle state and its own
|
|
3
|
+
* `health()` hook.
|
|
4
|
+
*
|
|
5
|
+
* @module pluginDiagnostics/pluginDiagnostic.health
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* States in which a plugin is between two settled states, or brought
|
|
9
|
+
* part-way up by a `start()` that has not finished.
|
|
10
|
+
*/
|
|
11
|
+
const IN_PROGRESS_STATES = new Set([
|
|
12
|
+
"installing",
|
|
13
|
+
"installed",
|
|
14
|
+
"initializing",
|
|
15
|
+
"initialized",
|
|
16
|
+
"starting",
|
|
17
|
+
"stopping",
|
|
18
|
+
"disposing",
|
|
19
|
+
]);
|
|
20
|
+
/**
|
|
21
|
+
* Creates a default healthy status for a plugin.
|
|
22
|
+
*/
|
|
23
|
+
export function createHealthyHealth() {
|
|
24
|
+
return { status: "healthy" };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates a degraded health status for a plugin.
|
|
28
|
+
*/
|
|
29
|
+
export function createDegradedHealth(details) {
|
|
30
|
+
return { status: "degraded", ...(details !== undefined ? { details } : {}) };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates an unhealthy health status for a plugin.
|
|
34
|
+
*/
|
|
35
|
+
export function createUnhealthyHealth(details) {
|
|
36
|
+
return { status: "unhealthy", ...(details !== undefined ? { details } : {}) };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Health of one plugin.
|
|
40
|
+
*
|
|
41
|
+
* A failed plugin is `unhealthy`. A started plugin answers with its own
|
|
42
|
+
* `health()` when it has one (a throwing `health()` is `unhealthy`), else
|
|
43
|
+
* `healthy`. A plugin part-way through boot or a transition is `degraded`.
|
|
44
|
+
* A plugin that is idle — `registered`, or cleanly `stopped` or `disposed`
|
|
45
|
+
* — is `healthy`: before this rule every plugin read `degraded` after a
|
|
46
|
+
* clean `stop()`, which made the report useless during shutdown.
|
|
47
|
+
*/
|
|
48
|
+
export function resolvePluginHealth(plugin, state, failed, error) {
|
|
49
|
+
if (failed) {
|
|
50
|
+
return createUnhealthyHealth(error instanceof Error ? error.message : error);
|
|
51
|
+
}
|
|
52
|
+
if (state === "started") {
|
|
53
|
+
if (typeof plugin.health !== "function")
|
|
54
|
+
return createHealthyHealth();
|
|
55
|
+
try {
|
|
56
|
+
return plugin.health();
|
|
57
|
+
}
|
|
58
|
+
catch (cause) {
|
|
59
|
+
return createUnhealthyHealth(cause instanceof Error ? cause.message : cause);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return IN_PROGRESS_STATES.has(state)
|
|
63
|
+
? createDegradedHealth({ state })
|
|
64
|
+
: createHealthyHealth();
|
|
65
|
+
}
|
|
@@ -7,4 +7,3 @@ export type { PluginLifecycleEvent } from "./pluginEvent.core.js";
|
|
|
7
7
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvent.core.js";
|
|
8
8
|
export { isPluginEventBus, toPluginEvents } from "./pluginEvent.bus.js";
|
|
9
9
|
export { deliverPluginEvent } from "./pluginEvent.deliver.js";
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -31,4 +31,3 @@ export declare const PLUGIN_EVENTS: {
|
|
|
31
31
|
* Creates a plugin lifecycle event.
|
|
32
32
|
*/
|
|
33
33
|
export declare function createPluginLifecycleEvent(plugin: PluginMetadata, state: PluginState, previousState?: PluginState, error?: unknown): PluginLifecycleEvent;
|
|
34
|
-
//# sourceMappingURL=pluginEvent.core.d.ts.map
|
|
@@ -15,4 +15,3 @@ import type { PluginEvents } from "../pluginTypes/pluginContext.type.js";
|
|
|
15
15
|
* @param onFailure - Receives a synchronous throw or an async rejection.
|
|
16
16
|
*/
|
|
17
17
|
export declare function deliverPluginEvent(events: PluginEvents, name: string, payload: unknown, onFailure: (error: unknown) => void): void;
|
|
18
|
-
//# sourceMappingURL=pluginEvent.deliver.d.ts.map
|
|
@@ -6,4 +6,3 @@
|
|
|
6
6
|
export type { CreatePluginContextOptions, OwnedPluginContext, } from "./pluginContext.core.js";
|
|
7
7
|
export { createPluginContext, createOwnedPluginContext, } from "./pluginContext.core.js";
|
|
8
8
|
export type { PluginContext } from "../pluginTypes/pluginContext.type.js";
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -24,6 +24,12 @@ export interface CreatePluginContextOptions {
|
|
|
24
24
|
* one it aborts on shutdown so plugins are told to stop.
|
|
25
25
|
*/
|
|
26
26
|
readonly abortController?: AbortController;
|
|
27
|
+
/**
|
|
28
|
+
* Metadata of the host application, exposed to the plugin as
|
|
29
|
+
* `context.host`. The manager fills it from the `plugin` metadata of
|
|
30
|
+
* the context passed to `start()`/`stop()`.
|
|
31
|
+
*/
|
|
32
|
+
readonly host?: PluginMetadata;
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
29
35
|
* A plugin context together with the handles needed to tear it down.
|
|
@@ -51,4 +57,3 @@ export declare function createOwnedPluginContext(plugin: PluginMetadata, options
|
|
|
51
57
|
* collection and the abort handle with the context.
|
|
52
58
|
*/
|
|
53
59
|
export declare function createPluginContext(plugin: PluginMetadata, options?: CreatePluginContextOptions): PluginContext;
|
|
54
|
-
//# sourceMappingURL=pluginContext.core.d.ts.map
|
|
@@ -11,6 +11,7 @@ export function createOwnedPluginContext(plugin, options = {}) {
|
|
|
11
11
|
const disposables = options.disposables ?? [];
|
|
12
12
|
const context = {
|
|
13
13
|
plugin,
|
|
14
|
+
...(options.host !== undefined ? { host: options.host } : {}),
|
|
14
15
|
signal: abortController.signal,
|
|
15
16
|
container: options.container,
|
|
16
17
|
config: options.config,
|
|
@@ -43,4 +44,3 @@ export function createOwnedPluginContext(plugin, options = {}) {
|
|
|
43
44
|
export function createPluginContext(plugin, options = {}) {
|
|
44
45
|
return createOwnedPluginContext(plugin, options).context;
|
|
45
46
|
}
|
|
46
|
-
//# sourceMappingURL=pluginContext.core.js.map
|
|
@@ -25,6 +25,11 @@ export declare class LifecycleController {
|
|
|
25
25
|
/**
|
|
26
26
|
* Runs a hook under the configured timeout, clearing the timer either
|
|
27
27
|
* way so a completed hook never leaves one armed.
|
|
28
|
+
*
|
|
29
|
+
* The timer is deliberately ref'd: it guards pending work, and an
|
|
30
|
+
* unref'd one let Node exit (code 13, "unsettled top-level await")
|
|
31
|
+
* when a `start()` hook hung before anything else held the event
|
|
32
|
+
* loop, so no `PluginTimeoutError` was raised and nothing rolled back.
|
|
28
33
|
*/
|
|
29
34
|
private runHook;
|
|
30
35
|
install<TPlugin extends Plugin>(registered: RegisteredPlugin<TPlugin>, context: PluginContext): Promise<void>;
|
|
@@ -63,4 +68,3 @@ export declare class LifecycleController {
|
|
|
63
68
|
private canTransition;
|
|
64
69
|
private ensureTransition;
|
|
65
70
|
}
|
|
66
|
-
//# sourceMappingURL=pluginLifecycle.core.d.ts.map
|
|
@@ -2,6 +2,7 @@ import { isValidTransition } from "../pluginTypes/pluginState.type.js";
|
|
|
2
2
|
import { PluginDisposeError, PluginStateError, PluginTimeoutError, } from "@zudojs/errors";
|
|
3
3
|
import { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "../pluginEvents/pluginEvent.core.js";
|
|
4
4
|
import { AbandonedHooks } from "./pluginLifecycle.abandoned.js";
|
|
5
|
+
import { toPhaseError } from "./pluginLifecycle.phaseError.js";
|
|
5
6
|
import { reportPluginFailure } from "./pluginLifecycle.report.js";
|
|
6
7
|
import { deliverPluginEvent } from "../pluginEvents/pluginEvent.deliver.js";
|
|
7
8
|
/**
|
|
@@ -36,6 +37,11 @@ export class LifecycleController {
|
|
|
36
37
|
/**
|
|
37
38
|
* Runs a hook under the configured timeout, clearing the timer either
|
|
38
39
|
* way so a completed hook never leaves one armed.
|
|
40
|
+
*
|
|
41
|
+
* The timer is deliberately ref'd: it guards pending work, and an
|
|
42
|
+
* unref'd one let Node exit (code 13, "unsettled top-level await")
|
|
43
|
+
* when a `start()` hook hung before anything else held the event
|
|
44
|
+
* loop, so no `PluginTimeoutError` was raised and nothing rolled back.
|
|
39
45
|
*/
|
|
40
46
|
async runHook(pluginName, phase, run, onAbandoned) {
|
|
41
47
|
const timeout = this.options.hookTimeout ?? 0;
|
|
@@ -58,7 +64,6 @@ export class LifecycleController {
|
|
|
58
64
|
metadata: { phase },
|
|
59
65
|
}));
|
|
60
66
|
}, Math.min(timeout, MAX_TIMER_DELAY));
|
|
61
|
-
timer.unref?.();
|
|
62
67
|
}),
|
|
63
68
|
]);
|
|
64
69
|
}
|
|
@@ -100,10 +105,12 @@ export class LifecycleController {
|
|
|
100
105
|
emitLifecycleEvent(context, endEvent, metadata, settled, transient);
|
|
101
106
|
}
|
|
102
107
|
catch (error) {
|
|
108
|
+
// Diagnostics and the `failed` event keep what the hook threw; the
|
|
109
|
+
// caller gets it wrapped in the phase's error, naming the plugin.
|
|
103
110
|
registered.setError(error);
|
|
104
111
|
this.transitionToFailed(registered);
|
|
105
112
|
emitLifecycleEvent(context, PLUGIN_EVENTS.FAILED, metadata, "failed", transient, error);
|
|
106
|
-
throw error;
|
|
113
|
+
throw toPhaseError(transient, metadata.name, error);
|
|
107
114
|
}
|
|
108
115
|
}
|
|
109
116
|
/**
|
|
@@ -218,4 +225,3 @@ export class LifecycleController {
|
|
|
218
225
|
}
|
|
219
226
|
}
|
|
220
227
|
}
|
|
221
|
-
//# sourceMappingURL=pluginLifecycle.core.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a lifecycle hook's failure in the typed error for its phase.
|
|
3
|
+
*
|
|
4
|
+
* `PluginInitializationError`, `PluginStartError` and `PluginStopError`
|
|
5
|
+
* were exported but never thrown: a hook's raw error was rethrown as-is,
|
|
6
|
+
* so nothing but `diagnostics()` said which plugin had failed. The wrap
|
|
7
|
+
* names the plugin and the phase and keeps the original as `cause`.
|
|
8
|
+
*
|
|
9
|
+
* @module pluginLifecycle/pluginLifecycle.phaseError
|
|
10
|
+
*/
|
|
11
|
+
import type { PluginState } from "../pluginTypes/pluginState.type.js";
|
|
12
|
+
/**
|
|
13
|
+
* Returns the error to throw for a hook that failed in `phase`.
|
|
14
|
+
*
|
|
15
|
+
* A `PluginError` — a `PluginTimeoutError`, `PluginStateError`, or a
|
|
16
|
+
* typed error a plugin threw on purpose — already names the plugin and
|
|
17
|
+
* lets callers branch on it, so it propagates unchanged. Anything else is
|
|
18
|
+
* wrapped in the phase's error class with the original as `cause`; the
|
|
19
|
+
* message quotes the original's so existing substring matches still hold.
|
|
20
|
+
*/
|
|
21
|
+
export declare function toPhaseError(phase: PluginState, pluginName: string, error: unknown): unknown;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a lifecycle hook's failure in the typed error for its phase.
|
|
3
|
+
*
|
|
4
|
+
* `PluginInitializationError`, `PluginStartError` and `PluginStopError`
|
|
5
|
+
* were exported but never thrown: a hook's raw error was rethrown as-is,
|
|
6
|
+
* so nothing but `diagnostics()` said which plugin had failed. The wrap
|
|
7
|
+
* names the plugin and the phase and keeps the original as `cause`.
|
|
8
|
+
*
|
|
9
|
+
* @module pluginLifecycle/pluginLifecycle.phaseError
|
|
10
|
+
*/
|
|
11
|
+
import { PluginError, PluginInitializationError, PluginStartError, PluginStopError, } from "@zudojs/errors";
|
|
12
|
+
/** The lifecycle-hook error class for each transient phase. */
|
|
13
|
+
const PHASE_ERRORS = {
|
|
14
|
+
installing: PluginInitializationError,
|
|
15
|
+
initializing: PluginInitializationError,
|
|
16
|
+
starting: PluginStartError,
|
|
17
|
+
stopping: PluginStopError,
|
|
18
|
+
};
|
|
19
|
+
/** The verb a phase's failure message uses. */
|
|
20
|
+
const PHASE_VERBS = {
|
|
21
|
+
installing: "install",
|
|
22
|
+
initializing: "initialize",
|
|
23
|
+
starting: "start",
|
|
24
|
+
stopping: "stop",
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Returns the error to throw for a hook that failed in `phase`.
|
|
28
|
+
*
|
|
29
|
+
* A `PluginError` — a `PluginTimeoutError`, `PluginStateError`, or a
|
|
30
|
+
* typed error a plugin threw on purpose — already names the plugin and
|
|
31
|
+
* lets callers branch on it, so it propagates unchanged. Anything else is
|
|
32
|
+
* wrapped in the phase's error class with the original as `cause`; the
|
|
33
|
+
* message quotes the original's so existing substring matches still hold.
|
|
34
|
+
*/
|
|
35
|
+
export function toPhaseError(phase, pluginName, error) {
|
|
36
|
+
if (error instanceof PluginError)
|
|
37
|
+
return error;
|
|
38
|
+
const PhaseError = PHASE_ERRORS[phase];
|
|
39
|
+
if (PhaseError === undefined)
|
|
40
|
+
return error;
|
|
41
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
42
|
+
return new PhaseError(`Plugin "${pluginName}" failed to ${PHASE_VERBS[phase]}: ${detail}`, pluginName, { cause: error });
|
|
43
|
+
}
|
|
@@ -13,4 +13,3 @@ import type { PluginLogger } from "../pluginTypes/pluginContext.type.js";
|
|
|
13
13
|
* @param fields - Extra structured context.
|
|
14
14
|
*/
|
|
15
15
|
export declare function reportPluginFailure(logger: PluginLogger | undefined, message: string, error: unknown, fields?: Record<string, unknown>): void;
|
|
16
|
-
//# sourceMappingURL=pluginLifecycle.report.d.ts.map
|
|
@@ -85,10 +85,15 @@ export declare class PluginManager {
|
|
|
85
85
|
/**
|
|
86
86
|
* Registers a plugin.
|
|
87
87
|
*
|
|
88
|
+
* `options` is typed from the plugin: for a `Plugin<TOptions>` (a
|
|
89
|
+
* plugin whose `install(context, options)` declares its options type)
|
|
90
|
+
* it must be a `TOptions`, so a mistyped options object is a compile
|
|
91
|
+
* error rather than a runtime surprise in `install`.
|
|
92
|
+
*
|
|
88
93
|
* @throws {PluginAlreadyRegisteredError} when the name is taken, so
|
|
89
94
|
* callers can implement idempotent registration.
|
|
90
95
|
*/
|
|
91
|
-
register<
|
|
96
|
+
register<TOptions = unknown>(plugin: Plugin<TOptions>, options?: TOptions): void;
|
|
92
97
|
/**
|
|
93
98
|
* Removes a plugin that has not been started.
|
|
94
99
|
*
|
|
@@ -151,4 +156,3 @@ export declare class PluginManager {
|
|
|
151
156
|
private report;
|
|
152
157
|
private toDependencyMap;
|
|
153
158
|
}
|
|
154
|
-
//# sourceMappingURL=pluginManager.core.d.ts.map
|
|
@@ -61,6 +61,11 @@ export class PluginManager {
|
|
|
61
61
|
/**
|
|
62
62
|
* Registers a plugin.
|
|
63
63
|
*
|
|
64
|
+
* `options` is typed from the plugin: for a `Plugin<TOptions>` (a
|
|
65
|
+
* plugin whose `install(context, options)` declares its options type)
|
|
66
|
+
* it must be a `TOptions`, so a mistyped options object is a compile
|
|
67
|
+
* error rather than a runtime surprise in `install`.
|
|
68
|
+
*
|
|
64
69
|
* @throws {PluginAlreadyRegisteredError} when the name is taken, so
|
|
65
70
|
* callers can implement idempotent registration.
|
|
66
71
|
*/
|
|
@@ -302,6 +307,10 @@ export class PluginManager {
|
|
|
302
307
|
logger: base.logger,
|
|
303
308
|
events: base.events,
|
|
304
309
|
disposables: registered.disposables,
|
|
310
|
+
// The host's own metadata used to be dropped here: every plugin saw
|
|
311
|
+
// only itself under `context.plugin` and had no way to learn which
|
|
312
|
+
// application was hosting it.
|
|
313
|
+
host: base.host ?? base.plugin,
|
|
305
314
|
});
|
|
306
315
|
this.contexts.set(name, { context: owned.context, abort: owned.abort });
|
|
307
316
|
return owned.context;
|
|
@@ -347,4 +356,3 @@ export class PluginManager {
|
|
|
347
356
|
return map;
|
|
348
357
|
}
|
|
349
358
|
}
|
|
350
|
-
//# sourceMappingURL=pluginManager.core.js.map
|
|
@@ -8,5 +8,5 @@ export type { PluginMetadata } from "./pluginMetadata.type.js";
|
|
|
8
8
|
export type { PluginDependency } from "./pluginDependency.type.js";
|
|
9
9
|
export type { PluginContext, PluginContainer, PluginConfig, PluginLogger, PluginEvents, PluginEventBus, PluginEventSource, PluginDisposable, } from "./pluginContext.type.js";
|
|
10
10
|
export type { Plugin } from "./plugin.type.js";
|
|
11
|
+
export type { PluginHealth, PluginHealthStatus } from "./plugin.type.js";
|
|
11
12
|
export type { PluginErrorOptions } from "@zudojs/errors";
|
|
12
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { PluginMetadata } from "./pluginMetadata.type.js";
|
|
2
2
|
import type { PluginDependency } from "./pluginDependency.type.js";
|
|
3
3
|
import type { PluginContext } from "./pluginContext.type.js";
|
|
4
|
+
/**
|
|
5
|
+
* Plugin health status.
|
|
6
|
+
*/
|
|
7
|
+
export type PluginHealthStatus = "healthy" | "degraded" | "unhealthy";
|
|
8
|
+
/**
|
|
9
|
+
* Plugin health information: what a plugin's own `health()` returns and
|
|
10
|
+
* what `PluginManager.diagnostics()` reports for it.
|
|
11
|
+
*/
|
|
12
|
+
export interface PluginHealth {
|
|
13
|
+
readonly status: PluginHealthStatus;
|
|
14
|
+
readonly details?: unknown;
|
|
15
|
+
}
|
|
4
16
|
/**
|
|
5
17
|
* Plugin interface definition.
|
|
6
18
|
*/
|
|
@@ -13,5 +25,11 @@ export interface Plugin<TOptions = unknown> {
|
|
|
13
25
|
start?(context: PluginContext): void | Promise<void>;
|
|
14
26
|
stop?(context: PluginContext): void | Promise<void>;
|
|
15
27
|
dispose?(context: PluginContext): void | Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Reports the plugin's own health while it is `started`. Consulted by
|
|
30
|
+
* `PluginManager.diagnostics()`, which otherwise derives health from
|
|
31
|
+
* lifecycle state alone; a throwing `health()` is reported as
|
|
32
|
+
* `unhealthy` with the error message as `details`.
|
|
33
|
+
*/
|
|
34
|
+
health?(): PluginHealth;
|
|
16
35
|
}
|
|
17
|
-
//# sourceMappingURL=plugin.type.d.ts.map
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { PluginMetadata } from "./pluginMetadata.type.js";
|
|
2
2
|
/**
|
|
3
3
|
* Minimal container interface for plugin context.
|
|
4
|
+
*
|
|
5
|
+
* `register` is all the plugin system itself needs. `resolve` and `has`
|
|
6
|
+
* are declared optional so a plugin can read from a real container
|
|
7
|
+
* (`@zudojs/container`'s satisfies this shape) without casting; a host
|
|
8
|
+
* that passes a register-only object leaves them `undefined`.
|
|
4
9
|
*/
|
|
5
10
|
export interface PluginContainer {
|
|
6
11
|
register(token: unknown, provider: unknown): void;
|
|
12
|
+
resolve?<T = unknown>(token: unknown): T;
|
|
13
|
+
has?(token: unknown): boolean;
|
|
7
14
|
}
|
|
8
15
|
/**
|
|
9
16
|
* Minimal config interface for plugin context.
|
|
@@ -63,6 +70,12 @@ export interface PluginDisposable {
|
|
|
63
70
|
*/
|
|
64
71
|
export interface PluginContext {
|
|
65
72
|
readonly plugin: PluginMetadata;
|
|
73
|
+
/**
|
|
74
|
+
* Metadata of the host application — the `plugin` metadata of the
|
|
75
|
+
* context handed to `PluginManager.start()`. Absent on a context built
|
|
76
|
+
* directly with `createPluginContext` and no `host` option.
|
|
77
|
+
*/
|
|
78
|
+
readonly host?: PluginMetadata;
|
|
66
79
|
readonly container?: PluginContainer;
|
|
67
80
|
readonly config?: PluginConfig;
|
|
68
81
|
readonly logger?: PluginLogger;
|
|
@@ -75,4 +88,3 @@ export interface PluginContext {
|
|
|
75
88
|
onDispose(handler: () => void | Promise<void>): void;
|
|
76
89
|
registerDisposable(disposable: PluginDisposable): void;
|
|
77
90
|
}
|
|
78
|
-
//# sourceMappingURL=pluginContext.type.d.ts.map
|
|
@@ -10,4 +10,3 @@ export declare const VALID_STATE_TRANSITIONS: Readonly<Record<PluginState, reado
|
|
|
10
10
|
* Determines whether a state transition is valid.
|
|
11
11
|
*/
|
|
12
12
|
export declare function isValidTransition(from: PluginState, to: PluginState): boolean;
|
|
13
|
-
//# sourceMappingURL=pluginState.type.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/plugins",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Plugin system for extending Zudojs applications with modular capabilities.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"!dist/.tsbuildinfo"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@zudojs/errors": "1.
|
|
27
|
+
"@zudojs/errors": "1.4.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^26.6.2",
|
|
31
|
-
"@zudojs/events": "1.
|
|
31
|
+
"@zudojs/events": "1.4.0",
|
|
32
32
|
"typescript": "7.0.2",
|
|
33
33
|
"vitest": "^5.0.1"
|
|
34
34
|
},
|