| import webpush from 'web-push'; |
| import { prisma } from './prisma'; |
| import { logger } from '../logger'; |
|
|
| |
| const publicVapidKey = process.env.VAPID_PUBLIC_KEY; |
| const privateVapidKey = process.env.VAPID_PRIVATE_KEY; |
| const contactEmail = process.env.VAPID_EMAIL || 'mailto:support@xamle.studio'; |
|
|
| if (publicVapidKey && privateVapidKey) { |
| webpush.setVapidDetails(contactEmail, publicVapidKey, privateVapidKey); |
| } else { |
| logger.warn('[PUSH-SERVICE] VAPID keys are missing. Push notifications will not work.'); |
| |
| } |
|
|
| export const pushService = { |
| |
| |
| |
| async subscribe(userId: string, organizationId: string, subscription: any) { |
| return prisma.pushSubscription.upsert({ |
| where: { endpoint: subscription.endpoint }, |
| update: { |
| userId, |
| organizationId, |
| p256dh: subscription.keys.p256dh, |
| auth: subscription.keys.auth |
| }, |
| create: { |
| userId, |
| organizationId, |
| endpoint: subscription.endpoint, |
| p256dh: subscription.keys.p256dh, |
| auth: subscription.keys.auth |
| } |
| }); |
| }, |
|
|
| |
| |
| |
| async notifyOrganization(organizationId: string, title: string, body: string, icon?: string) { |
| const subscriptions = await prisma.pushSubscription.findMany({ |
| where: { organizationId } |
| }); |
|
|
| const payload = JSON.stringify({ |
| title, |
| body, |
| icon: icon || 'https://xamle.studio/logo.png', |
| timestamp: Date.now() |
| }); |
|
|
| const results = await Promise.allSettled( |
| subscriptions.map((sub: any) => { |
| const pushConfig = { |
| endpoint: sub.endpoint, |
| keys: { |
| p256dh: sub.p256dh, |
| auth: sub.auth |
| } |
| }; |
|
|
| return webpush.sendNotification(pushConfig, payload); |
| }) |
| ); |
|
|
| |
| for (let i = 0; i < results.length; i++) { |
| if (results[i].status === 'rejected') { |
| const error = (results[i] as PromiseRejectedResult).reason; |
| if (error.statusCode === 410 || error.statusCode === 404) { |
| logger.info(`[PUSH-SERVICE] Removing expired subscription: ${subscriptions[i].endpoint}`); |
| await prisma.pushSubscription.delete({ where: { id: subscriptions[i].id } }).catch(() => {}); |
| } |
| } |
| } |
| } |
| }; |
|
|