@dataql/node
Version:
DataQL core SDK for unified data management with MongoDB and GraphQL - Production Multi-Cloud Ready
329 lines (328 loc) • 11.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
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 Promise.resolve(`${pluginConfig.entry}`).then(s => __importStar(require(s)));
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;