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

iceaddr-ts

v0.1.0

Published

Icelandic address registry (Staðfangaskrá) lookup for TypeScript, Cloudflare Workers and Node — a zero-dependency, edge-native port of the data layer of Sveinbjörn Þórðarson's iceaddr.

Readme

iceaddr-ts

Icelandic address registry (Staðfangaskrá) lookup for TypeScript, Cloudflare Workers and Node — a zero-dependency, edge-native port of the data layer of Sveinbjörn Þórðarson's excellent Python library iceaddr.

iceaddr is the canonical tool for Icelandic addresses, but it's Python with a bundled SQLite database. There was no equivalent you could run in a V8 isolate (Cloudflare Workers, Deno, Bun) or drop into a TypeScript project. This package fills that gap: pure functions, no native code, no database required, and it ships no address data — it fetches the registry live from the public HMS export and you keep it wherever you like (memory, KV, Postgres).

Credit where it's due. This is an independent reimplementation that mirrors iceaddr's semantics; the postcode table is ported from iceaddr (BSD-3-Clause). All the hard-won design — which columns matter, the cleaning rules, the search behaviour — comes from Sveinbjörn's original. See NOTICE.md.

Install

npm install iceaddr-ts      # or: pnpm add iceaddr-ts

ESM and CommonJS builds are both shipped. Node 18+ (for fetch / Web Streams) or any modern edge runtime.

Quick start

import { loadStadfangaskra, createAddressIndex } from "iceaddr-ts";

// 1. Fetch + clean the registry straight from HMS (~139k records, no data is
//    bundled in this package). Do this at startup, or on a schedule.
const addresses = await loadStadfangaskra();

// 2. Build an in-memory index for fast lookups.
const ix = createAddressIndex(addresses);

// 3. Autocomplete — house-number prefix matching included.
ix.search("Gullengi 3");
//=> [{ streetNf: "Gullengi", houseNumber: 3, ..., display: "Gullengi 3, 112 Reykjavík" },
//    { ..., houseNumber: 31 }, { ..., houseNumber: 33 }, ...]

// 4. Strict validation of a typed-in address.
ix.validate({ street: "Njálsgata", houseNumber: 8, houseLetter: "c", postalCode: "101" });
//=> { hnitnum: 10001..., display: "Njálsgata 8c, 101 Reykjavík", city: "Reykjavík", ... }

// 5. Re-resolve a previously selected address by its stable id.
ix.lookupByHnitnum(10001234);

What you get

The library has four layers; import only what you need.

Core — pure CSV parsing & cleaning (zero data)

import { parseCsvLine, cleanAddressRow, validateHeader, parseAddressQuery } from "iceaddr-ts";

parseAddressQuery("Njálsgata 8C");
//=> { street: "Njálsgata", number: 8, letter: "c" }

cleanAddressRow / validateHeader / parseCsvLine / haversineKm plus the CleanAddress and ParsedAddressQuery types. This is the data-free core — it applies the same filtering iceaddr does (drop rows with no stable id or street, postcode outside the known set, coordinates outside Iceland; comma-decimal → dot; lower-case house letters).

Each record carries both identifiers, mirroring iceaddr: hnitnum (the coordinate point, not unique per address) and heinum (the address itself, the stable id you join on). Tracking iceaddr#16 by Jökull Sólberg.

Fetch — the registry, live from HMS (no data redistributed)

import { streamStadfangaskra, loadStadfangaskra, STADFANGASKRA_URL } from "iceaddr-ts";

// Stream record-by-record (constant memory) ...
for await (const a of streamStadfangaskra()) { /* ... */ }

// ... or collect them all.
const all = await loadStadfangaskra();

Options: { url?, fetch?, knownPostcodes?, signal? }. The header is validated first and the call throws if the upstream CSV schema has drifted, so a silent change at HMS can't quietly corrupt your data.

Lookup — in-memory search / validate (no DB)

createAddressIndex(addresses) → an AddressIndex with .search(query, {limit}), .validate({street, houseNumber, houseLetter, postalCode}), and .lookupByHnitnum(id). Results carry a composed display line and a city / region resolved from the bundled postcode table.

For very high query volumes, a Postgres + pg_trgm index is the scalable path (see Reference: a Postgres-resident service below); the in-memory index is ideal for scripts, edge functions with the dataset in memory/KV, and tests.

Postcodes — the one bundled dataset

import { POSTCODES, postcodeLookup, knownPostcodes } from "iceaddr-ts/postcodes";

postcodeLookup("101");
//=> { code: "101", nominative: "Reykjavík", dative: "Reykjavík",
//     region: "Höfuðborgarsvæðið", description: "Miðborg", kind: "Stærra dreifbýli" }

195 postcodes with nominative + dative place names and region info, ported from iceaddr. Importing from iceaddr-ts/postcodes keeps it separate from the data-free core.

A note on the data

This package ships only the postcode table. The ~139k address records are fetched at runtime from the public HMS export and never redistributed here. The address data is published by HMS / Þjóðskrá Íslands under CC-BY 4.0 — if you ship it in a product, attribute it: "Staðfangaskrá by HMS / Þjóðskrá Íslands, CC-BY 4.0". See NOTICE.md for the full picture.

The registry refreshes upstream often (at least daily). A typical setup fetches it on a schedule (a daily/weekly cron) and serves lookups from the loaded set.

Reference: a Postgres-resident service

This package is the in-memory / streaming half of the picture. The original production deployment loads the cleaned records into Postgres and serves autocomplete via a pg_trgm trigram index with a weekly refresh job — the scalable shape for high traffic. That design (schema, indexes, the atomic-swap refresh, the DISTINCT ON (hnitnum) dedup needed because the upstream CSV is not unique on hnitnum) is written up in the companion design note and is meant to be copied and adapted, not consumed as a library.

Development

pnpm install
pnpm build        # tsdown → dual ESM/CJS + .d.ts
pnpm test         # vitest
pnpm lint         # oxlint
pnpm typecheck    # tsc --noEmit

License

MIT (this package's code). Bundled postcode data is from iceaddr (BSD-3-Clause); runtime-fetched address data is CC-BY 4.0. See LICENSE and NOTICE.md.