mostlyright 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -8,6 +8,7 @@ import * as weather from "@mostlyrightmd/weather";
8
8
 
9
9
  // src/research.ts
10
10
  import {
11
+ DataAvailabilityError,
11
12
  NotFoundError,
12
13
  STATION_BY_CODE,
13
14
  STATION_BY_ICAO,
@@ -38,6 +39,63 @@ import {
38
39
  parseGhcnhPsv,
39
40
  parseIemCsv
40
41
  } from "@mostlyrightmd/weather";
42
+
43
+ // src/research.types.ts
44
+ var KNOWN_RESEARCH_OPTION_KEYS = /* @__PURE__ */ new Set([
45
+ // Pre-Phase-21 fetcher controls.
46
+ "signal",
47
+ "awcHours",
48
+ "iemPolitenessMs",
49
+ "ghcnhPolitenessMs",
50
+ "cliPolitenessMs",
51
+ "now",
52
+ "cache",
53
+ // Pre-Phase-21 selectors.
54
+ "city",
55
+ "contract",
56
+ "contracts",
57
+ "stationOverride",
58
+ "sources",
59
+ "source",
60
+ "includeTrades",
61
+ "onWarning",
62
+ // Phase 21 21-01: Python-parity composable kwargs.
63
+ "include_forecast",
64
+ "forecast_model",
65
+ "forecast_models",
66
+ "qc",
67
+ "tz_override",
68
+ "backend",
69
+ "return_type"
70
+ ]);
71
+ function validateResearchKwargs(opts) {
72
+ const present = (v) => v !== void 0 && v !== null;
73
+ for (const key of Object.keys(opts)) {
74
+ if (!KNOWN_RESEARCH_OPTION_KEYS.has(key)) {
75
+ throw new TypeError(
76
+ `research(): unknown option key ${JSON.stringify(key)}. Valid keys: ${[...KNOWN_RESEARCH_OPTION_KEYS].sort().join(", ")}`
77
+ );
78
+ }
79
+ }
80
+ if (present(opts.sources) && present(opts.source)) {
81
+ throw new TypeError(
82
+ "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"
83
+ );
84
+ }
85
+ if (present(opts.forecast_model) && present(opts.forecast_models)) {
86
+ throw new TypeError(
87
+ "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"
88
+ );
89
+ }
90
+ const wantsForecast = present(opts.forecast_model) || present(opts.forecast_models);
91
+ if (wantsForecast && opts.include_forecast !== true) {
92
+ throw new TypeError(
93
+ "research(): forecast_model=/forecast_models= require include_forecast=true; the model filter is otherwise silently ignored"
94
+ );
95
+ }
96
+ }
97
+
98
+ // src/research.ts
41
99
  var AWC_MAX_HOURS = 168;
42
100
  async function resolveCache(opts) {
43
101
  if (opts.cache === null) return null;
@@ -304,9 +362,9 @@ async function fetchIemAsosWithCache(stationCode, _fromYear, _extendedToYear, fr
304
362
  }
305
363
  }
306
364
  }
307
- for (const obs of monthRows) {
308
- const obsDate = obs.observed_at.slice(0, 10);
309
- if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs);
365
+ for (const obs2 of monthRows) {
366
+ const obsDate = obs2.observed_at.slice(0, 10);
367
+ if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs2);
310
368
  }
311
369
  }
312
370
  return acc;
@@ -377,14 +435,22 @@ async function fetchGhcnhWithCache(stationCode, ghcnhId, fromDate, extendedTo, o
377
435
  }
378
436
  }
379
437
  }
380
- for (const obs of monthRows) {
381
- const obsDate = obs.observed_at.slice(0, 10);
382
- if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs);
438
+ for (const obs2 of monthRows) {
439
+ const obsDate = obs2.observed_at.slice(0, 10);
440
+ if (obsDate >= fromDate && obsDate <= extendedTo) acc.push(obs2);
383
441
  }
384
442
  }
385
443
  return acc;
386
444
  }
