@idealite/web-services
Version:
Comprehensive web services library with webhook system and Mux integration
113 lines (112 loc) • 4.23 kB
JavaScript
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;
;