fix browser notifications + make them work when browser is closed
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import webpush from "web-push";
|
||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
import { ensureDataDir } from "../paths";
|
||||
import { logger } from "../logger";
|
||||
|
||||
let vapidKeys: { publicKey: string; privateKey: string } | null = null;
|
||||
|
||||
function getVapidPath(): string {
|
||||
return resolve(ensureDataDir(), "vapid-keys.json");
|
||||
}
|
||||
|
||||
export function loadOrGenerateVapidKeys(): { publicKey: string; privateKey: string } {
|
||||
if (vapidKeys) return vapidKeys;
|
||||
|
||||
const vapidPath = getVapidPath();
|
||||
|
||||
if (existsSync(vapidPath)) {
|
||||
try {
|
||||
const raw = readFileSync(vapidPath, "utf-8");
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed.publicKey && parsed.privateKey) {
|
||||
vapidKeys = { publicKey: parsed.publicKey, privateKey: parsed.privateKey };
|
||||
logger.info("[web-push] loaded VAPID keys from " + vapidPath);
|
||||
return vapidKeys;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.warn("[web-push] failed to read vapid-keys.json, regenerating", err);
|
||||
}
|
||||
}
|
||||
|
||||
const generated = webpush.generateVAPIDKeys();
|
||||
vapidKeys = { publicKey: generated.publicKey, privateKey: generated.privateKey };
|
||||
|
||||
try {
|
||||
writeFileSync(vapidPath, JSON.stringify(vapidKeys, null, 2));
|
||||
logger.info("[web-push] generated and saved VAPID keys to " + vapidPath);
|
||||
} catch (err) {
|
||||
logger.warn("[web-push] failed to persist VAPID keys", err);
|
||||
}
|
||||
|
||||
return vapidKeys;
|
||||
}
|
||||
|
||||
export function getVapidPublicKey(): string {
|
||||
return loadOrGenerateVapidKeys().publicKey;
|
||||
}
|
||||
|
||||
export async function sendWebPush(
|
||||
subscription: { endpoint: string; keys: { p256dh: string; auth: string } },
|
||||
payload: string,
|
||||
): Promise<{ success: boolean; gone?: boolean; error?: string }> {
|
||||
const keys = loadOrGenerateVapidKeys();
|
||||
webpush.setVapidDetails("mailto:overlord@localhost", keys.publicKey, keys.privateKey);
|
||||
|
||||
try {
|
||||
await webpush.sendNotification(subscription, payload, { TTL: 60 * 60 });
|
||||
return { success: true };
|
||||
} catch (err: any) {
|
||||
const statusCode = err?.statusCode;
|
||||
if (statusCode === 404 || statusCode === 410) {
|
||||
return { success: false, gone: true, error: `subscription gone (${statusCode})` };
|
||||
}
|
||||
return { success: false, error: err?.message || String(err) };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user