UNPKG

@idealite/web-services

Version:

Comprehensive web services library with webhook system and Mux integration

113 lines (112 loc) 4.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExpressWebhookReceiver = void 0; const base_webhook_receiver_abstract_1 = require("../abstracts/base-webhook-receiver.abstract"); /** * Express-based webhook receiver implementation * Handles webhook reception in Express.js applications */ class ExpressWebhookReceiver extends base_webhook_receiver_abstract_1.BaseWebhookReceiver { unknownTypeHandler; /** * Set custom handler for unknown webhook types */ setUnknownTypeHandler(handler) { this.unknownTypeHandler = handler; } /** * Handle unknown webhook types */ async handleUnknownType(payload) { if (this.unknownTypeHandler) { await this.unknownTypeHandler(payload); } else { console.warn(`No handler registered for webhook type: ${payload.type}`, { payloadId: payload.id, timestamp: payload.timestamp, }); } } /** * Create Express middleware for webhook handling */ createMiddleware() { return async (req, res, _next) => { try { // Verify webhook if signature is present const signature = req.headers['x-webhook-signature']; const secret = req.headers['x-webhook-secret']; if (signature && secret) { const rawBody = JSON.stringify(req.body); const sigStr = Array.isArray(signature) ? signature[0] : signature; const secretStr = Array.isArray(secret) ? secret[0] : secret; if (!this.verifyWebhook(rawBody, sigStr || '', secretStr || '')) { res.status(401).json({ error: 'Invalid webhook signature' }); return; } } // Process the webhook const payload = this.normalizePayload(req.body); await this.processWebhook(payload); res.status(200).json({ success: true, processed: payload.id }); } catch (error) { console.error('Webhook processing error:', error); res.status(500).json({ error: 'Webhook processing failed', message: error instanceof Error ? error.message : 'Unknown error', }); } }; } /** * Normalize incoming payload to match WebhookPayload interface */ normalizePayload(body) { // If already in correct format, return as-is if (this.isValidWebhookPayload(body)) { return body; } // Otherwise, create a normalized payload const bodyObj = body; return { id: bodyObj?.id || this.generateId(), timestamp: bodyObj?.timestamp || new Date().toISOString(), type: bodyObj?.type || bodyObj?.event_type || 'unknown', data: bodyObj?.data || bodyObj, metadata: bodyObj?.metadata || {}, }; } /** * Check if payload matches WebhookPayload interface */ isValidWebhookPayload(payload) { return (typeof payload === 'object' && payload !== null && typeof payload.id === 'string' && typeof payload.timestamp === 'string' && typeof payload.type === 'string' && typeof payload.data === 'object'); } /** * Generate a unique ID for webhook payloads */ generateId() { return `webhook_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Override error handling to provide more Express-specific logging */ handleError(error, handler, payload) { console.error('Express webhook handler error:', { error: error instanceof Error ? error.message : error, stack: error instanceof Error ? error.stack : undefined, handlerType: handler.type, payloadId: payload.id, payloadType: payload.type, timestamp: new Date().toISOString(), }); } } exports.ExpressWebhookReceiver = ExpressWebhookReceiver;