Files
plugin-manager/dist/PluginLoader.d.ts
2026-04-18 21:04:28 +10:00

110 lines
4.3 KiB
TypeScript

import type { NotificationOptions } from './PluginInterfaces.js';
import type { IPluginEventClient } from './interfaces.js';
import type { PluginRegistry } from './PluginRegistry.js';
/**
* Configuration options for constructing a {@link PluginLoader}.
*
* @remarks Node.js only — this class uses `fs`, `path`, and `module` from the Node standard library.
*/
export interface PluginLoaderOptions {
/** The registry to register and wire loaded plugins into. */
registry: PluginRegistry;
/**
* Optional event client forwarded to each plugin's context.
* Any object with `on(event, handler)` / `off(event, handler)` works.
*/
eventClient?: IPluginEventClient;
/**
* Called when a plugin invokes `context.notify(...)`.
* The host is responsible for displaying the notification.
*/
onNotify?: (options: NotificationOptions) => void | Promise<void>;
}
/**
* Node.js-specific loader that discovers and registers plugins from the filesystem.
*
* Provide a directory; the loader scans each immediate subdirectory, resolves the
* entry point, imports the module (CJS or ESM), normalises it to the {@link Plugin}
* interface, and wires it into the supplied {@link PluginRegistry}.
*
* Supports:
* - Native plugins exporting `onLoad` / `onUnload`
* - Legacy plugins exporting `activate` / `deactivate` (with a compat shim)
* - `plugin-metadata.json` for stable plugin IDs
* - `package.json` `"main"` for custom entry points (falls back to `index.js`)
*
* @example
* ```ts
* const loader = new PluginLoader({ registry, eventClient: myEmitter });
* const ids = await loader.loadFromDirectory('/path/to/plugins');
* console.log('Loaded:', ids);
* ```
*/
export declare class PluginLoader {
private readonly registry;
private readonly eventClient?;
private readonly onNotify?;
constructor(options: PluginLoaderOptions);
/**
* Scans `dir` for plugin subdirectories and loads each one.
* Subdirectories that lack a recognisable entry point are silently skipped;
* those that throw during loading emit a console warning and are skipped.
*
* @param dir - Absolute path to the plugins folder.
* @returns IDs of all plugins that loaded successfully.
*/
loadFromDirectory(dir: string): Promise<string[]>;
/**
* Loads a single plugin from an absolute directory path.
*
* Resolution order for the plugin ID:
* 1. `plugin-metadata.json` → `id` field
* 2. `path.basename(pluginDir)`
*
* Resolution order for the entry point:
* 1. `package.json` → `main` field
* 2. `index.js`
*
* @param pluginDir - Absolute path to the plugin directory.
* @returns The plugin ID used for registration.
* @throws If no entry point is found or the module cannot be loaded.
*/
loadPlugin(pluginDir: string): Promise<string>;
/**
* Reads and parses `plugin-metadata.json` from the plugin directory.
* Returns `null` if the file is absent or malformed.
*
* @param pluginDir - Plugin root directory.
*/
private _readMetadata;
/**
* Resolves the JavaScript entry point for a plugin.
* Reads `main` from `package.json` when present; falls back to `index.js`.
*
* @param pluginDir - Plugin root directory.
* @throws If no entry file can be found.
*/
private _resolveEntry;
/**
* Imports a plugin module from an absolute file path.
*
* Attempts CJS evaluation first (via `new Function` with a `createRequire`-backed
* `require` shim). Falls back to native ESM `import()` on `SyntaxError`.
*
* @param filePath - Absolute path to the plugin entry file.
* @throws On load or evaluation errors that are not `SyntaxError`.
*/
private _importModule;
/**
* Normalises a raw plugin module export to the {@link Plugin} interface.
*
* - Native: object with `onLoad` function — used as-is.
* - Legacy: object with `activate` function — wrapped into `onLoad` / `onUnload`
* with a compatibility shim for removed APIs (`registerHook`, `runHook`, `getConfig`).
*
* @param raw - Raw module exports.
* @throws If the module exports neither `onLoad` nor `activate`.
*/
private _normalise;
}
//# sourceMappingURL=PluginLoader.d.ts.map