// "Let Daisy handle it" on quick add: tell Daisy's routine about the new task. // Configured in /etc/personal-website/prod.env: // DAISY_TASK_WEBHOOK_URL where to POST {task_id, title} // DAISY_TASK_WEBHOOK_KEY secret sent with it // DAISY_TASK_WEBHOOK_HEADER header name (default Authorization, sent as "Bearer "; // any other header gets the bare key) // Unset URL or key: nothing is sent and the task is still saved. export type DaisyHookConfig = { url: string; headers: Record }; export function daisyHookConfig(env: Record = process.env) { const url = env.DAISY_TASK_WEBHOOK_URL?.trim(); const key = env.DAISY_TASK_WEBHOOK_KEY?.trim(); if (!url || !key) return null; const header = env.DAISY_TASK_WEBHOOK_HEADER?.trim() || 'Authorization'; const value = header.toLowerCase() === 'authorization' ? `Bearer ${key}` : key; return { url, headers: { 'content-type': 'application/json', [header]: value } }; } /** Fire and forget: never awaited by the request, 3 s timeout, failures only logged. */ export function notifyDaisy( task: { id: number; title: string }, config: DaisyHookConfig | null = daisyHookConfig(), fetcher: typeof fetch = fetch ): 'sent' | 'not-configured' { if (!config) return 'not-configured'; fetcher(config.url, { method: 'POST', headers: config.headers, body: JSON.stringify({ task_id: task.id, title: task.title }), signal: AbortSignal.timeout(3000) }) .then((res) => { if (!res.ok) console.error(`[daisy-hook] task ${task.id}: HTTP ${res.status}`); }) .catch((err) => console.error(`[daisy-hook] task ${task.id}: ${String(err)}`)); return 'sent'; }