Skip to content

mohamad-kayal/vin-decoder-au

Repository files navigation

vin-decoder-au

A zero-dependency TypeScript VIN decoder with first-class Australian-market context.

CI License: MIT

The problem

Every Australian automotive tool that touches a VIN ends up reinventing the wheel. The existing JS libraries (vin-decoder, vin-validator) are unmaintained, US-centric, and — most painfully — they reject perfectly valid JDM, EU, and AU VINs because the ISO 3779 check digit doesn't match.

The check digit at position 9 is mandatory only for vehicles destined for North America and China. Toyota Japan, Mazda Japan, BMW Germany, Holden Australia — none of them populate it consistently. A library that treats a check-digit mismatch as a fatal error is unusable in any market that imports.

This library doesn't.

What I built

  • Pure parser. Splits a VIN into WMI, VDS, VIS. Computes the ISO 3779 check digit but reports it as informational, not fatal.
  • Australian lens. Bundled WMI table covers the AU import wave (LDV, Great Wall, Haval, BYD, MG, Chery, Polestar) plus historical AU manufacturers (Holden, Ford Australia). isLikelyJdmImport, isAuAssembled, isLikelyRhdMarket helpers derived from WMI metadata.
  • Honest model-year handling. The encoding cycles every 30 years and cannot be disambiguated from the VIN alone. We return both candidates and let you narrow with the compliance plate.
  • Discriminated unions everywhere. No throws. { ok: true, ... } | { ok: false, reason }.
  • Zero runtime dependencies. Works in Node ≥20 and the browser.
  • CLI included. npx vin-decoder-au — works as a one-shot tool.

Stack: TypeScript 5.7, ESM-only, vitest, tsup. No magic.

Install

npm install vin-decoder-au

Usage

import { decodeVin } from 'vin-decoder-au';

const result = decodeVin('JTDBR32E830012345');

if (!result.ok) {
  console.error(result.reason); // 'INVALID_LENGTH' | 'INVALID_CHARACTERS' | ...
  return;
}

result.wmi;                  // 'JTD'
result.manufacturer?.name;   // 'Toyota'
result.modelYearCandidates;  // [2003, 2033] — both are possible, you decide
result.checkDigit.valid;     // null — JDM VINs don't require it
result.au.isLikelyJdmImport; // true
result.au.isLikelyRhdMarket; // true

Other entry points

import { validateVin, getWmi, computeCheckDigit, modelYearCandidates } from 'vin-decoder-au';

validateVin('1HGBH41JXMN109186');  // { ok: true }
validateVin('1HGBH41JXMN10918!');  // { ok: false, reason: 'INVALID_CHARACTERS', message: ... }

getWmi('6T1');                     // { ok: true, manufacturer: { name: 'Toyota Australia', ... } }
computeCheckDigit('1HGBH41JXMN109186'); // 'X'
modelYearCandidates('M');          // [1991, 2021]

CLI

npx vin-decoder-au JTDBR32E830012345

# Or JSON for piping
npx vin-decoder-au --json 1HGBH41JXMN109186 | jq

# Or stdin
echo JTDBR32E830012345 | npx vin-decoder-au

How it differs

vin-decoder vin-validator vin-decoder-au
TypeScript-first
ESM
Throws on invalid ❌ (returns Result)
Rejects JDM/EU VINs on check-digit mismatch
Returns both 30-year candidates
AU-assembled / JDM-import flags
Last commit years ago years ago now

What I'd do next

  • AU compliance plate parser (build date / GVM / engine number) as a sibling package.
  • Optional NHTSA enrichment add-on (vin-decoder-au-nhtsa) for US-market year/model/trim — kept separate so the core library stays offline and dependency-free.
  • More WMIs — the table is curated, not exhaustive. PRs welcome, especially for sub-3-character WMIs used by small-volume manufacturers.

A note on accuracy

The AU helpers are hints, not legal facts. A WMI tells you where a vehicle was originally built; it does not tell you whether the specific car you're holding has been converted, re-imported, or grey-channeled. Use these flags as defaults in a UI, not as compliance evidence.

Why I built it

I run a used-car dealership in Brisbane and ship a multi-tenant inspection SaaS. Both touch VINs constantly. The status quo of throwing on imported vehicles wasn't acceptable, so I extracted the parser into something the rest of the AU ecosystem can use.


MIT · @mohamad-kayal · moekayal.me

About

Zero-dependency TypeScript VIN decoder with first-class Australian-market context (JDM-import detection, AU assembly, RHD inference). Includes CLI.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors