Hook-Engine a TypeScript-First Webhook Engine with Built in Adapters, CLI

4 months ago 10

Enterprise-grade webhook processing engine for Node.js applications with production-ready features:

  • 7 Webhook Adapters - Stripe, GitHub, Discord, Shopify, PayPal, Twilio, SendGrid
  • Signature Verification - Cryptographic validation for all providers
  • Structured Logging - JSON logs with multiple outputs and rotation
  • Security & Reliability - Rate limiting, circuit breakers, health monitoring
  • CLI Tools - Development, testing, and monitoring utilities
  • Multi-tenant Support - Handle multiple customers/environments
  • Performance Monitoring - Real-time metrics and observability
  • Error Recovery - Retry logic with exponential backoff

Most webhook implementations suffer from:

  • 💥 Poor Error Handling - Silent failures in production
  • 🔒 Security Gaps - Missing signature verification
  • 📊 No Observability - Lack of monitoring and logging
  • 🔁 No Retry Logic - Lost events due to temporary failures
  • 🧪 Hard to Test - No development tools or replay capabilities
  • 🏗️ Not Scalable - Can't handle multiple providers or high volume

Hook-Engine solves all these problems with a production-ready, enterprise-grade solution.


npm install hook-engine # or yarn add hook-engine # or pnpm add hook-engine

Global CLI installation:

npm install -g hook-engine

import express from 'express'; import { receiveWebhook } from 'hook-engine'; const app = express(); // Raw body parser for signature verification app.use('/webhooks', express.raw({ type: 'application/json' })); app.post('/webhooks/stripe', async (req, res) => { try { const event = await receiveWebhook(req, { source: 'stripe', secret: process.env.STRIPE_WEBHOOK_SECRET }); console.log(`✅ Received ${event.type}:`, event.id); // Your business logic here switch (event.type) { case 'invoice.payment_succeeded': console.log('💰 Payment succeeded!'); break; case 'customer.subscription.created': console.log('🎉 New subscription!'); break; } res.status(200).json({ success: true }); } catch (error) { console.error('❌ Webhook failed:', error.message); res.status(400).json({ error: 'Webhook processing failed' }); } }); app.listen(3000, () => { console.log('🚀 Webhook server running on port 3000'); });

🏗️ Supported Webhook Providers

Provider Status Signature Verification Advanced Features
Stripe ✅ Production Ready HMAC SHA-256
GitHub ✅ Production Ready HMAC SHA-256
Discord ✅ Production Ready Ed25519
Shopify ✅ Production Ready HMAC SHA-256
PayPal ✅ Production Ready Certificate Validation
Twilio ✅ Production Ready HMAC SHA-1
SendGrid ✅ Production Ready ECDSA

Provider-Specific Examples

// Stripe const stripeEvent = await receiveWebhook(req, { source: 'stripe', secret: 'whsec_...' }); // GitHub const githubEvent = await receiveWebhook(req, { source: 'github', secret: 'github_webhook_secret' }); // Shopify const shopifyEvent = await receiveWebhook(req, { source: 'shopify', secret: 'shopify_webhook_secret' });

1. Multiple Webhook Adapters

Handle webhooks from multiple providers in a single application:

