npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

buoydata

v0.2.2

Published

Modern TypeScript SDK for NDBC realtime buoy data.

Readme

buoydata

https://www.npmjs.com/package/buoydata

Modern TypeScript SDK for NOAA NDBC realtime buoy data. The library provides a fetch layer, parsing helpers, and typed models for standard meteorological measurements while still supporting arbitrary realtime2 data types.

Reminder: No support or warranty is provided or expected. Use at your own risk.

Installation

pnpm add buoydata

Quickstart

import {
  fetchRealtimeData,
  parseRealtimeData,
  parseRealtimeTable,
} from 'buoydata';

const raw = await fetchRealtimeData({ buoyId: '46026', type: 'txt' });
const data = parseRealtimeData('46026', raw);

console.log(data.measurements[0].wind.averageSpeed);

const table = parseRealtimeTable(raw);
console.log(table.headers);

Requirements

  • Node.js 18+ (server-side only; this package depends on nodejs-polars).

Node usage

Node 18+ includes fetch globally. If you need a custom client, pass it explicitly:

import { fetchRealtimeData } from 'buoydata';
import fetch from 'node-fetch';

const raw = await fetchRealtimeData({ buoyId: '46026', fetch });

API

fetchRealtimeData

Fetches realtime2 files from NDBC.

fetchRealtimeData({
  buoyId: string,
  type?: string,
  fetch?: typeof fetch,
  requestInit?: RequestInit,
  baseUrl?: string,
}): Promise<string>

buildRealtimeUrl

Builds the realtime2 URL for a buoy and file type.

buildRealtimeUrl(buoyId: string, type?: string, baseUrl?: string): string

fetchBuoyList and fetchStationIndex

Retrieve station IDs using the NDBC active station XML feed (no longer 404-prone). You can optionally include inactive stations from the station catalog, and fetchStationIndex gives you an isActive helper without needing to reparse data.

const active = await fetchBuoyList(); // active IDs only
const all = await fetchBuoyList({ includeInactive: true }); // full catalog

const index = await fetchStationIndex();
index.isActive('46026'); // true/false

parseRealtimeData

Parses a realtime2 text file into typed Measurement objects. Standard fields are mapped into structured measurement fields. Unknown columns are ignored unless includeUnknownFields is enabled.

parseRealtimeData(
  buoyId: string,
  rawText: string,
  options?: {
    coerceNumbers?: boolean;
    missingValue?: number | null;
    missingTokens?: string[];
    commentPrefix?: string;
    includeUnknownFields?: boolean;
  },
): BuoyData

parseRealtimeTable

Parses a realtime2 text file into a generic table representation with headers, units, and raw rows.

parseRealtimeTable(
  rawText: string,
  options?: {
    coerceNumbers?: boolean;
    missingValue?: number | null;
    missingTokens?: string[];
    commentPrefix?: string;
  },
): RealtimeTable

parseRealtimeTableFrame

Parses a realtime2 text file into a Polars DataFrame with headers, units, and raw rows.

parseRealtimeTableFrame(
  rawText: string,
  options?: {
    coerceNumbers?: boolean;
    missingValue?: number | null;
    missingTokens?: string[];
    commentPrefix?: string;
  },
): RealtimeTableFrame

toDataFrame

Converts a RealtimeTable into a Polars DataFrame.

toDataFrame(table: RealtimeTable): DataFrame

parseRow

Parses a single row into values using whitespace splitting and missing-data handling.

parseRow(
  rawRow: string,
  options?: {
    coerceNumbers?: boolean;
    missingValue?: number | null;
    missingTokens?: string[];
  },
): ParsedValue[]

objectifyTable

Converts a RealtimeTable into an array of records keyed by header values.

objectifyTable(table: RealtimeTable): RealtimeRecord[]

getMeasurementDate

Creates a UTC Date instance from a Measurement (using year, month, day, hour, minute).

getMeasurementDate(measurement: Measurement): Date

URL utilities

formatQueryParams(params: QueryParams): string
buildURL(base: string, path?: string, params?: QueryParams): string

Data models

Measurement

Structured representation of standard meteorological data:

  • year, month, day, hour, minute
  • airTemperature, dewpointTemperature
  • pressureTendancy, seaLevelPressure, stationVisibility
  • wind (direction, averageSpeed, peakGustSpeed)
  • water (averagePeriod, dominantDirection, dominantPeriod, significantHeight, surfaceTemperature, tide)

BuoyData

{
  id: string;
  measurements: Measurement[];
}

RealtimeTable

{
  headers: string[];
  units: string[];
  rows: (string | number | null)[][];
  rawRows: string[];
}

RealtimeTableFrame

{
  headers: string[];
  units: string[];
  frame: DataFrame;
  rawRows: string[];
}

RealtimeRecord

Record<string, string | number | null>

Parsing behavior

  • Comment lines start with # and are ignored for table parsing.
  • The units row (typically #yr mo dy ...) is parsed into units.
  • Missing data tokens default to MM and numeric 9s (e.g. 99, 999, 9999, 99.0).
  • parseRealtimeTable uses null as the default missing value; parseRealtimeData uses NaN by default to align with numeric measurement fields.
  • Numbers are coerced automatically unless coerceNumbers is set to false.

Code layout

src/
  index.ts                Public exports
  models/
    measurement.ts        Typed data models for standard met data
    table.ts              Generic table and record types
  realtime/
    fetch.ts              Fetch layer and realtime URL builder
    parser.ts             Table parsing, objectification, and measurement mapping
  utils/
    date.ts               Measurement date helper
    url.ts                URL and query param utilities

tests/
  fixtures/               Downloaded realtime2 sample files
  parser.test.ts          Parsing tests across formats
  fetch.test.ts           Fetch layer tests (mocked)
  url.test.ts             URL/query param tests
  date.test.ts            Measurement date utility test

Architecture diagrams

High-level flow

                +----------------------+
                |   NDBC realtime2     |
                |  (https endpoint)    |
                +----------+-----------+
                           |
                           | fetchRealtimeData
                           v
                    +------+------+
                    | rawText     |
                    +------+------+
                           |
           +---------------+----------------+
           |                                |
           v                                v
  parseRealtimeTable                 parseRealtimeData
           |                                |
           v                                v
   RealtimeTable                     BuoyData (typed)
           |
           v
    objectifyTable
           |
           v
    RealtimeRecord[]

Parsing pipeline (parseRealtimeTable)

rawText
  |
  v
normalizeLines (trim, drop blanks)
  |
  v
filter comment lines ("# ")
  |
  v
parse header row  --> headers[]
  |
  v
parse units row   --> units[]
  |
  v
parse data rows   --> rows[][]

Measurement mapping (parseRealtimeData)

RealtimeTable
  |
  v
objectifyTable -> RealtimeRecord[]
  |
  v
toMeasurement
  |
  v
Measurement[] (BuoyData.measurements)

Testing

pnpm test

License

MIT