Files
Checkmate/server/src/service/infrastructure/notificationProviders/webhook.ts
T
2026-03-03 23:27:48 +00:00

125 lines
3.4 KiB
TypeScript

const SERVICE_NAME = "WebhookProvider";
import type { Notification } from "@/types/index.js";
import { INotificationProvider } from "@/service/index.js";
import type { NotificationMessage } from "@/types/notificationMessage.js";
import { getTestMessage } from "@/service/infrastructure/notificationProviders/utils.js";
import got from "got";
import { ILogger } from "@/utils/logger.js";
export class WebhookProvider implements INotificationProvider {
private logger: ILogger;
constructor(logger: ILogger) {
this.logger = logger;
}
sendMessage = async (notification: Notification, message: NotificationMessage): Promise<boolean> => {
if (!notification.address) {
return false;
}
// Build webhook payload from unified message
const payload = this.buildWebhookPayload(message);
try {
await got.post(notification.address, {
json: payload,
headers: {
"Content-Type": "application/json",
},
});
this.logger.info({
message: "Webhook notification sent",
service: SERVICE_NAME,
method: "sendMessage",
});
return true;
} catch (error) {
const err = error as Error;
this.logger.warn({
message: "Webhook alert failed",
service: SERVICE_NAME,
method: "sendMessage",
stack: err?.stack,
});
return false;
}
};
private buildWebhookPayload(message: NotificationMessage): object {
const lines: string[] = [];
// Title and summary
lines.push(`**${message.content.title}**`);
lines.push(message.content.summary);
lines.push("");
// Monitor information
lines.push("**Monitor Details:**");
lines.push(`- Name: ${message.monitor.name}`);
lines.push(`- URL: ${message.monitor.url}`);
lines.push(`- Type: ${message.monitor.type}`);
lines.push(`- Status: ${message.monitor.status}`);
lines.push("");
// Additional details
if (message.content.details && message.content.details.length > 0) {
lines.push("**Additional Information:**");
message.content.details.forEach((detail) => lines.push(`- ${detail}`));
lines.push("");
}
// Threshold breaches (for hardware monitors)
if (message.content.thresholds && message.content.thresholds.length > 0) {
lines.push("**Threshold Breaches:**");
message.content.thresholds.forEach((breach) => {
lines.push(`- ${breach.metric.toUpperCase()}: ${breach.formattedValue} (threshold: ${breach.threshold}${breach.unit})`);
});
lines.push("");
}
// Incident link
if (message.content.incident) {
lines.push(`[View Incident](${message.clientHost}/infrastructure/${message.monitor.id})`);
}
// Return webhook payload with both text and structured data
return {
text: lines.join("\n"),
severity: message.severity,
type: message.type,
monitor: {
id: message.monitor.id,
name: message.monitor.name,
url: message.monitor.url,
status: message.monitor.status,
},
timestamp: message.content.timestamp,
};
}
sendTestAlert = async (notification: Notification) => {
if (!notification.address) {
return false;
}
try {
await got.post(notification.address, {
json: { text: getTestMessage() },
headers: {
"Content-Type": "application/json",
},
});
return true;
} catch (error) {
const err = error as Error;
this.logger.warn({
message: "Webhook test alert failed",
service: SERVICE_NAME,
method: "sendTestAlert",
stack: err?.stack,
});
return false;
}
};
}