/** * Web Push Notification Sender * Sends push notifications to subscribed users */ import webpush from 'web-push' import { getPushSubscriptionsByRoles, deletePushSubscription } from './pushDb' // Configure web-push with VAPID keys const vapidPublicKey = process.env.VAPID_PUBLIC_KEY || '' const vapidPrivateKey = process.env.VAPID_PRIVATE_KEY || '' const vapidSubject = process.env.VAPID_SUBJECT || 'mailto:support@logship.de' if (vapidPublicKey && vapidPrivateKey) { webpush.setVapidDetails( vapidSubject, vapidPublicKey, vapidPrivateKey ) console.log('[WebPush] ✅ VAPID configured successfully') } else { console.warn('[WebPush] ⚠️ VAPID keys not configured - push notifications will not work') } interface PushPayload { title: string body: string icon?: string badge?: string url?: string data?: any } /** * Send push notification to specific roles */ export const sendPushToRoles = async (roleIds: number[], payload: PushPayload) => { if (!vapidPublicKey || !vapidPrivateKey) { console.warn('[WebPush] Skipping push - VAPID not configured') return { sent: 0, failed: 0, removed: 0 } } try { // Get all subscriptions for these roles const subscriptions = getPushSubscriptionsByRoles(roleIds) if (subscriptions.length === 0) { console.log('[WebPush] No subscriptions found for roles:', roleIds) return { sent: 0, failed: 0, removed: 0 } } console.log(`[WebPush] Sending to ${subscriptions.length} subscribers for roles:`, roleIds) const results = { sent: 0, failed: 0, removed: 0 } // Send to all subscriptions const promises = subscriptions.map(async (sub: any) => { try { const pushSubscription = { endpoint: sub.endpoint, keys: { p256dh: sub.p256dh, auth: sub.auth } } await webpush.sendNotification( pushSubscription, JSON.stringify(payload), { // Time-to-live: 24 hours (86400 seconds) TTL: 86400, // High urgency for immediate delivery even in background urgency: 'high', // Topic for notification grouping (optional) topic: 'new-orders' } ) results.sent++ console.log('[WebPush] ✅ Sent to:', sub.endpoint.substring(0, 50) + '...') } catch (error: any) { console.error('[WebPush] ❌ Failed to send:', error.message) // Remove subscription if it's expired (410 Gone) if (error.statusCode === 410 || error.statusCode === 404) { console.log('[WebPush] Removing expired subscription:', sub.endpoint) deletePushSubscription(sub.endpoint) results.removed++ } else { results.failed++ } } }) await Promise.all(promises) console.log('[WebPush] Results:', results) return results } catch (error: any) { console.error('[WebPush] ❌ Error sending push notifications:', error.message) return { sent: 0, failed: 0, removed: 0 } } } /** * Send push notification for new orders */ export const sendNewOrderNotification = async (roleIds: number[], orderCount: number, orderDetails?: any) => { const title = orderCount === 1 ? '🔔 New Order Received' : `🔔 ${orderCount} New Orders Received` const body = orderCount === 1 ? 'You have 1 new order waiting to be processed' : `You have ${orderCount} new orders waiting to be processed` return sendPushToRoles(roleIds, { title, body, icon: '/favicon.ico', badge: '/favicon.ico', url: '/sales/orders', data: { type: 'new_orders', count: orderCount, timestamp: Date.now(), ...orderDetails } }) }