Skip to content

lu1tr0n/nationid

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

101 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

nationid

English ยท Espaรฑol ยท Portuguรชs

TypeScript-first, zero-dependency validator for national identity and tax documents from every country.

npm version bundle size types license CI

๐ŸŽฎ Live playground: https://lu1tr0n.github.io/nationid_example/ โ€” try every country, every helper, in 3 locales. ๐Ÿ“– API Reference: https://lu1tr0n.github.io/nationid/ ๐Ÿ“Š Benchmarks: see BENCHMARKS.md

nationid is a focused, comprehensive library for validating national identity documents and tax IDs. It ships with checksum verification (not just regex shape), proper formatting and normalization, and works in Node, browsers, Bun, Deno and edge runtimes.

Why

Existing tools cover a fraction of the world. validator.js only validates 6 LATAM tax IDs. cpf-cnpj-validator covers Brazil. rut.js covers Chile. None ship El Salvador, Guatemala, Honduras, Dominican Republic, or Costa Rica with checksum verification.

nationid fills that gap. As of v2.2 it ships 54 countries with ~145 document codes, all with proper algorithms documented from official sources โ€” and ships an API-stability promise plus a CI-enforced governance test that every high-confidence spec cites a first-party issuer source.

What's new in v2.2

  • ๐Ÿ‡ธ๐Ÿ‡ฌ Singapore โ€” second country of Asia phase 2. Three new specs under nationid/sg: SG_NRIC (9-char identity number for citizens/PRs, weighted mod-11 check letter, ICA) and SG_FIN (9-char foreigner identity number incl. the 2022 M-series, ICA/MOM), both personal; and SG_UEN (Unique Entity Number, three category formats each with its own check letter, ACRA), tax. All three at confidence: "high".
  • UEN check digits โ€” SG_UEN upgrades from format-only to full check-letter validation across all three categories (Business, Local Company, Other Entity), with the 38-code entity-type whitelist. Constants are taken verbatim from python-stdnum/stdnum/sg/uen.py; the four doctest fixtures (00192200M, 197401143C, S16FC0121D, T01FC6132D) anchor the suite, alongside the real-world Cat B UENs 196800306E (DBS) and 199201624D (Singtel).
  • Oracle-agreement tests โ€” every SG spec runs a property test against an independent re-implementation of the published algorithm (NRIC/FIN weighted mod-11, plus the three UEN categories). Singapore's authoritative URLs are all on *.gov.sg hosts, so the governance citation test passes without a host-allowlist patch.
  • 7000+ โ†’ 7800+ tests, 54 countries ร— 145 codes.

What's new in v2.1 (2026-05-24)

  • ๐Ÿ‡ฏ๐Ÿ‡ต Japan โ€” first country of Asia phase 2. Two new specs under nationid/jp: JP_MY_NUMBER (12-digit Individual Number, weighted mod-11, MIC Ordinance 85/2014) and JP_CORPORATE_NUMBER (13-digit Corporate Number, weighted mod-9, NTA). Both at confidence: "high". The NTA's own corporate number 7000012050002 is verifiable in the public registry and is used as a canonical anchor in the test suite.
  • Oracle-agreement tests โ€” every JP spec runs a 10k-sample property test against an inline port of python-stdnum/stdnum/jp/in_.py (My Number) and python-stdnum/stdnum/jp/cn.py (Corporate Number). Independent cross-validation built into CI.
  • 6970+ โ†’ 7000+ tests, 53 countries ร— ~147 codes.

What's new in v2.0 (2026-05-24)

  • ๐Ÿ‡ช๐Ÿ‡บ EU-VAT complete โ€” 16 EU members + 1 EEA participant ship VAT validators in one batched release: IE_VAT, AT_UID, LU_VAT, GR_VAT, CZ_DIC, HU_VAT, RO_VAT, BG_VAT, HR_OIB, SK_VAT, SI_VAT, LT_VAT, LV_VAT, EE_VAT, MT_VAT, CY_VAT, IS_VSK. Unlocks EU VIES feature parity as a single tagline.
  • ISO/IEC 7064 MOD 11,10 primitive โ€” mod11_10CheckDigit + mod11_10Valid exported from nationid/algorithms. Length-generic; used by HR_OIB, DE_USTID, DE_STEUER_ID.
  • Greek EL/GR prefix handling built in โ€” accept both on input, normalise to EL (canonical VIES form). Closes the #1 historical EU-VAT bug.
  • Every URL in every v2.0+ JSDoc verified live via browser_fetch (firefox133 TLS impersonation) before publish โ€” fixes 5 broken URLs caught in shipped India v1.2 and 3 in v2.0. web.archive.org snapshots accepted as supplementary citation where issuer cert blocks programmatic checks. Pre-v2.0 specs are being back-filled to the same standard on a country-by-country basis as part of the post-v2.1 architecture audit.

