"use node"; import { action } from "../_generated/server"; import { v } from "convex/values"; import { internal } from "../_generated/api"; /** * Enviar push notification usando Web Push API */ export const enviarPush = action({ args: { subscriptionId: v.id("pushSubscriptions"), titulo: v.string(), corpo: v.string(), data: v.optional( v.object({ conversaId: v.optional(v.string()), mensagemId: v.optional(v.string()), tipo: v.optional(v.string()), }) ), }, returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }), handler: async (ctx, args) => { try { // Buscar subscription const subscription = await ctx.runQuery(internal.pushNotifications.getSubscriptionById, { subscriptionId: args.subscriptionId, }); if (!subscription || !subscription.ativo) { return { sucesso: false, erro: "Subscription não encontrada ou inativa" }; } // Web Push requer VAPID keys (deve estar em variáveis de ambiente) // Por enquanto, vamos usar uma implementação básica // Em produção, você precisará configurar VAPID keys const webpush = await import("web-push"); // VAPID keys devem vir de variáveis de ambiente const publicKey = process.env.VAPID_PUBLIC_KEY; const privateKey = process.env.VAPID_PRIVATE_KEY; if (!publicKey || !privateKey) { console.warn("⚠️ VAPID keys não configuradas. Push notifications não funcionarão."); // Em desenvolvimento, podemos retornar sucesso sem enviar return { sucesso: true }; } webpush.setVapidDetails("mailto:suporte@sgse.app", publicKey, privateKey); // Preparar payload da notificação const payload = JSON.stringify({ title: args.titulo, body: args.corpo, icon: "/favicon.png", badge: "/favicon.png", data: args.data || {}, tag: args.data?.conversaId || "default", requireInteraction: args.data?.tipo === "mencao", // Menções requerem interação }); // Enviar push notification await webpush.sendNotification( { endpoint: subscription.endpoint, keys: { p256dh: subscription.keys.p256dh, auth: subscription.keys.auth, }, }, payload ); console.log(`✅ Push notification enviada para ${subscription.endpoint}`); return { sucesso: true }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error("❌ Erro ao enviar push notification:", errorMessage); // Se subscription inválida, marcar como inativa if (errorMessage.includes("410") || errorMessage.includes("expired")) { await ctx.runMutation(internal.pushNotifications.marcarSubscriptionInativa, { subscriptionId: args.subscriptionId, }); } return { sucesso: false, erro: errorMessage }; } }, });