Skip to content

@mostlyrightmd/weather

high_temp_f: null | number

Daily high °F, rounded to int. null when missing or out-of-bounds.

issued_at: null | string

ISO 8601 UTC issuance time parsed from product[:12], else null.

low_temp_f: null | number

Daily low °F, rounded to int. null when missing or out-of-bounds.

observation_date: string

Local climate day, YYYY-MM-DD.

product_id: null | string

Raw NWS product identifier when present.

report_type: ReportType

Inferred report type.

report_type_priority: number

Numeric priority for dedup (final=3, ncei_final=2.5, correction=2, preliminary=1, estimated=0). Sourced from CLIMATE_REPORT_TYPE_PRIORITY in @mostlyrightmd/core codegen.

source: "iem"

Always "iem" for CLI records.

station_code: string

Station code (3-letter NWS or 4-letter ICAO, caller’s choice).


One station-local day’s rollup.

Field names mirror Python DailyExtreme TypedDict exactly so cross-language code reads the same way:

  • date, station, low_f, high_f, mean_f, precip_in
  • low_coverage (boolean) and observation_count (int) for debug-friendly gating

date: string

Station-local calendar date as YYYY-MM-DD.

high_c: null | number

Maximum temperature in °C, or null on low coverage.

high_f: null | number

Maximum temperature in °F, or null on low coverage.

low_c: null | number

Minimum temperature in °C, or null on low coverage. This is the settlement-correct quantity Polymarket resolves on (the Python daily_extremes label is Celsius, daily_extremes_low_c).

low_coverage: boolean

True when observation_count < 12 (matches Python low-coverage gate).

low_f: null | number

Minimum temperature in °F, or null on low coverage.

mean_c: null | number

Mean temperature in °C, or null on low coverage.

mean_f: null | number

Mean temperature in °F, or null on low coverage.

observation_count: number

Count of observation rows that contributed to the day.

precip_in: null | number

Total 1-hour precipitation across the local day, in inches.

source_high: null | string

Source identifier of the row that produced tmax (null on low coverage).

source_low: null | string

Source identifier of the row that produced tmin (null on low coverage).

station: string

ICAO station code.


optional merge: DailyExtremesMergeMode

Source merge mode; default "live_v1".

optional signal: AbortSignal

Caller abort signal, propagated to every IEM/AWC fetch (and composed with each attempt’s retry backoff wait). An abort mid-flight rejects promptly with the platform AbortError — never reclassified as a transport error.


Optional knobs for forecastNwp.

readonly optional cycle: string

Model run datetime — UTC ISO string.

readonly optional forecastHour: number

Forecast hour ahead of cycle.

readonly optional member: string

Ensemble member id (e.g. GEFS "p05", CFS "03"). Mirrors the Python member= kwarg (issue #74); only meaningful for GEFS / CFS. Signature-forward only — TS NWP execution lands in v2.0+.


Optional knobs for iemMosForecasts.

readonly optional fetchFn: (input, init?) => Promise<Response>(input, init?) => Promise<Response>

Override the fetch function (used by tests).

MDN Reference

URL | RequestInfo

RequestInit

Promise<Response>

MDN Reference

string | URL | Request

RequestInit

Promise<Response>

readonly optional model: IemMosModel

Default "nbe".

readonly optional signal: AbortSignal

Caller abort signal. Propagated to every per-cycle fetch; an abort during an in-flight request rejects promptly with the platform AbortError.


One IEM MOS forecast row (PLAN-11). camelCase TS / snake_case Python.

readonly dewPointC: null | number

2-m dew point in Celsius.

readonly forecastHour: number

(validAt - issuedAt) in hours.

readonly issuedAt: string

Model run datetime — UTC ISO string.

readonly model: string

UPPERCASE model id (e.g. "NBE").

readonly precipProbability: null | number

12-hour probability of precipitation [0, 1].

readonly retrievedAt: string

When the row was fetched — UTC ISO string.

readonly skyCoverPct: null | number

Sky cover %; IEM MOS does not expose this — always null.

readonly source: IemMosSource

Per-row source identity. Always "iem.archive" for now.

readonly station: string

ICAO station code (uppercased).

readonly tempC: null | number

2-m temperature in Celsius (null when MOS field is M / missing).

readonly validAt: string

Forecast valid datetime — UTC ISO string.

readonly windDirDeg: null | number

Wind direction in degrees [0, 360).

readonly windSpeedMs: null | number

10-m wind speed in m/s.


readonly optional source: null | string

Live source to poll. "awc" (default, fastest) or "iem" (~10-min delay; useful when AWC is down). Case-insensitive.


Single observation row, matching specs/observation.json.

Notes on null vs unknown:

  • Every field defaults to null if the upstream record omits it, fails bounds, or fails type parsing. This mirrors the Python parser (no exceptions on bad input — only on missing required keys).
  • source is always the string literal "awc" for AWC-sourced rows (the row-level enum is "awc" | "iem" | "ghcnh"; the .live/.archive suffix is a CATALOG-layer source-id, not a row field).
  • event_time_utc is ISO 8601 UTC with Z suffix.

readonly altimeter_inhg: null | number

readonly dewpoint_c: null | number

readonly dewpoint_f: null | number

readonly event_time_utc: string

readonly observation_type: "METAR" | "SPECI"

readonly peak_wind_dir: null | number

readonly peak_wind_gust_kt: null | number

readonly peak_wind_time: null | string

readonly precipitation_in_1h: null | number

readonly qc_field: null | number

readonly raw_metar: null | string

readonly sea_level_pressure_hpa: null | number

readonly sky_base_1_ft: null | number

readonly sky_base_2_ft: null | number

readonly sky_base_3_ft: null | number

readonly sky_base_4_ft: null | number

readonly sky_cover_1: null | string

readonly sky_cover_2: null | string

readonly sky_cover_3: null | string

readonly sky_cover_4: null | string

readonly snow_depth_inches: null | number

readonly source: "awc" | "ghcnh" | "iem"

Per-row source tag. Widened in TS-W2 Plan 01 to cover all 3 row-level observation sources (AWC live, IEM ASOS archive, GHCNh archive). Each parser still emits its own literal — AWC emits "awc", IEM ASOS emits "iem", GHCNh emits "ghcnh" — but the shared Observation contract accepts all three so mergeObservations (TS-W2 Plan 04) sees one row shape across sources. Matches Python schema.observation.v1.source enum.

readonly station_code: string

readonly temp_c: null | number

readonly temp_f: null | number

readonly visibility_miles: null | number

readonly weather_codes: null | string

readonly wind_dir_degrees: null | number

readonly wind_gust_kt: null | number

readonly wind_speed_kt: null | number


optional signal: AbortSignal

Caller abort signal, propagated to every IEM/AWC fetch (and composed with each attempt’s retry backoff wait). An abort mid-flight rejects promptly with the platform AbortError — never reclassified as a transport error.

optional source: ObsSourceFilter

Optional source filter. null (default) means all sources merged.

optional strategy: ObsStrategy

Strategy mode; default "auto".

optional timezone: string

IANA timezone override forwarded to the local_standard_date LST-bucketing machinery (mirrors Python observations(..., timezone=...)). Rarely needed for the canonical station registry (all covered); used for stations whose tz is not in the registry.


Single observation row. Field set mirrors the canonical Observation schema (@mostlyrightmd/weather Observation interface) with the METAR-derived fields (temp_f / dewpoint_f / wind_speed_kts / …).

optional dewpoint_c: null | number

optional dewpoint_f: null | number

event_time_utc: string

optional local_standard_date: string

ISO YYYY-MM-DD string of the local standard day this report belongs to, computed via localStandardDateFor (never a raw event_time_utc[:10] UTC-day slice — a pre-midnight-UTC METAR belongs to the PRIOR LST day for negative-offset US stations). Present on every per-report row with a parseable event_time_utc; it is the per-report join key the composed observation-grain dataset uses to LEFT-join daily columns onto each report.

optional precipitation_mm_1h: null | number

optional pressure_inhg: null | number

optional raw_metar: null | string

source: string

station: string

temp_c: null | number

temp_f: null | number

optional wind_direction_degrees: null | number

optional wind_speed_kts: null | number


Optional knobs for openMeteoForecasts.

readonly optional allowLeakage: boolean

Required true to invoke mode: "seamless".

readonly optional fetchFn: (input, init?) => Promise<Response>(input, init?) => Promise<Response>

Override the fetch function (used by tests).

MDN Reference

URL | RequestInfo

RequestInit

Promise<Response>

MDN Reference

string | URL | Request

RequestInit

Promise<Response>

readonly optional issuedAt: string

Optional ISO cycle for Single Runs API dispatch.

readonly optional mode: OpenMeteoMode

Default "training".

readonly optional model: OpenMeteoModel

Default "gfs_global".

readonly optional signal: AbortSignal

Caller abort signal. Propagated to the forecast fetch; an abort during an in-flight request rejects promptly with the platform AbortError.


One Open-Meteo forecast row (schema.forecast.station.v1).

readonly apparentTempC: null | number

readonly capeJkg: null | number

readonly cloudCoverPct: null | number

readonly dewPointC: null | number

readonly directRadiationWm2: null | number

readonly forecastHour: null | number

(validAt - issuedAt) in hours. null when issuedAt is null.

readonly freezingLevelM: null | number

readonly issuedAt: null | string

Model run datetime — UTC ISO string. May be null for source="open_meteo.seamless" rows (cycle unrecoverable by design).

readonly model: string

Open-Meteo model key (lowercase, e.g. "gfs_global").

readonly precipitationMm: null | number

readonly precipProbability: null | number

readonly pressureMslHpa: null | number

readonly retrievedAt: string

readonly shortwaveRadiationWm2: null | number

readonly snowDepthM: null | number

readonly source: OpenMeteoSource

readonly station: string

readonly surfacePressureHpa: null | number

readonly tempC: null | number

readonly validAt: string

readonly visibilityM: null | number

readonly weatherCode: null | number

readonly windDirDeg: null | number

readonly windGustsMs: null | number

readonly windSpeedMs: null | number


readonly apiKey: string

The MOSTLYRIGHT_API_KEY sent as x-api-key. REQUIRED.

readonly optional fetchImpl: FetchLike

Injectable fetch (tests). Default: the browser/MV3 global.

readonly fromTime: string

Event-time window start (ISO-8601).

readonly hostedUrl: string

The weather serving base URL (MOSTLYRIGHT_WEATHER_HOSTED_URL) — the deployed mr-serving origin. REQUIRED; a missing seam throws HostedConfigError. In the MV3 extension this is build-injected.

readonly optional product: string

Optional product id; omit for the server’s per-source default product.

readonly optional retrievedAt: string

Retrieval timestamp override (ISO-8601 UTC). Default: now.

readonly satellite: string

Explicit satellite id (e.g. "goes16"). REQUIRED: the hosted /satellite endpoint does NOT auto-route (unlike the Python satellite() dispatch, which resolves the family client-side before the hosted call), so the browser shim must name the family or the server returns 422.

readonly optional signal: AbortSignal

Optional AbortSignal for cancellation.

readonly station: string | readonly string[]

Single station or a list (ICAO/NWS codes). At least one is required.

readonly toTime: string

Event-time window end (ISO-8601).

readonly optional variable: string

Optional single-variable filter.


A canonical satellite row emitted by satelliteHosted. Mirrors the Python satellite(...) DataFrame row (snake_case wire keys → camelCase props). Field presence follows the wire row: a genuine extracted row carries every field; a degenerate qc_status="suspect" sentinel row (the Python units-contract boundary path) carries empty scan times + pixelRow=-1.

readonly asOfTime: null | string

RFC3339-Z knowledge-time string echoed by the server, or null.

readonly delivery: "hosted"

Delivery channel lineage — always "hosted" on this path.

readonly eventTime: null | string

Event time (scan start), ISO-8601 UTC, or null.

readonly ingestedAt: null | string

readonly knowledgeTime: null | string

Knowledge time (leakage anchor), ISO-8601 UTC, or null.

readonly pixelCol: null | number

readonly pixelDataQualityFlag: null | number

readonly pixelRow: null | number

readonly pixelValue: null | number

readonly pressureLevelHpa: null | number

readonly product: string

readonly qcStatus: string

readonly retrievedAt: string

When the SDK retrieved the row (ISO-8601 UTC).

readonly satellite: string

readonly scanEndUtc: null | string

Byte-faithful RFC3339-Z scan-end string, or null.

readonly scanStartUtc: null | string

Byte-faithful RFC3339-Z scan-start string (event time), or null.

readonly source: string

Satellite family identity — passed through verbatim (D2), never re-derived.

readonly sourceObjectKey: string

readonly station: string

readonly stationLat: null | number

readonly stationLon: null | number

readonly subsatelliteLongitudeDegrees: null | number

readonly units: string

readonly variable: string


readonly optional pollSeconds: null | number

Override the polite-floor cadence. Must be >= the per-source floor (AWC=30, IEM=60). When omitted, uses the floor for the active source.

readonly optional signal: AbortSignal

Optional AbortSignal for clean cancellation. When fired, the current polite-floor sleep is interrupted and the generator returns. The current in-flight fetch (if any) is allowed to complete — AbortSignal is not threaded into the underlying fetchers (yet) since the v0.14.1 fetchers are synchronous and wrapped via the platform fetch.

readonly optional source: null | string

Live source to poll. "awc" (default) or "iem". Case-insensitive.

DailyExtremesMergeMode: "live_v1" | "awc_only" | "iem_only"

Merge mode controlling which sources contribute observations.

  • live_v1 (default) — IEM ASOS for historical depth + AWC for the recent 168h window. Matches Python merge="live_v1".
  • awc_only — AWC live METAR only. Window must be inside the 168h AWC retention or callers see a sparse return.
  • iem_only — IEM ASOS archive only. No live fallback.

IemMosModel: "nbe" | "gfs" | "lav" | "met" | "ecm"

IEM MOS model enum (matches Python SUPPORTED_MOS_MODELS).


IemMosSource: "iem.archive" | "iem.live"

Canonical source enum (matches Python source column values).


LiveObservation: Omit<Observation, "source"> & object

Observation row emitted by mostlyright.live.stream and live.latest.

Same shape as the canonical Observation row, but with source narrowed to the live-channel identity tags. The widened-archive "awc" / "iem" / "ghcnh" source values are NOT valid here — that’s the point of the separate type.

readonly source: LiveSourceTag


LiveSource: typeof SUPPORTED_SOURCES[number]

Validated source enum derived from SUPPORTED_SOURCES.


LiveSourceTag: typeof SOURCE_IDENTITY_TAGS[LiveSource]


NwpModel: "hrrr" | "gfs" | "nbm" | "hrrrak" | "gefs" | "gdas" | "rap" | "rrfs" | "rtma" | "urma" | "cfs" | "ecmwf_ifs_hres" | "ecmwf_ifs_ens" | "ecmwf_aifs_single" | "ecmwf_aifs_ens" | "hrdps" | "rdps" | "gdps" | "geps" | "reps" | "hafs" | "nam" | "href" | "hiresw"

NWP model enum — mirror of Python SUPPORTED_NWP_MODELS (24 entries).


ObsFrameSource: "merged.live_v1" | "awc" | "iem" | "ghcnh"

Frame-level source identity — serialized as provenance.source on the @mostlyrightmd/core!DataResult observations() returns (DX-H4). Value mirrors Python df.attrs["source"]:

  • unpinned (source omitted / null) → "merged.live_v1" (the fused-policy frame tag a single-source/pinned schema MUST loudly reject).
  • pinned (source set) → the bare pinned source ("awc" / "iem").

ObsSourceFilter: "awc" | "iem" | "ghcnh" | null

Source filter — matches Python tw.weather.obs(source=...) _VALID_SOURCES frozenset {"awc", "iem", "ghcnh"}. null (default) means all sources merged.

fix-: ghcnh validates as accepted but is not yet wired in TS (no GHCNh fetcher path in fetchByStrategy); selecting it raises DataAvailabilityError(reason="model_unavailable") rather than silently returning []. Tracking issue: TS-W4 GHCNh fetcher port. The cli value was removed — it is not a valid Python source filter either.


ObsStrategy: "auto" | "exact_window" | "warm_cache" | "hosted"

Strategy enum — matches Python verbatim.


OpenMeteoMode: "training" | "live" | "seamless"

Open-Meteo dispatch mode for openMeteoForecasts.


OpenMeteoModel: "gfs_seamless" | "gfs_global" | "gfs_graphcast025" | "aigfs025" | "hgefs025" | "ncep_hrrr_conus" | "ncep_nbm_conus" | "ncep_nam_conus" | "ecmwf_ifs025" | "ecmwf_ifs_hres" | "ecmwf_aifs025_single" | "dwd_icon_seamless" | "dwd_icon_global" | "dwd_icon_eu" | "dwd_icon_d2" | "dwd_icon_d2_15min" | "meteofrance_seamless" | "meteofrance_arpege_world025" | "meteofrance_arpege_europe" | "meteofrance_arome_france0025" | "meteofrance_arome_france_hd" | "meteofrance_arome_france_hd_15min" | "jma_seamless" | "jma_gsm" | "jma_msm" | "kma_seamless" | "kma_gdps" | "kma_ldps" | "cma_grapes_global" | "bom_access_global" | "ukmo_global_deterministic_10km" | "ukmo_uk_deterministic_2km" | "metno_nordic_pp" | "cmc_gem_gdps" | "cmc_gem_rdps" | "cmc_gem_hrdps"

The 36 Open-Meteo forecast models in scope.


OpenMeteoSource: "open_meteo.previous_runs" | "open_meteo.single_run" | "open_meteo.live" | "open_meteo.seamless"

Open-Meteo source-identity enum (per-endpoint discrimination).


ReportType: "final" | "ncei_final" | "correction" | "preliminary" | "estimated"


SatelliteSourceIdentity: typeof SATELLITE_SOURCE_IDENTITIES[number]

const HIGH_TEMP_MAX_F: 150 = 150


const HIGH_TEMP_MIN_F: -60 = -60

Climate temp bounds from specs/climate.json. Inclusive.


const LOW_TEMP_MAX_F: 130 = 130


const LOW_TEMP_MIN_F: -80 = -80


const OPEN_METEO_MODELS: ReadonlySet<OpenMeteoModel>

The canonical 36-model set (set-equality lock).


const POLITE_FLOORS_S: Readonly<Record<LiveSource, number>>

Minimum allowed poll cadence per source, in seconds.

  • AWC: 30s — aviationweather.gov has no documented rate limit but 30s is the empirically-validated floor that won’t trip anti-abuse heuristics.
  • IEM: 60s — mesonet.agron.iastate.edu is a university server; IEM docs explicitly ask for reasonable headroom above 1 req/s.

const SATELLITE_SOURCE_IDENTITIES: readonly ["noaa_goes", "jma_himawari", "noaa_viirs", "eumetsat_meteosat"]

The satellite family source identities the hosted rows carry (D2 — one identity per instrument family, mirror-invariant). Informational; the shim passes source through verbatim (never re-derives it).


const SOURCE_IDENTITY_TAGS: object

Canonical per-source source field tag emitted on every observation row.

"awc.live" / "iem.live" are the live-channel identity tags — distinct from the archive-channel "awc" / "iem" written by the historical fetchers. Cross-SDK parity: these match Python SOURCE_IDENTITY_TAGS.

readonly awc: "awc.live" = "awc.live"

readonly iem: "iem.live" = "iem.live"


const SUPPORTED_SOURCES: readonly ["awc", "iem"]

Canonical ordered tuple of supported sources. Order matters — keep AWC first.


const version: "1.9.9" = "1.9.9"

Public package version; kept in lockstep with package.json.

dailyExtremes(station, fromDate, toDate, opts): Promise<DataResult<DailyExtremeRow>>

Compute per-day tmin/tmax/tmean/precip for a station’s window.

Matches Python mostlyright.international.daily_extremes signature. Day-bucketing uses the station’s IANA local tz from the STATIONS registry; US ASOS stations get integer-°F precision ( invariant); other stations get 0.1-precision values.

string

4-letter ICAO (e.g. “KNYC”, “EGLL”) or 3-letter NWS registry code (e.g. “NYC”) — parity with Python daily_extremes(), which accepts both. Output rows carry the ICAO regardless of input form (Python parity).

string

ISO date YYYY-MM-DD (inclusive, station-local)

string

ISO date YYYY-MM-DD (inclusive, station-local)

DailyExtremesOptions = {}

optional merge mode (default "live_v1")

Promise<DataResult<DailyExtremeRow>>

array of DailyExtremeRow, one per station-local day

Error if station is not in the STATIONS registry


forecastNwp(station, model, _opts): Promise<never>

Fetch a gridded NWP forecast — v1.x stub, deferred to v2.0+.

string

NwpModel

ForecastNwpOptions = {}

Promise<never>

⚠️ Not yet implemented in TypeScript. This function exists so callers can write code against the future-stable signature, but it throws on every call. Use the Python SDK (mostlyright>=1.0) for gridded NWP today — it wires the NCEP family (HRRR, GFS, NBM, RAP, RRFS, …) end-to-end.

Why deferred: GRIB2 decode requires native libraries (eccodes C library or cfgrib Python wrapper). No production-ready browser-side decoder exists in May 2026; a WASM port’s compile time + bundle size are impractical for v1.x. v2.0+ tracks the GRIB2 ecosystem maturity.

Workaround paths:

  • 7 major US stations (KNYC, KLAX, KORD, KMIA, KDEN, KSEA, KATL) → iemMosForecasts ships MOS-based forecasts that solve most use cases. The error hint includes this pointer automatically.
  • Everything else → use the Python SDK (pip install mostlyrightmd-weather).

NwpNotAvailableError on every call (v1.x). The error is a subclass of DataAvailabilityError, so existing catch (e instanceof DataAvailabilityError) paths continue to catch it. The thrown instance carries typed .station and .model properties for log/error attribution.

docs/nwp-forecasts.md for the full architectural rationale, the supported-model list, and the v2.0+ roadmap.


iemMosForecasts(station, fromDate, toDate, opts): Promise<DataResult<IemMosRow>>

Fetch IEM MOS forecasts for station in [fromDate, toDate].

Mirrors Python fetch_iem_mos(...). Iterates the model’s runtime-hour grid (NBE moved from {01,07,13,19}Z to {00,06,12,18}Z on 2026-05-05; other models use {00,06,12,18}Z), GETs the JSON endpoint, and projects rows to IemMosRow.

404 responses are silently skipped (many runtimes have no MOS data). Empty input range returns [].

string

string

string

IemMosOptions = {}

Promise<DataResult<IemMosRow>>

Error if model is not in SUPPORTED_MODELS.


isLiveSource(s): s is “awc” | “iem”

Type guard: narrow a string to LiveSource.

string

s is “awc” | “iem”


latest(station, opts): Promise<LiveObservation>

Return the most-recent observation row for station from a SINGLE source.

Same fetch path as stream, but returns once instead of looping. Use this for cron-style polling where you want one fresh observation per invocation.

string

ICAO ("KNYC") or 3-letter US ID ("NYC"). Case-insensitive.

LatestOptions = {}

Optional { source }.

Promise<LiveObservation>

Error when opts.source is unknown.

NoLiveDataError when the upstream returned no observations for the station — payload carries the resolved station and live source tag for branching.


observations(rawStation, fromDate, toDate, opts): Promise<DataResult<ObsRow>>

Fetch the merged per-report observations for a station’s window.

Mirrors Python mostlyright.weather.observations(station, from_date, to_date, source=None, strategy='auto') — per-report rows only. The strategy enum selects between the smart-router’s three concrete fetch paths.

The returned array carries a non-enumerable frameSource tag ("merged.live_v1" when unpinned, the bare source when pinned) mirroring Python’s df.attrs["source"]. Every row carries a local_standard_date.

string

ICAO code (e.g. “KNYC”) OR 3-letter NWS code (e.g. “NYC”). Resolved through the station registry: IEM ASOS is fetched by the NWS code, AWC by the ICAO — so observations(“KNYC”) == observations(“NYC”).

string

ISO date YYYY-MM-DD (inclusive)

string

ISO date YYYY-MM-DD (inclusive)

ObsOptions = {}

optional source filter + strategy mode

Promise<DataResult<ObsRow>>

ObsResult: per-report ObsRow array + frameSource

ValidationError when station is malformed OR not in the registry (before any fetch — same typed error climate() throws)

DataAvailabilityError when strategy=‘hosted’ (v0.2.x deferral)

TypeError when strategy is not in the accepted enum


openMeteoForecasts(station, fromDate, toDate, opts): Promise<DataResult<OpenMeteoRow>>

Fetch Open-Meteo forecasts for station in [fromDate, toDate].

OM-07. Mirrors Python fetch_open_meteo. Default mode: "training" hits Previous Runs API; with issuedAt: "..." dispatches to Single Runs API. mode: "live" hits Live Forecast API with cycle-math fallback issuedAt. mode: "seamless" requires allowLeakage: true (BANNED for training data).

string

string

string

OpenMeteoOptions = {}

Promise<DataResult<OpenMeteoRow>>


projectSatelliteRow(raw, retrievedAt): null | SatelliteRow

Project one untrusted wire row into a canonical SatelliteRow.

Reads snake_case wire keys (parity with the Python live schema) and emits camelCase props. source is passed through verbatim (D2 — never re-derived); delivery is forced to "hosted" (this is the hosted path,). The leakage overlay (eventTime / knowledgeTime) is derived from the wire event_time_utc / knowledge_time (falling back to scan_start_utc / as_of_time) and normalized to tz-aware UTC — a row that cannot be knowledge-anchored still ships (annotate-never-drop), carrying a null knowledgeTime, matching the Python annotate-never-drop discipline (D5).

unknown

string

null | SatelliteRow


satelliteHosted(options): Promise<readonly SatelliteRow[]>

Fetch satellite rows from the hosted weather serving /satellite endpoint.

The TS mirror of the Python satellite(delivery="hosted", ...): GETs ${MOSTLYRIGHT_WEATHER_HOSTED_URL}/satellite?... with the MOSTLYRIGHT_API_KEY header and returns rows byte-identical to the Python hosted contract. The source family identity is passed through verbatim; delivery is "hosted".

MV3-safe: fetch + JSON only (via hostedFetchJson). No Node APIs.

SatelliteHostedOptions

Promise<readonly SatelliteRow[]>

when MOSTLYRIGHT_WEATHER_HOSTED_URL / MOSTLYRIGHT_API_KEY / station is missing — surfaced BEFORE any network call.

on a non-2xx or non-JSON response (from hostedFetchJson).


sourceTag(source): LiveSourceTag

Map a validated source name to its canonical row-level identity tag.

"awc" | "iem"

LiveSourceTag


stream(station, opts): AsyncGenerator<LiveObservation>

Yield fresh observations for station from a SINGLE source on a polite-floor cadence.

The loop:

  1. Validate source + pollSeconds (throws BEFORE first poll).
  2. Poll once.
  3. If the most-recent observation’s event_time_utc differs from the last one yielded, yield it. Otherwise skip (dedup).
  4. await sleep(pollSeconds).
  5. Loop.

Empty responses (network error, fetcher returned []) DO NOT abort the stream — they’re treated as “nothing fresh yet” and the loop continues after the polite-floor sleep. To get a single-shot failure path, use latest.

string

StreamOptions = {}

AsyncGenerator<LiveObservation>

Error BEFORE the first poll when opts.source is unsupported or opts.pollSeconds is below the polite floor.


validatePollSeconds(pollSeconds, source): number

Apply the polite-floor invariant to a caller-supplied cadence.

Caller-supplied cadence. undefined/null → use the floor.

undefined | null | number

A validated source name (call validateSource first).

"awc" | "iem"

number

The cadence to use, in seconds.

Error when pollSeconds is below the polite floor.


validateSource(source): "awc" | "iem"

Normalize and validate a source option.

Caller-supplied source string. undefined/null defaults to the first entry in SUPPORTED_SOURCES (AWC). Case-insensitive.

undefined | null | string

"awc" | "iem"

The normalized lowercase source name (one of SUPPORTED_SOURCES).

Error when the source is not in SUPPORTED_SOURCES.