import { NextResponse } from "next/server"; import { upsertPushSubscription, removePushSubscription } from "@/lib/push-store"; import { isWebPushConfigured } from "@/lib/push-service"; import { normalizeProvinceName } from "@/lib/provinces"; import { DEFAULT_TEMPERATURE_UNIT, DEFAULT_WIND_SPEED_UNIT, isTemperatureUnit, isWindSpeedUnit } from "@/lib/weather-utils"; import type { Language } from "@/lib/i18n"; import type { BrowserPushSubscription } from "@/types/notifications"; import type { WeatherRegion } from "@/types/weather-region"; export const runtime = "nodejs"; function isBrowserPushSubscription(value: unknown): value is BrowserPushSubscription { if (!value || typeof value !== "object") return false; const subscription = value as Partial; 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; region?: unknown; language?: unknown; enabled?: unknown; morningBriefEnabled?: unknown; tomorrowBriefEnabled?: unknown; latitude?: unknown; longitude?: unknown; locationName?: unknown; timezone?: unknown; countyTeryt?: unknown; temperatureUnit?: unknown; windSpeedUnit?: unknown; } | null; const subscription = body?.subscription; const region: WeatherRegion = body?.region === "GLOBAL" ? "GLOBAL" : "PL"; const province = normalizeProvinceName(typeof body?.province === "string" ? body.province : null); const language: Language = body?.language === "en" ? "en" : "pl"; const rawTemperatureUnit = body?.temperatureUnit; const rawWindSpeedUnit = body?.windSpeedUnit; const enabled = body?.enabled !== false && region === "PL"; if (!isBrowserPushSubscription(subscription) || (enabled && !province)) { return NextResponse.json({ error: "Invalid push subscription." }, { status: 400 }); } const now = new Date().toISOString(); upsertPushSubscription({ endpoint: subscription.endpoint, subscription, province, region, language, enabled, morningBriefEnabled: body?.morningBriefEnabled === true, tomorrowBriefEnabled: body?.tomorrowBriefEnabled === 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, timezone: typeof body?.timezone === "string" && body.timezone.trim() ? body.timezone.trim().slice(0, 80) : null, countyTeryt: typeof body?.countyTeryt === "string" && /^\d{4}$/.test(body.countyTeryt) ? body.countyTeryt : null, temperatureUnit: isTemperatureUnit(rawTemperatureUnit) ? rawTemperatureUnit : DEFAULT_TEMPERATURE_UNIT, windSpeedUnit: isWindSpeedUnit(rawWindSpeedUnit) ? rawWindSpeedUnit : DEFAULT_WIND_SPEED_UNIT, 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 }); }