mostlyright 1.5.1 → 1.6.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.
- package/dist/{chunk-OTJGBPL4.mjs → chunk-4RWHWFV3.mjs} +8 -4
- package/dist/chunk-4RWHWFV3.mjs.map +1 -0
- package/dist/{iem-asos-BPSHDERE.mjs → iem-asos-GEUKTQTM.mjs} +2 -2
- package/dist/index.bundle.mjs +61 -25
- package/dist/index.bundle.mjs.map +1 -1
- package/dist/index.global.js +74 -26
- package/dist/index.global.js.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-OTJGBPL4.mjs.map +0 -1
- /package/dist/{iem-asos-BPSHDERE.mjs.map → iem-asos-GEUKTQTM.mjs.map} +0 -0
package/dist/index.global.js
CHANGED
|
@@ -63,6 +63,13 @@ var mostlyright = (() => {
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
// ../core/src/schemas/generated/forecast_nwp.v1.ts
|
|
67
|
+
var init_forecast_nwp_v1 = __esm({
|
|
68
|
+
"../core/src/schemas/generated/forecast_nwp.v1.ts"() {
|
|
69
|
+
"use strict";
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
66
73
|
// ../core/src/schemas/generated/index.ts
|
|
67
74
|
var init_generated = __esm({
|
|
68
75
|
"../core/src/schemas/generated/index.ts"() {
|
|
@@ -73,6 +80,7 @@ var mostlyright = (() => {
|
|
|
73
80
|
init_settlement_cli_v1();
|
|
74
81
|
init_observation_ledger_v1();
|
|
75
82
|
init_observation_qc_v1();
|
|
83
|
+
init_forecast_nwp_v1();
|
|
76
84
|
}
|
|
77
85
|
});
|
|
78
86
|
|
|
@@ -2917,6 +2925,11 @@ var mostlyright = (() => {
|
|
|
2917
2925
|
Number.parseInt(parts[2], 10)
|
|
2918
2926
|
];
|
|
2919
2927
|
}
|
|
2928
|
+
function addOneDay(iso) {
|
|
2929
|
+
const [y, m, d] = splitIso(iso);
|
|
2930
|
+
const next = new Date(Date.UTC(y, m - 1, d + 1));
|
|
2931
|
+
return next.toISOString().slice(0, 10);
|
|
2932
|
+
}
|
|
2920
2933
|
async function downloadIemAsos(stationCode, start, end, opts = {}) {
|
|
2921
2934
|
const reportType = opts.reportType ?? 3;
|
|
2922
2935
|
if (!VALID_REPORT_TYPES.has(reportType)) {
|
|
@@ -2926,10 +2939,9 @@ var mostlyright = (() => {
|
|
|
2926
2939
|
if (start > end) {
|
|
2927
2940
|
return [];
|
|
2928
2941
|
}
|
|
2929
|
-
const
|
|
2930
|
-
const chunks = yearlyChunksExclusiveEnd(normalizedStart, end);
|
|
2942
|
+
const chunks = opts.exactStart ? [[start, addOneDay(end)]] : yearlyChunksExclusiveEnd(`${start.slice(0, 4)}-01-01`, end);
|
|
2931
2943
|
const politenessMs = opts.politenessMs ?? IEM_POLITE_DELAY_MS;
|
|
2932
|
-
const { reportType: _rtDrop, politenessMs: _pmDrop, ...fetchOpts } = opts;
|
|
2944
|
+
const { reportType: _rtDrop, politenessMs: _pmDrop, exactStart: _esDrop, ...fetchOpts } = opts;
|
|
2933
2945
|
const out = [];
|
|
2934
2946
|
for (const [chunkStart, chunkEnd] of chunks) {
|
|
2935
2947
|
const url = buildIemUrl(stationCode, chunkStart, chunkEnd, reportType);
|
|
@@ -4075,6 +4087,26 @@ var mostlyright = (() => {
|
|
|
4075
4087
|
var SUPPORTED_MODELS = /* @__PURE__ */ new Set(["nbe", "gfs", "lav", "met", "ecm"]);
|
|
4076
4088
|
var KT_TO_MS2 = 0.5144444;
|
|
4077
4089
|
var NBE_CYCLE_CUTOVER = Date.UTC(2026, 5 - 1, 5, 0, 0, 0);
|
|
4090
|
+
var MOS_FETCH_CONCURRENCY = 8;
|
|
4091
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
4092
|
+
const results = new Array(items.length);
|
|
4093
|
+
let cursor = 0;
|
|
4094
|
+
let failed = false;
|
|
4095
|
+
async function worker() {
|
|
4096
|
+
while (cursor < items.length && !failed) {
|
|
4097
|
+
const index = cursor++;
|
|
4098
|
+
try {
|
|
4099
|
+
results[index] = await fn(items[index], index);
|
|
4100
|
+
} catch (err) {
|
|
4101
|
+
failed = true;
|
|
4102
|
+
throw err;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
const poolSize = Math.min(limit, items.length);
|
|
4107
|
+
await Promise.all(Array.from({ length: poolSize }, () => worker()));
|
|
4108
|
+
return results;
|
|
4109
|
+
}
|
|
4078
4110
|
function runtimeHoursFor(model, fromDt, toDt) {
|
|
4079
4111
|
if (model !== "nbe") return [0, 6, 12, 18];
|
|
4080
4112
|
const fromMs = fromDt.getTime();
|
|
@@ -4158,31 +4190,37 @@ var mostlyright = (() => {
|
|
|
4158
4190
|
const toDt = parseIsoDate2(toDate, true);
|
|
4159
4191
|
const hours = runtimeHoursFor(model, fromDt, toDt);
|
|
4160
4192
|
const retrievedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4161
|
-
const rows = [];
|
|
4162
4193
|
const dayMs = 864e5;
|
|
4194
|
+
const urls = [];
|
|
4163
4195
|
for (let day = fromDt.getTime(); day <= toDt.getTime(); day += dayMs) {
|
|
4164
4196
|
for (const h of hours) {
|
|
4165
4197
|
const rt = new Date(day);
|
|
4166
4198
|
rt.setUTCHours(h, 0, 0, 0);
|
|
4167
4199
|
if (rt < fromDt || rt > toDt) continue;
|
|
4168
|
-
|
|
4169
|
-
station
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
if (!resp.ok) {
|
|
4176
|
-
throw new Error(`iemMosForecasts: HTTP ${resp.status} on ${url}`);
|
|
4177
|
-
}
|
|
4178
|
-
const payload = await resp.json();
|
|
4179
|
-
for (const raw of payload.data ?? []) {
|
|
4180
|
-
const projected = parseRow(raw, station, model, retrievedAt);
|
|
4181
|
-
if (projected !== null) rows.push(projected);
|
|
4182
|
-
}
|
|
4200
|
+
urls.push(
|
|
4201
|
+
`${IEM_MOS_URL}?station=${encodeURIComponent(
|
|
4202
|
+
station
|
|
4203
|
+
)}&model=${encodeURIComponent(model.toUpperCase())}&runtime=${encodeURIComponent(
|
|
4204
|
+
rt.toISOString()
|
|
4205
|
+
)}`
|
|
4206
|
+
);
|
|
4183
4207
|
}
|
|
4184
4208
|
}
|
|
4185
|
-
|
|
4209
|
+
const perCycle = await mapWithConcurrency(urls, MOS_FETCH_CONCURRENCY, async (url) => {
|
|
4210
|
+
const resp = await fetchFn(url);
|
|
4211
|
+
if (resp.status === 404) return [];
|
|
4212
|
+
if (!resp.ok) {
|
|
4213
|
+
throw new Error(`iemMosForecasts: HTTP ${resp.status} on ${url}`);
|
|
4214
|
+
}
|
|
4215
|
+
const payload = await resp.json();
|
|
4216
|
+
const out = [];
|
|
4217
|
+
for (const raw of payload.data ?? []) {
|
|
4218
|
+
const projected = parseRow(raw, station, model, retrievedAt);
|
|
4219
|
+
if (projected !== null) out.push(projected);
|
|
4220
|
+
}
|
|
4221
|
+
return out;
|
|
4222
|
+
});
|
|
4223
|
+
return perCycle.flat();
|
|
4186
4224
|
}
|
|
4187
4225
|
|
|
4188
4226
|
// ../weather/src/forecasts/nwp-stub.ts
|
|
@@ -4461,6 +4499,15 @@ var mostlyright = (() => {
|
|
|
4461
4499
|
const n = typeof value === "number" ? value : Number(value);
|
|
4462
4500
|
return Number.isFinite(n) ? n : null;
|
|
4463
4501
|
}
|
|
4502
|
+
function maybeInt(value) {
|
|
4503
|
+
const n = maybeNumber2(value);
|
|
4504
|
+
if (n === null) return null;
|
|
4505
|
+
const floor = Math.floor(n);
|
|
4506
|
+
const diff = n - floor;
|
|
4507
|
+
if (diff < 0.5) return floor;
|
|
4508
|
+
if (diff > 0.5) return floor + 1;
|
|
4509
|
+
return floor % 2 === 0 ? floor : floor + 1;
|
|
4510
|
+
}
|
|
4464
4511
|
function pickHourlyValue(hourly, key, isPreviousRuns, idx) {
|
|
4465
4512
|
const arr = isPreviousRuns ? hourly[`${key}_previous_day1`] ?? hourly[key] : hourly[key];
|
|
4466
4513
|
if (!Array.isArray(arr) || idx >= arr.length) return null;
|
|
@@ -4556,20 +4603,20 @@ var mostlyright = (() => {
|
|
|
4556
4603
|
dewPointC: maybeNumber2(pickHourlyValue(h, "dew_point_2m", isPrev, i)),
|
|
4557
4604
|
apparentTempC: maybeNumber2(pickHourlyValue(h, "apparent_temperature", isPrev, i)),
|
|
4558
4605
|
windSpeedMs: maybeNumber2(pickHourlyValue(h, "wind_speed_10m", isPrev, i)),
|
|
4559
|
-
windDirDeg:
|
|
4606
|
+
windDirDeg: maybeInt(pickHourlyValue(h, "wind_direction_10m", isPrev, i)),
|
|
4560
4607
|
windGustsMs: maybeNumber2(pickHourlyValue(h, "wind_gusts_10m", isPrev, i)),
|
|
4561
4608
|
precipProbability: popPct === null ? null : popPct / 100,
|
|
4562
4609
|
precipitationMm: maybeNumber2(pickHourlyValue(h, "precipitation", isPrev, i)),
|
|
4563
|
-
cloudCoverPct:
|
|
4610
|
+
cloudCoverPct: maybeInt(pickHourlyValue(h, "cloud_cover", isPrev, i)),
|
|
4564
4611
|
surfacePressureHpa: maybeNumber2(pickHourlyValue(h, "surface_pressure", isPrev, i)),
|
|
4565
4612
|
pressureMslHpa: maybeNumber2(pickHourlyValue(h, "pressure_msl", isPrev, i)),
|
|
4566
4613
|
shortwaveRadiationWm2: maybeNumber2(pickHourlyValue(h, "shortwave_radiation", isPrev, i)),
|
|
4567
4614
|
directRadiationWm2: maybeNumber2(pickHourlyValue(h, "direct_radiation", isPrev, i)),
|
|
4568
4615
|
capeJkg: maybeNumber2(pickHourlyValue(h, "cape", isPrev, i)),
|
|
4569
|
-
freezingLevelM:
|
|
4616
|
+
freezingLevelM: maybeInt(pickHourlyValue(h, "freezing_level_height", isPrev, i)),
|
|
4570
4617
|
snowDepthM: maybeNumber2(pickHourlyValue(h, "snow_depth", isPrev, i)),
|
|
4571
|
-
visibilityM:
|
|
4572
|
-
weatherCode:
|
|
4618
|
+
visibilityM: maybeInt(pickHourlyValue(h, "visibility", isPrev, i)),
|
|
4619
|
+
weatherCode: maybeInt(pickHourlyValue(h, "weather_code", isPrev, i)),
|
|
4573
4620
|
source,
|
|
4574
4621
|
retrievedAt
|
|
4575
4622
|
});
|
|
@@ -6496,7 +6543,8 @@ var mostlyright = (() => {
|
|
|
6496
6543
|
if (resolvedStrategy === "exact_window") {
|
|
6497
6544
|
const chunks = await downloadIemAsos(station, fromDate, toDate, {
|
|
6498
6545
|
reportType: 3,
|
|
6499
|
-
politenessMs: 1e3
|
|
6546
|
+
politenessMs: 1e3,
|
|
6547
|
+
exactStart: true
|
|
6500
6548
|
});
|
|
6501
6549
|
for (const chunk of chunks) {
|
|
6502
6550
|
const rows = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|