UNPKG

@dataql/node

Version:

DataQL core SDK for unified data management with MongoDB and GraphQL - Production Multi-Cloud Ready

296 lines (295 loc) 9.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PluginRegistry = void 0; /** * Plugin Registry Implementation * * Handles plugin discovery, installation, and management. * This is the foundation for a plugin ecosystem around DataQL. */ class PluginRegistry { constructor(registryUrl = "https://registry.dataql.dev") { this.cache = new Map(); this.installed = new Map(); this.registryUrl = registryUrl; } /** * Search for plugins in the registry */ async search(query, type) { try { const params = new URLSearchParams({ q: query }); if (type) params.append("type", type); const response = await fetch(`${this.registryUrl}/search?${params}`); if (!response.ok) { throw new Error(`Registry search failed: ${response.statusText}`); } const results = await response.json(); return results.plugins || []; } catch (error) { console.error("Plugin search failed:", error); return this.searchLocal(query, type); } } /** * Get detailed information about a plugin */ async getPluginInfo(pluginId) { // Check cache first const cached = this.cache.get(pluginId); if (cached) { return cached; } try { const response = await fetch(`${this.registryUrl}/plugins/${pluginId}`); if (!response.ok) { throw new Error(`Plugin not found: ${pluginId}`); } const info = await response.json(); this.cache.set(pluginId, info); return info; } catch (error) { throw new Error(`Failed to get plugin info: ${error.message}`); } } /** * Install a plugin from the registry */ async install(pluginId, version) { try { console.log(`Installing plugin: ${pluginId}${version ? `@${version}` : ""}`); // Get plugin info const info = await this.getPluginInfo(pluginId); const targetVersion = version || info.version; // Download and install plugin await this.downloadPlugin(pluginId, targetVersion); console.log(`Plugin installed successfully: ${pluginId}@${targetVersion}`); } catch (error) { throw new Error(`Plugin installation failed: ${error.message}`); } } /** * Uninstall a plugin */ async uninstall(pluginId) { try { this.installed.delete(pluginId); this.cache.delete(pluginId); // Remove from local storage/filesystem await this.removePluginFiles(pluginId); console.log(`Plugin uninstalled: ${pluginId}`); } catch (error) { throw new Error(`Plugin uninstallation failed: ${error.message}`); } } /** * List installed plugins */ async listInstalled() { const installed = []; for (const [pluginId, plugin] of this.installed) { installed.push({ id: plugin.id, name: plugin.name, description: plugin.description, version: plugin.version, author: plugin.author, type: plugin.type, downloads: 0, rating: 0, tags: [], repository: "", homepage: "", license: "", dependencies: plugin.dependencies || [], peerDependencies: [], createdAt: new Date(), updatedAt: new Date(), }); } return installed; } /** * Update a plugin to a new version */ async update(pluginId, version) { await this.uninstall(pluginId); await this.install(pluginId, version); } /** * Publish a plugin to the registry */ async publish(plugin, manifest) { try { const publishData = { plugin: { id: plugin.id, name: plugin.name, description: plugin.description, version: plugin.version, author: plugin.author, type: plugin.type, dependencies: plugin.dependencies, }, manifest, }; const response = await fetch(`${this.registryUrl}/publish`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(publishData), }); if (!response.ok) { throw new Error(`Publish failed: ${response.statusText}`); } console.log(`Plugin published successfully: ${plugin.id}@${plugin.version}`); } catch (error) { throw new Error(`Plugin publishing failed: ${error.message}`); } } /** * Discover plugins from various sources */ async discoverPlugins(options) { const discovered = []; // Search in specified directories for (const directory of options.directories) { const plugins = await this.discoverFromDirectory(directory, options.patterns); discovered.push(...plugins); } // Auto-install missing plugins if enabled if (options.autoInstall) { for (const plugin of discovered) { if (!this.installed.has(plugin.id)) { try { await this.installLocalPlugin(plugin); } catch (error) { console.warn(`Failed to auto-install plugin ${plugin.id}:`, error.message); } } } } return discovered; } /** * Load a plugin from a manifest */ async loadFromManifest(manifest) { const { plugin: pluginConfig } = manifest.dataql; // Dynamic import of plugin const pluginModule = await import(pluginConfig.entry); const PluginClass = pluginModule.default || pluginModule[pluginConfig.name]; if (!PluginClass) { throw new Error(`Plugin class not found in ${pluginConfig.entry}`); } return new PluginClass(); } /** * Validate plugin compatibility */ validateCompatibility(plugin, dataqlVersion) { // Check if plugin is compatible with current DataQL version // This would implement semver compatibility checking return true; // Simplified for now } /** * Private: Search locally cached plugins */ searchLocal(query, type) { const results = []; const searchTerm = query.toLowerCase(); for (const info of this.cache.values()) { if (type && info.type !== type) continue; if (info.name.toLowerCase().includes(searchTerm) || info.description.toLowerCase().includes(searchTerm) || info.tags.some((tag) => tag.toLowerCase().includes(searchTerm))) { results.push(info); } } return results; } /** * Private: Download plugin from registry */ async downloadPlugin(pluginId, version) { // In a real implementation, this would: // 1. Download the plugin package // 2. Verify signatures/checksums // 3. Extract to local plugin directory // 4. Install dependencies // 5. Register plugin console.log(`Downloading ${pluginId}@${version}...`); // Simulated download await new Promise((resolve) => setTimeout(resolve, 1000)); } /** * Private: Remove plugin files */ async removePluginFiles(pluginId) { // Remove plugin files from local storage/filesystem console.log(`Removing plugin files for ${pluginId}`); } /** * Private: Discover plugins from directory */ async discoverFromDirectory(directory, patterns) { const plugins = []; try { // In a real implementation, this would: // 1. Scan directory for package.json files // 2. Check if they contain dataql.plugin configuration // 3. Load and validate plugins // 4. Return discovered plugins console.log(`Scanning directory for plugins: ${directory}`); // Simulated discovery return plugins; } catch (error) { console.warn(`Failed to discover plugins in ${directory}:`, error.message); return []; } } /** * Private: Install a locally discovered plugin */ async installLocalPlugin(plugin) { this.installed.set(plugin.id, plugin); console.log(`Auto-installed local plugin: ${plugin.id}`); } /** * Get registry statistics */ async getStats() { try { const response = await fetch(`${this.registryUrl}/stats`); if (!response.ok) { throw new Error("Failed to get registry stats"); } return await response.json(); } catch (error) { return { totalPlugins: this.cache.size, pluginsByType: {}, recentlyUpdated: [], popular: [], }; } } /** * Clear registry cache */ clearCache() { this.cache.clear(); } } exports.PluginRegistry = PluginRegistry;