From 7258a5da9b134518b0980191d7f83119fdba58bd Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Thu, 10 Apr 2025 01:52:42 +0000 Subject: [PATCH] Add webhook delivery logging to track webhook delivery success and failures. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/a898ba77-0ead-4328-8588-855dadf1612d.jpg --- server/storage.ts | 82 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/server/storage.ts b/server/storage.ts index f10cb49..0ffa670 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -6,7 +6,8 @@ import { type Provider, type InsertProvider, type ApiToken, type InsertApiToken, type DnsHistory, - type Webhook, type InsertWebhook + type Webhook, type InsertWebhook, + type WebhookDeliveryLog, type InsertWebhookDeliveryLog } from "@shared/schema"; import session from "express-session"; import { DatabaseStorage } from "./database-storage"; @@ -88,6 +89,7 @@ export class MemStorage implements IStorage { private apiTokensMap: Map; private historyMap: Map; private webhooksMap: Map; + private webhookDeliveryLogsMap: Map; // Counters for IDs private userIdCounter: number; @@ -98,6 +100,7 @@ export class MemStorage implements IStorage { private apiTokenIdCounter: number; private historyIdCounter: number; private webhookIdCounter: number; + private webhookDeliveryLogIdCounter: number; public sessionStore: any; @@ -110,6 +113,7 @@ export class MemStorage implements IStorage { this.apiTokensMap = new Map(); this.historyMap = new Map(); this.webhooksMap = new Map(); + this.webhookDeliveryLogsMap = new Map(); this.userIdCounter = 1; this.orgIdCounter = 1; @@ -119,6 +123,7 @@ export class MemStorage implements IStorage { this.apiTokenIdCounter = 1; this.historyIdCounter = 1; this.webhookIdCounter = 1; + this.webhookDeliveryLogIdCounter = 1; // Session store is created in the DatabaseStorage class this.sessionStore = null; @@ -503,9 +508,39 @@ export class MemStorage implements IStorage { if (!webhook || !webhook.isActive) return false; try { + // Using the webhook utility to deliver the webhook + const { generateSignature, deliverWebhook } = await import('./utils/webhook'); + // In a real implementation, this would make an HTTP request to the webhook URL console.log(`Triggering webhook ${webhook.name} (${webhook.id}) with payload:`, payload); + // Generate signature for the payload if a secret is set + const signature = webhook.secret ? generateSignature(payload, webhook.secret) : ''; + + // In a real implementation, this would make the actual HTTP request + // For now, simulate a successful delivery + const deliveryResult = { + success: true, + statusCode: 200, + message: 'Webhook delivered successfully (simulated)', + timestamp: new Date(), + responseBody: JSON.stringify({ success: true }), + retryCount: 0 + }; + + // Log the delivery attempt + await this.addWebhookDeliveryLog({ + webhookId: webhook.id, + event: payload.event || 'unknown', + payload, + signature, + status: deliveryResult.success, + statusCode: deliveryResult.statusCode, + message: deliveryResult.message, + responseBody: deliveryResult.responseBody, + retryCount: deliveryResult.retryCount + }); + // Update the lastTriggered timestamp const updatedWebhook = { ...webhook, @@ -516,9 +551,54 @@ export class MemStorage implements IStorage { return true; } catch (error) { console.error(`Error triggering webhook ${webhook.id}:`, error); + + // Log the failed delivery attempt + await this.addWebhookDeliveryLog({ + webhookId: webhook.id, + event: payload.event || 'unknown', + payload, + signature: '', + status: false, + message: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, + retryCount: 0 + }); + return false; } } + + // Webhook Delivery Logs + async addWebhookDeliveryLog(log: InsertWebhookDeliveryLog): Promise { + const numId = this.webhookDeliveryLogIdCounter++; + const createdAt = new Date(); + + const newLog: WebhookDeliveryLog = { + id: numId.toString(), + webhookId: log.webhookId, + event: log.event, + payload: log.payload, + signature: log.signature || null, + status: log.status, + statusCode: log.statusCode || null, + message: log.message, + responseBody: log.responseBody || null, + retryCount: log.retryCount || 0, + createdAt + }; + + this.webhookDeliveryLogsMap.set(numId, newLog); + return newLog; + } + + async getWebhookDeliveryLog(id: string): Promise { + return this.webhookDeliveryLogsMap.get(parseInt(id)); + } + + async getWebhookDeliveryLogsByWebhook(webhookId: string): Promise { + return Array.from(this.webhookDeliveryLogsMap.values()) + .filter(log => log.webhookId === webhookId) + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); + } } export const storage = new DatabaseStorage();