Spaces:
Paused
Paused
File size: 4,000 Bytes
35743bd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | /**
* Database module: Webhooks
* CRUD operations for webhook event subscriptions
*/
import { getDbInstance } from "./core";
import crypto from "crypto";
export interface Webhook {
id: string;
url: string;
events: string[];
secret: string | null;
enabled: boolean;
description: string;
created_at: string;
last_triggered_at: string | null;
last_status: number | null;
failure_count: number;
}
interface WebhookRow {
id: string;
url: string;
events: string;
secret: string | null;
enabled: number;
description: string;
created_at: string;
last_triggered_at: string | null;
last_status: number | null;
failure_count: number;
}
function rowToWebhook(row: WebhookRow): Webhook {
return {
...row,
events: JSON.parse(row.events || '["*"]'),
enabled: row.enabled === 1,
};
}
export function getWebhooks(): Webhook[] {
const db = getDbInstance();
const rows = db.prepare("SELECT * FROM webhooks ORDER BY created_at DESC").all() as WebhookRow[];
return rows.map(rowToWebhook);
}
export function getWebhook(id: string): Webhook | null {
const db = getDbInstance();
const row = db.prepare("SELECT * FROM webhooks WHERE id = ?").get(id) as WebhookRow | undefined;
return row ? rowToWebhook(row) : null;
}
export function getEnabledWebhooks(): Webhook[] {
const db = getDbInstance();
const rows = db.prepare("SELECT * FROM webhooks WHERE enabled = 1").all() as WebhookRow[];
return rows.map(rowToWebhook);
}
export function createWebhook(data: {
url: string;
events?: string[];
secret?: string;
description?: string;
}): Webhook {
const db = getDbInstance();
const id = crypto.randomUUID();
const secret = data.secret || `whsec_${crypto.randomBytes(24).toString("hex")}`;
db.prepare(
`INSERT INTO webhooks (id, url, events, secret, description)
VALUES (?, ?, ?, ?, ?)`
).run(id, data.url, JSON.stringify(data.events || ["*"]), secret, data.description || "");
return getWebhook(id)!;
}
export function updateWebhook(
id: string,
data: Partial<{
url: string;
events: string[];
secret: string;
enabled: boolean;
description: string;
}>
): Webhook | null {
const db = getDbInstance();
const existing = getWebhook(id);
if (!existing) return null;
const fields: string[] = [];
const values: any[] = [];
if (data.url !== undefined) {
fields.push("url = ?");
values.push(data.url);
}
if (data.events !== undefined) {
fields.push("events = ?");
values.push(JSON.stringify(data.events));
}
if (data.secret !== undefined) {
fields.push("secret = ?");
values.push(data.secret);
}
if (data.enabled !== undefined) {
fields.push("enabled = ?");
values.push(data.enabled ? 1 : 0);
}
if (data.description !== undefined) {
fields.push("description = ?");
values.push(data.description);
}
if (fields.length === 0) return existing;
values.push(id);
db.prepare(`UPDATE webhooks SET ${fields.join(", ")} WHERE id = ?`).run(...values);
return getWebhook(id);
}
export function deleteWebhook(id: string): boolean {
const db = getDbInstance();
const result = db.prepare("DELETE FROM webhooks WHERE id = ?").run(id);
return (result as any).changes > 0;
}
export function recordWebhookDelivery(id: string, status: number, success: boolean): void {
const db = getDbInstance();
if (success) {
db.prepare(
`UPDATE webhooks SET last_triggered_at = datetime('now'), last_status = ?, failure_count = 0 WHERE id = ?`
).run(status, id);
} else {
db.prepare(
`UPDATE webhooks SET last_triggered_at = datetime('now'), last_status = ?, failure_count = failure_count + 1 WHERE id = ?`
).run(status, id);
}
}
export function disableWebhooksWithHighFailures(threshold = 10): number {
const db = getDbInstance();
const result = db
.prepare(`UPDATE webhooks SET enabled = 0 WHERE failure_count >= ? AND enabled = 1`)
.run(threshold);
return (result as any).changes;
}
|