Files
skills/docs/security-stack/security/password-strength/README.md
2026-05-29 08:20:56 +01:00

208 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# @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.
<!-- begin:auto-docs -->
## Documentation tree
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- wikipedia — <!-- begin:auto-docs --> _(no submodules…
- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- wikipedia — <!-- begin:auto-docs --> _(no submodules…
- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- azerty — <!-- begin:auto-docs --> _(no submodules)_…
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- azerty — <!-- begin:auto-docs --> _(no submodules)_…
- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- date — <!-- begin:auto-docs --> _(no submodules)_ <!…
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs --> - l33t-table — Provides the default character → lette…
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs --> - l33t-table — Provides the default character → lette…
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- date — <!-- begin:auto-docs --> _(no submodules)_ <!…
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
<!-- end:auto-docs --> - [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-…
- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-…
- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-doc…
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-doc…
- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs…
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs…
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-docs --> _(no submodule…
- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-docs --> _(no submodule…
- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-docs --> _(no submodules)_…
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-docs --> _(no submodules)_…
- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs --> _(no submodules)_ <…
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs --> _(no submodules)_ <…
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_ - [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_ - [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_ - [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_ - [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ - [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_ - [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ - [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ - [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ - [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ - [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ - [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ - [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ - [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ - [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ - [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ - [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ - [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ - [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
## Install
```bash
bun add @suaveplan/password-strength
```
## Quick Start
```ts
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
| Module | Doc |
|---|---|
| `errors/error-codes` | [`src/errors/error-codes.md`](src/errors/error-codes.md) |
| `matchers/dictionary` | [`src/matchers/dictionary/dictionary.md`](src/matchers/dictionary/dictionary.md) |
| `matchers/dictionary/l33t-table` | [`src/matchers/dictionary/l33t-table.md`](src/matchers/dictionary/l33t-table.md) |
| `matchers/sequence` | [`src/matchers/sequence/sequence.md`](src/matchers/sequence/sequence.md) |
| `matchers/repeat` | [`src/matchers/repeat/repeat.md`](src/matchers/repeat/repeat.md) |
| `matchers/date` | [`src/matchers/date/date.md`](src/matchers/date/date.md) |
| `matchers/keyboard` | [`src/matchers/keyboard/keyboard.md`](src/matchers/keyboard/keyboard.md) |
| `matchers/regex` | [`src/matchers/regex/regex.md`](src/matchers/regex/regex.md) |
| `graphs/qwerty` | [`src/graphs/qwerty/qwerty.md`](src/graphs/qwerty/qwerty.md) |
| `graphs/dvorak` | [`src/graphs/dvorak/dvorak.md`](src/graphs/dvorak/dvorak.md) |
| `graphs/azerty` | [`src/graphs/azerty/azerty.md`](src/graphs/azerty/azerty.md) |
| `graphs/validate-graph` | [`src/graphs/validate-graph.md`](src/graphs/validate-graph.md) |
| `dicts/en/passwords` | [`src/dicts/en/passwords.md`](src/dicts/en/passwords.md) |
| `dicts/en/english-wikipedia` | [`src/dicts/en/english-wikipedia.md`](src/dicts/en/english-wikipedia.md) |
| `dicts/en/names` | [`src/dicts/en/names.md`](src/dicts/en/names.md) |
| `dicts/de/wikipedia` | [`src/dicts/de/wikipedia.md`](src/dicts/de/wikipedia.md) |
| `dicts/fr/wikipedia` | [`src/dicts/fr/wikipedia.md`](src/dicts/fr/wikipedia.md) |
| `dicts/es/wikipedia` | [`src/dicts/es/wikipedia.md`](src/dicts/es/wikipedia.md) |
| `dicts/zh-Hans/wikipedia` | [`src/dicts/zh-Hans/wikipedia.md`](src/dicts/zh-Hans/wikipedia.md) |
| `dicts/ru/wikipedia` | [`src/dicts/ru/wikipedia.md`](src/dicts/ru/wikipedia.md) |
| `dicts/load-dictionaries` | [`src/dicts/load-dictionaries.md`](src/dicts/load-dictionaries.md) |
| `scoring/score` | [`src/scoring/score.md`](src/scoring/score.md) |
| `scoring/crack-times` | [`src/scoring/crack-times.md`](src/scoring/crack-times.md) |
| `scoring/estimate-guesses` | [`src/scoring/estimate-guesses.md`](src/scoring/estimate-guesses.md) |
| `scoring/most-guessable-match-sequence` | [`src/scoring/most-guessable-match-sequence.md`](src/scoring/most-guessable-match-sequence.md) |
| `assess/assess` | [`src/assess/assess.md`](src/assess/assess.md) |
| `assess/assess-reactive` | [`src/assess/assess-reactive.md`](src/assess/assess-reactive.md) |
| `feedback/feedback` | [`src/feedback/feedback.md`](src/feedback/feedback.md) |
| `schemas` | [`src/schemas/schemas.md`](src/schemas/schemas.md) |
| `observability/metrics` | [`src/observability/metrics.md`](src/observability/metrics.md) |
## 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.