import { getSupabaseConfig, supabaseFetch } from './_supabase.js'; import { json } from './_session.js'; const PUBLIC_HEADERS = { 'access-control-allow-origin': '*', 'access-control-allow-methods': 'GET, OPTIONS', 'access-control-allow-headers': 'content-type' }; const POL_PRICE_URL = 'https://api.coinbase.com/v2/exchange-rates?currency=POL'; function sum(values) { return values.reduce((total, value) => { const numeric = Number(value); return Number.isFinite(numeric) ? total + numeric : total; }, 0); } function groupCount(rows, key) { return rows.reduce((acc, row) => { const value = row[key] || 'unknown'; acc[value] = (acc[value] || 0) + 1; return acc; }, {}); } function sumNativeByCurrency(rows) { return rows.reduce((acc, row) => { const amount = Number(row.amount_native); const currency = String(row.currency || '').trim().toUpperCase(); if (!Number.isFinite(amount) || amount <= 0 || !currency || currency === 'USD') return acc; acc[currency] = Number(((acc[currency] || 0) + amount).toFixed(8)); return acc; }, {}); } async function getUsdRateByCurrency() { try { const response = await fetch(POL_PRICE_URL, { headers: { accept: 'application/json' } }); if (!response.ok) throw new Error(`price_status_${response.status}`); const payload = await response.json(); const polUsd = Number(payload?.data?.rates?.USD); return { POL: Number.isFinite(polUsd) && polUsd > 0 ? polUsd : 0 }; } catch (error) { return { POL: 0 }; } } function normalizeLedgerRows(rows, usdRates = {}) { return rows.map((row) => { const currency = String(row.currency || '').trim().toUpperCase(); const nativeAmount = Number(row.amount_native); const explicitUsd = Number(row.amount_usd); const derivedUsd = (!Number.isFinite(explicitUsd) || explicitUsd <= 0) && Number.isFinite(nativeAmount) && nativeAmount > 0 && Number.isFinite(Number(usdRates[currency])) && Number(usdRates[currency]) > 0 ? Number((nativeAmount * Number(usdRates[currency])).toFixed(2)) : explicitUsd; return { ...row, amount_usd: Number.isFinite(derivedUsd) && derivedUsd > 0 ? derivedUsd : 0 }; }); } export async function onRequestOptions() { return new Response(null, { status: 204, headers: PUBLIC_HEADERS }); } export async function onRequestGet({ env }) { const config = getSupabaseConfig(env); if (!config) { return json({ ok: true, configured: false, generatedAt: new Date().toISOString(), totals: { donations: 0, amountUsd: 0, nativeByCurrency: {}, projects: 0, integrations: 0 }, byProvider: {}, recent: [] }, 200, PUBLIC_HEADERS); } try { const usdRates = await getUsdRateByCurrency(); const rows = await supabaseFetch( config, '/rest/v1/soulwall_ledger?select=event_id,client_id,integration_origin,provider,project_slug,project_name,tx_hash,currency,amount_usd,amount_native,network,status,confirmed_at,created_at&status=eq.confirmed&order=confirmed_at.desc.nullslast,created_at.desc&limit=1000' ); const confirmed = normalizeLedgerRows(Array.isArray(rows) ? rows : [], usdRates); const projects = new Set(confirmed.map((row) => row.project_slug || row.project_name).filter(Boolean)); const integrations = new Set(confirmed.map((row) => row.client_id || row.integration_origin).filter(Boolean)); return json({ ok: true, configured: true, generatedAt: new Date().toISOString(), totals: { donations: confirmed.length, amountUsd: Number(sum(confirmed.map((row) => row.amount_usd)).toFixed(2)), nativeByCurrency: sumNativeByCurrency(confirmed), projects: projects.size, integrations: integrations.size }, byProvider: groupCount(confirmed, 'provider'), recent: confirmed.slice(0, 25) }, 200, PUBLIC_HEADERS); } catch (error) { return json({ ok: false, configured: true, error: error?.message || 'Ledger read failed.', totals: { donations: 0, amountUsd: 0, nativeByCurrency: {}, projects: 0, integrations: 0 }, byProvider: {}, recent: [] }, 500, PUBLIC_HEADERS); } }