@mulutime/plugin-sdk
Version:
SDK for developing MuluTime booking platform plugins
276 lines • 10.6 kB
JavaScript
"use strict";
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPlugin = exports.createManifest = exports.createEnhancedPlugin = exports.TemplateGenerator = exports.TestUtils = exports.BasePlugin = exports.PluginSDK = void 0;
exports.initializePluginSDK = initializePluginSDK;
// MuluTime Plugin SDK for external developers
const ajv_1 = __importDefault(require("ajv"));
// Import types from the shared types package
const plugin_types_1 = require("@mulutime/plugin-types");
const helpers_1 = require("./helpers");
const testUtilities_1 = require("./testUtilities");
const pluginClients_1 = require("./pluginClients");
// =============================================================================
// PLUGIN SDK CLASS
// =============================================================================
class PluginSDK {
constructor(context) {
this.context = context;
this.ajv = new ajv_1.default();
// Create HTTP client with authentication
this.httpClient = this.context.http;
}
// Logging utilities
get logger() {
return this.context.logger;
}
// Storage utilities
get storage() {
return this.context.storage;
}
// Expose setConfig utility if available
async setConfig(config) {
if (typeof this.context.setConfig === 'function') {
await this.context.setConfig(config);
}
else {
throw new Error('setConfig is not implemented in this context');
}
}
// API client utilities
get api() {
return this.context.api;
}
// Plugin configuration
get config() {
return this.context.config;
}
// Plugin permissions
get permissions() {
return this.context.permissions;
}
// HTTP client for external APIs
get http() {
return this.httpClient;
}
// Get plugin context
getContext() {
return this.context;
}
// Validate data against JSON schema
validateSchema(data, schema) {
const validate = this.ajv.compile(schema);
const valid = validate(data);
return {
valid,
errors: valid ? undefined : validate.errors?.map(err => err.message || 'Validation error')
};
}
// Check if plugin has permission
hasPermission(permission) {
return this.context.permissions.includes(permission);
}
// Require permission (throws if not available)
requirePermission(permission) {
if (!this.hasPermission(permission)) {
throw new Error(`Plugin requires permission: ${permission}`);
}
}
// Get user/organization context
getUserId() {
return this.context.userId;
}
getOrganizationId() {
return this.context.organizationId;
}
// Make authenticated API calls to the booking system
async callBookingAPI(endpoint, options = {}) {
const { method = 'GET', data, params } = options;
try {
const response = await this.httpClient.request({
url: endpoint,
method,
data,
params
});
return response.data;
}
catch (error) {
this.logger.error(`API call failed: ${endpoint}`, error);
throw error;
}
}
// Trigger a system event (if plugin has permission)
async triggerEvent(eventType, data) {
this.requirePermission(plugin_types_1.PluginPermission.SEND_NOTIFICATIONS);
await this.callBookingAPI('/api/system/events', {
method: 'POST',
data: {
eventType,
data,
source: this.context.pluginId
}
});
}
// Action system utilities (initialize on demand)
get actions() {
if (!this.actionRegistry) {
this.actionRegistry = (0, action_registry_1.createActionRegistry)();
this.actionExecutor = (0, action_executor_1.createActionExecutor)(this.actionRegistry);
}
return {
registry: this.actionRegistry,
executor: this.actionExecutor
};
}
}
exports.PluginSDK = PluginSDK;
// =============================================================================
// BASE PLUGIN CLASS
// =============================================================================
class BasePlugin {
constructor() {
this.sdk = null;
}
// ---- Domain-specific (e.g. calendar) plugin methods ----
// Plugins can override these as needed. If not implemented, throw by default.
async fetchExternalEvents(context) {
throw new Error('fetchExternalEvents is not implemented for this plugin.');
}
async createEvent(eventData, context) {
throw new Error('createEvent is not implemented for this plugin.');
}
// Initialize the plugin with SDK context and register actions
initialize(context) {
this.sdk = new PluginSDK(context);
// Auto-register actions from decorators/metadata
this.registerActions();
}
// Register plugin actions with the action system
registerActions() {
if (!this.sdk)
return;
const actions = (0, action_registry_1.extractAllActions)(this.constructor);
if (Object.keys(actions).length > 0) {
this.sdk.actions.registry.registerPlugin(this.manifest.id, actions);
}
}
// Get SDK instance
getSDK() {
if (!this.sdk) {
throw new Error('Plugin not initialized. Call initialize() first.');
}
return this.sdk;
}
// Default lifecycle implementations (can be overridden)
async onInstall(context) {
this.initialize(context);
this.getSDK().logger.info('Plugin installed');
}
async onUninstall(context) {
this.initialize(context);
this.getSDK().logger.info('Plugin uninstalled');
}
async onUpdate(context, oldVersion) {
this.initialize(context);
this.getSDK().logger.info(`Plugin updated from ${oldVersion} to ${this.manifest.version}`);
}
async onActivate(context) {
this.initialize(context);
this.getSDK().logger.info('Plugin activated');
}
async onDeactivate(context) {
this.initialize(context);
this.getSDK().logger.info('Plugin deactivated');
}
// Default validation
async validateConfig(config) {
if (this.manifest.configSchema) {
return this.getSDK().validateSchema(config, this.manifest.configSchema);
}
return { valid: true };
}
// Get configuration schema
getConfigSchema() {
return this.manifest.configSchema;
}
// Default webhook handler
async handleWebhook(context, payload) {
this.initialize(context);
this.getSDK().logger.warn('Webhook received but no handler implemented');
return { status: 'not_implemented' };
}
}
exports.BasePlugin = BasePlugin;
// =============================================================================
// ACTION SYSTEM INTEGRATION
// =============================================================================
// Export all action system components
__exportStar(require("./actions"), exports);
// Import action system for SDK integration
const action_registry_1 = require("./actions/action-registry");
const action_executor_1 = require("./actions/action-executor");
// =============================================================================
// SDK INITIALIZATION
// =============================================================================
async function initializePluginSDK(baseURL, pluginSecret) {
const api = new pluginClients_1.PluginAPIClient(baseURL, pluginSecret);
// Get context from API
const contextResponse = await api.get('/api/plugin/v1/sdk/context');
if (!contextResponse.ok) {
throw new Error(`Failed to initialize SDK: ${contextResponse.statusText}`);
}
const contextData = await contextResponse.json();
// Create SDK instances
const storage = new pluginClients_1.PluginStorageClient(api);
const logger = new pluginClients_1.PluginLoggerClient(api);
// Create full context
const context = {
userId: contextData.userId,
organizationId: contextData.organizationId,
pluginId: contextData.pluginId,
permissions: contextData.permissions || [],
config: contextData.config || {},
storage,
logger,
api,
http: contextData.http,
errors: contextData.errors,
systemBaseUrl: contextData.systemBaseUrl,
apiToken: pluginSecret // Use plugin secret as token
};
return new PluginSDK(context);
}
// =============================================================================
// EXPORTS
// =============================================================================
exports.TestUtils = new testUtilities_1.PluginTestUtils();
exports.TemplateGenerator = helpers_1.PluginTemplateGenerator;
var helpers_2 = require("./helpers");
Object.defineProperty(exports, "createEnhancedPlugin", { enumerable: true, get: function () { return helpers_2.createEnhancedPlugin; } });
Object.defineProperty(exports, "createManifest", { enumerable: true, get: function () { return helpers_2.createManifest; } });
Object.defineProperty(exports, "createPlugin", { enumerable: true, get: function () { return helpers_2.createPlugin; } });
// Re-export all types for easier access
__exportStar(require("./types"), exports);
__exportStar(require("./helpers"), exports);
__exportStar(require("./testUtilities"), exports);
__exportStar(require("./pluginClients"), exports);
// Default export
exports.default = PluginSDK;
//# sourceMappingURL=index.js.map