
Security News
White House Authorizes Private Companies to Conduct Offensive Cyber Operations
A new federal program will let vetted U.S. cybersecurity firms help investigate and disrupt foreign cybercrime groups under government direction.
@squawk/weather
Advanced tools
Parse raw aviation weather strings (METAR, SPECI, TAF, SIGMET, AIRMET, PIREP) into structured objects
Pure parsing library for aviation weather strings. Parses raw METAR, SPECI, TAF,
SIGMET, AIRMET, PIREP, and FD (winds and temperatures aloft) text into fully
typed, structured objects. The core @squawk/weather export contains no network
calls - consumers provide raw weather strings however they obtain them (ADDS
API, AVWX, local feed, file dump) and the package returns structured results.
An opt-in fetch layer is available at @squawk/weather/fetch for consumers
who want to pull live data directly from the Aviation Weather Center (AWC)
text API. It uses the Node 22+ global fetch; pulling it in is a choice so
the core parsing import graph stays network-free.
Part of the @squawk aviation library suite. See all packages on npm.
import { parseMetar } from '@squawk/weather';
const metar = parseMetar(
'METAR KJFK 041853Z 21010KT 10SM FEW250 18/06 A3012 RMK AO2 SLP203 T01830061',
);
console.log(metar.stationId); // "KJFK"
console.log(metar.observationTime); // { day: 4, hour: 18, minute: 53 }
console.log(metar.wind?.speedKt); // 10
console.log(metar.visibility?.visibilitySm); // 10
console.log(metar.flightCategory); // "VFR"
console.log(metar.remarks?.seaLevelPressureMb); // 1020.3
import { parseTaf } from '@squawk/weather';
const taf = parseTaf(
'TAF KJFK 041730Z 0418/0524 21012KT P6SM FEW250 FM042200 24015G25KT P6SM SCT040 BKN080',
);
console.log(taf.stationId); // "KJFK"
console.log(taf.issuedAt); // { day: 4, hour: 17, minute: 30 }
console.log(taf.validFrom); // { day: 4, hour: 18, minute: 0 }
console.log(taf.forecast[0].wind?.speedKt); // 12
console.log(taf.forecast[1].changeType); // "FM"
console.log(taf.forecast[1].start); // { day: 4, hour: 22, minute: 0 }
Use parseSigmetBulletin as the primary entry point - it handles both single
SIGMETs and multi-SIGMET bulletins (common in AWC convective SIGMET feeds),
always returning an array.
import { parseSigmetBulletin } from '@squawk/weather';
// Works with single SIGMETs or full bulletins from any source
const sigmets = parseSigmetBulletin(rawSigmetText);
for (const sigmet of sigmets) {
if (sigmet.format === 'NONCONVECTIVE') {
console.log(sigmet.seriesName); // "NOVEMBER"
console.log(sigmet.hazards[0].hazardType); // "TURBULENCE"
console.log(sigmet.hazards[0].altitudeRange); // { baseFt: 35000, topFt: 41000 }
} else if (sigmet.format === 'CONVECTIVE') {
console.log(sigmet.region); // "C"
console.log(sigmet.thunderstormType); // "AREA"
console.log(sigmet.tops); // { altitudeFt: 45000, isAbove: true }
} else {
console.log(sigmet.firCode); // "PAZA"
console.log(sigmet.phenomena); // "SEV TURB"
}
}
If you know you have a single SIGMET record, parseSigmet returns a single
object instead of an array:
import { parseSigmet } from '@squawk/weather';
const sigmet = parseSigmet(singleSigmetRecord);
console.log(sigmet.format); // "CONVECTIVE" | "NONCONVECTIVE" | "INTERNATIONAL"
import { parseWindsAloft, getLevelAtFt } from '@squawk/weather';
const forecast = parseWindsAloft(rawFdBulletin);
console.log(forecast.basedOn); // { day: 24, hour: 12, minute: 0 }
console.log(forecast.altitudesFt); // [3000, 6000, 9000, 12000, 18000, 24000, 30000, 34000, 39000]
const bdl = forecast.stations.find((s) => s.stationId === 'BDL');
const at9k = bdl && getLevelAtFt(bdl, 9000);
console.log(at9k?.directionDeg); // 330
console.log(at9k?.speedKt); // 40
console.log(at9k?.temperatureC); // -4
// Light-and-variable winds (raw "9900") set a flag rather than a zero speed:
const lv = forecast.stations[1]?.levels[0];
console.log(lv?.isLightAndVariable); // true
console.log(lv?.speedKt); // undefined
parseMetar(raw)Parses a raw METAR or SPECI string into a structured Metar object. SPECI
observations use the same parser and are distinguished by the type field.
parseTaf(raw)Parses a raw TAF string into a structured Taf object. Handles both US (FAA)
and ICAO formats including FM, TEMPO, BECMG, and PROB change groups, wind shear
(WS), turbulence (5-group), icing (6-group), CAVOK, NSW, and cancelled (CNL)
forecasts. Multi-line TAFs are normalized automatically.
parseSigmetBulletin(raw)Recommended entry point for SIGMET parsing. Handles both single SIGMET records
and multi-SIGMET bulletins (e.g. AWC convective bulletins containing multiple
individually numbered SIGMETs with a shared outlook). Returns a Sigmet[]
array. For single records, returns a one-element array.
parseSigmet(raw)Parses a single SIGMET record into a structured Sigmet discriminated union.
Use this when you know the input contains exactly one SIGMET. Auto-detects the
format from content and returns one of three variants:
ConvectiveSigmet - domestic CONUS thunderstorm advisories (area/line/isolated TS, outlook sections, severe weather hazards)NonConvectiveSigmet - domestic CONUS turbulence, icing, volcanic ash, dust/sandstorm (supports multi-hazard and cancellations)InternationalSigmet - ICAO format for Alaska, oceanic FIRs, and international airspace (tropical cyclone, volcanic ash, cancellations)Accepts both raw WMO-wrapped messages and body-only messages.
parseAirmet(raw)Parses an AIRMET bulletin string into a structured Airmet object. Handles
Sierra (IFR, mountain obscuration), Tango (turbulence, strong surface winds,
LLWS), and Zulu (icing, freezing levels) series. Accepts both WMO-wrapped
and body-only bulletins.
parsePirep(raw)Parses a raw PIREP (Pilot Report) string into a structured Pirep object.
Handles both routine (UA) and urgent (UUA) reports with all standard
slash-delimited fields: location (/OV) with station, radial/distance, route,
and lat/lon variants; time (/TM); flight level (/FL); aircraft type (/TP);
sky condition (/SK) with standard and compact notation; weather/visibility (/WX);
temperature (/TA); wind (/WV, magnetic); turbulence (/TB) with intensity ranges,
types, frequencies, and BLO/ABV modifiers; icing (/IC) with intensity ranges and
types; and free-text remarks (/RM).
import { parsePirep } from '@squawk/weather';
const pirep = parsePirep(
'UA /OV OKC063015/TM 1522/FL085/TP C172/SK BKN065-TOP090/TB LGT/IC LGT RIME/RM SMOOTH',
);
console.log(pirep.type); // "UA"
console.log(pirep.altitudeFtMsl); // 8500
console.log(pirep.aircraftType); // "C172"
console.log(pirep.turbulence?.[0]?.intensity); // "LGT"
console.log(pirep.icing?.[0]?.type); // "RIME"
parseWindsAloft(raw)Parses a raw FD (Forecast Winds and Temperatures Aloft) bulletin - sometimes
referred to by its older name "FB" - into a structured WindsAloftForecast
object. Handles the AWC wire-format preamble ((Extracted from ...) or a
plain WMO header line), the fixed-width altitude table, light-and-variable
winds (raw code 9900), high-speed wind encoding (direction codes 51-86
denoting speeds >= 100 kt), and implicit-negative temperatures above the
TEMPS NEG ABV threshold.
getLevelAtFt(station, altitudeFt)Helper that returns the WindsAloftLevel entry for a given altitude on a
station row. Returns undefined when the altitude is not a column in the
bulletin; no interpolation is performed.
deriveFlightCategory(visibilityStatuteMiles, isLessThan, sky, isCavok)Derives the flight category (VFR, MVFR, IFR, LIFR) from visibility and ceiling conditions.
Import from the @squawk/weather/fetch subpath to get fetch+parse helpers
that hit the AWC text API. Each function issues a single HTTP request and
returns parsed results alongside any per-record parse errors and the full
raw body.
import {
fetchMetar,
fetchTaf,
fetchPirep,
fetchSigmets,
fetchInternationalSigmets,
fetchWindsAloft,
} from '@squawk/weather/fetch';
const { metars } = await fetchMetar(['KJFK', 'KLAX']);
const { tafs } = await fetchTaf('KJFK');
const { pireps } = await fetchPirep('KDEN');
const { sigmets } = await fetchSigmets();
const { sigmets: international } = await fetchInternationalSigmets();
const { forecast } = await fetchWindsAloft({
region: 'northeast',
altitudeBand: 'low',
forecastHours: 6,
});
fetchMetar and fetchTaf accept a single 4-letter ICAO identifier or an
array of them (comma-joined into one request). fetchPirep takes a single
4-letter ICAO identifier as the search center; the AWC endpoint rejects
shorter forms (e.g. DEN) with a 400. fetchSigmets and
fetchInternationalSigmets return the full current SIGMET set for their
respective regions and take no ID argument:
fetchSigmets - domestic (CONUS) SIGMETs via /api/data/airsigmet.fetchInternationalSigmets - international / ICAO-format SIGMETs via
/api/data/isigmet. Does not include SIGMETs issued by the US in
domestic format.fetchWindsAloft - winds-aloft forecast (FD) bulletin via
/api/data/windtemp. Returns a single parsed WindsAloftForecast
(not an array); parser errors are thrown rather than captured as
per-record failures, because the endpoint returns a single bulletin.AWC does not currently expose a raw-text AIRMET endpoint; parseAirmet is
still available for callers who have AIRMET text from another source.
fetchPirep accepts additional AWC filter parameters:
await fetchPirep('KDEN', {
distance: 100, // nautical miles from the center station
age: 6, // hours back
level: 200, // altitude in hundreds of feet (+/-3000 ft)
inten: 'mod', // minimum intensity: 'lgt' | 'mod' | 'sev'
});
fetchSigmets accepts a hazard filter:
await fetchSigmets({ hazard: 'turb' }); // 'conv' | 'turb' | 'ice' | 'ifr'
fetchWindsAloft accepts region, altitude band, and forecast horizon:
await fetchWindsAloft({
region: 'northeast',
altitudeBand: 'low', // 'low' covers 3k-39k ft; 'high' covers FL450+
forecastHours: 6, // 6 | 12 | 24
});
Region values are contiguousUs, northeast, southeast, northCentral,
southCentral, rockyMountain, pacificCoast, alaska, hawaii, and
westernPacific. All three parameters are optional - when omitted, the AWC
API applies its own defaults.
Every fetch function accepts an optional options object:
await fetchMetar('KJFK', {
signal: controller.signal, // AbortController signal for cancellation
baseUrl: 'https://mirror.test/api', // override the AWC base URL
});
AwcFetchError with status, statusText, body, and url.parseErrors
array in the result, not thrown. Other records in the same response still
parse successfully.import { fetchMetar, AwcFetchError } from '@squawk/weather/fetch';
try {
const { metars, parseErrors } = await fetchMetar('KJFK');
for (const { raw, error } of parseErrors) {
console.warn('Failed to parse:', raw, error);
}
} catch (err) {
if (err instanceof AwcFetchError) {
console.error(`AWC ${err.status}: ${err.body}`);
} else {
throw err;
}
}
This package exports all weather-related type definitions directly. Import types from @squawk/weather rather than @squawk/types:
import type {
Metar,
Taf,
Sigmet,
Airmet,
Pirep,
WindsAloftForecast,
WindsAloftStationForecast,
WindsAloftLevel,
FlightCategory,
} from '@squawk/weather';
FAQs
Parse raw aviation weather strings (METAR, SPECI, TAF, SIGMET, AIRMET, PIREP) into structured objects
The npm package @squawk/weather receives a total of 50 weekly downloads. As such, @squawk/weather popularity was classified as not popular.
We found that @squawk/weather demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A new federal program will let vetted U.S. cybersecurity firms help investigate and disrupt foreign cybercrime groups under government direction.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.