mostlyright 1.1.3 → 1.4.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 +19 -3
- package/dist/{chunk-IN2UOZYO.mjs → chunk-7XWX6QZG.mjs} +619 -175
- package/dist/chunk-7XWX6QZG.mjs.map +1 -0
- package/dist/{chunk-465FJZTS.mjs → chunk-TT6J2BKH.mjs} +2 -2
- package/dist/{chunk-465FJZTS.mjs.map → chunk-TT6J2BKH.mjs.map} +1 -1
- package/dist/{iem-asos-ZPUMH3KM.mjs → iem-asos-OLJNQPEM.mjs} +3 -3
- package/dist/index.bundle.mjs +2758 -227
- 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 +3444 -448
- 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-JXVFCGSQ.mjs} +18 -4
- package/package.json +27 -5
- package/dist/chunk-IN2UOZYO.mjs.map +0 -1
- /package/dist/{iem-asos-ZPUMH3KM.mjs.map → iem-asos-OLJNQPEM.mjs.map} +0 -0
- /package/dist/{src-NP2MZ322.mjs.map → src-JXVFCGSQ.mjs.map} +0 -0
package/dist/index.bundle.mjs
CHANGED
|
@@ -4,12 +4,16 @@ import {
|
|
|
4
4
|
buildIemUrl,
|
|
5
5
|
downloadIemAsos,
|
|
6
6
|
yearlyChunksExclusiveEnd
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TT6J2BKH.mjs";
|
|
8
8
|
import {
|
|
9
9
|
CLIMATE_REPORT_TYPE_PRIORITY,
|
|
10
|
+
DataAvailabilityError,
|
|
10
11
|
LiveStreamError,
|
|
11
12
|
NoLiveDataError,
|
|
12
13
|
NotFoundError,
|
|
14
|
+
NwpNotAvailableError,
|
|
15
|
+
OpenMeteoSeamlessLeakageError,
|
|
16
|
+
STATIONS,
|
|
13
17
|
STATION_BY_CODE,
|
|
14
18
|
STATION_BY_ICAO,
|
|
15
19
|
SourceMismatchError,
|
|
@@ -18,7 +22,7 @@ import {
|
|
|
18
22
|
helloCore,
|
|
19
23
|
settlementDateFor,
|
|
20
24
|
src_exports
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-7XWX6QZG.mjs";
|
|
22
26
|
import {
|
|
23
27
|
awcToObservation,
|
|
24
28
|
celsiusToFahrenheit,
|
|
@@ -66,12 +70,18 @@ __export(src_exports2, {
|
|
|
66
70
|
LiveStreamError: () => LiveStreamError,
|
|
67
71
|
NCEI_POLITE_DELAY_MS: () => NCEI_POLITE_DELAY_MS,
|
|
68
72
|
NoLiveDataError: () => NoLiveDataError,
|
|
73
|
+
OPEN_METEO_LIVE_URL: () => OPEN_METEO_LIVE_URL,
|
|
74
|
+
OPEN_METEO_MODELS: () => OPEN_METEO_MODELS,
|
|
75
|
+
OPEN_METEO_PREVIOUS_RUNS_URL: () => OPEN_METEO_PREVIOUS_RUNS_URL,
|
|
76
|
+
OPEN_METEO_SEAMLESS_URL: () => OPEN_METEO_SEAMLESS_URL,
|
|
77
|
+
OPEN_METEO_SINGLE_RUNS_URL: () => OPEN_METEO_SINGLE_RUNS_URL,
|
|
69
78
|
POLITE_FLOORS_S: () => POLITE_FLOORS_S,
|
|
70
79
|
SOURCE_IDENTITY_TAGS: () => SOURCE_IDENTITY_TAGS,
|
|
71
80
|
SSID_COLUMNS: () => SSID_COLUMNS,
|
|
72
81
|
SUPPORTED_SOURCES: () => SUPPORTED_SOURCES,
|
|
73
82
|
awcToObservation: () => awcToObservation,
|
|
74
83
|
buildIemUrl: () => buildIemUrl,
|
|
84
|
+
dailyExtremes: () => dailyExtremes,
|
|
75
85
|
downloadCli: () => downloadCli,
|
|
76
86
|
downloadCliRange: () => downloadCliRange,
|
|
77
87
|
downloadGhcnh: () => downloadGhcnh,
|
|
@@ -90,12 +100,15 @@ __export(src_exports2, {
|
|
|
90
100
|
latest: () => latest,
|
|
91
101
|
mapCloudCover: () => mapCloudCover,
|
|
92
102
|
mergeClimate: () => mergeClimate,
|
|
103
|
+
obs: () => obs,
|
|
104
|
+
openMeteoForecasts: () => openMeteoForecasts,
|
|
93
105
|
parseAwcVisibility: () => parseAwcVisibility,
|
|
94
106
|
parseCliRecord: () => parseCliRecord,
|
|
95
107
|
parseCliResponse: () => parseCliResponse,
|
|
96
108
|
parseGhcnhPsv: () => parseGhcnhPsv,
|
|
97
109
|
parseGhcnhRow: () => parseGhcnhRow,
|
|
98
110
|
parseIemCsv: () => parseIemCsv,
|
|
111
|
+
resolveAutoStrategy: () => resolveAutoStrategy,
|
|
99
112
|
sourceTag: () => sourceTag,
|
|
100
113
|
stream: () => stream,
|
|
101
114
|
validatePollSeconds: () => validatePollSeconds,
|
|
@@ -289,10 +302,10 @@ function inferReportType(product, observationDate) {
|
|
|
289
302
|
if (!product) return "preliminary";
|
|
290
303
|
const issued = parseProductTimestamp(product);
|
|
291
304
|
if (issued === null) return "preliminary";
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
305
|
+
const obs2 = parseObservationDate(observationDate);
|
|
306
|
+
if (obs2 === null) return "preliminary";
|
|
294
307
|
const issuedDayUtc = Date.UTC(issued.getUTCFullYear(), issued.getUTCMonth(), issued.getUTCDate());
|
|
295
|
-
const obsDayUtc =
|
|
308
|
+
const obsDayUtc = obs2.getTime();
|
|
296
309
|
const deltaDays = Math.round((issuedDayUtc - obsDayUtc) / 864e5);
|
|
297
310
|
if (deltaDays <= 0) return "preliminary";
|
|
298
311
|
if (deltaDays === 1) {
|
|
@@ -655,8 +668,8 @@ function parseGhcnhPsv(psvBody) {
|
|
|
655
668
|
const key = header[c];
|
|
656
669
|
row[key] = c < cells.length ? cells[c] : "";
|
|
657
670
|
}
|
|
658
|
-
const
|
|
659
|
-
if (
|
|
671
|
+
const obs2 = parseGhcnhRow(row);
|
|
672
|
+
if (obs2 !== null) out.push(obs2);
|
|
660
673
|
}
|
|
661
674
|
return out;
|
|
662
675
|
}
|
|
@@ -719,8 +732,8 @@ function normalizeStation(station) {
|
|
|
719
732
|
if (s.length === 3) return `K${s}`;
|
|
720
733
|
return s;
|
|
721
734
|
}
|
|
722
|
-
function asLiveObservation(
|
|
723
|
-
return { ...
|
|
735
|
+
function asLiveObservation(obs2, tag) {
|
|
736
|
+
return { ...obs2, source: tag };
|
|
724
737
|
}
|
|
725
738
|
async function fetchAwcLatest(station) {
|
|
726
739
|
const icao = normalizeStation(station);
|
|
@@ -728,9 +741,9 @@ async function fetchAwcLatest(station) {
|
|
|
728
741
|
const tag = sourceTag("awc");
|
|
729
742
|
const rows = [];
|
|
730
743
|
for (const m of raw) {
|
|
731
|
-
const
|
|
732
|
-
if (
|
|
733
|
-
rows.push(asLiveObservation(
|
|
744
|
+
const obs2 = awcToObservation(m);
|
|
745
|
+
if (obs2 !== null) {
|
|
746
|
+
rows.push(asLiveObservation(obs2, tag));
|
|
734
747
|
}
|
|
735
748
|
}
|
|
736
749
|
return rows;
|
|
@@ -762,9 +775,9 @@ function previousDayIso(iso) {
|
|
|
762
775
|
}
|
|
763
776
|
async function fetchIemLatest(station) {
|
|
764
777
|
const [{ fetchWithRetry: fetchWithRetry2 }, { STATION_CODE_RE: STATION_CODE_RE3 }, { buildIemUrl: buildIemUrl2 }, { parseIemCsv: parseIemCsv2 }] = await Promise.all([
|
|
765
|
-
import("./src-
|
|
778
|
+
import("./src-JXVFCGSQ.mjs"),
|
|
766
779
|
import("./bounds-KSTXL77E.mjs"),
|
|
767
|
-
import("./iem-asos-
|
|
780
|
+
import("./iem-asos-OLJNQPEM.mjs"),
|
|
768
781
|
import("./iem-IO2HIL5V.mjs")
|
|
769
782
|
]);
|
|
770
783
|
const icao = normalizeStation(station);
|
|
@@ -786,8 +799,8 @@ async function fetchIemLatest(station) {
|
|
|
786
799
|
const response = await fetchWithRetry2(url);
|
|
787
800
|
const csv = await response.text();
|
|
788
801
|
const override = reportType === 3 ? "METAR" : "SPECI";
|
|
789
|
-
const
|
|
790
|
-
for (const row of
|
|
802
|
+
const obs2 = parseIemCsv2(csv, { observationTypeOverride: override });
|
|
803
|
+
for (const row of obs2) {
|
|
791
804
|
rows.push(asLiveObservation(row, tag));
|
|
792
805
|
}
|
|
793
806
|
}
|
|
@@ -1000,10 +1013,2006 @@ async function iemMosForecasts(station, fromDate, toDate, opts = {}) {
|
|
|
1000
1013
|
}
|
|
1001
1014
|
|
|
1002
1015
|
// ../weather/src/forecasts/nwp-stub.ts
|
|
1003
|
-
|
|
1016
|
+
var IEM_MOS_COVERED_STATIONS = /* @__PURE__ */ new Set([
|
|
1017
|
+
"KNYC",
|
|
1018
|
+
"KLAX",
|
|
1019
|
+
"KORD",
|
|
1020
|
+
"KMIA",
|
|
1021
|
+
"KDEN",
|
|
1022
|
+
"KSEA",
|
|
1023
|
+
"KATL"
|
|
1024
|
+
]);
|
|
1025
|
+
function buildHint(station, model) {
|
|
1026
|
+
const hasMosCoverage = IEM_MOS_COVERED_STATIONS.has(station.toUpperCase());
|
|
1027
|
+
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.`;
|
|
1028
|
+
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/nwp-forecasts/ for the architectural reason + v2.0+ tracking.`;
|
|
1029
|
+
}
|
|
1030
|
+
async function forecastNwp(station, model, _opts = {}) {
|
|
1031
|
+
throw new NwpNotAvailableError({
|
|
1032
|
+
station,
|
|
1033
|
+
model,
|
|
1034
|
+
hint: buildHint(station, model)
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// ../weather/src/forecasts/open-meteo-models.ts
|
|
1039
|
+
var OPEN_METEO_MODELS = /* @__PURE__ */ new Set([
|
|
1040
|
+
// NCEP (8)
|
|
1041
|
+
"gfs_seamless",
|
|
1042
|
+
"gfs_global",
|
|
1043
|
+
"gfs_graphcast025",
|
|
1044
|
+
"aigfs025",
|
|
1045
|
+
"hgefs025",
|
|
1046
|
+
"ncep_hrrr_conus",
|
|
1047
|
+
"ncep_nbm_conus",
|
|
1048
|
+
"ncep_nam_conus",
|
|
1049
|
+
// ECMWF (3)
|
|
1050
|
+
"ecmwf_ifs025",
|
|
1051
|
+
"ecmwf_ifs_hres",
|
|
1052
|
+
"ecmwf_aifs025_single",
|
|
1053
|
+
// DWD (5)
|
|
1054
|
+
"dwd_icon_seamless",
|
|
1055
|
+
"dwd_icon_global",
|
|
1056
|
+
"dwd_icon_eu",
|
|
1057
|
+
"dwd_icon_d2",
|
|
1058
|
+
"dwd_icon_d2_15min",
|
|
1059
|
+
// Météo-France (6)
|
|
1060
|
+
"meteofrance_seamless",
|
|
1061
|
+
"meteofrance_arpege_world025",
|
|
1062
|
+
"meteofrance_arpege_europe",
|
|
1063
|
+
"meteofrance_arome_france0025",
|
|
1064
|
+
"meteofrance_arome_france_hd",
|
|
1065
|
+
"meteofrance_arome_france_hd_15min",
|
|
1066
|
+
// Asia + Oceania (8)
|
|
1067
|
+
"jma_seamless",
|
|
1068
|
+
"jma_gsm",
|
|
1069
|
+
"jma_msm",
|
|
1070
|
+
"kma_seamless",
|
|
1071
|
+
"kma_gdps",
|
|
1072
|
+
"kma_ldps",
|
|
1073
|
+
"cma_grapes_global",
|
|
1074
|
+
"bom_access_global",
|
|
1075
|
+
// Europe (3)
|
|
1076
|
+
"ukmo_global_deterministic_10km",
|
|
1077
|
+
"ukmo_uk_deterministic_2km",
|
|
1078
|
+
"metno_nordic_pp",
|
|
1079
|
+
// GEM Canada (3)
|
|
1080
|
+
"cmc_gem_gdps",
|
|
1081
|
+
"cmc_gem_rdps",
|
|
1082
|
+
"cmc_gem_hrdps"
|
|
1083
|
+
]);
|
|
1084
|
+
var SIX_HOURLY = [0, 6, 12, 18];
|
|
1085
|
+
var THREE_HOURLY = [0, 3, 6, 9, 12, 15, 18, 21];
|
|
1086
|
+
var HOURLY = Array.from({ length: 24 }, (_, i) => i);
|
|
1087
|
+
var TWELVE_HOURLY = [0, 12];
|
|
1088
|
+
var CYCLE_HOURS = /* @__PURE__ */ new Map([
|
|
1089
|
+
// NCEP
|
|
1090
|
+
["gfs_seamless", SIX_HOURLY],
|
|
1091
|
+
["gfs_global", SIX_HOURLY],
|
|
1092
|
+
["gfs_graphcast025", SIX_HOURLY],
|
|
1093
|
+
["aigfs025", SIX_HOURLY],
|
|
1094
|
+
["hgefs025", SIX_HOURLY],
|
|
1095
|
+
["ncep_hrrr_conus", HOURLY],
|
|
1096
|
+
["ncep_nbm_conus", HOURLY],
|
|
1097
|
+
["ncep_nam_conus", SIX_HOURLY],
|
|
1098
|
+
// ECMWF
|
|
1099
|
+
["ecmwf_ifs025", SIX_HOURLY],
|
|
1100
|
+
["ecmwf_ifs_hres", SIX_HOURLY],
|
|
1101
|
+
["ecmwf_aifs025_single", SIX_HOURLY],
|
|
1102
|
+
// DWD
|
|
1103
|
+
["dwd_icon_seamless", SIX_HOURLY],
|
|
1104
|
+
["dwd_icon_global", SIX_HOURLY],
|
|
1105
|
+
["dwd_icon_eu", SIX_HOURLY],
|
|
1106
|
+
["dwd_icon_d2", THREE_HOURLY],
|
|
1107
|
+
["dwd_icon_d2_15min", THREE_HOURLY],
|
|
1108
|
+
// Météo-France
|
|
1109
|
+
["meteofrance_seamless", SIX_HOURLY],
|
|
1110
|
+
["meteofrance_arpege_world025", SIX_HOURLY],
|
|
1111
|
+
["meteofrance_arpege_europe", SIX_HOURLY],
|
|
1112
|
+
["meteofrance_arome_france0025", THREE_HOURLY],
|
|
1113
|
+
["meteofrance_arome_france_hd", THREE_HOURLY],
|
|
1114
|
+
["meteofrance_arome_france_hd_15min", THREE_HOURLY],
|
|
1115
|
+
// Asia + Oceania
|
|
1116
|
+
["jma_seamless", SIX_HOURLY],
|
|
1117
|
+
["jma_gsm", SIX_HOURLY],
|
|
1118
|
+
["jma_msm", THREE_HOURLY],
|
|
1119
|
+
["kma_seamless", SIX_HOURLY],
|
|
1120
|
+
["kma_gdps", SIX_HOURLY],
|
|
1121
|
+
["kma_ldps", THREE_HOURLY],
|
|
1122
|
+
["cma_grapes_global", SIX_HOURLY],
|
|
1123
|
+
["bom_access_global", SIX_HOURLY],
|
|
1124
|
+
// Europe
|
|
1125
|
+
["ukmo_global_deterministic_10km", SIX_HOURLY],
|
|
1126
|
+
["ukmo_uk_deterministic_2km", THREE_HOURLY],
|
|
1127
|
+
["metno_nordic_pp", HOURLY],
|
|
1128
|
+
// GEM Canada
|
|
1129
|
+
["cmc_gem_gdps", TWELVE_HOURLY],
|
|
1130
|
+
["cmc_gem_rdps", SIX_HOURLY],
|
|
1131
|
+
["cmc_gem_hrdps", SIX_HOURLY]
|
|
1132
|
+
]);
|
|
1133
|
+
var PUBLISH_LAG_HOURS = /* @__PURE__ */ new Map([
|
|
1134
|
+
// NCEP — global 6h, regional/mesoscale 2h
|
|
1135
|
+
["gfs_seamless", 6],
|
|
1136
|
+
["gfs_global", 6],
|
|
1137
|
+
["gfs_graphcast025", 6],
|
|
1138
|
+
["aigfs025", 6],
|
|
1139
|
+
["hgefs025", 6],
|
|
1140
|
+
["ncep_hrrr_conus", 2],
|
|
1141
|
+
["ncep_nbm_conus", 2],
|
|
1142
|
+
["ncep_nam_conus", 2],
|
|
1143
|
+
// ECMWF — global 6h
|
|
1144
|
+
["ecmwf_ifs025", 6],
|
|
1145
|
+
["ecmwf_ifs_hres", 6],
|
|
1146
|
+
["ecmwf_aifs025_single", 6],
|
|
1147
|
+
// DWD
|
|
1148
|
+
["dwd_icon_seamless", 4],
|
|
1149
|
+
["dwd_icon_global", 4],
|
|
1150
|
+
["dwd_icon_eu", 4],
|
|
1151
|
+
["dwd_icon_d2", 2],
|
|
1152
|
+
["dwd_icon_d2_15min", 2],
|
|
1153
|
+
// Météo-France
|
|
1154
|
+
["meteofrance_seamless", 4],
|
|
1155
|
+
["meteofrance_arpege_world025", 6],
|
|
1156
|
+
["meteofrance_arpege_europe", 4],
|
|
1157
|
+
["meteofrance_arome_france0025", 2],
|
|
1158
|
+
["meteofrance_arome_france_hd", 2],
|
|
1159
|
+
["meteofrance_arome_france_hd_15min", 2],
|
|
1160
|
+
// Asia + Oceania
|
|
1161
|
+
["jma_seamless", 6],
|
|
1162
|
+
["jma_gsm", 6],
|
|
1163
|
+
["jma_msm", 2],
|
|
1164
|
+
["kma_seamless", 6],
|
|
1165
|
+
["kma_gdps", 6],
|
|
1166
|
+
["kma_ldps", 2],
|
|
1167
|
+
["cma_grapes_global", 6],
|
|
1168
|
+
["bom_access_global", 6],
|
|
1169
|
+
// Europe
|
|
1170
|
+
["ukmo_global_deterministic_10km", 6],
|
|
1171
|
+
["ukmo_uk_deterministic_2km", 2],
|
|
1172
|
+
["metno_nordic_pp", 2],
|
|
1173
|
+
// GEM Canada
|
|
1174
|
+
["cmc_gem_gdps", 6],
|
|
1175
|
+
["cmc_gem_rdps", 4],
|
|
1176
|
+
["cmc_gem_hrdps", 2]
|
|
1177
|
+
]);
|
|
1178
|
+
function floorToCycleMs(valueUtcMs, cycleHours) {
|
|
1179
|
+
if (cycleHours.length === 0) {
|
|
1180
|
+
throw new Error("cycleHours must be non-empty");
|
|
1181
|
+
}
|
|
1182
|
+
const d = new Date(valueUtcMs);
|
|
1183
|
+
const hour = d.getUTCHours();
|
|
1184
|
+
const sorted = [...cycleHours].sort((a, b) => a - b);
|
|
1185
|
+
const candidates = sorted.filter((h) => h <= hour);
|
|
1186
|
+
if (candidates.length > 0) {
|
|
1187
|
+
const targetHour = candidates[candidates.length - 1];
|
|
1188
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), targetHour, 0, 0, 0);
|
|
1189
|
+
}
|
|
1190
|
+
const lastCycle = sorted[sorted.length - 1];
|
|
1191
|
+
const prior = new Date(valueUtcMs - 864e5);
|
|
1192
|
+
return Date.UTC(
|
|
1193
|
+
prior.getUTCFullYear(),
|
|
1194
|
+
prior.getUTCMonth(),
|
|
1195
|
+
prior.getUTCDate(),
|
|
1196
|
+
lastCycle,
|
|
1197
|
+
0,
|
|
1198
|
+
0,
|
|
1199
|
+
0
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
function issuedAtFromPreviousDayMs(validAtUtcMs, N, cycleHours) {
|
|
1203
|
+
if (N < 1 || N > 7) {
|
|
1204
|
+
throw new Error(`N must be in 1..7 (Open-Meteo previous_dayN limit); got ${N}`);
|
|
1205
|
+
}
|
|
1206
|
+
return floorToCycleMs(validAtUtcMs - N * 864e5, cycleHours);
|
|
1207
|
+
}
|
|
1208
|
+
function issuedAtFromLiveCycleMathMs(nowUtcMs, publishLagHours, cycleHours) {
|
|
1209
|
+
return floorToCycleMs(nowUtcMs - publishLagHours * 36e5, cycleHours);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// ../weather/src/forecasts/open-meteo.ts
|
|
1213
|
+
var OPEN_METEO_PREVIOUS_RUNS_URL = "https://previous-runs-api.open-meteo.com/v1/forecast";
|
|
1214
|
+
var OPEN_METEO_SINGLE_RUNS_URL = "https://single-runs-api.open-meteo.com/v1/forecast";
|
|
1215
|
+
var OPEN_METEO_LIVE_URL = "https://api.open-meteo.com/v1/forecast";
|
|
1216
|
+
var OPEN_METEO_SEAMLESS_URL = "https://historical-forecast-api.open-meteo.com/v1/forecast";
|
|
1217
|
+
var VALID_MODES = /* @__PURE__ */ new Set(["training", "live", "seamless"]);
|
|
1218
|
+
var HOURLY_VARIABLES = [
|
|
1219
|
+
"temperature_2m",
|
|
1220
|
+
"dew_point_2m",
|
|
1221
|
+
"apparent_temperature",
|
|
1222
|
+
"wind_speed_10m",
|
|
1223
|
+
"wind_direction_10m",
|
|
1224
|
+
"wind_gusts_10m",
|
|
1225
|
+
"precipitation",
|
|
1226
|
+
"precipitation_probability",
|
|
1227
|
+
"cloud_cover",
|
|
1228
|
+
"surface_pressure",
|
|
1229
|
+
"pressure_msl",
|
|
1230
|
+
"shortwave_radiation",
|
|
1231
|
+
"direct_radiation",
|
|
1232
|
+
"cape",
|
|
1233
|
+
"freezing_level_height",
|
|
1234
|
+
"snow_depth",
|
|
1235
|
+
"visibility",
|
|
1236
|
+
"weather_code"
|
|
1237
|
+
];
|
|
1238
|
+
var STATION_COORDS = /* @__PURE__ */ new Map([
|
|
1239
|
+
["KNYC", { lat: 40.78, lon: -73.97 }],
|
|
1240
|
+
["KORD", { lat: 41.98, lon: -87.9 }],
|
|
1241
|
+
["KDEN", { lat: 39.86, lon: -104.67 }],
|
|
1242
|
+
["KMIA", { lat: 25.79, lon: -80.29 }],
|
|
1243
|
+
["KSEA", { lat: 47.45, lon: -122.31 }]
|
|
1244
|
+
]);
|
|
1245
|
+
function resolveCoords(station) {
|
|
1246
|
+
const coords = STATION_COORDS.get(station);
|
|
1247
|
+
if (coords) return coords;
|
|
1004
1248
|
throw new Error(
|
|
1005
|
-
|
|
1249
|
+
`openMeteoForecasts: station=${JSON.stringify(station)} not in built-in coords table; add to STATION_COORDS`
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
function buildHourlyParam(endpoint) {
|
|
1253
|
+
if (endpoint === OPEN_METEO_PREVIOUS_RUNS_URL) {
|
|
1254
|
+
return HOURLY_VARIABLES.map((v) => `${v}_previous_day1`).join(",");
|
|
1255
|
+
}
|
|
1256
|
+
return HOURLY_VARIABLES.join(",");
|
|
1257
|
+
}
|
|
1258
|
+
function dispatchEndpoint(mode, opts) {
|
|
1259
|
+
if (mode === "training") {
|
|
1260
|
+
return opts.issuedAt ? OPEN_METEO_SINGLE_RUNS_URL : OPEN_METEO_PREVIOUS_RUNS_URL;
|
|
1261
|
+
}
|
|
1262
|
+
if (mode === "live") {
|
|
1263
|
+
return OPEN_METEO_LIVE_URL;
|
|
1264
|
+
}
|
|
1265
|
+
if (mode === "seamless") {
|
|
1266
|
+
if (!opts.allowLeakage) {
|
|
1267
|
+
throw new OpenMeteoSeamlessLeakageError(
|
|
1268
|
+
"Open-Meteo seamless endpoint is banned for training data (see Tarabcak/mostlyright#70). Pass allowLeakage: true to opt in; LeakageDetector will still reject these rows when asOf is asserted.",
|
|
1269
|
+
{
|
|
1270
|
+
model: opts.model,
|
|
1271
|
+
endpointUrl: OPEN_METEO_SEAMLESS_URL
|
|
1272
|
+
}
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
return OPEN_METEO_SEAMLESS_URL;
|
|
1276
|
+
}
|
|
1277
|
+
throw new Error(`openMeteoForecasts: unknown mode ${JSON.stringify(mode)}`);
|
|
1278
|
+
}
|
|
1279
|
+
function isoIfNotNull(ms) {
|
|
1280
|
+
return ms === null ? null : new Date(ms).toISOString();
|
|
1281
|
+
}
|
|
1282
|
+
function maybeNumber2(value) {
|
|
1283
|
+
if (value === null || value === void 0) return null;
|
|
1284
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
1285
|
+
return Number.isFinite(n) ? n : null;
|
|
1286
|
+
}
|
|
1287
|
+
function pickHourlyValue(hourly, key, isPreviousRuns, idx) {
|
|
1288
|
+
const arr = isPreviousRuns ? hourly[`${key}_previous_day1`] ?? hourly[key] : hourly[key];
|
|
1289
|
+
if (!Array.isArray(arr) || idx >= arr.length) return null;
|
|
1290
|
+
return arr[idx];
|
|
1291
|
+
}
|
|
1292
|
+
async function openMeteoForecasts(station, fromDate, toDate, opts = {}) {
|
|
1293
|
+
const model = opts.model ?? "gfs_global";
|
|
1294
|
+
if (!OPEN_METEO_MODELS.has(model)) {
|
|
1295
|
+
throw new Error(
|
|
1296
|
+
`openMeteoForecasts: model must be one of OPEN_METEO_MODELS (36 keys); got ${JSON.stringify(model)}`
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
const mode = opts.mode ?? "training";
|
|
1300
|
+
if (!VALID_MODES.has(mode)) {
|
|
1301
|
+
throw new Error(
|
|
1302
|
+
`openMeteoForecasts: mode must be one of training,live,seamless; got ${JSON.stringify(mode)}`
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
const endpoint = dispatchEndpoint(mode, {
|
|
1306
|
+
allowLeakage: opts.allowLeakage ?? false,
|
|
1307
|
+
model,
|
|
1308
|
+
issuedAt: opts.issuedAt
|
|
1309
|
+
});
|
|
1310
|
+
const { lat, lon } = resolveCoords(station);
|
|
1311
|
+
const params = new URLSearchParams();
|
|
1312
|
+
params.set("latitude", String(lat));
|
|
1313
|
+
params.set("longitude", String(lon));
|
|
1314
|
+
params.set("start_date", fromDate);
|
|
1315
|
+
params.set("end_date", toDate);
|
|
1316
|
+
params.set("hourly", buildHourlyParam(endpoint));
|
|
1317
|
+
params.set("models", model);
|
|
1318
|
+
params.set("timezone", "UTC");
|
|
1319
|
+
if (endpoint === OPEN_METEO_SINGLE_RUNS_URL && opts.issuedAt) {
|
|
1320
|
+
params.set("run", opts.issuedAt);
|
|
1321
|
+
}
|
|
1322
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
1323
|
+
const url = `${endpoint}?${params.toString()}`;
|
|
1324
|
+
const resp = await fetchFn(url);
|
|
1325
|
+
if (resp.status === 404) return [];
|
|
1326
|
+
if (!resp.ok) {
|
|
1327
|
+
throw new Error(`openMeteoForecasts: HTTP ${resp.status} on ${url}`);
|
|
1328
|
+
}
|
|
1329
|
+
const payload = await resp.json();
|
|
1330
|
+
const hourly = payload.hourly ?? {};
|
|
1331
|
+
const times = hourly.time ?? [];
|
|
1332
|
+
if (times.length === 0) return [];
|
|
1333
|
+
let source;
|
|
1334
|
+
if (endpoint === OPEN_METEO_PREVIOUS_RUNS_URL) {
|
|
1335
|
+
source = "open_meteo.previous_runs";
|
|
1336
|
+
} else if (endpoint === OPEN_METEO_SINGLE_RUNS_URL) {
|
|
1337
|
+
source = "open_meteo.single_run";
|
|
1338
|
+
} else if (endpoint === OPEN_METEO_LIVE_URL) {
|
|
1339
|
+
source = "open_meteo.live";
|
|
1340
|
+
} else {
|
|
1341
|
+
source = "open_meteo.seamless";
|
|
1342
|
+
}
|
|
1343
|
+
const cycleHours = CYCLE_HOURS.get(model) ?? [0, 6, 12, 18];
|
|
1344
|
+
const publishLag = PUBLISH_LAG_HOURS.get(model) ?? 6;
|
|
1345
|
+
const retrievedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1346
|
+
const nowMs = Date.now();
|
|
1347
|
+
const rows = [];
|
|
1348
|
+
for (let i = 0; i < times.length; i++) {
|
|
1349
|
+
const tIso = times[i] ?? "";
|
|
1350
|
+
if (!tIso) continue;
|
|
1351
|
+
const validAtMs = Date.parse(tIso.endsWith("Z") || tIso.includes("+") ? tIso : `${tIso}Z`);
|
|
1352
|
+
let issuedAtMs;
|
|
1353
|
+
if (source === "open_meteo.previous_runs") {
|
|
1354
|
+
issuedAtMs = issuedAtFromPreviousDayMs(validAtMs, 1, cycleHours);
|
|
1355
|
+
} else if (source === "open_meteo.single_run") {
|
|
1356
|
+
issuedAtMs = opts.issuedAt ? Date.parse(
|
|
1357
|
+
opts.issuedAt.endsWith("Z") || opts.issuedAt.includes("+") ? opts.issuedAt : `${opts.issuedAt}Z`
|
|
1358
|
+
) : null;
|
|
1359
|
+
} else if (source === "open_meteo.live") {
|
|
1360
|
+
issuedAtMs = issuedAtFromLiveCycleMathMs(nowMs, publishLag, cycleHours);
|
|
1361
|
+
} else {
|
|
1362
|
+
issuedAtMs = null;
|
|
1363
|
+
}
|
|
1364
|
+
const validAtIso = new Date(validAtMs).toISOString();
|
|
1365
|
+
const forecastHour = issuedAtMs === null ? null : Math.round((validAtMs - issuedAtMs) / 36e5);
|
|
1366
|
+
const isPrev = source === "open_meteo.previous_runs";
|
|
1367
|
+
const h = hourly;
|
|
1368
|
+
const popPct = maybeNumber2(pickHourlyValue(h, "precipitation_probability", isPrev, i));
|
|
1369
|
+
rows.push({
|
|
1370
|
+
station,
|
|
1371
|
+
model,
|
|
1372
|
+
issuedAt: isoIfNotNull(issuedAtMs),
|
|
1373
|
+
validAt: validAtIso,
|
|
1374
|
+
forecastHour,
|
|
1375
|
+
tempC: maybeNumber2(pickHourlyValue(h, "temperature_2m", isPrev, i)),
|
|
1376
|
+
dewPointC: maybeNumber2(pickHourlyValue(h, "dew_point_2m", isPrev, i)),
|
|
1377
|
+
apparentTempC: maybeNumber2(pickHourlyValue(h, "apparent_temperature", isPrev, i)),
|
|
1378
|
+
windSpeedMs: maybeNumber2(pickHourlyValue(h, "wind_speed_10m", isPrev, i)),
|
|
1379
|
+
windDirDeg: maybeNumber2(pickHourlyValue(h, "wind_direction_10m", isPrev, i)),
|
|
1380
|
+
windGustsMs: maybeNumber2(pickHourlyValue(h, "wind_gusts_10m", isPrev, i)),
|
|
1381
|
+
precipProbability: popPct === null ? null : popPct / 100,
|
|
1382
|
+
precipitationMm: maybeNumber2(pickHourlyValue(h, "precipitation", isPrev, i)),
|
|
1383
|
+
cloudCoverPct: maybeNumber2(pickHourlyValue(h, "cloud_cover", isPrev, i)),
|
|
1384
|
+
surfacePressureHpa: maybeNumber2(pickHourlyValue(h, "surface_pressure", isPrev, i)),
|
|
1385
|
+
pressureMslHpa: maybeNumber2(pickHourlyValue(h, "pressure_msl", isPrev, i)),
|
|
1386
|
+
shortwaveRadiationWm2: maybeNumber2(pickHourlyValue(h, "shortwave_radiation", isPrev, i)),
|
|
1387
|
+
directRadiationWm2: maybeNumber2(pickHourlyValue(h, "direct_radiation", isPrev, i)),
|
|
1388
|
+
capeJkg: maybeNumber2(pickHourlyValue(h, "cape", isPrev, i)),
|
|
1389
|
+
freezingLevelM: maybeNumber2(pickHourlyValue(h, "freezing_level_height", isPrev, i)),
|
|
1390
|
+
snowDepthM: maybeNumber2(pickHourlyValue(h, "snow_depth", isPrev, i)),
|
|
1391
|
+
visibilityM: maybeNumber2(pickHourlyValue(h, "visibility", isPrev, i)),
|
|
1392
|
+
weatherCode: maybeNumber2(pickHourlyValue(h, "weather_code", isPrev, i)),
|
|
1393
|
+
source,
|
|
1394
|
+
retrievedAt
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
return rows;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// ../core/dist/discovery/index.mjs
|
|
1401
|
+
var STATIONS2 = [
|
|
1402
|
+
{
|
|
1403
|
+
code: "EDDB",
|
|
1404
|
+
country: "DE",
|
|
1405
|
+
ghcnh_id: null,
|
|
1406
|
+
icao: "EDDB",
|
|
1407
|
+
latitude: 52.3667,
|
|
1408
|
+
longitude: 13.5033,
|
|
1409
|
+
name: "Berlin Brandenburg",
|
|
1410
|
+
tz: "Europe/Berlin",
|
|
1411
|
+
venues: [
|
|
1412
|
+
"polymarket"
|
|
1413
|
+
]
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
code: "EDDF",
|
|
1417
|
+
country: "DE",
|
|
1418
|
+
ghcnh_id: null,
|
|
1419
|
+
icao: "EDDF",
|
|
1420
|
+
latitude: 50.0379,
|
|
1421
|
+
longitude: 8.5622,
|
|
1422
|
+
name: "Frankfurt am Main",
|
|
1423
|
+
tz: "Europe/Berlin",
|
|
1424
|
+
venues: [
|
|
1425
|
+
"polymarket"
|
|
1426
|
+
]
|
|
1427
|
+
},
|
|
1428
|
+
{
|
|
1429
|
+
code: "EDDM",
|
|
1430
|
+
country: "DE",
|
|
1431
|
+
ghcnh_id: null,
|
|
1432
|
+
icao: "EDDM",
|
|
1433
|
+
latitude: 48.3538,
|
|
1434
|
+
longitude: 11.7861,
|
|
1435
|
+
name: "Munich Franz Josef Strauss",
|
|
1436
|
+
tz: "Europe/Berlin",
|
|
1437
|
+
venues: [
|
|
1438
|
+
"polymarket"
|
|
1439
|
+
]
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
code: "EFHK",
|
|
1443
|
+
country: "FI",
|
|
1444
|
+
ghcnh_id: null,
|
|
1445
|
+
icao: "EFHK",
|
|
1446
|
+
latitude: 60.3172,
|
|
1447
|
+
longitude: 24.9633,
|
|
1448
|
+
name: "Helsinki-Vantaa",
|
|
1449
|
+
tz: "Europe/Helsinki",
|
|
1450
|
+
venues: [
|
|
1451
|
+
"polymarket"
|
|
1452
|
+
]
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
code: "EGKK",
|
|
1456
|
+
country: "GB",
|
|
1457
|
+
ghcnh_id: null,
|
|
1458
|
+
icao: "EGKK",
|
|
1459
|
+
latitude: 51.1481,
|
|
1460
|
+
longitude: -0.1903,
|
|
1461
|
+
name: "London Gatwick",
|
|
1462
|
+
tz: "Europe/London",
|
|
1463
|
+
venues: [
|
|
1464
|
+
"polymarket"
|
|
1465
|
+
]
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
code: "EGLL",
|
|
1469
|
+
country: "GB",
|
|
1470
|
+
ghcnh_id: null,
|
|
1471
|
+
icao: "EGLL",
|
|
1472
|
+
latitude: 51.4706,
|
|
1473
|
+
longitude: -0.4619,
|
|
1474
|
+
name: "London Heathrow",
|
|
1475
|
+
tz: "Europe/London",
|
|
1476
|
+
venues: [
|
|
1477
|
+
"polymarket"
|
|
1478
|
+
]
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
code: "EHAM",
|
|
1482
|
+
country: "NL",
|
|
1483
|
+
ghcnh_id: null,
|
|
1484
|
+
icao: "EHAM",
|
|
1485
|
+
latitude: 52.3086,
|
|
1486
|
+
longitude: 4.7639,
|
|
1487
|
+
name: "Amsterdam Schiphol",
|
|
1488
|
+
tz: "Europe/Amsterdam",
|
|
1489
|
+
venues: [
|
|
1490
|
+
"polymarket"
|
|
1491
|
+
]
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
code: "EKCH",
|
|
1495
|
+
country: "DK",
|
|
1496
|
+
ghcnh_id: null,
|
|
1497
|
+
icao: "EKCH",
|
|
1498
|
+
latitude: 55.6181,
|
|
1499
|
+
longitude: 12.6561,
|
|
1500
|
+
name: "Copenhagen Kastrup",
|
|
1501
|
+
tz: "Europe/Copenhagen",
|
|
1502
|
+
venues: [
|
|
1503
|
+
"polymarket"
|
|
1504
|
+
]
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
code: "EPWA",
|
|
1508
|
+
country: "PL",
|
|
1509
|
+
ghcnh_id: null,
|
|
1510
|
+
icao: "EPWA",
|
|
1511
|
+
latitude: 52.1657,
|
|
1512
|
+
longitude: 20.9671,
|
|
1513
|
+
name: "Warsaw Chopin",
|
|
1514
|
+
tz: "Europe/Warsaw",
|
|
1515
|
+
venues: [
|
|
1516
|
+
"polymarket"
|
|
1517
|
+
]
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
code: "ESSA",
|
|
1521
|
+
country: "SE",
|
|
1522
|
+
ghcnh_id: null,
|
|
1523
|
+
icao: "ESSA",
|
|
1524
|
+
latitude: 59.6519,
|
|
1525
|
+
longitude: 17.9186,
|
|
1526
|
+
name: "Stockholm Arlanda",
|
|
1527
|
+
tz: "Europe/Stockholm",
|
|
1528
|
+
venues: [
|
|
1529
|
+
"polymarket"
|
|
1530
|
+
]
|
|
1531
|
+
},
|
|
1532
|
+
{
|
|
1533
|
+
code: "ATL",
|
|
1534
|
+
country: "US",
|
|
1535
|
+
ghcnh_id: "USW00013874",
|
|
1536
|
+
icao: "KATL",
|
|
1537
|
+
latitude: 33.6407,
|
|
1538
|
+
longitude: -84.4277,
|
|
1539
|
+
name: "Hartsfield-Jackson Atlanta International",
|
|
1540
|
+
tz: "America/New_York",
|
|
1541
|
+
venues: [
|
|
1542
|
+
"kalshi",
|
|
1543
|
+
"polymarket"
|
|
1544
|
+
]
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
code: "AUS",
|
|
1548
|
+
country: "US",
|
|
1549
|
+
ghcnh_id: "USW00013904",
|
|
1550
|
+
icao: "KAUS",
|
|
1551
|
+
latitude: 30.1975,
|
|
1552
|
+
longitude: -97.6664,
|
|
1553
|
+
name: "Austin-Bergstrom International",
|
|
1554
|
+
tz: "America/Chicago",
|
|
1555
|
+
venues: [
|
|
1556
|
+
"kalshi",
|
|
1557
|
+
"polymarket"
|
|
1558
|
+
]
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
code: "BNA",
|
|
1562
|
+
country: "US",
|
|
1563
|
+
ghcnh_id: "USW00013897",
|
|
1564
|
+
icao: "KBNA",
|
|
1565
|
+
latitude: 36.1245,
|
|
1566
|
+
longitude: -86.6782,
|
|
1567
|
+
name: "Nashville International",
|
|
1568
|
+
tz: "America/Chicago",
|
|
1569
|
+
venues: [
|
|
1570
|
+
"kalshi"
|
|
1571
|
+
]
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
code: "BOS",
|
|
1575
|
+
country: "US",
|
|
1576
|
+
ghcnh_id: "USW00014739",
|
|
1577
|
+
icao: "KBOS",
|
|
1578
|
+
latitude: 42.3656,
|
|
1579
|
+
longitude: -71.0096,
|
|
1580
|
+
name: "Boston Logan International",
|
|
1581
|
+
tz: "America/New_York",
|
|
1582
|
+
venues: [
|
|
1583
|
+
"kalshi",
|
|
1584
|
+
"polymarket"
|
|
1585
|
+
]
|
|
1586
|
+
},
|
|
1587
|
+
{
|
|
1588
|
+
code: "CVG",
|
|
1589
|
+
country: "US",
|
|
1590
|
+
ghcnh_id: "USW00093814",
|
|
1591
|
+
icao: "KCVG",
|
|
1592
|
+
latitude: 39.0488,
|
|
1593
|
+
longitude: -84.6678,
|
|
1594
|
+
name: "Cincinnati/Northern Kentucky International",
|
|
1595
|
+
tz: "America/New_York",
|
|
1596
|
+
venues: [
|
|
1597
|
+
"kalshi"
|
|
1598
|
+
]
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
code: "DCA",
|
|
1602
|
+
country: "US",
|
|
1603
|
+
ghcnh_id: "USW00013743",
|
|
1604
|
+
icao: "KDCA",
|
|
1605
|
+
latitude: 38.8512,
|
|
1606
|
+
longitude: -77.0402,
|
|
1607
|
+
name: "Washington Reagan National",
|
|
1608
|
+
tz: "America/New_York",
|
|
1609
|
+
venues: [
|
|
1610
|
+
"kalshi",
|
|
1611
|
+
"polymarket"
|
|
1612
|
+
]
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
code: "DEN",
|
|
1616
|
+
country: "US",
|
|
1617
|
+
ghcnh_id: "USW00003017",
|
|
1618
|
+
icao: "KDEN",
|
|
1619
|
+
latitude: 39.8561,
|
|
1620
|
+
longitude: -104.6737,
|
|
1621
|
+
name: "Denver International",
|
|
1622
|
+
tz: "America/Denver",
|
|
1623
|
+
venues: [
|
|
1624
|
+
"kalshi",
|
|
1625
|
+
"polymarket"
|
|
1626
|
+
]
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
code: "DFW",
|
|
1630
|
+
country: "US",
|
|
1631
|
+
ghcnh_id: "USW00003927",
|
|
1632
|
+
icao: "KDFW",
|
|
1633
|
+
latitude: 32.8998,
|
|
1634
|
+
longitude: -97.0403,
|
|
1635
|
+
name: "Dallas-Fort Worth International",
|
|
1636
|
+
tz: "America/Chicago",
|
|
1637
|
+
venues: [
|
|
1638
|
+
"kalshi",
|
|
1639
|
+
"polymarket"
|
|
1640
|
+
]
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
code: "DTW",
|
|
1644
|
+
country: "US",
|
|
1645
|
+
ghcnh_id: "USW00094847",
|
|
1646
|
+
icao: "KDTW",
|
|
1647
|
+
latitude: 42.2124,
|
|
1648
|
+
longitude: -83.3534,
|
|
1649
|
+
name: "Detroit Metropolitan Wayne County",
|
|
1650
|
+
tz: "America/New_York",
|
|
1651
|
+
venues: [
|
|
1652
|
+
"kalshi",
|
|
1653
|
+
"polymarket"
|
|
1654
|
+
]
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
code: "HOU",
|
|
1658
|
+
country: "US",
|
|
1659
|
+
ghcnh_id: "USW00012918",
|
|
1660
|
+
icao: "KHOU",
|
|
1661
|
+
latitude: 29.6454,
|
|
1662
|
+
longitude: -95.2789,
|
|
1663
|
+
name: "Houston Hobby",
|
|
1664
|
+
tz: "America/Chicago",
|
|
1665
|
+
venues: []
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
code: "IAH",
|
|
1669
|
+
country: "US",
|
|
1670
|
+
ghcnh_id: "USW00012960",
|
|
1671
|
+
icao: "KIAH",
|
|
1672
|
+
latitude: 29.9844,
|
|
1673
|
+
longitude: -95.3414,
|
|
1674
|
+
name: "Houston George Bush Intercontinental",
|
|
1675
|
+
tz: "America/Chicago",
|
|
1676
|
+
venues: [
|
|
1677
|
+
"kalshi",
|
|
1678
|
+
"polymarket"
|
|
1679
|
+
]
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
code: "LAS",
|
|
1683
|
+
country: "US",
|
|
1684
|
+
ghcnh_id: "USW00023169",
|
|
1685
|
+
icao: "KLAS",
|
|
1686
|
+
latitude: 36.084,
|
|
1687
|
+
longitude: -115.1537,
|
|
1688
|
+
name: "Harry Reid (McCarran) International",
|
|
1689
|
+
tz: "America/Los_Angeles",
|
|
1690
|
+
venues: [
|
|
1691
|
+
"kalshi"
|
|
1692
|
+
]
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
code: "LAX",
|
|
1696
|
+
country: "US",
|
|
1697
|
+
ghcnh_id: "USW00023174",
|
|
1698
|
+
icao: "KLAX",
|
|
1699
|
+
latitude: 33.9425,
|
|
1700
|
+
longitude: -118.4081,
|
|
1701
|
+
name: "Los Angeles International",
|
|
1702
|
+
tz: "America/Los_Angeles",
|
|
1703
|
+
venues: [
|
|
1704
|
+
"kalshi",
|
|
1705
|
+
"polymarket"
|
|
1706
|
+
]
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
code: "MDW",
|
|
1710
|
+
country: "US",
|
|
1711
|
+
ghcnh_id: "USW00014819",
|
|
1712
|
+
icao: "KMDW",
|
|
1713
|
+
latitude: 41.7868,
|
|
1714
|
+
longitude: -87.7522,
|
|
1715
|
+
name: "Chicago Midway International",
|
|
1716
|
+
tz: "America/Chicago",
|
|
1717
|
+
venues: [
|
|
1718
|
+
"kalshi"
|
|
1719
|
+
]
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
code: "MIA",
|
|
1723
|
+
country: "US",
|
|
1724
|
+
ghcnh_id: "USW00012839",
|
|
1725
|
+
icao: "KMIA",
|
|
1726
|
+
latitude: 25.7959,
|
|
1727
|
+
longitude: -80.287,
|
|
1728
|
+
name: "Miami International",
|
|
1729
|
+
tz: "America/New_York",
|
|
1730
|
+
venues: [
|
|
1731
|
+
"kalshi",
|
|
1732
|
+
"polymarket"
|
|
1733
|
+
]
|
|
1734
|
+
},
|
|
1735
|
+
{
|
|
1736
|
+
code: "MSP",
|
|
1737
|
+
country: "US",
|
|
1738
|
+
ghcnh_id: "USW00014922",
|
|
1739
|
+
icao: "KMSP",
|
|
1740
|
+
latitude: 44.8848,
|
|
1741
|
+
longitude: -93.2223,
|
|
1742
|
+
name: "Minneapolis-St Paul International",
|
|
1743
|
+
tz: "America/Chicago",
|
|
1744
|
+
venues: [
|
|
1745
|
+
"kalshi",
|
|
1746
|
+
"polymarket"
|
|
1747
|
+
]
|
|
1748
|
+
},
|
|
1749
|
+
{
|
|
1750
|
+
code: "MSY",
|
|
1751
|
+
country: "US",
|
|
1752
|
+
ghcnh_id: "USW00012916",
|
|
1753
|
+
icao: "KMSY",
|
|
1754
|
+
latitude: 29.9934,
|
|
1755
|
+
longitude: -90.258,
|
|
1756
|
+
name: "New Orleans Louis Armstrong International",
|
|
1757
|
+
tz: "America/Chicago",
|
|
1758
|
+
venues: []
|
|
1759
|
+
},
|
|
1760
|
+
{
|
|
1761
|
+
code: "NYC",
|
|
1762
|
+
country: "US",
|
|
1763
|
+
ghcnh_id: "USW00094728",
|
|
1764
|
+
icao: "KNYC",
|
|
1765
|
+
latitude: 40.7789,
|
|
1766
|
+
longitude: -73.9692,
|
|
1767
|
+
name: "Central Park, New York",
|
|
1768
|
+
tz: "America/New_York",
|
|
1769
|
+
venues: [
|
|
1770
|
+
"kalshi"
|
|
1771
|
+
]
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
code: "OKC",
|
|
1775
|
+
country: "US",
|
|
1776
|
+
ghcnh_id: "USW00013967",
|
|
1777
|
+
icao: "KOKC",
|
|
1778
|
+
latitude: 35.3931,
|
|
1779
|
+
longitude: -97.6007,
|
|
1780
|
+
name: "Oklahoma City Will Rogers World",
|
|
1781
|
+
tz: "America/Chicago",
|
|
1782
|
+
venues: []
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
code: "PHL",
|
|
1786
|
+
country: "US",
|
|
1787
|
+
ghcnh_id: "USW00013739",
|
|
1788
|
+
icao: "KPHL",
|
|
1789
|
+
latitude: 39.8721,
|
|
1790
|
+
longitude: -75.2411,
|
|
1791
|
+
name: "Philadelphia International",
|
|
1792
|
+
tz: "America/New_York",
|
|
1793
|
+
venues: [
|
|
1794
|
+
"kalshi",
|
|
1795
|
+
"polymarket"
|
|
1796
|
+
]
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
code: "PHX",
|
|
1800
|
+
country: "US",
|
|
1801
|
+
ghcnh_id: "USW00023183",
|
|
1802
|
+
icao: "KPHX",
|
|
1803
|
+
latitude: 33.4373,
|
|
1804
|
+
longitude: -112.0078,
|
|
1805
|
+
name: "Phoenix Sky Harbor International",
|
|
1806
|
+
tz: "America/Phoenix",
|
|
1807
|
+
venues: [
|
|
1808
|
+
"kalshi",
|
|
1809
|
+
"polymarket"
|
|
1810
|
+
]
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
code: "SAT",
|
|
1814
|
+
country: "US",
|
|
1815
|
+
ghcnh_id: "USW00012921",
|
|
1816
|
+
icao: "KSAT",
|
|
1817
|
+
latitude: 29.5337,
|
|
1818
|
+
longitude: -98.4698,
|
|
1819
|
+
name: "San Antonio International",
|
|
1820
|
+
tz: "America/Chicago",
|
|
1821
|
+
venues: []
|
|
1822
|
+
},
|
|
1823
|
+
{
|
|
1824
|
+
code: "SEA",
|
|
1825
|
+
country: "US",
|
|
1826
|
+
ghcnh_id: "USW00024233",
|
|
1827
|
+
icao: "KSEA",
|
|
1828
|
+
latitude: 47.4502,
|
|
1829
|
+
longitude: -122.3088,
|
|
1830
|
+
name: "Seattle-Tacoma International",
|
|
1831
|
+
tz: "America/Los_Angeles",
|
|
1832
|
+
venues: [
|
|
1833
|
+
"kalshi",
|
|
1834
|
+
"polymarket"
|
|
1835
|
+
]
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
code: "SFO",
|
|
1839
|
+
country: "US",
|
|
1840
|
+
ghcnh_id: "USW00023234",
|
|
1841
|
+
icao: "KSFO",
|
|
1842
|
+
latitude: 37.6213,
|
|
1843
|
+
longitude: -122.379,
|
|
1844
|
+
name: "San Francisco International",
|
|
1845
|
+
tz: "America/Los_Angeles",
|
|
1846
|
+
venues: [
|
|
1847
|
+
"kalshi",
|
|
1848
|
+
"polymarket"
|
|
1849
|
+
]
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
code: "SLC",
|
|
1853
|
+
country: "US",
|
|
1854
|
+
ghcnh_id: "USW00024127",
|
|
1855
|
+
icao: "KSLC",
|
|
1856
|
+
latitude: 40.7884,
|
|
1857
|
+
longitude: -111.9778,
|
|
1858
|
+
name: "Salt Lake City International",
|
|
1859
|
+
tz: "America/Denver",
|
|
1860
|
+
venues: [
|
|
1861
|
+
"kalshi"
|
|
1862
|
+
]
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
code: "LEBL",
|
|
1866
|
+
country: "ES",
|
|
1867
|
+
ghcnh_id: null,
|
|
1868
|
+
icao: "LEBL",
|
|
1869
|
+
latitude: 41.2974,
|
|
1870
|
+
longitude: 2.0833,
|
|
1871
|
+
name: "Barcelona El Prat",
|
|
1872
|
+
tz: "Europe/Madrid",
|
|
1873
|
+
venues: [
|
|
1874
|
+
"polymarket"
|
|
1875
|
+
]
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
code: "LEMD",
|
|
1879
|
+
country: "ES",
|
|
1880
|
+
ghcnh_id: null,
|
|
1881
|
+
icao: "LEMD",
|
|
1882
|
+
latitude: 40.4719,
|
|
1883
|
+
longitude: -3.5626,
|
|
1884
|
+
name: "Madrid Barajas",
|
|
1885
|
+
tz: "Europe/Madrid",
|
|
1886
|
+
venues: [
|
|
1887
|
+
"polymarket"
|
|
1888
|
+
]
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
code: "LFPB",
|
|
1892
|
+
country: "FR",
|
|
1893
|
+
ghcnh_id: null,
|
|
1894
|
+
icao: "LFPB",
|
|
1895
|
+
latitude: 48.9694,
|
|
1896
|
+
longitude: 2.4414,
|
|
1897
|
+
name: "Paris Le Bourget",
|
|
1898
|
+
tz: "Europe/Paris",
|
|
1899
|
+
venues: [
|
|
1900
|
+
"polymarket"
|
|
1901
|
+
]
|
|
1902
|
+
},
|
|
1903
|
+
{
|
|
1904
|
+
code: "LFPG",
|
|
1905
|
+
country: "FR",
|
|
1906
|
+
ghcnh_id: null,
|
|
1907
|
+
icao: "LFPG",
|
|
1908
|
+
latitude: 49.0097,
|
|
1909
|
+
longitude: 2.5479,
|
|
1910
|
+
name: "Paris Charles de Gaulle",
|
|
1911
|
+
tz: "Europe/Paris",
|
|
1912
|
+
venues: [
|
|
1913
|
+
"polymarket"
|
|
1914
|
+
]
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
code: "LFPO",
|
|
1918
|
+
country: "FR",
|
|
1919
|
+
ghcnh_id: null,
|
|
1920
|
+
icao: "LFPO",
|
|
1921
|
+
latitude: 48.7233,
|
|
1922
|
+
longitude: 2.3794,
|
|
1923
|
+
name: "Paris Orly",
|
|
1924
|
+
tz: "Europe/Paris",
|
|
1925
|
+
venues: [
|
|
1926
|
+
"polymarket"
|
|
1927
|
+
]
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
code: "LIMC",
|
|
1931
|
+
country: "IT",
|
|
1932
|
+
ghcnh_id: null,
|
|
1933
|
+
icao: "LIMC",
|
|
1934
|
+
latitude: 45.6306,
|
|
1935
|
+
longitude: 8.7281,
|
|
1936
|
+
name: "Milan Malpensa",
|
|
1937
|
+
tz: "Europe/Rome",
|
|
1938
|
+
venues: [
|
|
1939
|
+
"polymarket"
|
|
1940
|
+
]
|
|
1941
|
+
},
|
|
1942
|
+
{
|
|
1943
|
+
code: "LIRF",
|
|
1944
|
+
country: "IT",
|
|
1945
|
+
ghcnh_id: null,
|
|
1946
|
+
icao: "LIRF",
|
|
1947
|
+
latitude: 41.8003,
|
|
1948
|
+
longitude: 12.2389,
|
|
1949
|
+
name: "Rome Fiumicino",
|
|
1950
|
+
tz: "Europe/Rome",
|
|
1951
|
+
venues: [
|
|
1952
|
+
"polymarket"
|
|
1953
|
+
]
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
code: "LOWW",
|
|
1957
|
+
country: "AT",
|
|
1958
|
+
ghcnh_id: null,
|
|
1959
|
+
icao: "LOWW",
|
|
1960
|
+
latitude: 48.1103,
|
|
1961
|
+
longitude: 16.5697,
|
|
1962
|
+
name: "Vienna International",
|
|
1963
|
+
tz: "Europe/Vienna",
|
|
1964
|
+
venues: [
|
|
1965
|
+
"polymarket"
|
|
1966
|
+
]
|
|
1967
|
+
},
|
|
1968
|
+
{
|
|
1969
|
+
code: "LSZH",
|
|
1970
|
+
country: "CH",
|
|
1971
|
+
ghcnh_id: null,
|
|
1972
|
+
icao: "LSZH",
|
|
1973
|
+
latitude: 47.4647,
|
|
1974
|
+
longitude: 8.5492,
|
|
1975
|
+
name: "Zurich",
|
|
1976
|
+
tz: "Europe/Zurich",
|
|
1977
|
+
venues: [
|
|
1978
|
+
"polymarket"
|
|
1979
|
+
]
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
code: "NZAA",
|
|
1983
|
+
country: "NZ",
|
|
1984
|
+
ghcnh_id: null,
|
|
1985
|
+
icao: "NZAA",
|
|
1986
|
+
latitude: -37.0081,
|
|
1987
|
+
longitude: 174.7917,
|
|
1988
|
+
name: "Auckland",
|
|
1989
|
+
tz: "Pacific/Auckland",
|
|
1990
|
+
venues: [
|
|
1991
|
+
"polymarket"
|
|
1992
|
+
]
|
|
1993
|
+
},
|
|
1994
|
+
{
|
|
1995
|
+
code: "NZWN",
|
|
1996
|
+
country: "NZ",
|
|
1997
|
+
ghcnh_id: null,
|
|
1998
|
+
icao: "NZWN",
|
|
1999
|
+
latitude: -41.3272,
|
|
2000
|
+
longitude: 174.8053,
|
|
2001
|
+
name: "Wellington",
|
|
2002
|
+
tz: "Pacific/Auckland",
|
|
2003
|
+
venues: [
|
|
2004
|
+
"polymarket"
|
|
2005
|
+
]
|
|
2006
|
+
},
|
|
2007
|
+
{
|
|
2008
|
+
code: "OERK",
|
|
2009
|
+
country: "SA",
|
|
2010
|
+
ghcnh_id: null,
|
|
2011
|
+
icao: "OERK",
|
|
2012
|
+
latitude: 24.9576,
|
|
2013
|
+
longitude: 46.6988,
|
|
2014
|
+
name: "Riyadh King Khalid International",
|
|
2015
|
+
tz: "Asia/Riyadh",
|
|
2016
|
+
venues: [
|
|
2017
|
+
"polymarket"
|
|
2018
|
+
]
|
|
2019
|
+
},
|
|
2020
|
+
{
|
|
2021
|
+
code: "OMDB",
|
|
2022
|
+
country: "AE",
|
|
2023
|
+
ghcnh_id: null,
|
|
2024
|
+
icao: "OMDB",
|
|
2025
|
+
latitude: 25.2532,
|
|
2026
|
+
longitude: 55.3657,
|
|
2027
|
+
name: "Dubai International",
|
|
2028
|
+
tz: "Asia/Dubai",
|
|
2029
|
+
venues: [
|
|
2030
|
+
"polymarket"
|
|
2031
|
+
]
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
code: "OTHH",
|
|
2035
|
+
country: "QA",
|
|
2036
|
+
ghcnh_id: null,
|
|
2037
|
+
icao: "OTHH",
|
|
2038
|
+
latitude: 25.2731,
|
|
2039
|
+
longitude: 51.608,
|
|
2040
|
+
name: "Doha Hamad International",
|
|
2041
|
+
tz: "Asia/Qatar",
|
|
2042
|
+
venues: [
|
|
2043
|
+
"polymarket"
|
|
2044
|
+
]
|
|
2045
|
+
},
|
|
2046
|
+
{
|
|
2047
|
+
code: "RCTP",
|
|
2048
|
+
country: "TW",
|
|
2049
|
+
ghcnh_id: null,
|
|
2050
|
+
icao: "RCTP",
|
|
2051
|
+
latitude: 25.0777,
|
|
2052
|
+
longitude: 121.2328,
|
|
2053
|
+
name: "Taipei Taoyuan",
|
|
2054
|
+
tz: "Asia/Taipei",
|
|
2055
|
+
venues: [
|
|
2056
|
+
"polymarket"
|
|
2057
|
+
]
|
|
2058
|
+
},
|
|
2059
|
+
{
|
|
2060
|
+
code: "RJAA",
|
|
2061
|
+
country: "JP",
|
|
2062
|
+
ghcnh_id: null,
|
|
2063
|
+
icao: "RJAA",
|
|
2064
|
+
latitude: 35.7647,
|
|
2065
|
+
longitude: 140.3864,
|
|
2066
|
+
name: "Tokyo Narita",
|
|
2067
|
+
tz: "Asia/Tokyo",
|
|
2068
|
+
venues: [
|
|
2069
|
+
"polymarket"
|
|
2070
|
+
]
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
code: "RJTT",
|
|
2074
|
+
country: "JP",
|
|
2075
|
+
ghcnh_id: null,
|
|
2076
|
+
icao: "RJTT",
|
|
2077
|
+
latitude: 35.5522,
|
|
2078
|
+
longitude: 139.78,
|
|
2079
|
+
name: "Tokyo Haneda",
|
|
2080
|
+
tz: "Asia/Tokyo",
|
|
2081
|
+
venues: [
|
|
2082
|
+
"polymarket"
|
|
2083
|
+
]
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
code: "RKSI",
|
|
2087
|
+
country: "KR",
|
|
2088
|
+
ghcnh_id: null,
|
|
2089
|
+
icao: "RKSI",
|
|
2090
|
+
latitude: 37.4691,
|
|
2091
|
+
longitude: 126.4505,
|
|
2092
|
+
name: "Seoul Incheon",
|
|
2093
|
+
tz: "Asia/Seoul",
|
|
2094
|
+
venues: [
|
|
2095
|
+
"polymarket"
|
|
2096
|
+
]
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
code: "SAEZ",
|
|
2100
|
+
country: "AR",
|
|
2101
|
+
ghcnh_id: null,
|
|
2102
|
+
icao: "SAEZ",
|
|
2103
|
+
latitude: -34.8222,
|
|
2104
|
+
longitude: -58.5358,
|
|
2105
|
+
name: "Buenos Aires Ezeiza",
|
|
2106
|
+
tz: "America/Argentina/Buenos_Aires",
|
|
2107
|
+
venues: [
|
|
2108
|
+
"polymarket"
|
|
2109
|
+
]
|
|
2110
|
+
},
|
|
2111
|
+
{
|
|
2112
|
+
code: "SBGR",
|
|
2113
|
+
country: "BR",
|
|
2114
|
+
ghcnh_id: null,
|
|
2115
|
+
icao: "SBGR",
|
|
2116
|
+
latitude: -23.4356,
|
|
2117
|
+
longitude: -46.4731,
|
|
2118
|
+
name: "S\xE3o Paulo Guarulhos",
|
|
2119
|
+
tz: "America/Sao_Paulo",
|
|
2120
|
+
venues: [
|
|
2121
|
+
"polymarket"
|
|
2122
|
+
]
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
code: "UUEE",
|
|
2126
|
+
country: "RU",
|
|
2127
|
+
ghcnh_id: null,
|
|
2128
|
+
icao: "UUEE",
|
|
2129
|
+
latitude: 55.9728,
|
|
2130
|
+
longitude: 37.4147,
|
|
2131
|
+
name: "Moscow Sheremetyevo",
|
|
2132
|
+
tz: "Europe/Moscow",
|
|
2133
|
+
venues: [
|
|
2134
|
+
"polymarket"
|
|
2135
|
+
]
|
|
2136
|
+
},
|
|
2137
|
+
{
|
|
2138
|
+
code: "VABB",
|
|
2139
|
+
country: "IN",
|
|
2140
|
+
ghcnh_id: null,
|
|
2141
|
+
icao: "VABB",
|
|
2142
|
+
latitude: 19.0887,
|
|
2143
|
+
longitude: 72.8679,
|
|
2144
|
+
name: "Mumbai Chhatrapati Shivaji",
|
|
2145
|
+
tz: "Asia/Kolkata",
|
|
2146
|
+
venues: [
|
|
2147
|
+
"polymarket"
|
|
2148
|
+
]
|
|
2149
|
+
},
|
|
2150
|
+
{
|
|
2151
|
+
code: "VHHH",
|
|
2152
|
+
country: "HK",
|
|
2153
|
+
ghcnh_id: null,
|
|
2154
|
+
icao: "VHHH",
|
|
2155
|
+
latitude: 22.308,
|
|
2156
|
+
longitude: 113.9185,
|
|
2157
|
+
name: "Hong Kong International",
|
|
2158
|
+
tz: "Asia/Hong_Kong",
|
|
2159
|
+
venues: [
|
|
2160
|
+
"polymarket"
|
|
2161
|
+
]
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
code: "VIDP",
|
|
2165
|
+
country: "IN",
|
|
2166
|
+
ghcnh_id: null,
|
|
2167
|
+
icao: "VIDP",
|
|
2168
|
+
latitude: 28.5562,
|
|
2169
|
+
longitude: 77.1,
|
|
2170
|
+
name: "Delhi Indira Gandhi",
|
|
2171
|
+
tz: "Asia/Kolkata",
|
|
2172
|
+
venues: [
|
|
2173
|
+
"polymarket"
|
|
2174
|
+
]
|
|
2175
|
+
},
|
|
2176
|
+
{
|
|
2177
|
+
code: "VTBS",
|
|
2178
|
+
country: "TH",
|
|
2179
|
+
ghcnh_id: null,
|
|
2180
|
+
icao: "VTBS",
|
|
2181
|
+
latitude: 13.69,
|
|
2182
|
+
longitude: 100.7501,
|
|
2183
|
+
name: "Bangkok Suvarnabhumi",
|
|
2184
|
+
tz: "Asia/Bangkok",
|
|
2185
|
+
venues: [
|
|
2186
|
+
"polymarket"
|
|
2187
|
+
]
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
code: "WSSS",
|
|
2191
|
+
country: "SG",
|
|
2192
|
+
ghcnh_id: null,
|
|
2193
|
+
icao: "WSSS",
|
|
2194
|
+
latitude: 1.3644,
|
|
2195
|
+
longitude: 103.9915,
|
|
2196
|
+
name: "Singapore Changi",
|
|
2197
|
+
tz: "Asia/Singapore",
|
|
2198
|
+
venues: [
|
|
2199
|
+
"polymarket"
|
|
2200
|
+
]
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
code: "YBBN",
|
|
2204
|
+
country: "AU",
|
|
2205
|
+
ghcnh_id: null,
|
|
2206
|
+
icao: "YBBN",
|
|
2207
|
+
latitude: -27.3842,
|
|
2208
|
+
longitude: 153.1175,
|
|
2209
|
+
name: "Brisbane",
|
|
2210
|
+
tz: "Australia/Brisbane",
|
|
2211
|
+
venues: [
|
|
2212
|
+
"polymarket"
|
|
2213
|
+
]
|
|
2214
|
+
},
|
|
2215
|
+
{
|
|
2216
|
+
code: "YMML",
|
|
2217
|
+
country: "AU",
|
|
2218
|
+
ghcnh_id: null,
|
|
2219
|
+
icao: "YMML",
|
|
2220
|
+
latitude: -37.6733,
|
|
2221
|
+
longitude: 144.8433,
|
|
2222
|
+
name: "Melbourne Tullamarine",
|
|
2223
|
+
tz: "Australia/Melbourne",
|
|
2224
|
+
venues: [
|
|
2225
|
+
"polymarket"
|
|
2226
|
+
]
|
|
2227
|
+
},
|
|
2228
|
+
{
|
|
2229
|
+
code: "YSSY",
|
|
2230
|
+
country: "AU",
|
|
2231
|
+
ghcnh_id: null,
|
|
2232
|
+
icao: "YSSY",
|
|
2233
|
+
latitude: -33.9461,
|
|
2234
|
+
longitude: 151.1772,
|
|
2235
|
+
name: "Sydney Kingsford Smith",
|
|
2236
|
+
tz: "Australia/Sydney",
|
|
2237
|
+
venues: [
|
|
2238
|
+
"polymarket"
|
|
2239
|
+
]
|
|
2240
|
+
},
|
|
2241
|
+
{
|
|
2242
|
+
code: "ZBAA",
|
|
2243
|
+
country: "CN",
|
|
2244
|
+
ghcnh_id: null,
|
|
2245
|
+
icao: "ZBAA",
|
|
2246
|
+
latitude: 40.0801,
|
|
2247
|
+
longitude: 116.5846,
|
|
2248
|
+
name: "Beijing Capital",
|
|
2249
|
+
tz: "Asia/Shanghai",
|
|
2250
|
+
venues: [
|
|
2251
|
+
"polymarket"
|
|
2252
|
+
]
|
|
2253
|
+
},
|
|
2254
|
+
{
|
|
2255
|
+
code: "ZSPD",
|
|
2256
|
+
country: "CN",
|
|
2257
|
+
ghcnh_id: null,
|
|
2258
|
+
icao: "ZSPD",
|
|
2259
|
+
latitude: 31.1443,
|
|
2260
|
+
longitude: 121.8083,
|
|
2261
|
+
name: "Shanghai Pudong",
|
|
2262
|
+
tz: "Asia/Shanghai",
|
|
2263
|
+
venues: [
|
|
2264
|
+
"polymarket"
|
|
2265
|
+
]
|
|
2266
|
+
}
|
|
2267
|
+
];
|
|
2268
|
+
var STATION_BY_CODE2 = /* @__PURE__ */ new Map([
|
|
2269
|
+
["ATL", STATIONS2[10]],
|
|
2270
|
+
["AUS", STATIONS2[11]],
|
|
2271
|
+
["BNA", STATIONS2[12]],
|
|
2272
|
+
["BOS", STATIONS2[13]],
|
|
2273
|
+
["CVG", STATIONS2[14]],
|
|
2274
|
+
["DCA", STATIONS2[15]],
|
|
2275
|
+
["DEN", STATIONS2[16]],
|
|
2276
|
+
["DFW", STATIONS2[17]],
|
|
2277
|
+
["DTW", STATIONS2[18]],
|
|
2278
|
+
["EDDB", STATIONS2[0]],
|
|
2279
|
+
["EDDF", STATIONS2[1]],
|
|
2280
|
+
["EDDM", STATIONS2[2]],
|
|
2281
|
+
["EFHK", STATIONS2[3]],
|
|
2282
|
+
["EGKK", STATIONS2[4]],
|
|
2283
|
+
["EGLL", STATIONS2[5]],
|
|
2284
|
+
["EHAM", STATIONS2[6]],
|
|
2285
|
+
["EKCH", STATIONS2[7]],
|
|
2286
|
+
["EPWA", STATIONS2[8]],
|
|
2287
|
+
["ESSA", STATIONS2[9]],
|
|
2288
|
+
["HOU", STATIONS2[19]],
|
|
2289
|
+
["IAH", STATIONS2[20]],
|
|
2290
|
+
["LAS", STATIONS2[21]],
|
|
2291
|
+
["LAX", STATIONS2[22]],
|
|
2292
|
+
["LEBL", STATIONS2[35]],
|
|
2293
|
+
["LEMD", STATIONS2[36]],
|
|
2294
|
+
["LFPB", STATIONS2[37]],
|
|
2295
|
+
["LFPG", STATIONS2[38]],
|
|
2296
|
+
["LFPO", STATIONS2[39]],
|
|
2297
|
+
["LIMC", STATIONS2[40]],
|
|
2298
|
+
["LIRF", STATIONS2[41]],
|
|
2299
|
+
["LOWW", STATIONS2[42]],
|
|
2300
|
+
["LSZH", STATIONS2[43]],
|
|
2301
|
+
["MDW", STATIONS2[23]],
|
|
2302
|
+
["MIA", STATIONS2[24]],
|
|
2303
|
+
["MSP", STATIONS2[25]],
|
|
2304
|
+
["MSY", STATIONS2[26]],
|
|
2305
|
+
["NYC", STATIONS2[27]],
|
|
2306
|
+
["NZAA", STATIONS2[44]],
|
|
2307
|
+
["NZWN", STATIONS2[45]],
|
|
2308
|
+
["OERK", STATIONS2[46]],
|
|
2309
|
+
["OKC", STATIONS2[28]],
|
|
2310
|
+
["OMDB", STATIONS2[47]],
|
|
2311
|
+
["OTHH", STATIONS2[48]],
|
|
2312
|
+
["PHL", STATIONS2[29]],
|
|
2313
|
+
["PHX", STATIONS2[30]],
|
|
2314
|
+
["RCTP", STATIONS2[49]],
|
|
2315
|
+
["RJAA", STATIONS2[50]],
|
|
2316
|
+
["RJTT", STATIONS2[51]],
|
|
2317
|
+
["RKSI", STATIONS2[52]],
|
|
2318
|
+
["SAEZ", STATIONS2[53]],
|
|
2319
|
+
["SAT", STATIONS2[31]],
|
|
2320
|
+
["SBGR", STATIONS2[54]],
|
|
2321
|
+
["SEA", STATIONS2[32]],
|
|
2322
|
+
["SFO", STATIONS2[33]],
|
|
2323
|
+
["SLC", STATIONS2[34]],
|
|
2324
|
+
["UUEE", STATIONS2[55]],
|
|
2325
|
+
["VABB", STATIONS2[56]],
|
|
2326
|
+
["VHHH", STATIONS2[57]],
|
|
2327
|
+
["VIDP", STATIONS2[58]],
|
|
2328
|
+
["VTBS", STATIONS2[59]],
|
|
2329
|
+
["WSSS", STATIONS2[60]],
|
|
2330
|
+
["YBBN", STATIONS2[61]],
|
|
2331
|
+
["YMML", STATIONS2[62]],
|
|
2332
|
+
["YSSY", STATIONS2[63]],
|
|
2333
|
+
["ZBAA", STATIONS2[64]],
|
|
2334
|
+
["ZSPD", STATIONS2[65]]
|
|
2335
|
+
]);
|
|
2336
|
+
var STATION_BY_ICAO2 = /* @__PURE__ */ new Map([
|
|
2337
|
+
["EDDB", STATIONS2[0]],
|
|
2338
|
+
["EDDF", STATIONS2[1]],
|
|
2339
|
+
["EDDM", STATIONS2[2]],
|
|
2340
|
+
["EFHK", STATIONS2[3]],
|
|
2341
|
+
["EGKK", STATIONS2[4]],
|
|
2342
|
+
["EGLL", STATIONS2[5]],
|
|
2343
|
+
["EHAM", STATIONS2[6]],
|
|
2344
|
+
["EKCH", STATIONS2[7]],
|
|
2345
|
+
["EPWA", STATIONS2[8]],
|
|
2346
|
+
["ESSA", STATIONS2[9]],
|
|
2347
|
+
["KATL", STATIONS2[10]],
|
|
2348
|
+
["KAUS", STATIONS2[11]],
|
|
2349
|
+
["KBNA", STATIONS2[12]],
|
|
2350
|
+
["KBOS", STATIONS2[13]],
|
|
2351
|
+
["KCVG", STATIONS2[14]],
|
|
2352
|
+
["KDCA", STATIONS2[15]],
|
|
2353
|
+
["KDEN", STATIONS2[16]],
|
|
2354
|
+
["KDFW", STATIONS2[17]],
|
|
2355
|
+
["KDTW", STATIONS2[18]],
|
|
2356
|
+
["KHOU", STATIONS2[19]],
|
|
2357
|
+
["KIAH", STATIONS2[20]],
|
|
2358
|
+
["KLAS", STATIONS2[21]],
|
|
2359
|
+
["KLAX", STATIONS2[22]],
|
|
2360
|
+
["KMDW", STATIONS2[23]],
|
|
2361
|
+
["KMIA", STATIONS2[24]],
|
|
2362
|
+
["KMSP", STATIONS2[25]],
|
|
2363
|
+
["KMSY", STATIONS2[26]],
|
|
2364
|
+
["KNYC", STATIONS2[27]],
|
|
2365
|
+
["KOKC", STATIONS2[28]],
|
|
2366
|
+
["KPHL", STATIONS2[29]],
|
|
2367
|
+
["KPHX", STATIONS2[30]],
|
|
2368
|
+
["KSAT", STATIONS2[31]],
|
|
2369
|
+
["KSEA", STATIONS2[32]],
|
|
2370
|
+
["KSFO", STATIONS2[33]],
|
|
2371
|
+
["KSLC", STATIONS2[34]],
|
|
2372
|
+
["LEBL", STATIONS2[35]],
|
|
2373
|
+
["LEMD", STATIONS2[36]],
|
|
2374
|
+
["LFPB", STATIONS2[37]],
|
|
2375
|
+
["LFPG", STATIONS2[38]],
|
|
2376
|
+
["LFPO", STATIONS2[39]],
|
|
2377
|
+
["LIMC", STATIONS2[40]],
|
|
2378
|
+
["LIRF", STATIONS2[41]],
|
|
2379
|
+
["LOWW", STATIONS2[42]],
|
|
2380
|
+
["LSZH", STATIONS2[43]],
|
|
2381
|
+
["NZAA", STATIONS2[44]],
|
|
2382
|
+
["NZWN", STATIONS2[45]],
|
|
2383
|
+
["OERK", STATIONS2[46]],
|
|
2384
|
+
["OMDB", STATIONS2[47]],
|
|
2385
|
+
["OTHH", STATIONS2[48]],
|
|
2386
|
+
["RCTP", STATIONS2[49]],
|
|
2387
|
+
["RJAA", STATIONS2[50]],
|
|
2388
|
+
["RJTT", STATIONS2[51]],
|
|
2389
|
+
["RKSI", STATIONS2[52]],
|
|
2390
|
+
["SAEZ", STATIONS2[53]],
|
|
2391
|
+
["SBGR", STATIONS2[54]],
|
|
2392
|
+
["UUEE", STATIONS2[55]],
|
|
2393
|
+
["VABB", STATIONS2[56]],
|
|
2394
|
+
["VHHH", STATIONS2[57]],
|
|
2395
|
+
["VIDP", STATIONS2[58]],
|
|
2396
|
+
["VTBS", STATIONS2[59]],
|
|
2397
|
+
["WSSS", STATIONS2[60]],
|
|
2398
|
+
["YBBN", STATIONS2[61]],
|
|
2399
|
+
["YMML", STATIONS2[62]],
|
|
2400
|
+
["YSSY", STATIONS2[63]],
|
|
2401
|
+
["ZBAA", STATIONS2[64]],
|
|
2402
|
+
["ZSPD", STATIONS2[65]]
|
|
2403
|
+
]);
|
|
2404
|
+
var LOW_COVERAGE_THRESHOLD = 12;
|
|
2405
|
+
var PARTS_CACHE = /* @__PURE__ */ new Map();
|
|
2406
|
+
function getDateFormatter(tz) {
|
|
2407
|
+
let f = PARTS_CACHE.get(tz);
|
|
2408
|
+
if (f === void 0) {
|
|
2409
|
+
f = new Intl.DateTimeFormat("en-US", {
|
|
2410
|
+
timeZone: tz,
|
|
2411
|
+
year: "numeric",
|
|
2412
|
+
month: "2-digit",
|
|
2413
|
+
day: "2-digit"
|
|
2414
|
+
});
|
|
2415
|
+
PARTS_CACHE.set(tz, f);
|
|
2416
|
+
}
|
|
2417
|
+
return f;
|
|
2418
|
+
}
|
|
2419
|
+
function localDateFor(instant, tz) {
|
|
2420
|
+
const parts = getDateFormatter(tz).formatToParts(instant);
|
|
2421
|
+
let y = "";
|
|
2422
|
+
let m = "";
|
|
2423
|
+
let d = "";
|
|
2424
|
+
for (const p of parts) {
|
|
2425
|
+
if (p.type === "year") y = p.value;
|
|
2426
|
+
else if (p.type === "month") m = p.value;
|
|
2427
|
+
else if (p.type === "day") d = p.value;
|
|
2428
|
+
}
|
|
2429
|
+
return `${y}-${m}-${d}`;
|
|
2430
|
+
}
|
|
2431
|
+
function parseInstant(observed) {
|
|
2432
|
+
if (observed === void 0 || observed === null || observed.length === 0) {
|
|
2433
|
+
return null;
|
|
2434
|
+
}
|
|
2435
|
+
const ms = Date.parse(observed);
|
|
2436
|
+
if (Number.isNaN(ms)) return null;
|
|
2437
|
+
return new Date(ms);
|
|
2438
|
+
}
|
|
2439
|
+
function roundHalfUp(value, places) {
|
|
2440
|
+
if (!Number.isFinite(value)) return value;
|
|
2441
|
+
const scale = 10 ** places;
|
|
2442
|
+
const sign = value < 0 ? -1 : 1;
|
|
2443
|
+
const abs = Math.abs(value);
|
|
2444
|
+
const rounded = Math.floor(abs * scale + 0.5 + abs * 1e-12) / scale;
|
|
2445
|
+
return sign * rounded;
|
|
2446
|
+
}
|
|
2447
|
+
function cToF(c) {
|
|
2448
|
+
return c * 1.8 + 32;
|
|
2449
|
+
}
|
|
2450
|
+
function internationalDailyExtremes(rows, opts) {
|
|
2451
|
+
const tz = opts.stationTz;
|
|
2452
|
+
if (typeof tz !== "string" || tz.length === 0) {
|
|
2453
|
+
throw new RangeError("internationalDailyExtremes: stationTz is required (non-empty string)");
|
|
2454
|
+
}
|
|
2455
|
+
const precision = opts.precision ?? 0;
|
|
2456
|
+
const minObs = opts.minObs ?? LOW_COVERAGE_THRESHOLD;
|
|
2457
|
+
try {
|
|
2458
|
+
getDateFormatter(tz);
|
|
2459
|
+
} catch (e) {
|
|
2460
|
+
throw new RangeError(
|
|
2461
|
+
`internationalDailyExtremes: invalid stationTz ${JSON.stringify(tz)}: ${e.message}`
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2464
|
+
const byLocalDate = /* @__PURE__ */ new Map();
|
|
2465
|
+
for (const row of rows) {
|
|
2466
|
+
const instant = parseInstant(row.observed_at);
|
|
2467
|
+
if (instant === null) continue;
|
|
2468
|
+
const localDate = localDateFor(instant, tz);
|
|
2469
|
+
let bucket = byLocalDate.get(localDate);
|
|
2470
|
+
if (bucket === void 0) {
|
|
2471
|
+
bucket = { temps: [], precipMm: 0 };
|
|
2472
|
+
byLocalDate.set(localDate, bucket);
|
|
2473
|
+
}
|
|
2474
|
+
const t = row.temp_c;
|
|
2475
|
+
if (typeof t === "number" && Number.isFinite(t)) {
|
|
2476
|
+
bucket.temps.push({ value: t, source: row.source ?? null });
|
|
2477
|
+
}
|
|
2478
|
+
const p = row.precip_mm_1h;
|
|
2479
|
+
if (typeof p === "number" && Number.isFinite(p)) {
|
|
2480
|
+
bucket.precipMm += p;
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
const out = [];
|
|
2484
|
+
const sortedDates = [...byLocalDate.keys()].sort();
|
|
2485
|
+
for (const localDate of sortedDates) {
|
|
2486
|
+
const bucket = byLocalDate.get(localDate);
|
|
2487
|
+
if (bucket === void 0) continue;
|
|
2488
|
+
const nObs = bucket.temps.length;
|
|
2489
|
+
let tempMinC = null;
|
|
2490
|
+
let tempMaxC = null;
|
|
2491
|
+
let tempMeanC = null;
|
|
2492
|
+
let sourceTmin = null;
|
|
2493
|
+
let sourceTmax = null;
|
|
2494
|
+
if (nObs > 0 && nObs >= minObs) {
|
|
2495
|
+
let minIdx = 0;
|
|
2496
|
+
let maxIdx = 0;
|
|
2497
|
+
let sum = 0;
|
|
2498
|
+
for (let i = 0; i < bucket.temps.length; i += 1) {
|
|
2499
|
+
const v = bucket.temps[i];
|
|
2500
|
+
sum += v.value;
|
|
2501
|
+
const minRow2 = bucket.temps[minIdx];
|
|
2502
|
+
const maxRow2 = bucket.temps[maxIdx];
|
|
2503
|
+
if (v.value < minRow2.value) minIdx = i;
|
|
2504
|
+
if (v.value > maxRow2.value) maxIdx = i;
|
|
2505
|
+
}
|
|
2506
|
+
const mean = sum / nObs;
|
|
2507
|
+
const minRow = bucket.temps[minIdx];
|
|
2508
|
+
const maxRow = bucket.temps[maxIdx];
|
|
2509
|
+
tempMinC = roundHalfUp(minRow.value, precision);
|
|
2510
|
+
tempMaxC = roundHalfUp(maxRow.value, precision);
|
|
2511
|
+
tempMeanC = roundHalfUp(mean, precision);
|
|
2512
|
+
sourceTmin = minRow.source;
|
|
2513
|
+
sourceTmax = maxRow.source;
|
|
2514
|
+
}
|
|
2515
|
+
out.push(
|
|
2516
|
+
Object.freeze({
|
|
2517
|
+
localDate,
|
|
2518
|
+
nObs,
|
|
2519
|
+
tempMinC,
|
|
2520
|
+
tempMaxC,
|
|
2521
|
+
tempMeanC,
|
|
2522
|
+
tempMinF: tempMinC === null ? null : roundHalfUp(cToF(tempMinC), precision),
|
|
2523
|
+
tempMaxF: tempMaxC === null ? null : roundHalfUp(cToF(tempMaxC), precision),
|
|
2524
|
+
precipMm: roundHalfUp(bucket.precipMm, 4),
|
|
2525
|
+
sourceTmin,
|
|
2526
|
+
sourceTmax
|
|
2527
|
+
})
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2530
|
+
return out;
|
|
2531
|
+
}
|
|
2532
|
+
var BUILT_IN_SCHEMAS = Object.freeze([
|
|
2533
|
+
{
|
|
2534
|
+
id: "schema.observation.v1",
|
|
2535
|
+
title: "schema.observation.v1",
|
|
2536
|
+
columnCount: 20,
|
|
2537
|
+
columns: [
|
|
2538
|
+
{ name: "dew_point_c", description: "units: celsius \u2014 bounded", nullable: true },
|
|
2539
|
+
{ name: "event_time", description: "observation valid time", nullable: false },
|
|
2540
|
+
{
|
|
2541
|
+
name: "metar_raw",
|
|
2542
|
+
description: "raw METAR text if source has it; null for AWC JSON (structured-only)",
|
|
2543
|
+
nullable: true
|
|
2544
|
+
},
|
|
2545
|
+
{
|
|
2546
|
+
name: "observation_type",
|
|
2547
|
+
description: "METAR | SPECI; defaults METAR when source can't distinguish (e.g. AWC JSON)",
|
|
2548
|
+
nullable: false
|
|
2549
|
+
},
|
|
2550
|
+
{
|
|
2551
|
+
name: "precip_mm_1h",
|
|
2552
|
+
description: "units: mm \u2014 hourly precip (METAR p01i, converted from inches)",
|
|
2553
|
+
nullable: true
|
|
2554
|
+
},
|
|
2555
|
+
{
|
|
2556
|
+
name: "sky_base_1_m",
|
|
2557
|
+
description: "units: meters \u2014 first cloud layer base height (converted from feet)",
|
|
2558
|
+
nullable: true
|
|
2559
|
+
},
|
|
2560
|
+
{ name: "sky_base_2_m", description: "units: meters", nullable: true },
|
|
2561
|
+
{ name: "sky_base_3_m", description: "units: meters", nullable: true },
|
|
2562
|
+
{ name: "sky_base_4_m", description: "units: meters", nullable: true },
|
|
2563
|
+
{ name: "sky_cover_1", description: "first cloud layer cover code", nullable: true },
|
|
2564
|
+
{ name: "sky_cover_2", description: "second layer; null if not present", nullable: true },
|
|
2565
|
+
{ name: "sky_cover_3", description: "third layer; null if not present", nullable: true },
|
|
2566
|
+
{ name: "sky_cover_4", description: "fourth layer; null if not present", nullable: true },
|
|
2567
|
+
{
|
|
2568
|
+
name: "slp_hpa",
|
|
2569
|
+
description: "units: hPa \u2014 sea-level pressure (canonical aviation unit, not converted across modes)",
|
|
2570
|
+
nullable: true
|
|
2571
|
+
},
|
|
2572
|
+
{ name: "station", description: "ICAO/ASOS station ID (e.g. KORD)", nullable: false },
|
|
2573
|
+
{
|
|
2574
|
+
name: "temp_c",
|
|
2575
|
+
description: "units: celsius \u2014 bounded TEMP_MIN_C..TEMP_MAX_C",
|
|
2576
|
+
nullable: true
|
|
2577
|
+
},
|
|
2578
|
+
{
|
|
2579
|
+
name: "visibility_m",
|
|
2580
|
+
description: "units: meters \u2014 converted from statute miles",
|
|
2581
|
+
nullable: true
|
|
2582
|
+
},
|
|
2583
|
+
{
|
|
2584
|
+
name: "wind_dir_deg",
|
|
2585
|
+
description: "units: degrees \u2014 0-360, bounded",
|
|
2586
|
+
nullable: true
|
|
2587
|
+
},
|
|
2588
|
+
{ name: "wind_gust_ms", description: "units: m/s \u2014 converted from kt", nullable: true },
|
|
2589
|
+
{ name: "wind_speed_ms", description: "units: m/s \u2014 converted from kt", nullable: true }
|
|
2590
|
+
]
|
|
2591
|
+
},
|
|
2592
|
+
{
|
|
2593
|
+
id: "schema.forecast.iem_mos.v1",
|
|
2594
|
+
title: "schema.forecast.iem_mos.v1",
|
|
2595
|
+
columnCount: 11,
|
|
2596
|
+
columns: [
|
|
2597
|
+
{ name: "dew_point_c", description: "units: celsius", nullable: true },
|
|
2598
|
+
{
|
|
2599
|
+
name: "forecast_hour",
|
|
2600
|
+
description: "units: hours \u2014 (valid_at - issued_at).total_seconds() / 3600",
|
|
2601
|
+
nullable: false
|
|
2602
|
+
},
|
|
2603
|
+
{
|
|
2604
|
+
name: "issued_at",
|
|
2605
|
+
description: "model run time (from source `runtime` field)",
|
|
2606
|
+
nullable: false
|
|
2607
|
+
},
|
|
2608
|
+
{ name: "model", description: "e.g. NBE, GFS, LAV, MET", nullable: false },
|
|
2609
|
+
{
|
|
2610
|
+
name: "precip_probability",
|
|
2611
|
+
description: "units: probability \u2014 bounded [0, 1]",
|
|
2612
|
+
nullable: true
|
|
2613
|
+
},
|
|
2614
|
+
{
|
|
2615
|
+
name: "sky_cover_pct",
|
|
2616
|
+
description: "units: percent \u2014 bounded [0, 100]",
|
|
2617
|
+
nullable: true
|
|
2618
|
+
},
|
|
2619
|
+
{ name: "station", description: "", nullable: false },
|
|
2620
|
+
{ name: "temp_c", description: "units: celsius", nullable: true },
|
|
2621
|
+
{
|
|
2622
|
+
name: "valid_at",
|
|
2623
|
+
description: "forecast target time (from source `ftime`)",
|
|
2624
|
+
nullable: false
|
|
2625
|
+
},
|
|
2626
|
+
{ name: "wind_dir_deg", description: "units: degrees", nullable: true },
|
|
2627
|
+
{ name: "wind_speed_ms", description: "units: m/s", nullable: true }
|
|
2628
|
+
]
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
id: "schema.settlement.cli.v1",
|
|
2632
|
+
title: "schema.settlement.cli.v1",
|
|
2633
|
+
columnCount: 12,
|
|
2634
|
+
columns: [
|
|
2635
|
+
{
|
|
2636
|
+
name: "cli_data_quality",
|
|
2637
|
+
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.",
|
|
2638
|
+
nullable: false
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
name: "event_time",
|
|
2642
|
+
description: "00:00 local time on observation_date converted to UTC; for sort/join only",
|
|
2643
|
+
nullable: false
|
|
2644
|
+
},
|
|
2645
|
+
{
|
|
2646
|
+
name: "observation_date",
|
|
2647
|
+
description: "local climate day per NWS convention (no timezone applied to the date itself)",
|
|
2648
|
+
nullable: false
|
|
2649
|
+
},
|
|
2650
|
+
{ name: "precipitation_in", description: "units: inches", nullable: true },
|
|
2651
|
+
{
|
|
2652
|
+
name: "product_release_time",
|
|
2653
|
+
description: "parsed from CLI product header (_climate.py::_parse_product_timestamp)",
|
|
2654
|
+
nullable: false
|
|
2655
|
+
},
|
|
2656
|
+
{
|
|
2657
|
+
name: "report_type",
|
|
2658
|
+
description: "preliminary | final | correction; dedup priority preliminary < final < correction",
|
|
2659
|
+
nullable: false
|
|
2660
|
+
},
|
|
2661
|
+
{
|
|
2662
|
+
name: "settlement_finality",
|
|
2663
|
+
description: "provisional | final | superseded. Kalshi NHIGH/NLOW settlement contractually requires 'final'; 'provisional' values are kept for early-look research only.",
|
|
2664
|
+
nullable: false
|
|
2665
|
+
},
|
|
2666
|
+
{ name: "snowfall_in", description: "units: inches", nullable: true },
|
|
2667
|
+
{ name: "station", description: "ICAO/ASOS station ID", nullable: false },
|
|
2668
|
+
{
|
|
2669
|
+
name: "station_tz",
|
|
2670
|
+
description: "IANA timezone for the station (e.g. America/Chicago for KORD). Required for local-climate-day semantics; see \xA7U.",
|
|
2671
|
+
nullable: false
|
|
2672
|
+
},
|
|
2673
|
+
{
|
|
2674
|
+
name: "temp_max_F",
|
|
2675
|
+
description: "units: fahrenheit \u2014 daily high (uppercase F for consistency with obs imperial mode)",
|
|
2676
|
+
nullable: true
|
|
2677
|
+
},
|
|
2678
|
+
{ name: "temp_min_F", description: "units: fahrenheit \u2014 daily low", nullable: true }
|
|
2679
|
+
]
|
|
2680
|
+
},
|
|
2681
|
+
{
|
|
2682
|
+
id: "schema.observation_ledger.v1",
|
|
2683
|
+
title: "schema.observation_ledger.v1",
|
|
2684
|
+
columnCount: 15,
|
|
2685
|
+
columns: [
|
|
2686
|
+
{ name: "as_of_time", description: "", nullable: true },
|
|
2687
|
+
{ name: "dewpoint_c", description: "units: celsius", nullable: true },
|
|
2688
|
+
{ name: "ingestion_id", description: "", nullable: true },
|
|
2689
|
+
{ name: "observation_kind", description: "", nullable: true },
|
|
2690
|
+
{
|
|
2691
|
+
name: "observation_quality",
|
|
2692
|
+
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.",
|
|
2693
|
+
nullable: true
|
|
2694
|
+
},
|
|
2695
|
+
{ name: "observation_type", description: "", nullable: false },
|
|
2696
|
+
{ name: "observed_at", description: "", nullable: false },
|
|
2697
|
+
{ name: "parser_name", description: "", nullable: true },
|
|
2698
|
+
{ name: "parser_version", description: "", nullable: true },
|
|
2699
|
+
{ name: "provenance", description: "", nullable: true },
|
|
2700
|
+
{ name: "qc_status", description: "", nullable: true },
|
|
2701
|
+
{
|
|
2702
|
+
name: "source",
|
|
2703
|
+
description: "ncei reserved per D-2.1-09; never written in v0.1.0.",
|
|
2704
|
+
nullable: false
|
|
2705
|
+
},
|
|
2706
|
+
{ name: "source_received_at", description: "", nullable: true },
|
|
2707
|
+
{ name: "station_code", description: "", nullable: false },
|
|
2708
|
+
{ name: "temp_c", description: "units: celsius", nullable: true }
|
|
2709
|
+
]
|
|
2710
|
+
},
|
|
2711
|
+
{
|
|
2712
|
+
id: "schema.observation_qc.v1",
|
|
2713
|
+
title: "schema.observation_qc.v1",
|
|
2714
|
+
columnCount: 13,
|
|
2715
|
+
columns: [
|
|
2716
|
+
{ name: "as_of_time", description: "", nullable: true },
|
|
2717
|
+
{
|
|
2718
|
+
name: "detector_metadata",
|
|
2719
|
+
description: "JSON-serialized detector payload; shape per qc_system.",
|
|
2720
|
+
nullable: true
|
|
2721
|
+
},
|
|
2722
|
+
{
|
|
2723
|
+
name: "field",
|
|
2724
|
+
description: "Observation column the rule evaluated (e.g. temp_c).",
|
|
2725
|
+
nullable: false
|
|
2726
|
+
},
|
|
2727
|
+
{ name: "flag", description: "", nullable: false },
|
|
2728
|
+
{ name: "ingestion_id", description: "", nullable: true },
|
|
2729
|
+
{ name: "observation_kind", description: "", nullable: true },
|
|
2730
|
+
{ name: "observed_at", description: "", nullable: false },
|
|
2731
|
+
{ name: "parser_name", description: "", nullable: true },
|
|
2732
|
+
{ name: "qc_system", description: "", nullable: false },
|
|
2733
|
+
{ name: "qc_version", description: "", nullable: false },
|
|
2734
|
+
{ name: "rule_id", description: "", nullable: false },
|
|
2735
|
+
{ name: "source", description: "", nullable: false },
|
|
2736
|
+
{ name: "station_code", description: "", nullable: false }
|
|
2737
|
+
]
|
|
2738
|
+
}
|
|
2739
|
+
]);
|
|
2740
|
+
function deepFreezeSchema(info) {
|
|
2741
|
+
const frozenCols = Object.freeze(info.columns.map((c) => Object.freeze({ ...c })));
|
|
2742
|
+
return Object.freeze({ ...info, columns: frozenCols });
|
|
2743
|
+
}
|
|
2744
|
+
var REGISTRY = new Map(
|
|
2745
|
+
BUILT_IN_SCHEMAS.map((info) => [info.id, deepFreezeSchema(info)])
|
|
2746
|
+
);
|
|
2747
|
+
var FEATURE_NAMES = Object.freeze([
|
|
2748
|
+
"calendarFeatures",
|
|
2749
|
+
"clipOutliers",
|
|
2750
|
+
"diff",
|
|
2751
|
+
"diff2",
|
|
2752
|
+
"heatIndex",
|
|
2753
|
+
"lag",
|
|
2754
|
+
"rolling",
|
|
2755
|
+
"spread",
|
|
2756
|
+
"windChill"
|
|
2757
|
+
]);
|
|
2758
|
+
|
|
2759
|
+
// ../weather/src/dailyExtremes.ts
|
|
2760
|
+
var LOW_COVERAGE_THRESHOLD2 = 12;
|
|
2761
|
+
function addUtcDays(iso, days) {
|
|
2762
|
+
const [yStr, mStr, dStr] = iso.split("-");
|
|
2763
|
+
const dt = new Date(Date.UTC(Number(yStr), Number(mStr) - 1, Number(dStr)));
|
|
2764
|
+
dt.setUTCDate(dt.getUTCDate() + days);
|
|
2765
|
+
const yyyy = dt.getUTCFullYear();
|
|
2766
|
+
const mm = String(dt.getUTCMonth() + 1).padStart(2, "0");
|
|
2767
|
+
const dd = String(dt.getUTCDate()).padStart(2, "0");
|
|
2768
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
2769
|
+
}
|
|
2770
|
+
function lookupStation(icao) {
|
|
2771
|
+
const upper = icao.toUpperCase();
|
|
2772
|
+
for (const s of STATIONS) {
|
|
2773
|
+
if (s.icao === upper) {
|
|
2774
|
+
return { tz: s.tz, isUs: s.country === "US" };
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
throw new Error(`dailyExtremes: station "${icao}" not in registry \u2014 check STATIONS catalog`);
|
|
2778
|
+
}
|
|
2779
|
+
function cToF2(c) {
|
|
2780
|
+
if (c === null) return null;
|
|
2781
|
+
return c * (9 / 5) + 32;
|
|
2782
|
+
}
|
|
2783
|
+
function roundHalfUp2(value, decimals) {
|
|
2784
|
+
const m = 10 ** decimals;
|
|
2785
|
+
return Math.round(value * m) / m;
|
|
2786
|
+
}
|
|
2787
|
+
async function fetchIemAsosObservations(station, fromDate, toDate) {
|
|
2788
|
+
const fromYear = Number.parseInt(fromDate.slice(0, 4), 10);
|
|
2789
|
+
const toYear = Number.parseInt(toDate.slice(0, 4), 10);
|
|
2790
|
+
const out = [];
|
|
2791
|
+
for (let year = fromYear; year <= toYear; year++) {
|
|
2792
|
+
const chunks = await downloadIemAsos(station, `${year}-01-01`, `${year}-12-31`, {
|
|
2793
|
+
reportType: 3,
|
|
2794
|
+
politenessMs: 1e3
|
|
2795
|
+
});
|
|
2796
|
+
for (const chunk of chunks) {
|
|
2797
|
+
const parsed = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|
|
2798
|
+
for (const row of parsed) {
|
|
2799
|
+
const obsDate = row.observed_at.slice(0, 10);
|
|
2800
|
+
if (obsDate >= fromDate && obsDate <= toDate) {
|
|
2801
|
+
const precipInches = row.precip_1hr_inches ?? null;
|
|
2802
|
+
out.push({
|
|
2803
|
+
observed_at: row.observed_at,
|
|
2804
|
+
temp_c: row.temp_c ?? null,
|
|
2805
|
+
precip_mm_1h: precipInches !== null ? precipInches * 25.4 : null,
|
|
2806
|
+
source: row.source
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
return out;
|
|
2813
|
+
}
|
|
2814
|
+
async function fetchAwcObservations(station, fromDate, toDate) {
|
|
2815
|
+
const raw = await fetchAwcMetars([station]);
|
|
2816
|
+
const out = [];
|
|
2817
|
+
for (const r of raw) {
|
|
2818
|
+
const obs2 = awcToObservation(r);
|
|
2819
|
+
if (obs2 === null) continue;
|
|
2820
|
+
const obsDate = obs2.observed_at.slice(0, 10);
|
|
2821
|
+
if (obsDate >= fromDate && obsDate <= toDate) {
|
|
2822
|
+
const precipInches = obs2.precip_1hr_inches ?? null;
|
|
2823
|
+
out.push({
|
|
2824
|
+
observed_at: obs2.observed_at,
|
|
2825
|
+
temp_c: obs2.temp_c ?? null,
|
|
2826
|
+
precip_mm_1h: precipInches !== null ? precipInches * 25.4 : null,
|
|
2827
|
+
source: obs2.source
|
|
2828
|
+
});
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
return out;
|
|
2832
|
+
}
|
|
2833
|
+
async function fetchForMode(station, fromDate, toDate, mode) {
|
|
2834
|
+
switch (mode) {
|
|
2835
|
+
case "iem_only":
|
|
2836
|
+
return fetchIemAsosObservations(station, fromDate, toDate);
|
|
2837
|
+
case "awc_only":
|
|
2838
|
+
return fetchAwcObservations(station, fromDate, toDate);
|
|
2839
|
+
case "live_v1": {
|
|
2840
|
+
const [iem, awc] = await Promise.all([
|
|
2841
|
+
fetchIemAsosObservations(station, fromDate, toDate),
|
|
2842
|
+
fetchAwcObservations(station, fromDate, toDate).catch(() => [])
|
|
2843
|
+
]);
|
|
2844
|
+
return [...iem, ...awc];
|
|
2845
|
+
}
|
|
2846
|
+
default: {
|
|
2847
|
+
const _exhaustive = mode;
|
|
2848
|
+
throw new TypeError(`dailyExtremes: unknown merge mode "${String(_exhaustive)}"`);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
function projectRow(station, d, isUs) {
|
|
2853
|
+
const lowCoverage = d.nObs < LOW_COVERAGE_THRESHOLD2;
|
|
2854
|
+
const decimals = isUs ? 0 : 1;
|
|
2855
|
+
const precipIn = d.precipMm !== null && d.precipMm !== void 0 ? roundHalfUp2(d.precipMm / 25.4, 2) : null;
|
|
2856
|
+
if (lowCoverage) {
|
|
2857
|
+
return {
|
|
2858
|
+
date: d.localDate,
|
|
2859
|
+
station,
|
|
2860
|
+
tmin_f: null,
|
|
2861
|
+
tmax_f: null,
|
|
2862
|
+
tmean_f: null,
|
|
2863
|
+
precip_in: precipIn,
|
|
2864
|
+
low_coverage: true,
|
|
2865
|
+
n_obs: d.nObs
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
return {
|
|
2869
|
+
date: d.localDate,
|
|
2870
|
+
station,
|
|
2871
|
+
tmin_f: d.tempMinF !== null ? roundHalfUp2(d.tempMinF, decimals) : null,
|
|
2872
|
+
tmax_f: d.tempMaxF !== null ? roundHalfUp2(d.tempMaxF, decimals) : null,
|
|
2873
|
+
tmean_f: d.tempMeanC !== null ? roundHalfUp2(cToF2(d.tempMeanC), decimals) : null,
|
|
2874
|
+
precip_in: precipIn,
|
|
2875
|
+
low_coverage: false,
|
|
2876
|
+
n_obs: d.nObs
|
|
2877
|
+
};
|
|
2878
|
+
}
|
|
2879
|
+
async function dailyExtremes(station, fromDate, toDate, opts = {}) {
|
|
2880
|
+
const { tz, isUs } = lookupStation(station);
|
|
2881
|
+
const merge = opts.merge ?? "live_v1";
|
|
2882
|
+
const fetchFrom = addUtcDays(fromDate, -1);
|
|
2883
|
+
const fetchTo = addUtcDays(toDate, 1);
|
|
2884
|
+
const rows = await fetchForMode(station, fetchFrom, fetchTo, merge);
|
|
2885
|
+
const extremes = internationalDailyExtremes(rows, {
|
|
2886
|
+
stationTz: tz,
|
|
2887
|
+
precision: isUs ? 1 : 0
|
|
2888
|
+
});
|
|
2889
|
+
return extremes.filter((d) => d.localDate >= fromDate && d.localDate <= toDate).map((d) => projectRow(station.toUpperCase(), d, isUs));
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
// ../weather/src/obs.ts
|
|
2893
|
+
function daysBetween(fromDate, toDate) {
|
|
2894
|
+
const from = Date.UTC(
|
|
2895
|
+
Number.parseInt(fromDate.slice(0, 4), 10),
|
|
2896
|
+
Number.parseInt(fromDate.slice(5, 7), 10) - 1,
|
|
2897
|
+
Number.parseInt(fromDate.slice(8, 10), 10)
|
|
2898
|
+
);
|
|
2899
|
+
const to = Date.UTC(
|
|
2900
|
+
Number.parseInt(toDate.slice(0, 4), 10),
|
|
2901
|
+
Number.parseInt(toDate.slice(5, 7), 10) - 1,
|
|
2902
|
+
Number.parseInt(toDate.slice(8, 10), 10)
|
|
1006
2903
|
);
|
|
2904
|
+
return Math.round((to - from) / (24 * 60 * 60 * 1e3)) + 1;
|
|
2905
|
+
}
|
|
2906
|
+
function resolveAutoStrategy(fromDate, toDate) {
|
|
2907
|
+
return daysBetween(fromDate, toDate) <= 7 ? "exact_window" : "warm_cache";
|
|
2908
|
+
}
|
|
2909
|
+
function inchesToMm(inches) {
|
|
2910
|
+
if (inches === null || inches === void 0) return null;
|
|
2911
|
+
return inches * 25.4;
|
|
2912
|
+
}
|
|
2913
|
+
function mbToInhg(mb) {
|
|
2914
|
+
if (mb === null || mb === void 0) return null;
|
|
2915
|
+
return mb * 0.029529983071445;
|
|
2916
|
+
}
|
|
2917
|
+
function fromObservation(o) {
|
|
2918
|
+
const tempC = o.temp_c ?? null;
|
|
2919
|
+
const dewC = o.dewpoint_c ?? null;
|
|
2920
|
+
return {
|
|
2921
|
+
station: o.station_code,
|
|
2922
|
+
observed_at: o.observed_at,
|
|
2923
|
+
source: o.source,
|
|
2924
|
+
temp_c: tempC,
|
|
2925
|
+
temp_f: tempC !== null ? tempC * (9 / 5) + 32 : null,
|
|
2926
|
+
dewpoint_c: dewC,
|
|
2927
|
+
dewpoint_f: dewC !== null ? dewC * (9 / 5) + 32 : null,
|
|
2928
|
+
wind_speed_kts: o.wind_speed_kt ?? null,
|
|
2929
|
+
wind_direction_deg: o.wind_dir_degrees ?? null,
|
|
2930
|
+
pressure_inhg: mbToInhg(o.sea_level_pressure_mb),
|
|
2931
|
+
precip_mm_1h: inchesToMm(o.precip_1hr_inches),
|
|
2932
|
+
raw_metar: o.raw_metar ?? null
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2935
|
+
async function fetchIemForWindow(station, fromDate, toDate, resolvedStrategy) {
|
|
2936
|
+
const out = [];
|
|
2937
|
+
if (resolvedStrategy === "exact_window") {
|
|
2938
|
+
const chunks = await downloadIemAsos(station, fromDate, toDate, {
|
|
2939
|
+
reportType: 3,
|
|
2940
|
+
politenessMs: 1e3
|
|
2941
|
+
});
|
|
2942
|
+
for (const chunk of chunks) {
|
|
2943
|
+
const rows = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|
|
2944
|
+
for (const r of rows) {
|
|
2945
|
+
const d = r.observed_at.slice(0, 10);
|
|
2946
|
+
if (d >= fromDate && d <= toDate) out.push(fromObservation(r));
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
return out;
|
|
2950
|
+
}
|
|
2951
|
+
const fromYear = Number.parseInt(fromDate.slice(0, 4), 10);
|
|
2952
|
+
const toYear = Number.parseInt(toDate.slice(0, 4), 10);
|
|
2953
|
+
for (let year = fromYear; year <= toYear; year++) {
|
|
2954
|
+
const chunks = await downloadIemAsos(station, `${year}-01-01`, `${year}-12-31`, {
|
|
2955
|
+
reportType: 3,
|
|
2956
|
+
politenessMs: 1e3
|
|
2957
|
+
});
|
|
2958
|
+
for (const chunk of chunks) {
|
|
2959
|
+
const rows = parseIemCsv(chunk.csv, { observationTypeOverride: "METAR" });
|
|
2960
|
+
for (const r of rows) {
|
|
2961
|
+
const d = r.observed_at.slice(0, 10);
|
|
2962
|
+
if (d >= fromDate && d <= toDate) out.push(fromObservation(r));
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
return out;
|
|
2967
|
+
}
|
|
2968
|
+
async function fetchAwcForWindow(station, fromDate, toDate) {
|
|
2969
|
+
const raw = await fetchAwcMetars([station]);
|
|
2970
|
+
const out = [];
|
|
2971
|
+
for (const r of raw) {
|
|
2972
|
+
const obs2 = awcToObservation(r);
|
|
2973
|
+
if (obs2 === null) continue;
|
|
2974
|
+
const d = obs2.observed_at.slice(0, 10);
|
|
2975
|
+
if (d >= fromDate && d <= toDate) out.push(fromObservation(obs2));
|
|
2976
|
+
}
|
|
2977
|
+
return out;
|
|
2978
|
+
}
|
|
2979
|
+
async function fetchByStrategy(station, fromDate, toDate, resolvedStrategy, source) {
|
|
2980
|
+
const wantsIem = source === null || source === void 0 || source === "iem";
|
|
2981
|
+
const wantsAwc = source === null || source === void 0 || source === "awc";
|
|
2982
|
+
const tasks = [];
|
|
2983
|
+
if (wantsIem) tasks.push(fetchIemForWindow(station, fromDate, toDate, resolvedStrategy));
|
|
2984
|
+
if (wantsAwc) tasks.push(fetchAwcForWindow(station, fromDate, toDate).catch(() => []));
|
|
2985
|
+
const results = await Promise.all(tasks);
|
|
2986
|
+
return results.flat();
|
|
2987
|
+
}
|
|
2988
|
+
async function obs(station, fromDate, toDate, opts = {}) {
|
|
2989
|
+
const strategy = opts.strategy ?? "auto";
|
|
2990
|
+
const source = opts.source ?? null;
|
|
2991
|
+
if (source === "ghcnh") {
|
|
2992
|
+
throw new DataAvailabilityError({
|
|
2993
|
+
reason: "model_unavailable",
|
|
2994
|
+
source: "obs.ghcnh",
|
|
2995
|
+
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."
|
|
2996
|
+
});
|
|
2997
|
+
}
|
|
2998
|
+
if (strategy === "hosted") {
|
|
2999
|
+
throw new DataAvailabilityError({
|
|
3000
|
+
reason: "model_unavailable",
|
|
3001
|
+
source: "obs-hosted-stub",
|
|
3002
|
+
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"
|
|
3003
|
+
});
|
|
3004
|
+
}
|
|
3005
|
+
let resolved;
|
|
3006
|
+
if (strategy === "auto") {
|
|
3007
|
+
resolved = resolveAutoStrategy(fromDate, toDate);
|
|
3008
|
+
} else if (strategy === "exact_window" || strategy === "warm_cache") {
|
|
3009
|
+
resolved = strategy;
|
|
3010
|
+
} else {
|
|
3011
|
+
throw new TypeError(
|
|
3012
|
+
`obs: unknown strategy "${String(strategy)}" \u2014 expected one of: auto, exact_window, warm_cache, hosted`
|
|
3013
|
+
);
|
|
3014
|
+
}
|
|
3015
|
+
return fetchByStrategy(station, fromDate, toDate, resolved, source);
|
|
1007
3016
|
}
|
|
1008
3017
|
|
|
1009
3018
|
// ../weather/src/index.ts
|
|
@@ -1107,6 +3116,10 @@ var KALSHI_SETTLEMENT_STATIONS = {
|
|
|
1107
3116
|
SLC: {
|
|
1108
3117
|
citation: "https://kalshi.com/markets/khighslc (Salt Lake City International)",
|
|
1109
3118
|
station: "KSLC"
|
|
3119
|
+
},
|
|
3120
|
+
TLV: {
|
|
3121
|
+
citation: "https://kalshi.com/markets/kxhightlv (Harry Reid/McCarran; settles vs NWS CLILAS)",
|
|
3122
|
+
station: "KLAS"
|
|
1110
3123
|
}
|
|
1111
3124
|
};
|
|
1112
3125
|
var KNOWN_WRONG_STATIONS = /* @__PURE__ */ new Set([
|
|
@@ -1692,10 +3705,11 @@ replaceTraps((oldTraps) => ({
|
|
|
1692
3705
|
}
|
|
1693
3706
|
}));
|
|
1694
3707
|
|
|
1695
|
-
// ../core/dist/internal/chunk-
|
|
3708
|
+
// ../core/dist/internal/chunk-QDQSYUFW.mjs
|
|
1696
3709
|
function lockKeyFor(key) {
|
|
1697
3710
|
return `mostlyright:cache:lock:${key}`;
|
|
1698
3711
|
}
|
|
3712
|
+
var CACHE_SCHEMA_VERSION = "v2-phase18-integer-f";
|
|
1699
3713
|
var MemoryStore = class {
|
|
1700
3714
|
#entries = /* @__PURE__ */ new Map();
|
|
1701
3715
|
#chain = /* @__PURE__ */ new Map();
|
|
@@ -1842,7 +3856,71 @@ var IndexedDBStore = class {
|
|
|
1842
3856
|
return next;
|
|
1843
3857
|
}
|
|
1844
3858
|
};
|
|
1845
|
-
var
|
|
3859
|
+
var VERSION_FIELD = "_cache_schema_version";
|
|
3860
|
+
function isVersionedEntry(v) {
|
|
3861
|
+
if (v === null || typeof v !== "object") return false;
|
|
3862
|
+
if (!(VERSION_FIELD in v)) return false;
|
|
3863
|
+
return typeof v[VERSION_FIELD] === "string";
|
|
3864
|
+
}
|
|
3865
|
+
function hasListKeys(s) {
|
|
3866
|
+
return typeof s.listKeys === "function";
|
|
3867
|
+
}
|
|
3868
|
+
var VersionedCacheStore = class {
|
|
3869
|
+
#inner;
|
|
3870
|
+
#version;
|
|
3871
|
+
constructor(inner, version4) {
|
|
3872
|
+
if (typeof version4 !== "string" || version4.length === 0) {
|
|
3873
|
+
throw new TypeError("versionedCacheStore: version must be a non-empty string");
|
|
3874
|
+
}
|
|
3875
|
+
this.#inner = inner;
|
|
3876
|
+
this.#version = version4;
|
|
3877
|
+
}
|
|
3878
|
+
/**
|
|
3879
|
+
* Test/diagnostics seam: return the underlying store so tests can assert
|
|
3880
|
+
* which concrete backend `defaultCacheStore()` selected. NOT a production
|
|
3881
|
+
* API — production code MUST use the wrapped store so version
|
|
3882
|
+
* invalidation fires on stale reads.
|
|
3883
|
+
*
|
|
3884
|
+
* @internal
|
|
3885
|
+
*/
|
|
3886
|
+
__peekInner() {
|
|
3887
|
+
return this.#inner;
|
|
3888
|
+
}
|
|
3889
|
+
async get(key) {
|
|
3890
|
+
const raw = await this.#inner.get(key);
|
|
3891
|
+
if (raw === null) return null;
|
|
3892
|
+
if (!isVersionedEntry(raw)) {
|
|
3893
|
+
return null;
|
|
3894
|
+
}
|
|
3895
|
+
if (raw._cache_schema_version !== this.#version) {
|
|
3896
|
+
return null;
|
|
3897
|
+
}
|
|
3898
|
+
return raw.value;
|
|
3899
|
+
}
|
|
3900
|
+
async set(key, value, opts) {
|
|
3901
|
+
const wrapped = {
|
|
3902
|
+
value,
|
|
3903
|
+
[VERSION_FIELD]: this.#version
|
|
3904
|
+
};
|
|
3905
|
+
await this.#inner.set(key, wrapped, opts);
|
|
3906
|
+
}
|
|
3907
|
+
async delete(key) {
|
|
3908
|
+
await this.#inner.delete(key);
|
|
3909
|
+
}
|
|
3910
|
+
async withLock(key, fn) {
|
|
3911
|
+
return this.#inner.withLock(key, fn);
|
|
3912
|
+
}
|
|
3913
|
+
async listKeys(prefix) {
|
|
3914
|
+
if (hasListKeys(this.#inner)) {
|
|
3915
|
+
return this.#inner.listKeys(prefix);
|
|
3916
|
+
}
|
|
3917
|
+
return Object.freeze([]);
|
|
3918
|
+
}
|
|
3919
|
+
};
|
|
3920
|
+
function versionedCacheStore(inner, version4) {
|
|
3921
|
+
return new VersionedCacheStore(inner, version4);
|
|
3922
|
+
}
|
|
3923
|
+
var STATIONS3 = [
|
|
1846
3924
|
{
|
|
1847
3925
|
code: "EDDB",
|
|
1848
3926
|
country: "DE",
|
|
@@ -1851,7 +3929,10 @@ var STATIONS = [
|
|
|
1851
3929
|
latitude: 52.3667,
|
|
1852
3930
|
longitude: 13.5033,
|
|
1853
3931
|
name: "Berlin Brandenburg",
|
|
1854
|
-
tz: "Europe/Berlin"
|
|
3932
|
+
tz: "Europe/Berlin",
|
|
3933
|
+
venues: [
|
|
3934
|
+
"polymarket"
|
|
3935
|
+
]
|
|
1855
3936
|
},
|
|
1856
3937
|
{
|
|
1857
3938
|
code: "EDDF",
|
|
@@ -1861,7 +3942,10 @@ var STATIONS = [
|
|
|
1861
3942
|
latitude: 50.0379,
|
|
1862
3943
|
longitude: 8.5622,
|
|
1863
3944
|
name: "Frankfurt am Main",
|
|
1864
|
-
tz: "Europe/Berlin"
|
|
3945
|
+
tz: "Europe/Berlin",
|
|
3946
|
+
venues: [
|
|
3947
|
+
"polymarket"
|
|
3948
|
+
]
|
|
1865
3949
|
},
|
|
1866
3950
|
{
|
|
1867
3951
|
code: "EDDM",
|
|
@@ -1871,7 +3955,10 @@ var STATIONS = [
|
|
|
1871
3955
|
latitude: 48.3538,
|
|
1872
3956
|
longitude: 11.7861,
|
|
1873
3957
|
name: "Munich Franz Josef Strauss",
|
|
1874
|
-
tz: "Europe/Berlin"
|
|
3958
|
+
tz: "Europe/Berlin",
|
|
3959
|
+
venues: [
|
|
3960
|
+
"polymarket"
|
|
3961
|
+
]
|
|
1875
3962
|
},
|
|
1876
3963
|
{
|
|
1877
3964
|
code: "EFHK",
|
|
@@ -1881,7 +3968,10 @@ var STATIONS = [
|
|
|
1881
3968
|
latitude: 60.3172,
|
|
1882
3969
|
longitude: 24.9633,
|
|
1883
3970
|
name: "Helsinki-Vantaa",
|
|
1884
|
-
tz: "Europe/Helsinki"
|
|
3971
|
+
tz: "Europe/Helsinki",
|
|
3972
|
+
venues: [
|
|
3973
|
+
"polymarket"
|
|
3974
|
+
]
|
|
1885
3975
|
},
|
|
1886
3976
|
{
|
|
1887
3977
|
code: "EGKK",
|
|
@@ -1891,7 +3981,10 @@ var STATIONS = [
|
|
|
1891
3981
|
latitude: 51.1481,
|
|
1892
3982
|
longitude: -0.1903,
|
|
1893
3983
|
name: "London Gatwick",
|
|
1894
|
-
tz: "Europe/London"
|
|
3984
|
+
tz: "Europe/London",
|
|
3985
|
+
venues: [
|
|
3986
|
+
"polymarket"
|
|
3987
|
+
]
|
|
1895
3988
|
},
|
|
1896
3989
|
{
|
|
1897
3990
|
code: "EGLL",
|
|
@@ -1901,7 +3994,10 @@ var STATIONS = [
|
|
|
1901
3994
|
latitude: 51.4706,
|
|
1902
3995
|
longitude: -0.4619,
|
|
1903
3996
|
name: "London Heathrow",
|
|
1904
|
-
tz: "Europe/London"
|
|
3997
|
+
tz: "Europe/London",
|
|
3998
|
+
venues: [
|
|
3999
|
+
"polymarket"
|
|
4000
|
+
]
|
|
1905
4001
|
},
|
|
1906
4002
|
{
|
|
1907
4003
|
code: "EHAM",
|
|
@@ -1911,7 +4007,10 @@ var STATIONS = [
|
|
|
1911
4007
|
latitude: 52.3086,
|
|
1912
4008
|
longitude: 4.7639,
|
|
1913
4009
|
name: "Amsterdam Schiphol",
|
|
1914
|
-
tz: "Europe/Amsterdam"
|
|
4010
|
+
tz: "Europe/Amsterdam",
|
|
4011
|
+
venues: [
|
|
4012
|
+
"polymarket"
|
|
4013
|
+
]
|
|
1915
4014
|
},
|
|
1916
4015
|
{
|
|
1917
4016
|
code: "EKCH",
|
|
@@ -1921,7 +4020,10 @@ var STATIONS = [
|
|
|
1921
4020
|
latitude: 55.6181,
|
|
1922
4021
|
longitude: 12.6561,
|
|
1923
4022
|
name: "Copenhagen Kastrup",
|
|
1924
|
-
tz: "Europe/Copenhagen"
|
|
4023
|
+
tz: "Europe/Copenhagen",
|
|
4024
|
+
venues: [
|
|
4025
|
+
"polymarket"
|
|
4026
|
+
]
|
|
1925
4027
|
},
|
|
1926
4028
|
{
|
|
1927
4029
|
code: "EPWA",
|
|
@@ -1931,7 +4033,10 @@ var STATIONS = [
|
|
|
1931
4033
|
latitude: 52.1657,
|
|
1932
4034
|
longitude: 20.9671,
|
|
1933
4035
|
name: "Warsaw Chopin",
|
|
1934
|
-
tz: "Europe/Warsaw"
|
|
4036
|
+
tz: "Europe/Warsaw",
|
|
4037
|
+
venues: [
|
|
4038
|
+
"polymarket"
|
|
4039
|
+
]
|
|
1935
4040
|
},
|
|
1936
4041
|
{
|
|
1937
4042
|
code: "ESSA",
|
|
@@ -1941,7 +4046,10 @@ var STATIONS = [
|
|
|
1941
4046
|
latitude: 59.6519,
|
|
1942
4047
|
longitude: 17.9186,
|
|
1943
4048
|
name: "Stockholm Arlanda",
|
|
1944
|
-
tz: "Europe/Stockholm"
|
|
4049
|
+
tz: "Europe/Stockholm",
|
|
4050
|
+
venues: [
|
|
4051
|
+
"polymarket"
|
|
4052
|
+
]
|
|
1945
4053
|
},
|
|
1946
4054
|
{
|
|
1947
4055
|
code: "ATL",
|
|
@@ -1951,7 +4059,11 @@ var STATIONS = [
|
|
|
1951
4059
|
latitude: 33.6407,
|
|
1952
4060
|
longitude: -84.4277,
|
|
1953
4061
|
name: "Hartsfield-Jackson Atlanta International",
|
|
1954
|
-
tz: "America/New_York"
|
|
4062
|
+
tz: "America/New_York",
|
|
4063
|
+
venues: [
|
|
4064
|
+
"kalshi",
|
|
4065
|
+
"polymarket"
|
|
4066
|
+
]
|
|
1955
4067
|
},
|
|
1956
4068
|
{
|
|
1957
4069
|
code: "AUS",
|
|
@@ -1961,7 +4073,24 @@ var STATIONS = [
|
|
|
1961
4073
|
latitude: 30.1975,
|
|
1962
4074
|
longitude: -97.6664,
|
|
1963
4075
|
name: "Austin-Bergstrom International",
|
|
1964
|
-
tz: "America/Chicago"
|
|
4076
|
+
tz: "America/Chicago",
|
|
4077
|
+
venues: [
|
|
4078
|
+
"kalshi",
|
|
4079
|
+
"polymarket"
|
|
4080
|
+
]
|
|
4081
|
+
},
|
|
4082
|
+
{
|
|
4083
|
+
code: "BNA",
|
|
4084
|
+
country: "US",
|
|
4085
|
+
ghcnh_id: "USW00013897",
|
|
4086
|
+
icao: "KBNA",
|
|
4087
|
+
latitude: 36.1245,
|
|
4088
|
+
longitude: -86.6782,
|
|
4089
|
+
name: "Nashville International",
|
|
4090
|
+
tz: "America/Chicago",
|
|
4091
|
+
venues: [
|
|
4092
|
+
"kalshi"
|
|
4093
|
+
]
|
|
1965
4094
|
},
|
|
1966
4095
|
{
|
|
1967
4096
|
code: "BOS",
|
|
@@ -1971,7 +4100,24 @@ var STATIONS = [
|
|
|
1971
4100
|
latitude: 42.3656,
|
|
1972
4101
|
longitude: -71.0096,
|
|
1973
4102
|
name: "Boston Logan International",
|
|
1974
|
-
tz: "America/New_York"
|
|
4103
|
+
tz: "America/New_York",
|
|
4104
|
+
venues: [
|
|
4105
|
+
"kalshi",
|
|
4106
|
+
"polymarket"
|
|
4107
|
+
]
|
|
4108
|
+
},
|
|
4109
|
+
{
|
|
4110
|
+
code: "CVG",
|
|
4111
|
+
country: "US",
|
|
4112
|
+
ghcnh_id: "USW00093814",
|
|
4113
|
+
icao: "KCVG",
|
|
4114
|
+
latitude: 39.0488,
|
|
4115
|
+
longitude: -84.6678,
|
|
4116
|
+
name: "Cincinnati/Northern Kentucky International",
|
|
4117
|
+
tz: "America/New_York",
|
|
4118
|
+
venues: [
|
|
4119
|
+
"kalshi"
|
|
4120
|
+
]
|
|
1975
4121
|
},
|
|
1976
4122
|
{
|
|
1977
4123
|
code: "DCA",
|
|
@@ -1981,7 +4127,11 @@ var STATIONS = [
|
|
|
1981
4127
|
latitude: 38.8512,
|
|
1982
4128
|
longitude: -77.0402,
|
|
1983
4129
|
name: "Washington Reagan National",
|
|
1984
|
-
tz: "America/New_York"
|
|
4130
|
+
tz: "America/New_York",
|
|
4131
|
+
venues: [
|
|
4132
|
+
"kalshi",
|
|
4133
|
+
"polymarket"
|
|
4134
|
+
]
|
|
1985
4135
|
},
|
|
1986
4136
|
{
|
|
1987
4137
|
code: "DEN",
|
|
@@ -1991,7 +4141,11 @@ var STATIONS = [
|
|
|
1991
4141
|
latitude: 39.8561,
|
|
1992
4142
|
longitude: -104.6737,
|
|
1993
4143
|
name: "Denver International",
|
|
1994
|
-
tz: "America/Denver"
|
|
4144
|
+
tz: "America/Denver",
|
|
4145
|
+
venues: [
|
|
4146
|
+
"kalshi",
|
|
4147
|
+
"polymarket"
|
|
4148
|
+
]
|
|
1995
4149
|
},
|
|
1996
4150
|
{
|
|
1997
4151
|
code: "DFW",
|
|
@@ -2001,7 +4155,25 @@ var STATIONS = [
|
|
|
2001
4155
|
latitude: 32.8998,
|
|
2002
4156
|
longitude: -97.0403,
|
|
2003
4157
|
name: "Dallas-Fort Worth International",
|
|
2004
|
-
tz: "America/Chicago"
|
|
4158
|
+
tz: "America/Chicago",
|
|
4159
|
+
venues: [
|
|
4160
|
+
"kalshi",
|
|
4161
|
+
"polymarket"
|
|
4162
|
+
]
|
|
4163
|
+
},
|
|
4164
|
+
{
|
|
4165
|
+
code: "DTW",
|
|
4166
|
+
country: "US",
|
|
4167
|
+
ghcnh_id: "USW00094847",
|
|
4168
|
+
icao: "KDTW",
|
|
4169
|
+
latitude: 42.2124,
|
|
4170
|
+
longitude: -83.3534,
|
|
4171
|
+
name: "Detroit Metropolitan Wayne County",
|
|
4172
|
+
tz: "America/New_York",
|
|
4173
|
+
venues: [
|
|
4174
|
+
"kalshi",
|
|
4175
|
+
"polymarket"
|
|
4176
|
+
]
|
|
2005
4177
|
},
|
|
2006
4178
|
{
|
|
2007
4179
|
code: "HOU",
|
|
@@ -2011,7 +4183,22 @@ var STATIONS = [
|
|
|
2011
4183
|
latitude: 29.6454,
|
|
2012
4184
|
longitude: -95.2789,
|
|
2013
4185
|
name: "Houston Hobby",
|
|
2014
|
-
tz: "America/Chicago"
|
|
4186
|
+
tz: "America/Chicago",
|
|
4187
|
+
venues: []
|
|
4188
|
+
},
|
|
4189
|
+
{
|
|
4190
|
+
code: "IAH",
|
|
4191
|
+
country: "US",
|
|
4192
|
+
ghcnh_id: "USW00012960",
|
|
4193
|
+
icao: "KIAH",
|
|
4194
|
+
latitude: 29.9844,
|
|
4195
|
+
longitude: -95.3414,
|
|
4196
|
+
name: "Houston George Bush Intercontinental",
|
|
4197
|
+
tz: "America/Chicago",
|
|
4198
|
+
venues: [
|
|
4199
|
+
"kalshi",
|
|
4200
|
+
"polymarket"
|
|
4201
|
+
]
|
|
2015
4202
|
},
|
|
2016
4203
|
{
|
|
2017
4204
|
code: "LAS",
|
|
@@ -2021,7 +4208,10 @@ var STATIONS = [
|
|
|
2021
4208
|
latitude: 36.084,
|
|
2022
4209
|
longitude: -115.1537,
|
|
2023
4210
|
name: "Harry Reid (McCarran) International",
|
|
2024
|
-
tz: "America/Los_Angeles"
|
|
4211
|
+
tz: "America/Los_Angeles",
|
|
4212
|
+
venues: [
|
|
4213
|
+
"kalshi"
|
|
4214
|
+
]
|
|
2025
4215
|
},
|
|
2026
4216
|
{
|
|
2027
4217
|
code: "LAX",
|
|
@@ -2031,7 +4221,11 @@ var STATIONS = [
|
|
|
2031
4221
|
latitude: 33.9425,
|
|
2032
4222
|
longitude: -118.4081,
|
|
2033
4223
|
name: "Los Angeles International",
|
|
2034
|
-
tz: "America/Los_Angeles"
|
|
4224
|
+
tz: "America/Los_Angeles",
|
|
4225
|
+
venues: [
|
|
4226
|
+
"kalshi",
|
|
4227
|
+
"polymarket"
|
|
4228
|
+
]
|
|
2035
4229
|
},
|
|
2036
4230
|
{
|
|
2037
4231
|
code: "MDW",
|
|
@@ -2041,7 +4235,10 @@ var STATIONS = [
|
|
|
2041
4235
|
latitude: 41.7868,
|
|
2042
4236
|
longitude: -87.7522,
|
|
2043
4237
|
name: "Chicago Midway International",
|
|
2044
|
-
tz: "America/Chicago"
|
|
4238
|
+
tz: "America/Chicago",
|
|
4239
|
+
venues: [
|
|
4240
|
+
"kalshi"
|
|
4241
|
+
]
|
|
2045
4242
|
},
|
|
2046
4243
|
{
|
|
2047
4244
|
code: "MIA",
|
|
@@ -2051,7 +4248,11 @@ var STATIONS = [
|
|
|
2051
4248
|
latitude: 25.7959,
|
|
2052
4249
|
longitude: -80.287,
|
|
2053
4250
|
name: "Miami International",
|
|
2054
|
-
tz: "America/New_York"
|
|
4251
|
+
tz: "America/New_York",
|
|
4252
|
+
venues: [
|
|
4253
|
+
"kalshi",
|
|
4254
|
+
"polymarket"
|
|
4255
|
+
]
|
|
2055
4256
|
},
|
|
2056
4257
|
{
|
|
2057
4258
|
code: "MSP",
|
|
@@ -2061,7 +4262,11 @@ var STATIONS = [
|
|
|
2061
4262
|
latitude: 44.8848,
|
|
2062
4263
|
longitude: -93.2223,
|
|
2063
4264
|
name: "Minneapolis-St Paul International",
|
|
2064
|
-
tz: "America/Chicago"
|
|
4265
|
+
tz: "America/Chicago",
|
|
4266
|
+
venues: [
|
|
4267
|
+
"kalshi",
|
|
4268
|
+
"polymarket"
|
|
4269
|
+
]
|
|
2065
4270
|
},
|
|
2066
4271
|
{
|
|
2067
4272
|
code: "MSY",
|
|
@@ -2071,7 +4276,8 @@ var STATIONS = [
|
|
|
2071
4276
|
latitude: 29.9934,
|
|
2072
4277
|
longitude: -90.258,
|
|
2073
4278
|
name: "New Orleans Louis Armstrong International",
|
|
2074
|
-
tz: "America/Chicago"
|
|
4279
|
+
tz: "America/Chicago",
|
|
4280
|
+
venues: []
|
|
2075
4281
|
},
|
|
2076
4282
|
{
|
|
2077
4283
|
code: "NYC",
|
|
@@ -2081,7 +4287,10 @@ var STATIONS = [
|
|
|
2081
4287
|
latitude: 40.7789,
|
|
2082
4288
|
longitude: -73.9692,
|
|
2083
4289
|
name: "Central Park, New York",
|
|
2084
|
-
tz: "America/New_York"
|
|
4290
|
+
tz: "America/New_York",
|
|
4291
|
+
venues: [
|
|
4292
|
+
"kalshi"
|
|
4293
|
+
]
|
|
2085
4294
|
},
|
|
2086
4295
|
{
|
|
2087
4296
|
code: "OKC",
|
|
@@ -2091,7 +4300,8 @@ var STATIONS = [
|
|
|
2091
4300
|
latitude: 35.3931,
|
|
2092
4301
|
longitude: -97.6007,
|
|
2093
4302
|
name: "Oklahoma City Will Rogers World",
|
|
2094
|
-
tz: "America/Chicago"
|
|
4303
|
+
tz: "America/Chicago",
|
|
4304
|
+
venues: []
|
|
2095
4305
|
},
|
|
2096
4306
|
{
|
|
2097
4307
|
code: "PHL",
|
|
@@ -2101,7 +4311,11 @@ var STATIONS = [
|
|
|
2101
4311
|
latitude: 39.8721,
|
|
2102
4312
|
longitude: -75.2411,
|
|
2103
4313
|
name: "Philadelphia International",
|
|
2104
|
-
tz: "America/New_York"
|
|
4314
|
+
tz: "America/New_York",
|
|
4315
|
+
venues: [
|
|
4316
|
+
"kalshi",
|
|
4317
|
+
"polymarket"
|
|
4318
|
+
]
|
|
2105
4319
|
},
|
|
2106
4320
|
{
|
|
2107
4321
|
code: "PHX",
|
|
@@ -2111,7 +4325,11 @@ var STATIONS = [
|
|
|
2111
4325
|
latitude: 33.4373,
|
|
2112
4326
|
longitude: -112.0078,
|
|
2113
4327
|
name: "Phoenix Sky Harbor International",
|
|
2114
|
-
tz: "America/Phoenix"
|
|
4328
|
+
tz: "America/Phoenix",
|
|
4329
|
+
venues: [
|
|
4330
|
+
"kalshi",
|
|
4331
|
+
"polymarket"
|
|
4332
|
+
]
|
|
2115
4333
|
},
|
|
2116
4334
|
{
|
|
2117
4335
|
code: "SAT",
|
|
@@ -2121,7 +4339,8 @@ var STATIONS = [
|
|
|
2121
4339
|
latitude: 29.5337,
|
|
2122
4340
|
longitude: -98.4698,
|
|
2123
4341
|
name: "San Antonio International",
|
|
2124
|
-
tz: "America/Chicago"
|
|
4342
|
+
tz: "America/Chicago",
|
|
4343
|
+
venues: []
|
|
2125
4344
|
},
|
|
2126
4345
|
{
|
|
2127
4346
|
code: "SEA",
|
|
@@ -2131,7 +4350,11 @@ var STATIONS = [
|
|
|
2131
4350
|
latitude: 47.4502,
|
|
2132
4351
|
longitude: -122.3088,
|
|
2133
4352
|
name: "Seattle-Tacoma International",
|
|
2134
|
-
tz: "America/Los_Angeles"
|
|
4353
|
+
tz: "America/Los_Angeles",
|
|
4354
|
+
venues: [
|
|
4355
|
+
"kalshi",
|
|
4356
|
+
"polymarket"
|
|
4357
|
+
]
|
|
2135
4358
|
},
|
|
2136
4359
|
{
|
|
2137
4360
|
code: "SFO",
|
|
@@ -2141,7 +4364,24 @@ var STATIONS = [
|
|
|
2141
4364
|
latitude: 37.6213,
|
|
2142
4365
|
longitude: -122.379,
|
|
2143
4366
|
name: "San Francisco International",
|
|
2144
|
-
tz: "America/Los_Angeles"
|
|
4367
|
+
tz: "America/Los_Angeles",
|
|
4368
|
+
venues: [
|
|
4369
|
+
"kalshi",
|
|
4370
|
+
"polymarket"
|
|
4371
|
+
]
|
|
4372
|
+
},
|
|
4373
|
+
{
|
|
4374
|
+
code: "SLC",
|
|
4375
|
+
country: "US",
|
|
4376
|
+
ghcnh_id: "USW00024127",
|
|
4377
|
+
icao: "KSLC",
|
|
4378
|
+
latitude: 40.7884,
|
|
4379
|
+
longitude: -111.9778,
|
|
4380
|
+
name: "Salt Lake City International",
|
|
4381
|
+
tz: "America/Denver",
|
|
4382
|
+
venues: [
|
|
4383
|
+
"kalshi"
|
|
4384
|
+
]
|
|
2145
4385
|
},
|
|
2146
4386
|
{
|
|
2147
4387
|
code: "LEBL",
|
|
@@ -2151,7 +4391,10 @@ var STATIONS = [
|
|
|
2151
4391
|
latitude: 41.2974,
|
|
2152
4392
|
longitude: 2.0833,
|
|
2153
4393
|
name: "Barcelona El Prat",
|
|
2154
|
-
tz: "Europe/Madrid"
|
|
4394
|
+
tz: "Europe/Madrid",
|
|
4395
|
+
venues: [
|
|
4396
|
+
"polymarket"
|
|
4397
|
+
]
|
|
2155
4398
|
},
|
|
2156
4399
|
{
|
|
2157
4400
|
code: "LEMD",
|
|
@@ -2161,7 +4404,10 @@ var STATIONS = [
|
|
|
2161
4404
|
latitude: 40.4719,
|
|
2162
4405
|
longitude: -3.5626,
|
|
2163
4406
|
name: "Madrid Barajas",
|
|
2164
|
-
tz: "Europe/Madrid"
|
|
4407
|
+
tz: "Europe/Madrid",
|
|
4408
|
+
venues: [
|
|
4409
|
+
"polymarket"
|
|
4410
|
+
]
|
|
2165
4411
|
},
|
|
2166
4412
|
{
|
|
2167
4413
|
code: "LFPB",
|
|
@@ -2171,7 +4417,10 @@ var STATIONS = [
|
|
|
2171
4417
|
latitude: 48.9694,
|
|
2172
4418
|
longitude: 2.4414,
|
|
2173
4419
|
name: "Paris Le Bourget",
|
|
2174
|
-
tz: "Europe/Paris"
|
|
4420
|
+
tz: "Europe/Paris",
|
|
4421
|
+
venues: [
|
|
4422
|
+
"polymarket"
|
|
4423
|
+
]
|
|
2175
4424
|
},
|
|
2176
4425
|
{
|
|
2177
4426
|
code: "LFPG",
|
|
@@ -2181,7 +4430,10 @@ var STATIONS = [
|
|
|
2181
4430
|
latitude: 49.0097,
|
|
2182
4431
|
longitude: 2.5479,
|
|
2183
4432
|
name: "Paris Charles de Gaulle",
|
|
2184
|
-
tz: "Europe/Paris"
|
|
4433
|
+
tz: "Europe/Paris",
|
|
4434
|
+
venues: [
|
|
4435
|
+
"polymarket"
|
|
4436
|
+
]
|
|
2185
4437
|
},
|
|
2186
4438
|
{
|
|
2187
4439
|
code: "LFPO",
|
|
@@ -2191,7 +4443,10 @@ var STATIONS = [
|
|
|
2191
4443
|
latitude: 48.7233,
|
|
2192
4444
|
longitude: 2.3794,
|
|
2193
4445
|
name: "Paris Orly",
|
|
2194
|
-
tz: "Europe/Paris"
|
|
4446
|
+
tz: "Europe/Paris",
|
|
4447
|
+
venues: [
|
|
4448
|
+
"polymarket"
|
|
4449
|
+
]
|
|
2195
4450
|
},
|
|
2196
4451
|
{
|
|
2197
4452
|
code: "LIMC",
|
|
@@ -2201,7 +4456,10 @@ var STATIONS = [
|
|
|
2201
4456
|
latitude: 45.6306,
|
|
2202
4457
|
longitude: 8.7281,
|
|
2203
4458
|
name: "Milan Malpensa",
|
|
2204
|
-
tz: "Europe/Rome"
|
|
4459
|
+
tz: "Europe/Rome",
|
|
4460
|
+
venues: [
|
|
4461
|
+
"polymarket"
|
|
4462
|
+
]
|
|
2205
4463
|
},
|
|
2206
4464
|
{
|
|
2207
4465
|
code: "LIRF",
|
|
@@ -2211,7 +4469,10 @@ var STATIONS = [
|
|
|
2211
4469
|
latitude: 41.8003,
|
|
2212
4470
|
longitude: 12.2389,
|
|
2213
4471
|
name: "Rome Fiumicino",
|
|
2214
|
-
tz: "Europe/Rome"
|
|
4472
|
+
tz: "Europe/Rome",
|
|
4473
|
+
venues: [
|
|
4474
|
+
"polymarket"
|
|
4475
|
+
]
|
|
2215
4476
|
},
|
|
2216
4477
|
{
|
|
2217
4478
|
code: "LOWW",
|
|
@@ -2221,7 +4482,10 @@ var STATIONS = [
|
|
|
2221
4482
|
latitude: 48.1103,
|
|
2222
4483
|
longitude: 16.5697,
|
|
2223
4484
|
name: "Vienna International",
|
|
2224
|
-
tz: "Europe/Vienna"
|
|
4485
|
+
tz: "Europe/Vienna",
|
|
4486
|
+
venues: [
|
|
4487
|
+
"polymarket"
|
|
4488
|
+
]
|
|
2225
4489
|
},
|
|
2226
4490
|
{
|
|
2227
4491
|
code: "LSZH",
|
|
@@ -2231,7 +4495,10 @@ var STATIONS = [
|
|
|
2231
4495
|
latitude: 47.4647,
|
|
2232
4496
|
longitude: 8.5492,
|
|
2233
4497
|
name: "Zurich",
|
|
2234
|
-
tz: "Europe/Zurich"
|
|
4498
|
+
tz: "Europe/Zurich",
|
|
4499
|
+
venues: [
|
|
4500
|
+
"polymarket"
|
|
4501
|
+
]
|
|
2235
4502
|
},
|
|
2236
4503
|
{
|
|
2237
4504
|
code: "NZAA",
|
|
@@ -2241,7 +4508,10 @@ var STATIONS = [
|
|
|
2241
4508
|
latitude: -37.0081,
|
|
2242
4509
|
longitude: 174.7917,
|
|
2243
4510
|
name: "Auckland",
|
|
2244
|
-
tz: "Pacific/Auckland"
|
|
4511
|
+
tz: "Pacific/Auckland",
|
|
4512
|
+
venues: [
|
|
4513
|
+
"polymarket"
|
|
4514
|
+
]
|
|
2245
4515
|
},
|
|
2246
4516
|
{
|
|
2247
4517
|
code: "NZWN",
|
|
@@ -2251,7 +4521,10 @@ var STATIONS = [
|
|
|
2251
4521
|
latitude: -41.3272,
|
|
2252
4522
|
longitude: 174.8053,
|
|
2253
4523
|
name: "Wellington",
|
|
2254
|
-
tz: "Pacific/Auckland"
|
|
4524
|
+
tz: "Pacific/Auckland",
|
|
4525
|
+
venues: [
|
|
4526
|
+
"polymarket"
|
|
4527
|
+
]
|
|
2255
4528
|
},
|
|
2256
4529
|
{
|
|
2257
4530
|
code: "OERK",
|
|
@@ -2261,7 +4534,10 @@ var STATIONS = [
|
|
|
2261
4534
|
latitude: 24.9576,
|
|
2262
4535
|
longitude: 46.6988,
|
|
2263
4536
|
name: "Riyadh King Khalid International",
|
|
2264
|
-
tz: "Asia/Riyadh"
|
|
4537
|
+
tz: "Asia/Riyadh",
|
|
4538
|
+
venues: [
|
|
4539
|
+
"polymarket"
|
|
4540
|
+
]
|
|
2265
4541
|
},
|
|
2266
4542
|
{
|
|
2267
4543
|
code: "OMDB",
|
|
@@ -2271,7 +4547,10 @@ var STATIONS = [
|
|
|
2271
4547
|
latitude: 25.2532,
|
|
2272
4548
|
longitude: 55.3657,
|
|
2273
4549
|
name: "Dubai International",
|
|
2274
|
-
tz: "Asia/Dubai"
|
|
4550
|
+
tz: "Asia/Dubai",
|
|
4551
|
+
venues: [
|
|
4552
|
+
"polymarket"
|
|
4553
|
+
]
|
|
2275
4554
|
},
|
|
2276
4555
|
{
|
|
2277
4556
|
code: "OTHH",
|
|
@@ -2281,7 +4560,10 @@ var STATIONS = [
|
|
|
2281
4560
|
latitude: 25.2731,
|
|
2282
4561
|
longitude: 51.608,
|
|
2283
4562
|
name: "Doha Hamad International",
|
|
2284
|
-
tz: "Asia/Qatar"
|
|
4563
|
+
tz: "Asia/Qatar",
|
|
4564
|
+
venues: [
|
|
4565
|
+
"polymarket"
|
|
4566
|
+
]
|
|
2285
4567
|
},
|
|
2286
4568
|
{
|
|
2287
4569
|
code: "RCTP",
|
|
@@ -2291,7 +4573,10 @@ var STATIONS = [
|
|
|
2291
4573
|
latitude: 25.0777,
|
|
2292
4574
|
longitude: 121.2328,
|
|
2293
4575
|
name: "Taipei Taoyuan",
|
|
2294
|
-
tz: "Asia/Taipei"
|
|
4576
|
+
tz: "Asia/Taipei",
|
|
4577
|
+
venues: [
|
|
4578
|
+
"polymarket"
|
|
4579
|
+
]
|
|
2295
4580
|
},
|
|
2296
4581
|
{
|
|
2297
4582
|
code: "RJAA",
|
|
@@ -2301,7 +4586,10 @@ var STATIONS = [
|
|
|
2301
4586
|
latitude: 35.7647,
|
|
2302
4587
|
longitude: 140.3864,
|
|
2303
4588
|
name: "Tokyo Narita",
|
|
2304
|
-
tz: "Asia/Tokyo"
|
|
4589
|
+
tz: "Asia/Tokyo",
|
|
4590
|
+
venues: [
|
|
4591
|
+
"polymarket"
|
|
4592
|
+
]
|
|
2305
4593
|
},
|
|
2306
4594
|
{
|
|
2307
4595
|
code: "RJTT",
|
|
@@ -2311,7 +4599,10 @@ var STATIONS = [
|
|
|
2311
4599
|
latitude: 35.5522,
|
|
2312
4600
|
longitude: 139.78,
|
|
2313
4601
|
name: "Tokyo Haneda",
|
|
2314
|
-
tz: "Asia/Tokyo"
|
|
4602
|
+
tz: "Asia/Tokyo",
|
|
4603
|
+
venues: [
|
|
4604
|
+
"polymarket"
|
|
4605
|
+
]
|
|
2315
4606
|
},
|
|
2316
4607
|
{
|
|
2317
4608
|
code: "RKSI",
|
|
@@ -2321,7 +4612,10 @@ var STATIONS = [
|
|
|
2321
4612
|
latitude: 37.4691,
|
|
2322
4613
|
longitude: 126.4505,
|
|
2323
4614
|
name: "Seoul Incheon",
|
|
2324
|
-
tz: "Asia/Seoul"
|
|
4615
|
+
tz: "Asia/Seoul",
|
|
4616
|
+
venues: [
|
|
4617
|
+
"polymarket"
|
|
4618
|
+
]
|
|
2325
4619
|
},
|
|
2326
4620
|
{
|
|
2327
4621
|
code: "SAEZ",
|
|
@@ -2331,7 +4625,10 @@ var STATIONS = [
|
|
|
2331
4625
|
latitude: -34.8222,
|
|
2332
4626
|
longitude: -58.5358,
|
|
2333
4627
|
name: "Buenos Aires Ezeiza",
|
|
2334
|
-
tz: "America/Argentina/Buenos_Aires"
|
|
4628
|
+
tz: "America/Argentina/Buenos_Aires",
|
|
4629
|
+
venues: [
|
|
4630
|
+
"polymarket"
|
|
4631
|
+
]
|
|
2335
4632
|
},
|
|
2336
4633
|
{
|
|
2337
4634
|
code: "SBGR",
|
|
@@ -2341,7 +4638,10 @@ var STATIONS = [
|
|
|
2341
4638
|
latitude: -23.4356,
|
|
2342
4639
|
longitude: -46.4731,
|
|
2343
4640
|
name: "S\xE3o Paulo Guarulhos",
|
|
2344
|
-
tz: "America/Sao_Paulo"
|
|
4641
|
+
tz: "America/Sao_Paulo",
|
|
4642
|
+
venues: [
|
|
4643
|
+
"polymarket"
|
|
4644
|
+
]
|
|
2345
4645
|
},
|
|
2346
4646
|
{
|
|
2347
4647
|
code: "UUEE",
|
|
@@ -2351,7 +4651,10 @@ var STATIONS = [
|
|
|
2351
4651
|
latitude: 55.9728,
|
|
2352
4652
|
longitude: 37.4147,
|
|
2353
4653
|
name: "Moscow Sheremetyevo",
|
|
2354
|
-
tz: "Europe/Moscow"
|
|
4654
|
+
tz: "Europe/Moscow",
|
|
4655
|
+
venues: [
|
|
4656
|
+
"polymarket"
|
|
4657
|
+
]
|
|
2355
4658
|
},
|
|
2356
4659
|
{
|
|
2357
4660
|
code: "VABB",
|
|
@@ -2361,7 +4664,10 @@ var STATIONS = [
|
|
|
2361
4664
|
latitude: 19.0887,
|
|
2362
4665
|
longitude: 72.8679,
|
|
2363
4666
|
name: "Mumbai Chhatrapati Shivaji",
|
|
2364
|
-
tz: "Asia/Kolkata"
|
|
4667
|
+
tz: "Asia/Kolkata",
|
|
4668
|
+
venues: [
|
|
4669
|
+
"polymarket"
|
|
4670
|
+
]
|
|
2365
4671
|
},
|
|
2366
4672
|
{
|
|
2367
4673
|
code: "VHHH",
|
|
@@ -2371,7 +4677,10 @@ var STATIONS = [
|
|
|
2371
4677
|
latitude: 22.308,
|
|
2372
4678
|
longitude: 113.9185,
|
|
2373
4679
|
name: "Hong Kong International",
|
|
2374
|
-
tz: "Asia/Hong_Kong"
|
|
4680
|
+
tz: "Asia/Hong_Kong",
|
|
4681
|
+
venues: [
|
|
4682
|
+
"polymarket"
|
|
4683
|
+
]
|
|
2375
4684
|
},
|
|
2376
4685
|
{
|
|
2377
4686
|
code: "VIDP",
|
|
@@ -2381,7 +4690,10 @@ var STATIONS = [
|
|
|
2381
4690
|
latitude: 28.5562,
|
|
2382
4691
|
longitude: 77.1,
|
|
2383
4692
|
name: "Delhi Indira Gandhi",
|
|
2384
|
-
tz: "Asia/Kolkata"
|
|
4693
|
+
tz: "Asia/Kolkata",
|
|
4694
|
+
venues: [
|
|
4695
|
+
"polymarket"
|
|
4696
|
+
]
|
|
2385
4697
|
},
|
|
2386
4698
|
{
|
|
2387
4699
|
code: "VTBS",
|
|
@@ -2391,7 +4703,10 @@ var STATIONS = [
|
|
|
2391
4703
|
latitude: 13.69,
|
|
2392
4704
|
longitude: 100.7501,
|
|
2393
4705
|
name: "Bangkok Suvarnabhumi",
|
|
2394
|
-
tz: "Asia/Bangkok"
|
|
4706
|
+
tz: "Asia/Bangkok",
|
|
4707
|
+
venues: [
|
|
4708
|
+
"polymarket"
|
|
4709
|
+
]
|
|
2395
4710
|
},
|
|
2396
4711
|
{
|
|
2397
4712
|
code: "WSSS",
|
|
@@ -2401,7 +4716,10 @@ var STATIONS = [
|
|
|
2401
4716
|
latitude: 1.3644,
|
|
2402
4717
|
longitude: 103.9915,
|
|
2403
4718
|
name: "Singapore Changi",
|
|
2404
|
-
tz: "Asia/Singapore"
|
|
4719
|
+
tz: "Asia/Singapore",
|
|
4720
|
+
venues: [
|
|
4721
|
+
"polymarket"
|
|
4722
|
+
]
|
|
2405
4723
|
},
|
|
2406
4724
|
{
|
|
2407
4725
|
code: "YBBN",
|
|
@@ -2411,7 +4729,10 @@ var STATIONS = [
|
|
|
2411
4729
|
latitude: -27.3842,
|
|
2412
4730
|
longitude: 153.1175,
|
|
2413
4731
|
name: "Brisbane",
|
|
2414
|
-
tz: "Australia/Brisbane"
|
|
4732
|
+
tz: "Australia/Brisbane",
|
|
4733
|
+
venues: [
|
|
4734
|
+
"polymarket"
|
|
4735
|
+
]
|
|
2415
4736
|
},
|
|
2416
4737
|
{
|
|
2417
4738
|
code: "YMML",
|
|
@@ -2421,7 +4742,10 @@ var STATIONS = [
|
|
|
2421
4742
|
latitude: -37.6733,
|
|
2422
4743
|
longitude: 144.8433,
|
|
2423
4744
|
name: "Melbourne Tullamarine",
|
|
2424
|
-
tz: "Australia/Melbourne"
|
|
4745
|
+
tz: "Australia/Melbourne",
|
|
4746
|
+
venues: [
|
|
4747
|
+
"polymarket"
|
|
4748
|
+
]
|
|
2425
4749
|
},
|
|
2426
4750
|
{
|
|
2427
4751
|
code: "YSSY",
|
|
@@ -2431,7 +4755,10 @@ var STATIONS = [
|
|
|
2431
4755
|
latitude: -33.9461,
|
|
2432
4756
|
longitude: 151.1772,
|
|
2433
4757
|
name: "Sydney Kingsford Smith",
|
|
2434
|
-
tz: "Australia/Sydney"
|
|
4758
|
+
tz: "Australia/Sydney",
|
|
4759
|
+
venues: [
|
|
4760
|
+
"polymarket"
|
|
4761
|
+
]
|
|
2435
4762
|
},
|
|
2436
4763
|
{
|
|
2437
4764
|
code: "ZBAA",
|
|
@@ -2441,7 +4768,10 @@ var STATIONS = [
|
|
|
2441
4768
|
latitude: 40.0801,
|
|
2442
4769
|
longitude: 116.5846,
|
|
2443
4770
|
name: "Beijing Capital",
|
|
2444
|
-
tz: "Asia/Shanghai"
|
|
4771
|
+
tz: "Asia/Shanghai",
|
|
4772
|
+
venues: [
|
|
4773
|
+
"polymarket"
|
|
4774
|
+
]
|
|
2445
4775
|
},
|
|
2446
4776
|
{
|
|
2447
4777
|
code: "ZSPD",
|
|
@@ -2451,134 +4781,147 @@ var STATIONS = [
|
|
|
2451
4781
|
latitude: 31.1443,
|
|
2452
4782
|
longitude: 121.8083,
|
|
2453
4783
|
name: "Shanghai Pudong",
|
|
2454
|
-
tz: "Asia/Shanghai"
|
|
4784
|
+
tz: "Asia/Shanghai",
|
|
4785
|
+
venues: [
|
|
4786
|
+
"polymarket"
|
|
4787
|
+
]
|
|
2455
4788
|
}
|
|
2456
4789
|
];
|
|
2457
|
-
var
|
|
2458
|
-
["ATL",
|
|
2459
|
-
["AUS",
|
|
2460
|
-
["
|
|
2461
|
-
["
|
|
2462
|
-
["
|
|
2463
|
-
["
|
|
2464
|
-
["
|
|
2465
|
-
["
|
|
2466
|
-
["
|
|
2467
|
-
["
|
|
2468
|
-
["
|
|
2469
|
-
["
|
|
2470
|
-
["
|
|
2471
|
-
["
|
|
2472
|
-
["
|
|
2473
|
-
["
|
|
2474
|
-
["
|
|
2475
|
-
["
|
|
2476
|
-
["
|
|
2477
|
-
["
|
|
2478
|
-
["
|
|
2479
|
-
["
|
|
2480
|
-
["
|
|
2481
|
-
["
|
|
2482
|
-
["
|
|
2483
|
-
["
|
|
2484
|
-
["
|
|
2485
|
-
["
|
|
2486
|
-
["
|
|
2487
|
-
["
|
|
2488
|
-
["
|
|
2489
|
-
["
|
|
2490
|
-
["
|
|
2491
|
-
["
|
|
2492
|
-
["
|
|
2493
|
-
["
|
|
2494
|
-
["
|
|
2495
|
-
["
|
|
2496
|
-
["
|
|
2497
|
-
["
|
|
2498
|
-
["
|
|
2499
|
-
["
|
|
2500
|
-
["
|
|
2501
|
-
["
|
|
2502
|
-
["
|
|
2503
|
-
["
|
|
2504
|
-
["
|
|
2505
|
-
["
|
|
2506
|
-
["
|
|
2507
|
-
["
|
|
2508
|
-
["
|
|
2509
|
-
["
|
|
2510
|
-
["
|
|
2511
|
-
["
|
|
2512
|
-
["
|
|
2513
|
-
["
|
|
2514
|
-
["
|
|
2515
|
-
["
|
|
2516
|
-
["
|
|
2517
|
-
["
|
|
2518
|
-
["
|
|
4790
|
+
var STATION_BY_CODE3 = /* @__PURE__ */ new Map([
|
|
4791
|
+
["ATL", STATIONS3[10]],
|
|
4792
|
+
["AUS", STATIONS3[11]],
|
|
4793
|
+
["BNA", STATIONS3[12]],
|
|
4794
|
+
["BOS", STATIONS3[13]],
|
|
4795
|
+
["CVG", STATIONS3[14]],
|
|
4796
|
+
["DCA", STATIONS3[15]],
|
|
4797
|
+
["DEN", STATIONS3[16]],
|
|
4798
|
+
["DFW", STATIONS3[17]],
|
|
4799
|
+
["DTW", STATIONS3[18]],
|
|
4800
|
+
["EDDB", STATIONS3[0]],
|
|
4801
|
+
["EDDF", STATIONS3[1]],
|
|
4802
|
+
["EDDM", STATIONS3[2]],
|
|
4803
|
+
["EFHK", STATIONS3[3]],
|
|
4804
|
+
["EGKK", STATIONS3[4]],
|
|
4805
|
+
["EGLL", STATIONS3[5]],
|
|
4806
|
+
["EHAM", STATIONS3[6]],
|
|
4807
|
+
["EKCH", STATIONS3[7]],
|
|
4808
|
+
["EPWA", STATIONS3[8]],
|
|
4809
|
+
["ESSA", STATIONS3[9]],
|
|
4810
|
+
["HOU", STATIONS3[19]],
|
|
4811
|
+
["IAH", STATIONS3[20]],
|
|
4812
|
+
["LAS", STATIONS3[21]],
|
|
4813
|
+
["LAX", STATIONS3[22]],
|
|
4814
|
+
["LEBL", STATIONS3[35]],
|
|
4815
|
+
["LEMD", STATIONS3[36]],
|
|
4816
|
+
["LFPB", STATIONS3[37]],
|
|
4817
|
+
["LFPG", STATIONS3[38]],
|
|
4818
|
+
["LFPO", STATIONS3[39]],
|
|
4819
|
+
["LIMC", STATIONS3[40]],
|
|
4820
|
+
["LIRF", STATIONS3[41]],
|
|
4821
|
+
["LOWW", STATIONS3[42]],
|
|
4822
|
+
["LSZH", STATIONS3[43]],
|
|
4823
|
+
["MDW", STATIONS3[23]],
|
|
4824
|
+
["MIA", STATIONS3[24]],
|
|
4825
|
+
["MSP", STATIONS3[25]],
|
|
4826
|
+
["MSY", STATIONS3[26]],
|
|
4827
|
+
["NYC", STATIONS3[27]],
|
|
4828
|
+
["NZAA", STATIONS3[44]],
|
|
4829
|
+
["NZWN", STATIONS3[45]],
|
|
4830
|
+
["OERK", STATIONS3[46]],
|
|
4831
|
+
["OKC", STATIONS3[28]],
|
|
4832
|
+
["OMDB", STATIONS3[47]],
|
|
4833
|
+
["OTHH", STATIONS3[48]],
|
|
4834
|
+
["PHL", STATIONS3[29]],
|
|
4835
|
+
["PHX", STATIONS3[30]],
|
|
4836
|
+
["RCTP", STATIONS3[49]],
|
|
4837
|
+
["RJAA", STATIONS3[50]],
|
|
4838
|
+
["RJTT", STATIONS3[51]],
|
|
4839
|
+
["RKSI", STATIONS3[52]],
|
|
4840
|
+
["SAEZ", STATIONS3[53]],
|
|
4841
|
+
["SAT", STATIONS3[31]],
|
|
4842
|
+
["SBGR", STATIONS3[54]],
|
|
4843
|
+
["SEA", STATIONS3[32]],
|
|
4844
|
+
["SFO", STATIONS3[33]],
|
|
4845
|
+
["SLC", STATIONS3[34]],
|
|
4846
|
+
["UUEE", STATIONS3[55]],
|
|
4847
|
+
["VABB", STATIONS3[56]],
|
|
4848
|
+
["VHHH", STATIONS3[57]],
|
|
4849
|
+
["VIDP", STATIONS3[58]],
|
|
4850
|
+
["VTBS", STATIONS3[59]],
|
|
4851
|
+
["WSSS", STATIONS3[60]],
|
|
4852
|
+
["YBBN", STATIONS3[61]],
|
|
4853
|
+
["YMML", STATIONS3[62]],
|
|
4854
|
+
["YSSY", STATIONS3[63]],
|
|
4855
|
+
["ZBAA", STATIONS3[64]],
|
|
4856
|
+
["ZSPD", STATIONS3[65]]
|
|
2519
4857
|
]);
|
|
2520
|
-
var
|
|
2521
|
-
["EDDB",
|
|
2522
|
-
["EDDF",
|
|
2523
|
-
["EDDM",
|
|
2524
|
-
["EFHK",
|
|
2525
|
-
["EGKK",
|
|
2526
|
-
["EGLL",
|
|
2527
|
-
["EHAM",
|
|
2528
|
-
["EKCH",
|
|
2529
|
-
["EPWA",
|
|
2530
|
-
["ESSA",
|
|
2531
|
-
["KATL",
|
|
2532
|
-
["KAUS",
|
|
2533
|
-
["
|
|
2534
|
-
["
|
|
2535
|
-
["
|
|
2536
|
-
["
|
|
2537
|
-
["
|
|
2538
|
-
["
|
|
2539
|
-
["
|
|
2540
|
-
["
|
|
2541
|
-
["
|
|
2542
|
-
["
|
|
2543
|
-
["
|
|
2544
|
-
["
|
|
2545
|
-
["
|
|
2546
|
-
["
|
|
2547
|
-
["
|
|
2548
|
-
["
|
|
2549
|
-
["
|
|
2550
|
-
["
|
|
2551
|
-
["
|
|
2552
|
-
["
|
|
2553
|
-
["
|
|
2554
|
-
["
|
|
2555
|
-
["
|
|
2556
|
-
["
|
|
2557
|
-
["
|
|
2558
|
-
["
|
|
2559
|
-
["
|
|
2560
|
-
["
|
|
2561
|
-
["
|
|
2562
|
-
["
|
|
2563
|
-
["
|
|
2564
|
-
["
|
|
2565
|
-
["
|
|
2566
|
-
["
|
|
2567
|
-
["
|
|
2568
|
-
["
|
|
2569
|
-
["
|
|
2570
|
-
["
|
|
2571
|
-
["
|
|
2572
|
-
["
|
|
2573
|
-
["
|
|
2574
|
-
["
|
|
2575
|
-
["
|
|
2576
|
-
["
|
|
2577
|
-
["
|
|
2578
|
-
["
|
|
2579
|
-
["
|
|
2580
|
-
["
|
|
2581
|
-
["
|
|
4858
|
+
var STATION_BY_ICAO3 = /* @__PURE__ */ new Map([
|
|
4859
|
+
["EDDB", STATIONS3[0]],
|
|
4860
|
+
["EDDF", STATIONS3[1]],
|
|
4861
|
+
["EDDM", STATIONS3[2]],
|
|
4862
|
+
["EFHK", STATIONS3[3]],
|
|
4863
|
+
["EGKK", STATIONS3[4]],
|
|
4864
|
+
["EGLL", STATIONS3[5]],
|
|
4865
|
+
["EHAM", STATIONS3[6]],
|
|
4866
|
+
["EKCH", STATIONS3[7]],
|
|
4867
|
+
["EPWA", STATIONS3[8]],
|
|
4868
|
+
["ESSA", STATIONS3[9]],
|
|
4869
|
+
["KATL", STATIONS3[10]],
|
|
4870
|
+
["KAUS", STATIONS3[11]],
|
|
4871
|
+
["KBNA", STATIONS3[12]],
|
|
4872
|
+
["KBOS", STATIONS3[13]],
|
|
4873
|
+
["KCVG", STATIONS3[14]],
|
|
4874
|
+
["KDCA", STATIONS3[15]],
|
|
4875
|
+
["KDEN", STATIONS3[16]],
|
|
4876
|
+
["KDFW", STATIONS3[17]],
|
|
4877
|
+
["KDTW", STATIONS3[18]],
|
|
4878
|
+
["KHOU", STATIONS3[19]],
|
|
4879
|
+
["KIAH", STATIONS3[20]],
|
|
4880
|
+
["KLAS", STATIONS3[21]],
|
|
4881
|
+
["KLAX", STATIONS3[22]],
|
|
4882
|
+
["KMDW", STATIONS3[23]],
|
|
4883
|
+
["KMIA", STATIONS3[24]],
|
|
4884
|
+
["KMSP", STATIONS3[25]],
|
|
4885
|
+
["KMSY", STATIONS3[26]],
|
|
4886
|
+
["KNYC", STATIONS3[27]],
|
|
4887
|
+
["KOKC", STATIONS3[28]],
|
|
4888
|
+
["KPHL", STATIONS3[29]],
|
|
4889
|
+
["KPHX", STATIONS3[30]],
|
|
4890
|
+
["KSAT", STATIONS3[31]],
|
|
4891
|
+
["KSEA", STATIONS3[32]],
|
|
4892
|
+
["KSFO", STATIONS3[33]],
|
|
4893
|
+
["KSLC", STATIONS3[34]],
|
|
4894
|
+
["LEBL", STATIONS3[35]],
|
|
4895
|
+
["LEMD", STATIONS3[36]],
|
|
4896
|
+
["LFPB", STATIONS3[37]],
|
|
4897
|
+
["LFPG", STATIONS3[38]],
|
|
4898
|
+
["LFPO", STATIONS3[39]],
|
|
4899
|
+
["LIMC", STATIONS3[40]],
|
|
4900
|
+
["LIRF", STATIONS3[41]],
|
|
4901
|
+
["LOWW", STATIONS3[42]],
|
|
4902
|
+
["LSZH", STATIONS3[43]],
|
|
4903
|
+
["NZAA", STATIONS3[44]],
|
|
4904
|
+
["NZWN", STATIONS3[45]],
|
|
4905
|
+
["OERK", STATIONS3[46]],
|
|
4906
|
+
["OMDB", STATIONS3[47]],
|
|
4907
|
+
["OTHH", STATIONS3[48]],
|
|
4908
|
+
["RCTP", STATIONS3[49]],
|
|
4909
|
+
["RJAA", STATIONS3[50]],
|
|
4910
|
+
["RJTT", STATIONS3[51]],
|
|
4911
|
+
["RKSI", STATIONS3[52]],
|
|
4912
|
+
["SAEZ", STATIONS3[53]],
|
|
4913
|
+
["SBGR", STATIONS3[54]],
|
|
4914
|
+
["UUEE", STATIONS3[55]],
|
|
4915
|
+
["VABB", STATIONS3[56]],
|
|
4916
|
+
["VHHH", STATIONS3[57]],
|
|
4917
|
+
["VIDP", STATIONS3[58]],
|
|
4918
|
+
["VTBS", STATIONS3[59]],
|
|
4919
|
+
["WSSS", STATIONS3[60]],
|
|
4920
|
+
["YBBN", STATIONS3[61]],
|
|
4921
|
+
["YMML", STATIONS3[62]],
|
|
4922
|
+
["YSSY", STATIONS3[63]],
|
|
4923
|
+
["ZBAA", STATIONS3[64]],
|
|
4924
|
+
["ZSPD", STATIONS3[65]]
|
|
2582
4925
|
]);
|
|
2583
4926
|
var _STATION_TZ = Object.freeze({
|
|
2584
4927
|
// Eastern (UTC-5 standard / UTC-4 DST)
|
|
@@ -2725,13 +5068,13 @@ function _lstOffsetHours(stationTz) {
|
|
|
2725
5068
|
}
|
|
2726
5069
|
function _lstOffsetHoursFor(station) {
|
|
2727
5070
|
const upper = station.trim().toUpperCase();
|
|
2728
|
-
const byCode =
|
|
5071
|
+
const byCode = STATION_BY_CODE3.get(upper);
|
|
2729
5072
|
if (byCode !== void 0) return _lstOffsetHours(byCode.tz);
|
|
2730
|
-
const byIcao =
|
|
5073
|
+
const byIcao = STATION_BY_ICAO3.get(upper);
|
|
2731
5074
|
if (byIcao !== void 0) return _lstOffsetHours(byIcao.tz);
|
|
2732
5075
|
if (upper.length === 4 && upper.startsWith("K")) {
|
|
2733
5076
|
const stripped = upper.slice(1);
|
|
2734
|
-
const retry =
|
|
5077
|
+
const retry = STATION_BY_CODE3.get(stripped);
|
|
2735
5078
|
if (retry !== void 0) return _lstOffsetHours(retry.tz);
|
|
2736
5079
|
}
|
|
2737
5080
|
throw new RangeError(`unknown station: ${JSON.stringify(station)}`);
|
|
@@ -2803,8 +5146,8 @@ function cacheKeyForClimate(station, year) {
|
|
|
2803
5146
|
|
|
2804
5147
|
// ../core/dist/internal/cache/index.browser.mjs
|
|
2805
5148
|
async function defaultCacheStore() {
|
|
2806
|
-
|
|
2807
|
-
return
|
|
5149
|
+
const inner = typeof indexedDB !== "undefined" ? new IndexedDBStore() : new MemoryStore();
|
|
5150
|
+
return versionedCacheStore(inner, CACHE_SCHEMA_VERSION);
|
|
2808
5151
|
}
|
|
2809
5152
|
|
|
2810
5153
|
// ../core/dist/internal/pairs.mjs
|
|
@@ -2990,9 +5333,9 @@ function marketCloseUtc(dateStr, station, tzOverride) {
|
|
|
2990
5333
|
);
|
|
2991
5334
|
return new Date(marketCloseAsUtcMs - offsetHours * 36e5);
|
|
2992
5335
|
}
|
|
2993
|
-
function collectNonNull(
|
|
5336
|
+
function collectNonNull(obs2, key) {
|
|
2994
5337
|
const out = [];
|
|
2995
|
-
for (const o of
|
|
5338
|
+
for (const o of obs2) {
|
|
2996
5339
|
const v = o[key];
|
|
2997
5340
|
if (typeof v === "number" && Number.isFinite(v)) out.push(v);
|
|
2998
5341
|
}
|
|
@@ -3087,13 +5430,68 @@ function buildPairsRow(dateStr, station, observations, climate, opts = {}) {
|
|
|
3087
5430
|
function buildPairs(station, dates, observationsByDate, climateByDate, opts = {}) {
|
|
3088
5431
|
const out = [];
|
|
3089
5432
|
for (const date of dates) {
|
|
3090
|
-
const
|
|
5433
|
+
const obs2 = observationsByDate[date] ?? [];
|
|
3091
5434
|
const climate = climateByDate[date] ?? null;
|
|
3092
|
-
out.push(buildPairsRow(date, station,
|
|
5435
|
+
out.push(buildPairsRow(date, station, obs2, climate, opts));
|
|
3093
5436
|
}
|
|
3094
5437
|
return Object.freeze(out);
|
|
3095
5438
|
}
|
|
3096
5439
|
|
|
5440
|
+
// src/research.types.ts
|
|
5441
|
+
var KNOWN_RESEARCH_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
5442
|
+
// Pre-Phase-21 fetcher controls.
|
|
5443
|
+
"signal",
|
|
5444
|
+
"awcHours",
|
|
5445
|
+
"iemPolitenessMs",
|
|
5446
|
+
"ghcnhPolitenessMs",
|
|
5447
|
+
"cliPolitenessMs",
|
|
5448
|
+
"now",
|
|
5449
|
+
"cache",
|
|
5450
|
+
// Pre-Phase-21 selectors.
|
|
5451
|
+
"city",
|
|
5452
|
+
"contract",
|
|
5453
|
+
"contracts",
|
|
5454
|
+
"stationOverride",
|
|
5455
|
+
"sources",
|
|
5456
|
+
"source",
|
|
5457
|
+
"includeTrades",
|
|
5458
|
+
"onWarning",
|
|
5459
|
+
// Phase 21 21-01: Python-parity composable kwargs.
|
|
5460
|
+
"include_forecast",
|
|
5461
|
+
"forecast_model",
|
|
5462
|
+
"forecast_models",
|
|
5463
|
+
"qc",
|
|
5464
|
+
"tz_override",
|
|
5465
|
+
"backend",
|
|
5466
|
+
"return_type"
|
|
5467
|
+
]);
|
|
5468
|
+
function validateResearchKwargs(opts) {
|
|
5469
|
+
const present = (v) => v !== void 0 && v !== null;
|
|
5470
|
+
for (const key of Object.keys(opts)) {
|
|
5471
|
+
if (!KNOWN_RESEARCH_OPTION_KEYS.has(key)) {
|
|
5472
|
+
throw new TypeError(
|
|
5473
|
+
`research(): unknown option key ${JSON.stringify(key)}. Valid keys: ${[...KNOWN_RESEARCH_OPTION_KEYS].sort().join(", ")}`
|
|
5474
|
+
);
|
|
5475
|
+
}
|
|
5476
|
+
}
|
|
5477
|
+
if (present(opts.sources) && present(opts.source)) {
|
|
5478
|
+
throw new TypeError(
|
|
5479
|
+
"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"
|
|
5480
|
+
);
|
|
5481
|
+
}
|
|
5482
|
+
if (present(opts.forecast_model) && present(opts.forecast_models)) {
|
|
5483
|
+
throw new TypeError(
|
|
5484
|
+
"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"
|
|
5485
|
+
);
|
|
5486
|
+
}
|
|
5487
|
+
const wantsForecast = present(opts.forecast_model) || present(opts.forecast_models);
|
|
5488
|
+
if (wantsForecast && opts.include_forecast !== true) {
|
|
5489
|
+
throw new TypeError(
|
|
5490
|
+
"research(): forecast_model=/forecast_models= require include_forecast=true; the model filter is otherwise silently ignored"
|
|
5491
|
+
);
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
|
|
3097
5495
|
// src/research.ts
|
|
3098
5496
|
var AWC_MAX_HOURS2 = 168;
|
|
3099
5497
|
async function resolveCache(opts) {
|
|
@@ -3361,9 +5759,9 @@ async function fetchIemAsosWithCache(stationCode, _fromYear, _extendedToYear, fr
|
|
|
3361
5759
|
}
|
|
3362
5760
|
}
|
|
3363
5761
|
}
|
|
3364
|
-
for (const
|
|
3365
|
-
const obsDate =
|
|
3366
|
-
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(
|
|
5762
|
+
for (const obs2 of monthRows) {
|
|
5763
|
+
const obsDate = obs2.observed_at.slice(0, 10);
|
|
5764
|
+
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs2);
|
|
3367
5765
|
}
|
|
3368
5766
|
}
|
|
3369
5767
|
return acc;
|
|
@@ -3434,14 +5832,22 @@ async function fetchGhcnhWithCache(stationCode, ghcnhId, fromDate, extendedTo, o
|
|
|
3434
5832
|
}
|
|
3435
5833
|
}
|
|
3436
5834
|
}
|
|
3437
|
-
for (const
|
|
3438
|
-
const obsDate =
|
|
3439
|
-
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(
|
|
5835
|
+
for (const obs2 of monthRows) {
|
|
5836
|
+
const obsDate = obs2.observed_at.slice(0, 10);
|
|
5837
|
+
if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs2);
|
|
3440
5838
|
}
|
|
3441
5839
|
}
|
|
3442
5840
|
return acc;
|
|
3443
5841
|
}
|
|
3444
5842
|
async function research(station, fromDate, toDate, opts = {}) {
|
|
5843
|
+
validateResearchKwargs(opts);
|
|
5844
|
+
if (opts.backend === "polars") {
|
|
5845
|
+
throw new DataAvailabilityError({
|
|
5846
|
+
reason: "model_unavailable",
|
|
5847
|
+
hint: 'polars backend not available in TypeScript SDK; use Python (mostlyrightmd) for backend="polars". TS returns plain object arrays.',
|
|
5848
|
+
source: "research.backend"
|
|
5849
|
+
});
|
|
5850
|
+
}
|
|
3445
5851
|
const hasCity = typeof opts.city === "string" && opts.city.length > 0;
|
|
3446
5852
|
const hasContract = typeof opts.contract === "string" && opts.contract.length > 0;
|
|
3447
5853
|
const hasContracts = Array.isArray(opts.contracts) && opts.contracts.length > 0;
|
|
@@ -3517,8 +5923,8 @@ async function research(station, fromDate, toDate, opts = {}) {
|
|
|
3517
5923
|
if (opts.signal !== void 0) awcOpts.signal = opts.signal;
|
|
3518
5924
|
const awcRaw = await fetchAwcMetars([resolved.icao], awcOpts);
|
|
3519
5925
|
for (const m of awcRaw) {
|
|
3520
|
-
const
|
|
3521
|
-
if (
|
|
5926
|
+
const obs2 = awcToObservation(m);
|
|
5927
|
+
if (obs2 !== null) awcRows.push(obs2);
|
|
3522
5928
|
}
|
|
3523
5929
|
}
|
|
3524
5930
|
const iemRows = await fetchIemAsosWithCache(
|
|
@@ -3549,8 +5955,8 @@ async function research(station, fromDate, toDate, opts = {}) {
|
|
|
3549
5955
|
const observationsByDate = {};
|
|
3550
5956
|
const dateLo = dates[0] ?? "";
|
|
3551
5957
|
const dateHi = dates[dates.length - 1] ?? "";
|
|
3552
|
-
for (const
|
|
3553
|
-
const settleDate = observedSettlementDate(
|
|
5958
|
+
for (const obs2 of merged) {
|
|
5959
|
+
const settleDate = observedSettlementDate(obs2.observed_at, resolved.code);
|
|
3554
5960
|
if (settleDate === null) continue;
|
|
3555
5961
|
if (settleDate < dateLo || settleDate > dateHi) continue;
|
|
3556
5962
|
let bucket = observationsByDate[settleDate];
|
|
@@ -3558,7 +5964,7 @@ async function research(station, fromDate, toDate, opts = {}) {
|
|
|
3558
5964
|
bucket = [];
|
|
3559
5965
|
observationsByDate[settleDate] = bucket;
|
|
3560
5966
|
}
|
|
3561
|
-
bucket.push(
|
|
5967
|
+
bucket.push(obs2);
|
|
3562
5968
|
}
|
|
3563
5969
|
const climateByDate = {};
|
|
3564
5970
|
for (const cli of mergedClimate) {
|
|
@@ -3692,8 +6098,8 @@ async function researchBySource(station, source, fromDate, toDate, opts = {}) {
|
|
|
3692
6098
|
const raw = await fetchAwcMetars([resolved.icao], awcOpts);
|
|
3693
6099
|
const parsed = [];
|
|
3694
6100
|
for (const m of raw) {
|
|
3695
|
-
const
|
|
3696
|
-
if (
|
|
6101
|
+
const obs2 = awcToObservation(m);
|
|
6102
|
+
if (obs2 !== null) parsed.push(obs2);
|
|
3697
6103
|
}
|
|
3698
6104
|
rows = parsed.filter((r) => {
|
|
3699
6105
|
const d = r.observed_at.slice(0, 10);
|
|
@@ -3983,13 +6389,135 @@ function discover(args) {
|
|
|
3983
6389
|
});
|
|
3984
6390
|
}
|
|
3985
6391
|
|
|
6392
|
+
// ../core/dist/preprocessing/index.mjs
|
|
6393
|
+
var preprocessing_exports = {};
|
|
6394
|
+
__export(preprocessing_exports, {
|
|
6395
|
+
PHYSICS_BOUNDS: () => PHYSICS_BOUNDS,
|
|
6396
|
+
clipOutliers: () => clipOutliers,
|
|
6397
|
+
iemCrosscheck: () => crosscheckIemGhcnh
|
|
6398
|
+
});
|
|
6399
|
+
var PHYSICS_BOUNDS = /* @__PURE__ */ new Map([
|
|
6400
|
+
["temp_c", [-89, 57]],
|
|
6401
|
+
["dew_point_c", [-89, 35]],
|
|
6402
|
+
["dewpoint_c", [-89, 35]],
|
|
6403
|
+
["wind_speed_ms", [0, 100]],
|
|
6404
|
+
["wind_speed_kt", [0, 200]],
|
|
6405
|
+
["wind_dir_deg", [0, 360]],
|
|
6406
|
+
["wind_dir_degrees", [0, 360]],
|
|
6407
|
+
["slp_hpa", [870, 1085]],
|
|
6408
|
+
["sea_level_pressure_mb", [870, 1085]],
|
|
6409
|
+
["relative_humidity_pct_2m", [0, 100]],
|
|
6410
|
+
["precip_mm_1h", [0, 305]]
|
|
6411
|
+
]);
|
|
6412
|
+
function clipOutliers(rows, col, opts = {}) {
|
|
6413
|
+
const std = opts.std ?? 3;
|
|
6414
|
+
const key = `${col}_clipped`;
|
|
6415
|
+
let lo;
|
|
6416
|
+
let hi;
|
|
6417
|
+
let passThrough = false;
|
|
6418
|
+
if (opts.bounds !== void 0) {
|
|
6419
|
+
[lo, hi] = opts.bounds;
|
|
6420
|
+
} else if (PHYSICS_BOUNDS.has(col)) {
|
|
6421
|
+
const b = PHYSICS_BOUNDS.get(col);
|
|
6422
|
+
if (b === void 0) {
|
|
6423
|
+
throw new Error(`PHYSICS_BOUNDS.get(${col}) unexpectedly undefined`);
|
|
6424
|
+
}
|
|
6425
|
+
[lo, hi] = b;
|
|
6426
|
+
} else {
|
|
6427
|
+
if (!Number.isFinite(std) || std <= 0) {
|
|
6428
|
+
throw new RangeError(
|
|
6429
|
+
`clipOutliers: std must be > 0 for the sigma fallback (got ${std}); pass bounds=[lo, hi] or use a physics-default column`
|
|
6430
|
+
);
|
|
6431
|
+
}
|
|
6432
|
+
const vals = [];
|
|
6433
|
+
for (const r of rows) {
|
|
6434
|
+
const v = r?.[col];
|
|
6435
|
+
if (typeof v === "number" && Number.isFinite(v)) vals.push(v);
|
|
6436
|
+
}
|
|
6437
|
+
if (vals.length < 2) {
|
|
6438
|
+
passThrough = true;
|
|
6439
|
+
lo = Number.NEGATIVE_INFINITY;
|
|
6440
|
+
hi = Number.POSITIVE_INFINITY;
|
|
6441
|
+
} else {
|
|
6442
|
+
const mu = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
6443
|
+
const sumSq = vals.reduce((a, b) => a + (b - mu) ** 2, 0);
|
|
6444
|
+
const sigma = Math.sqrt(sumSq / (vals.length - 1));
|
|
6445
|
+
if (sigma === 0 || !Number.isFinite(sigma)) {
|
|
6446
|
+
passThrough = true;
|
|
6447
|
+
lo = Number.NEGATIVE_INFINITY;
|
|
6448
|
+
hi = Number.POSITIVE_INFINITY;
|
|
6449
|
+
} else {
|
|
6450
|
+
lo = mu - std * sigma;
|
|
6451
|
+
hi = mu + std * sigma;
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6455
|
+
const out = [];
|
|
6456
|
+
for (const r of rows) {
|
|
6457
|
+
const v = r?.[col];
|
|
6458
|
+
let clipped;
|
|
6459
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
6460
|
+
clipped = passThrough ? v : Math.min(Math.max(v, lo), hi);
|
|
6461
|
+
} else {
|
|
6462
|
+
clipped = null;
|
|
6463
|
+
}
|
|
6464
|
+
out.push({ ...r, [key]: clipped });
|
|
6465
|
+
}
|
|
6466
|
+
return out;
|
|
6467
|
+
}
|
|
6468
|
+
function crosscheckIemGhcnh(iemRows, ghcnhRows, opts = {}) {
|
|
6469
|
+
const tolC = opts.tolC ?? 2;
|
|
6470
|
+
if (iemRows.length === 0 || ghcnhRows.length === 0) return [];
|
|
6471
|
+
for (const r of iemRows) {
|
|
6472
|
+
if (typeof r?.station !== "string" || typeof r?.eventTime !== "string") {
|
|
6473
|
+
throw new Error(
|
|
6474
|
+
"crosscheckIemGhcnh: iem rows must carry 'station' (string) and 'eventTime' (string) keys"
|
|
6475
|
+
);
|
|
6476
|
+
}
|
|
6477
|
+
}
|
|
6478
|
+
for (const r of ghcnhRows) {
|
|
6479
|
+
if (typeof r?.station !== "string" || typeof r?.eventTime !== "string") {
|
|
6480
|
+
throw new Error(
|
|
6481
|
+
"crosscheckIemGhcnh: ghcnh rows must carry 'station' (string) and 'eventTime' (string) keys"
|
|
6482
|
+
);
|
|
6483
|
+
}
|
|
6484
|
+
}
|
|
6485
|
+
const iemMap = /* @__PURE__ */ new Map();
|
|
6486
|
+
for (const r of iemRows) {
|
|
6487
|
+
const key = `${r.station}|${r.eventTime}`;
|
|
6488
|
+
iemMap.set(key, r);
|
|
6489
|
+
}
|
|
6490
|
+
const out = [];
|
|
6491
|
+
for (const g of ghcnhRows) {
|
|
6492
|
+
const key = `${g.station}|${g.eventTime}`;
|
|
6493
|
+
const i = iemMap.get(key);
|
|
6494
|
+
if (i === void 0) continue;
|
|
6495
|
+
const iT = typeof i.temp_c === "number" && Number.isFinite(i.temp_c) ? i.temp_c : null;
|
|
6496
|
+
const gT = typeof g.temp_c === "number" && Number.isFinite(g.temp_c) ? g.temp_c : null;
|
|
6497
|
+
if (iT === null || gT === null) continue;
|
|
6498
|
+
const delta = Math.abs(iT - gT);
|
|
6499
|
+
if (delta > tolC) {
|
|
6500
|
+
out.push({
|
|
6501
|
+
station: g.station,
|
|
6502
|
+
eventTime: g.eventTime,
|
|
6503
|
+
tempCIem: iT,
|
|
6504
|
+
tempCGhcnh: gT,
|
|
6505
|
+
deltaC: delta
|
|
6506
|
+
});
|
|
6507
|
+
}
|
|
6508
|
+
}
|
|
6509
|
+
return out;
|
|
6510
|
+
}
|
|
6511
|
+
|
|
3986
6512
|
// src/index.ts
|
|
6513
|
+
var Preprocessing = preprocessing_exports;
|
|
3987
6514
|
var version3 = "0.0.0";
|
|
3988
6515
|
export {
|
|
3989
6516
|
LiveStreamError,
|
|
3990
6517
|
MODE2_SOURCES,
|
|
3991
6518
|
NoLiveDataError,
|
|
3992
6519
|
POLITE_FLOORS_S,
|
|
6520
|
+
Preprocessing,
|
|
3993
6521
|
SELECTOR_NAMES,
|
|
3994
6522
|
SOURCE_ALIASES,
|
|
3995
6523
|
SOURCE_IDENTITY_TAGS,
|
|
@@ -3998,6 +6526,7 @@ export {
|
|
|
3998
6526
|
assertSourceIdentity,
|
|
3999
6527
|
buildOverrideWarning,
|
|
4000
6528
|
src_exports as core,
|
|
6529
|
+
dailyExtremes,
|
|
4001
6530
|
discover,
|
|
4002
6531
|
helloCore,
|
|
4003
6532
|
helloMarkets,
|
|
@@ -4006,6 +6535,8 @@ export {
|
|
|
4006
6535
|
isMode2Source,
|
|
4007
6536
|
latest,
|
|
4008
6537
|
src_exports3 as markets,
|
|
6538
|
+
obs,
|
|
6539
|
+
preprocessing_exports as preprocessing,
|
|
4009
6540
|
research,
|
|
4010
6541
|
researchBySource,
|
|
4011
6542
|
resolveCity,
|