UNPKG

@mulutime/plugin-sdk

Version:

SDK for developing MuluTime booking platform plugins

423 lines 15.9 kB
"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