What's new in v1.2 (2026-05-23)

  • ๐Ÿ‡ฎ๐Ÿ‡ณ India support โ€” first Asia country. Five new specs under nationid/in: IN_AADHAAR (Verhoeff + palindrome reject, UIDAI), IN_VID (16-digit Aadhaar alias), IN_PAN (entity-type whitelist, Income Tax Department), IN_GSTIN (Luhn mod-36 + embedded PAN + state code, CBIC), IN_EPIC (format-only, ECI).
  • Verhoeff primitive โ€” verhoeffValid and verhoeffCheckDigit exported from nationid/algorithms. Canonical Dโ‚… multiplication and permutation tables verbatim from Verhoeff (1969).
  • 6488 โ†’ 6606 tests, 35 countries ร— ~125 codes. Tarball 2.9 MB unpacked (+200 KB).

What's new in v1.1 (2026-05-22)

  • Country catalog under nationid/catalog โ€” getCountryInfo, listCountries, countryName, flagEmoji. Backed by Intl.DisplayNames (CLDR), so any locale the runtime supports works out of the box โ€” not just es / en / pt.

What's new in v1.0

  • TypeScript inference upgraded. parse("MX_CURP", x).code now infers the literal "MX_CURP", not the 124-member union. extractDOB / extractSex / extractRegion constrain their first argument to the codes that actually encode each field. Country bundles expose literal country / defaultPersonal / defaultTax types.
  • 76% smaller npm tarball. From 1.7 MB โ†’ 414 KB by dropping shipped sourcemaps and breaking the extract/pii/catalog subpaths' dependency on the root REGISTRY. nationid/extract alone drops -90% raw.
  • Three small breaking changes, all documented in MIGRATION.md ยง0: pii.mask now throws on unknown codes (symmetric with hash/lastN); package.json exports denies undocumented subpaths; CA_PASAPORTE and ES_PASAPORTE confidence demote high โ†’ moderate (no first-party issuer spec to cite).
  • Governance test. New tests/governance/confidence-citations.test.ts fails CI if any confidence: "high" spec lacks an issuer-TLD URL or recognized legal statute in its JSDoc header.

See MIGRATION.md ยง0 before upgrading from v0.x.

Install

npm i nationid
# or
pnpm add nationid
# or
yarn add nationid

Requires Node 20+.

Quick start

import { validate, format, normalize, parse } from "nationid";

validate("SV_DUI", "04567890-3");          // true
validate("BR_CPF", "529.982.247-25");      // true
validate("CL_RUT", "12.345.678-5");        // true
validate("ES_DNI", "12345678Z");           // true

format("SV_DUI", "045678903");             // "04567890-3"
normalize("SV_DUI", "04567890-3");         // "045678903"

const result = parse("SV_NIT", "0614-150585-101-5");
if (result.ok) {
  console.log(result.normalized);          // "06141505851015"
  console.log(result.formatted);           // "0614-150585-101-5"
  console.log(result.confidence);          // "moderate"
}

parse() returns a discriminated union โ€” no exceptions are thrown from the public API. On failure it carries a typed reason.kind:

const r = parse("SV_DUI", "");
if (!r.ok) r.reason.kind; // "empty" | "too_short" | "too_long" | "invalid_format" | "invalid_checksum"

Live playground

Try every country and every helper without installing anything: https://lu1tr0n.github.io/nationid_example/

The playground covers:

  • โœ… validate / parse / format / normalize for every supported country
  • ๐ŸŽฏ extract (DOB, sex, region) where the document encodes it
  • ๐Ÿ”’ pii masking + SHA-256 hashing for safe display and storage
  • ๐ŸŒ i18n error messages in es, en, pt
  • ๐Ÿ“š catalog โ€” queryable document metadata for UI dropdowns
  • 6 best-practice code examples (React forms, server validation, KYC display, etc.)

