@zudojs/plugins 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.
- package/LICENSE +21 -0
- package/README.md +135 -29
- package/dist/index.d.ts +34 -13
- package/dist/index.js +28 -10
- package/dist/pluginDependencies/dependencyResolver.core.d.ts +47 -6
- package/dist/pluginDependencies/dependencyResolver.core.js +108 -46
- package/dist/pluginDependencies/index.d.ts +6 -2
- package/dist/pluginDependencies/index.js +4 -1
- package/dist/pluginDependencies/versionCheck.core.d.ts +67 -0
- package/dist/pluginDependencies/versionCheck.core.js +199 -0
- package/dist/pluginDiagnostics/pluginDiagnostic.core.d.ts +9 -0
- package/dist/pluginDiagnostics/pluginDiagnostic.core.js +16 -12
- package/dist/pluginIntegration/index.d.ts +2 -1
- package/dist/pluginIntegration/index.js +1 -1
- package/dist/pluginIntegration/pluginContext.core.d.ts +35 -5
- package/dist/pluginIntegration/pluginContext.core.js +28 -5
- package/dist/pluginLifecycle/pluginLifecycle.core.d.ts +42 -0
- package/dist/pluginLifecycle/pluginLifecycle.core.js +132 -70
- package/dist/pluginManager/pluginManager.core.d.ts +121 -3
- package/dist/pluginManager/pluginManager.core.js +282 -47
- package/dist/pluginRegistry/pluginRegistry.core.d.ts +15 -6
- package/dist/pluginRegistry/pluginRegistry.core.js +6 -1
- package/dist/pluginTypes/index.d.ts +1 -1
- package/dist/pluginTypes/pluginContext.type.d.ts +11 -3
- package/dist/pluginTypes/pluginState.type.js +6 -3
- package/package.json +26 -15
- package/dist/.tsbuildinfo +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/pluginDependencies/dependencyResolver.core.d.ts.map +0 -1
- package/dist/pluginDependencies/dependencyResolver.core.js.map +0 -1
- package/dist/pluginDependencies/index.d.ts.map +0 -1
- package/dist/pluginDependencies/index.js.map +0 -1
- package/dist/pluginDiagnostics/index.d.ts.map +0 -1
- package/dist/pluginDiagnostics/index.js.map +0 -1
- package/dist/pluginDiagnostics/pluginDiagnostic.core.d.ts.map +0 -1
- package/dist/pluginDiagnostics/pluginDiagnostic.core.js.map +0 -1
- package/dist/pluginEvents/index.d.ts.map +0 -1
- package/dist/pluginEvents/index.js.map +0 -1
- package/dist/pluginEvents/pluginEvent.core.d.ts.map +0 -1
- package/dist/pluginEvents/pluginEvent.core.js.map +0 -1
- package/dist/pluginIntegration/index.d.ts.map +0 -1
- package/dist/pluginIntegration/index.js.map +0 -1
- package/dist/pluginIntegration/pluginContext.core.d.ts.map +0 -1
- package/dist/pluginIntegration/pluginContext.core.js.map +0 -1
- package/dist/pluginLifecycle/pluginLifecycle.core.d.ts.map +0 -1
- package/dist/pluginLifecycle/pluginLifecycle.core.js.map +0 -1
- package/dist/pluginManager/pluginManager.core.d.ts.map +0 -1
- package/dist/pluginManager/pluginManager.core.js.map +0 -1
- package/dist/pluginRegistry/index.d.ts.map +0 -1
- package/dist/pluginRegistry/index.js.map +0 -1
- package/dist/pluginRegistry/pluginRegistry.core.d.ts.map +0 -1
- package/dist/pluginRegistry/pluginRegistry.core.js.map +0 -1
- package/dist/pluginTypes/index.d.ts.map +0 -1
- package/dist/pluginTypes/index.js.map +0 -1
- package/dist/pluginTypes/plugin.type.d.ts.map +0 -1
- package/dist/pluginTypes/plugin.type.js.map +0 -1
- package/dist/pluginTypes/pluginContext.type.d.ts.map +0 -1
- package/dist/pluginTypes/pluginContext.type.js.map +0 -1
- package/dist/pluginTypes/pluginDependency.type.d.ts.map +0 -1
- package/dist/pluginTypes/pluginDependency.type.js.map +0 -1
- package/dist/pluginTypes/pluginMetadata.type.d.ts.map +0 -1
- package/dist/pluginTypes/pluginMetadata.type.js.map +0 -1
- package/dist/pluginTypes/pluginState.type.d.ts.map +0 -1
- package/dist/pluginTypes/pluginState.type.js.map +0 -1
|
@@ -1,126 +1,188 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PluginStateError } from "@zudojs/errors";
|
|
1
|
+
import { isValidTransition } from "../pluginTypes/pluginState.type.js";
|
|
2
|
+
import { PluginDisposeError, PluginStateError, PluginTimeoutError, } from "@zudojs/errors";
|
|
3
3
|
import { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "../pluginEvents/pluginEvent.core.js";
|
|
4
4
|
/**
|
|
5
5
|
* Emits a plugin lifecycle event if the context supports events.
|
|
6
|
+
*
|
|
7
|
+
* A throwing subscriber must not abort the lifecycle phase that emitted
|
|
8
|
+
* the event, so delivery failures are contained here.
|
|
6
9
|
*/
|
|
7
|
-
function emitLifecycleEvent(context, eventName,
|
|
10
|
+
function emitLifecycleEvent(context, eventName, plugin, state, previousState, error) {
|
|
8
11
|
if (!context.events?.emit) {
|
|
9
12
|
return;
|
|
10
13
|
}
|
|
11
|
-
const event = createPluginLifecycleEvent(
|
|
12
|
-
|
|
14
|
+
const event = createPluginLifecycleEvent(plugin, state, previousState, error);
|
|
15
|
+
try {
|
|
16
|
+
context.events.emit(eventName, event);
|
|
17
|
+
}
|
|
18
|
+
catch (emitError) {
|
|
19
|
+
queueMicrotask(() => {
|
|
20
|
+
console.error(`[@zudojs/plugins] Listener for "${eventName}" threw.`, emitError);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
13
23
|
}
|
|
24
|
+
/** Largest delay a timer can represent. */
|
|
25
|
+
const MAX_TIMER_DELAY = 2_147_483_647;
|
|
14
26
|
/**
|
|
15
27
|
* Executes plugin lifecycle phases with state management and event emission.
|
|
16
28
|
*/
|
|
17
29
|
export class LifecycleController {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
options;
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Runs a hook under the configured timeout, clearing the timer either
|
|
36
|
+
* way so a completed hook never leaves one armed.
|
|
37
|
+
*/
|
|
38
|
+
async runHook(pluginName, phase, run) {
|
|
39
|
+
const timeout = this.options.hookTimeout ?? 0;
|
|
40
|
+
if (timeout <= 0) {
|
|
41
|
+
await run();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let timer;
|
|
45
|
+
const hook = Promise.resolve().then(run);
|
|
46
|
+
// The hook keeps running if the timeout wins; handle its eventual
|
|
47
|
+
// rejection so it is never unhandled.
|
|
48
|
+
hook.catch(() => { });
|
|
24
49
|
try {
|
|
25
|
-
await
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
50
|
+
await Promise.race([
|
|
51
|
+
hook,
|
|
52
|
+
new Promise((_, reject) => {
|
|
53
|
+
timer = setTimeout(() => reject(new PluginTimeoutError(pluginName, timeout, {
|
|
54
|
+
metadata: { phase },
|
|
55
|
+
})), Math.min(timeout, MAX_TIMER_DELAY));
|
|
56
|
+
timer.unref?.();
|
|
57
|
+
}),
|
|
58
|
+
]);
|
|
29
59
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
finally {
|
|
61
|
+
if (timer !== undefined) {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
}
|
|
34
64
|
}
|
|
35
65
|
}
|
|
66
|
+
async install(registered, context) {
|
|
67
|
+
await this.runPhase(registered, context, "installing", "installed", PLUGIN_EVENTS.INSTALLING, PLUGIN_EVENTS.INSTALLED, () => registered.plugin.install?.(context, registered.options));
|
|
68
|
+
}
|
|
36
69
|
async initialize(registered, context) {
|
|
37
|
-
|
|
38
|
-
const from = registered.state;
|
|
39
|
-
this.ensureTransition(registered, "initializing");
|
|
40
|
-
registered.setState("initializing");
|
|
41
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.INITIALIZING, name, "initializing", from);
|
|
42
|
-
try {
|
|
43
|
-
await registered.plugin.initialize?.(context);
|
|
44
|
-
this.ensureTransition(registered, "initialized");
|
|
45
|
-
registered.setState("initialized");
|
|
46
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.INITIALIZED, name, "initialized", "initializing");
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
registered.setState("failed");
|
|
50
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.FAILED, name, "failed", from, error);
|
|
51
|
-
throw error;
|
|
52
|
-
}
|
|
70
|
+
await this.runPhase(registered, context, "initializing", "initialized", PLUGIN_EVENTS.INITIALIZING, PLUGIN_EVENTS.INITIALIZED, () => registered.plugin.initialize?.(context));
|
|
53
71
|
}
|
|
54
72
|
async start(registered, context) {
|
|
55
|
-
|
|
56
|
-
const from = registered.state;
|
|
57
|
-
this.ensureTransition(registered, "starting");
|
|
58
|
-
registered.setState("starting");
|
|
59
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.STARTING, name, "starting", from);
|
|
60
|
-
try {
|
|
61
|
-
await registered.plugin.start?.(context);
|
|
62
|
-
this.ensureTransition(registered, "started");
|
|
63
|
-
registered.setState("started");
|
|
64
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.STARTED, name, "started", "starting");
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
registered.setState("failed");
|
|
68
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.FAILED, name, "failed", from, error);
|
|
69
|
-
throw error;
|
|
70
|
-
}
|
|
73
|
+
await this.runPhase(registered, context, "starting", "started", PLUGIN_EVENTS.STARTING, PLUGIN_EVENTS.STARTED, () => registered.plugin.start?.(context));
|
|
71
74
|
}
|
|
72
75
|
async stop(registered, context) {
|
|
73
|
-
|
|
76
|
+
await this.runPhase(registered, context, "stopping", "stopped", PLUGIN_EVENTS.STOPPING, PLUGIN_EVENTS.STOPPED, () => registered.plugin.stop?.(context));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Runs one lifecycle phase, moving through its transient state.
|
|
80
|
+
*
|
|
81
|
+
* On failure the plugin moves to `failed` through the state machine
|
|
82
|
+
* rather than around it, so the recorded state is always one the
|
|
83
|
+
* machine actually permits.
|
|
84
|
+
*/
|
|
85
|
+
async runPhase(registered, context, transient, settled, startEvent, endEvent, run) {
|
|
86
|
+
const metadata = registered.plugin.metadata;
|
|
74
87
|
const from = registered.state;
|
|
75
|
-
this.ensureTransition(registered,
|
|
76
|
-
registered.setState(
|
|
77
|
-
emitLifecycleEvent(context,
|
|
88
|
+
this.ensureTransition(registered, transient);
|
|
89
|
+
registered.setState(transient);
|
|
90
|
+
emitLifecycleEvent(context, startEvent, metadata, transient, from);
|
|
78
91
|
try {
|
|
79
|
-
await
|
|
80
|
-
this.ensureTransition(registered,
|
|
81
|
-
registered.setState(
|
|
82
|
-
emitLifecycleEvent(context,
|
|
92
|
+
await this.runHook(metadata.name, transient, run);
|
|
93
|
+
this.ensureTransition(registered, settled);
|
|
94
|
+
registered.setState(settled);
|
|
95
|
+
emitLifecycleEvent(context, endEvent, metadata, settled, transient);
|
|
83
96
|
}
|
|
84
97
|
catch (error) {
|
|
85
|
-
registered.
|
|
86
|
-
|
|
98
|
+
registered.setError(error);
|
|
99
|
+
this.transitionToFailed(registered);
|
|
100
|
+
emitLifecycleEvent(context, PLUGIN_EVENTS.FAILED, metadata, "failed", transient, error);
|
|
87
101
|
throw error;
|
|
88
102
|
}
|
|
89
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Disposes a plugin and everything it registered for cleanup.
|
|
106
|
+
*
|
|
107
|
+
* Disposables run in reverse registration order — the mirror of how
|
|
108
|
+
* they were acquired — and the list is emptied so a second dispose
|
|
109
|
+
* cannot run them again. Every failure is collected; the plugin still
|
|
110
|
+
* reaches a terminal state so it cannot be disposed twice.
|
|
111
|
+
*/
|
|
90
112
|
async dispose(registered, context) {
|
|
91
|
-
const
|
|
113
|
+
const metadata = registered.plugin.metadata;
|
|
92
114
|
const from = registered.state;
|
|
115
|
+
if (from === "disposed" || from === "disposing") {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
93
118
|
this.ensureTransition(registered, "disposing");
|
|
94
119
|
registered.setState("disposing");
|
|
95
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.DISPOSING,
|
|
120
|
+
emitLifecycleEvent(context, PLUGIN_EVENTS.DISPOSING, metadata, "disposing", from);
|
|
96
121
|
const errors = [];
|
|
97
|
-
|
|
122
|
+
// Take the list before running it: a disposable that registers
|
|
123
|
+
// another during teardown must not extend the loop indefinitely.
|
|
124
|
+
const disposables = registered.disposables.splice(0, registered.disposables.length);
|
|
125
|
+
for (const disposable of disposables.reverse()) {
|
|
98
126
|
try {
|
|
99
|
-
await disposable.dispose();
|
|
127
|
+
await this.runHook(metadata.name, "disposing", () => disposable.dispose());
|
|
100
128
|
}
|
|
101
129
|
catch (error) {
|
|
102
130
|
errors.push(error);
|
|
103
131
|
}
|
|
104
132
|
}
|
|
105
133
|
try {
|
|
106
|
-
await registered.plugin.dispose?.(context);
|
|
134
|
+
await this.runHook(metadata.name, "disposing", () => registered.plugin.dispose?.(context));
|
|
107
135
|
}
|
|
108
136
|
catch (error) {
|
|
109
137
|
errors.push(error);
|
|
110
138
|
}
|
|
111
139
|
registered.setState("disposed");
|
|
112
|
-
emitLifecycleEvent(context, PLUGIN_EVENTS.DISPOSED,
|
|
140
|
+
emitLifecycleEvent(context, PLUGIN_EVENTS.DISPOSED, metadata, "disposed", "disposing");
|
|
113
141
|
if (errors.length > 0) {
|
|
114
|
-
|
|
142
|
+
const error = new PluginDisposeError(errors.length === 1
|
|
143
|
+
? `Plugin "${metadata.name}" failed to dispose.`
|
|
144
|
+
: `Plugin "${metadata.name}" reported ${errors.length} disposal failures.`, metadata.name, { cause: errors[0] });
|
|
145
|
+
// Every failure is retained; reporting only the first would hide
|
|
146
|
+
// the rest of a partially failed teardown.
|
|
147
|
+
Object.defineProperty(error, "errors", {
|
|
148
|
+
value: Object.freeze([...errors]),
|
|
149
|
+
enumerable: true,
|
|
150
|
+
configurable: true,
|
|
151
|
+
});
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Moves a plugin to `failed`, via `stopping` when required.
|
|
157
|
+
*/
|
|
158
|
+
transitionToFailed(registered) {
|
|
159
|
+
if (registered.state === "failed") {
|
|
160
|
+
return;
|
|
115
161
|
}
|
|
162
|
+
if (this.canTransition(registered.state, "failed")) {
|
|
163
|
+
registered.setState("failed");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// A phase can fail from a settled state (a hook that threw after
|
|
167
|
+
// the state had already advanced). Route through `stopping`, which
|
|
168
|
+
// every settled state permits, so the machine stays consistent.
|
|
169
|
+
if (this.canTransition(registered.state, "stopping")) {
|
|
170
|
+
registered.setState("stopping");
|
|
171
|
+
}
|
|
172
|
+
registered.setState("failed");
|
|
173
|
+
}
|
|
174
|
+
canTransition(from, to) {
|
|
175
|
+
// Delegates to the exported predicate rather than re-deriving it:
|
|
176
|
+
// two copies of the transition rule can disagree, and the public
|
|
177
|
+
// `isValidTransition` must describe what the controller actually does.
|
|
178
|
+
return isValidTransition(from, to);
|
|
116
179
|
}
|
|
117
180
|
ensureTransition(registered, to) {
|
|
118
181
|
const from = registered.state;
|
|
119
182
|
if (from === to) {
|
|
120
183
|
return;
|
|
121
184
|
}
|
|
122
|
-
|
|
123
|
-
if (!valid) {
|
|
185
|
+
if (!this.canTransition(from, to)) {
|
|
124
186
|
throw new PluginStateError(registered.plugin.metadata.name, from, to);
|
|
125
187
|
}
|
|
126
188
|
}
|
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
import type { Plugin } from "../pluginTypes/plugin.type.js";
|
|
2
|
-
import type { PluginContext } from "../pluginTypes/pluginContext.type.js";
|
|
2
|
+
import type { PluginContext, PluginEvents } from "../pluginTypes/pluginContext.type.js";
|
|
3
3
|
import type { PluginDiagnosticReport } from "../pluginDiagnostics/pluginDiagnostic.core.js";
|
|
4
|
+
/**
|
|
5
|
+
* Options for a plugin manager.
|
|
6
|
+
*/
|
|
7
|
+
export interface PluginManagerOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Whether declared dependency versions are enforced at startup.
|
|
10
|
+
* Defaults to `true`. A declared version that is never checked is
|
|
11
|
+
* worse than no version at all.
|
|
12
|
+
*/
|
|
13
|
+
readonly checkVersions?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Receives errors raised during shutdown. Teardown continues past a
|
|
16
|
+
* failing plugin either way, but without this the failures are
|
|
17
|
+
* invisible.
|
|
18
|
+
*/
|
|
19
|
+
readonly onError?: (error: unknown, pluginName: string) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Maximum time a single lifecycle hook may run, in milliseconds.
|
|
22
|
+
* Defaults to `0` (unbounded). Set a value so one hanging plugin
|
|
23
|
+
* cannot hang boot or shutdown.
|
|
24
|
+
*/
|
|
25
|
+
readonly hookTimeout?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Capabilities plugins are permitted to declare.
|
|
28
|
+
*
|
|
29
|
+
* When set, a plugin whose `metadata.capabilities` includes anything
|
|
30
|
+
* outside this list is rejected at registration. Leave unset to allow
|
|
31
|
+
* any capability.
|
|
32
|
+
*/
|
|
33
|
+
readonly allowedCapabilities?: readonly string[];
|
|
34
|
+
/**
|
|
35
|
+
* Event sink for `plugin:registered`.
|
|
36
|
+
*
|
|
37
|
+
* Registration happens before any plugin context exists, so the
|
|
38
|
+
* lifecycle events emitted through `context.events` cannot cover it.
|
|
39
|
+
* Without this, `PLUGIN_EVENTS.REGISTERED` was a name nothing ever
|
|
40
|
+
* emitted.
|
|
41
|
+
*/
|
|
42
|
+
readonly events?: PluginEvents;
|
|
43
|
+
}
|
|
4
44
|
/**
|
|
5
45
|
* Plugin manager coordinates registration, dependency resolution, lifecycle, and disposal.
|
|
6
46
|
*/
|
|
@@ -9,14 +49,92 @@ export declare class PluginManager {
|
|
|
9
49
|
private readonly resolver;
|
|
10
50
|
private readonly lifecycle;
|
|
11
51
|
private readonly plugins;
|
|
12
|
-
|
|
13
|
-
|
|
52
|
+
private readonly options;
|
|
53
|
+
/**
|
|
54
|
+
* Dependency-first order from the last successful resolution.
|
|
55
|
+
*
|
|
56
|
+
* Shutdown reverses this rather than registration order: tearing down
|
|
57
|
+
* in registration order destroys a dependency while its dependents are
|
|
58
|
+
* still using it.
|
|
59
|
+
*/
|
|
60
|
+
private startupOrder;
|
|
61
|
+
private starting;
|
|
62
|
+
/**
|
|
63
|
+
* Per-plugin context views and their abort handles.
|
|
64
|
+
*
|
|
65
|
+
* Each plugin gets a context whose `onDispose` and
|
|
66
|
+
* `registerDisposable` write to that plugin's own disposables list —
|
|
67
|
+
* the list the lifecycle actually drains — and whose `signal` this
|
|
68
|
+
* manager aborts on shutdown.
|
|
69
|
+
*/
|
|
70
|
+
private readonly contexts;
|
|
71
|
+
constructor(options?: PluginManagerOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Registers a plugin.
|
|
74
|
+
*
|
|
75
|
+
* @throws {PluginAlreadyRegisteredError} when the name is taken, so
|
|
76
|
+
* callers can implement idempotent registration.
|
|
77
|
+
*/
|
|
78
|
+
register<TPlugin extends Plugin>(plugin: TPlugin, options?: unknown): void;
|
|
79
|
+
/**
|
|
80
|
+
* Removes a plugin that has not been started.
|
|
81
|
+
*
|
|
82
|
+
* Keeps the manager's own view in step with the registry; leaving a
|
|
83
|
+
* removed plugin in `plugins` would keep it in dependency resolution.
|
|
84
|
+
*/
|
|
85
|
+
unregister(name: string): boolean;
|
|
14
86
|
get<TPlugin extends Plugin>(name: string): TPlugin | undefined;
|
|
15
87
|
has(name: string): boolean;
|
|
16
88
|
list(): readonly Plugin[];
|
|
89
|
+
/**
|
|
90
|
+
* Installs, initializes and starts every plugin in dependency order.
|
|
91
|
+
*
|
|
92
|
+
* A failure anywhere rolls back: everything already brought up is
|
|
93
|
+
* stopped and disposed before the error is rethrown, so an aborted
|
|
94
|
+
* startup does not strand resources with no route to release them.
|
|
95
|
+
*/
|
|
17
96
|
start(context: PluginContext): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Stops and disposes every plugin, in reverse dependency order.
|
|
99
|
+
*
|
|
100
|
+
* Teardown continues past a failing plugin so one bad `stop` cannot
|
|
101
|
+
* strand the rest, and every failure is reported through `onError`
|
|
102
|
+
* rather than swallowed.
|
|
103
|
+
*/
|
|
18
104
|
stop(context: PluginContext): Promise<void>;
|
|
19
105
|
diagnostics(): PluginDiagnosticReport;
|
|
106
|
+
/**
|
|
107
|
+
* Tears down everything brought up by a failed startup.
|
|
108
|
+
*/
|
|
109
|
+
private rollback;
|
|
110
|
+
/**
|
|
111
|
+
* Registered plugins in reverse dependency order.
|
|
112
|
+
*
|
|
113
|
+
* Falls back to reverse registration order for plugins registered
|
|
114
|
+
* after the last resolution, which is the best available guess.
|
|
115
|
+
*/
|
|
116
|
+
private teardownOrder;
|
|
117
|
+
/**
|
|
118
|
+
* Returns the plugin's own context view, creating it on first use.
|
|
119
|
+
*
|
|
120
|
+
* The base context supplies the shared services; only the identity,
|
|
121
|
+
* the disposables collection and the abort signal are per-plugin.
|
|
122
|
+
*/
|
|
123
|
+
private contextFor;
|
|
124
|
+
/**
|
|
125
|
+
* Aborts a plugin's signal, keeping the context available.
|
|
126
|
+
*
|
|
127
|
+
* The entry stays so `dispose` still receives the same — now aborted —
|
|
128
|
+
* context; removing it here would hand the dispose hook a fresh
|
|
129
|
+
* context whose signal had never fired.
|
|
130
|
+
*/
|
|
131
|
+
private abortContext;
|
|
132
|
+
/**
|
|
133
|
+
* Emits `plugin:registered`, containing a throwing subscriber so a bad
|
|
134
|
+
* listener cannot fail the registration that triggered it.
|
|
135
|
+
*/
|
|
136
|
+
private emitRegistered;
|
|
137
|
+
private report;
|
|
20
138
|
private toDependencyMap;
|
|
21
139
|
}
|
|
22
140
|
//# sourceMappingURL=pluginManager.core.d.ts.map
|