Files
wtr/lib/imgw-current-api.ts

78 lines
3.0 KiB
TypeScript

import { toNumber } from "@/lib/weather-utils";
import type { ImgwCurrentWeather, RawImgwHybridWeatherResponse, RawImgwHybridWeatherRow } from "@/types/imgw-current";
function toCelsius(value: unknown) {
const temperature = toNumber(value);
if (temperature === null) return null;
return temperature > 150 ? temperature - 273.15 : temperature;
}
function toHectopascals(value: unknown) {
const pressure = toNumber(value);
if (pressure === null) return null;
return pressure > 2_000 ? pressure / 100 : pressure;
}
function normalizeDate(value: unknown) {
if (typeof value !== "string") return null;
const date = new Date(value);
return Number.isNaN(date.getTime()) ? null : date.toISOString();
}
function getWeatherCode(iconCode: unknown) {
if (typeof iconCode !== "string") return null;
const match = iconCode.match(/z(\d{2})/i);
return match ? Number(match[1]) : null;
}
function getCondition(weatherCode: number | null, rainfall10m: number | null, snowfall10m: number | null) {
if (weatherCode !== null && weatherCode >= 95) return "thunderstorm" as const;
if ((snowfall10m ?? 0) > 0) return "snow" as const;
if ((rainfall10m ?? 0) > 0) return "rain" as const;
return null;
}
export function normalizeImgwCurrentWeather(payload: RawImgwHybridWeatherResponse): ImgwCurrentWeather | null {
if (!payload.data?.Valid || !Array.isArray(payload.data.Data)) return null;
const row = payload.data.Data
.filter((candidate): candidate is RawImgwHybridWeatherRow => {
if (!candidate || typeof candidate !== "object") return false;
return candidate.Type === "Type_Ten_Minutes"
&& typeof candidate.MODEL === "string"
&& candidate.MODEL.includes("AROME")
&& normalizeDate(candidate.Date) !== null;
})
.sort((left, right) => String(right.Date).localeCompare(String(left.Date)))[0];
if (!row) return null;
const measuredAt = normalizeDate(row.Date);
if (!measuredAt) return null;
const rainfall10m = toNumber(row.Rain10m);
const snowfall10m = toNumber(row.Snow10m);
const weatherCode = getWeatherCode(row.Icon10);
return {
measuredAt,
temperature: toCelsius(row.Temperature),
feelsLike: toCelsius(row.Chill),
windSpeed: toNumber(row.Wind_Speed),
windDirection: toNumber(row.Wind_Dir),
humidity: toNumber(row.Humidity),
pressure: toHectopascals(row.PressureMSL),
precipitation10m: toNumber(row.Precipitation10m),
rainfall10m,
snowfall10m,
cloudCover: toNumber(row.Cloud),
weatherCode,
condition: getCondition(weatherCode, rainfall10m, snowfall10m),
};
}
export async function fetchImgwCurrentWeather(latitude: number, longitude: number, signal?: AbortSignal) {
const params = new URLSearchParams({ latitude: String(latitude), longitude: String(longitude) });
const response = await fetch(`/api/imgw-current?${params}`, { signal });
if (!response.ok) throw new Error("Nie udało się pobrać bieżącej analizy IMGW Hybrid.");
return normalizeImgwCurrentWeather(await response.json() as RawImgwHybridWeatherResponse);
}