Source code for the showcase site: https://github.com/lu1tr0n/nationid_example

Tree-shakable subpath imports

Single country, ~3-5KB gzipped:

import { validate } from "nationid/sv";
validate("DUI", "045678903");

Algorithm primitives:

import { luhnValid, mod11WeightedSum } from "nationid/algorithms";

DX helpers โ€” extract / pii / i18n / catalog

Four tree-shakable modules for common app needs (available since v0.3):

// Extract structured data from valid documents
import { extractDOB, extractSex, extractRegion } from "nationid/extract";
extractDOB("MX_CURP", "GOMC850315HDFRRR07");  // { year: 1985, month: 3, day: 15 }
extractSex("AR_CUIT", "20-12345678-3");        // "M"

// Mask + hash for safe display and storage
import { mask, hash, lastN } from "nationid/pii";
mask("BR_CPF", "12345678901");                          // "***.***.**9-01"
await hash("BR_CPF", "12345678901", { salt: "tenant" }); // hex SHA-256

// Localized error messages (es, en, pt)
import { getErrorMessage } from "nationid/i18n";
getErrorMessage({ kind: "too_short" }, "es", "DUI");  // "El DUI es demasiado corto."

// Document catalog with localized names โ€” for UI dropdowns
import { listDocuments } from "nationid/catalog";
listDocuments("MX", "es");
// [{ code: "MX_CURP", displayName: "CURP",
//    longName: "Clave รšnica de Registro de Poblaciรณn",
//    purpose: "identity", confidence: "high", ... }, ...]

// Country catalog (v1.1) โ€” names + flags for every supported country.
// Uses Intl.DisplayNames (CLDR) so any locale the runtime supports works.
import { getCountryInfo, listCountries, flagEmoji } from "nationid/catalog";
getCountryInfo("MX", "es");
// { code: "MX", alpha3: "MEX", name: "Mรฉxico", flag: "๐Ÿ‡ฒ๐Ÿ‡ฝ" }
flagEmoji("BR");          // "๐Ÿ‡ง๐Ÿ‡ท"
listCountries("pt").length; // 54

Each subpath is independently tree-shakable. Single locales (nationid/i18n/es, /en, /pt) ship as <200B bundles.

Coverage (54 countries)

