/** * @fileoverview REST Hook subscribe/unsubscribe and HTTP delivery. * @module services/webhookService */ import { createWebhook, deleteWebhook } from '../store/webhooks.js'; import { createDebugger } from '../debug/logger.js'; const log = createDebugger('webhooks'); const ALLOWED_EVENTS = new Set(['timestamp.completed', 'timestamp.failed']); /** * @param {object} ctx - auth context * @param {{ targetUrl: string, event: string }} params */ export function subscribe(ctx, { targetUrl, event }) { if (!targetUrl) { throw new Error('targetUrl is required'); } if (!ALLOWED_EVENTS.has(event)) { throw new Error(`Unsupported event: ${event}`); } return createWebhook({ tenantId: ctx.tenantId, targetUrl, event, }); } /** * @param {object} ctx * @param {{ hookId?: string, targetUrl?: string }} params */ export function unsubscribe(ctx, { hookId, targetUrl }) { const removed = deleteWebhook({ tenantId: ctx.tenantId, hookId, targetUrl, }); if (!removed) { throw new Error('Webhook subscription not found'); } return { removed: true }; } /** * POST payload to Zapier target URL. * @param {string} targetUrl * @param {object} payload * @returns {Promise<{ ok: boolean, status: number }>} */ export async function deliverWebhook(targetUrl, payload) { log.debug('deliverWebhook', { targetUrl, event: payload?.event }); const response = await fetch(targetUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'User-Agent': 'Verae-Zapier-Middleware/1.0', }, body: JSON.stringify(payload), }); log.debug('deliverWebhook result', { status: response.status, ok: response.ok }); return { ok: response.ok, status: response.status }; }