@i-giann/open-meteo-wrapper 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,673 @@
1
+ import { useCallback as B, useEffect as q, useMemo as Q } from "react";
2
+ import { create as $ } from "zustand";
3
+ import { produce as z } from "immer";
4
+ function V(e, a) {
5
+ let t;
6
+ try {
7
+ t = e();
8
+ } catch {
9
+ return;
10
+ }
11
+ return {
12
+ getItem: (u) => {
13
+ var r;
14
+ const s = (d) => d === null ? null : JSON.parse(d, void 0), i = (r = t.getItem(u)) != null ? r : null;
15
+ return i instanceof Promise ? i.then(s) : s(i);
16
+ },
17
+ setItem: (u, r) => t.setItem(
18
+ u,
19
+ JSON.stringify(r, void 0)
20
+ ),
21
+ removeItem: (u) => t.removeItem(u)
22
+ };
23
+ }
24
+ const x = (e) => (a) => {
25
+ try {
26
+ const t = e(a);
27
+ return t instanceof Promise ? t : {
28
+ then(o) {
29
+ return x(o)(t);
30
+ },
31
+ catch(o) {
32
+ return this;
33
+ }
34
+ };
35
+ } catch (t) {
36
+ return {
37
+ then(o) {
38
+ return this;
39
+ },
40
+ catch(o) {
41
+ return x(o)(t);
42
+ }
43
+ };
44
+ }
45
+ }, X = (e, a) => (t, o, u) => {
46
+ let r = {
47
+ storage: V(() => localStorage),
48
+ partialize: (c) => c,
49
+ version: 0,
50
+ merge: (c, T) => ({
51
+ ...T,
52
+ ...c
53
+ }),
54
+ ...a
55
+ }, s = !1;
56
+ const i = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set();
57
+ let m = r.storage;
58
+ if (!m)
59
+ return e(
60
+ (...c) => {
61
+ console.warn(
62
+ `[zustand persist middleware] Unable to update item '${r.name}', the given storage is currently unavailable.`
63
+ ), t(...c);
64
+ },
65
+ o,
66
+ u
67
+ );
68
+ const g = () => {
69
+ const c = r.partialize({ ...o() });
70
+ return m.setItem(r.name, {
71
+ state: c,
72
+ version: r.version
73
+ });
74
+ }, p = u.setState;
75
+ u.setState = (c, T) => {
76
+ p(c, T), g();
77
+ };
78
+ const l = e(
79
+ (...c) => {
80
+ t(...c), g();
81
+ },
82
+ o,
83
+ u
84
+ );
85
+ u.getInitialState = () => l;
86
+ let v;
87
+ const L = () => {
88
+ var c, T;
89
+ if (!m) return;
90
+ s = !1, i.forEach((R) => {
91
+ var y;
92
+ return R((y = o()) != null ? y : l);
93
+ });
94
+ const N = ((T = r.onRehydrateStorage) == null ? void 0 : T.call(r, (c = o()) != null ? c : l)) || void 0;
95
+ return x(m.getItem.bind(m))(r.name).then((R) => {
96
+ if (R)
97
+ if (typeof R.version == "number" && R.version !== r.version) {
98
+ if (r.migrate) {
99
+ const y = r.migrate(
100
+ R.state,
101
+ R.version
102
+ );
103
+ return y instanceof Promise ? y.then((D) => [!0, D]) : [!0, y];
104
+ }
105
+ console.error(
106
+ "State loaded from storage couldn't be migrated since no migrate function was provided"
107
+ );
108
+ } else
109
+ return [!1, R.state];
110
+ return [!1, void 0];
111
+ }).then((R) => {
112
+ var y;
113
+ const [D, U] = R;
114
+ if (v = r.merge(
115
+ U,
116
+ (y = o()) != null ? y : l
117
+ ), t(v, !0), D)
118
+ return g();
119
+ }).then(() => {
120
+ N == null || N(v, void 0), v = o(), s = !0, d.forEach((R) => R(v));
121
+ }).catch((R) => {
122
+ N == null || N(void 0, R);
123
+ });
124
+ };
125
+ return u.persist = {
126
+ setOptions: (c) => {
127
+ r = {
128
+ ...r,
129
+ ...c
130
+ }, c.storage && (m = c.storage);
131
+ },
132
+ clearStorage: () => {
133
+ m == null || m.removeItem(r.name);
134
+ },
135
+ getOptions: () => r,
136
+ rehydrate: () => L(),
137
+ hasHydrated: () => s,
138
+ onHydrate: (c) => (i.add(c), () => {
139
+ i.delete(c);
140
+ }),
141
+ onFinishHydration: (c) => (d.add(c), () => {
142
+ d.delete(c);
143
+ })
144
+ }, r.skipHydration || L(), v || l;
145
+ }, ee = X;
146
+ var I = /* @__PURE__ */ ((e) => (e.SUCCESS = "success", e.ERROR = "error", e.WARNING = "warning", e.INFO = "info", e))(I || {}), w = /* @__PURE__ */ ((e) => (e.NETWORK_ERROR = "network_error", e.API_ERROR = "api_error", e.DATA_ERROR = "data_error", e.UNKNOWN_ERROR = "unknown_error", e))(w || {}), k = /* @__PURE__ */ ((e) => (e.Temperature = "temperature_2m", e.RelativeHumidity = "relative_humidity_2m", e.DewPoint = "dew_point_2m", e.ApparentTemperature = "apparent_temperature", e.PrecipitationProbability = "precipitation_probability", e.Precipitation = "precipitation", e.Rain = "rain", e.Snowfall = "snowfall", e.SnowDepth = "snow_depth", e.WeatherCode = "weather_code", e.PressureMsl = "pressure_msl", e.CloudCover = "cloud_cover", e.Visibility = "visibility", e.WindSpeed = "wind_speed_10m", e.WindDirection = "wind_direction_10m", e.UvIndex = "uv_index", e.IsDay = "is_day", e))(k || {}), G = /* @__PURE__ */ ((e) => (e.TemperatureMax = "temperature_2m_max", e.TemperatureMin = "temperature_2m_min", e.Sunrise = "sunrise", e.Sunset = "sunset", e.DaylightDuration = "daylight_duration", e))(G || {}), E = /* @__PURE__ */ ((e) => (e.UNKNOWN = "Desconocido", e.LOW = "Bajo", e.MODERATE = "Moderado", e.HIGH = "Alto", e))(E || {}), h = /* @__PURE__ */ ((e) => (e.clear_sky = "Cielo despejado", e.mainly_clear = "Mayormente despejado", e.partly_cloudy = "Parcialmente nublado", e.overcast = "Mayormente nublado", e.fog = "Niebla", e.depositing_rime_fog = "Niebla con escarcha", e.drizzle_light = "Llovizna ligera", e.drizzle_moderate = "Llovizna moderada", e.drizzle_dense = "Llovizna densa", e.freezing_drizzle_light = "Llovizna helada ligera", e.freezing_drizzle_dense = "Llovizna helada densa", e.rain_slight = "Lluvia ligera", e.rain_moderate = "Lluvia moderada", e.rain_heavy = "Lluvia intensa", e.freezing_rain_light = "Lluvia helada ligera", e.freezing_rain_heavy = "Lluvia helada intensa", e.snowfall_slight = "Nevada ligera", e.snowfall_moderate = "Nevada moderada", e.snowfall_heavy = "Nevada intensa", e.snow_grains = "Precipitación de granos de nieve", e.rain_showers_slight = "Chubascos ligeros", e.rain_showers_moderate = "Chubascos moderados", e.rain_showers_violent = "Chubascos violentos", e.snow_showers_slight = "Chubascos de nieve ligeros", e.snow_showers_heavy = "Chubascos de nieve intensos", e.thunderstorm = "Tormenta", e))(h || {});
147
+ const te = "https://api.open-meteo.com/v1/forecast", A = {
148
+ /** Zona horaria por defecto para las consultas */
149
+ DEFAULT_TIMEZONE: "America/Sao_Paulo",
150
+ /** Parámetros meteorológicos por hora solicitados por defecto */
151
+ DEFAULT_HOURLY_PARAMS: [
152
+ k.Temperature,
153
+ k.WeatherCode
154
+ ],
155
+ /** Parámetros meteorológicos diarios solicitados por defecto */
156
+ DEFAULT_DAILY_PARAMS: [
157
+ G.TemperatureMax,
158
+ G.TemperatureMin
159
+ ],
160
+ /** Número de días pasados a incluir por defecto */
161
+ DEFAULT_PAST_DAYS: 0,
162
+ /** Número de días de pronóstico a incluir por defecto */
163
+ DEFAULT_FORECAST_DAYS: 7,
164
+ /** Duración del caché en milisegundos (10 minutos) */
165
+ DEFAULT_CACHE_DURATION: 10 * 60 * 1e3,
166
+ /** Timeout para las solicitudes HTTP en milisegundos */
167
+ REQUEST_TIMEOUT: 1e4
168
+ }, H = {
169
+ /** Descripciones de recomendaciones por nivel de riesgo UV */
170
+ DESCRIPTIONS: {
171
+ [E.UNKNOWN]: "No se puede determinar el riesgo de exposición",
172
+ [E.LOW]: "Puedes disfrutar de estar afuera con seguridad",
173
+ [E.MODERATE]: "Busca sombra durante las horas del mediodía. Ponte una remera, utiliza protector solar y un sombrero.",
174
+ [E.HIGH]: "Evita estar afuera durante las horas del mediodía. Asegúrate de buscar sombra. La remera, el protector solar y el sombrero son imprescindibles."
175
+ }
176
+ }, re = {
177
+ // Cielo despejado y parcialmente nublado
178
+ 0: h.clear_sky,
179
+ 1: h.mainly_clear,
180
+ 2: h.partly_cloudy,
181
+ 3: h.overcast,
182
+ // Niebla
183
+ 45: h.fog,
184
+ 48: h.depositing_rime_fog,
185
+ // Llovizna
186
+ 51: h.drizzle_light,
187
+ 53: h.drizzle_moderate,
188
+ 55: h.drizzle_dense,
189
+ 56: h.freezing_drizzle_light,
190
+ 57: h.freezing_drizzle_dense,
191
+ // Lluvia
192
+ 61: h.rain_slight,
193
+ 63: h.rain_moderate,
194
+ 65: h.rain_heavy,
195
+ 66: h.freezing_rain_light,
196
+ 67: h.freezing_rain_heavy,
197
+ // Nieve
198
+ 71: h.snowfall_slight,
199
+ 73: h.snowfall_moderate,
200
+ 75: h.snowfall_heavy,
201
+ 77: h.snow_grains,
202
+ // Chubascos
203
+ 80: h.rain_showers_slight,
204
+ 81: h.rain_showers_moderate,
205
+ 82: h.rain_showers_violent,
206
+ 85: h.snow_showers_slight,
207
+ 86: h.snow_showers_heavy,
208
+ // Tormentas
209
+ 95: h.thunderstorm
210
+ }, f = {
211
+ // Tiempo
212
+ time: "iso8601",
213
+ hour: "iso8601",
214
+ // Temperatura
215
+ temperature_2m: "ºC",
216
+ temperature_2m_max: "ºC",
217
+ temperature_2m_min: "ºC",
218
+ dew_point_2m: "ºC",
219
+ apparent_temperature: "ºC",
220
+ // Humedad y precipitación
221
+ relative_humidity_2m: "%",
222
+ precipitation_probability: "%",
223
+ precipitation: "mm",
224
+ rain: "mm",
225
+ snowfall: "cm",
226
+ snow_depth: "m",
227
+ // Presión y viento
228
+ pressure_msl: "hPa",
229
+ wind_speed_10m: "km/h",
230
+ wind_direction_10m: "°",
231
+ // Cielo y visibilidad
232
+ cloud_cover: "%",
233
+ visibility: "km",
234
+ weather_code: "wmo code",
235
+ // Sol y UV
236
+ sunrise: "iso8601",
237
+ sunset: "iso8601",
238
+ daylight_duration: "h",
239
+ is_day: "flag"
240
+ };
241
+ class ae {
242
+ async fetchRaw({
243
+ latitude: a,
244
+ longitude: t,
245
+ hourly: o = A.DEFAULT_HOURLY_PARAMS,
246
+ daily: u = A.DEFAULT_DAILY_PARAMS,
247
+ timezone: r = A.DEFAULT_TIMEZONE,
248
+ past_days: s = A.DEFAULT_PAST_DAYS,
249
+ forecast_days: i = A.DEFAULT_FORECAST_DAYS
250
+ }) {
251
+ try {
252
+ const d = new URL(te), m = new URLSearchParams({
253
+ latitude: a.toString(),
254
+ longitude: t.toString(),
255
+ hourly: o.join(","),
256
+ daily: u.join(","),
257
+ timezone: r,
258
+ past_days: s.toString(),
259
+ forecast_days: i.toString()
260
+ });
261
+ d.search = m.toString();
262
+ const g = new AbortController(), p = setTimeout(() => g.abort(), A.REQUEST_TIMEOUT), l = await fetch(d.toString(), {
263
+ signal: g.signal
264
+ });
265
+ return clearTimeout(p), l.ok ? await l.json() : l.status >= 500 ? this.buildError({
266
+ error: "Debido a un problema en el servidor, no podemos obtener la información del clima.",
267
+ info: "Por favor, inténtalo de nuevo más tarde.",
268
+ status: l.status,
269
+ errorType: w.API_ERROR
270
+ }) : l.status >= 400 ? l.status === 408 ? this.buildError({
271
+ error: "La solicitud ha tardado demasiado tiempo en completarse.",
272
+ status: 408,
273
+ info: "Revisa tu conexión a internet e intenta de nuevo.",
274
+ type: I.WARNING,
275
+ errorType: w.NETWORK_ERROR
276
+ }) : this.buildError({
277
+ error: "No pudimos obtener la información del clima.",
278
+ info: "Verifica que la ubicación ingresada sea correcta e inténtalo de nuevo.",
279
+ status: l.status,
280
+ type: I.WARNING,
281
+ errorType: w.API_ERROR
282
+ }) : this.buildError({
283
+ error: "Ocurrió un error al obtener los datos del clima.",
284
+ status: l.status,
285
+ errorType: w.UNKNOWN_ERROR
286
+ });
287
+ } catch (d) {
288
+ return d instanceof DOMException && d.name === "AbortError" ? this.buildError({
289
+ error: "La solicitud ha tardado demasiado tiempo en completarse.",
290
+ status: 408,
291
+ info: "Revisa tu conexión a internet e intenta de nuevo.",
292
+ type: I.WARNING,
293
+ errorType: w.NETWORK_ERROR
294
+ }) : this.buildError({
295
+ error: "Ocurrió un error inesperado al obtener los datos meteorológicos.",
296
+ type: I.ERROR,
297
+ status: 0,
298
+ errorType: w.UNKNOWN_ERROR
299
+ });
300
+ }
301
+ }
302
+ buildError({ error: a, info: t, status: o, type: u, errorType: r }) {
303
+ return {
304
+ error: a || "Error desconocido.",
305
+ info: t,
306
+ status: o || 0,
307
+ type: u || I.ERROR,
308
+ errorType: r || w.UNKNOWN_ERROR
309
+ };
310
+ }
311
+ }
312
+ const ne = (e) => e < 0 ? E.UNKNOWN : e <= 2 ? E.LOW : e <= 7 ? E.MODERATE : E.HIGH, oe = (e) => e < 0 ? H.DESCRIPTIONS[E.UNKNOWN] : e <= 2 ? H.DESCRIPTIONS[E.LOW] : e <= 7 ? H.DESCRIPTIONS[E.MODERATE] : H.DESCRIPTIONS[E.HIGH];
313
+ class ie {
314
+ adapt(a, t, o) {
315
+ const u = t, r = u + 1, s = t + o + 1, i = this.processWeatherData(
316
+ a,
317
+ u,
318
+ r
319
+ ), d = i.length > 0 ? i[0] : {};
320
+ return {
321
+ pastDay: this.processWeatherData(a, 0, u),
322
+ currentDay: d,
323
+ forecast: this.processWeatherData(a, r, s),
324
+ timezone: a.timezone,
325
+ latitude: a.latitude,
326
+ longitude: a.longitude
327
+ };
328
+ }
329
+ processWeatherData(a, t, o) {
330
+ const { daily: u } = a, r = [], {
331
+ time: s,
332
+ temperature_2m_max: i,
333
+ temperature_2m_min: d,
334
+ sunrise: m,
335
+ sunset: g,
336
+ daylight_duration: p
337
+ } = u;
338
+ for (let l = t; l < o; l++) {
339
+ const v = {};
340
+ s != null && s[l] && (v.day = { value: new Date(s[l]), unit: f.time }), (i == null ? void 0 : i[l]) !== void 0 && (v.temperatureMax = {
341
+ value: i[l],
342
+ unit: f.temperature_2m_max
343
+ }), (d == null ? void 0 : d[l]) !== void 0 && (v.temperatureMin = {
344
+ value: d[l],
345
+ unit: f.temperature_2m_min
346
+ }), m != null && m[l] && (v.sunrise = {
347
+ value: new Date(m[l]),
348
+ unit: f.sunrise
349
+ }), g != null && g[l] && (v.sunset = { value: new Date(g[l]), unit: f.sunset }), (p == null ? void 0 : p[l]) !== void 0 && (v.daylightDuration = {
350
+ value: p[l] / 3600,
351
+ unit: f.daylight_duration
352
+ }), v.hourly = this.getHourlyData(a, l), r.push(v);
353
+ }
354
+ return r;
355
+ }
356
+ getHourlyData(a, t) {
357
+ const { hourly: o, daily: u } = a, {
358
+ time: r,
359
+ temperature_2m: s,
360
+ relative_humidity_2m: i,
361
+ dew_point_2m: d,
362
+ apparent_temperature: m,
363
+ precipitation_probability: g,
364
+ precipitation: p,
365
+ rain: l,
366
+ snowfall: v,
367
+ snow_depth: L,
368
+ weather_code: c,
369
+ pressure_msl: T,
370
+ cloud_cover: N,
371
+ visibility: R,
372
+ wind_direction_10m: y,
373
+ wind_speed_10m: D,
374
+ uv_index: U,
375
+ is_day: C
376
+ } = o, b = a.timezone || "UTC";
377
+ let F, M, P;
378
+ const W = u.time[t];
379
+ if (typeof W == "string" && /^\d{4}-\d{2}-\d{2}$/.test(W)) {
380
+ const S = W.split("-").map(Number);
381
+ F = S[0], M = S[1] - 1, P = S[2];
382
+ } else {
383
+ const S = new Date(W);
384
+ F = Number(
385
+ S.toLocaleString("en", { timeZone: b, year: "numeric" })
386
+ ), M = Number(S.toLocaleString("en", { timeZone: b, month: "numeric" })) - 1, P = Number(
387
+ S.toLocaleString("en", { timeZone: b, day: "numeric" })
388
+ );
389
+ }
390
+ const Y = [];
391
+ for (let S = 0; S < 24; S++) {
392
+ let K = -1;
393
+ for (let n = 0; n < r.length; n++) {
394
+ const _ = new Date(r[n]), O = Number(
395
+ _.toLocaleString("en", { timeZone: b, year: "numeric" })
396
+ ), j = Number(
397
+ _.toLocaleString("en", { timeZone: b, month: "numeric" })
398
+ ) - 1, Z = Number(
399
+ _.toLocaleString("en", { timeZone: b, day: "numeric" })
400
+ ), J = Number(
401
+ _.toLocaleString("en", {
402
+ timeZone: b,
403
+ hour: "numeric",
404
+ hour12: !1
405
+ })
406
+ );
407
+ if (O === F && j === M && Z === P && J === S) {
408
+ K = n;
409
+ break;
410
+ }
411
+ }
412
+ if (K !== -1) {
413
+ const n = K, _ = {};
414
+ if (_.hour = { value: new Date(r[n]), unit: f.hour }, (s == null ? void 0 : s[n]) !== void 0 && (_.temperature = {
415
+ value: s[n],
416
+ unit: f.temperature_2m
417
+ }), (i == null ? void 0 : i[n]) !== void 0 && (_.relativeHumidity = {
418
+ value: i[n],
419
+ unit: f.relative_humidity_2m
420
+ }), (d == null ? void 0 : d[n]) !== void 0 && (_.dewPoint = {
421
+ value: d[n],
422
+ unit: f.dew_point_2m
423
+ }), (m == null ? void 0 : m[n]) !== void 0 && (_.apparentTemperature = {
424
+ value: m[n],
425
+ unit: f.apparent_temperature
426
+ }), (g == null ? void 0 : g[n]) !== void 0 && (_.precipitationProbability = {
427
+ value: g[n],
428
+ unit: f.precipitation_probability
429
+ }), (p == null ? void 0 : p[n]) !== void 0 && (_.precipitation = {
430
+ value: p[n],
431
+ unit: f.precipitation
432
+ }), (l == null ? void 0 : l[n]) !== void 0 && (_.rain = { value: l[n], unit: f.rain }), (v == null ? void 0 : v[n]) !== void 0 && (_.snowfall = { value: v[n], unit: f.snowfall }), (L == null ? void 0 : L[n]) !== void 0 && (_.snowDepth = { value: L[n], unit: f.snow_depth }), (c == null ? void 0 : c[n]) !== void 0) {
433
+ _.weatherCode = {
434
+ value: c[n],
435
+ unit: f.weather_code
436
+ };
437
+ const O = re[c[n]];
438
+ O && (_.weatherDescription = { value: O, unit: "text" });
439
+ }
440
+ if ((T == null ? void 0 : T[n]) !== void 0 && (_.pressureMsl = {
441
+ value: T[n],
442
+ unit: f.pressure_msl
443
+ }), (N == null ? void 0 : N[n]) !== void 0 && (_.cloudCover = {
444
+ value: N[n],
445
+ unit: f.cloud_cover
446
+ }), (R == null ? void 0 : R[n]) !== void 0 && (_.visibility = {
447
+ value: R[n] / 1e3,
448
+ unit: f.visibility
449
+ }), ((D == null ? void 0 : D[n]) !== void 0 || (y == null ? void 0 : y[n]) !== void 0) && (_.wind = {
450
+ speed: {
451
+ value: (D == null ? void 0 : D[n]) || 0,
452
+ unit: f.wind_speed_10m
453
+ }
454
+ }, (y == null ? void 0 : y[n]) !== void 0 && (_.wind.direction = {
455
+ value: y[n],
456
+ unit: f.wind_direction_10m
457
+ })), (U == null ? void 0 : U[n]) !== void 0) {
458
+ const O = U[n];
459
+ _.uv = {
460
+ value: O,
461
+ riskLevel: ne(O),
462
+ description: oe(O),
463
+ unit: "index"
464
+ };
465
+ }
466
+ (C == null ? void 0 : C[n]) !== void 0 && (_.isDay = { value: C[n], unit: f.is_day }), Y.push(_);
467
+ } else {
468
+ const n = new Date(
469
+ Date.UTC(F, M, P, S, 0, 0, 0)
470
+ );
471
+ Y.push({ hour: { value: n, unit: f.hour } });
472
+ }
473
+ }
474
+ return Y;
475
+ }
476
+ }
477
+ const se = async (e, a) => {
478
+ const {
479
+ latitude: t,
480
+ longitude: o,
481
+ hourly: u = A.DEFAULT_HOURLY_PARAMS,
482
+ daily: r = A.DEFAULT_DAILY_PARAMS,
483
+ timezone: s = A.DEFAULT_TIMEZONE,
484
+ past_days: i = A.DEFAULT_PAST_DAYS,
485
+ forecast_days: d = A.DEFAULT_FORECAST_DAYS
486
+ } = e, m = (a == null ? void 0 : a.client) || new ae(), g = (a == null ? void 0 : a.adapter) || new ie(), p = await m.fetchRaw({
487
+ latitude: t,
488
+ longitude: o,
489
+ hourly: u,
490
+ daily: r,
491
+ timezone: s,
492
+ past_days: i,
493
+ forecast_days: d
494
+ });
495
+ return "error" in p ? p : g.adapt(
496
+ p,
497
+ i || 0,
498
+ d || 0
499
+ );
500
+ };
501
+ let ue = (e) => se(e);
502
+ function le(e, a) {
503
+ return JSON.stringify(e) === JSON.stringify(a);
504
+ }
505
+ const de = $()(
506
+ ee(
507
+ (e, a) => ({
508
+ data: null,
509
+ loading: !1,
510
+ error: null,
511
+ autoRefresh: !0,
512
+ fetchParams: null,
513
+ // Variables de caché
514
+ lastFetchTime: null,
515
+ cacheDuration: 10 * 60 * 1e3,
516
+ // 10 minutos por defecto
517
+ /**
518
+ * Realiza la solicitud para obtener datos meteorológicos.
519
+ * Si los parámetros y el caché lo permiten, reutiliza los datos existentes.
520
+ * Si no, realiza una nueva consulta y actualiza el estado.
521
+ */
522
+ fetchWeather: async (t) => {
523
+ const o = a(), u = Date.now();
524
+ if (!(o.fetchParams && le(o.fetchParams, t) && o.data && o.lastFetchTime !== null && u - o.lastFetchTime < o.cacheDuration)) {
525
+ e(
526
+ z((s) => {
527
+ s.loading = !0, s.error = null, s.fetchParams = t;
528
+ })
529
+ );
530
+ try {
531
+ const s = await ue(t);
532
+ if ("error" in s) {
533
+ e(
534
+ z((i) => {
535
+ i.error = s, i.loading = !1;
536
+ })
537
+ );
538
+ return;
539
+ }
540
+ e(
541
+ z((i) => {
542
+ i.data = s, i.loading = !1, i.error = null, i.lastFetchTime = Date.now();
543
+ })
544
+ );
545
+ } catch (s) {
546
+ const i = s instanceof Error ? s.message : "Error desconocido.";
547
+ e(
548
+ z((d) => {
549
+ d.error = {
550
+ error: i,
551
+ type: I.WARNING,
552
+ errorType: w.UNKNOWN_ERROR,
553
+ status: 0
554
+ }, d.loading = !1;
555
+ })
556
+ );
557
+ }
558
+ }
559
+ },
560
+ /** Indica si está en proceso de carga */
561
+ isLoading: () => a().loading,
562
+ /** Indica si se ha producido algún error */
563
+ hasError: () => a().error !== null,
564
+ /** Devuelve el error actual */
565
+ getError: () => a().error,
566
+ /** Limpia el error actual */
567
+ clearError: () => e(
568
+ z((t) => {
569
+ t.error = null;
570
+ })
571
+ ),
572
+ /**
573
+ * Activa o desactiva la actualización automática.
574
+ * Si se activa, programa la actualización para la próxima medianoche local.
575
+ */
576
+ setAutoRefresh: (t) => {
577
+ e({ autoRefresh: t }), t && a().scheduleAutoRefresh();
578
+ },
579
+ /**
580
+ * Programa una actualización automática de datos para la medianoche local
581
+ * en la zona horaria de los datos obtenidos, y vuelve a programarla
582
+ * cada vez que se llega a esa hora.
583
+ */
584
+ scheduleAutoRefresh: () => {
585
+ const { data: t, fetchParams: o } = a();
586
+ if (!t || !t.timezone || !o) return;
587
+ const u = (/* @__PURE__ */ new Date()).toLocaleString("es-ES", {
588
+ timeZone: t.timezone
589
+ }), r = new Date(u), s = new Date(r);
590
+ s.setHours(24, 0, 0, 0);
591
+ const i = s.getTime() - r.getTime();
592
+ setTimeout(async () => {
593
+ await a().fetchWeather(o), a().scheduleAutoRefresh();
594
+ }, i);
595
+ },
596
+ /** Devuelve todos los datos meteorológicos */
597
+ getAllWeatherData: () => a().data,
598
+ getCurrentDayWeather: () => {
599
+ var t;
600
+ return ((t = a().data) == null ? void 0 : t.currentDay) || null;
601
+ },
602
+ getPastDayWeather: () => {
603
+ var t;
604
+ return ((t = a().data) == null ? void 0 : t.pastDay) || null;
605
+ },
606
+ getForecastWeather: () => {
607
+ var t;
608
+ return ((t = a().data) == null ? void 0 : t.forecast) || null;
609
+ },
610
+ /**
611
+ * Devuelve los datos meteorológicos de la hora actual.
612
+ * Busca la hora local actual en el array de horas del día.
613
+ */
614
+ getCurrentHourWeather() {
615
+ var i, d;
616
+ const { data: t } = a();
617
+ if (!t) return null;
618
+ const o = t.timezone, u = (/* @__PURE__ */ new Date()).toLocaleString("en", {
619
+ timeZone: o
620
+ }), r = new Date(u);
621
+ return ((d = (i = t.currentDay) == null ? void 0 : i.hourly) == null ? void 0 : d.find((m) => m.hour ? new Date(m.hour.value).getHours() === r.getHours() : null)) || null;
622
+ }
623
+ }),
624
+ {
625
+ name: "weather-store",
626
+ partialize: (e) => ({
627
+ data: e.data,
628
+ fetchParams: e.fetchParams,
629
+ lastFetchTime: e.lastFetchTime,
630
+ autoRefresh: e.autoRefresh
631
+ })
632
+ }
633
+ )
634
+ ), _e = () => {
635
+ const e = de(), a = B(
636
+ async (o) => {
637
+ await e.fetchWeather(o);
638
+ },
639
+ [e.fetchWeather]
640
+ );
641
+ return q(() => {
642
+ e.autoRefresh && e.fetchParams && e.scheduleAutoRefresh();
643
+ }, [e.autoRefresh, e.fetchParams]), {
644
+ ...Q(
645
+ () => {
646
+ var o, u, r;
647
+ return {
648
+ // Datos meteorológicos principales
649
+ data: e.data,
650
+ currentDay: ((o = e.data) == null ? void 0 : o.currentDay) || null,
651
+ pastDays: ((u = e.data) == null ? void 0 : u.pastDay) || null,
652
+ forecast: ((r = e.data) == null ? void 0 : r.forecast) || null,
653
+ currentHour: e.getCurrentHourWeather(),
654
+ // Estado
655
+ isLoading: e.loading,
656
+ error: e.error
657
+ };
658
+ },
659
+ [e.data, e.loading, e.error]
660
+ ),
661
+ /** Acción para solicitar datos meteorológicos */
662
+ fetchWeather: a,
663
+ /** Activa o desactiva la actualización automática */
664
+ setAutoRefresh: e.setAutoRefresh,
665
+ /** Limpia el error actual */
666
+ clearError: e.clearError
667
+ };
668
+ };
669
+ export {
670
+ se as fetchWeather,
671
+ _e as useWeather,
672
+ de as useWeatherStore
673
+ };
@@ -0,0 +1,10 @@
1
+ import { WeatherData } from "../../types/apiTypes";
2
+ import { StructureWeatherData } from "../../types/weatherTypes";
3
+ export interface IWeatherAdapter {
4
+ adapt(raw: WeatherData, pastDays: number, forecastDays: number): StructureWeatherData;
5
+ }
6
+ export declare class OpenMeteoAdapter implements IWeatherAdapter {
7
+ adapt(raw: WeatherData, pastDays: number, forecastDays: number): StructureWeatherData;
8
+ private processWeatherData;
9
+ private getHourlyData;
10
+ }
@@ -0,0 +1,9 @@
1
+ import { FetchWeatherProps, FetchError } from "../../types/weatherTypes";
2
+ import { WeatherData } from "../../types/apiTypes";
3
+ export interface IWeatherApiClient {
4
+ fetchRaw(params: FetchWeatherProps): Promise<WeatherData | FetchError>;
5
+ }
6
+ export declare class OpenMeteoClient implements IWeatherApiClient {
7
+ fetchRaw({ latitude, longitude, hourly, daily, timezone, past_days, forecast_days, }: FetchWeatherProps): Promise<WeatherData | FetchError>;
8
+ private buildError;
9
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./weatherService";
2
+ export * from "./api/OpenMeteoClient";
3
+ export * from "./adapters/OpenMeteoAdapter";