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; } /** * 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; /** * 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; /** * 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