@zudojs/plugins 1.2.0 → 1.3.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/README.md +25 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/pluginEvents/index.d.ts +2 -0
- package/dist/pluginEvents/index.js +2 -0
- package/dist/pluginEvents/pluginEvent.bus.d.ts +26 -0
- package/dist/pluginEvents/pluginEvent.bus.js +56 -0
- package/dist/pluginEvents/pluginEvent.deliver.d.ts +18 -0
- package/dist/pluginEvents/pluginEvent.deliver.js +41 -0
- package/dist/pluginIntegration/pluginContext.core.d.ts +6 -2
- package/dist/pluginIntegration/pluginContext.core.js +2 -1
- package/dist/pluginLifecycle/pluginLifecycle.core.js +5 -6
- package/dist/pluginManager/pluginManager.core.d.ts +10 -4
- package/dist/pluginManager/pluginManager.core.js +10 -10
- package/dist/pluginTypes/index.d.ts +1 -1
- package/dist/pluginTypes/pluginContext.type.d.ts +26 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -155,7 +155,31 @@ const manager = new PluginManager({
|
|
|
155
155
|
});
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
A throwing subscriber never fails the phase that emitted the event
|
|
158
|
+
A throwing subscriber never fails the phase that emitted the event, and
|
|
159
|
+
neither does an async `emit` whose promise rejects: both are reported
|
|
160
|
+
(through `onError`, the logger, or a `ZudoPluginWarning`) instead of
|
|
161
|
+
propagating. Before 1.3 an async rejection escaped as an
|
|
162
|
+
`unhandledRejection`, which terminates Node by default, after `start()` had
|
|
163
|
+
already resolved.
|
|
164
|
+
|
|
165
|
+
### Using an `@zudojs/events` bus
|
|
166
|
+
|
|
167
|
+
Both the manager's `events` option and `createPluginContext`'s `events`
|
|
168
|
+
accept an `EventBus` directly. It is adapted with `toPluginEvents`, so
|
|
169
|
+
`context.events` is still a `PluginEvents`: `emit(name, payload)` publishes
|
|
170
|
+
`{ type: name, payload }` (the bus normalises `plugin:started` to
|
|
171
|
+
`plugin.started`), `on(name, handler)` subscribes and hands the handler the
|
|
172
|
+
event's payload, and `off(name, handler)` cancels that subscription.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { EventBus } from "@zudojs/events";
|
|
176
|
+
|
|
177
|
+
const bus = new EventBus();
|
|
178
|
+
bus.on("plugin.*", (event) => console.log(event.type, event.payload));
|
|
179
|
+
|
|
180
|
+
const manager = new PluginManager({ events: bus });
|
|
181
|
+
await manager.start(createPluginContext({ name: "host" }, { events: bus }));
|
|
182
|
+
```
|
|
159
183
|
|
|
160
184
|
## Diagnostics
|
|
161
185
|
|
package/dist/index.d.ts
CHANGED
|
@@ -55,11 +55,12 @@ export { LifecycleController } from "./pluginLifecycle/pluginLifecycle.core.js";
|
|
|
55
55
|
export type { LifecycleControllerOptions } from "./pluginLifecycle/pluginLifecycle.core.js";
|
|
56
56
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvents/pluginEvent.core.js";
|
|
57
57
|
export type { PluginLifecycleEvent } from "./pluginEvents/pluginEvent.core.js";
|
|
58
|
+
export { isPluginEventBus, toPluginEvents, } from "./pluginEvents/pluginEvent.bus.js";
|
|
58
59
|
export { buildDiagnosticReport, createHealthyHealth, createDegradedHealth, createUnhealthyHealth, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
59
60
|
export type { PluginHealth, PluginHealthStatus, PluginDiagnostic, PluginDiagnosticReport, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
60
61
|
export { isValidTransition, VALID_STATE_TRANSITIONS, } from "./pluginTypes/pluginState.type.js";
|
|
61
62
|
export { createPluginContext, createOwnedPluginContext, } from "./pluginIntegration/pluginContext.core.js";
|
|
62
63
|
export type { CreatePluginContextOptions, OwnedPluginContext, } from "./pluginIntegration/pluginContext.core.js";
|
|
63
64
|
export { PluginError, PluginRegistrationError, PluginAlreadyRegisteredError, PluginNotFoundError, PluginDependencyError, PluginDependencyCycleError, PluginInitializationError, PluginStartError, PluginStopError, PluginDisposeError, PluginTimeoutError, PluginStateError, createPluginError, isPluginError, } from "@zudojs/errors";
|
|
64
|
-
export type { PluginState, PluginMetadata, PluginDependency, PluginContext, PluginContainer, PluginConfig, PluginLogger, PluginEvents, PluginDisposable, Plugin, PluginErrorOptions, } from "./pluginTypes/index.js";
|
|
65
|
+
export type { PluginState, PluginMetadata, PluginDependency, PluginContext, PluginContainer, PluginConfig, PluginLogger, PluginEvents, PluginEventBus, PluginEventSource, PluginDisposable, Plugin, PluginErrorOptions, } from "./pluginTypes/index.js";
|
|
65
66
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,7 @@ export { parseVersion, compareVersions, satisfiesVersion, assertDependencyVersio
|
|
|
49
49
|
export { PluginDependencyVersionError } from "./pluginDependencies/versionCheck.core.js";
|
|
50
50
|
export { LifecycleController } from "./pluginLifecycle/pluginLifecycle.core.js";
|
|
51
51
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvents/pluginEvent.core.js";
|
|
52
|
+
export { isPluginEventBus, toPluginEvents, } from "./pluginEvents/pluginEvent.bus.js";
|
|
52
53
|
export { buildDiagnosticReport, createHealthyHealth, createDegradedHealth, createUnhealthyHealth, } from "./pluginDiagnostics/pluginDiagnostic.core.js";
|
|
53
54
|
export { isValidTransition, VALID_STATE_TRANSITIONS, } from "./pluginTypes/pluginState.type.js";
|
|
54
55
|
export { createPluginContext, createOwnedPluginContext, } from "./pluginIntegration/pluginContext.core.js";
|
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type { PluginLifecycleEvent } from "./pluginEvent.core.js";
|
|
7
7
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvent.core.js";
|
|
8
|
+
export { isPluginEventBus, toPluginEvents } from "./pluginEvent.bus.js";
|
|
9
|
+
export { deliverPluginEvent } from "./pluginEvent.deliver.js";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,4 +4,6 @@
|
|
|
4
4
|
* Plugin lifecycle event types and event names.
|
|
5
5
|
*/
|
|
6
6
|
export { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "./pluginEvent.core.js";
|
|
7
|
+
export { isPluginEventBus, toPluginEvents } from "./pluginEvent.bus.js";
|
|
8
|
+
export { deliverPluginEvent } from "./pluginEvent.deliver.js";
|
|
7
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PluginEventBus, PluginEvents, PluginEventSource } from "../pluginTypes/pluginContext.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether an event source is an event bus (such as `@zudojs/events`'
|
|
4
|
+
* `EventBus`) rather than a {@link PluginEvents} sink.
|
|
5
|
+
*
|
|
6
|
+
* A bus publishes objects (`publishEvent({ type, payload })`); a sink
|
|
7
|
+
* emits a name and a payload. Calling a bus's `emit` with a bare name
|
|
8
|
+
* throws `InvalidEventError`, so the two must be told apart.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isPluginEventBus(source: PluginEventSource): source is PluginEventBus;
|
|
11
|
+
/**
|
|
12
|
+
* Adapts an event bus to the {@link PluginEvents} interface plugins use.
|
|
13
|
+
*
|
|
14
|
+
* - `emit(name, payload)` publishes `{ type: name, payload }` and returns
|
|
15
|
+
* the publish promise, so a rejection can be caught by the caller.
|
|
16
|
+
* - `on(name, handler)` subscribes on the bus and hands the handler the
|
|
17
|
+
* event's `payload` — the same value a sink's `emit` would pass.
|
|
18
|
+
* - `off(name, handler)` cancels that subscription.
|
|
19
|
+
*
|
|
20
|
+
* A {@link PluginEvents} sink is returned unchanged.
|
|
21
|
+
*
|
|
22
|
+
* @param source - An event bus or a plugin events sink.
|
|
23
|
+
* @returns A {@link PluginEvents} view of it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function toPluginEvents(source: PluginEventSource): PluginEvents;
|
|
26
|
+
//# sourceMappingURL=pluginEvent.bus.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether an event source is an event bus (such as `@zudojs/events`'
|
|
3
|
+
* `EventBus`) rather than a {@link PluginEvents} sink.
|
|
4
|
+
*
|
|
5
|
+
* A bus publishes objects (`publishEvent({ type, payload })`); a sink
|
|
6
|
+
* emits a name and a payload. Calling a bus's `emit` with a bare name
|
|
7
|
+
* throws `InvalidEventError`, so the two must be told apart.
|
|
8
|
+
*/
|
|
9
|
+
export function isPluginEventBus(source) {
|
|
10
|
+
return (typeof source.publishEvent === "function");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Adapts an event bus to the {@link PluginEvents} interface plugins use.
|
|
14
|
+
*
|
|
15
|
+
* - `emit(name, payload)` publishes `{ type: name, payload }` and returns
|
|
16
|
+
* the publish promise, so a rejection can be caught by the caller.
|
|
17
|
+
* - `on(name, handler)` subscribes on the bus and hands the handler the
|
|
18
|
+
* event's `payload` — the same value a sink's `emit` would pass.
|
|
19
|
+
* - `off(name, handler)` cancels that subscription.
|
|
20
|
+
*
|
|
21
|
+
* A {@link PluginEvents} sink is returned unchanged.
|
|
22
|
+
*
|
|
23
|
+
* @param source - An event bus or a plugin events sink.
|
|
24
|
+
* @returns A {@link PluginEvents} view of it.
|
|
25
|
+
*/
|
|
26
|
+
export function toPluginEvents(source) {
|
|
27
|
+
if (!isPluginEventBus(source))
|
|
28
|
+
return source;
|
|
29
|
+
const bus = source;
|
|
30
|
+
const subscriptions = new Map();
|
|
31
|
+
return {
|
|
32
|
+
on(event, handler) {
|
|
33
|
+
const byHandler = subscriptions.get(event) ?? new Map();
|
|
34
|
+
subscriptions.set(event, byHandler);
|
|
35
|
+
if (byHandler.has(handler))
|
|
36
|
+
return;
|
|
37
|
+
byHandler.set(handler, bus.on(event, (published) => {
|
|
38
|
+
handler(published.payload);
|
|
39
|
+
}));
|
|
40
|
+
},
|
|
41
|
+
off(event, handler) {
|
|
42
|
+
const byHandler = subscriptions.get(event);
|
|
43
|
+
const subscription = byHandler?.get(handler);
|
|
44
|
+
if (!byHandler || !subscription)
|
|
45
|
+
return;
|
|
46
|
+
subscription.unsubscribe();
|
|
47
|
+
byHandler.delete(handler);
|
|
48
|
+
if (byHandler.size === 0)
|
|
49
|
+
subscriptions.delete(event);
|
|
50
|
+
},
|
|
51
|
+
emit(event, payload) {
|
|
52
|
+
return bus.publishEvent({ type: event, payload });
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=pluginEvent.bus.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PluginEvents } from "../pluginTypes/pluginContext.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* Emits an event and contains every way delivery can fail.
|
|
4
|
+
*
|
|
5
|
+
* A subscriber that throws synchronously, and an `emit` that returns a
|
|
6
|
+
* promise which later rejects, are both passed to `onFailure` and never
|
|
7
|
+
* propagate: a lifecycle phase must not fail because of a listener, and
|
|
8
|
+
* an unobserved rejection would otherwise surface as an
|
|
9
|
+
* `unhandledRejection` — which terminates Node by default — after the
|
|
10
|
+
* phase has already resolved.
|
|
11
|
+
*
|
|
12
|
+
* @param events - Where to emit.
|
|
13
|
+
* @param name - The event name.
|
|
14
|
+
* @param payload - The event payload.
|
|
15
|
+
* @param onFailure - Receives a synchronous throw or an async rejection.
|
|
16
|
+
*/
|
|
17
|
+
export declare function deliverPluginEvent(events: PluginEvents, name: string, payload: unknown, onFailure: (error: unknown) => void): void;
|
|
18
|
+
//# sourceMappingURL=pluginEvent.deliver.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emits an event and contains every way delivery can fail.
|
|
3
|
+
*
|
|
4
|
+
* A subscriber that throws synchronously, and an `emit` that returns a
|
|
5
|
+
* promise which later rejects, are both passed to `onFailure` and never
|
|
6
|
+
* propagate: a lifecycle phase must not fail because of a listener, and
|
|
7
|
+
* an unobserved rejection would otherwise surface as an
|
|
8
|
+
* `unhandledRejection` — which terminates Node by default — after the
|
|
9
|
+
* phase has already resolved.
|
|
10
|
+
*
|
|
11
|
+
* @param events - Where to emit.
|
|
12
|
+
* @param name - The event name.
|
|
13
|
+
* @param payload - The event payload.
|
|
14
|
+
* @param onFailure - Receives a synchronous throw or an async rejection.
|
|
15
|
+
*/
|
|
16
|
+
export function deliverPluginEvent(events, name, payload, onFailure) {
|
|
17
|
+
let result;
|
|
18
|
+
try {
|
|
19
|
+
result = events.emit(name, payload);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
onFailure(error);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (isThenable(result)) {
|
|
26
|
+
result.then(undefined, (error) => {
|
|
27
|
+
try {
|
|
28
|
+
onFailure(error);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// A throwing failure hook must not become an unhandled rejection.
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isThenable(value) {
|
|
37
|
+
return (value !== null &&
|
|
38
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
39
|
+
typeof value.then === "function");
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=pluginEvent.deliver.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PluginMetadata } from "../pluginTypes/pluginMetadata.type.js";
|
|
2
|
-
import type { PluginContext, PluginContainer, PluginConfig, PluginLogger,
|
|
2
|
+
import type { PluginContext, PluginContainer, PluginConfig, PluginLogger, PluginEventSource, PluginDisposable } from "../pluginTypes/pluginContext.type.js";
|
|
3
3
|
/**
|
|
4
4
|
* Options for creating a plugin context.
|
|
5
5
|
*/
|
|
@@ -7,7 +7,11 @@ export interface CreatePluginContextOptions {
|
|
|
7
7
|
readonly container?: PluginContainer;
|
|
8
8
|
readonly config?: PluginConfig;
|
|
9
9
|
readonly logger?: PluginLogger;
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Event sink, or an event bus such as `@zudojs/events`' `EventBus`,
|
|
12
|
+
* which is adapted so `context.events` is always a `PluginEvents`.
|
|
13
|
+
*/
|
|
14
|
+
readonly events?: PluginEventSource;
|
|
11
15
|
/**
|
|
12
16
|
* Collection that receives everything the plugin registers for
|
|
13
17
|
* cleanup. The plugin manager passes the registered plugin's own
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toPluginEvents } from "../pluginEvents/pluginEvent.bus.js";
|
|
1
2
|
/**
|
|
2
3
|
* Creates a plugin context and returns it with its teardown handles.
|
|
3
4
|
*
|
|
@@ -14,7 +15,7 @@ export function createOwnedPluginContext(plugin, options = {}) {
|
|
|
14
15
|
container: options.container,
|
|
15
16
|
config: options.config,
|
|
16
17
|
logger: options.logger,
|
|
17
|
-
events: options.events,
|
|
18
|
+
events: options.events ? toPluginEvents(options.events) : undefined,
|
|
18
19
|
onDispose(handler) {
|
|
19
20
|
disposables.push({ dispose: handler });
|
|
20
21
|
},
|
|
@@ -3,25 +3,24 @@ import { PluginDisposeError, PluginStateError, PluginTimeoutError, } from "@zudo
|
|
|
3
3
|
import { PLUGIN_EVENTS, createPluginLifecycleEvent, } from "../pluginEvents/pluginEvent.core.js";
|
|
4
4
|
import { AbandonedHooks } from "./pluginLifecycle.abandoned.js";
|
|
5
5
|
import { reportPluginFailure } from "./pluginLifecycle.report.js";
|
|
6
|
+
import { deliverPluginEvent } from "../pluginEvents/pluginEvent.deliver.js";
|
|
6
7
|
/**
|
|
7
8
|
* Emits a plugin lifecycle event if the context supports events.
|
|
8
9
|
*
|
|
9
10
|
* A throwing subscriber must not abort the lifecycle phase that emitted
|
|
10
|
-
* the event, so delivery failures
|
|
11
|
+
* the event, so delivery failures — a synchronous throw or an async
|
|
12
|
+
* `emit` that rejects — are contained and reported here.
|
|
11
13
|
*/
|
|
12
14
|
function emitLifecycleEvent(context, eventName, plugin, state, previousState, error) {
|
|
13
15
|
if (!context.events?.emit) {
|
|
14
16
|
return;
|
|
15
17
|
}
|
|
16
18
|
const event = createPluginLifecycleEvent(plugin, state, previousState, error);
|
|
17
|
-
|
|
18
|
-
context.events.emit(eventName, event);
|
|
19
|
-
}
|
|
20
|
-
catch (emitError) {
|
|
19
|
+
deliverPluginEvent(context.events, eventName, event, (emitError) => {
|
|
21
20
|
queueMicrotask(() => {
|
|
22
21
|
reportPluginFailure(context.logger, `Listener for "${eventName}" threw.`, emitError, { plugin: plugin.name, event: eventName });
|
|
23
22
|
});
|
|
24
|
-
}
|
|
23
|
+
});
|
|
25
24
|
}
|
|
26
25
|
/** Largest delay a timer can represent. */
|
|
27
26
|
const MAX_TIMER_DELAY = 2_147_483_647;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from "../pluginTypes/plugin.type.js";
|
|
2
|
-
import type { PluginContext,
|
|
2
|
+
import type { PluginContext, PluginEventSource } from "../pluginTypes/pluginContext.type.js";
|
|
3
3
|
import type { PluginDiagnosticReport } from "../pluginDiagnostics/pluginDiagnostic.core.js";
|
|
4
4
|
import type { PluginLogger } from "../pluginTypes/pluginContext.type.js";
|
|
5
5
|
/**
|
|
@@ -39,8 +39,11 @@ export interface PluginManagerOptions {
|
|
|
39
39
|
* lifecycle events emitted through `context.events` cannot cover it.
|
|
40
40
|
* Without this, `PLUGIN_EVENTS.REGISTERED` was a name nothing ever
|
|
41
41
|
* emitted.
|
|
42
|
+
*
|
|
43
|
+
* Accepts an event bus such as `@zudojs/events`' `EventBus` as well as a
|
|
44
|
+
* `PluginEvents` sink.
|
|
42
45
|
*/
|
|
43
|
-
readonly events?:
|
|
46
|
+
readonly events?: PluginEventSource;
|
|
44
47
|
/**
|
|
45
48
|
* Logger for teardown failures when `onError` is not supplied.
|
|
46
49
|
* Defaults to the logger on the context passed to `start()`/`stop()`.
|
|
@@ -56,6 +59,8 @@ export declare class PluginManager {
|
|
|
56
59
|
private readonly lifecycle;
|
|
57
60
|
private readonly plugins;
|
|
58
61
|
private readonly options;
|
|
62
|
+
/** `options.events`, adapted to the sink interface. */
|
|
63
|
+
private readonly events;
|
|
59
64
|
/**
|
|
60
65
|
* Dependency-first order from the last successful resolution.
|
|
61
66
|
*
|
|
@@ -138,8 +143,9 @@ export declare class PluginManager {
|
|
|
138
143
|
*/
|
|
139
144
|
private abortContext;
|
|
140
145
|
/**
|
|
141
|
-
* Emits `plugin:registered`, containing a throwing subscriber
|
|
142
|
-
* listener cannot fail the
|
|
146
|
+
* Emits `plugin:registered`, containing a throwing subscriber — or a
|
|
147
|
+
* rejecting async `emit` — so a bad listener cannot fail the
|
|
148
|
+
* registration that triggered it.
|
|
143
149
|
*/
|
|
144
150
|
private emitRegistered;
|
|
145
151
|
private report;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { toPluginEvents } from "../pluginEvents/pluginEvent.bus.js";
|
|
2
|
+
import { deliverPluginEvent } from "../pluginEvents/pluginEvent.deliver.js";
|
|
1
3
|
import { PluginRegistryImpl } from "../pluginRegistry/pluginRegistry.core.js";
|
|
2
4
|
import { DependencyResolver, assertResolutionValid, } from "../pluginDependencies/dependencyResolver.core.js";
|
|
3
5
|
import { assertDependencyVersions } from "../pluginDependencies/versionCheck.core.js";
|
|
@@ -25,6 +27,8 @@ export class PluginManager {
|
|
|
25
27
|
lifecycle;
|
|
26
28
|
plugins = new Map();
|
|
27
29
|
options;
|
|
30
|
+
/** `options.events`, adapted to the sink interface. */
|
|
31
|
+
events;
|
|
28
32
|
/**
|
|
29
33
|
* Dependency-first order from the last successful resolution.
|
|
30
34
|
*
|
|
@@ -52,6 +56,7 @@ export class PluginManager {
|
|
|
52
56
|
? { hookTimeout: options.hookTimeout }
|
|
53
57
|
: {});
|
|
54
58
|
this.options = options;
|
|
59
|
+
this.events = options.events ? toPluginEvents(options.events) : undefined;
|
|
55
60
|
}
|
|
56
61
|
/**
|
|
57
62
|
* Registers a plugin.
|
|
@@ -312,20 +317,15 @@ export class PluginManager {
|
|
|
312
317
|
this.contexts.get(name)?.abort(reason);
|
|
313
318
|
}
|
|
314
319
|
/**
|
|
315
|
-
* Emits `plugin:registered`, containing a throwing subscriber
|
|
316
|
-
* listener cannot fail the
|
|
320
|
+
* Emits `plugin:registered`, containing a throwing subscriber — or a
|
|
321
|
+
* rejecting async `emit` — so a bad listener cannot fail the
|
|
322
|
+
* registration that triggered it.
|
|
317
323
|
*/
|
|
318
324
|
emitRegistered(plugin) {
|
|
319
|
-
|
|
320
|
-
if (!events) {
|
|
325
|
+
if (!this.events) {
|
|
321
326
|
return;
|
|
322
327
|
}
|
|
323
|
-
|
|
324
|
-
events.emit(PLUGIN_EVENTS.REGISTERED, createPluginLifecycleEvent(plugin.metadata, "registered"));
|
|
325
|
-
}
|
|
326
|
-
catch (error) {
|
|
327
|
-
this.report(error, plugin.metadata.name);
|
|
328
|
-
}
|
|
328
|
+
deliverPluginEvent(this.events, PLUGIN_EVENTS.REGISTERED, createPluginLifecycleEvent(plugin.metadata, "registered"), (error) => this.report(error, plugin.metadata.name));
|
|
329
329
|
}
|
|
330
330
|
report(error, pluginName) {
|
|
331
331
|
if (this.options.onError) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export type { PluginState } from "./pluginState.type.js";
|
|
7
7
|
export type { PluginMetadata } from "./pluginMetadata.type.js";
|
|
8
8
|
export type { PluginDependency } from "./pluginDependency.type.js";
|
|
9
|
-
export type { PluginContext, PluginContainer, PluginConfig, PluginLogger, PluginEvents, PluginDisposable, } from "./pluginContext.type.js";
|
|
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
11
|
export type { PluginErrorOptions } from "@zudojs/errors";
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -21,12 +21,37 @@ export interface PluginLogger {
|
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Minimal events interface for plugin context.
|
|
24
|
+
*
|
|
25
|
+
* `emit` may return a promise. A rejection is contained and reported, just
|
|
26
|
+
* like a synchronous throw — it never fails the phase that emitted.
|
|
24
27
|
*/
|
|
25
28
|
export interface PluginEvents {
|
|
26
29
|
on(event: string, handler: (event: unknown) => void): void;
|
|
27
30
|
off(event: string, handler: (event: unknown) => void): void;
|
|
28
|
-
emit(event: string, payload: unknown): void
|
|
31
|
+
emit(event: string, payload: unknown): void | PromiseLike<unknown>;
|
|
29
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* The part of an event bus the plugin system uses — satisfied by
|
|
35
|
+
* `@zudojs/events`' `EventBus`, which can be passed wherever
|
|
36
|
+
* {@link PluginEventSource} is accepted.
|
|
37
|
+
*/
|
|
38
|
+
export interface PluginEventBus {
|
|
39
|
+
publishEvent(input: {
|
|
40
|
+
readonly type: string;
|
|
41
|
+
readonly payload: unknown;
|
|
42
|
+
}): Promise<unknown>;
|
|
43
|
+
on(eventType: string, handler: (event: {
|
|
44
|
+
readonly payload: unknown;
|
|
45
|
+
}) => unknown): {
|
|
46
|
+
unsubscribe(): void;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* What the plugin system accepts as an event source: a
|
|
51
|
+
* {@link PluginEvents} sink, or an event bus it adapts with
|
|
52
|
+
* `toPluginEvents`.
|
|
53
|
+
*/
|
|
54
|
+
export type PluginEventSource = PluginEvents | PluginEventBus;
|
|
30
55
|
/**
|
|
31
56
|
* Something a plugin registers so the manager releases it on shutdown.
|
|
32
57
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/plugins",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Plugin system for extending Zudojs applications with modular capabilities.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
"!dist/.tsbuildinfo"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@zudojs/errors": "1.
|
|
27
|
+
"@zudojs/errors": "1.3.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^26.
|
|
30
|
+
"@types/node": "^26.6.2",
|
|
31
|
+
"@zudojs/events": "1.3.0",
|
|
31
32
|
"typescript": "7.0.2",
|
|
32
|
-
"vitest": "^
|
|
33
|
+
"vitest": "^5.0.1"
|
|
33
34
|
},
|
|
34
35
|
"engines": {
|
|
35
36
|
"node": ">=24.0.0"
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"plugins",
|
|
43
44
|
"extensions"
|
|
44
45
|
],
|
|
45
|
-
"homepage": "https://
|
|
46
|
+
"homepage": "https://zudojs.oyinlola.site/docs/packages-plugins",
|
|
46
47
|
"bugs": {
|
|
47
48
|
"url": "https://github.com/oyinlola-tech/zudo/issues"
|
|
48
49
|
},
|