// utils/pushService.js const webpush = require('web-push'); const db = require('../db'); const hasVapid = !!process.env.VAPID_PUBLIC_KEY && !!process.env.VAPID_PRIVATE_KEY; if (!hasVapid) { console.warn('[Push] VAPID keys não definidas. Push desativado.'); } else { webpush.setVapidDetails( process.env.VAPID_SUBJECT || 'mailto:admin@evstation.local', process.env.VAPID_PUBLIC_KEY, process.env.VAPID_PRIVATE_KEY ); } // retry simples p/ 429 e 5xx async function sendWithRetry(subscription, message, tries = 2) { try { return await webpush.sendNotification(subscription, message); } catch (err) { const code = err?.statusCode; if ((code === 429 || code >= 500) && tries > 1) { await new Promise((r) => setTimeout(r, 1000)); return sendWithRetry(subscription, message, tries - 1); } throw err; } } async function sendPushToUser(userId, payload) { if (!hasVapid) return; const subs = await db('push_subscriptions') .where({ user_id: userId }) .select('id', 'endpoint', 'p256dh', 'auth'); if (!subs.length) return; const message = JSON.stringify(payload); await Promise.allSettled( subs.map(async (s) => { const subscription = { endpoint: s.endpoint, keys: { p256dh: s.p256dh, auth: s.auth, }, }; try { await sendWithRetry(subscription, message); // TTL opcional (default 15min) // se quiseres usar TTL do payload, descomenta e passa options no sendWithRetry // await webpush.sendNotification(subscription, message, { // TTL: payload.ttl ?? 60 * 15, // }); } catch (err) { const code = err?.statusCode; // remove subscriptions mortas if (code === 404 || code === 410) { await db('push_subscriptions').where({ id: s.id }).del(); } else { console.error('[Push] erro ao enviar:', err.message); } } }) ); } module.exports = { sendPushToUser };