112 lines
4.2 KiB
JavaScript
112 lines
4.2 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.pluginRegistry = void 0;
|
|
const logger_1 = require("../config/logger");
|
|
/**
|
|
* Registry central dos plugins.
|
|
* Gerencia o lifecycle (activate/deactivate) e expõe metadados para a API admin.
|
|
*/
|
|
class PluginRegistry {
|
|
entries = new Map();
|
|
ctx;
|
|
/** Deve ser chamado uma vez no bootstrap com o contexto completo */
|
|
setContext(ctx) {
|
|
this.ctx = ctx;
|
|
}
|
|
/** Registra plugins carregados (sem ativar ainda) */
|
|
register(plugins) {
|
|
for (const { instance, manifest, dir } of plugins) {
|
|
this.entries.set(manifest.name, { instance, manifest, active: false, dir });
|
|
}
|
|
}
|
|
/** Ativa todos os plugins marcados como enabled no manifest.
|
|
* Plugins com dependências faltando são pulados com warning (não crasham o servidor). */
|
|
async activateAll() {
|
|
for (const [name, entry] of this.entries) {
|
|
if (!entry.manifest.enabled)
|
|
continue;
|
|
try {
|
|
await this.activate(name);
|
|
}
|
|
catch (err) {
|
|
logger_1.logger.warn({ name, err: err.message }, '[PluginRegistry] Plugin pulado na inicialização');
|
|
}
|
|
}
|
|
}
|
|
async activate(name) {
|
|
const entry = this.entries.get(name);
|
|
if (!entry)
|
|
throw new Error(`Plugin "${name}" não encontrado`);
|
|
if (entry.active)
|
|
return;
|
|
// Verifica dependências
|
|
for (const dep of entry.manifest.dependencies) {
|
|
const depEntry = this.entries.get(dep);
|
|
if (!depEntry?.active) {
|
|
throw new Error(`Dependência "${dep}" do plugin "${name}" não está ativa`);
|
|
}
|
|
}
|
|
try {
|
|
await entry.instance.activate(this.ctx);
|
|
entry.active = true;
|
|
entry.manifest.enabled = true;
|
|
logger_1.logger.info({ name }, '[PluginRegistry] Plugin ativado');
|
|
}
|
|
catch (err) {
|
|
logger_1.logger.error({ err, name }, '[PluginRegistry] Falha ao ativar plugin');
|
|
throw err;
|
|
}
|
|
}
|
|
async deactivate(name) {
|
|
const entry = this.entries.get(name);
|
|
if (!entry)
|
|
throw new Error(`Plugin "${name}" não encontrado`);
|
|
if (!entry.active)
|
|
return;
|
|
if (!entry.manifest.canDisable)
|
|
throw new Error(`Plugin "${name}" não pode ser desativado`);
|
|
// Verifica se algum plugin ativo depende deste
|
|
for (const [depName, depEntry] of this.entries) {
|
|
if (depEntry.active && depEntry.manifest.dependencies.includes(name)) {
|
|
throw new Error(`Plugin "${depName}" depende de "${name}". Desative-o primeiro.`);
|
|
}
|
|
}
|
|
try {
|
|
await entry.instance.deactivate(this.ctx);
|
|
entry.active = false;
|
|
entry.manifest.enabled = false;
|
|
logger_1.logger.info({ name }, '[PluginRegistry] Plugin desativado');
|
|
}
|
|
catch (err) {
|
|
logger_1.logger.error({ err, name }, '[PluginRegistry] Falha ao desativar plugin');
|
|
throw err;
|
|
}
|
|
}
|
|
/** Retorna lista de todos os plugins com status para a API admin */
|
|
list() {
|
|
return Array.from(this.entries.entries()).map(([name, entry]) => ({ name, ...entry }));
|
|
}
|
|
getEntry(name) {
|
|
return this.entries.get(name);
|
|
}
|
|
/**
|
|
* Força reativação de um plugin sem passar pelo deactivate.
|
|
* Útil quando canDisable=false mas a config foi atualizada e precisa ser relida.
|
|
*/
|
|
async reactivate(name) {
|
|
const entry = this.entries.get(name);
|
|
if (!entry)
|
|
throw new Error(`Plugin "${name}" não encontrado`);
|
|
entry.active = false;
|
|
await this.activate(name);
|
|
logger_1.logger.info({ name }, '[PluginRegistry] Plugin reativado com nova config');
|
|
}
|
|
/** Retorna menu items de todos os plugins ativos */
|
|
getActiveMenuItems() {
|
|
return Array.from(this.entries.values())
|
|
.filter((e) => e.active && e.manifest.frontend?.menuItems?.length)
|
|
.map((e) => ({ pluginName: e.manifest.name, items: e.manifest.frontend }));
|
|
}
|
|
}
|
|
exports.pluginRegistry = new PluginRegistry();
|