@mulutime/plugin-sdk
Version:
SDK for developing MuluTime booking platform plugins
423 lines • 15.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ActionRegistry = void 0;
exports.createActionRegistry = createActionRegistry;
exports.extractAllActions = extractAllActions;
const event_handler_1 = require("./event-handler");
const scheduled_handler_1 = require("./scheduled-handler");
const api_handler_1 = require("./api-handler");
const lifecycle_handler_1 = require("./lifecycle-handler");
class ActionRegistry {
constructor(options = {}) {
this.registeredPlugins = new Map();
this.options = {
enableEventHandling: true,
enableScheduledActions: true,
enableAPIActions: true,
enableLifecycleActions: true,
...options
};
// Initialize handlers
this.eventHandler = new event_handler_1.EventActionHandler(options.eventHandlerOptions);
this.scheduledHandler = new scheduled_handler_1.ScheduledActionHandler(options.scheduledHandlerOptions);
this.apiHandler = new api_handler_1.APIActionHandler(options.apiHandlerOptions);
this.lifecycleHandler = new lifecycle_handler_1.LifecycleActionHandler(options.lifecycleHandlerOptions);
}
/**
* Register all actions for a plugin
*/
registerPlugin(pluginId, actions) {
this.registeredPlugins.set(pluginId, actions);
// Register event actions
if (this.options.enableEventHandling && actions.eventActions) {
this.eventHandler.registerMany(actions.eventActions);
}
// Register scheduled actions
if (this.options.enableScheduledActions && actions.scheduledActions) {
this.scheduledHandler.registerMany(actions.scheduledActions);
}
// Register API actions
if (this.options.enableAPIActions && actions.apiActions) {
this.apiHandler.registerMany(actions.apiActions);
}
// Register lifecycle actions
if (this.options.enableLifecycleActions && actions.lifecycleActions) {
this.lifecycleHandler.register(pluginId, actions.lifecycleActions);
}
}
/**
* Unregister all actions for a plugin
*/
unregisterPlugin(pluginId) {
const actions = this.registeredPlugins.get(pluginId);
if (!actions) {
return;
}
// Unregister event actions
if (actions.eventActions) {
actions.eventActions.forEach(action => {
this.eventHandler.unregister(action.eventType, action.handler);
});
}
// Unregister scheduled actions
if (actions.scheduledActions) {
actions.scheduledActions.forEach(action => {
this.scheduledHandler.unregister(action.name);
});
}
// Unregister API actions
if (actions.apiActions) {
actions.apiActions.forEach(action => {
this.apiHandler.unregister(action.method, action.path);
});
}
// Unregister lifecycle actions
this.lifecycleHandler.unregister(pluginId);
this.registeredPlugins.delete(pluginId);
}
/**
* Register a single event action
*/
registerEventAction(pluginId, action) {
if (!this.options.enableEventHandling)
return;
const actions = this.registeredPlugins.get(pluginId) || {};
if (!actions.eventActions) {
actions.eventActions = [];
}
actions.eventActions.push(action);
this.registeredPlugins.set(pluginId, actions);
this.eventHandler.register(action);
}
/**
* Register a single scheduled action
*/
registerScheduledAction(pluginId, action) {
if (!this.options.enableScheduledActions)
return;
const actions = this.registeredPlugins.get(pluginId) || {};
if (!actions.scheduledActions) {
actions.scheduledActions = [];
}
actions.scheduledActions.push(action);
this.registeredPlugins.set(pluginId, actions);
this.scheduledHandler.register(action);
}
/**
* Register a single API action
*/
registerAPIAction(pluginId, action) {
if (!this.options.enableAPIActions)
return;
const actions = this.registeredPlugins.get(pluginId) || {};
if (!actions.apiActions) {
actions.apiActions = [];
}
actions.apiActions.push(action);
this.registeredPlugins.set(pluginId, actions);
this.apiHandler.register(action);
}
/**
* Register lifecycle actions
*/
registerLifecycleActions(pluginId, actions) {
if (!this.options.enableLifecycleActions)
return;
const pluginActions = this.registeredPlugins.get(pluginId) || {};
pluginActions.lifecycleActions = actions;
this.registeredPlugins.set(pluginId, pluginActions);
this.lifecycleHandler.register(pluginId, actions);
}
/**
* Get the event handler
*/
getEventHandler() {
return this.eventHandler;
}
/**
* Get the scheduled action handler
*/
getScheduledHandler() {
return this.scheduledHandler;
}
/**
* Get the API action handler
*/
getAPIHandler() {
return this.apiHandler;
}
/**
* Get the lifecycle action handler
*/
getLifecycleHandler() {
return this.lifecycleHandler;
}
/**
* Get actions for a specific plugin
*/
getPluginActions(pluginId) {
return this.registeredPlugins.get(pluginId);
}
/**
* Get all registered plugins
*/
getRegisteredPlugins() {
return Array.from(this.registeredPlugins.keys());
}
/**
* Check if a plugin is registered
*/
isPluginRegistered(pluginId) {
return this.registeredPlugins.has(pluginId);
}
/**
* Enable a plugin's scheduled actions
*/
enablePluginScheduledActions(pluginId, context) {
const actions = this.registeredPlugins.get(pluginId);
if (actions?.scheduledActions) {
actions.scheduledActions.forEach(action => {
this.scheduledHandler.enable(action.name);
});
this.scheduledHandler.start(context);
}
}
/**
* Disable a plugin's scheduled actions
*/
disablePluginScheduledActions(pluginId) {
const actions = this.registeredPlugins.get(pluginId);
if (actions?.scheduledActions) {
actions.scheduledActions.forEach(action => {
this.scheduledHandler.disable(action.name);
});
}
}
/**
* Execute a scheduled action immediately
*/
async executeScheduledActionNow(pluginId, actionName, context) {
const actions = this.registeredPlugins.get(pluginId);
if (!actions?.scheduledActions) {
throw new Error(`Plugin ${pluginId} has no scheduled actions`);
}
const action = actions.scheduledActions.find(a => a.name === actionName);
if (!action) {
throw new Error(`Scheduled action ${actionName} not found for plugin ${pluginId}`);
}
await this.scheduledHandler.executeNow(actionName, context);
}
/**
* Get comprehensive statistics
*/
getStats() {
const eventStats = this.eventHandler.getStats();
const scheduledStats = this.scheduledHandler.getStats();
const apiStats = this.apiHandler.getStats();
const lifecycleStats = this.lifecycleHandler.getStats();
return {
plugins: this.registeredPlugins.size,
eventActions: eventStats.totalHandlers,
scheduledActions: scheduledStats.totalActions,
apiActions: apiStats.totalActions,
lifecycleActions: Object.keys(lifecycleStats.executionsByAction).length,
totalExecutions: scheduledStats.totalExecutions +
apiStats.totalExecutions +
lifecycleStats.totalExecutions
};
}
/**
* Get detailed statistics for a specific plugin
*/
getPluginStats(pluginId) {
const actions = this.registeredPlugins.get(pluginId);
if (!actions) {
return {
eventActions: 0,
scheduledActions: 0,
apiActions: 0,
hasLifecycleActions: false,
scheduledExecutions: 0,
apiExecutions: 0,
lifecycleExecutions: 0
};
}
const scheduledHistory = this.scheduledHandler.getExecutionHistory();
const apiHistory = this.apiHandler.getExecutionLogs();
const lifecycleHistory = this.lifecycleHandler.getExecutionHistory(pluginId);
return {
eventActions: actions.eventActions?.length || 0,
scheduledActions: actions.scheduledActions?.length || 0,
apiActions: actions.apiActions?.length || 0,
hasLifecycleActions: !!actions.lifecycleActions,
scheduledExecutions: scheduledHistory.filter(e => actions.scheduledActions?.some(a => a.name === e.actionName)).length,
apiExecutions: apiHistory.length, // This could be filtered by plugin-specific API paths
lifecycleExecutions: lifecycleHistory.length
};
}
/**
* Validate plugin actions before registration
*/
validatePluginActions(pluginId, actions) {
const errors = [];
const warnings = [];
// Validate plugin ID
if (!pluginId || pluginId.trim().length === 0) {
errors.push('Plugin ID is required');
}
// Validate event actions
if (actions.eventActions) {
actions.eventActions.forEach((action, index) => {
if (!action.eventType) {
errors.push(`Event action ${index}: eventType is required`);
}
if (!action.handler) {
errors.push(`Event action ${index}: handler is required`);
}
if (typeof action.handler !== 'function') {
errors.push(`Event action ${index}: handler must be a function`);
}
});
}
// Validate scheduled actions
if (actions.scheduledActions) {
const actionNames = new Set();
actions.scheduledActions.forEach((action, index) => {
if (!action.name) {
errors.push(`Scheduled action ${index}: name is required`);
}
else if (actionNames.has(action.name)) {
errors.push(`Scheduled action ${index}: duplicate action name "${action.name}"`);
}
else {
actionNames.add(action.name);
}
if (!action.schedule) {
errors.push(`Scheduled action ${index}: schedule is required`);
}
if (!action.handler) {
errors.push(`Scheduled action ${index}: handler is required`);
}
if (typeof action.handler !== 'function') {
errors.push(`Scheduled action ${index}: handler must be a function`);
}
// Validate time format for specific schedules
if (action.schedule === 'DAILY' && action.time) {
const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/;
if (!timeRegex.test(action.time)) {
errors.push(`Scheduled action ${index}: invalid time format "${action.time}". Use HH:MM format`);
}
}
});
}
// Validate API actions
if (actions.apiActions) {
const endpoints = new Set();
actions.apiActions.forEach((action, index) => {
if (!action.path) {
errors.push(`API action ${index}: path is required`);
}
if (!action.method) {
errors.push(`API action ${index}: method is required`);
}
if (!action.handler) {
errors.push(`API action ${index}: handler is required`);
}
if (typeof action.handler !== 'function') {
errors.push(`API action ${index}: handler must be a function`);
}
if (action.path && action.method) {
const endpoint = `${action.method}:${action.path}`;
if (endpoints.has(endpoint)) {
errors.push(`API action ${index}: duplicate endpoint "${endpoint}"`);
}
else {
endpoints.add(endpoint);
}
}
// Validate HTTP method
const validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'];
if (action.method && !validMethods.includes(action.method)) {
errors.push(`API action ${index}: invalid HTTP method "${action.method}"`);
}
});
}
// Validate lifecycle actions
if (actions.lifecycleActions) {
const lifecycleAction = actions.lifecycleActions;
Object.entries(lifecycleAction).forEach(([key, handler]) => {
if (handler && typeof handler !== 'function') {
errors.push(`Lifecycle action ${key}: must be a function`);
}
});
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
/**
* Clear all registered actions
*/
clear() {
this.eventHandler.clear();
this.scheduledHandler.clear();
this.apiHandler.clear();
this.lifecycleHandler.clear();
this.registeredPlugins.clear();
}
/**
* Start all scheduled actions for all plugins
*/
startAllScheduledActions(context) {
if (this.options.enableScheduledActions) {
this.scheduledHandler.start(context);
}
}
/**
* Stop all scheduled actions
*/
stopAllScheduledActions() {
if (this.options.enableScheduledActions) {
this.scheduledHandler.stop();
}
}
/**
* Get health status of the action registry
*/
getHealthStatus() {
// This is a simplified health check
// In a production system, you'd check for actual health indicators
return {
status: 'healthy',
details: {
eventHandler: 'healthy',
scheduledHandler: 'healthy',
apiHandler: 'healthy',
lifecycleHandler: 'healthy'
},
registeredPlugins: this.registeredPlugins.size
};
}
}
exports.ActionRegistry = ActionRegistry;
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
function createActionRegistry(options) {
return new ActionRegistry(options);
}
function extractAllActions(pluginClass) {
const eventActions = pluginClass.__eventActions || [];
const scheduledActions = pluginClass.__scheduledActions || [];
const apiActions = pluginClass.__apiActions || [];
const lifecycleActions = pluginClass.__lifecycleActions || {};
return {
eventActions: eventActions.length > 0 ? eventActions : undefined,
scheduledActions: scheduledActions.length > 0 ? scheduledActions : undefined,
apiActions: apiActions.length > 0 ? apiActions : undefined,
lifecycleActions: Object.keys(lifecycleActions).length > 0 ? lifecycleActions : undefined
};
}
//# sourceMappingURL=action-registry.js.map