diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c7c379a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,107 @@ +{ + "name": "@pluginhost/core", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@pluginhost/core", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "node-fetch": "^3.3.2" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + } + } +} diff --git a/src/PluginHost.js b/src/PluginHost.js index 34723d9..367def1 100644 --- a/src/PluginHost.js +++ b/src/PluginHost.js @@ -1,9 +1,13 @@ import { EventEmitter } from 'events'; import { readdir, readFile, mkdir } from 'fs/promises'; -import { join, resolve } from 'path'; +import { join, resolve, dirname } from 'path'; import { existsSync } from 'fs'; +import { fileURLToPath } from 'url'; import fetch from 'node-fetch'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + /** * Plugin Host - Manages plugin lifecycle and provides plugin API */ @@ -11,7 +15,10 @@ export class PluginHost extends EventEmitter { constructor(options = {}) { super(); this.directoryUrl = options.directoryUrl; - this.pluginsDir = resolve(options.pluginsDir || './plugins'); + // Resolve relative to the PluginHost.js file location (src/), then go up one level + this.pluginsDir = options.pluginsDir ? + (options.pluginsDir.startsWith('.') ? resolve(__dirname, '..', options.pluginsDir) : resolve(options.pluginsDir)) + : resolve(__dirname, '../plugins'); this.autoUpdate = options.autoUpdate ?? true; this.updateInterval = options.updateInterval || 300000; @@ -42,18 +49,32 @@ export class PluginHost extends EventEmitter { */ async updateRegistry() { try { - const response = await fetch(this.directoryUrl); - if (!response.ok) { - console.warn('Failed to fetch plugin registry:', response.statusText); + // First fetch the index to get the list of available plugins + const indexUrl = `${this.directoryUrl}/index.json`; + const indexResponse = await fetch(indexUrl); + + if (!indexResponse.ok) { + console.warn('Failed to fetch plugin index:', indexResponse.statusText); return; } - const html = await response.text(); - const pluginFiles = this._parseDirectoryListing(html); + const index = await indexResponse.json(); + const pluginIds = index.plugins || []; + + console.log(`Found ${pluginIds.length} plugins in directory`); - for (const file of pluginFiles) { - if (file.endsWith('.json')) { - await this._fetchPluginDefinition(file); + // Fetch each plugin definition + for (const pluginId of pluginIds) { + const pluginUrl = `${this.directoryUrl}/${pluginId}.json`; + try { + const response = await fetch(pluginUrl); + if (response.ok) { + const plugin = await response.json(); + this.pluginRegistry.set(plugin.id, plugin); + console.log(` āœ“ ${plugin.name} v${plugin.version}`); + } + } catch (error) { + console.warn(` āœ— Could not fetch ${pluginId}:`, error.message); } } diff --git a/src/index.js b/src/index.js index c4245de..9c11eb3 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,22 @@ import { PluginHost } from './PluginHost.js'; const host = new PluginHost({ directoryUrl: 'http://synbox.ruv.wtf:8418/litruv/Plugin-Directory/raw/branch/main/plugins', pluginsDir: './plugins', - autoUpdate: true, + autoUpdate: true, // Auto-fetch registry updates updateInterval: 300000 // 5 minutes }); +console.log('šŸ”Œ Initializing Plugin Host...\n'); + await host.initialize(); await host.loadPlugins(); -console.log('Plugin Host initialized with plugins:', host.getLoadedPlugins().map(p => p.name)); +console.log('\nšŸ“Š Plugin Host Status:'); +console.log('===================='); +console.log('Loaded plugins:', host.getLoadedPlugins().map(p => `${p.name} v${p.version}`).join(', ') || 'none'); +console.log('Plugin directory:', host.pluginsDir); +console.log('\nšŸ“¦ Available in Registry:', host.getRegistry().length); +host.getRegistry().forEach(p => { + console.log(` - ${p.name} v${p.version} (${p.id})`); +}); + +console.log('\n✨ Plugin Host ready!');