/** * Webhook handler with modular callback system */ import logger from './logger.js'; export class WebhookHandler { constructor() { this.callbacks = new Map(); this.globalCallbacks = []; } /** * Register a callback for a specific event type * @param {string} eventType - The Gogs event type (e.g., 'push', 'create', 'delete') * @param {Function} callback - Function to handle the event (payload, headers) => void */ on(eventType, callback) { if (!this.callbacks.has(eventType)) { this.callbacks.set(eventType, []); } this.callbacks.get(eventType).push(callback); logger.info(`Registered callback for event: ${eventType}`); } /** * Register a global callback that runs for all events * @param {Function} callback - Function to handle any event (eventType, payload, headers) => void */ onAny(callback) { this.globalCallbacks.push(callback); logger.info('Registered global callback'); } /** * Process an incoming webhook * @param {string} eventType - The event type from X-Gogs-Event header * @param {object} payload - The parsed webhook payload * @param {object} headers - Request headers */ async handle(eventType, payload, headers) { logger.webhook(eventType, payload); // Execute global callbacks for (const callback of this.globalCallbacks) { try { await callback(eventType, payload, headers); } catch (error) { logger.error('Error in global callback', error); } } // Execute event-specific callbacks const callbacks = this.callbacks.get(eventType); if (callbacks && callbacks.length > 0) { for (const callback of callbacks) { try { await callback(payload, headers); } catch (error) { logger.error(`Error in callback for event '${eventType}'`, error); } } } } /** * Get count of registered callbacks */ getStats() { return { globalCallbacks: this.globalCallbacks.length, eventCallbacks: Object.fromEntries( Array.from(this.callbacks.entries()).map(([event, cbs]) => [event, cbs.length]) ) }; } }