vin-decoder-au
v0.1.0
Published
Zero-dependency TypeScript VIN decoder with first-class Australian-market context (JDM-import detection, AU assembly, RHD inference).
Maintainers
Readme
vin-decoder-au
A zero-dependency TypeScript VIN decoder with first-class Australian-market context.
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,isLikelyRhdMarkethelpers 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-auUsage
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; // trueOther 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-auHow 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
