- Bidirectional Monday.com integration with column mapping and file uploads - Generic webhook system with HMAC-SHA256 signing and configurable events - Field-level activity log with diff tracking on card detail page - Persistent notification center with unread badge in header - Event dispatcher wired into OCR pipeline, card edits, exports, and deletes - New Prisma models: ActivityLog, Notification; new fields on AppSettings and ResponseCard - Settings UI with full Monday.com and webhook configuration panels Made-with: Cursor
39 lines
991 B
TypeScript
39 lines
991 B
TypeScript
import { createHmac } from "crypto";
|
|
|
|
export async function sendWebhook(
|
|
url: string,
|
|
secret: string,
|
|
event: string,
|
|
card: Record<string, unknown>
|
|
): Promise<{ ok: boolean; status?: number; error?: string }> {
|
|
const payload = JSON.stringify({
|
|
event,
|
|
timestamp: new Date().toISOString(),
|
|
card,
|
|
});
|
|
|
|
const headers: Record<string, string> = {
|
|
"Content-Type": "application/json",
|
|
};
|
|
|
|
if (secret) {
|
|
const sig = createHmac("sha256", secret).update(payload).digest("hex");
|
|
headers["X-Webhook-Signature"] = sig;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch(url, {
|
|
method: "POST",
|
|
headers,
|
|
body: payload,
|
|
signal: AbortSignal.timeout(10_000),
|
|
});
|
|
if (!res.ok) {
|
|
return { ok: false, status: res.status, error: `HTTP ${res.status}` };
|
|
}
|
|
return { ok: true, status: res.status };
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : "Request failed";
|
|
return { ok: false, error: message };
|
|
}
|
|
}
|