mostlyright 1.0.0 → 1.1.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.
@@ -1798,6 +1798,27 @@ var mostlyright = (() => {
1798
1798
  }
1799
1799
  });
1800
1800
 
1801
+ // ../weather/src/_internal/tgroup.ts
1802
+ function parseTgroup(rawMetar) {
1803
+ if (!rawMetar) return [null, null];
1804
+ const rmkIdx = rawMetar.indexOf("RMK");
1805
+ if (rmkIdx < 0) return [null, null];
1806
+ const match = TGROUP_RE.exec(rawMetar.slice(rmkIdx));
1807
+ if (!match) return [null, null];
1808
+ const tSign = match[1] === "1" ? -1 : 1;
1809
+ const tVal = Number.parseInt(match[2], 10) / 10 * tSign;
1810
+ const dSign = match[3] === "1" ? -1 : 1;
1811
+ const dVal = Number.parseInt(match[4], 10) / 10 * dSign;
1812
+ return [tVal, dVal];
1813
+ }
1814
+ var TGROUP_RE;
1815
+ var init_tgroup = __esm({
1816
+ "../weather/src/_internal/tgroup.ts"() {
1817
+ "use strict";
1818
+ TGROUP_RE = /\bT([01])(\d{3})([01])(\d{3})\b/;
1819
+ }
1820
+ });
1821
+
1801
1822
  // ../weather/src/_parsers/awc.ts
