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

postal-mx

v0.1.0

Published

Typed reader for Mexico's official postal code catalog (SEPOMEX). Ships the parser, not the data.

Readme

postal-mx

Lector tipado del catálogo oficial de códigos postales de México (SEPOMEX / Correos de México). Trae el lector, no los datos.

bun add postal-mx

Por qué no incluye el catálogo

El archivo lo publica Correos de México y su propio encabezado dice:

«se proporciona en forma gratuita para uso particular, no estando permitida su comercialización, total o parcial, ni su distribución a terceros bajo ningún concepto».

Publicar los 145 mil registros dentro de un paquete de npm sería justamente esa distribución a terceros. Así que este paquete trae el parser, los tipos y la tabla de entidades federativas —datos públicos de INEGI e ISO, no del catálogo— y deja que cada instalación baje su propia copia de la fuente oficial, que es el uso particular que la licencia sí permite.

Uso

import { downloadCatalog, groupByPostalCode, iterCatalog } from 'postal-mx'

const bytes = await downloadCatalog()          // ~14 MB desde correosdemexico.gob.mx
const byPostalCode = groupByPostalCode(iterCatalog(bytes))

byPostalCode.get('64000')
// {
//   postalCode: '64000',
//   state: { iso: 'NLE', inegi: '19', name: 'Nuevo León' },
//   municipality: 'Monterrey',
//   municipalityCode: '039',
//   city: 'Monterrey',
//   settlements: [{ name: 'La Finca', kind: 'Colonia' }, …],
// }

Para importar a una base de datos, iterCatalog recorre fila por fila sin materializar el catálogo entero:

for (const record of iterCatalog(bytes)) {
  // record.postalCode, record.settlement, record.municipality…
}

Lo que un código postal determina

Contra el catálogo completo (32 292 códigos, 144 261 asentamientos):

  • Estado y municipio son únicos por CP. Ningún código cruza dos municipios, así que esos dos campos se pueden autollenar sin preguntar.
  • La ciudad sólo existe en zonas urbanas — viene vacía en dos de cada tres filas, y ahí city es null (nunca ''). El municipio hace sus veces.
  • El asentamiento es lo único que queda a elección: colonia, ranchería, fraccionamiento, ejido… settlements los trae ordenados por nombre.

Falla ruidosamente

Un parser tolerante importaría 145 mil filas con las columnas corridas y nadie se enteraría hasta que un paquete saliera a la dirección equivocada. Por eso:

  • la cabecera se compara campo por campo contra las 15 columnas esperadas;
  • una fila con otro número de columnas lanza, no se descarta;
  • un código postal que no sean cinco dígitos lanza;
  • una descarga sospechosamente pequeña (una página de error con 200) lanza;
  • un CP que apareciera en dos municipios lanza, porque invalidaría el autollenado que este paquete promete.

API

| | | |---|---| | downloadCatalog(options?) | Baja el catálogo crudo. CATALOG_URL es la fuente oficial. | | decodeCatalog(bytes) | Windows-1252 → texto. Leerlo como UTF-8 rompe todos los acentos. | | iterCatalog(input) | Generador de PostalRecord, una por asentamiento. | | parseCatalog(input) | Lo mismo, materializado en un arreglo. | | groupByPostalCode(records) | Map<string, PostalCodeInfo> — lo que cada CP determina. | | MX_STATES / getState(code) | Las 32 entidades por clave INEGI (19) o ISO 3166-2 (NLE). | | isValidPostalCode(value) | Cinco dígitos. |

Los nombres de estado son los del catálogo, que no siempre son los de uso corriente («Coahuila de Zaragoza», «México» por el Estado de México). Por eso el cruce entre catálogos se hace por clave, nunca por nombre.

Licencia

MIT para el código de este paquete. El catálogo que descargues se rige por los términos de Correos de México citados arriba.