Compare commits

..

2 Commits

Author SHA1 Message Date
zv
763de7fd05 fix: handle notification endpoint failures 2026-06-12 21:33:41 +02:00
zv
11e9e01b53 docs: add conventional commit guidance 2026-06-12 21:29:43 +02:00
3 changed files with 52 additions and 35 deletions

View File

@@ -101,6 +101,7 @@ Przy zmianach UI:
- Przy zmianach PWA sprawdź spójność `public/manifest.json`, `public/sw.js` i rejestracji service workera.
- Przed zakończeniem uruchom co najmniej `npm run lint` i `npm run build`. Jeśli dodano testy, uruchom także ich skrypt.
- Sprawdź `git diff --check` oraz `git status`. Nie commituj wygenerowanego churnu w `next-env.d.ts`.
- Po każdej zmianie rób commit i używaj formatu Conventional Commits, np. `fix: correct warning filtering`.
- Ważne decyzje o źródłach danych, ograniczeniach API, uruchamianiu i wdrożeniu dokumentuj krótko w `README.md`.
## Utrzymywanie pliku

View File

@@ -26,6 +26,10 @@ function isCronAuthorized(request: Request) {
return authHeader === `Bearer ${secret}` || secretHeader === secret;
}
function getErrorMessage(error: unknown) {
return error instanceof Error ? error.message : "Unknown notification check error.";
}
export async function GET(request: Request) {
if (!isCronAuthorized(request)) {
return NextResponse.json({ error: "Unauthorized." }, { status: 401 });
@@ -34,44 +38,51 @@ export async function GET(request: Request) {
return NextResponse.json({ error: "Web Push is not configured." }, { status: 503 });
}
const now = Date.now();
const warnings = (await fetchMeteoWarnings(AbortSignal.timeout(12_000))).filter((warning) => isRelevantWarning(warning, now));
const subscriptions = getPushSubscriptions().filter((subscription) => subscription.enabled);
const activeWarningIds = new Set(warnings.map((warning) => warning.id));
let sent = 0;
let skipped = 0;
let failed = 0;
try {
const now = Date.now();
const warnings = (await fetchMeteoWarnings(AbortSignal.timeout(12_000))).filter((warning) => isRelevantWarning(warning, now));
const subscriptions = getPushSubscriptions().filter((subscription) => subscription.enabled);
const activeWarningIds = new Set(warnings.map((warning) => warning.id));
let sent = 0;
let skipped = 0;
let failed = 0;
pruneSentWarnings(activeWarningIds);
pruneSentWarnings(activeWarningIds);
for (const subscription of subscriptions) {
const matchingWarnings = warnings.filter((warning) => (
subscription.countyTeryt ? warningMatchesCounty(warning, subscription.countyTeryt) : warning.provinces.includes(subscription.province)
));
for (const warning of matchingWarnings) {
if (hasSentWarning(subscription.endpoint, warning.id)) {
skipped += 1;
continue;
}
for (const subscription of subscriptions) {
const matchingWarnings = warnings.filter((warning) => (
subscription.countyTeryt ? warningMatchesCounty(warning, subscription.countyTeryt) : warning.provinces.includes(subscription.province)
));
for (const warning of matchingWarnings) {
if (hasSentWarning(subscription.endpoint, warning.id)) {
skipped += 1;
continue;
}
try {
await sendWarningNotification(subscription, warning);
markWarningSent(subscription.endpoint, warning.id);
sent += 1;
} catch (error) {
failed += 1;
const statusCode = typeof error === "object" && error !== null && "statusCode" in error ? Number(error.statusCode) : null;
if (statusCode === 404 || statusCode === 410) removePushSubscription(subscription.endpoint);
try {
await sendWarningNotification(subscription, warning);
markWarningSent(subscription.endpoint, warning.id);
sent += 1;
} catch (error) {
failed += 1;
const statusCode = typeof error === "object" && error !== null && "statusCode" in error ? Number(error.statusCode) : null;
if (statusCode === 404 || statusCode === 410) removePushSubscription(subscription.endpoint);
}
}
}
}
return NextResponse.json({
ok: true,
subscriptions: subscriptions.length,
warnings: warnings.length,
sent,
skipped,
failed,
});
return NextResponse.json({
ok: true,
subscriptions: subscriptions.length,
warnings: warnings.length,
sent,
skipped,
failed,
});
} catch (error) {
return NextResponse.json({
error: "Unable to check IMGW meteorological warnings.",
details: getErrorMessage(error),
}, { status: 502 });
}
}

View File

@@ -42,7 +42,11 @@ export async function GET(request: Request) {
&& Number.isFinite(subscription.latitude)
&& Number.isFinite(subscription.longitude)
));
const warnings = await fetchMeteoWarnings(AbortSignal.timeout(12_000));
let warningsUnavailable = false;
const warnings = await fetchMeteoWarnings(AbortSignal.timeout(12_000)).catch(() => {
warningsUnavailable = true;
return [];
});
let sent = 0;
let skipped = 0;
let failed = 0;
@@ -82,6 +86,7 @@ export async function GET(request: Request) {
ok: true,
date: dateKey,
subscriptions: subscriptions.length,
warningsUnavailable,
sent,
skipped,
failed,