Files
portabase/src/features/notifications/providers/webhook.ts
T

50 lines
1.4 KiB
TypeScript
Raw Normal View History

import type { EventPayload, DispatchResult } from '../types';
type WebhookConfig = {
webhookUrl: string;
webhookHeaders?: { key: string; value: string }[];
webhookSecret?: string;
webhookSecretHeader?: string;
};
2026-01-07 13:33:23 +01:00
export async function sendWebhook(
config: WebhookConfig,
2026-01-07 13:33:23 +01:00
payload: EventPayload
): Promise<DispatchResult> {
const { webhookUrl, webhookHeaders, webhookSecret, webhookSecretHeader } = config;
2026-01-07 13:33:23 +01:00
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'User-Agent': 'Portabase-Notifier/1.0',
2026-01-07 13:33:23 +01:00
};
// New format: iterate custom headers array
if (webhookHeaders && webhookHeaders.length > 0) {
const RESERVED = new Set(['content-type', 'user-agent']);
for (const { key, value } of webhookHeaders) {
if (key && !RESERVED.has(key.toLowerCase())) headers[key] = value;
}
} else if (webhookSecret) {
// Legacy format: single secret header pair
2026-01-07 13:33:23 +01:00
headers[webhookSecretHeader || 'X-Webhook-Secret'] = webhookSecret;
}
const res = await fetch(webhookUrl, {
method: 'POST',
body: JSON.stringify(payload),
headers,
2026-01-07 13:33:23 +01:00
});
if (!res.ok) {
const err = await res.text();
throw new Error(`Webhook error: ${res.status} ${err}`);
}
return {
success: true,
provider: 'webhook',
message: 'Sent to Webhook',
response: await res.text(),
};
}