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

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).

Readme

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