Country Personal Tax
๐Ÿ‡ธ๐Ÿ‡ป El Salvador DUI NIT
๐Ÿ‡ฒ๐Ÿ‡ฝ Mรฉxico CURP, Clave de Elector RFC (PF + PM)
๐Ÿ‡จ๐Ÿ‡ด Colombia CC, CE, TI, Pasaporte, PEP, PPT NIT
๐Ÿ‡ง๐Ÿ‡ท Brasil CPF, CNH, Tรญtulo de Eleitor CNPJ, PIS
๐Ÿ‡ต๐Ÿ‡ช Perรบ DNI, CE RUC
๐Ÿ‡ฆ๐Ÿ‡ท Argentina DNI, CUIL CUIT, CDI
๐Ÿ‡จ๐Ÿ‡ฑ Chile RUT/RUN RUT/RUN
๐Ÿ‡ฉ๐Ÿ‡ด Rep. Dominicana Cรฉdula RNC
๐Ÿ‡ฌ๐Ÿ‡น Guatemala DPI NIT
๐Ÿ‡ญ๐Ÿ‡ณ Honduras DNI RTN
๐Ÿ‡จ๐Ÿ‡ท Costa Rica Cรฉdula fรญsica, DIMEX Cรฉdula jurรญdica
๐Ÿ‡ช๐Ÿ‡ธ Espaรฑa DNI, NIE NIF (CIF), NUSS
๐Ÿ‡บ๐Ÿ‡ธ United States SSN, ITIN EIN
๐Ÿ‡ง๐Ÿ‡ด Bolivia (v0.4) CI NIT
๐Ÿ‡ช๐Ÿ‡จ Ecuador (v0.4) Cรฉdula RUC
๐Ÿ‡ต๐Ÿ‡พ Paraguay (v0.4) CI RUC
๐Ÿ‡ณ๐Ÿ‡ฎ Nicaragua (v0.4) Cรฉdula RUC
๐Ÿ‡ต๐Ÿ‡ฆ Panamรก (v0.4) Cรฉdula RUC
๐Ÿ‡บ๐Ÿ‡พ Uruguay (v0.4) CI RUT
๐Ÿ‡จ๐Ÿ‡ฆ Canadรก (v0.4) SIN BN
๐Ÿ‡ต๐Ÿ‡น Portugal (v0.4) CC NIF
๐Ÿ‡ป๐Ÿ‡ช Venezuela (v0.4) Cรฉdula RIF
๐Ÿ‡ฌ๐Ÿ‡ง United Kingdom (v0.6) NINO, NHS Number UTR, VAT
๐Ÿ‡ซ๐Ÿ‡ท France (v0.6) NIR SIREN, SIRET, TVA
๐Ÿ‡ฉ๐Ÿ‡ช Germany (v0.6) Steuer-ID Steuernummer, USt-IdNr
๐Ÿ‡ฎ๐Ÿ‡น Italy (v0.6) Codice Fiscale Partita IVA
๐Ÿ‡ณ๐Ÿ‡ฑ Netherlands (v0.6) BSN BTW
๐Ÿ‡ง๐Ÿ‡ช Belgium (v0.6) NRN BTW
๐Ÿ‡จ๐Ÿ‡ญ Switzerland (v0.6) AHV UID, MWST
๐Ÿ‡ต๐Ÿ‡ฑ Poland (v0.6) PESEL NIP, REGON
๐Ÿ‡ธ๐Ÿ‡ช Sweden (v0.6) Personnummer Organisationsnummer, Moms
๐Ÿ‡ณ๐Ÿ‡ด Norway (v0.6) Fรธdselsnummer, D-nummer Organisasjonsnummer, MVA
๐Ÿ‡ฉ๐Ÿ‡ฐ Denmark (v0.6) CPR CVR, Moms
๐Ÿ‡ซ๐Ÿ‡ฎ Finland (v0.6) HETU Y-tunnus, ALV
๐Ÿ‡ฎ๐Ÿ‡ณ India (v1.2) Aadhaar, VID, Voter ID (EPIC) PAN, GSTIN
๐Ÿ‡ฏ๐Ÿ‡ต Japan (v2.1) My Number Corporate Number
๐Ÿ‡ธ๐Ÿ‡ฌ Singapore (v2.2) NRIC, FIN UEN
๐Ÿ‡ฎ๐Ÿ‡ช Ireland (v2.0) โ€” VAT
๐Ÿ‡ฆ๐Ÿ‡น Austria (v2.0) โ€” UID (USt-IdNr)
๐Ÿ‡ฑ๐Ÿ‡บ Luxembourg (v2.0) โ€” TVA
๐Ÿ‡ฌ๐Ÿ‡ท Greece (v2.0) โ€” VAT (AFM, VIES prefix EL)
๐Ÿ‡จ๐Ÿ‡ฟ Czechia (v2.0) โ€” DIฤŒ (legal entity)
๐Ÿ‡ญ๐Ÿ‡บ Hungary (v2.0) โ€” VAT (kรถzรถssรฉgi adรณszรกm)
๐Ÿ‡ท๐Ÿ‡ด Romania (v2.0) โ€” VAT (CUI / CIF)
๐Ÿ‡ง๐Ÿ‡ฌ Bulgaria (v2.0) โ€” VAT (legal entity)
๐Ÿ‡ญ๐Ÿ‡ท Croatia (v2.0) OIB OIB
๐Ÿ‡ธ๐Ÿ‡ฐ Slovakia (v2.0) โ€” VAT (IฤŒ DPH)
๐Ÿ‡ธ๐Ÿ‡ฎ Slovenia (v2.0) โ€” VAT (DDV)
๐Ÿ‡ฑ๐Ÿ‡น Lithuania (v2.0) โ€” VAT (PVM)
๐Ÿ‡ฑ๐Ÿ‡ป Latvia (v2.0) โ€” VAT (PVN, legal entity high / personal moderate)
๐Ÿ‡ช๐Ÿ‡ช Estonia (v2.0) โ€” VAT (KMKR)
๐Ÿ‡ฒ๐Ÿ‡น Malta (v2.0) โ€” VAT
๐Ÿ‡จ๐Ÿ‡พ Cyprus (v2.0) โ€” VAT
๐Ÿ‡ฎ๐Ÿ‡ธ Iceland (v2.0) โ€” VSK (format-only, EEA not VIES)

Full per-country docs with algorithms and sources cited live in docs/countries/.

Confidence flag

Each spec carries a confidence value reflecting how well-verified its algorithm is:

  • high โ€” official source AND mature library agree.
  • moderate โ€” one official source OR mature library agrees; the other missing.
  • low โ€” only community / reverse-engineered. Format-only validation.
  • unconfirmed โ€” no algorithm verified. Format-only validation.

UIs can choose to surface a warning when a low-confidence document validates only by format.

Used by

  • Emiso โ€” multi-tenant electronic-invoicing platform for Central America. Uses nationid for receiver DUI / NIT / RUC validation and KYC masking.

If your product uses nationid and you'd like to be listed here, open a PR adding a one-line entry above.

Comparison

nationid validator.js cpf-cnpj-validator rut.js
LATAM countries 22 6 1 1
European countries 31 (EU-27 VIES + UK/CH/NO/IS) 8 0 0
EU-VIES VAT coverage EU-27 complete partial 0 0
Asia countries 3 (IN, JP, SG; KR/TW next) 0 0 0
El Salvador โœ… โŒ โŒ โŒ
Guatemala โœ… โŒ โŒ โŒ
Honduras โœ… โŒ โŒ โŒ
Costa Rica โœ… โŒ โŒ โŒ
Bundle size (1 country) ~3-5KB ~40KB full ~5KB ~5KB
TypeScript types First-class Yes Limited Limited
Tree-shakable subpaths โœ… โŒ N/A N/A
Zero deps โœ… โœ… โœ… โœ…

Roadmap

  • v0.1 โ€” 13 countries: SV, MX, CO, BR, PE, AR, CL, DO, GT, HN, CR, ES, US โœ…
  • v0.2 โ€” 8 additional codes in covered countries โœ…
  • v0.3 โ€” extract + pii + i18n + catalog subpaths โœ…
  • v0.4 โ€” 9 new countries: UY, VE, PA, EC, BO, PY, NI, CA, PT โœ…
  • v0.5 โ€” Passport family + ICAO 9303 algorithm + BR_CNPJ alphanum + MX_NSS + audit fixes โœ…
  • v0.6 โ€” Europe principal: GB, FR, DE, IT, NL, BE, CH, PL, SE, NO, DK, FI โœ…
  • v1.0 โ€” API stability declared. Every high-confidence spec backed by a first-party citation (CI-enforced). 76% smaller tarball. Type inference narrowing for parse / getSpec / extract*. โœ…
  • v1.1 โ€” Country catalog under nationid/catalog: names + flags + ISO alpha-3, locale param via Intl.DisplayNames (any BCP 47 tag). โœ…
  • v1.2 โ€” Asia phase 1: India (Aadhaar, VID, PAN, GSTIN, EPIC) + Verhoeff primitive. โœ…
  • v2.0 โ€” EU-VAT complete: 16 EU members + Iceland (EEA). ISO/IEC 7064 MOD 11,10 primitive. URL liveness audit pattern. โœ…
  • v2.1 โ€” Asia phase 2 โ€” Japan (My Number + Corporate Number). MIC + NTA algorithms cross-validated against python-stdnum. โœ…
  • v2.2 โ€” Asia phase 2 โ€” Singapore (NRIC, FIN, UEN). ICA/ACRA algorithms, UEN cross-validated against python-stdnum/stdnum/sg/uen.py. โœ…
  • v2.3-v2.4 โ€” Asia phase 2 (research + verification complete): KR (RRN/BRN), TW (ID/Tax). Implementing next.
  • v2.5 โ€” Balkans via JMBG core primitive (RS/BA/MK/ME) + GB Northern Ireland XI prefix + BG_EGN + CZ_RC (unlocks 10-digit BG and full CZ DIC branches).
  • v2.x โ€” @nationid/react companion with <DocumentInput>, additional i18n locales, mutation testing (Stryker), lazy REGISTRY for full root-import tree-shaking.

Contributing

See CONTRIBUTING.md. Country submissions are welcomed โ€” every country added must include cited official sources and a comprehensive test fixture set.

License

MIT โ€” see LICENSE.

About

TypeScript-first, zero-dependency validator for national identity and tax documents from every country. 52 countries, ~145 codes, cited confidence tiers, tree-shakable subpaths.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors