Files
wtr/app/api/notifications/subscriptions/route.ts

68 lines
2.6 KiB
TypeScript

import { NextResponse } from "next/server";
import { upsertPushSubscription, removePushSubscription } from "@/lib/push-store";
import { isWebPushConfigured } from "@/lib/push-service";
import { normalizeProvinceName } from "@/lib/provinces";
import type { Language } from "@/lib/i18n";
import type { BrowserPushSubscription } from "@/types/notifications";
export const runtime = "nodejs";
function isBrowserPushSubscription(value: unknown): value is BrowserPushSubscription {
if (!value || typeof value !== "object") return false;
const subscription = value as Partial<BrowserPushSubscription>;
return typeof subscription.endpoint === "string"
&& subscription.endpoint.startsWith("https://")
&& typeof subscription.keys?.p256dh === "string"
&& typeof subscription.keys.auth === "string";
}
export async function POST(request: Request) {
if (!isWebPushConfigured()) {
return NextResponse.json({ error: "Web Push is not configured." }, { status: 503 });
}
const body = await request.json().catch(() => null) as {
subscription?: unknown;
province?: unknown;
language?: unknown;
enabled?: unknown;
morningBriefEnabled?: unknown;
latitude?: unknown;
longitude?: unknown;
locationName?: unknown;
} | null;
const subscription = body?.subscription;
const province = normalizeProvinceName(typeof body?.province === "string" ? body.province : null);
const language: Language = body?.language === "en" ? "en" : "pl";
if (!isBrowserPushSubscription(subscription) || !province) {
return NextResponse.json({ error: "Invalid push subscription." }, { status: 400 });
}
const now = new Date().toISOString();
upsertPushSubscription({
endpoint: subscription.endpoint,
subscription,
province,
language,
enabled: body?.enabled !== false,
morningBriefEnabled: body?.morningBriefEnabled === true,
latitude: typeof body?.latitude === "number" && Number.isFinite(body.latitude) ? body.latitude : null,
longitude: typeof body?.longitude === "number" && Number.isFinite(body.longitude) ? body.longitude : null,
locationName: typeof body?.locationName === "string" && body.locationName.trim() ? body.locationName.trim().slice(0, 80) : null,
createdAt: now,
updatedAt: now,
});
return NextResponse.json({ ok: true });
}
export async function DELETE(request: Request) {
const body = await request.json().catch(() => null) as { endpoint?: unknown } | null;
if (typeof body?.endpoint !== "string" || !body.endpoint) {
return NextResponse.json({ error: "Invalid push subscription endpoint." }, { status: 400 });
}
removePushSubscription(body.endpoint);
return NextResponse.json({ ok: true });
}