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

laterite

v0.16.0

Published

AGS4 geotechnical data for Node.js — read, validate, produce, and query (the Node port of the laterite Python toolkit, Rust-backed).

Readme

laterite

AGS4 geotechnical data for Node.js — read, validate, produce, and query, backed by a Rust engine (the Node surface of the laterite toolkit).

Born-typed: a 2DP heading comes back as a JavaScript number, an ID as a string, a DT as a Date — decoded directly from the engine's typed Arrow, the same typing the Python and browser-wasm hosts produce.

npm install laterite

laterite is in beta — a statement about how much real-world use it has had, not how much testing. The API can still change; what it runs on is the steadier promise. What that means · tell us how it goes.

Prebuilt native binaries ship for linux-x64-gnu, darwin-arm64, and win32-x64-msvc (auto-selected via optionalDependencies). No build step, no Python, no toolchain.

Read & validate

import { read, validate } from "laterite";

const ags = read("delivery.ags"); // path, or read(bytes) / read(undefined, { text })
ags.groups; // ["PROJ", "LOCA", "SAMP", …]
const loca = ags.table("LOCA"); // a born-typed apache-arrow Table
loca.getChild("LOCA_GL")?.get(0); // → 12.3 (a number)

const report = validate("delivery.ags");
report.isValid; // boolean
report.findings; // [{ rule, line?, group, desc, severity? }]
report.toJson(); // byte-identical to `lat validate --json`

Produce AGS4

From per-group data (arrow-js Tables or plain row objects):

import { buildAgs4 } from "laterite";

const res = buildAgs4(
  new Map([
    ["PROJ", [{ PROJ_ID: "P1", PROJ_NAME: "Demo" }]],
    ["LOCA", [{ LOCA_ID: "BH01", LOCA_GL: 12.3 }]],
  ]),
  { edition: "4.1.1", mode: "autofix" },
);

res.text; // the AGS4 document
res.save("out.ags");

The engine formats each cell from the heading's declared AGS4 TYPE — a 2DP column emits 12.30, a 3SF column 1.23e4, a DT a spec-shaped timestamp — so pass raw typed values and let it render. Pre-stringified cells are written through verbatim.

…or from a typed builder graph (import { PROJ, LOCA } from "laterite"):

import { PROJ, LOCA, buildAgs4 } from "laterite";

const proj = new PROJ({
  PROJ_ID: "P1",
  PROJ_NAME: "Demo",
  locas: [new LOCA({ LOCA_ID: "BH01", LOCA_GL: 12.3 })],
});
buildAgs4(proj); // walks the tree → valid AGS4

SQL across groups (optional)

sql() / at() need the optional peer @duckdb/node-api:

npm install @duckdb/node-api
const ags = read("delivery.ags");

// cross-group JOIN — plain JS row objects by default
const rows = await ags.sql(
  "SELECT * FROM SAMP JOIN LOCA USING (LOCA_ID) WHERE LOCA_GL > 50",
);

// key-filter a location's whole related record set
const frames = await ags.at("LOCA", ["BH01", "BH02"]).frames();

// opt into arrow-js Table output (loads DuckDB's `arrow` community extension)
const table = await ags.sql("SELECT * FROM LOCA", { arrow: true });

Command line — npx laterite

The package ships the lat CLI too — the same AGS4 tool as the standalone Rust binary and uvx --from laterite lat, one launcher per ecosystem:

npx laterite validate delivery.ags          # or `lat …` after a global install
npx laterite read delivery.ags LOCA --csv    # dump a group (raw file cells)
npx laterite diff old.ags new.ags            # revision delta
npx laterite pack delivery.ags delivery.ags.zst
npx laterite excel delivery.ags delivery.xlsx

Verbs: validate (the default — a bare lat <file> runs it) · read · fix · diff · certify · rules · pack / unpack / lock / unlock · excel. The scriptable outputs (validate --json / --ndjson, read --json / --csv, rules --json) are byte-identical to the Rust binary; lock / unlock take the passphrase from --password-file or $LAT_TRANSPORT_PASSWORD (never a flag).

Performance

Node 24, macOS arm64, hot files, mean of 5 warm runs. Fixtures are synthetic, spec-valid AGS4 from ags4-forge — the wide scaffold: 123 groups, realistic type mix, zero findings.

| File (123 groups) | read | validate | read + typed tables | | ----------------: | ----------------: | ----------------: | --------------------: | | 4.9 MB | 16 ms · 310 MB/s | 40 ms · 122 MB/s | 22 ms · 225 MB/s | | 25.0 MB | 75 ms · 335 MB/s | 186 ms · 134 MB/s | 97 ms · 258 MB/s | | 103.0 MB | 301 ms · 343 MB/s | 769 ms · 134 MB/s | 392 ms · 262 MB/s | | 276.5 MB | 787 ms · 351 MB/s | 2.0 s · 140 MB/s | 1.1 s · 242 MB/s | | 551.6 MB | 1.7 s · 327 MB/s | 4.1 s · 134 MB/s | 2.4 s · 228 MB/s |

read parses and holds the file; the third column adds materialising every group to an apache-arrow Table, which is what a consumer actually pays. Throughput holds across the whole range — a half-gigabyte delivery is the 4.9 MB rate, not a cliff.

Reproduce with node tools/bench-node.mjs in the repo. It generates the rungs and verifies each against a pinned SHA-256, so a change to the fixture generator can't move these numbers unnoticed.

Also exported

  • agsTypes — canonicalType / displayHint / parseValue
  • registry — GROUPS, childGroups, ancestorChain, …
  • transport — pack / unpack (zstd) + lock / unlock (age passphrase)

Part of the laterite suite

One clean-room Rust AGS4 engine, surfaced for every stack. Scriptable output is byte-identical across all of them, so a CI gate and a notebook can't disagree.

| Surface | Package | Get it | | ----------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------- | | Node.js | laterite — npm | npm install laterite | | Python | laterite — PyPI | pip install laterite | | CLI | lat | bundled here, or GitHub Releases | | DuckDB | laterite_ags4 — community extension | INSTALL laterite_ags4 FROM community; | | Browser | validator + data explorer — WASM | open in a browser |

Running in a browser? This package is Node-only — it loads a native addon via optionalDependencies and touches the filesystem. Use the wasm build instead: same engine, same rules, no fs.

📖 Documentation · Node guide · Cookbook

License

MIT