2.6 KiB
sequence — alphanumeric sequence matcher
(no submodules)
Purpose
Detects ascending and descending runs of consecutive characters within a single
alphabet class (lowercase letters, uppercase letters, decimal digits) per
Wheeler §3.2. A run of abcd carries far less entropy than four random
letters and the scorer needs an explicit pattern record to compute the right
guesses count.
Features
- Lower, upper, and digit alphabets
- Both directions (ascending
1234, descending9876) - Minimum length 2
- Each match carries
sequenceSpace(size of the alphabet) andascending
Usage: Basic Example
import { sequenceMatch } from "@suaveplan/password-strength/matchers/sequence";
const matches = sequenceMatch("abcd");
console.log(matches[0].ascending); // true
console.log(matches[0].sequenceName); // "lower"
Usage: Advanced Example
import { sequenceMatch } from "@suaveplan/password-strength/matchers/sequence";
// Mixed runs are reported separately
for (const m of sequenceMatch("abc987XYZ")) {
console.log(m.token, m.sequenceName, m.ascending);
}
// abc lower true
// 987 digits false
// XYZ upper true
API Reference
sequenceMatch(password: string): SequenceMatch[]— return every maximal ascending or descending run of length ≥ 2 within a single alphabet class.
Implementation Notes
The walk is single-pass: at each index, the matcher checks the delta between
adjacent characters; if it is +1 or -1 within the same alphabet, the
matcher extends the run greedily until the delta breaks or the alphabet
changes. Runs of length 1 are filtered out. The algorithm is O(n) over the
password length and emits each maximal run exactly once.
Additional Implementation Notes
The implementation follows the canonical zxcvbn algorithm from Wheeler 2016 with
the suaveplan-style additions described in the package proposal: structured error
codes via the defineCodes registry, Zod boundaries at every public entry
point, OTel histograms and counters keyed to low-cardinality attributes, and
a strict input-length guard at 200 characters. Consumers integrate with their
existing observability stack by installing a meter provider before importing
the package, and with their i18n stack via the MessageResolver callback type
declared in @suaveplan/types. The bundled data tables are intentionally
small to keep the package bundle compact; production deployments should swap
in fuller frequency-ranked tables via loadDictionaries. The default English
dictionary set is a frozen DictionarySet that the matcher never mutates;
caller-supplied dictionaries override defaults by name.