Files
wtr/lib/imgw-api.ts

75 lines
2.9 KiB
TypeScript

import {
normalizeHydroStation,
normalizeSynopStation,
normalizeWarning,
} from "@/lib/weather-utils";
import type {
HydroStation,
MeteoStationPosition,
RawHydroStation,
RawMeteoStation,
RawSynopStation,
RawWarning,
SynopStation,
WeatherWarning,
WarningKind,
} from "@/types/imgw";
async function getJson<T>(path: string, signal?: AbortSignal): Promise<T> {
const response = await fetch(`/api/imgw/${path}`, { signal });
if (!response.ok) {
const details = await response.text().catch(() => "");
throw new Error(details || `IMGW API zwróciło status ${response.status}.`);
}
return response.json() as Promise<T>;
}
export async function fetchSynopStations(signal?: AbortSignal): Promise<SynopStation[]> {
const rows = await getJson<RawSynopStation[]>("synop", signal);
return rows.map(normalizeSynopStation).filter((station): station is SynopStation => station !== null);
}
export async function fetchSynopStation(id: string, signal?: AbortSignal): Promise<SynopStation> {
const row = await getJson<RawSynopStation>(`synop/id/${encodeURIComponent(id)}`, signal);
const station = normalizeSynopStation(row);
if (!station) throw new Error("IMGW zwróciło niekompletne dane stacji.");
return station;
}
export async function fetchHydroStations(signal?: AbortSignal): Promise<HydroStation[]> {
const rows = await getJson<RawHydroStation[]>("hydro", signal);
return rows.map(normalizeHydroStation).filter((station): station is HydroStation => station !== null);
}
export async function fetchMeteoStationPositions(signal?: AbortSignal): Promise<MeteoStationPosition[]> {
const rows = await getJson<RawMeteoStation[]>("meteo", signal);
return rows.flatMap((row) => {
const latitude = Number(row.lat);
const longitude = Number(row.lon);
if (!row.nazwa_stacji?.trim() || !Number.isFinite(latitude) || !Number.isFinite(longitude)) return [];
return [{ name: row.nazwa_stacji, latitude, longitude }];
});
}
async function fetchWarningsByKind(kind: WarningKind, signal?: AbortSignal): Promise<WeatherWarning[]> {
const rows = await getJson<RawWarning[]>(kind === "meteo" ? "warningsmeteo" : "warningshydro", signal);
return Array.isArray(rows) ? rows.map((warning, index) => normalizeWarning(warning, kind, index)) : [];
}
function compareWarnings(a: WeatherWarning, b: WeatherWarning) {
if (a.kind !== b.kind) return a.kind === "meteo" ? -1 : 1;
return (b.publishedAt ?? "").localeCompare(a.publishedAt ?? "");
}
export async function fetchWarnings(signal?: AbortSignal): Promise<WeatherWarning[]> {
const results = await Promise.allSettled([
fetchWarningsByKind("meteo", signal),
fetchWarningsByKind("hydro", signal),
]);
const warnings = results.flatMap((result) => result.status === "fulfilled" ? result.value : []);
if (results.every((result) => result.status === "rejected")) {
throw new Error("Nie udało się pobrać ostrzeżeń IMGW.");
}
return warnings.sort(compareWarnings);
}