import webpush, { type PushSubscription, WebPushError } from "web-push"; import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message"; import { parsePhoneNumber } from "awesome-phonenumber"; import { type NotificationSubscription, Direction } from "@prisma/client"; import serverConfig from "~/config/config.server"; import db from "~/utils/db.server"; import logger from "~/utils/logger.server"; import { translateMessageDirection } from "~/utils/twilio.server"; export type NotificationPayload = Omit & { title: string; // max 50 characters body: string; // max 150 characters data: { recipient: string; type: "message" | "call"; }; }; export async function notify(subscriptions: NotificationSubscription[], payload: NotificationPayload) { webpush.setVapidDetails("mailto:mokht@rmi.al", serverConfig.webPush.publicKey, serverConfig.webPush.privateKey); const title = truncate(payload.title, 50); const body = truncate(payload.body, 150); const _payload = JSON.stringify({ ...payload, title, body, }); await Promise.all( subscriptions.map(async (subscription) => { const webPushSubscription: PushSubscription = { endpoint: subscription.endpoint, keys: { p256dh: subscription.keys_p256dh, auth: subscription.keys_auth, }, }; try { await webpush.sendNotification(webPushSubscription, _payload); } catch (error: any) { logger.error(error); if (error instanceof WebPushError) { // subscription most likely expired or has been revoked await db.notificationSubscription.delete({ where: { id: subscription.id } }); } } }), ); } function truncate(str: string, maxLength: number) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength - 1) + "\u2026"; } export function buildMessageNotificationPayload(message: MessageInstance): NotificationPayload { const direction = translateMessageDirection(message.direction); const recipient = direction === Direction.Outbound ? message.to : message.from; return { title: parsePhoneNumber(recipient).getNumber("international"), body: message.body, actions: [ { action: "reply", title: "Reply", }, ], data: { recipient, type: "message" }, }; }