@suaveplan/password-strength - zxcvbn-style password strength estimator — pattern-matching + dictionary cracker model per Wheeler 2016. Zero browser/Node/React deps.
Summary
zxcvbn-style password strength estimator — pattern-matching + dictionary
cracker model per Wheeler 2016. Universal; zero browser/Node/React
deps. Re-implementation of the open-source dropbox/zxcvbn algorithm in
style: Zod boundaries, OTel histograms + counters, structured
PWSTRENGTH.* error codes, 100% coverage, multilingual dictionary
subpaths, runtime dictionary swap, observable streaming variant, and a
hard 200-character DoS guard.
Documentation tree
- assess — (no submodules)
- assess-reactive — Debounce + cancel-on-newer-input wrapper around
assessfor UI strength meters that update as the user types. Each new… - assess — (no submodules)
- assess-reactive — Debounce + cancel-on-newer-input wrapper around
- dicts — (no submodules) - wikipedia — _(no submodules…
- de — (no submodules)
- wikipedia — (no submodules)
- english-wikipedia — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- names — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- passwords — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- es — (no submodules)
- wikipedia — (no submodules)
- fr — (no submodules)
- wikipedia — (no submodules)
- ru — (no submodules)
- wikipedia — (no submodules)
- zh-Hans — (no submodules)
- wikipedia — (no submodules)
- load-dictionaries — (no submodules) - wikipedia — _(no submodules…
- de — (no submodules)
- errors — (no submodules)
- error-codes — (no submodules)
- feedback — (no submodules)
- feedback — (no submodules)
- graphs — (no submodules) - azerty — (no submodules)…
- matchers — (no submodules) - date — (no submodules) <!…
- date — (no submodules)
- date — (no submodules)
- dictionary — (no submodules) - l33t-table — Provides the default character → lette…
- dictionary — (no submodules) - l33t-table — Provides the default character → lette…
- l33t-table — Provides the default character → letter substitution table used by the
dictionaryMatchmatcher to recognise l33t-enco…
- keyboard — (no submodules)
- keyboard — (no submodules)
- regex — (no submodules)
- regex — (no submodules)
- repeat — (no submodules)
- repeat — (no submodules)
- sequence — (no submodules)
- sequence — (no submodules)
- types — (no submodules) - date — (no submodules) <!…
- date — (no submodules)
- observability — (no submodules)
- metrics — (no submodules)
- schemas — (no submodules)
- schemas — (no submodules)
- crack-times — Maps a
guessescount to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin… - estimate-guesses — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- most-guessable-match-sequence — Picks the lowest-
Π guesses × k!cover of the password from the union of pattern matches plus implicit bruteforce-char… - score — Maps a
guessescount to a coarse integer score per Wheeler 2016 section 5. This score (0–4) is what most consumer…
- assess — (no submodules)- dicts — (no submodules)- de — (no submodules)- wikipedia — (no submodules)- english-wikipedia — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- names — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- passwords — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- es — (no submodules)- wikipedia — (no submodules)- fr — (no submodules)- wikipedia — (no submodules)- ru — (no submodules)- wikipedia — (no submodules)- zh-Hans — (no submodules)- wikipedia — (no submodules)- load-dictionaries — (no submodules)- errors — (no submodules)- error-codes — (no submodules)- feedback — (no submodules)- feedback — (no submodules)- graphs — (no submodules)- azerty — (no submodules)- azerty — (no submodules)- dvorak — (no submodules)- dvorak — (no submodules)- qwerty — (no submodules)- qwerty — (no submodules)- validate-graph — (no submodules)- matchers — (no submodules)- date — (no submodules)- date — (no submodules)- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- l33t-table — Provides the default character → letter substitution table used by the
dictionaryMatchmatcher to recognise l33t-enco…
- keyboard — (no submodules)- keyboard — (no submodules)- regex — (no submodules)- regex — (no submodules)- repeat — (no submodules)- repeat — (no submodules)- sequence — (no submodules)- sequence — (no submodules)- types — (no submodules)- observability — (no submodules)- metrics — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- crack-times — Maps a
guessescount to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin… - estimate-guesses — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- most-guessable-match-sequence — Picks the lowest-
Π guesses × k!cover of the password from the union of pattern matches plus implicit bruteforce-char… - score — Maps a
guessescount to a coarse integer score per Wheeler 2016 section 5. This score (0–4) is what most consumer… - assess-reactive — Debounce + cancel-on-newer-input wrapper around
assessfor UI strength meters that update as the user types. Each new… - assess — (no submodules)- dicts — (no submodules)- wikipedia — <!-- begin:auto-…
- de — (no submodules)- wikipedia — (no submodules)- english-wikipedia — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- names — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- passwords — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- es — (no submodules)- wikipedia — (no submodules)- fr — (no submodules)- wikipedia — (no submodules)- ru — (no submodules)- wikipedia — (no submodules)- zh-Hans — (no submodules)- wikipedia — (no submodules)- load-dictionaries — (no submodules)- wikipedia — <!-- begin:auto-…
- errors — (no submodules)- error-codes — (no submodules)- feedback — (no submodules)- feedback — (no submodules)- graphs — (no submodules)- azerty — <!-- begin:auto-doc…
- matchers — (no submodules)- date — <!-- begin:auto-docs…
- date — (no submodules)- date — (no submodules)- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- l33t-table — Provides the default character → letter substitution table used by the
dictionaryMatchmatcher to recognise l33t-enco…
- keyboard — (no submodules)- keyboard — (no submodules)- regex — (no submodules)- regex — (no submodules)- repeat — (no submodules)- repeat — (no submodules)- sequence — (no submodules)- sequence — (no submodules)- types — (no submodules)- date — <!-- begin:auto-docs…
- date — (no submodules)- date — (no submodules)- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- observability — (no submodules)- metrics — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- crack-times — Maps a
guessescount to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin… - estimate-guesses — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- most-guessable-match-sequence — Picks the lowest-
Π guesses × k!cover of the password from the union of pattern matches plus implicit bruteforce-char… - score — Maps a
guessescount to a coarse integer score per Wheeler 2016 section 5. This score (0–4) is what most consumer… - assess-reactive — Debounce + cancel-on-newer-input wrapper around
assessfor UI strength meters that update as the user types. Each new… - assess — (no submodules)- dicts — (no submodules)- wikipedia — _(no submodule…
- de — (no submodules)- wikipedia — (no submodules)- english-wikipedia — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- names — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- passwords — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- es — (no submodules)- wikipedia — (no submodules)- fr — (no submodules)- wikipedia — (no submodules)- ru — (no submodules)- wikipedia — (no submodules)- zh-Hans — (no submodules)- wikipedia — (no submodules)- load-dictionaries — (no submodules)- wikipedia — _(no submodule…
- errors — (no submodules)- error-codes — (no submodules)- feedback — (no submodules)- feedback — (no submodules)- graphs — (no submodules)- azerty — (no submodules)…
- matchers — (no submodules)- date — (no submodules) <…
- date — (no submodules)- date — (no submodules)- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- l33t-table — Provides the default character → letter substitution table used by the
dictionaryMatchmatcher to recognise l33t-enco…
- keyboard — (no submodules)- keyboard — (no submodules)- regex — (no submodules)- regex — (no submodules)- repeat — (no submodules)- repeat — (no submodules)- sequence — (no submodules)- sequence — (no submodules)- types — (no submodules)- date — (no submodules) <…
- date — (no submodules)- date — (no submodules)- dictionary — (no submodules)- l33t-table — Provides the default character → lette…
- observability — (no submodules)- metrics — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- crack-times — Maps a
guessescount to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin… - estimate-guesses — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- most-guessable-match-sequence — Picks the lowest-
Π guesses × k!cover of the password from the union of pattern matches plus implicit bruteforce-char… - score — Maps a
guessescount to a coarse integer score per Wheeler 2016 section 5. This score (0–4) is what most consumer… - assess-reactive — Debounce + cancel-on-newer-input wrapper around
assessfor UI strength meters that update as the user types. Each new… - assess — (no submodules)- dicts — (no submodules) - de — (no submodules) - wikipedia — (no submodules) - english-wikipedia — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- names — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- passwords — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- es — (no submodules) - wikipedia — (no submodules) - fr — (no submodules) - wikipedia — (no submodules) - ru — (no submodules) - wikipedia — (no submodules) - zh-Hans — (no submodules) - wikipedia — (no submodules) - load-dictionaries — (no submodules)- errors — (no submodules) - error-codes — (no submodules)- feedback — (no submodules) - feedback — (no submodules)- graphs — (no submodules) - azerty — (no submodules) - azerty — (no submodules) - dvorak — (no submodules) - dvorak — (no submodules) - qwerty — (no submodules) - qwerty — (no submodules) - validate-graph — (no submodules)- matchers — (no submodules) - date — (no submodules) - date — (no submodules) - dictionary — (no submodules) - dictionary — (no submodules) - l33t-table — Provides the default character → letter substitution table used by the
dictionaryMatchmatcher to recognise l33t-enco… - keyboard — (no submodules) - keyboard — (no submodules) - regex — (no submodules) - regex — (no submodules) - repeat — (no submodules) - repeat — (no submodules) - sequence — (no submodules) - sequence — (no submodules) - types — (no submodules)- observability — (no submodules) - metrics — (no submodules)- schemas — (no submodules) - schemas — (no submodules)- crack-times — Maps a
guessescount to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
- estimate-guesses — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- most-guessable-match-sequence — Picks the lowest-
Π guesses × k!cover of the password from the union of pattern matches plus implicit bruteforce-char… - score — Maps a
guessescount to a coarse integer score per Wheeler 2016 section 5. This score (0–4) is what most consumer…
Install
bun add @suaveplan/password-strength
Quick Start
import { assess } from "@suaveplan/password-strength";
const result = assess("Password1!");
console.log(result.score); // 0..4 bucket
console.log(result.guesses); // closed-form guess count
console.log(result.feedback.warning); // English-default UI string
console.log(result.crackTimes.offline_fast_hashing_1e10_per_second);
Modules
Features
- Six pattern matchers: dictionary (with l33t + reverse), sequence, repeat, date, keyboard adjacency, regex
- DP cover with factorial penalty per Wheeler section 4
- Four crack-time scenarios, site-tunable via
adjustments - 5-bucket score (
0–4) per Wheeler section 5 - 200-character DoS guard
- Streaming variant (
assessReactive) with debounce + cancel-on-newer - Runtime dictionary swap via
loadDictionaries - Multilingual dictionary subpaths (
en,de,fr,es,zh-Hans,ru) - Keyboard graph subpaths (
qwerty,dvorak,azerty) - Zod-validated boundaries at every public entry point
- OTel histogram + counters for assess duration, score distribution, error code, and matcher hit count
Baseline benchmarks
Run bun run src/__benchmarks__/assess.bench.ts to print baseline numbers
locally. Indicative timings on commodity hardware (single fork, no warmup):
| Bench | Mean |
|---|---|
| 8-char password | ~0.5 ms |
| 64-char password | ~5 ms |
| Dictionary-heavy | ~1 ms |
| DP n=100 | ~3 ms |
| DP n=199 | ~12 ms |
The 200-character DoS guard keeps p99 well under the 5 ms it() default.