import config from "./config.js"; import { getRpcServer } from "./rpc/server.js"; import { PluginAPI, RPCMethod, Plugin } from "./types.js"; import slugify from "slugify"; import { dynImport } from "./util"; let pluginApi: PluginApiManager; let globby: typeof import("globby").globby; const sanitizeName = (name: string) => slugify(name, { lower: true, strict: true }); export class PluginApiManager { private registeredPlugins: Map = new Map(); public async loadPlugin(moduleName: string): Promise { moduleName = sanitizeName(moduleName); if (this.registeredPlugins.has(moduleName)) { return this.registeredPlugins.get(moduleName) as Plugin; } const paths = await globby([`${moduleName}.js`, "${moduleName}.mjs"], { cwd: config.get("plugin-folder"), }); if (!paths.length) { throw new Error(`Plugin ${moduleName} does not exist`); } let plugin: Plugin; try { plugin = (await import(paths.shift() as string)) as Plugin; } catch (e) { throw e; } plugin.name = sanitizeName(plugin.name); this.registeredPlugins.set(plugin.name, plugin); try { plugin.plugin(this.getPluginAPI(plugin.name)); } catch (e) { throw e; } return plugin; } private getPluginAPI(pluginName: string): PluginAPI { return { config, registerMethod: (methodName: string, method: RPCMethod): void => { getRpcServer().registerMethod(pluginName, methodName, method); }, loadPlugin: getPluginAPI().loadPlugin, getMethods: getRpcServer().getMethods, }; } } export function getPluginAPI(): PluginApiManager { if (!pluginApi) { pluginApi = new PluginApiManager(); } return pluginApi as PluginApiManager; } export async function loadPlugins() { globby = ((await dynImport("globby")) as typeof import("globby")).globby; for (const plugin of config.array("plugins")) { await getPluginAPI().loadPlugin(plugin); } }