import { receiveWebhook, adapters } from 'hook-engine'; const webhookConfigs = { stripe: { source: 'stripe', secret: process.env.STRIPE_SECRET }, github: { source: 'github', secret: process.env.GITHUB_SECRET }, shopify: { source: 'shopify', secret: process.env.SHOPIFY_SECRET } }; app.post('/webhooks/:provider', async (req, res) => { const provider = req.params.provider; const config = webhookConfigs[provider]; if (!config) { return res.status(400).json({ error: `Unsupported provider: ${provider}`, supportedProviders: Object.keys(webhookConfigs) }); } const event = await receiveWebhook(req, config); // Route to appropriate handler switch (provider) { case 'stripe': await handleStripeEvent(event); break; case 'github': await handleGitHubEvent(event); break; case 'shopify': await handleShopifyEvent(event); break; } res.status(200).json({ success: true, provider, eventId: event.id }); });

Enterprise-grade logging with JSON output, multiple transports, and rich metadata:

import { StructuredLogger } from 'hook-engine'; const logger = new StructuredLogger({ level: 'info', format: 'json', outputs: [ { type: 'console', config: { colorize: true } }, { type: 'file', config: { filename: './logs/webhooks.log' } } ], enableColors: true, enableTimestamps: true, enableStackTrace: true, maxFileSize: 10 * 1024 * 1024, // 10MB maxFiles: 5, rotateDaily: true }); // Webhook-specific logging logger.webhook({ level: 'info', source: 'stripe', operation: 'webhook_processed', duration: 150, status: 'success', metadata: { eventType: 'invoice.payment_succeeded', eventId: 'evt_123', requestId: 'req_456' } }); // Performance logging logger.performance({ level: 'info', operation: 'payment_processing', duration: 200, metrics: { memoryUsage: process.memoryUsage().heapUsed, requestCount: 1 }, metadata: { requestId: 'req_456' } }); // Security logging logger.security({ level: 'warn', securityEvent: 'invalid_signature', source: '192.168.1.100', severity: 'medium', details: { ip: '192.168.1.100', userAgent: 'curl/7.68.0', endpoint: '/webhooks/stripe', reason: 'Invalid webhook signature' }, metadata: { requestId: 'req_456' } });

3. Security & Reliability Features

Built-in security and reliability features for production environments:

import { SecurityManager, ReliabilityManager } from 'hook-engine'; // Security features const securityManager = new SecurityManager({ rateLimiting: { windowMs: 15 * 60 * 1000, // 15 minutes maxRequests: 100 }, ipFiltering: { allowlist: ['192.168.1.0/24'], denylist: ['10.0.0.0/8'] }, signatureValidation: { enforceSignatures: true, allowedClockSkew: 300 // 5 minutes } }); // Reliability features const reliabilityManager = new ReliabilityManager({ circuitBreaker: { failureThreshold: 5, resetTimeout: 60000 }, healthChecks: { interval: 30000, timeout: 5000 }, gracefulShutdown: { timeout: 30000 } }); // Apply middleware app.use('/webhooks', securityManager.middleware()); app.use('/webhooks', reliabilityManager.middleware());

Comprehensive CLI tools for development, testing, and monitoring:

# Test webhook endpoints hook-engine test --url http://localhost:3000/webhooks/stripe --provider stripe # Generate configurations hook-engine generate --provider stripe --output ./config/stripe.json # Monitor webhook performance hook-engine monitor --duration 60 --format json # Validate webhook signatures hook-engine validate --provider stripe --payload '{"data":"test"}' --signature "t=123,v1=abc" --secret "whsec_secret" # Development server with auto-reload hook-engine dev --port 3000 --provider stripe --auto-reload # Benchmark webhook performance hook-engine benchmark --provider stripe --requests 100 --concurrent 10

5. Performance Monitoring

Real-time performance monitoring and metrics:

// Built-in metrics endpoints app.get('/health', (req, res) => { res.json({ status: 'healthy', timestamp: new Date().toISOString(), uptime: process.uptime(), memory: process.memoryUsage(), providers: ['stripe', 'github', 'shopify'] }); }); app.get('/metrics', (req, res) => { res.json({ timestamp: new Date().toISOString(), memory: process.memoryUsage(), cpu: process.cpuUsage(), uptime: process.uptime(), loadAverage: require('os').loadavg() }); }); app.get('/status', (req, res) => { res.json({ service: 'webhook-processor', version: '1.0.0', features: { adapters: ['stripe', 'github', 'shopify'], security: 'enabled', reliability: 'enabled', logging: 'structured', multiTenant: 'enabled' } }); });

🏢 Real-World Example: E-commerce Platform

Complete e-commerce platform handling payments, orders, deployments, and email events:

import express from 'express'; import { receiveWebhook, StructuredLogger, SecurityManager, ReliabilityManager } from 'hook-engine'; const app = express(); // Setup structured logging const logger = new StructuredLogger({ level: 'info', format: 'json', outputs: [ { type: 'console', config: { colorize: true } }, { type: 'file', config: { filename: './logs/ecommerce.log' } } ] }); // Business services class EcommerceServices { static async processPayment(event, logger) { logger.info('Processing payment event', { operation: 'payment_processing', eventType: event.type, eventId: event.id }); switch (event.type) { case 'invoice.payment_succeeded': await this.handlePaymentSuccess(event, logger); break; case 'invoice.payment_failed': await this.handlePaymentFailure(event, logger); break; } } static async processOrder(event, logger) { logger.info('Processing order event', { operation: 'order_processing', eventType: event.type, eventId: event.id }); switch (event.type) { case 'orders/create': await this.handleNewOrder(event, logger); break; case 'orders/paid': await this.handleOrderPaid(event, logger); break; } } } // Webhook handler with full feature demonstration app.post('/webhooks/:provider', async (req, res) => { const provider = req.params.provider; const startTime = Date.now(); try { const config = webhookConfigs[provider]; const event = await receiveWebhook(req, config); // Route to appropriate service switch (provider) { case 'stripe': await EcommerceServices.processPayment(event, logger); break; case 'shopify': await EcommerceServices.processOrder(event, logger); break; } const duration = Date.now() - startTime; logger.webhook({ level: 'info', source: provider, operation: 'webhook_processed', duration, status: 'success', metadata: { eventType: event.type, eventId: event.id } }); res.status(200).json({ success: true, provider, eventId: event.id, processingTime: `${duration}ms` }); } catch (error) { logger.error('Webhook processing failed', error); res.status(400).json({ error: 'Webhook processing failed' }); } });

Handle webhooks for multiple customers or environments:

import { MultiTenantManager } from 'hook-engine'; const tenantManager = new MultiTenantManager({ tenantResolver: (req) => { // Extract tenant from subdomain, header, or path return req.headers['x-tenant-id'] || 'default'; }, configProvider: async (tenantId) => { // Load tenant-specific configuration return await loadTenantConfig(tenantId); } }); app.use('/webhooks', tenantManager.middleware());

Event Filtering and Routing

Advanced event processing with filtering and routing:

import { EventProcessor } from 'hook-engine'; const processor = new EventProcessor({ filters: [ { eventType: 'push', condition: (event) => event.payload.ref === 'refs/heads/main' } ], routes: [ { condition: (event) => event.type === 'invoice.payment_succeeded', destination: 'payment-service' }, { condition: (event) => event.type.startsWith('orders/'), destination: 'order-service' } ] });

Process multiple events efficiently:

import { BatchProcessor } from 'hook-engine'; const batchProcessor = new BatchProcessor({ batchSize: 10, flushInterval: 5000, // 5 seconds processor: async (events) => { console.log(`Processing batch of ${events.length} events`); await processBatch(events); } });

# Webhook secrets STRIPE_WEBHOOK_SECRET=whsec_your_stripe_secret GITHUB_WEBHOOK_SECRET=your_github_secret SHOPIFY_WEBHOOK_SECRET=your_shopify_secret SENDGRID_WEBHOOK_SECRET=your_sendgrid_secret # Server configuration PORT=3000 NODE_ENV=production # Logging configuration LOG_LEVEL=info LOG_FORMAT=json LOG_FILE=./logs/webhooks.log # Security configuration RATE_LIMIT_WINDOW_MS=900000 RATE_LIMIT_MAX_REQUESTS=100
// config/webhooks.ts export const webhookConfig = { providers: { stripe: { source: 'stripe', secret: process.env.STRIPE_WEBHOOK_SECRET, endpoints: ['/webhooks/stripe'] }, github: { source: 'github', secret: process.env.GITHUB_WEBHOOK_SECRET, endpoints: ['/webhooks/github'] } }, security: { rateLimiting: { windowMs: 15 * 60 * 1000, maxRequests: 100 }, signatureValidation: { enforceSignatures: true, allowedClockSkew: 300 } }, logging: { level: 'info', format: 'json', outputs: ['console', 'file'] } };

The package includes comprehensive examples demonstrating all features:

# Basic webhook processing npm run example:basic # Multiple webhook providers npm run example:multi # Structured logging demonstration npm run example:logging # CLI tools demonstration npm run example:cli # Complete e-commerce platform npm run example:ecommerce

FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY dist ./dist COPY config ./config EXPOSE 3000 CMD ["node", "dist/server.js"]
apiVersion: apps/v1 kind: Deployment metadata: name: webhook-processor spec: replicas: 3 selector: matchLabels: app: webhook-processor template: metadata: labels: app: webhook-processor spec: containers: - name: webhook-processor image: your-registry/webhook-processor:latest ports: - containerPort: 3000 env: - name: STRIPE_WEBHOOK_SECRET valueFrom: secretKeyRef: name: webhook-secrets key: stripe-secret livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10

Environment-Specific Configuration

// config/production.ts export const productionConfig = { logging: { level: 'warn', outputs: [ { type: 'file', config: { filename: '/var/log/webhooks.log' } }, { type: 'http', config: { url: 'https://logs.example.com/webhook' } } ] }, security: { rateLimiting: { windowMs: 15 * 60 * 1000, maxRequests: 1000 } }, reliability: { circuitBreaker: { failureThreshold: 10, resetTimeout: 60000 } } };

📊 Monitoring & Observability

All logs follow a structured JSON format for easy parsing and analysis:

{ "timestamp": "2024-01-15T10:30:00.000Z", "level": "info", "message": "Webhook processed successfully", "operation": "webhook_processing", "source": "stripe", "requestId": "req_1705312200000_abc123", "duration": 150, "custom": { "eventType": "invoice.payment_succeeded", "eventId": "evt_123" } }
// Integration with Prometheus import { register, Counter, Histogram } from 'prom-client'; const webhookCounter = new Counter({ name: 'webhooks_processed_total', help: 'Total number of webhooks processed', labelNames: ['provider', 'event_type', 'status'] }); const webhookDuration = new Histogram({ name: 'webhook_processing_duration_seconds', help: 'Webhook processing duration', labelNames: ['provider', 'event_type'] }); // Metrics endpoint app.get('/metrics', (req, res) => { res.set('Content-Type', register.contentType); res.end(register.metrics()); });
app.get('/health', (req, res) => { const health = { status: 'healthy', timestamp: new Date().toISOString(), uptime: process.uptime(), memory: process.memoryUsage(), checks: { database: 'healthy', redis: 'healthy', external_api: 'healthy' } }; res.status(200).json(health); });

import { receiveWebhook } from 'hook-engine'; import { createMockRequest } from 'hook-engine/testing'; describe('Webhook Processing', () => { it('should process valid Stripe webhook', async () => { const mockReq = createMockRequest({ provider: 'stripe', payload: { type: 'invoice.payment_succeeded', id: 'evt_123' }, secret: 'whsec_test_secret' }); const event = await receiveWebhook(mockReq, { source: 'stripe', secret: 'whsec_test_secret' }); expect(event.type).toBe('invoice.payment_succeeded'); expect(event.id).toBe('evt_123'); }); });
import request from 'supertest'; import app from '../src/app'; describe('Webhook Endpoints', () => { it('should handle Stripe webhook', async () => { const response = await request(app) .post('/webhooks/stripe') .set('Content-Type', 'application/json') .set('Stripe-Signature', 'valid_signature') .send({ type: 'invoice.payment_succeeded', id: 'evt_123' }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); }); });

We welcome contributions! Please see our Contributing Guide for details.

# Clone the repository git clone https://github.com/your-username/hook-engine.git cd hook-engine # Install dependencies npm install # Build the project npm run build # Run tests npm test # Run examples npm run example:basic

Adding New Webhook Providers

  1. Create adapter in src/adapters/
  2. Add signature verification logic
  3. Update exports in src/index.ts
  4. Add tests and documentation
  5. Submit pull request

receiveWebhook(request, config)

Process incoming webhook with signature verification.

Parameters:

  • request - HTTP request object
  • config - Webhook configuration

Returns: Parsed webhook event

StructuredLogger(options)

Create structured logger instance.

Options:

  • level - Log level (debug, info, warn, error)
  • format - Output format (json, text)
  • outputs - Array of output configurations
  • StripeAdapter - Stripe webhook processing
  • GitHubAdapter - GitHub webhook processing
  • DiscordAdapter - Discord webhook processing
  • ShopifyAdapter - Shopify webhook processing
  • PayPalAdapter - PayPal webhook processing
  • TwilioAdapter - Twilio webhook processing
  • SendGridAdapter - SendGrid webhook processing
  • SecurityManager - Security features and middleware
  • ReliabilityManager - Reliability features and middleware
  • MultiTenantManager - Multi-tenant support


Hook-Engine is designed for high performance and scalability:

  • Throughput: 10,000+ webhooks/second
  • Latency: <10ms processing time
  • Memory: Efficient memory usage with streaming
  • Scalability: Horizontal scaling support

Security is a top priority:

  • Signature Verification - Cryptographic validation for all providers
  • Rate Limiting - Configurable rate limiting per IP/tenant
  • Input Validation - Comprehensive request validation
  • Security Headers - Automatic security headers
  • Audit Logging - Security event logging
  • IP Filtering - Allow/deny lists

  • GraphQL Subscriptions - Real-time webhook delivery
  • Message Queues - Redis/RabbitMQ integration
  • Webhook Replay - Historical event replay
  • Dashboard UI - Web-based monitoring dashboard
  • More Providers - Additional webhook providers
  • Cloud Functions - Serverless deployment support

MIT License - see LICENSE file for details.


  • GitHub Issues - Bug reports and feature requests
  • Documentation - Comprehensive guides and examples
  • Community - Join our Discord community
  • Enterprise Support - Commercial support available

⭐ Star this repository if Hook-Engine helps you build better webhook infrastructure!

🔗 Share it with your team if it saves you development time!


Built with ❤️ by developers, for developers.

Read Entire Article