Spaces:
Sleeping
Sleeping
File size: 2,163 Bytes
cb43fbd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import { z } from 'zod';
/**
* Weather API contract — single source of truth for the /api/weather endpoints.
*
* The legacy Express routes treat lat/lng as opaque strings (they are parsed with
* parseFloat inside the service) and only check for presence, so the query schemas
* mirror that: non-empty strings, not coerced numbers. `lang` defaults to 'de',
* matching the Express default.
*
* The bespoke "X is required" 400 messages are reproduced in the controller, not
* derived from these schemas, so the error body stays byte-identical to Express.
*/
export const weatherQuerySchema = z.object({
lat: z.string().min(1),
lng: z.string().min(1),
date: z.string().min(1).optional(),
lang: z.string().min(1).default('de'),
});
export type WeatherQuery = z.infer<typeof weatherQuerySchema>;
/** Detailed weather requires a date (the Express route 400s without it). */
export const detailedWeatherQuerySchema = weatherQuerySchema.extend({
date: z.string().min(1),
});
export type DetailedWeatherQuery = z.infer<typeof detailedWeatherQuerySchema>;
export const hourlyEntrySchema = z.object({
hour: z.number(),
temp: z.number(),
precipitation: z.number(),
precipitation_probability: z.number(),
main: z.string(),
wind: z.number(),
humidity: z.number(),
});
export type HourlyEntry = z.infer<typeof hourlyEntrySchema>;
/**
* Weather response DTO. Fields are optional because the Express service emits
* different subsets depending on the request type (current / forecast / climate /
* detailed) and on error (`{ ..., error: 'no_forecast' }`).
*/
export const weatherResultSchema = z.object({
temp: z.number(),
temp_max: z.number().optional(),
temp_min: z.number().optional(),
main: z.string(),
description: z.string(),
type: z.string(),
sunrise: z.string().nullable().optional(),
sunset: z.string().nullable().optional(),
precipitation_sum: z.number().optional(),
precipitation_probability_max: z.number().optional(),
wind_max: z.number().optional(),
hourly: z.array(hourlyEntrySchema).optional(),
error: z.string().optional(),
});
export type WeatherResult = z.infer<typeof weatherResultSchema>;
|