1802
1823
  function icaoToStationCode(icao) {
1803
1824
  const upper = icao.trim().toUpperCase();
@@ -1871,18 +1892,6 @@ var mostlyright = (() => {
1871
1892
  }
1872
1893
  return { dir, speed: spd, time };
1873
1894
  }
1874
- function parseTGroup(rawMetar) {
1875
- if (!rawMetar) return { tempC: null, dewpC: null };
1876
- const rmkIdx = rawMetar.indexOf("RMK");
1877
- if (rmkIdx < 0) return { tempC: null, dewpC: null };
1878
- const m = TGROUP_RE.exec(rawMetar.slice(rmkIdx));
1879
- if (!m) return { tempC: null, dewpC: null };
1880
- const tSign = m[1] === "1" ? -1 : 1;
1881
- const tVal = Number.parseInt(m[2], 10) / 10 * tSign;
1882
- const dSign = m[3] === "1" ? -1 : 1;
1883
- const dVal = Number.parseInt(m[4], 10) / 10 * dSign;
1884
- return { tempC: tVal, dewpC: dVal };
1885
- }
1886
1895
  function safeInt(v) {
1887
1896
  if (v === null || v === void 0) return null;
1888
1897
  const f = typeof v === "number" ? v : Number(v);
@@ -1955,13 +1964,15 @@ var mostlyright = (() => {
1955
1964
  }
1956
1965
  let tempC = safeFloat(m.temp);
1957
1966
  let dewpC = safeFloat(m.dewp);
1958
- const { tempC: tgTemp, dewpC: tgDewp } = parseTGroup(rawMetar);
1959
- if (tgTemp !== null) tempC = tgTemp;
1960
- if (tgDewp !== null) dewpC = tgDewp;
1967
+ const [tgTemp, tgDewp] = parseTgroup(rawMetar);
1968
+ const hasTgroupTemp = tgTemp !== null;
1969
+ const hasTgroupDewp = tgDewp !== null;
1970
+ if (hasTgroupTemp) tempC = tgTemp;
1971
+ if (hasTgroupDewp) dewpC = tgDewp;
1961
1972
  tempC = boundedFloat(tempC, TEMP_MIN_C, TEMP_MAX_C);
1962
1973
  dewpC = boundedFloat(dewpC, TEMP_MIN_C, TEMP_MAX_C);
1963
- const tempF = celsiusToFahrenheit(tempC);
1964
- const dewpointF = celsiusToFahrenheit(dewpC);
1974
+ const tempF = hasTgroupTemp && tempC !== null ? Math.round(tempC * 9 / 5 + 32) : celsiusToFahrenheit(tempC);
1975
+ const dewpointF = hasTgroupDewp && dewpC !== null ? Math.round(dewpC * 9 / 5 + 32) : celsiusToFahrenheit(dewpC);
1965
1976
  const pk = parsePeakWind(rawMetar);
1966
1977
  const pkDir = boundedInt(pk.dir, WIND_DIR_LO, WIND_DIR_HI);
1967
1978
  const pkSpd = boundedInt(pk.speed, 0, WIND_GUST_MAX);
@@ -2001,15 +2012,15 @@ var mostlyright = (() => {
2001
2012
  raw_metar: rawMetar
2002
2013
  };
2003
2014
  }
2004
- var WIND_DIR_LO, WIND_DIR_HI, PK_WND_RE, TGROUP_RE;
2015
+ var WIND_DIR_LO, WIND_DIR_HI, PK_WND_RE;
2005
2016
  var init_awc = __esm({
2006
2017
  "../weather/src/_parsers/awc.ts"() {
2007
2018
  "use strict";
2008
2019
  init_bounds();
2009
2020
  init_convert();
2021
+ init_tgroup();
2010
2022
  [WIND_DIR_LO, WIND_DIR_HI] = WIND_DIR_BOUNDS;
2011
2023
  PK_WND_RE = /PK WND (\d{3})(\d{2,3})\/(\d{4})/;
2012
- TGROUP_RE = /\bT([01])(\d{3})([01])(\d{3})\b/;
2013
2024
  }
2014
2025
  });
2015
2026
 
@@ -2212,12 +2223,19 @@ var mostlyright = (() => {
2212
2223
  const observationType = override !== void 0 ? override : detectObsType(metarText);
2213
2224
  const rawTempF = safeFloat2(row.tmpf ?? "");
2214
2225
  const rawDewpF = safeFloat2(row.dwpf ?? "");
2215
- const tempC = boundedFloat(fahrenheitToCelsius(rawTempF), TEMP_MIN_C, TEMP_MAX_C, {
2226
+ let tempC = boundedFloat(fahrenheitToCelsius(rawTempF), TEMP_MIN_C, TEMP_MAX_C, {
2216
2227
  field: "temp_c"
2217
2228
  });
2218
- const dewpC = boundedFloat(fahrenheitToCelsius(rawDewpF), TEMP_MIN_C, TEMP_MAX_C, {
2229
+ let dewpC = boundedFloat(fahrenheitToCelsius(rawDewpF), TEMP_MIN_C, TEMP_MAX_C, {
2219
2230
  field: "dewpoint_c"
2220
2231
  });
2232
+ const [tgTemp, tgDewp] = parseTgroup(metarText);
2233
+ if (tgTemp !== null && tempC !== null) {
2234
+ tempC = boundedFloat(tgTemp, TEMP_MIN_C, TEMP_MAX_C, { field: "temp_c" });
2235
+ }
2236
+ if (tgDewp !== null && dewpC !== null) {
2237
+ dewpC = boundedFloat(tgDewp, TEMP_MIN_C, TEMP_MAX_C, { field: "dewpoint_c" });
2238
+ }
2221
2239
  const tempF = tempC !== null ? rawTempF : null;
2222
2240
  const dewpF = dewpC !== null ? rawDewpF : null;
2223
2241
  const windDir = boundedInt(safeInt2(row.drct ?? ""), WIND_DIR_LO2, WIND_DIR_HI2);
@@ -2315,6 +2333,7 @@ var mostlyright = (() => {
2315
2333
  "use strict";
2316
2334
  init_bounds();
2317
2335
  init_convert();
2336
+ init_tgroup();
2318
2337
  init_awc();
2319
2338
  [WIND_DIR_LO2, WIND_DIR_HI2] = WIND_DIR_BOUNDS;
2320
2339
  TS_RE = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})$/;
@@ -3226,13 +3245,7 @@ var mostlyright = (() => {
3226
3245
 
3227
3246
  // ../weather/src/forecasts/iem-mos.ts
3228
3247
  var IEM_MOS_URL = "https://mesonet.agron.iastate.edu/api/1/mos.json";
3229
- var SUPPORTED_MODELS = /* @__PURE__ */ new Set([
3230
- "nbe",
3231
- "gfs",
3232
- "lav",
3233
- "met",
3234
- "ecm"
3235
- ]);
3248
+ var SUPPORTED_MODELS = /* @__PURE__ */ new Set(["nbe", "gfs", "lav", "met", "ecm"]);
3236
3249
  var KT_TO_MS2 = 0.5144444;
3237
3250
  var NBE_CYCLE_CUTOVER = Date.UTC(2026, 5 - 1, 5, 0, 0, 0);
3238
3251
  function runtimeHoursFor(model, fromDt, toDt) {
@@ -3275,9 +3288,7 @@ var mostlyright = (() => {
3275
3288
  const issuedDt = parseDate(raw.runtime ?? raw.model_runtime);
3276
3289
  const validDt = parseDate(raw.ftime ?? raw.valid_time);
3277
3290
  if (issuedDt === null || validDt === null) return null;
3278
- const forecastHour = Math.round(
3279
- (validDt.getTime() - issuedDt.getTime()) / 36e5
3280
- );
3291
+ const forecastHour = Math.round((validDt.getTime() - issuedDt.getTime()) / 36e5);
3281
3292
  return {
3282
3293
  station,
3283
3294
  model: model.toUpperCase(),
@@ -3300,9 +3311,7 @@ var mostlyright = (() => {
3300
3311
  function parseIsoDate2(iso, endOfDay) {
3301
3312
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso);
3302
3313
  if (match === null) {
3303
- throw new Error(
3304
- `iemMosForecasts: from/to dates must be ISO YYYY-MM-DD; got ${iso}`
3305
- );
3314
+ throw new Error(`iemMosForecasts: from/to dates must be ISO YYYY-MM-DD; got ${iso}`);
3306
3315
  }
3307
3316
  const [, y, m, d] = match;
3308
3317
  if (endOfDay) {
@@ -3331,15 +3340,13 @@ var mostlyright = (() => {
3331
3340
  if (rt < fromDt || rt > toDt) continue;
3332
3341
  const url = `${IEM_MOS_URL}?station=${encodeURIComponent(
3333
3342
  station
3334
- )}&model=${encodeURIComponent(model)}&runtime=${encodeURIComponent(
3343
+ )}&model=${encodeURIComponent(model.toUpperCase())}&runtime=${encodeURIComponent(
3335
3344
  rt.toISOString()
3336
3345
  )}`;
3337
3346
  const resp = await fetchFn(url);
3338
3347
  if (resp.status === 404) continue;
3339
3348
  if (!resp.ok) {
3340
- throw new Error(
3341
- `iemMosForecasts: HTTP ${resp.status} on ${url}`
3342
- );
3349
+ throw new Error(`iemMosForecasts: HTTP ${resp.status} on ${url}`);
3343
3350
  }
3344
3351
  const payload = await resp.json();
3345
3352
  for (const raw of payload.data ?? []) {