Skip to content

What it decodes

The package covers the parts of GRIB2 that the forecast engine’s feeds use, which is a subset of the full specification. It parses sections over raw GRIB2 bytes, including repeated sections 2–7 (multi-field messages) and section 6 bitmaps, and decodes the grid and packing templates below. Anything else is rejected with a named error instead of being approximated. An unsupported packing template, for example, fails with the exact template number and the supported list.

Each grid carries an analytic inverse mapping, so nearest-gridpoint lookup is O(1) per point.

TemplateGridWhere it appears in the feeds
3.0Regular latitude-longitudeGFS 0.25°, GDPS 0.15°, GEPS 0.5°
3.1Rotated latitude-longitudeEvery ECCC HRDPS, RDPS, REPS, and RAQDPS field
3.30Lambert conformalHRRR CONUS 3 km, NAM 12 km and CONUS nest

nearestGridpoint reports the great-circle distance alongside the index, because callers use the distance as the out-of-domain guard. It clamps and reports instead of throwing. src/grid.ts holds the inverses, and src/nearest.ts holds the lookup.

Why template 3.1 needs an analytic inverse Two stacked panels. Above, a schematic globe: the true graticule in solid strokes, the rotated graticule in dashed strokes, the rotated south pole marked at -36.0885°, -114.6949°, and the HRDPS continental domain lying along the rotated equator. Below, the neighbourhood of the launch at 49.3634°, -117.2361°: dashed rotated gridlines at 0.0225° spacing tilted against the solid true graticule, the launch mapped by toRotated to rotated (-4.5183°, -1.6599°), fractional cell (584.95, 345.96), nearest gridpoint (i 585, j 346) = storage index 879425, with the 0.156 km residual drawn in a magnified inset.

TemplatePackingImplementation
5.0Simple packingPure TypeScript
5.2Complex packingPure TypeScript
5.3Complex packing with spatial differencingPure TypeScript
5.40JPEG 2000Through an injected decoder interface, so the codec dependency never enters this package’s core

The fixture findings record the measured shape of the feeds. Every harvested NOAA record (GFS, HRRR, NAM) uses DRT 5.3, and every ECCC Datamart product uses DRT 5.40. The JPEG 2000 seam and its Node wiring have their own page.

Rotated and Lambert grids store wind grid-relative (uvRelativeToGrid=1 on every ECCC rotated grid). src/wind.ts rotates grid-relative components to earth-relative, including the Lambert cone constant.

NOMADS publishes an .idx sidecar per GRIB file: one line per record, with byte offsets. src/idx.ts parses the sidecar and fetches single records by HTTP Range request. The caller passes in the fetch function instead of the module using a global one.

  • parseIdx / findRecord: parse the sidecar text and locate a record by its fields.
  • byteRange: the inclusive HTTP Range header value for a record, open-ended for the last record.
  • pairSpan: the combined span of a paired U/V record set.
  • fetchIndex: fetch and parse a sidecar (a plain, unranged GET).
  • fetchRecord: fetch one record’s bytes with a Range request.

Only 206 Partial Content counts as success. A 200 response to a Range request is a failure, because it means the server ignored Range and sent the whole multi-hundred-megabyte file. fetchRecord enforces this and throws with the offending status.

The browser-safe barrel (@azohra/meteo.grib) contains no node: imports, no ambient I/O, and no WASM. Everything that needs a runtime (the JPEG 2000 codecs, the worker pool) lives behind the Node-only @azohra/meteo.grib/j2k-node subpath.