mostlyright 1.1.2 → 1.2.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/README.md +3 -3
- package/dist/{chunk-465FJZTS.mjs → chunk-64FNXDHG.mjs} +2 -2
- package/dist/{chunk-IN2UOZYO.mjs → chunk-WKPNA46C.mjs} +40 -2
- package/dist/chunk-WKPNA46C.mjs.map +1 -0
- package/dist/{iem-asos-ZPUMH3KM.mjs → iem-asos-2D5EP2FT.mjs} +3 -3
- package/dist/index.bundle.mjs +1794 -167
- package/dist/index.bundle.mjs.map +1 -1
- package/dist/index.cjs +90 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.global.js +1843 -169
- package/dist/index.global.js.map +1 -1
- package/dist/index.mjs +91 -13
- package/dist/index.mjs.map +1 -1
- package/dist/{src-NP2MZ322.mjs → src-BBELB6SP.mjs} +6 -2
- package/package.json +36 -5
- package/dist/chunk-IN2UOZYO.mjs.map +0 -1
- /package/dist/{chunk-465FJZTS.mjs.map → chunk-64FNXDHG.mjs.map} +0 -0
- /package/dist/{iem-asos-ZPUMH3KM.mjs.map → iem-asos-2D5EP2FT.mjs.map} +0 -0
- /package/dist/{src-NP2MZ322.mjs.map → src-BBELB6SP.mjs.map} +0 -0
package/dist/index.global.js
CHANGED
|
@@ -962,7 +962,7 @@ var mostlyright = (() => {
|
|
|
962
962
|
}
|
|
963
963
|
return { _repr_only: true, value: String(value) };
|
|
964
964
|
}
|
|
965
|
-
var TradewindsError, SourceUnavailableError, SchemaValidationError, SourceMismatchError, LeakageError, TemporalDriftError, PayloadTooLargeError, DeferredMarketError, PolymarketEventError, TherminalError, NotFoundError, RateLimitError, ValidationError, AuthenticationError, ForbiddenError, ServerError, LiveStreamError, NoLiveDataError;
|
|
965
|
+
var TradewindsError, SourceUnavailableError, DATA_AVAILABILITY_REASONS, DataAvailabilityError, SchemaValidationError, SourceMismatchError, LeakageError, TemporalDriftError, PayloadTooLargeError, DeferredMarketError, PolymarketEventError, TherminalError, NotFoundError, RateLimitError, ValidationError, AuthenticationError, ForbiddenError, ServerError, LiveStreamError, NoLiveDataError;
|
|
966
966
|
var init_exceptions = __esm({
|
|
967
967
|
"../core/src/exceptions/index.ts"() {
|
|
968
968
|
"use strict";
|
|
@@ -1026,6 +1026,40 @@ var mostlyright = (() => {
|
|
|
1026
1026
|
};
|
|
1027
1027
|
}
|
|
1028
1028
|
};
|
|
1029
|
+
DATA_AVAILABILITY_REASONS = [
|
|
1030
|
+
"model_unavailable",
|
|
1031
|
+
"out_of_window",
|
|
1032
|
+
"cache_miss",
|
|
1033
|
+
"source_404",
|
|
1034
|
+
"source_5xx",
|
|
1035
|
+
"rate_limited"
|
|
1036
|
+
];
|
|
1037
|
+
DataAvailabilityError = class extends TradewindsError {
|
|
1038
|
+
static defaultErrorCode = "DATA_AVAILABILITY";
|
|
1039
|
+
reason;
|
|
1040
|
+
hint;
|
|
1041
|
+
constructor(options) {
|
|
1042
|
+
if (!DATA_AVAILABILITY_REASONS.includes(options.reason)) {
|
|
1043
|
+
throw new RangeError(
|
|
1044
|
+
`DataAvailabilityError: unknown reason "${String(options.reason)}". Valid reasons: ${DATA_AVAILABILITY_REASONS.join(", ")}`
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
if (typeof options.hint !== "string" || options.hint.length === 0) {
|
|
1048
|
+
throw new TypeError("DataAvailabilityError: hint is required and must be a non-empty string");
|
|
1049
|
+
}
|
|
1050
|
+
const message = `[${options.reason}] ${options.hint}`;
|
|
1051
|
+
super(message, options);
|
|
1052
|
+
this.reason = options.reason;
|
|
1053
|
+
this.hint = options.hint;
|
|
1054
|
+
}
|
|
1055
|
+
payload() {
|
|
1056
|
+
return {
|
|
1057
|
+
...super.payload(),
|
|
1058
|
+
reason: this.reason,
|
|
1059
|
+
hint: this.hint
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1029
1063
|
SchemaValidationError = class extends TradewindsError {
|
|
1030
1064
|
static defaultErrorCode = "SCHEMA_VALIDATION_FAILED";
|
|
1031
1065
|
schemaId;
|
|
@@ -1212,7 +1246,7 @@ var mostlyright = (() => {
|
|
|
1212
1246
|
NoLiveDataError = class extends LiveStreamError {
|
|
1213
1247
|
static defaultErrorCode = "NO_LIVE_DATA";
|
|
1214
1248
|
station;
|
|
1215
|
-
constructor(message
|
|
1249
|
+
constructor(message, options) {
|
|
1216
1250
|
super(message, { ...options, source: options.source });
|
|
1217
1251
|
this.station = options.station;
|
|
1218
1252
|
}
|
|
@@ -1628,6 +1662,8 @@ var mostlyright = (() => {
|
|
|
1628
1662
|
__export(src_exports, {
|
|
1629
1663
|
AuthenticationError: () => AuthenticationError,
|
|
1630
1664
|
CLIMATE_REPORT_TYPE_PRIORITY: () => CLIMATE_REPORT_TYPE_PRIORITY,
|
|
1665
|
+
DATA_AVAILABILITY_REASONS: () => DATA_AVAILABILITY_REASONS,
|
|
1666
|
+
DataAvailabilityError: () => DataAvailabilityError,
|
|
1631
1667
|
DeferredMarketError: () => DeferredMarketError,
|
|
1632
1668
|
ForbiddenError: () => ForbiddenError,
|
|
1633
1669
|
LIVE_V1_POLICY: () => LIVE_V1_POLICY,
|
|
@@ -2322,8 +2358,8 @@ var mostlyright = (() => {
|
|
|
2322
2358
|
const key = header[c];
|
|
2323
2359
|
row[key] = (cells[c] ?? "").trim();
|
|
2324
2360
|
}
|
|
2325
|
-
const
|
|
2326
|
-
if (
|
|
2361
|
+
const obs2 = iemToObservation(row, opts);
|
|
2362
|
+
if (obs2 !== null) out.push(obs2);
|
|
2327
2363
|
}
|
|
2328
2364
|
return out;
|
|
2329
2365
|
}
|
|
@@ -2348,6 +2384,7 @@ var mostlyright = (() => {
|
|
|
2348
2384
|
MODE2_SOURCES: () => MODE2_SOURCES,
|
|
2349
2385
|
NoLiveDataError: () => NoLiveDataError,
|
|
2350
2386
|
POLITE_FLOORS_S: () => POLITE_FLOORS_S,
|
|
2387
|
+
Preprocessing: () => Preprocessing,
|
|
2351
2388
|
SELECTOR_NAMES: () => SELECTOR_NAMES,
|
|
2352
2389
|
SOURCE_ALIASES: () => SOURCE_ALIASES,
|
|
2353
2390
|
SOURCE_IDENTITY_TAGS: () => SOURCE_IDENTITY_TAGS,
|
|
@@ -2356,6 +2393,7 @@ var mostlyright = (() => {
|
|
|
2356
2393
|
assertSourceIdentity: () => assertSourceIdentity,
|
|
2357
2394
|
buildOverrideWarning: () => buildOverrideWarning,
|
|
2358
2395
|
core: () => src_exports,
|
|
2396
|
+
dailyExtremes: () => dailyExtremes,
|
|
2359
2397
|
discover: () => discover,
|
|
2360
2398
|
helloCore: () => helloCore,
|
|
2361
2399
|
helloMarkets: () => helloMarkets,
|
|
@@ -2364,6 +2402,8 @@ var mostlyright = (() => {
|
|
|
2364
2402
|
isMode2Source: () => isMode2Source,
|
|
2365
2403
|
latest: () => latest,
|
|
2366
2404
|
markets: () => src_exports3,
|
|
2405
|
+
obs: () => obs,
|
|
2406
|
+
preprocessing: () => preprocessing_exports,
|
|
2367
2407
|
research: () => research,
|
|
2368
2408
|
researchBySource: () => researchBySource,
|
|
2369
2409
|
resolveCity: () => resolveCity,
|
|
@@ -2401,6 +2441,7 @@ var mostlyright = (() => {
|
|
|
2401
2441
|
SUPPORTED_SOURCES: () => SUPPORTED_SOURCES,
|
|
2402
2442
|
awcToObservation: () => awcToObservation,
|
|
2403
2443
|
buildIemUrl: () => buildIemUrl,
|
|
2444
|
+
dailyExtremes: () => dailyExtremes,
|
|
2404
2445
|
downloadCli: () => downloadCli,
|
|
2405
2446
|
downloadCliRange: () => downloadCliRange,
|
|
2406
2447
|
downloadGhcnh: () => downloadGhcnh,
|
|
@@ -2419,12 +2460,14 @@ var mostlyright = (() => {
|
|
|
2419
2460
|
latest: () => latest,
|
|
2420
2461
|
mapCloudCover: () => mapCloudCover,
|
|
2421
2462
|
mergeClimate: () => mergeClimate,
|
|
2463
|
+
obs: () => obs,
|
|
2422
2464
|
parseAwcVisibility: () => parseAwcVisibility,
|
|
2423
2465
|
parseCliRecord: () => parseCliRecord,
|
|
2424
2466
|
parseCliResponse: () => parseCliResponse,
|
|
2425
2467
|
parseGhcnhPsv: () => parseGhcnhPsv,
|
|
2426
2468
|
parseGhcnhRow: () => parseGhcnhRow,
|
|
2427
2469
|
parseIemCsv: () => parseIemCsv,
|
|
2470
|
+
resolveAutoStrategy: () => resolveAutoStrategy,
|
|
2428
2471
|
sourceTag: () => sourceTag,
|
|
2429
2472
|
stream: () => stream,
|
|
2430
2473
|
validatePollSeconds: () => validatePollSeconds,
|
|
@@ -2626,10 +2669,10 @@ var mostlyright = (() => {
|
|
|
2626
2669
|
if (!product) return "preliminary";
|
|
2627
2670
|
const issued = parseProductTimestamp(product);
|
|
2628
2671
|
if (issued === null) return "preliminary";
|
|
2629
|
-
const
|
|
2630
|
-
if (
|
|
2672
|
+
const obs2 = parseObservationDate(observationDate);
|
|
2673
|
+
if (obs2 === null) return "preliminary";
|
|
2631
2674
|
const issuedDayUtc = Date.UTC(issued.getUTCFullYear(), issued.getUTCMonth(), issued.getUTCDate());
|
|
2632
|
-
const obsDayUtc =
|
|
2675
|
+
const obsDayUtc = obs2.getTime();
|
|
2633
2676
|
const deltaDays = Math.round((issuedDayUtc - obsDayUtc) / 864e5);
|
|
2634
2677
|
if (deltaDays <= 0) return "preliminary";
|
|
2635
2678
|
if (deltaDays === 1) {
|
|
@@ -3005,8 +3048,8 @@ var mostlyright = (() => {
|
|
|
3005
3048
|
const key = header[c];
|
|
3006
3049
|
row[key] = c < cells.length ? cells[c] : "";
|
|
3007
3050
|
}
|
|
3008
|
-
const
|
|
3009
|
-
if (
|
|
3051
|
+
const obs2 = parseGhcnhRow(row);
|
|
3052
|
+
if (obs2 !== null) out.push(obs2);
|
|
3010
3053
|
}
|
|
3011
3054
|
return out;
|
|
3012
3055
|
}
|
|
@@ -3075,8 +3118,8 @@ var mostlyright = (() => {
|
|
|
3075
3118
|
if (s.length === 3) return `K${s}`;
|
|
3076
3119
|
return s;
|
|
3077
3120
|
}
|
|
3078
|
-
function asLiveObservation(
|
|
3079
|
-
return { ...
|
|
3121
|
+
function asLiveObservation(obs2, tag) {
|
|
3122
|
+
return { ...obs2, source: tag };
|
|
3080
3123
|
}
|
|
3081
3124
|
async function fetchAwcLatest(station) {
|
|
3082
3125
|
const icao = normalizeStation(station);
|
|
@@ -3084,9 +3127,9 @@ var mostlyright = (() => {
|
|
|
3084
3127
|
const tag = sourceTag("awc");
|
|
3085
3128
|
const rows = [];
|
|
3086
3129
|
for (const m of raw) {
|
|
3087
|
-
const
|
|
3088
|
-
if (
|
|
3089
|
-
rows.push(asLiveObservation(
|
|
3130
|
+
const obs2 = awcToObservation(m);
|
|
3131
|
+
if (obs2 !== null) {
|
|
3132
|
+
rows.push(asLiveObservation(obs2, tag));
|
|
3090
3133
|
}
|
|
3091
3134
|
}
|
|
3092
3135
|
return rows;
|
|
@@ -3142,8 +3185,8 @@ var mostlyright = (() => {
|
|
|
3142
3185
|
const response = await fetchWithRetry2(url);
|
|
3143
3186
|
const csv = await response.text();
|
|
3144
3187
|
const override = reportType === 3 ? "METAR" : "SPECI";
|
|
3145
|
-
const
|
|
3146
|
-
for (const row of
|
|
3188
|
+
const obs2 = parseIemCsv2(csv, { observationTypeOverride: override });
|
|
3189
|
+
for (const row of obs2) {
|
|
3147
3190
|
rows.push(asLiveObservation(row, tag));
|
|
3148
3191
|
}
|
|
3149
3192
|
}
|
|
@@ -3355,14 +3398,1394 @@ var mostlyright = (() => {
|
|
|
3355
3398
|
}
|
|
3356
3399
|
}
|
|
3357
3400
|
}
|
|
3358
|
-
return rows;
|
|
3401
|
+
return rows;
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
// ../weather/src/forecasts/nwp-stub.ts
|
|
3405
|
+
init_src();
|
|
3406
|
+
var IEM_MOS_COVERED_STATIONS = /* @__PURE__ */ new Set([
|
|
3407
|
+
"KNYC",
|
|
3408
|
+
"KLAX",
|
|
3409
|
+
"KORD",
|
|
3410
|
+
"KMIA",
|
|
3411
|
+
"KDEN",
|
|
3412
|
+
"KSEA",
|
|
3413
|
+
"KATL"
|
|
3414
|
+
]);
|
|
3415
|
+
function buildHint(station, model) {
|
|
3416
|
+
const hasMosCoverage = IEM_MOS_COVERED_STATIONS.has(station.toUpperCase());
|
|
3417
|
+
const mosLine = hasMosCoverage ? `Workaround for ${station}: iemMosForecasts("${station}", ...) is available (IEM MOS catalog covers this station).` : `Workaround: this station has no IEM MOS coverage; use the Python SDK's mostlyright.forecast_nwp() in v1.x.`;
|
|
3418
|
+
return `forecastNwp(${station}, "${model}") is a v1.x stub. Browser GRIB2 decode is not production-ready in May 2026 (no eccodes / cfgrib equivalent for the browser; WASM compile time + bundle size make it impractical for v1.x). ${mosLine} See https://mostlyright.md/docs/sdk/typescript/forecasts#typescript-lane for the architectural reason + v1.1+ tracking.`;
|
|
3419
|
+
}
|
|
3420
|
+
async function forecastNwp(station, model, _opts = {}) {
|
|
3421
|
+
throw new DataAvailabilityError({
|
|
3422
|
+
reason: "model_unavailable",
|
|
3423
|
+
source: "nwp-stub",
|
|
3424
|
+
hint: buildHint(station, model)
|
|
3425
|
+
});
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
// ../weather/src/dailyExtremes.ts
|
|
3429
|
+
init_src();
|
|
3430
|
+
|
|
3431
|
+
// ../core/dist/discovery/index.mjs
|
|
3432
|
+
var STATIONS2 = [
|
|
3433
|
+
{
|
|
3434
|
+
code: "EDDB",
|
|
3435
|
+
country: "DE",
|
|
3436
|
+
ghcnh_id: null,
|
|
3437
|
+
icao: "EDDB",
|
|
3438
|
+
latitude: 52.3667,
|
|
3439
|
+
longitude: 13.5033,
|
|
3440
|
+
name: "Berlin Brandenburg",
|
|
3441
|
+
tz: "Europe/Berlin"
|
|
3442
|
+
},
|
|
3443
|
+
{
|
|
3444
|
+
code: "EDDF",
|
|
3445
|
+
country: "DE",
|
|
3446
|
+
ghcnh_id: null,
|
|
3447
|
+
icao: "EDDF",
|
|
3448
|
+
latitude: 50.0379,
|
|
3449
|
+
longitude: 8.5622,
|
|
3450
|
+
name: "Frankfurt am Main",
|
|
3451
|
+
tz: "Europe/Berlin"
|
|
3452
|
+
},
|
|
3453
|
+
{
|
|
3454
|
+
code: "EDDM",
|
|
3455
|
+
country: "DE",
|
|
3456
|
+
ghcnh_id: null,
|
|
3457
|
+
icao: "EDDM",
|
|
3458
|
+
latitude: 48.3538,
|
|
3459
|
+
longitude: 11.7861,
|
|
3460
|
+
name: "Munich Franz Josef Strauss",
|
|
3461
|
+
tz: "Europe/Berlin"
|
|
3462
|
+
},
|
|
3463
|
+
{
|
|
3464
|
+
code: "EFHK",
|
|
3465
|
+
country: "FI",
|
|
3466
|
+
ghcnh_id: null,
|
|
3467
|
+
icao: "EFHK",
|
|
3468
|
+
latitude: 60.3172,
|
|
3469
|
+
longitude: 24.9633,
|
|
3470
|
+
name: "Helsinki-Vantaa",
|
|
3471
|
+
tz: "Europe/Helsinki"
|
|
3472
|
+
},
|
|
3473
|
+
{
|
|
3474
|
+
code: "EGKK",
|
|
3475
|
+
country: "GB",
|
|
3476
|
+
ghcnh_id: null,
|
|
3477
|
+
icao: "EGKK",
|
|
3478
|
+
latitude: 51.1481,
|
|
3479
|
+
longitude: -0.1903,
|
|
3480
|
+
name: "London Gatwick",
|
|
3481
|
+
tz: "Europe/London"
|
|
3482
|
+
},
|
|
3483
|
+
{
|
|
3484
|
+
code: "EGLL",
|
|
3485
|
+
country: "GB",
|
|
3486
|
+
ghcnh_id: null,
|
|
3487
|
+
icao: "EGLL",
|
|
3488
|
+
latitude: 51.4706,
|
|
3489
|
+
longitude: -0.4619,
|
|
3490
|
+
name: "London Heathrow",
|
|
3491
|
+
tz: "Europe/London"
|
|
3492
|
+
},
|
|
3493
|
+
{
|
|
3494
|
+
code: "EHAM",
|
|
3495
|
+
country: "NL",
|
|
3496
|
+
ghcnh_id: null,
|
|
3497
|
+
icao: "EHAM",
|
|
3498
|
+
latitude: 52.3086,
|
|
3499
|
+
longitude: 4.7639,
|
|
3500
|
+
name: "Amsterdam Schiphol",
|
|
3501
|
+
tz: "Europe/Amsterdam"
|
|
3502
|
+
},
|
|
3503
|
+
{
|
|
3504
|
+
code: "EKCH",
|
|
3505
|
+
country: "DK",
|
|
3506
|
+
ghcnh_id: null,
|
|
3507
|
+
icao: "EKCH",
|
|
3508
|
+
latitude: 55.6181,
|
|
3509
|
+
longitude: 12.6561,
|
|
3510
|
+
name: "Copenhagen Kastrup",
|
|
3511
|
+
tz: "Europe/Copenhagen"
|
|
3512
|
+
},
|
|
3513
|
+
{
|
|
3514
|
+
code: "EPWA",
|
|
3515
|
+
country: "PL",
|
|
3516
|
+
ghcnh_id: null,
|
|
3517
|
+
icao: "EPWA",
|
|
3518
|
+
latitude: 52.1657,
|
|
3519
|
+
longitude: 20.9671,
|
|
3520
|
+
name: "Warsaw Chopin",
|
|
3521
|
+
tz: "Europe/Warsaw"
|
|
3522
|
+
},
|
|
3523
|
+
{
|
|
3524
|
+
code: "ESSA",
|
|
3525
|
+
country: "SE",
|
|
3526
|
+
ghcnh_id: null,
|
|
3527
|
+
icao: "ESSA",
|
|
3528
|
+
latitude: 59.6519,
|
|
3529
|
+
longitude: 17.9186,
|
|
3530
|
+
name: "Stockholm Arlanda",
|
|
3531
|
+
tz: "Europe/Stockholm"
|
|
3532
|
+
},
|
|
3533
|
+
{
|
|
3534
|
+
code: "ATL",
|
|
3535
|
+
country: "US",
|
|
3536
|
+
ghcnh_id: "USW00013874",
|
|
3537
|
+
icao: "KATL",
|
|
3538
|
+
latitude: 33.6407,
|
|
3539
|
+
longitude: -84.4277,
|
|
3540
|
+
name: "Hartsfield-Jackson Atlanta International",
|
|
3541
|
+
tz: "America/New_York"
|
|
3542
|
+
},
|
|
3543
|
+
{
|
|
3544
|
+
code: "AUS",
|
|
3545
|
+
country: "US",
|
|
3546
|
+
ghcnh_id: "USW00013904",
|
|
3547
|
+
icao: "KAUS",
|
|
3548
|
+
latitude: 30.1975,
|
|
3549
|
+
longitude: -97.6664,
|
|
3550
|
+
name: "Austin-Bergstrom International",
|
|
3551
|
+
tz: "America/Chicago"
|
|
3552
|
+
},
|
|
3553
|
+
{
|
|
3554
|
+
code: "BOS",
|
|
3555
|
+
country: "US",
|
|
3556
|
+
ghcnh_id: "USW00014739",
|
|
3557
|
+
icao: "KBOS",
|
|
3558
|
+
latitude: 42.3656,
|
|
3559
|
+
longitude: -71.0096,
|
|
3560
|
+
name: "Boston Logan International",
|
|
3561
|
+
tz: "America/New_York"
|
|
3562
|
+
},
|
|
3563
|
+
{
|
|
3564
|
+
code: "DCA",
|
|
3565
|
+
country: "US",
|
|
3566
|
+
ghcnh_id: "USW00013743",
|
|
3567
|
+
icao: "KDCA",
|
|
3568
|
+
latitude: 38.8512,
|
|
3569
|
+
longitude: -77.0402,
|
|
3570
|
+
name: "Washington Reagan National",
|
|
3571
|
+
tz: "America/New_York"
|
|
3572
|
+
},
|
|
3573
|
+
{
|
|
3574
|
+
code: "DEN",
|
|
3575
|
+
country: "US",
|
|
3576
|
+
ghcnh_id: "USW00003017",
|
|
3577
|
+
icao: "KDEN",
|
|
3578
|
+
latitude: 39.8561,
|
|
3579
|
+
longitude: -104.6737,
|
|
3580
|
+
name: "Denver International",
|
|
3581
|
+
tz: "America/Denver"
|
|
3582
|
+
},
|
|
3583
|
+
{
|
|
3584
|
+
code: "DFW",
|
|
3585
|
+
country: "US",
|
|
3586
|
+
ghcnh_id: "USW00003927",
|
|
3587
|
+
icao: "KDFW",
|
|
3588
|
+
latitude: 32.8998,
|
|
3589
|
+
longitude: -97.0403,
|
|
3590
|
+
name: "Dallas-Fort Worth International",
|
|
3591
|
+
tz: "America/Chicago"
|
|
3592
|
+
},
|
|
3593
|
+
{
|
|
3594
|
+
code: "HOU",
|
|
3595
|
+
country: "US",
|
|
3596
|
+
ghcnh_id: "USW00012918",
|
|
3597
|
+
icao: "KHOU",
|
|
3598
|
+
latitude: 29.6454,
|
|
3599
|
+
longitude: -95.2789,
|
|
3600
|
+
name: "Houston Hobby",
|
|
3601
|
+
tz: "America/Chicago"
|
|
3602
|
+
},
|
|
3603
|
+
{
|
|
3604
|
+
code: "LAS",
|
|
3605
|
+
country: "US",
|
|
3606
|
+
ghcnh_id: "USW00023169",
|
|
3607
|
+
icao: "KLAS",
|
|
3608
|
+
latitude: 36.084,
|
|
3609
|
+
longitude: -115.1537,
|
|
3610
|
+
name: "Harry Reid (McCarran) International",
|
|
3611
|
+
tz: "America/Los_Angeles"
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
code: "LAX",
|
|
3615
|
+
country: "US",
|
|
3616
|
+
ghcnh_id: "USW00023174",
|
|
3617
|
+
icao: "KLAX",
|
|
3618
|
+
latitude: 33.9425,
|
|
3619
|
+
longitude: -118.4081,
|
|
3620
|
+
name: "Los Angeles International",
|
|
3621
|
+
tz: "America/Los_Angeles"
|
|
3622
|
+
},
|
|
3623
|
+
{
|
|
3624
|
+
code: "MDW",
|
|
3625
|
+
country: "US",
|
|
3626
|
+
ghcnh_id: "USW00014819",
|
|
3627
|
+
icao: "KMDW",
|
|
3628
|
+
latitude: 41.7868,
|
|
3629
|
+
longitude: -87.7522,
|
|
3630
|
+
name: "Chicago Midway International",
|
|
3631
|
+
tz: "America/Chicago"
|
|
3632
|
+
},
|
|
3633
|
+
{
|
|
3634
|
+
code: "MIA",
|
|
3635
|
+
country: "US",
|
|
3636
|
+
ghcnh_id: "USW00012839",
|
|
3637
|
+
icao: "KMIA",
|
|
3638
|
+
latitude: 25.7959,
|
|
3639
|
+
longitude: -80.287,
|
|
3640
|
+
name: "Miami International",
|
|
3641
|
+
tz: "America/New_York"
|
|
3642
|
+
},
|
|
3643
|
+
{
|
|
3644
|
+
code: "MSP",
|
|
3645
|
+
country: "US",
|
|
3646
|
+
ghcnh_id: "USW00014922",
|
|
3647
|
+
icao: "KMSP",
|
|
3648
|
+
latitude: 44.8848,
|
|
3649
|
+
longitude: -93.2223,
|
|
3650
|
+
name: "Minneapolis-St Paul International",
|
|
3651
|
+
tz: "America/Chicago"
|
|
3652
|
+
},
|
|
3653
|
+
{
|
|
3654
|
+
code: "MSY",
|
|
3655
|
+
country: "US",
|
|
3656
|
+
ghcnh_id: "USW00012916",
|
|
3657
|
+
icao: "KMSY",
|
|
3658
|
+
latitude: 29.9934,
|
|
3659
|
+
longitude: -90.258,
|
|
3660
|
+
name: "New Orleans Louis Armstrong International",
|
|
3661
|
+
tz: "America/Chicago"
|
|
3662
|
+
},
|
|
3663
|
+
{
|
|
3664
|
+
code: "NYC",
|
|
3665
|
+
country: "US",
|
|
3666
|
+
ghcnh_id: "USW00094728",
|
|
3667
|
+
icao: "KNYC",
|
|
3668
|
+
latitude: 40.7789,
|
|
3669
|
+
longitude: -73.9692,
|
|
3670
|
+
name: "Central Park, New York",
|
|
3671
|
+
tz: "America/New_York"
|
|
3672
|
+
},
|
|
3673
|
+
{
|
|
3674
|
+
code: "OKC",
|
|
3675
|
+
country: "US",
|
|
3676
|
+
ghcnh_id: "USW00013967",
|
|
3677
|
+
icao: "KOKC",
|
|
3678
|
+
latitude: 35.3931,
|
|
3679
|
+
longitude: -97.6007,
|
|
3680
|
+
name: "Oklahoma City Will Rogers World",
|
|
3681
|
+
tz: "America/Chicago"
|
|
3682
|
+
},
|
|
3683
|
+
{
|
|
3684
|
+
code: "PHL",
|
|
3685
|
+
country: "US",
|
|
3686
|
+
ghcnh_id: "USW00013739",
|
|
3687
|
+
icao: "KPHL",
|
|
3688
|
+
latitude: 39.8721,
|
|
3689
|
+
longitude: -75.2411,
|
|
3690
|
+
name: "Philadelphia International",
|
|
3691
|
+
tz: "America/New_York"
|
|
3692
|
+
},
|
|
3693
|
+
{
|
|
3694
|
+
code: "PHX",
|
|
3695
|
+
country: "US",
|
|
3696
|
+
ghcnh_id: "USW00023183",
|
|
3697
|
+
icao: "KPHX",
|
|
3698
|
+
latitude: 33.4373,
|
|
3699
|
+
longitude: -112.0078,
|
|
3700
|
+
name: "Phoenix Sky Harbor International",
|
|
3701
|
+
tz: "America/Phoenix"
|
|
3702
|
+
},
|
|
3703
|
+
{
|
|
3704
|
+
code: "SAT",
|
|
3705
|
+
country: "US",
|
|
3706
|
+
ghcnh_id: "USW00012921",
|
|
3707
|
+
icao: "KSAT",
|
|
3708
|
+
latitude: 29.5337,
|
|
3709
|
+
longitude: -98.4698,
|
|
3710
|
+
name: "San Antonio International",
|
|
3711
|
+
tz: "America/Chicago"
|
|
3712
|
+
},
|
|
3713
|
+
{
|
|
3714
|
+
code: "SEA",
|
|
3715
|
+
country: "US",
|
|
3716
|
+
ghcnh_id: "USW00024233",
|
|
3717
|
+
icao: "KSEA",
|
|
3718
|
+
latitude: 47.4502,
|
|
3719
|
+
longitude: -122.3088,
|
|
3720
|
+
name: "Seattle-Tacoma International",
|
|
3721
|
+
tz: "America/Los_Angeles"
|
|
3722
|
+
},
|
|
3723
|
+
{
|
|
3724
|
+
code: "SFO",
|
|
3725
|
+
country: "US",
|
|
3726
|
+
ghcnh_id: "USW00023234",
|
|
3727
|
+
icao: "KSFO",
|
|
3728
|
+
latitude: 37.6213,
|
|
3729
|
+
longitude: -122.379,
|
|
3730
|
+
name: "San Francisco International",
|
|
3731
|
+
tz: "America/Los_Angeles"
|
|
3732
|
+
},
|
|
3733
|
+
{
|
|
3734
|
+
code: "LEBL",
|
|
3735
|
+
country: "ES",
|
|
3736
|
+
ghcnh_id: null,
|
|
3737
|
+
icao: "LEBL",
|
|
3738
|
+
latitude: 41.2974,
|
|
3739
|
+
longitude: 2.0833,
|
|
3740
|
+
name: "Barcelona El Prat",
|
|
3741
|
+
tz: "Europe/Madrid"
|
|
3742
|
+
},
|
|
3743
|
+
{
|
|
3744
|
+
code: "LEMD",
|
|
3745
|
+
country: "ES",
|
|
3746
|
+
ghcnh_id: null,
|
|
3747
|
+
icao: "LEMD",
|
|
3748
|
+
latitude: 40.4719,
|
|
3749
|
+
longitude: -3.5626,
|
|
3750
|
+
name: "Madrid Barajas",
|
|
3751
|
+
tz: "Europe/Madrid"
|
|
3752
|
+
},
|
|
3753
|
+
{
|
|
3754
|
+
code: "LFPB",
|
|
3755
|
+
country: "FR",
|
|
3756
|
+
ghcnh_id: null,
|
|
3757
|
+
icao: "LFPB",
|
|
3758
|
+
latitude: 48.9694,
|
|
3759
|
+
longitude: 2.4414,
|
|
3760
|
+
name: "Paris Le Bourget",
|
|
3761
|
+
tz: "Europe/Paris"
|
|
3762
|
+
},
|
|
3763
|
+
{
|
|
3764
|
+
code: "LFPG",
|
|
3765
|
+
country: "FR",
|
|
3766
|
+
ghcnh_id: null,
|
|
3767
|
+
icao: "LFPG",
|
|
3768
|
+
latitude: 49.0097,
|
|
3769
|
+
longitude: 2.5479,
|
|
3770
|
+
name: "Paris Charles de Gaulle",
|
|
3771
|
+
tz: "Europe/Paris"
|
|
3772
|
+
},
|
|
3773
|
+
{
|
|
3774
|
+
code: "LFPO",
|
|
3775
|
+
country: "FR",
|
|
3776
|
+
ghcnh_id: null,
|
|
3777
|
+
icao: "LFPO",
|
|
3778
|
+
latitude: 48.7233,
|
|
3779
|
+
longitude: 2.3794,
|
|
3780
|
+
name: "Paris Orly",
|
|
3781
|
+
tz: "Europe/Paris"
|
|
3782
|
+
},
|
|
3783
|
+
{
|
|
3784
|
+
code: "LIMC",
|
|
3785
|
+
country: "IT",
|
|
3786
|
+
ghcnh_id: null,
|
|
3787
|
+
icao: "LIMC",
|
|
3788
|
+
latitude: 45.6306,
|
|
3789
|
+
longitude: 8.7281,
|
|
3790
|
+
name: "Milan Malpensa",
|
|
3791
|
+
tz: "Europe/Rome"
|
|
3792
|
+
},
|
|
3793
|
+
{
|
|
3794
|
+
code: "LIRF",
|
|
3795
|
+
country: "IT",
|
|
3796
|
+
ghcnh_id: null,
|
|
3797
|
+
icao: "LIRF",
|
|
3798
|
+
latitude: 41.8003,
|
|
3799
|
+
longitude: 12.2389,
|
|
3800
|
+
name: "Rome Fiumicino",
|
|
3801
|
+
tz: "Europe/Rome"
|
|
3802
|
+
},
|
|
3803
|
+
{
|
|
3804
|
+
code: "LOWW",
|
|
3805
|
+
country: "AT",
|
|
3806
|
+
ghcnh_id: null,
|
|
3807
|
+
icao: "LOWW",
|
|
3808
|
+
latitude: 48.1103,
|
|
3809
|
+
longitude: 16.5697,
|
|
3810
|
+
name: "Vienna International",
|
|
3811
|
+
tz: "Europe/Vienna"
|
|
3812
|
+
},
|
|
3813
|
+
{
|
|
3814
|
+
code: "LSZH",
|
|
3815
|
+
country: "CH",
|
|
3816
|
+
ghcnh_id: null,
|
|
3817
|
+
icao: "LSZH",
|
|
3818
|
+
latitude: 47.4647,
|
|
3819
|
+
longitude: 8.5492,
|
|
3820
|
+
name: "Zurich",
|
|
3821
|
+
tz: "Europe/Zurich"
|
|
3822
|
+
},
|
|
3823
|
+
{
|
|
3824
|
+
code: "NZAA",
|
|
3825
|
+
country: "NZ",
|
|
3826
|
+
ghcnh_id: null,
|
|
3827
|
+
icao: "NZAA",
|
|
3828
|
+
latitude: -37.0081,
|
|
3829
|
+
longitude: 174.7917,
|
|
3830
|
+
name: "Auckland",
|
|
3831
|
+
tz: "Pacific/Auckland"
|
|
3832
|
+
},
|
|
3833
|
+
{
|
|
3834
|
+
code: "NZWN",
|
|
3835
|
+
country: "NZ",
|
|
3836
|
+
ghcnh_id: null,
|
|
3837
|
+
icao: "NZWN",
|
|
3838
|
+
latitude: -41.3272,
|
|
3839
|
+
longitude: 174.8053,
|
|
3840
|
+
name: "Wellington",
|
|
3841
|
+
tz: "Pacific/Auckland"
|
|
3842
|
+
},
|
|
3843
|
+
{
|
|
3844
|
+
code: "OERK",
|
|
3845
|
+
country: "SA",
|
|
3846
|
+
ghcnh_id: null,
|
|
3847
|
+
icao: "OERK",
|
|
3848
|
+
latitude: 24.9576,
|
|
3849
|
+
longitude: 46.6988,
|
|
3850
|
+
name: "Riyadh King Khalid International",
|
|
3851
|
+
tz: "Asia/Riyadh"
|
|
3852
|
+
},
|
|
3853
|
+
{
|
|
3854
|
+
code: "OMDB",
|
|
3855
|
+
country: "AE",
|
|
3856
|
+
ghcnh_id: null,
|
|
3857
|
+
icao: "OMDB",
|
|
3858
|
+
latitude: 25.2532,
|
|
3859
|
+
longitude: 55.3657,
|
|
3860
|
+
name: "Dubai International",
|
|
3861
|
+
tz: "Asia/Dubai"
|
|
3862
|
+
},
|
|
3863
|
+
{
|
|
3864
|
+
code: "OTHH",
|
|
3865
|
+
country: "QA",
|
|
3866
|
+
ghcnh_id: null,
|
|
3867
|
+
icao: "OTHH",
|
|
3868
|
+
latitude: 25.2731,
|
|
3869
|
+
longitude: 51.608,
|
|
3870
|
+
name: "Doha Hamad International",
|
|
3871
|
+
tz: "Asia/Qatar"
|
|
3872
|
+
},
|
|
3873
|
+
{
|
|
3874
|
+
code: "RCTP",
|
|
3875
|
+
country: "TW",
|
|
3876
|
+
ghcnh_id: null,
|
|
3877
|
+
icao: "RCTP",
|
|
3878
|
+
latitude: 25.0777,
|
|
3879
|
+
longitude: 121.2328,
|
|
3880
|
+
name: "Taipei Taoyuan",
|
|
3881
|
+
tz: "Asia/Taipei"
|
|
3882
|
+
},
|
|
3883
|
+
{
|
|
3884
|
+
code: "RJAA",
|
|
3885
|
+
country: "JP",
|
|
3886
|
+
ghcnh_id: null,
|
|
3887
|
+
icao: "RJAA",
|
|
3888
|
+
latitude: 35.7647,
|
|
3889
|
+
longitude: 140.3864,
|
|
3890
|
+
name: "Tokyo Narita",
|
|
3891
|
+
tz: "Asia/Tokyo"
|
|
3892
|
+
},
|
|
3893
|
+
{
|
|
3894
|
+
code: "RJTT",
|
|
3895
|
+
country: "JP",
|
|
3896
|
+
ghcnh_id: null,
|
|
3897
|
+
icao: "RJTT",
|
|
3898
|
+
latitude: 35.5522,
|
|
3899
|
+
longitude: 139.78,
|
|
3900
|
+
name: "Tokyo Haneda",
|
|
3901
|
+
tz: "Asia/Tokyo"
|
|
3902
|
+
},
|
|
3903
|
+
{
|
|
3904
|
+
code: "RKSI",
|
|
3905
|
+
country: "KR",
|
|
3906
|
+
ghcnh_id: null,
|
|
3907
|
+
icao: "RKSI",
|
|
3908
|
+
latitude: 37.4691,
|
|
3909
|
+
longitude: 126.4505,
|
|
3910
|
+
name: "Seoul Incheon",
|
|
3911
|
+
tz: "Asia/Seoul"
|
|
3912
|
+
},
|
|
3913
|
+
{
|
|
3914
|
+
code: "SAEZ",
|
|
3915
|
+
country: "AR",
|
|
3916
|
+
ghcnh_id: null,
|
|
3917
|
+
icao: "SAEZ",
|
|
3918
|
+
latitude: -34.8222,
|
|
3919
|
+
longitude: -58.5358,
|
|
3920
|
+
name: "Buenos Aires Ezeiza",
|
|
3921
|
+
tz: "America/Argentina/Buenos_Aires"
|
|
3922
|
+
},
|
|
3923
|
+
{
|
|
3924
|
+
code: "SBGR",
|
|
3925
|
+
country: "BR",
|
|
3926
|
+
ghcnh_id: null,
|
|
3927
|
+
icao: "SBGR",
|
|
3928
|
+
latitude: -23.4356,
|
|
3929
|
+
longitude: -46.4731,
|
|
3930
|
+
name: "S\xE3o Paulo Guarulhos",
|
|
3931
|
+
tz: "America/Sao_Paulo"
|
|
3932
|
+
},
|
|
3933
|
+
{
|
|
3934
|
+
code: "UUEE",
|
|
3935
|
+
country: "RU",
|
|
3936
|
+
ghcnh_id: null,
|
|
3937
|
+
icao: "UUEE",
|
|
3938
|
+
latitude: 55.9728,
|
|
3939
|
+
longitude: 37.4147,
|
|
3940
|
+
name: "Moscow Sheremetyevo",
|
|
3941
|
+
tz: "Europe/Moscow"
|
|
3942
|
+
},
|
|
3943
|
+
{
|
|
3944
|
+
code: "VABB",
|
|
3945
|
+
country: "IN",
|
|
3946
|
+
ghcnh_id: null,
|
|
3947
|
+
icao: "VABB",
|
|
3948
|
+
latitude: 19.0887,
|
|
3949
|
+
longitude: 72.8679,
|
|
3950
|
+
name: "Mumbai Chhatrapati Shivaji",
|
|
3951
|
+
tz: "Asia/Kolkata"
|
|
3952
|
+
},
|
|
3953
|
+
{
|
|
3954
|
+
code: "VHHH",
|
|
3955
|
+
country: "HK",
|
|
3956
|
+
ghcnh_id: null,
|
|
3957
|
+
icao: "VHHH",
|
|
3958
|
+
latitude: 22.308,
|
|
3959
|
+
longitude: 113.9185,
|
|
3960
|
+
name: "Hong Kong International",
|
|
3961
|
+
tz: "Asia/Hong_Kong"
|
|
3962
|
+
},
|
|
3963
|
+
{
|
|
3964
|
+
code: "VIDP",
|
|
3965
|
+
country: "IN",
|
|
3966
|
+
ghcnh_id: null,
|
|
3967
|
+
icao: "VIDP",
|
|
3968
|
+
latitude: 28.5562,
|
|
3969
|
+
longitude: 77.1,
|
|
3970
|
+
name: "Delhi Indira Gandhi",
|
|
3971
|
+
tz: "Asia/Kolkata"
|
|
3972
|
+
},
|
|
3973
|
+
{
|
|
3974
|
+
code: "VTBS",
|
|
3975
|
+
country: "TH",
|
|
3976
|
+
ghcnh_id: null,
|
|
3977
|
+
icao: "VTBS",
|
|
3978
|
+
latitude: 13.69,
|
|
3979
|
+
longitude: 100.7501,
|
|
3980
|
+
name: "Bangkok Suvarnabhumi",
|
|
3981
|
+
tz: "Asia/Bangkok"
|
|
3982
|
+
},
|
|
3983
|
+
{
|
|
3984
|
+
code: "WSSS",
|
|
3985
|
+
country: "SG",
|
|
3986
|
+
ghcnh_id: null,
|
|
3987
|
+
icao: "WSSS",
|
|
3988
|
+
latitude: 1.3644,
|
|
3989
|
+
longitude: 103.9915,
|
|
3990
|
+
name: "Singapore Changi",
|
|
3991
|
+
tz: "Asia/Singapore"
|
|
3992
|
+
},
|
|
3993
|
+
{
|
|
3994
|
+
code: "YBBN",
|
|
3995
|
+
country: "AU",
|
|
3996
|
+
ghcnh_id: null,
|
|
3997
|
+
icao: "YBBN",
|
|
3998
|
+
latitude: -27.3842,
|
|
3999
|
+
longitude: 153.1175,
|
|
4000
|
+
name: "Brisbane",
|
|
4001
|
+
tz: "Australia/Brisbane"
|
|
4002
|
+
},
|
|
4003
|
+
{
|
|
4004
|
+
code: "YMML",
|
|
4005
|
+
country: "AU",
|
|
4006
|
+
ghcnh_id: null,
|
|
4007
|
+
icao: "YMML",
|
|
4008
|
+
latitude: -37.6733,
|
|
4009
|
+
longitude: 144.8433,
|
|
4010
|
+
name: "Melbourne Tullamarine",
|
|
4011
|
+
tz: "Australia/Melbourne"
|
|
4012
|
+
},
|
|
4013
|
+
{
|
|
4014
|
+
code: "YSSY",
|
|
4015
|
+
country: "AU",
|
|
4016
|
+
ghcnh_id: null,
|
|
4017
|
+
icao: "YSSY",
|
|
4018
|
+
latitude: -33.9461,
|
|
4019
|
+
longitude: 151.1772,
|
|
4020
|
+
name: "Sydney Kingsford Smith",
|
|
4021
|
+
tz: "Australia/Sydney"
|
|
4022
|
+
},
|
|
4023
|
+
{
|
|
4024
|
+
code: "ZBAA",
|
|
4025
|
+
country: "CN",
|
|
4026
|
+
ghcnh_id: null,
|
|
4027
|
+
icao: "ZBAA",
|
|
4028
|
+
latitude: 40.0801,
|
|
4029
|
+
longitude: 116.5846,
|
|
4030
|
+
name: "Beijing Capital",
|
|
4031
|
+
tz: "Asia/Shanghai"
|
|
4032
|
+
},
|
|
4033
|
+
{
|
|
4034
|
+
code: "ZSPD",
|
|
4035
|
+
country: "CN",
|
|
4036
|
+
ghcnh_id: null,
|
|
4037
|
+
icao: "ZSPD",
|
|
4038
|
+
latitude: 31.1443,
|
|
4039
|
+
longitude: 121.8083,
|
|
4040
|
+
name: "Shanghai Pudong",
|
|
4041
|
+
tz: "Asia/Shanghai"
|
|
4042
|
+
}
|
|
4043
|
+
];
|
|
4044
|
+
var STATION_BY_CODE2 = /* @__PURE__ */ new Map([
|
|
4045
|
+
["ATL", STATIONS2[10]],
|
|
4046
|
+
["AUS", STATIONS2[11]],
|
|
4047
|
+
["BOS", STATIONS2[12]],
|
|
4048
|
+
["DCA", STATIONS2[13]],
|
|
4049
|
+
["DEN", STATIONS2[14]],
|
|
4050
|
+
["DFW", STATIONS2[15]],
|
|
4051
|
+
["EDDB", STATIONS2[0]],
|
|
4052
|
+
["EDDF", STATIONS2[1]],
|
|
4053
|
+
["EDDM", STATIONS2[2]],
|
|
4054
|
+
["EFHK", STATIONS2[3]],
|
|
4055
|
+
["EGKK", STATIONS2[4]],
|
|
4056
|
+
["EGLL", STATIONS2[5]],
|
|
4057
|
+
["EHAM", STATIONS2[6]],
|
|
4058
|
+
["EKCH", STATIONS2[7]],
|
|
4059
|
+
["EPWA", STATIONS2[8]],
|
|
4060
|
+
["ESSA", STATIONS2[9]],
|
|
4061
|
+
["HOU", STATIONS2[16]],
|
|
4062
|
+
["LAS", STATIONS2[17]],
|
|
4063
|
+
["LAX", STATIONS2[18]],
|
|
4064
|
+
["LEBL", STATIONS2[30]],
|
|
4065
|
+
["LEMD", STATIONS2[31]],
|
|
4066
|
+
["LFPB", STATIONS2[32]],
|
|
4067
|
+
["LFPG", STATIONS2[33]],
|
|
4068
|
+
["LFPO", STATIONS2[34]],
|
|
4069
|
+
["LIMC", STATIONS2[35]],
|
|
4070
|
+
["LIRF", STATIONS2[36]],
|
|
4071
|
+
["LOWW", STATIONS2[37]],
|
|
4072
|
+
["LSZH", STATIONS2[38]],
|
|
4073
|
+
["MDW", STATIONS2[19]],
|
|
4074
|
+
["MIA", STATIONS2[20]],
|
|
4075
|
+
["MSP", STATIONS2[21]],
|
|
4076
|
+
["MSY", STATIONS2[22]],
|
|
4077
|
+
["NYC", STATIONS2[23]],
|
|
4078
|
+
["NZAA", STATIONS2[39]],
|
|
4079
|
+
["NZWN", STATIONS2[40]],
|
|
4080
|
+
["OERK", STATIONS2[41]],
|
|
4081
|
+
["OKC", STATIONS2[24]],
|
|
4082
|
+
["OMDB", STATIONS2[42]],
|
|
4083
|
+
["OTHH", STATIONS2[43]],
|
|
4084
|
+
["PHL", STATIONS2[25]],
|
|
4085
|
+
["PHX", STATIONS2[26]],
|
|
4086
|
+
["RCTP", STATIONS2[44]],
|
|
4087
|
+
["RJAA", STATIONS2[45]],
|
|
4088
|
+
["RJTT", STATIONS2[46]],
|
|
4089
|
+
["RKSI", STATIONS2[47]],
|
|
4090
|
+
["SAEZ", STATIONS2[48]],
|
|
4091
|
+
["SAT", STATIONS2[27]],
|
|
4092
|
+
["SBGR", STATIONS2[49]],
|
|
4093
|
+
["SEA", STATIONS2[28]],
|
|
4094
|
+
["SFO", STATIONS2[29]],
|
|
4095
|
+
["UUEE", STATIONS2[50]],
|
|
4096
|
+
["VABB", STATIONS2[51]],
|
|
4097
|
+
["VHHH", STATIONS2[52]],
|
|
4098
|
+
["VIDP", STATIONS2[53]],
|
|
4099
|
+
["VTBS", STATIONS2[54]],
|
|
4100
|
+
["WSSS", STATIONS2[55]],
|
|
4101
|
+
["YBBN", STATIONS2[56]],
|
|
4102
|
+
["YMML", STATIONS2[57]],
|
|
4103
|
+
["YSSY", STATIONS2[58]],
|
|
4104
|
+
["ZBAA", STATIONS2[59]],
|
|
4105
|
+
["ZSPD", STATIONS2[60]]
|
|
4106
|
+
]);
|
|
4107
|
+
var STATION_BY_ICAO2 = /* @__PURE__ */ new Map([
|
|
4108
|
+
["EDDB", STATIONS2[0]],
|
|
4109
|
+
["EDDF", STATIONS2[1]],
|
|
4110
|
+
["EDDM", STATIONS2[2]],
|
|
4111
|
+
["EFHK", STATIONS2[3]],
|
|
4112
|
+
["EGKK", STATIONS2[4]],
|
|
4113
|
+
["EGLL", STATIONS2[5]],
|
|
4114
|
+
["EHAM", STATIONS2[6]],
|
|
4115
|
+
["EKCH", STATIONS2[7]],
|
|
4116
|
+
["EPWA", STATIONS2[8]],
|
|
4117
|
+
["ESSA", STATIONS2[9]],
|
|
4118
|
+
["KATL", STATIONS2[10]],
|
|
4119
|
+
["KAUS", STATIONS2[11]],
|
|
4120
|
+
["KBOS", STATIONS2[12]],
|
|
4121
|
+
["KDCA", STATIONS2[13]],
|
|
4122
|
+
["KDEN", STATIONS2[14]],
|
|
4123
|
+
["KDFW", STATIONS2[15]],
|
|
4124
|
+
["KHOU", STATIONS2[16]],
|
|
4125
|
+
["KLAS", STATIONS2[17]],
|
|
4126
|
+
["KLAX", STATIONS2[18]],
|
|
4127
|
+
["KMDW", STATIONS2[19]],
|
|
4128
|
+
["KMIA", STATIONS2[20]],
|
|
4129
|
+
["KMSP", STATIONS2[21]],
|
|
4130
|
+
["KMSY", STATIONS2[22]],
|
|
4131
|
+
["KNYC", STATIONS2[23]],
|
|
4132
|
+
["KOKC", STATIONS2[24]],
|
|
4133
|
+
["KPHL", STATIONS2[25]],
|
|
4134
|
+
["KPHX", STATIONS2[26]],
|
|
4135
|
+
["KSAT", STATIONS2[27]],
|
|
4136
|
+
["KSEA", STATIONS2[28]],
|
|
4137
|
+
["KSFO", STATIONS2[29]],
|
|
4138
|
+
["LEBL", STATIONS2[30]],
|
|
4139
|
+
["LEMD", STATIONS2[31]],
|
|
4140
|
+
["LFPB", STATIONS2[32]],
|
|
4141
|
+
["LFPG", STATIONS2[33]],
|
|
4142
|
+
["LFPO", STATIONS2[34]],
|
|
4143
|
+
["LIMC", STATIONS2[35]],
|
|
4144
|
+
["LIRF", STATIONS2[36]],
|
|
4145
|
+
["LOWW", STATIONS2[37]],
|
|
4146
|
+
["LSZH", STATIONS2[38]],
|
|
4147
|
+
["NZAA", STATIONS2[39]],
|
|
4148
|
+
["NZWN", STATIONS2[40]],
|
|
4149
|
+
["OERK", STATIONS2[41]],
|
|
4150
|
+
["OMDB", STATIONS2[42]],
|
|
4151
|
+
["OTHH", STATIONS2[43]],
|
|
4152
|
+
["RCTP", STATIONS2[44]],
|
|
4153
|
+
["RJAA", STATIONS2[45]],
|
|
4154
|
+
["RJTT", STATIONS2[46]],
|
|
4155
|
+
["RKSI", STATIONS2[47]],
|
|
4156
|
+
["SAEZ", STATIONS2[48]],
|
|
4157
|
+
["SBGR", STATIONS2[49]],
|
|
4158
|
+
["UUEE", STATIONS2[50]],
|
|
4159
|
+
["VABB", STATIONS2[51]],
|
|
4160
|
+
["VHHH", STATIONS2[52]],
|
|
4161
|
+
["VIDP", STATIONS2[53]],
|
|
4162
|
+
["VTBS", STATIONS2[54]],
|
|
4163
|
+
["WSSS", STATIONS2[55]],
|
|
4164
|
+
["YBBN", STATIONS2[56]],
|
|
4165
|
+
["YMML", STATIONS2[57]],
|
|
4166
|
+
["YSSY", STATIONS2[58]],
|
|
4167
|
+
["ZBAA", STATIONS2[59]],
|
|
4168
|
+
["ZSPD", STATIONS2[60]]
|
|
4169
|
+
]);
|
|
4170
|
+
var LOW_COVERAGE_THRESHOLD = 12;
|
|
4171
|
+
var PARTS_CACHE = /* @__PURE__ */ new Map();
|
|
4172
|
+
function getDateFormatter(tz) {
|
|
4173
|
+
let f = PARTS_CACHE.get(tz);
|
|
4174
|
+
if (f === void 0) {
|
|
4175
|
+
f = new Intl.DateTimeFormat("en-US", {
|
|
4176
|
+
timeZone: tz,
|
|
4177
|
+
year: "numeric",
|
|
4178
|
+
month: "2-digit",
|
|
4179
|
+
day: "2-digit"
|
|
4180
|
+
});
|
|
4181
|
+
PARTS_CACHE.set(tz, f);
|
|
4182
|
+
}
|
|
4183
|
+
return f;
|
|
4184
|
+
}
|
|
4185
|
+
function localDateFor(instant, tz) {
|
|
4186
|
+
const parts = getDateFormatter(tz).formatToParts(instant);
|
|
4187
|
+
let y = "";
|
|
4188
|
+
let m = "";
|
|
4189
|
+
let d = "";
|
|
4190
|
+
for (const p of parts) {
|
|
4191
|
+
if (p.type === "year") y = p.value;
|
|
4192
|
+
else if (p.type === "month") m = p.value;
|
|
4193
|
+
else if (p.type === "day") d = p.value;
|
|
4194
|
+
}
|
|
4195
|
+
return `${y}-${m}-${d}`;
|
|
4196
|
+
}
|
|
4197
|
+
function parseInstant(observed) {
|
|
4198
|
+
if (observed === void 0 || observed === null || observed.length === 0) {
|
|
4199
|
+
return null;
|
|
4200
|
+
}
|
|
4201
|
+
const ms = Date.parse(observed);
|
|
4202
|
+
if (Number.isNaN(ms)) return null;
|
|
4203
|
+
return new Date(ms);
|
|
4204
|
+
}
|
|
4205
|
+
function roundHalfUp(value, places) {
|
|
4206
|
+
if (!Number.isFinite(value)) return value;
|
|
4207
|
+
const scale = 10 ** places;
|
|
4208
|
+
const sign = value < 0 ? -1 : 1;
|
|
4209
|
+
const abs = Math.abs(value);
|
|
4210
|
+
const rounded = Math.floor(abs * scale + 0.5 + abs * 1e-12) / scale;
|
|
4211
|
+
return sign * rounded;
|
|
4212
|
+
}
|
|
4213
|
+
function cToF(c) {
|
|
4214
|
+
return c * 1.8 + 32;
|
|
4215
|
+
}
|
|
4216
|
+
function internationalDailyExtremes(rows, opts) {
|
|
4217
|
+
const tz = opts.stationTz;
|
|
4218
|
+
if (typeof tz !== "string" || tz.length === 0) {
|
|
4219
|
+
throw new RangeError("internationalDailyExtremes: stationTz is required (non-empty string)");
|
|
4220
|
+
}
|
|
4221
|
+
const precision = opts.precision ?? 0;
|
|
4222
|
+
const minObs = opts.minObs ?? LOW_COVERAGE_THRESHOLD;
|
|
4223
|
+
try {
|
|
4224
|
+
getDateFormatter(tz);
|
|
4225
|
+
} catch (e) {
|
|
4226
|
+
throw new RangeError(
|
|
4227
|
+
`internationalDailyExtremes: invalid stationTz ${JSON.stringify(tz)}: ${e.message}`
|
|
4228
|
+
);
|
|
4229
|
+
}
|
|
4230
|
+
const byLocalDate = /* @__PURE__ */ new Map();
|
|
4231
|
+
for (const row of rows) {
|
|
4232
|
+
const instant = parseInstant(row.observed_at);
|
|
4233
|
+
if (instant === null) continue;
|
|
4234
|
+
const localDate = localDateFor(instant, tz);
|
|
4235
|
+
let bucket = byLocalDate.get(localDate);
|
|
4236
|
+
if (bucket === void 0) {
|
|
4237
|
+
bucket = { temps: [], precipMm: 0 };
|
|
4238
|
+
byLocalDate.set(localDate, bucket);
|
|
4239
|
+
}
|
|
4240
|
+
const t = row.temp_c;
|
|
4241
|
+
if (typeof t === "number" && Number.isFinite(t)) {
|
|
4242
|
+
bucket.temps.push({ value: t, source: row.source ?? null });
|
|
4243
|
+
}
|
|
4244
|
+
const p = row.precip_mm_1h;
|
|
4245
|
+
if (typeof p === "number" && Number.isFinite(p)) {
|
|
4246
|
+
bucket.precipMm += p;
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
const out = [];
|
|
4250
|
+
const sortedDates = [...byLocalDate.keys()].sort();
|
|
4251
|
+
for (const localDate of sortedDates) {
|
|
4252
|
+
const bucket = byLocalDate.get(localDate);
|
|
4253
|
+
if (bucket === void 0) continue;
|
|
4254
|
+
const nObs = bucket.temps.length;
|
|
4255
|
+
let tempMinC = null;
|
|
4256
|
+
let tempMaxC = null;
|
|
4257
|
+
let tempMeanC = null;
|
|
4258
|
+
let sourceTmin = null;
|
|
4259
|
+
let sourceTmax = null;
|
|
4260
|
+
if (nObs > 0 && nObs >= minObs) {
|
|
4261
|
+
let minIdx = 0;
|
|
4262
|
+
let maxIdx = 0;
|
|
4263
|
+
let sum = 0;
|
|
4264
|
+
for (let i = 0; i < bucket.temps.length; i += 1) {
|
|
4265
|
+
const v = bucket.temps[i];
|
|
4266
|
+
sum += v.value;
|
|
4267
|
+
const minRow2 = bucket.temps[minIdx];
|
|
4268
|
+
const maxRow2 = bucket.temps[maxIdx];
|
|
4269
|
+
if (v.value < minRow2.value) minIdx = i;
|
|
4270
|
+
if (v.value > maxRow2.value) maxIdx = i;
|
|
4271
|
+
}
|
|
4272
|
+
const mean = sum / nObs;
|
|
4273
|
+
const minRow = bucket.temps[minIdx];
|
|
4274
|
+
const maxRow = bucket.temps[maxIdx];
|
|
4275
|
+
tempMinC = roundHalfUp(minRow.value, precision);
|
|
4276
|
+
tempMaxC = roundHalfUp(maxRow.value, precision);
|
|
4277
|
+
tempMeanC = roundHalfUp(mean, precision);
|
|
4278
|
+
sourceTmin = minRow.source;
|
|
4279
|
+
sourceTmax = maxRow.source;
|
|
4280
|
+
}
|
|
4281
|
+
out.push(
|
|
4282
|
+
Object.freeze({
|
|
4283
|
+
localDate,
|
|
4284
|
+
nObs,
|
|
4285
|
+
tempMinC,
|
|
4286
|
+
tempMaxC,
|
|
4287
|
+
tempMeanC,
|
|
4288
|
+
tempMinF: tempMinC === null ? null : roundHalfUp(cToF(tempMinC), precision),
|
|
4289
|
+
tempMaxF: tempMaxC === null ? null : roundHalfUp(cToF(tempMaxC), precision),
|
|
4290
|
+
precipMm: roundHalfUp(bucket.precipMm, 4),
|
|
4291
|
+
sourceTmin,
|
|
4292
|
+
sourceTmax
|
|
4293
|
+
})
|
|
4294
|
+
);
|
|
4295
|
+
}
|
|
4296
|
+
return out;
|
|
4297
|
+
}
|
|
4298
|
+
var BUILT_IN_SCHEMAS = Object.freeze([
|
|
4299
|
+
{
|
|
4300
|
+
id: "schema.observation.v1",
|
|
4301
|
+
title: "schema.observation.v1",
|
|
4302
|
+
columnCount: 20,
|
|
4303
|
+
columns: [
|
|
4304
|
+
{ name: "dew_point_c", description: "units: celsius \u2014 bounded", nullable: true },
|
|
4305
|
+
{ name: "event_time", description: "observation valid time", nullable: false },
|
|
4306
|
+
{
|
|
4307
|
+
name: "metar_raw",
|
|
4308
|
+
description: "raw METAR text if source has it; null for AWC JSON (structured-only)",
|
|
4309
|
+
nullable: true
|
|
4310
|
+
},
|
|
4311
|
+
{
|
|
4312
|
+
name: "observation_type",
|
|
4313
|
+
description: "METAR | SPECI; defaults METAR when source can't distinguish (e.g. AWC JSON)",
|
|
4314
|
+
nullable: false
|
|
4315
|
+
},
|
|
4316
|
+
{
|
|
4317
|
+
name: "precip_mm_1h",
|
|
4318
|
+
description: "units: mm \u2014 hourly precip (METAR p01i, converted from inches)",
|
|
4319
|
+
nullable: true
|
|
4320
|
+
},
|
|
4321
|
+
{
|
|
4322
|
+
name: "sky_base_1_m",
|
|
4323
|
+
description: "units: meters \u2014 first cloud layer base height (converted from feet)",
|
|
4324
|
+
nullable: true
|
|
4325
|
+
},
|
|
4326
|
+
{ name: "sky_base_2_m", description: "units: meters", nullable: true },
|
|
4327
|
+
{ name: "sky_base_3_m", description: "units: meters", nullable: true },
|
|
4328
|
+
{ name: "sky_base_4_m", description: "units: meters", nullable: true },
|
|
4329
|
+
{ name: "sky_cover_1", description: "first cloud layer cover code", nullable: true },
|
|
4330
|
+
{ name: "sky_cover_2", description: "second layer; null if not present", nullable: true },
|
|
4331
|
+
{ name: "sky_cover_3", description: "third layer; null if not present", nullable: true },
|
|
4332
|
+
{ name: "sky_cover_4", description: "fourth layer; null if not present", nullable: true },
|
|
4333
|
+
{
|
|
4334
|
+
name: "slp_hpa",
|
|
4335
|
+
description: "units: hPa \u2014 sea-level pressure (canonical aviation unit, not converted across modes)",
|
|
4336
|
+
nullable: true
|
|
4337
|
+
},
|
|
4338
|
+
{ name: "station", description: "ICAO/ASOS station ID (e.g. KORD)", nullable: false },
|
|
4339
|
+
{
|
|
4340
|
+
name: "temp_c",
|
|
4341
|
+
description: "units: celsius \u2014 bounded TEMP_MIN_C..TEMP_MAX_C",
|
|
4342
|
+
nullable: true
|
|
4343
|
+
},
|
|
4344
|
+
{
|
|
4345
|
+
name: "visibility_m",
|
|
4346
|
+
description: "units: meters \u2014 converted from statute miles",
|
|
4347
|
+
nullable: true
|
|
4348
|
+
},
|
|
4349
|
+
{
|
|
4350
|
+
name: "wind_dir_deg",
|
|
4351
|
+
description: "units: degrees \u2014 0-360, bounded",
|
|
4352
|
+
nullable: true
|
|
4353
|
+
},
|
|
4354
|
+
{ name: "wind_gust_ms", description: "units: m/s \u2014 converted from kt", nullable: true },
|
|
4355
|
+
{ name: "wind_speed_ms", description: "units: m/s \u2014 converted from kt", nullable: true }
|
|
4356
|
+
]
|
|
4357
|
+
},
|
|
4358
|
+
{
|
|
4359
|
+
id: "schema.forecast.iem_mos.v1",
|
|
4360
|
+
title: "schema.forecast.iem_mos.v1",
|
|
4361
|
+
columnCount: 11,
|
|
4362
|
+
columns: [
|
|
4363
|
+
{ name: "dew_point_c", description: "units: celsius", nullable: true },
|
|
4364
|
+
{
|
|
4365
|
+
name: "forecast_hour",
|
|
4366
|
+
description: "units: hours \u2014 (valid_at - issued_at).total_seconds() / 3600",
|
|
4367
|
+
nullable: false
|
|
4368
|
+
},
|
|
4369
|
+
{
|
|
4370
|
+
name: "issued_at",
|
|
4371
|
+
description: "model run time (from source `runtime` field)",
|
|
4372
|
+
nullable: false
|
|
4373
|
+
},
|
|
4374
|
+
{ name: "model", description: "e.g. NBE, GFS, LAV, MET", nullable: false },
|
|
4375
|
+
{
|
|
4376
|
+
name: "precip_probability",
|
|
4377
|
+
description: "units: probability \u2014 bounded [0, 1]",
|
|
4378
|
+
nullable: true
|
|
4379
|
+
},
|
|
4380
|
+
{
|
|
4381
|
+
name: "sky_cover_pct",
|
|
4382
|
+
description: "units: percent \u2014 bounded [0, 100]",
|
|
4383
|
+
nullable: true
|
|
4384
|
+
},
|
|
4385
|
+
{ name: "station", description: "", nullable: false },
|
|
4386
|
+
{ name: "temp_c", description: "units: celsius", nullable: true },
|
|
4387
|
+
{
|
|
4388
|
+
name: "valid_at",
|
|
4389
|
+
description: "forecast target time (from source `ftime`)",
|
|
4390
|
+
nullable: false
|
|
4391
|
+
},
|
|
4392
|
+
{ name: "wind_dir_deg", description: "units: degrees", nullable: true },
|
|
4393
|
+
{ name: "wind_speed_ms", description: "units: m/s", nullable: true }
|
|
4394
|
+
]
|
|
4395
|
+
},
|
|
4396
|
+
{
|
|
4397
|
+
id: "schema.settlement.cli.v1",
|
|
4398
|
+
title: "schema.settlement.cli.v1",
|
|
4399
|
+
columnCount: 12,
|
|
4400
|
+
columns: [
|
|
4401
|
+
{
|
|
4402
|
+
name: "cli_data_quality",
|
|
4403
|
+
description: "NWS CLI data-quality marker (Pitfall 6/16). Allows downstream code to filter or weight settlement rows by issuer quality without re-parsing the product header.",
|
|
4404
|
+
nullable: false
|
|
4405
|
+
},
|
|
4406
|
+
{
|
|
4407
|
+
name: "event_time",
|
|
4408
|
+
description: "00:00 local time on observation_date converted to UTC; for sort/join only",
|
|
4409
|
+
nullable: false
|
|
4410
|
+
},
|
|
4411
|
+
{
|
|
4412
|
+
name: "observation_date",
|
|
4413
|
+
description: "local climate day per NWS convention (no timezone applied to the date itself)",
|
|
4414
|
+
nullable: false
|
|
4415
|
+
},
|
|
4416
|
+
{ name: "precipitation_in", description: "units: inches", nullable: true },
|
|
4417
|
+
{
|
|
4418
|
+
name: "product_release_time",
|
|
4419
|
+
description: "parsed from CLI product header (_climate.py::_parse_product_timestamp)",
|
|
4420
|
+
nullable: false
|
|
4421
|
+
},
|
|
4422
|
+
{
|
|
4423
|
+
name: "report_type",
|
|
4424
|
+
description: "preliminary | final | correction; dedup priority preliminary < final < correction",
|
|
4425
|
+
nullable: false
|
|
4426
|
+
},
|
|
4427
|
+
{
|
|
4428
|
+
name: "settlement_finality",
|
|
4429
|
+
description: "provisional | final | superseded. Kalshi NHIGH/NLOW settlement contractually requires 'final'; 'provisional' values are kept for early-look research only.",
|
|
4430
|
+
nullable: false
|
|
4431
|
+
},
|
|
4432
|
+
{ name: "snowfall_in", description: "units: inches", nullable: true },
|
|
4433
|
+
{ name: "station", description: "ICAO/ASOS station ID", nullable: false },
|
|
4434
|
+
{
|
|
4435
|
+
name: "station_tz",
|
|
4436
|
+
description: "IANA timezone for the station (e.g. America/Chicago for KORD). Required for local-climate-day semantics; see \xA7U.",
|
|
4437
|
+
nullable: false
|
|
4438
|
+
},
|
|
4439
|
+
{
|
|
4440
|
+
name: "temp_max_F",
|
|
4441
|
+
description: "units: fahrenheit \u2014 daily high (uppercase F for consistency with obs imperial mode)",
|
|
4442
|
+
nullable: true
|
|
4443
|
+
},
|
|
4444
|
+
{ name: "temp_min_F", description: "units: fahrenheit \u2014 daily low", nullable: true }
|
|
4445
|
+
]
|
|
4446
|
+
},
|
|
4447
|
+
{
|
|
4448
|
+
id: "schema.observation_ledger.v1",
|
|
4449
|
+
title: "schema.observation_ledger.v1",
|
|
4450
|
+
columnCount: 15,
|
|
4451
|
+
columns: [
|
|
4452
|
+
{ name: "as_of_time", description: "", nullable: true },
|
|
4453
|
+
{ name: "dewpoint_c", description: "units: celsius", nullable: true },
|
|
4454
|
+
{ name: "ingestion_id", description: "", nullable: true },
|
|
4455
|
+
{ name: "observation_kind", description: "", nullable: true },
|
|
4456
|
+
{
|
|
4457
|
+
name: "observation_quality",
|
|
4458
|
+
description: "Lineage row-quality flag per LINEAGE-01; distinct from qc_status enum slot AND distinct from the obs_qc_status bitmask column per QC-05.",
|
|
4459
|
+
nullable: true
|
|
4460
|
+
},
|
|
4461
|
+
{ name: "observation_type", description: "", nullable: false },
|
|
4462
|
+
{ name: "observed_at", description: "", nullable: false },
|
|
4463
|
+
{ name: "parser_name", description: "", nullable: true },
|
|
4464
|
+
{ name: "parser_version", description: "", nullable: true },
|
|
4465
|
+
{ name: "provenance", description: "", nullable: true },
|
|
4466
|
+
{ name: "qc_status", description: "", nullable: true },
|
|
4467
|
+
{
|
|
4468
|
+
name: "source",
|
|
4469
|
+
description: "ncei reserved per D-2.1-09; never written in v0.1.0.",
|
|
4470
|
+
nullable: false
|
|
4471
|
+
},
|
|
4472
|
+
{ name: "source_received_at", description: "", nullable: true },
|
|
4473
|
+
{ name: "station_code", description: "", nullable: false },
|
|
4474
|
+
{ name: "temp_c", description: "units: celsius", nullable: true }
|
|
4475
|
+
]
|
|
4476
|
+
},
|
|
4477
|
+
{
|
|
4478
|
+
id: "schema.observation_qc.v1",
|
|
4479
|
+
title: "schema.observation_qc.v1",
|
|
4480
|
+
columnCount: 13,
|
|
4481
|
+
columns: [
|
|
4482
|
+
{ name: "as_of_time", description: "", nullable: true },
|
|
4483
|
+
{
|
|
4484
|
+
name: "detector_metadata",
|
|
4485
|
+
description: "JSON-serialized detector payload; shape per qc_system.",
|
|
4486
|
+
nullable: true
|
|
4487
|
+
},
|
|
4488
|
+
{
|
|
4489
|
+
name: "field",
|
|
4490
|
+
description: "Observation column the rule evaluated (e.g. temp_c).",
|
|
4491
|
+
nullable: false
|
|
4492
|
+
},
|
|
4493
|
+
{ name: "flag", description: "", nullable: false },
|
|
4494
|
+
{ name: "ingestion_id", description: "", nullable: true },
|
|
4495
|
+
{ name: "observation_kind", description: "", nullable: true },
|
|
4496
|
+
{ name: "observed_at", description: "", nullable: false },
|
|
4497
|
+
{ name: "parser_name", description: "", nullable: true },
|
|
4498
|
+
{ name: "qc_system", description: "", nullable: false },
|
|
4499
|
+
{ name: "qc_version", description: "", nullable: false },
|
|
4500
|
+
{ name: "rule_id", description: "", nullable: false },
|
|
4501
|
+
{ name: "source", description: "", nullable: false },
|
|
4502
|
+
{ name: "station_code", description: "", nullable: false }
|
|
4503
|
+
]
|
|
4504
|
+
}
|
|
4505
|
+
]);
|
|
4506
|
+
function deepFreezeSchema(info) {
|
|
4507
|
+
const frozenCols = Object.freeze(info.columns.map((c) => Object.freeze({ ...c })));
|
|
4508
|
+
return Object.freeze({ ...info, columns: frozenCols });
|
|
4509
|
+
}
|
|
4510
|
+
var REGISTRY = new Map(
|
|
4511
|
+
BUILT_IN_SCHEMAS.map((info) => [info.id, deepFreezeSchema(info)])
|
|
4512
|
+
);
|
|
4513
|
+
var FEATURE_NAMES = Object.freeze([
|
|
4514
|
+
"calendarFeatures",
|
|
4515
|
+
"clipOutliers",
|
|
4516
|
+
"diff",
|
|
4517
|
+
"diff2",
|
|
4518
|
+
"heatIndex",
|
|
4519
|
+
"lag",
|
|
4520
|
+
"rolling",
|
|
4521
|
+
"spread",
|
|
4522
|
+
"windChill"
|
|
4523
|
+
]);
|
|
4524
|
+
|
|
4525
|
+
// ../weather/src/dailyExtremes.ts
|
|
4526
|
+
init_iem_asos();
|
|
4527
|
+
init_awc();
|
|
4528
|
+
init_iem();
|
|
4529
|
+
var LOW_COVERAGE_THRESHOLD2 = 12;
|
|
4530
|
+
function addUtcDays(iso, days) {
|
|
4531
|
+
const [yStr, mStr, dStr] = iso.split("-");
|
|
4532
|
+
const dt = new Date(Date.UTC(Number(yStr), Number(mStr) - 1, Number(dStr)));
|
|
4533
|
+
dt.setUTCDate(dt.getUTCDate() + days);
|
|
4534
|
+
const yyyy = dt.getUTCFullYear();
|
|
4535
|
+
const mm = String(dt.getUTCMonth() + 1).padStart(2, "0");
|
|
4536
|
+
const dd = String(dt.getUTCDate()).padStart(2, "0");
|
|
4537
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
4538
|
+
}
|
|
4539
|
+
function lookupStation(icao) {
|
|
4540
|
+
const upper = icao.toUpperCase();
|
|
4541
|
+
for (const s of STATIONS) {
|
|
4542
|
+
if (s.icao === upper) {
|
|
4543
|
+
return { tz: s.tz, isUs: s.country === "US" };
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
throw new Error(`dailyExtremes: station "${icao}" not in registry \u2014 check STATIONS catalog`);
|
|
4547
|
+
}
|
|
4548
|
+
function cToF2(c) {
|
|
4549
|
+
if (c === null) return null;
|
|
4550
|
+
return c * (9 / 5) + 32;
|
|
4551
|
+
}
|
|
4552
|
+
function roundHalfUp2(value, decimals) {
|
|
4553
|
+
const m = 10 ** decimals;
|
|
4554
|
+
return Math.round(value * m) / m;
|
|
4555
|
+
}
|
|
4556
|
+
async function fetchIemAsosObservations(station, fromDate, toDate) {
|
|
4557
|
+
const fromYear = Number.parseInt(fromDate.slice(0, 4), 10);
|
|
4558
|
+
const toYear = Number.parseInt(toDate.slice(0, 4), 10);
|
|
4559
|
+
const out = [];
|
|
4560
|
+
for (let year = fromYear; year <= toYear; year++) {
|
|
4561
|
+
const chunks = await downloadIemAsos(station, `${year}-01-01`, `${year}-12-31`, {
|
|
4562
|
+
reportType: 3,
|
|
4563
|
+
politenessMs: 1e3
|
|
4564
|
+
});
|
|
4565
|
+
for (const chunk of chunks) {
|
|
4566
|
+
const parsed = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|
|
4567
|
+
for (const row of parsed) {
|
|
4568
|
+
const obsDate = row.observed_at.slice(0, 10);
|
|
4569
|
+
if (obsDate >= fromDate && obsDate <= toDate) {
|
|
4570
|
+
const precipInches = row.precip_1hr_inches ?? null;
|
|
4571
|
+
out.push({
|
|
4572
|
+
observed_at: row.observed_at,
|
|
4573
|
+
temp_c: row.temp_c ?? null,
|
|
4574
|
+
precip_mm_1h: precipInches !== null ? precipInches * 25.4 : null,
|
|
4575
|
+
source: row.source
|
|
4576
|
+
});
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
return out;
|
|
4582
|
+
}
|
|
4583
|
+
async function fetchAwcObservations(station, fromDate, toDate) {
|
|
4584
|
+
const raw = await fetchAwcMetars([station]);
|
|
4585
|
+
const out = [];
|
|
4586
|
+
for (const r of raw) {
|
|
4587
|
+
const obs2 = awcToObservation(r);
|
|
4588
|
+
if (obs2 === null) continue;
|
|
4589
|
+
const obsDate = obs2.observed_at.slice(0, 10);
|
|
4590
|
+
if (obsDate >= fromDate && obsDate <= toDate) {
|
|
4591
|
+
const precipInches = obs2.precip_1hr_inches ?? null;
|
|
4592
|
+
out.push({
|
|
4593
|
+
observed_at: obs2.observed_at,
|
|
4594
|
+
temp_c: obs2.temp_c ?? null,
|
|
4595
|
+
precip_mm_1h: precipInches !== null ? precipInches * 25.4 : null,
|
|
4596
|
+
source: obs2.source
|
|
4597
|
+
});
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
return out;
|
|
4601
|
+
}
|
|
4602
|
+
async function fetchForMode(station, fromDate, toDate, mode) {
|
|
4603
|
+
switch (mode) {
|
|
4604
|
+
case "iem_only":
|
|
4605
|
+
return fetchIemAsosObservations(station, fromDate, toDate);
|
|
4606
|
+
case "awc_only":
|
|
4607
|
+
return fetchAwcObservations(station, fromDate, toDate);
|
|
4608
|
+
case "live_v1": {
|
|
4609
|
+
const [iem, awc] = await Promise.all([
|
|
4610
|
+
fetchIemAsosObservations(station, fromDate, toDate),
|
|
4611
|
+
fetchAwcObservations(station, fromDate, toDate).catch(() => [])
|
|
4612
|
+
]);
|
|
4613
|
+
return [...iem, ...awc];
|
|
4614
|
+
}
|
|
4615
|
+
default: {
|
|
4616
|
+
const _exhaustive = mode;
|
|
4617
|
+
throw new TypeError(`dailyExtremes: unknown merge mode "${String(_exhaustive)}"`);
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
function projectRow(station, d, isUs) {
|
|
4622
|
+
const lowCoverage = d.nObs < LOW_COVERAGE_THRESHOLD2;
|
|
4623
|
+
const decimals = isUs ? 0 : 1;
|
|
4624
|
+
const precipIn = d.precipMm !== null && d.precipMm !== void 0 ? roundHalfUp2(d.precipMm / 25.4, 2) : null;
|
|
4625
|
+
if (lowCoverage) {
|
|
4626
|
+
return {
|
|
4627
|
+
date: d.localDate,
|
|
4628
|
+
station,
|
|
4629
|
+
tmin_f: null,
|
|
4630
|
+
tmax_f: null,
|
|
4631
|
+
tmean_f: null,
|
|
4632
|
+
precip_in: precipIn,
|
|
4633
|
+
low_coverage: true,
|
|
4634
|
+
n_obs: d.nObs
|
|
4635
|
+
};
|
|
4636
|
+
}
|
|
4637
|
+
return {
|
|
4638
|
+
date: d.localDate,
|
|
4639
|
+
station,
|
|
4640
|
+
tmin_f: d.tempMinF !== null ? roundHalfUp2(d.tempMinF, decimals) : null,
|
|
4641
|
+
tmax_f: d.tempMaxF !== null ? roundHalfUp2(d.tempMaxF, decimals) : null,
|
|
4642
|
+
tmean_f: d.tempMeanC !== null ? roundHalfUp2(cToF2(d.tempMeanC), decimals) : null,
|
|
4643
|
+
precip_in: precipIn,
|
|
4644
|
+
low_coverage: false,
|
|
4645
|
+
n_obs: d.nObs
|
|
4646
|
+
};
|
|
4647
|
+
}
|
|
4648
|
+
async function dailyExtremes(station, fromDate, toDate, opts = {}) {
|
|
4649
|
+
const { tz, isUs } = lookupStation(station);
|
|
4650
|
+
const merge = opts.merge ?? "live_v1";
|
|
4651
|
+
const fetchFrom = addUtcDays(fromDate, -1);
|
|
4652
|
+
const fetchTo = addUtcDays(toDate, 1);
|
|
4653
|
+
const rows = await fetchForMode(station, fetchFrom, fetchTo, merge);
|
|
4654
|
+
const extremes = internationalDailyExtremes(rows, {
|
|
4655
|
+
stationTz: tz,
|
|
4656
|
+
precision: isUs ? 1 : 0
|
|
4657
|
+
});
|
|
4658
|
+
return extremes.filter((d) => d.localDate >= fromDate && d.localDate <= toDate).map((d) => projectRow(station.toUpperCase(), d, isUs));
|
|
3359
4659
|
}
|
|
3360
4660
|
|
|
3361
|
-
// ../weather/src/
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
4661
|
+
// ../weather/src/obs.ts
|
|
4662
|
+
init_src();
|
|
4663
|
+
init_iem_asos();
|
|
4664
|
+
init_awc();
|
|
4665
|
+
init_iem();
|
|
4666
|
+
function daysBetween(fromDate, toDate) {
|
|
4667
|
+
const from = Date.UTC(
|
|
4668
|
+
Number.parseInt(fromDate.slice(0, 4), 10),
|
|
4669
|
+
Number.parseInt(fromDate.slice(5, 7), 10) - 1,
|
|
4670
|
+
Number.parseInt(fromDate.slice(8, 10), 10)
|
|
3365
4671
|
);
|
|
4672
|
+
const to = Date.UTC(
|
|
4673
|
+
Number.parseInt(toDate.slice(0, 4), 10),
|
|
4674
|
+
Number.parseInt(toDate.slice(5, 7), 10) - 1,
|
|
4675
|
+
Number.parseInt(toDate.slice(8, 10), 10)
|
|
4676
|
+
);
|
|
4677
|
+
return Math.round((to - from) / (24 * 60 * 60 * 1e3)) + 1;
|
|
4678
|
+
}
|
|
4679
|
+
function resolveAutoStrategy(fromDate, toDate) {
|
|
4680
|
+
return daysBetween(fromDate, toDate) <= 7 ? "exact_window" : "warm_cache";
|
|
4681
|
+
}
|
|
4682
|
+
function inchesToMm(inches) {
|
|
4683
|
+
if (inches === null || inches === void 0) return null;
|
|
4684
|
+
return inches * 25.4;
|
|
4685
|
+
}
|
|
4686
|
+
function mbToInhg(mb) {
|
|
4687
|
+
if (mb === null || mb === void 0) return null;
|
|
4688
|
+
return mb * 0.029529983071445;
|
|
4689
|
+
}
|
|
4690
|
+
function fromObservation(o) {
|
|
4691
|
+
const tempC = o.temp_c ?? null;
|
|
4692
|
+
const dewC = o.dewpoint_c ?? null;
|
|
4693
|
+
return {
|
|
4694
|
+
station: o.station_code,
|
|
4695
|
+
observed_at: o.observed_at,
|
|
4696
|
+
source: o.source,
|
|
4697
|
+
temp_c: tempC,
|
|
4698
|
+
temp_f: tempC !== null ? tempC * (9 / 5) + 32 : null,
|
|
4699
|
+
dewpoint_c: dewC,
|
|
4700
|
+
dewpoint_f: dewC !== null ? dewC * (9 / 5) + 32 : null,
|
|
4701
|
+
wind_speed_kts: o.wind_speed_kt ?? null,
|
|
4702
|
+
wind_direction_deg: o.wind_dir_degrees ?? null,
|
|
4703
|
+
pressure_inhg: mbToInhg(o.sea_level_pressure_mb),
|
|
4704
|
+
precip_mm_1h: inchesToMm(o.precip_1hr_inches),
|
|
4705
|
+
raw_metar: o.raw_metar ?? null
|
|
4706
|
+
};
|
|
4707
|
+
}
|
|
4708
|
+
async function fetchIemForWindow(station, fromDate, toDate, resolvedStrategy) {
|
|
4709
|
+
const out = [];
|
|
4710
|
+
if (resolvedStrategy === "exact_window") {
|
|
4711
|
+
const chunks = await downloadIemAsos(station, fromDate, toDate, {
|
|
4712
|
+
reportType: 3,
|
|
4713
|
+
politenessMs: 1e3
|
|
4714
|
+
});
|
|
4715
|
+
for (const chunk of chunks) {
|
|
4716
|
+
const rows = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|
|
4717
|
+
for (const r of rows) {
|
|
4718
|
+
const d = r.observed_at.slice(0, 10);
|
|
4719
|
+
if (d >= fromDate && d <= toDate) out.push(fromObservation(r));
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4722
|
+
return out;
|
|
4723
|
+
}
|
|
4724
|
+
const fromYear = Number.parseInt(fromDate.slice(0, 4), 10);
|
|
4725
|
+
const toYear = Number.parseInt(toDate.slice(0, 4), 10);
|
|
4726
|
+
for (let year = fromYear; year <= toYear; year++) {
|
|
4727
|
+
const chunks = await downloadIemAsos(station, `${year}-01-01`, `${year}-12-31`, {
|
|
4728
|
+
reportType: 3,
|
|
4729
|
+
politenessMs: 1e3
|
|
4730
|
+
});
|
|
4731
|
+
for (const chunk of chunks) {
|
|
4732
|
+
const rows = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|
|
4733
|
+
for (const r of rows) {
|
|
4734
|
+
const d = r.observed_at.slice(0, 10);
|
|
4735
|
+
if (d >= fromDate && d <= toDate) out.push(fromObservation(r));
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
return out;
|
|
4740
|
+
}
|
|
4741
|
+
async function fetchAwcForWindow(station, fromDate, toDate) {
|
|
4742
|
+
const raw = await fetchAwcMetars([station]);
|
|
4743
|
+
const out = [];
|
|
4744
|
+
for (const r of raw) {
|
|
4745
|
+
const obs2 = awcToObservation(r);
|
|
4746
|
+
if (obs2 === null) continue;
|
|
4747
|
+
const d = obs2.observed_at.slice(0, 10);
|
|
4748
|
+
if (d >= fromDate && d <= toDate) out.push(fromObservation(obs2));
|
|
4749
|
+
}
|
|
4750
|
+
return out;
|
|
4751
|
+
}
|
|
4752
|
+
async function fetchByStrategy(station, fromDate, toDate, resolvedStrategy, source) {
|
|
4753
|
+
const wantsIem = source === null || source === void 0 || source === "iem";
|
|
4754
|
+
const wantsAwc = source === null || source === void 0 || source === "awc";
|
|
4755
|
+
const tasks = [];
|
|
4756
|
+
if (wantsIem) tasks.push(fetchIemForWindow(station, fromDate, toDate, resolvedStrategy));
|
|
4757
|
+
if (wantsAwc) tasks.push(fetchAwcForWindow(station, fromDate, toDate).catch(() => []));
|
|
4758
|
+
const results = await Promise.all(tasks);
|
|
4759
|
+
return results.flat();
|
|
4760
|
+
}
|
|
4761
|
+
async function obs(station, fromDate, toDate, opts = {}) {
|
|
4762
|
+
const strategy = opts.strategy ?? "auto";
|
|
4763
|
+
const source = opts.source ?? null;
|
|
4764
|
+
if (source === "ghcnh") {
|
|
4765
|
+
throw new DataAvailabilityError({
|
|
4766
|
+
reason: "model_unavailable",
|
|
4767
|
+
source: "obs.ghcnh",
|
|
4768
|
+
hint: "source='ghcnh' is a valid Python `obs()` filter but the GHCNh fetcher path is not yet wired in the TypeScript SDK. Use source='iem' or source='awc' (or omit `source` for merged) until the TS GHCNh fetcher ships."
|
|
4769
|
+
});
|
|
4770
|
+
}
|
|
4771
|
+
if (strategy === "hosted") {
|
|
4772
|
+
throw new DataAvailabilityError({
|
|
4773
|
+
reason: "model_unavailable",
|
|
4774
|
+
source: "obs-hosted-stub",
|
|
4775
|
+
hint: "hosted ingest API ships in v0.2.x \u2014 use strategy='exact_window' or 'warm_cache' for v1.x. See https://mostlyright.md/docs/sdk/typescript/ingest-strategies"
|
|
4776
|
+
});
|
|
4777
|
+
}
|
|
4778
|
+
let resolved;
|
|
4779
|
+
if (strategy === "auto") {
|
|
4780
|
+
resolved = resolveAutoStrategy(fromDate, toDate);
|
|
4781
|
+
} else if (strategy === "exact_window" || strategy === "warm_cache") {
|
|
4782
|
+
resolved = strategy;
|
|
4783
|
+
} else {
|
|
4784
|
+
throw new TypeError(
|
|
4785
|
+
`obs: unknown strategy "${String(strategy)}" \u2014 expected one of: auto, exact_window, warm_cache, hosted`
|
|
4786
|
+
);
|
|
4787
|
+
}
|
|
4788
|
+
return fetchByStrategy(station, fromDate, toDate, resolved, source);
|
|
3366
4789
|
}
|
|
3367
4790
|
|
|
3368
4791
|
// ../weather/src/index.ts
|
|
@@ -4057,10 +5480,11 @@ var mostlyright = (() => {
|
|
|
4057
5480
|
}
|
|
4058
5481
|
}));
|
|
4059
5482
|
|
|
4060
|
-
// ../core/dist/internal/chunk-
|
|
5483
|
+
// ../core/dist/internal/chunk-IPC4XUYW.mjs
|
|
4061
5484
|
function lockKeyFor(key) {
|
|
4062
5485
|
return `mostlyright:cache:lock:${key}`;
|
|
4063
5486
|
}
|
|
5487
|
+
var CACHE_SCHEMA_VERSION = "v2-phase18-integer-f";
|
|
4064
5488
|
var MemoryStore = class {
|
|
4065
5489
|
#entries = /* @__PURE__ */ new Map();
|
|
4066
5490
|
#chain = /* @__PURE__ */ new Map();
|
|
@@ -4207,7 +5631,71 @@ var mostlyright = (() => {
|
|
|
4207
5631
|
return next;
|
|
4208
5632
|
}
|
|
4209
5633
|
};
|
|
4210
|
-
var
|
|
5634
|
+
var VERSION_FIELD = "_cache_schema_version";
|
|
5635
|
+
function isVersionedEntry(v) {
|
|
5636
|
+
if (v === null || typeof v !== "object") return false;
|
|
5637
|
+
if (!(VERSION_FIELD in v)) return false;
|
|
5638
|
+
return typeof v[VERSION_FIELD] === "string";
|
|
5639
|
+
}
|
|
5640
|
+
function hasListKeys(s) {
|
|
5641
|
+
return typeof s.listKeys === "function";
|
|
5642
|
+
}
|
|
5643
|
+
var VersionedCacheStore = class {
|
|
5644
|
+
#inner;
|
|
5645
|
+
#version;
|
|
5646
|
+
constructor(inner, version5) {
|
|
5647
|
+
if (typeof version5 !== "string" || version5.length === 0) {
|
|
5648
|
+
throw new TypeError("versionedCacheStore: version must be a non-empty string");
|
|
5649
|
+
}
|
|
5650
|
+
this.#inner = inner;
|
|
5651
|
+
this.#version = version5;
|
|
5652
|
+
}
|
|
5653
|
+
/**
|
|
5654
|
+
* Test/diagnostics seam: return the underlying store so tests can assert
|
|
5655
|
+
* which concrete backend `defaultCacheStore()` selected. NOT a production
|
|
5656
|
+
* API — production code MUST use the wrapped store so version
|
|
5657
|
+
* invalidation fires on stale reads.
|
|
5658
|
+
*
|
|
5659
|
+
* @internal
|
|
5660
|
+
*/
|
|
5661
|
+
__peekInner() {
|
|
5662
|
+
return this.#inner;
|
|
5663
|
+
}
|
|
5664
|
+
async get(key) {
|
|
5665
|
+
const raw = await this.#inner.get(key);
|
|
5666
|
+
if (raw === null) return null;
|
|
5667
|
+
if (!isVersionedEntry(raw)) {
|
|
5668
|
+
return null;
|
|
5669
|
+
}
|
|
5670
|
+
if (raw._cache_schema_version !== this.#version) {
|
|
5671
|
+
return null;
|
|
5672
|
+
}
|
|
5673
|
+
return raw.value;
|
|
5674
|
+
}
|
|
5675
|
+
async set(key, value, opts) {
|
|
5676
|
+
const wrapped = {
|
|
5677
|
+
value,
|
|
5678
|
+
[VERSION_FIELD]: this.#version
|
|
5679
|
+
};
|
|
5680
|
+
await this.#inner.set(key, wrapped, opts);
|
|
5681
|
+
}
|
|
5682
|
+
async delete(key) {
|
|
5683
|
+
await this.#inner.delete(key);
|
|
5684
|
+
}
|
|
5685
|
+
async withLock(key, fn) {
|
|
5686
|
+
return this.#inner.withLock(key, fn);
|
|
5687
|
+
}
|
|
5688
|
+
async listKeys(prefix) {
|
|
5689
|
+
if (hasListKeys(this.#inner)) {
|
|
5690
|
+
return this.#inner.listKeys(prefix);
|
|
5691
|
+
}
|
|
5692
|
+
return Object.freeze([]);
|
|
5693
|
+
}
|
|
5694
|
+
};
|
|
5695
|
+
function versionedCacheStore(inner, version5) {
|
|
5696
|
+
return new VersionedCacheStore(inner, version5);
|
|
5697
|
+
}
|
|
5698
|
+
var STATIONS3 = [
|
|
4211
5699
|
{
|
|
4212
5700
|
code: "EDDB",
|
|
4213
5701
|
country: "DE",
|
|
@@ -4819,131 +6307,131 @@ var mostlyright = (() => {
|
|
|
4819
6307
|
tz: "Asia/Shanghai"
|
|
4820
6308
|
}
|
|
4821
6309
|
];
|
|
4822
|
-
var
|
|
4823
|
-
["ATL",
|
|
4824
|
-
["AUS",
|
|
4825
|
-
["BOS",
|
|
4826
|
-
["DCA",
|
|
4827
|
-
["DEN",
|
|
4828
|
-
["DFW",
|
|
4829
|
-
["EDDB",
|
|
4830
|
-
["EDDF",
|
|
4831
|
-
["EDDM",
|
|
4832
|
-
["EFHK",
|
|
4833
|
-
["EGKK",
|
|
4834
|
-
["EGLL",
|
|
4835
|
-
["EHAM",
|
|
4836
|
-
["EKCH",
|
|
4837
|
-
["EPWA",
|
|
4838
|
-
["ESSA",
|
|
4839
|
-
["HOU",
|
|
4840
|
-
["LAS",
|
|
4841
|
-
["LAX",
|
|
4842
|
-
["LEBL",
|
|
4843
|
-
["LEMD",
|
|
4844
|
-
["LFPB",
|
|
4845
|
-
["LFPG",
|
|
4846
|
-
["LFPO",
|
|
4847
|
-
["LIMC",
|
|
4848
|
-
["LIRF",
|
|
4849
|
-
["LOWW",
|
|
4850
|
-
["LSZH",
|
|
4851
|
-
["MDW",
|
|
4852
|
-
["MIA",
|
|
4853
|
-
["MSP",
|
|
4854
|
-
["MSY",
|
|
4855
|
-
["NYC",
|
|
4856
|
-
["NZAA",
|
|
4857
|
-
["NZWN",
|
|
4858
|
-
["OERK",
|
|
4859
|
-
["OKC",
|
|
4860
|
-
["OMDB",
|
|
4861
|
-
["OTHH",
|
|
4862
|
-
["PHL",
|
|
4863
|
-
["PHX",
|
|
4864
|
-
["RCTP",
|
|
4865
|
-
["RJAA",
|
|
4866
|
-
["RJTT",
|
|
4867
|
-
["RKSI",
|
|
4868
|
-
["SAEZ",
|
|
4869
|
-
["SAT",
|
|
4870
|
-
["SBGR",
|
|
4871
|
-
["SEA",
|
|
4872
|
-
["SFO",
|
|
4873
|
-
["UUEE",
|
|
4874
|
-
["VABB",
|
|
4875
|
-
["VHHH",
|
|
4876
|
-
["VIDP",
|
|
4877
|
-
["VTBS",
|
|
4878
|
-
["WSSS",
|
|
4879
|
-
["YBBN",
|
|
4880
|
-
["YMML",
|
|
4881
|
-
["YSSY",
|
|
4882
|
-
["ZBAA",
|
|
4883
|
-
["ZSPD",
|
|
6310
|
+
var STATION_BY_CODE3 = /* @__PURE__ */ new Map([
|
|
6311
|
+
["ATL", STATIONS3[10]],
|
|
6312
|
+
["AUS", STATIONS3[11]],
|
|
6313
|
+
["BOS", STATIONS3[12]],
|
|
6314
|
+
["DCA", STATIONS3[13]],
|
|
6315
|
+
["DEN", STATIONS3[14]],
|
|
6316
|
+
["DFW", STATIONS3[15]],
|
|
6317
|
+
["EDDB", STATIONS3[0]],
|
|
6318
|
+
["EDDF", STATIONS3[1]],
|
|
6319
|
+
["EDDM", STATIONS3[2]],
|
|
6320
|
+
["EFHK", STATIONS3[3]],
|
|
6321
|
+
["EGKK", STATIONS3[4]],
|
|
6322
|
+
["EGLL", STATIONS3[5]],
|
|
6323
|
+
["EHAM", STATIONS3[6]],
|
|
6324
|
+
["EKCH", STATIONS3[7]],
|
|
6325
|
+
["EPWA", STATIONS3[8]],
|
|
6326
|
+
["ESSA", STATIONS3[9]],
|
|
6327
|
+
["HOU", STATIONS3[16]],
|
|
6328
|
+
["LAS", STATIONS3[17]],
|
|
6329
|
+
["LAX", STATIONS3[18]],
|
|
6330
|
+
["LEBL", STATIONS3[30]],
|
|
6331
|
+
["LEMD", STATIONS3[31]],
|
|
6332
|
+
["LFPB", STATIONS3[32]],
|
|
6333
|
+
["LFPG", STATIONS3[33]],
|
|
6334
|
+
["LFPO", STATIONS3[34]],
|
|
6335
|
+
["LIMC", STATIONS3[35]],
|
|
6336
|
+
["LIRF", STATIONS3[36]],
|
|
6337
|
+
["LOWW", STATIONS3[37]],
|
|
6338
|
+
["LSZH", STATIONS3[38]],
|
|
6339
|
+
["MDW", STATIONS3[19]],
|
|
6340
|
+
["MIA", STATIONS3[20]],
|
|
6341
|
+
["MSP", STATIONS3[21]],
|
|
6342
|
+
["MSY", STATIONS3[22]],
|
|
6343
|
+
["NYC", STATIONS3[23]],
|
|
6344
|
+
["NZAA", STATIONS3[39]],
|
|
6345
|
+
["NZWN", STATIONS3[40]],
|
|
6346
|
+
["OERK", STATIONS3[41]],
|
|
6347
|
+
["OKC", STATIONS3[24]],
|
|
6348
|
+
["OMDB", STATIONS3[42]],
|
|
6349
|
+
["OTHH", STATIONS3[43]],
|
|
6350
|
+
["PHL", STATIONS3[25]],
|
|
6351
|
+
["PHX", STATIONS3[26]],
|
|
6352
|
+
["RCTP", STATIONS3[44]],
|
|
6353
|
+
["RJAA", STATIONS3[45]],
|
|
6354
|
+
["RJTT", STATIONS3[46]],
|
|
6355
|
+
["RKSI", STATIONS3[47]],
|
|
6356
|
+
["SAEZ", STATIONS3[48]],
|
|
6357
|
+
["SAT", STATIONS3[27]],
|
|
6358
|
+
["SBGR", STATIONS3[49]],
|
|
6359
|
+
["SEA", STATIONS3[28]],
|
|
6360
|
+
["SFO", STATIONS3[29]],
|
|
6361
|
+
["UUEE", STATIONS3[50]],
|
|
6362
|
+
["VABB", STATIONS3[51]],
|
|
6363
|
+
["VHHH", STATIONS3[52]],
|
|
6364
|
+
["VIDP", STATIONS3[53]],
|
|
6365
|
+
["VTBS", STATIONS3[54]],
|
|
6366
|
+
["WSSS", STATIONS3[55]],
|
|
6367
|
+
["YBBN", STATIONS3[56]],
|
|
6368
|
+
["YMML", STATIONS3[57]],
|
|
6369
|
+
["YSSY", STATIONS3[58]],
|
|
6370
|
+
["ZBAA", STATIONS3[59]],
|
|
6371
|
+
["ZSPD", STATIONS3[60]]
|
|
4884
6372
|
]);
|
|
4885
|
-
var
|
|
4886
|
-
["EDDB",
|
|
4887
|
-
["EDDF",
|
|
4888
|
-
["EDDM",
|
|
4889
|
-
["EFHK",
|
|
4890
|
-
["EGKK",
|
|
4891
|
-
["EGLL",
|
|
4892
|
-
["EHAM",
|
|
4893
|
-
["EKCH",
|
|
4894
|
-
["EPWA",
|
|
4895
|
-
["ESSA",
|
|
4896
|
-
["KATL",
|
|
4897
|
-
["KAUS",
|
|
4898
|
-
["KBOS",
|
|
4899
|
-
["KDCA",
|
|
4900
|
-
["KDEN",
|
|
4901
|
-
["KDFW",
|
|
4902
|
-
["KHOU",
|
|
4903
|
-
["KLAS",
|
|
4904
|
-
["KLAX",
|
|
4905
|
-
["KMDW",
|
|
4906
|
-
["KMIA",
|
|
4907
|
-
["KMSP",
|
|
4908
|
-
["KMSY",
|
|
4909
|
-
["KNYC",
|
|
4910
|
-
["KOKC",
|
|
4911
|
-
["KPHL",
|
|
4912
|
-
["KPHX",
|
|
4913
|
-
["KSAT",
|
|
4914
|
-
["KSEA",
|
|
4915
|
-
["KSFO",
|
|
4916
|
-
["LEBL",
|
|
4917
|
-
["LEMD",
|
|
4918
|
-
["LFPB",
|
|
4919
|
-
["LFPG",
|
|
4920
|
-
["LFPO",
|
|
4921
|
-
["LIMC",
|
|
4922
|
-
["LIRF",
|
|
4923
|
-
["LOWW",
|
|
4924
|
-
["LSZH",
|
|
4925
|
-
["NZAA",
|
|
4926
|
-
["NZWN",
|
|
4927
|
-
["OERK",
|
|
4928
|
-
["OMDB",
|
|
4929
|
-
["OTHH",
|
|
4930
|
-
["RCTP",
|
|
4931
|
-
["RJAA",
|
|
4932
|
-
["RJTT",
|
|
4933
|
-
["RKSI",
|
|
4934
|
-
["SAEZ",
|
|
4935
|
-
["SBGR",
|
|
4936
|
-
["UUEE",
|
|
4937
|
-
["VABB",
|
|
4938
|
-
["VHHH",
|
|
4939
|
-
["VIDP",
|
|
4940
|
-
["VTBS",
|
|
4941
|
-
["WSSS",
|
|
4942
|
-
["YBBN",
|
|
4943
|
-
["YMML",
|
|
4944
|
-
["YSSY",
|
|
4945
|
-
["ZBAA",
|
|
4946
|
-
["ZSPD",
|
|
6373
|
+
var STATION_BY_ICAO3 = /* @__PURE__ */ new Map([
|
|
6374
|
+
["EDDB", STATIONS3[0]],
|
|
6375
|
+
["EDDF", STATIONS3[1]],
|
|
6376
|
+
["EDDM", STATIONS3[2]],
|
|
6377
|
+
["EFHK", STATIONS3[3]],
|
|
6378
|
+
["EGKK", STATIONS3[4]],
|
|
6379
|
+
["EGLL", STATIONS3[5]],
|
|
6380
|
+
["EHAM", STATIONS3[6]],
|
|
6381
|
+
["EKCH", STATIONS3[7]],
|
|
6382
|
+
["EPWA", STATIONS3[8]],
|
|
6383
|
+
["ESSA", STATIONS3[9]],
|
|
6384
|
+
["KATL", STATIONS3[10]],
|
|
6385
|
+
["KAUS", STATIONS3[11]],
|
|
6386
|
+
["KBOS", STATIONS3[12]],
|
|
6387
|
+
["KDCA", STATIONS3[13]],
|
|
6388
|
+
["KDEN", STATIONS3[14]],
|
|
6389
|
+
["KDFW", STATIONS3[15]],
|
|
6390
|
+
["KHOU", STATIONS3[16]],
|
|
6391
|
+
["KLAS", STATIONS3[17]],
|
|
6392
|
+
["KLAX", STATIONS3[18]],
|
|
6393
|
+
["KMDW", STATIONS3[19]],
|
|
6394
|
+
["KMIA", STATIONS3[20]],
|
|
6395
|
+
["KMSP", STATIONS3[21]],
|
|
6396
|
+
["KMSY", STATIONS3[22]],
|
|
6397
|
+
["KNYC", STATIONS3[23]],
|
|
6398
|
+
["KOKC", STATIONS3[24]],
|
|
6399
|
+
["KPHL", STATIONS3[25]],
|
|
6400
|
+
["KPHX", STATIONS3[26]],
|
|
6401
|
+
["KSAT", STATIONS3[27]],
|
|
6402
|
+
["KSEA", STATIONS3[28]],
|
|
6403
|
+
["KSFO", STATIONS3[29]],
|
|
6404
|
+
["LEBL", STATIONS3[30]],
|
|
6405
|
+
["LEMD", STATIONS3[31]],
|
|
6406
|
+
["LFPB", STATIONS3[32]],
|
|
6407
|
+
["LFPG", STATIONS3[33]],
|
|
6408
|
+
["LFPO", STATIONS3[34]],
|
|
6409
|
+
["LIMC", STATIONS3[35]],
|
|
6410
|
+
["LIRF", STATIONS3[36]],
|
|
6411
|
+
["LOWW", STATIONS3[37]],
|
|
6412
|
+
["LSZH", STATIONS3[38]],
|
|
6413
|
+
["NZAA", STATIONS3[39]],
|
|
6414
|
+
["NZWN", STATIONS3[40]],
|
|
6415
|
+
["OERK", STATIONS3[41]],
|
|
6416
|
+
["OMDB", STATIONS3[42]],
|
|
6417
|
+
["OTHH", STATIONS3[43]],
|
|
6418
|
+
["RCTP", STATIONS3[44]],
|
|
6419
|
+
["RJAA", STATIONS3[45]],
|
|
6420
|
+
["RJTT", STATIONS3[46]],
|
|
6421
|
+
["RKSI", STATIONS3[47]],
|
|
6422
|
+
["SAEZ", STATIONS3[48]],
|
|
6423
|
+
["SBGR", STATIONS3[49]],
|
|
6424
|
+
["UUEE", STATIONS3[50]],
|
|
6425
|
+
["VABB", STATIONS3[51]],
|
|
6426
|
+
["VHHH", STATIONS3[52]],
|
|
6427
|
+
["VIDP", STATIONS3[53]],
|
|
6428
|
+
["VTBS", STATIONS3[54]],
|
|
6429
|
+
["WSSS", STATIONS3[55]],
|
|
6430
|
+
["YBBN", STATIONS3[56]],
|
|
6431
|
+
["YMML", STATIONS3[57]],
|
|
6432
|
+
["YSSY", STATIONS3[58]],
|
|
6433
|
+
["ZBAA", STATIONS3[59]],
|
|
6434
|
+
["ZSPD", STATIONS3[60]]
|
|
4947
6435
|
]);
|
|
4948
6436
|
var _STATION_TZ2 = Object.freeze({
|
|
4949
6437
|
// Eastern (UTC-5 standard / UTC-4 DST)
|
|
@@ -5090,13 +6578,13 @@ var mostlyright = (() => {
|
|
|
5090
6578
|
}
|
|
5091
6579
|
function _lstOffsetHoursFor(station) {
|
|
5092
6580
|
const upper = station.trim().toUpperCase();
|
|
5093
|
-
const byCode =
|
|
6581
|
+
const byCode = STATION_BY_CODE3.get(upper);
|
|
5094
6582
|
if (byCode !== void 0) return _lstOffsetHours2(byCode.tz);
|
|
5095
|
-
const byIcao =
|
|
6583
|
+
const byIcao = STATION_BY_ICAO3.get(upper);
|
|
5096
6584
|
if (byIcao !== void 0) return _lstOffsetHours2(byIcao.tz);
|
|
5097
6585
|
if (upper.length === 4 && upper.startsWith("K")) {
|
|
5098
6586
|
const stripped = upper.slice(1);
|
|
5099
|
-
const retry =
|
|
6587
|
+
const retry = STATION_BY_CODE3.get(stripped);
|
|
5100
6588
|
if (retry !== void 0) return _lstOffsetHours2(retry.tz);
|
|
5101
6589
|
}
|
|
5102
6590
|
throw new RangeError(`unknown station: ${JSON.stringify(station)}`);
|
|
@@ -5168,8 +6656,8 @@ var mostlyright = (() => {
|
|
|
5168
6656
|
|
|
5169
6657
|
// ../core/dist/internal/cache/index.browser.mjs
|
|
5170
6658
|
async function defaultCacheStore() {
|
|
5171
|
-
|
|
5172
|
-
return
|
|
6659
|
+
const inner = typeof indexedDB !== "undefined" ? new IndexedDBStore() : new MemoryStore();
|
|
6660
|
+
return versionedCacheStore(inner, CACHE_SCHEMA_VERSION);
|
|
5173
6661
|
}
|
|
5174
6662
|
|
|
5175
6663
|
// ../core/dist/internal/pairs.mjs
|
|
@@ -5355,9 +6843,9 @@ var mostlyright = (() => {
|
|
|
5355
6843
|
);
|
|
5356
6844
|
return new Date(marketCloseAsUtcMs - offsetHours * 36e5);
|
|
5357
6845
|
}
|
|
5358
|
-
function collectNonNull(
|
|
6846
|
+
function collectNonNull(obs2, key) {
|
|
5359
6847
|
const out = [];
|
|
5360
|
-
for (const o of
|
|
6848
|
+
for (const o of obs2) {
|
|
5361
6849
|
const v = o[key];
|
|
5362
6850
|
if (typeof v === "number" && Number.isFinite(v)) out.push(v);
|
|
5363
6851
|
}
|
|
@@ -5452,13 +6940,68 @@ var mostlyright = (() => {
|
|
|
5452
6940
|
function buildPairs(station, dates, observationsByDate, climateByDate, opts = {}) {
|
|
5453
6941
|
const out = [];
|
|
5454
6942
|
for (const date of dates) {
|
|
5455
|
-
const
|
|
6943
|
+
const obs2 = observationsByDate[date] ?? [];
|
|
5456
6944
|
const climate = climateByDate[date] ?? null;
|
|
5457
|
-
out.push(buildPairsRow(date, station,
|
|
6945
|
+
out.push(buildPairsRow(date, station, obs2, climate, opts));
|
|
5458
6946
|
}
|
|
5459
6947
|
return Object.freeze(out);
|
|
5460
6948
|
}
|
|
5461
6949
|
|
|
6950
|
+
// src/research.types.ts
|
|
6951
|
+
var KNOWN_RESEARCH_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
6952
|
+
// Pre-Phase-21 fetcher controls.
|
|
6953
|
+
"signal",
|
|
6954
|
+
"awcHours",
|
|
6955
|
+
"iemPolitenessMs",
|
|
6956
|
+
"ghcnhPolitenessMs",
|
|
6957
|
+
"cliPolitenessMs",
|
|
6958
|
+
"now",
|
|
6959
|
+
"cache",
|
|
6960
|
+
// Pre-Phase-21 selectors.
|
|
6961
|
+
"city",
|
|
6962
|
+
"contract",
|
|
6963
|
+
"contracts",
|
|
6964
|
+
"stationOverride",
|
|
6965
|
+
"sources",
|
|
6966
|
+
"source",
|
|
6967
|
+
"includeTrades",
|
|
6968
|
+
"onWarning",
|
|
6969
|
+
// Phase 21 21-01: Python-parity composable kwargs.
|
|
6970
|
+
"include_forecast",
|
|
6971
|
+
"forecast_model",
|
|
6972
|
+
"forecast_models",
|
|
6973
|
+
"qc",
|
|
6974
|
+
"tz_override",
|
|
6975
|
+
"backend",
|
|
6976
|
+
"return_type"
|
|
6977
|
+
]);
|
|
6978
|
+
function validateResearchKwargs(opts) {
|
|
6979
|
+
const present = (v) => v !== void 0 && v !== null;
|
|
6980
|
+
for (const key of Object.keys(opts)) {
|
|
6981
|
+
if (!KNOWN_RESEARCH_OPTION_KEYS.has(key)) {
|
|
6982
|
+
throw new TypeError(
|
|
6983
|
+
`research(): unknown option key ${JSON.stringify(key)}. Valid keys: ${[...KNOWN_RESEARCH_OPTION_KEYS].sort().join(", ")}`
|
|
6984
|
+
);
|
|
6985
|
+
}
|
|
6986
|
+
}
|
|
6987
|
+
if (present(opts.sources) && present(opts.source)) {
|
|
6988
|
+
throw new TypeError(
|
|
6989
|
+
"research(): sources= and source= are mutually exclusive \u2014 use `sources=` for the LIVE_V1 multi-source selector or `source=` for a single-source query, not both"
|
|
6990
|
+
);
|
|
6991
|
+
}
|
|
6992
|
+
if (present(opts.forecast_model) && present(opts.forecast_models)) {
|
|
6993
|
+
throw new TypeError(
|
|
6994
|
+
"research(): forecast_model= and forecast_models= are mutually exclusive \u2014 use `forecast_models=` for multi-model fan-out or `forecast_model=` for a single model, not both"
|
|
6995
|
+
);
|
|
6996
|
+
}
|
|
6997
|
+
const wantsForecast = present(opts.forecast_model) || present(opts.forecast_models);
|
|
6998
|
+
if (wantsForecast && opts.include_forecast !== true) {
|
|
6999
|
+
throw new TypeError(
|
|
7000
|
+
"research(): forecast_model=/forecast_models= require include_forecast=true; the model filter is otherwise silently ignored"
|
|
7001
|
+
);
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
7004
|
+
|
|
5462
7005
|
// src/research.ts
|
|
5463
7006
|
var AWC_MAX_HOURS2 = 168;
|
|
5464
7007
|
async function resolveCache(opts) {
|
|
@@ -5726,9 +7269,9 @@ var mostlyright = (() => {
|
|
|
5726
7269
|
}
|
|
5727
7270
|
}
|
|
5728
7271
|
}
|
|
5729
|
-
for (const
|
|
5730
|
-
const obsDate =
|
|
5731
|
-
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(
|
|
7272
|
+
for (const obs2 of monthRows) {
|
|
7273
|
+
const obsDate = obs2.observed_at.slice(0, 10);
|
|
7274
|
+
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs2);
|
|
5732
7275
|
}
|
|
5733
7276
|
}
|
|
5734
7277
|
return acc;
|
|
@@ -5799,14 +7342,22 @@ var mostlyright = (() => {
|
|
|
5799
7342
|
}
|
|
5800
7343
|
}
|
|
5801
7344
|
}
|
|
5802
|
-
for (const
|
|
5803
|
-
const obsDate =
|
|
5804
|
-
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(
|
|
7345
|
+
for (const obs2 of monthRows) {
|
|
7346
|
+
const obsDate = obs2.observed_at.slice(0, 10);
|
|
7347
|
+
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs2);
|
|
5805
7348
|
}
|
|
5806
7349
|
}
|
|
5807
7350
|
return acc;
|
|
5808
7351
|
}
|
|
5809
7352
|
async function research(station, fromDate, toDate, opts = {}) {
|
|
7353
|
+
validateResearchKwargs(opts);
|
|
7354
|
+
if (opts.backend === "polars") {
|
|
7355
|
+
throw new DataAvailabilityError({
|
|
7356
|
+
reason: "model_unavailable",
|
|
7357
|
+
hint: 'polars backend not available in TypeScript SDK; use Python (mostlyrightmd) for backend="polars". TS returns plain object arrays.',
|
|
7358
|
+
source: "research.backend"
|
|
7359
|
+
});
|
|
7360
|
+
}
|
|
5810
7361
|
const hasCity = typeof opts.city === "string" && opts.city.length > 0;
|
|
5811
7362
|
const hasContract = typeof opts.contract === "string" && opts.contract.length > 0;
|
|
5812
7363
|
const hasContracts = Array.isArray(opts.contracts) && opts.contracts.length > 0;
|
|
@@ -5882,8 +7433,8 @@ var mostlyright = (() => {
|
|
|
5882
7433
|
if (opts.signal !== void 0) awcOpts.signal = opts.signal;
|
|
5883
7434
|
const awcRaw = await fetchAwcMetars([resolved.icao], awcOpts);
|
|
5884
7435
|
for (const m of awcRaw) {
|
|
5885
|
-
const
|
|
5886
|
-
if (
|
|
7436
|
+
const obs2 = awcToObservation(m);
|
|
7437
|
+
if (obs2 !== null) awcRows.push(obs2);
|
|
5887
7438
|
}
|
|
5888
7439
|
}
|
|
5889
7440
|
const iemRows = await fetchIemAsosWithCache(
|
|
@@ -5914,8 +7465,8 @@ var mostlyright = (() => {
|
|
|
5914
7465
|
const observationsByDate = {};
|
|
5915
7466
|
const dateLo = dates[0] ?? "";
|
|
5916
7467
|
const dateHi = dates[dates.length - 1] ?? "";
|
|
5917
|
-
for (const
|
|
5918
|
-
const settleDate = observedSettlementDate(
|
|
7468
|
+
for (const obs2 of merged) {
|
|
7469
|
+
const settleDate = observedSettlementDate(obs2.observed_at, resolved.code);
|
|
5919
7470
|
if (settleDate === null) continue;
|
|
5920
7471
|
if (settleDate < dateLo || settleDate > dateHi) continue;
|
|
5921
7472
|
let bucket = observationsByDate[settleDate];
|
|
@@ -5923,7 +7474,7 @@ var mostlyright = (() => {
|
|
|
5923
7474
|
bucket = [];
|
|
5924
7475
|
observationsByDate[settleDate] = bucket;
|
|
5925
7476
|
}
|
|
5926
|
-
bucket.push(
|
|
7477
|
+
bucket.push(obs2);
|
|
5927
7478
|
}
|
|
5928
7479
|
const climateByDate = {};
|
|
5929
7480
|
for (const cli of mergedClimate) {
|
|
@@ -6058,8 +7609,8 @@ var mostlyright = (() => {
|
|
|
6058
7609
|
const raw = await fetchAwcMetars([resolved.icao], awcOpts);
|
|
6059
7610
|
const parsed = [];
|
|
6060
7611
|
for (const m of raw) {
|
|
6061
|
-
const
|
|
6062
|
-
if (
|
|
7612
|
+
const obs2 = awcToObservation(m);
|
|
7613
|
+
if (obs2 !== null) parsed.push(obs2);
|
|
6063
7614
|
}
|
|
6064
7615
|
rows = parsed.filter((r) => {
|
|
6065
7616
|
const d = r.observed_at.slice(0, 10);
|
|
@@ -6351,6 +7902,129 @@ var mostlyright = (() => {
|
|
|
6351
7902
|
|
|
6352
7903
|
// src/index.ts
|
|
6353
7904
|
init_src();
|
|
7905
|
+
|
|
7906
|
+
// ../core/dist/preprocessing/index.mjs
|
|
7907
|
+
var preprocessing_exports = {};
|
|
7908
|
+
__export(preprocessing_exports, {
|
|
7909
|
+
PHYSICS_BOUNDS: () => PHYSICS_BOUNDS,
|
|
7910
|
+
clipOutliers: () => clipOutliers,
|
|
7911
|
+
iemCrosscheck: () => crosscheckIemGhcnh
|
|
7912
|
+
});
|
|
7913
|
+
var PHYSICS_BOUNDS = /* @__PURE__ */ new Map([
|
|
7914
|
+
["temp_c", [-89, 57]],
|
|
7915
|
+
["dew_point_c", [-89, 35]],
|
|
7916
|
+
["dewpoint_c", [-89, 35]],
|
|
7917
|
+
["wind_speed_ms", [0, 100]],
|
|
7918
|
+
["wind_speed_kt", [0, 200]],
|
|
7919
|
+
["wind_dir_deg", [0, 360]],
|
|
7920
|
+
["wind_dir_degrees", [0, 360]],
|
|
7921
|
+
["slp_hpa", [870, 1085]],
|
|
7922
|
+
["sea_level_pressure_mb", [870, 1085]],
|
|
7923
|
+
["relative_humidity_pct_2m", [0, 100]],
|
|
7924
|
+
["precip_mm_1h", [0, 305]]
|
|
7925
|
+
]);
|
|
7926
|
+
function clipOutliers(rows, col, opts = {}) {
|
|
7927
|
+
const std = opts.std ?? 3;
|
|
7928
|
+
const key = `${col}_clipped`;
|
|
7929
|
+
let lo;
|
|
7930
|
+
let hi;
|
|
7931
|
+
let passThrough = false;
|
|
7932
|
+
if (opts.bounds !== void 0) {
|
|
7933
|
+
[lo, hi] = opts.bounds;
|
|
7934
|
+
} else if (PHYSICS_BOUNDS.has(col)) {
|
|
7935
|
+
const b = PHYSICS_BOUNDS.get(col);
|
|
7936
|
+
if (b === void 0) {
|
|
7937
|
+
throw new Error(`PHYSICS_BOUNDS.get(${col}) unexpectedly undefined`);
|
|
7938
|
+
}
|
|
7939
|
+
[lo, hi] = b;
|
|
7940
|
+
} else {
|
|
7941
|
+
if (!Number.isFinite(std) || std <= 0) {
|
|
7942
|
+
throw new RangeError(
|
|
7943
|
+
`clipOutliers: std must be > 0 for the sigma fallback (got ${std}); pass bounds=[lo, hi] or use a physics-default column`
|
|
7944
|
+
);
|
|
7945
|
+
}
|
|
7946
|
+
const vals = [];
|
|
7947
|
+
for (const r of rows) {
|
|
7948
|
+
const v = r?.[col];
|
|
7949
|
+
if (typeof v === "number" && Number.isFinite(v)) vals.push(v);
|
|
7950
|
+
}
|
|
7951
|
+
if (vals.length < 2) {
|
|
7952
|
+
passThrough = true;
|
|
7953
|
+
lo = Number.NEGATIVE_INFINITY;
|
|
7954
|
+
hi = Number.POSITIVE_INFINITY;
|
|
7955
|
+
} else {
|
|
7956
|
+
const mu = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
7957
|
+
const sumSq = vals.reduce((a, b) => a + (b - mu) ** 2, 0);
|
|
7958
|
+
const sigma = Math.sqrt(sumSq / (vals.length - 1));
|
|
7959
|
+
if (sigma === 0 || !Number.isFinite(sigma)) {
|
|
7960
|
+
passThrough = true;
|
|
7961
|
+
lo = Number.NEGATIVE_INFINITY;
|
|
7962
|
+
hi = Number.POSITIVE_INFINITY;
|
|
7963
|
+
} else {
|
|
7964
|
+
lo = mu - std * sigma;
|
|
7965
|
+
hi = mu + std * sigma;
|
|
7966
|
+
}
|
|
7967
|
+
}
|
|
7968
|
+
}
|
|
7969
|
+
const out = [];
|
|
7970
|
+
for (const r of rows) {
|
|
7971
|
+
const v = r?.[col];
|
|
7972
|
+
let clipped;
|
|
7973
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
7974
|
+
clipped = passThrough ? v : Math.min(Math.max(v, lo), hi);
|
|
7975
|
+
} else {
|
|
7976
|
+
clipped = null;
|
|
7977
|
+
}
|
|
7978
|
+
out.push({ ...r, [key]: clipped });
|
|
7979
|
+
}
|
|
7980
|
+
return out;
|
|
7981
|
+
}
|
|
7982
|
+
function crosscheckIemGhcnh(iemRows, ghcnhRows, opts = {}) {
|
|
7983
|
+
const tolC = opts.tolC ?? 2;
|
|
7984
|
+
if (iemRows.length === 0 || ghcnhRows.length === 0) return [];
|
|
7985
|
+
for (const r of iemRows) {
|
|
7986
|
+
if (typeof r?.station !== "string" || typeof r?.eventTime !== "string") {
|
|
7987
|
+
throw new Error(
|
|
7988
|
+
"crosscheckIemGhcnh: iem rows must carry 'station' (string) and 'eventTime' (string) keys"
|
|
7989
|
+
);
|
|
7990
|
+
}
|
|
7991
|
+
}
|
|
7992
|
+
for (const r of ghcnhRows) {
|
|
7993
|
+
if (typeof r?.station !== "string" || typeof r?.eventTime !== "string") {
|
|
7994
|
+
throw new Error(
|
|
7995
|
+
"crosscheckIemGhcnh: ghcnh rows must carry 'station' (string) and 'eventTime' (string) keys"
|
|
7996
|
+
);
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
const iemMap = /* @__PURE__ */ new Map();
|
|
8000
|
+
for (const r of iemRows) {
|
|
8001
|
+
const key = `${r.station}|${r.eventTime}`;
|
|
8002
|
+
iemMap.set(key, r);
|
|
8003
|
+
}
|
|
8004
|
+
const out = [];
|
|
8005
|
+
for (const g of ghcnhRows) {
|
|
8006
|
+
const key = `${g.station}|${g.eventTime}`;
|
|
8007
|
+
const i = iemMap.get(key);
|
|
8008
|
+
if (i === void 0) continue;
|
|
8009
|
+
const iT = typeof i.temp_c === "number" && Number.isFinite(i.temp_c) ? i.temp_c : null;
|
|
8010
|
+
const gT = typeof g.temp_c === "number" && Number.isFinite(g.temp_c) ? g.temp_c : null;
|
|
8011
|
+
if (iT === null || gT === null) continue;
|
|
8012
|
+
const delta = Math.abs(iT - gT);
|
|
8013
|
+
if (delta > tolC) {
|
|
8014
|
+
out.push({
|
|
8015
|
+
station: g.station,
|
|
8016
|
+
eventTime: g.eventTime,
|
|
8017
|
+
tempCIem: iT,
|
|
8018
|
+
tempCGhcnh: gT,
|
|
8019
|
+
deltaC: delta
|
|
8020
|
+
});
|
|
8021
|
+
}
|
|
8022
|
+
}
|
|
8023
|
+
return out;
|
|
8024
|
+
}
|
|
8025
|
+
|
|
8026
|
+
// src/index.ts
|
|
8027
|
+
var Preprocessing = preprocessing_exports;
|
|
6354
8028
|
var version4 = "0.0.0";
|
|
6355
8029
|
return __toCommonJS(index_exports);
|
|
6356
8030
|
})();
|