thrilled-be-core
Version:
Core Express backend package with middleware, logging, security, and base application setup
168 lines (167 loc) • 5.73 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PluginManager = void 0;
const Logger_1 = require("../logging/Logger");
class PluginManager {
plugins = new Map();
loadOrder = [];
logger;
constructor(logger) {
this.logger = logger || Logger_1.Logger.create({ level: 'info' });
}
/**
* Register a plugin with optional configuration
*/
register(plugin, config, enabled = true) {
if (this.plugins.has(plugin.name)) {
this.logger.warn(`Plugin ${plugin.name} is already registered. Skipping.`);
return this;
}
this.plugins.set(plugin.name, {
plugin,
config,
enabled,
});
this.logger.debug(`Plugin registered: ${plugin.name}@${plugin.version}`);
return this;
}
/**
* Get a registered plugin by name
*/
get(name) {
const registration = this.plugins.get(name);
return registration?.enabled ? registration.plugin : undefined;
}
/**
* Check if a plugin is registered and enabled
*/
has(name) {
const registration = this.plugins.get(name);
return Boolean(registration?.enabled);
}
/**
* Enable a plugin
*/
enable(name) {
const registration = this.plugins.get(name);
if (registration) {
registration.enabled = true;
this.logger.info(`Plugin enabled: ${name}`);
return true;
}
this.logger.warn(`Cannot enable plugin ${name}: not found`);
return false;
}
/**
* Disable a plugin
*/
disable(name) {
const registration = this.plugins.get(name);
if (registration) {
registration.enabled = false;
this.logger.info(`Plugin disabled: ${name}`);
return true;
}
this.logger.warn(`Cannot disable plugin ${name}: not found`);
return false;
}
/**
* Get list of all registered plugins
*/
list() {
return Array.from(this.plugins.entries()).map(([name, registration]) => ({
name,
version: registration.plugin.version,
enabled: registration.enabled || false,
}));
}
/**
* Sort plugins by their dependencies to determine load order
*/
calculateLoadOrder() {
const visited = new Set();
const visiting = new Set();
const order = [];
const visit = (pluginName) => {
if (visited.has(pluginName))
return;
if (visiting.has(pluginName)) {
throw new Error(`Circular dependency detected involving plugin: ${pluginName}`);
}
const registration = this.plugins.get(pluginName);
if (!registration?.enabled)
return;
visiting.add(pluginName);
// Visit dependencies first
const dependencies = registration.plugin.dependencies || [];
for (const dep of dependencies) {
if (!this.plugins.has(dep)) {
throw new Error(`Plugin ${pluginName} depends on ${dep}, but ${dep} is not registered`);
}
visit(dep);
}
visiting.delete(pluginName);
visited.add(pluginName);
order.push(pluginName);
};
// Visit all enabled plugins
for (const [name, registration] of this.plugins) {
if (registration.enabled) {
visit(name);
}
}
return order;
}
/**
* Initialize all registered and enabled plugins in dependency order
*/
async initializeAll(app) {
try {
this.loadOrder = this.calculateLoadOrder();
this.logger.info(`Initializing ${this.loadOrder.length} plugins in order: ${this.loadOrder.join(', ')}`);
for (const pluginName of this.loadOrder) {
const registration = this.plugins.get(pluginName);
if (!registration?.enabled)
continue;
const { plugin, config } = registration;
try {
this.logger.info(`Initializing plugin: ${plugin.name}@${plugin.version}`);
await plugin.register(app, config || {});
this.logger.info(`Plugin initialized successfully: ${plugin.name}`);
}
catch (error) {
this.logger.error(error, {
context: 'PluginManager.initializeAll',
plugin: plugin.name,
version: plugin.version,
});
// Decide whether to continue or fail fast based on plugin criticality
// For now, we'll continue with other plugins but log the failure
this.logger.warn(`Continuing with remaining plugins after ${plugin.name} failed to initialize`);
}
}
this.logger.info(`Plugin initialization completed. ${this.loadOrder.length} plugins processed.`);
}
catch (error) {
this.logger.error(error, {
context: 'PluginManager.initializeAll',
});
throw error;
}
}
/**
* Get the load order of plugins (useful for debugging)
*/
getLoadOrder() {
return [...this.loadOrder];
}
/**
* Clear all registered plugins
*/
clear() {
this.plugins.clear();
this.loadOrder = [];
this.logger.debug('All plugins cleared from manager');
}
}
exports.PluginManager = PluginManager;