TypeScript quickstart
The TypeScript SDK ships four packages on npm. The convenience meta-package mostlyright re-exports the surfaces you usually want; the scoped packages (@mostlyrightmd/core, @mostlyrightmd/weather, @mostlyrightmd/markets) let you depend on exactly what you need.
The npm packages ship in lockstep with the Python SDK at the same version (1.13.0).
01 · Get access
Section titled “01 · Get access”Node 18+. The package is ESM-first with CJS fallback. Both import and require work; types ship in the same package.
02 · First call
Section titled “02 · First call”import { dataset } from "mostlyright";
const rows = await dataset("KNYC", "2025-01-06", "2025-01-12");console.log(rows[0]);dataset() is the primary composer; research() is a fully working alias (dataset === research) for existing code. It returns Promise<ReadonlyArray<PairsRow>> — a frozen array with one row per LST day in [fromDate, toDate]. Each row carries:
type PairsRow = { date: string; // YYYY-MM-DD (LST) station: string; // 3-letter NWS code cli_high_f: number | null; cli_low_f: number | null; cli_report_type: string | null; obs_high_f: number | null; obs_low_f: number | null; obs_mean_f: number | null; obs_mean_dewpoint_f: number | null; obs_max_wind_kt: number | null; obs_max_gust_kt: number | null; obs_total_precip_in: number | null; obs_count: number; // ... plus fcst_* (null unless include_forecast) and market_close_utc};cli_* comes from the NWS CLI overnight final (the official daily climate record). obs_* comes from the merged METAR feed: AWC > IEM > GHCNh on tie-break. For the standalone CLI labels, import climate from the subpath: import { climate } from "@mostlyrightmd/weather/climate".
03 · Cache layout
Section titled “03 · Cache layout”The Node cache writes JSON envelopes (not parquet — parquet is a Python-only choice) to ~/.mostlyright/cache-ts/:
~/.mostlyright/cache-ts/├── observations/{ICAO}/{YYYY}/{MM}.json└── climate/{ICAO}/{YYYY}.jsonOverride the root with MOSTLYRIGHT_CACHE_DIR:
export MOSTLYRIGHT_CACHE_DIR=/data/mostlyrightThe Python SDK uses cache/v1/ and the TS SDK uses cache-ts/ under the same root, so they never overwrite each other.
04 · Live streaming
Section titled “04 · Live streaming”For live METAR ticks, use the stream() async generator from @mostlyrightmd/weather:
import { stream } from "@mostlyrightmd/weather";
for await (const row of stream("KNYC")) { console.log(row.observed_at, row.temp_f);}Pass an AbortSignal to interrupt cleanly:
import { stream } from "@mostlyrightmd/weather";
const controller = new AbortController();setTimeout(() => controller.abort(), 60_000);
for await (const row of stream("KNYC", { signal: controller.signal })) { console.log(row.observed_at, row.temp_f);}stream() never writes the cache. It dedups by observed_at so AWC’s “latest METAR” repeats between observation cycles collapse to one row per fresh tick.
05 · Browser usage
Section titled “05 · Browser usage”@mostlyrightmd/core is the only package designed for browser bundles — it ships under a 25 KB size budget. The weather and markets packages depend on Node-only modules (node:fs, node:path for the cache) and should not be bundled for the browser.
For a browser-side call, fetch JSON from your own backend that wraps research(), then validate with @mostlyrightmd/core/validator:
import { validateRows } from "@mostlyrightmd/core/validator";
const response = await fetch("/api/research?station=KNYC&from=2025-01-06&to=2025-01-12");const rows = await response.json();const result = validateRows(rows, "schema.observation.v1");What to read next
Section titled “What to read next”- Temporal safety —
KnowledgeViewfor point-in-time filtering,assertNoLeakagefor the audit path. - Source identity — fused vs source-pinned,
SourceMismatchError. - → v1.13 migration —
dataset(), TSobs()/climate()specifics, and theMODE2_*→SOURCE_PINNED_*rename. - Cache directory — moving from
~/.tradewinds/to~/.mostlyright/.