// Notion API — queries a database for tasks export async function fetchNotionTasks(config) { if (!config.token) throw new Error('Notion token not configured'); if (!config.projectIds || config.projectIds.length === 0) { throw new Error('Notion database ID not configured. Set a database ID in options.'); } const headers = { 'Authorization': `Bearer ${config.token}`, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json', }; const allTasks = []; for (const dbId of config.projectIds) { const res = await fetch(`https://api.notion.com/v1/databases/${dbId}/query`, { method: 'POST', headers, body: JSON.stringify({ page_size: 100 }), }); if (!res.ok) { console.warn(`Notion DB query failed for ${dbId}: ${res.status}`); continue; } const data = await res.json(); const results = data.results || []; for (const page of results) { const props = page.properties || {}; const titleProp = Object.values(props).find((p) => p.type === 'title'); const title = titleProp?.title?.[0]?.plain_text || 'Untitled'; const statusProp = Object.values(props).find((p) => p.type === 'status' || p.type === 'select' || p.type === 'checkbox'); let done = false; if (statusProp?.type === 'checkbox') done = statusProp.checkbox; else if (statusProp?.type === 'status') done = statusProp.status?.name === 'Done'; else if (statusProp?.type === 'select') done = statusProp.select?.name === 'Done'; if (done) continue; const dateProp = Object.values(props).find((p) => p.type === 'date'); const dueDate = dateProp?.date?.start ? new Date(dateProp.date.start) : null; const multiSelect = Object.values(props).filter((p) => p.type === 'multi_select'); const labels = multiSelect.flatMap((p) => p.multi_select?.map((s) => s.name) || []); const created = page.created_time ? new Date(page.created_time) : new Date(); const updated = page.last_edited_time ? new Date(page.last_edited_time) : created; allTasks.push({ id: `notion-${page.id}`, title, priority: 1, createdAt: created, updatedAt: updated, completedAt: null, dueDate, projectId: `notion-${dbId}`, projectName: dbId.slice(0, 8), labels, url: page.url, source: 'notion', raw: page, }); } } return allTasks; } export async function archiveNotionTask(taskId, token) { const realId = taskId.replace('notion-', ''); const res = await fetch(`https://api.notion.com/v1/pages/${realId}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${token}`, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json', }, body: JSON.stringify({ archived: true }), }); if (!res.ok) throw new Error(`Failed to archive Notion task: ${res.status}`); } export async function deleteNotionTask(taskId, token) { const realId = taskId.replace('notion-', ''); const res = await fetch(`https://api.notion.com/v1/blocks/${realId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}`, 'Notion-Version': '2022-06-28', }, }); if (!res.ok) throw new Error(`Failed to delete Notion task: ${res.status}`); }