387
445
  async function research(station, fromDate, toDate, opts = {}) {
446
+ validateResearchKwargs(opts);
447
+ if (opts.backend === "polars") {
448
+ throw new DataAvailabilityError({
449
+ reason: "model_unavailable",
450
+ hint: 'polars backend not available in TypeScript SDK; use Python (mostlyrightmd) for backend="polars". TS returns plain object arrays.',
451
+ source: "research.backend"
452
+ });
453
+ }
388
454
  const hasCity = typeof opts.city === "string" && opts.city.length > 0;
389
455
  const hasContract = typeof opts.contract === "string" && opts.contract.length > 0;
390
456
  const hasContracts = Array.isArray(opts.contracts) && opts.contracts.length > 0;
@@ -460,8 +526,8 @@ async function research(station, fromDate, toDate, opts = {}) {
460
526
  if (opts.signal !== void 0) awcOpts.signal = opts.signal;
461
527
  const awcRaw = await fetchAwcMetars([resolved.icao], awcOpts);
462
528
  for (const m of awcRaw) {
463
- const obs = awcToObservation(m);
464
- if (obs !== null) awcRows.push(obs);
529
+ const obs2 = awcToObservation(m);
530
+ if (obs2 !== null) awcRows.push(obs2);
465
531
  }
466
532
  }
467
533
  const iemRows = await fetchIemAsosWithCache(
@@ -492,8 +558,8 @@ async function research(station, fromDate, toDate, opts = {}) {
492
558
  const observationsByDate = {};
493
559
  const dateLo = dates[0] ?? "";
494
560
  const dateHi = dates[dates.length - 1] ?? "";
495
- for (const obs of merged) {
496
- const settleDate = observedSettlementDate(obs.observed_at, resolved.code);
561
+ for (const obs2 of merged) {
562
+ const settleDate = observedSettlementDate(obs2.observed_at, resolved.code);
497
563
  if (settleDate === null) continue;
498
564
  if (settleDate < dateLo || settleDate > dateHi) continue;
499
565
  let bucket = observationsByDate[settleDate];
@@ -501,7 +567,7 @@ async function research(station, fromDate, toDate, opts = {}) {
501
567
  bucket = [];
502
568
  observationsByDate[settleDate] = bucket;
503
569
  }
504
- bucket.push(obs);
570
+ bucket.push(obs2);
505
571
  }
506
572
  const climateByDate = {};
507
573
  for (const cli of mergedClimate) {
@@ -649,8 +715,8 @@ async function researchBySource(station, source, fromDate, toDate, opts = {}) {
649
715
  const raw = await fetchAwcMetars2([resolved.icao], awcOpts);
650
716
  const parsed = [];
651
717
  for (const m of raw) {
652
- const obs = awcToObservation2(m);
653
- if (obs !== null) parsed.push(obs);
718
+ const obs2 = awcToObservation2(m);
719
+ if (obs2 !== null) parsed.push(obs2);
654
720
  }
655
721
  rows = parsed.filter((r) => {
656
722
  const d = r.observed_at.slice(0, 10);
@@ -916,12 +982,21 @@ import {
916
982
  validateSource
917
983
  } from "@mostlyrightmd/weather";
918
984
  import { LiveStreamError, NoLiveDataError } from "@mostlyrightmd/core";
985
+ import {
986
+ dailyExtremes
987
+ } from "@mostlyrightmd/weather";
988
+ import {
989
+ obs
990
+ } from "@mostlyrightmd/weather";
991
+ import * as preprocessing from "@mostlyrightmd/core/preprocessing";
992
+ var Preprocessing = preprocessing;
919
993
  var version = "0.0.0";
920
994
  export {
921
995
  LiveStreamError,
922
996
  MODE2_SOURCES,
923
997
  NoLiveDataError,
924
998
  POLITE_FLOORS_S,
999
+ Preprocessing,
925
1000
  SELECTOR_NAMES,
926
1001
  SOURCE_ALIASES,
927
1002
  SOURCE_IDENTITY_TAGS,
@@ -930,6 +1005,7 @@ export {
930
1005
  assertSourceIdentity,
931
1006
  buildOverrideWarning,
932
1007
  core,
1008
+ dailyExtremes,
933
1009
  discover,
934
1010
  helloCore,
935
1011
  helloMarkets,
@@ -938,6 +1014,8 @@ export {
938
1014
  isMode2Source,
939
1015
  latest,
940
1016
  markets,
1017
+ obs,
1018
+ preprocessing,
941
1019
  research,
942
1020
  researchBySource,
943
1021
  resolveCity,