import webpush from "web-push"; import { readFileSync, writeFileSync, existsSync } from "node:fs"; import { resolve } from "node:path"; const SUBS_FILE = resolve("/Users/ace/palacering/palaces/manglasabang/secretariat/keychain/push-subscriptions.json"); const vapidPublic = process.env.VAPID_PUBLIC_KEY; const vapidPrivate = process.env.VAPID_PRIVATE_KEY; let configured = false; function ensureVapid() { if (configured) return true; if (!vapidPublic || !vapidPrivate) return false; webpush.setVapidDetails("mailto:ace@manglasabang.com", vapidPublic, vapidPrivate); configured = true; return true; } export async function notifyThreadDone(subject: string) { if (!ensureVapid()) return; let subs: any[]; try { subs = JSON.parse(readFileSync(SUBS_FILE, "utf8")); } catch { return; } const body = subject.length > 100 ? subject.slice(0, 97) + "..." : subject; const payload = JSON.stringify({ title: "Palace Code", body: `Done: ${body}`, tag: `palacecode-done-${Date.now()}`, url: "/code/", }); const dead: string[] = []; for (const sub of subs) { if (!sub.endpoint || sub.endpoint.includes("test.example.com")) continue; try { await webpush.sendNotification(sub, payload); } catch (e: any) { if (e.statusCode === 410 || e.statusCode === 404) dead.push(sub.endpoint); } } if (dead.length > 0 && existsSync(SUBS_FILE)) { const alive = subs.filter((s: any) => !dead.includes(s.endpoint)); writeFileSync(SUBS_FILE, JSON.stringify(alive, null, 2)); } }