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

@tsforge7/ts-password-validator

v0.1.0

Published

Entropy-based password validator with pluggable character sets and pattern collapsers.

Readme

ts-password-validator

English version

Валидатор паролей по энтропии для TypeScript. Подключаемые наборы символов и коллапсеры паттернов, без обязательных требований к типам символов, без словарей, без сетевых запросов. Поставка dual ESM + CJS с тайпингами и runtime-валидацией входных значений через Zod.

Алгоритм — TypeScript-порт wagslane/go-password-validator: те же наборы символов, те же штрафы за последовательности и повторы, та же формула log2(base^length).

Установка

npm install @tsforge7/ts-password-validator

Быстрый старт

import { validatePassword } from '@tsforge7/ts-password-validator';

const result = validatePassword('Ololo_123!');
// {
//   valid: true,
//   entropy: 55.5,
//   base: 72,
//   length: 10,
//   effectiveLength: 9,
//   strength: 'fair',
//   minEntropy: 50,
//   message: 'Password entropy 55.5 bits meets the required 50 bits (strength: fair).'
// }

validatePassword всегда возвращает полный IValidationResult — там и булево, и энтропия, и метка силы, и готовое сообщение для UI.

Свой порог

import { validatePassword } from '@tsforge7/ts-password-validator';

validatePassword('Ololo_123!', { minEntropy: 70 });
// { valid: false, strength: 'fair', message: '... below the required 70 bits ...' }

Переиспользуй валидатор (горячий путь)

import { createPasswordValidator } from '@tsforge7/ts-password-validator';

const validator = createPasswordValidator({ minEntropy: 70 });

validator.check('Ololo_123!'); //    → IValidationResult
validator.validate('Ololo_123!'); // → boolean
validator.getEntropy('Ololo_123!'); // → number
validator.details('Ololo_123!'); //   → IEntropyDetails

Только сила пароля

import {
  classifyStrength,
  getEntropyDetails,
  PASSWORD_STRENGTH,
} from '@tsforge7/ts-password-validator';

classifyStrength(42); // 'weak'
getEntropyDetails('xK#9!mLp_2');
// { entropy: 65.5, base: 94, length: 10, effectiveLength: 10 }

// Сравнивай с константой, а не магическими строками
if (classifyStrength(42) === PASSWORD_STRENGTH.weak) {
  // ...
}

PASSWORD_STRENGTHas const объект; его значения ровно те же, что и в IValidationResult.strength, а тип TPasswordStrength выведен из него.

Совместимые низкоуровневые функции

import {
  getPasswordEntropy,
  validatePasswordEntropy,
} from '@tsforge7/ts-password-validator';

getPasswordEntropy('Ololo_123!'); // 55.5 (бит)
validatePasswordEntropy('Ololo_123!'); // true

Кастомизация

createPasswordValidator принимает частичный options-объект — передавай только то, что хочешь переопределить.

import {
  createPasswordValidator,
  CharacterSet,
  RepeatCollapser,
  SequenceCollapser,
  PASSWORD_STRENGTH,
} from '@tsforge7/ts-password-validator';

const validator = createPasswordValidator({
  minEntropy: 60,
  characterSets: [
    new CharacterSet('абвгдеёжзийклмнопрстуфхцчшщъыьэюя'),
    new CharacterSet('АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'),
  ],
  sequences: ['абвгдеёжзийклмнопрстуфхцчшщъыьэюя'],
  strengthThresholds: [
    { entropy: 80, strength: PASSWORD_STRENGTH.veryStrong },
    { entropy: 60, strength: PASSWORD_STRENGTH.strong },
    { entropy: 40, strength: PASSWORD_STRENGTH.fair },
    { entropy: 20, strength: PASSWORD_STRENGTH.weak },
    { entropy: 0, strength: PASSWORD_STRENGTH.veryWeak },
  ],
});

validator.check('Прекрасный_Пароль42');

| Опция | Что переопределяет | По умолчанию | | -------------------- | ------------------------------------------------------- | ----------------------------- | | minEntropy | Порог для valid: true | 50 бит | | characterSets | Категории символов для расчёта базы | DEFAULT_CHARACTER_SETS | | sequences | Последовательности для дефолтного пайплайна коллапсеров | DEFAULT_SEQUENCES | | collapsers | Полный пайплайн коллапсеров (приоритетнее sequences) | DEFAULT_COLLAPSERS | | strengthThresholds | Соответствие энтропия → метка силы | DEFAULT_STRENGTH_THRESHOLDS |

Runtime-валидация входов

Каждая публичная функция и каждый конструктор класса, который можно инстанцировать напрямую, валидирует свои аргументы через Zod и кидает дружелюбный TypeError, если контракт нарушен. Защита работает и из JavaScript, и при any-типизированных данных.

validatePassword(123 as any);
// → TypeError: Invalid password: password must be a string (got number).

validatePassword('x', { minEntropy: -1 });
// → TypeError: Invalid options: minEntropy: Number must be greater than or equal to 0

validatePassword('x', { foo: 'bar' } as any);
// → TypeError: Invalid options: Unrecognized key(s) in object: 'foo'

new CharacterSet('');
// → TypeError: Invalid CharacterSet chars: CharacterSet chars must be a non-empty string

new RepeatCollapser(-1);
// → TypeError: Invalid maxStreak: maxStreak must be a positive integer

validatorOptionsSchema помечен .strict(), поэтому опечатка в ключе options ловится сразу, а не молча игнорируется.

Схемы лежат в src/commands/ как TypeScript-namespace'ы, которые в одном месте держат Zod-схему и выведенный из неё TS-тип:

import { z } from 'zod';

export namespace PasswordCommand {
  export const schema = z.string({ ... });
  export type Type = z.infer<typeof schema>;
}

Доступные команды: PasswordCommand, CharacterSetCommand, CollapserCommand, StrengthCommand, ValidatorOptionsCommand. Хелпер assertSchema(schema, value, label) делает safeParse + оборачивает в TypeError, если хочется валидировать что-то своё.

Форма результата

interface IValidationResult {
  valid: boolean;
  entropy: number; // биты
  base: number; // размер пула
  length: number; // сырых code points
  effectiveLength: number; // после схлопывания повторов/последовательностей
  strength: TPasswordStrength;
  minEntropy: number;
  message: string;
}

// PASSWORD_STRENGTH — источник истины, TPasswordStrength выведен из него
const PASSWORD_STRENGTH = {
  veryWeak: 'very-weak', //   0 – 34 бит
  weak: 'weak', //  35 – 49 бит
  fair: 'fair', //  50 – 69 бит
  strong: 'strong', //  70 – 99 бит
  veryStrong: 'very-strong', // 100+ бит
} as const;

type TPasswordStrength =
  (typeof PASSWORD_STRENGTH)[keyof typeof PASSWORD_STRENGTH];

Алгоритм

entropy(пароль) = effectiveLength · log2(base)

База (base)

Сумма размеров всех встреченных в пароле категорий + 1 за каждый уникальный символ вне этих категорий (например, unicode-буквы).

| Категория | Дефолтные символы | Размер | | ------------------ | ------------------------------------------------------------------------------------------------------------- | ------ | | Replace | !@$&* | 5 | | Separator | _-., (включая пробел) | 5 | | Прочие специальные | ", #, %, ', (, ), +, /, :, ;, <, =, >, ?, [, \, ], ^, {, \|, }, ~ | 22 | | Нижний регистр | a–z | 26 | | Верхний регистр | A–Z | 26 | | Цифры | 0–9 | 10 | | Unknown (каждый) | всё остальное (за каждый уникальный символ) | +1 |

Максимальная база со всеми шестью категориями — 94.

Эффективная длина

Длина уменьшается до подсчёта энтропии, чтобы не переоценивать предсказуемые паттерны:

  • Повторы — три и более одинаковых подряд считаются как два. aaaa → эффективная aa.
  • Последовательности — три и более подряд идущих символа из известной последовательности считаются как два; проверка регистронезависимая, в обе стороны. Дефолтные последовательности: 0123456789, qwertyuiop, asdfghjkl, zxcvbnm, abcdefghijklmnopqrstuvwxyz. Пример: qwertyqw, 987698.

Дефолтный порог

DEFAULT_MIN_ENTROPY = 50 бит. Авторы исходной Go-библиотеки рекомендуют 50–70 в зависимости от модели угроз.

Публичный API

Функции

| Экспорт | Возвращает | | ---------------------------------------- | -------------------- | | validatePassword(password, options?) | IValidationResult | | createPasswordValidator(options?) | PasswordValidator | | getEntropyDetails(password) | IEntropyDetails | | classifyStrength(entropy, thresholds?) | TPasswordStrength | | getPasswordEntropy(password) | number (биты) | | validatePasswordEntropy(password) | boolean | | assertSchema(schema, value, label) | разобранное значение |

Классы

| Экспорт | Назначение | | --------------------------- | ---------------------------------------------------- | | PasswordValidator | validate, check, getEntropy, details | | PasswordEntropyCalculator | calculate, details | | BaseCalculator | Размер пула из списка CharacterSet | | EffectiveLengthCalculator | Сокращает длину через пайплайн IPatternCollapser's | | CharacterSet | Пул символов с contains / size | | RepeatCollapser | aaa…aa | | SequenceCollapser | Коллапс прямых и обратных последовательностей |

Команды (Zod-схемы + выведенные типы)

| Namespace | Члены | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | PasswordCommand | schema, Type | | CharacterSetCommand | charsSchema, Chars | | CollapserCommand | sequenceSchema, maxStreakSchema, patternSchema, Sequence, MaxStreak, Pattern | | StrengthCommand | passwordStrengthSchema, entropySchema, thresholdSchema, thresholdsSchema, Entropy, Threshold, Thresholds | | ValidatorOptionsCommand | schema, Type |

Интерфейсы, типы и константы

| Экспорт | Тип | | ----------------------------- | --------- | | IValidationResult | интерфейс | | IEntropyDetails | интерфейс | | IPatternCollapser | интерфейс | | TPasswordStrength | тип | | PASSWORD_STRENGTH | константа | | DEFAULT_CHARACTER_SETS | константа | | DEFAULT_SEQUENCES | константа | | DEFAULT_COLLAPSERS | константа | | DEFAULT_MIN_ENTROPY | константа | | DEFAULT_STRENGTH_THRESHOLDS | константа | | defaultEntropyCalculator | инстанс | | defaultPasswordValidator | инстанс |

Output-shape интерфейсы (IValidationResult, IEntropyDetails, IPatternCollapser) лежат в src/interfaces/ и начинаются с I. Input shapes с runtime-схемой лежат в src/commands/ как namespace'ы. Type-aliasы верхнего уровня (например, TPasswordStrength) — с префиксом T.

Структура проекта

src/
├── base-calculator.ts
├── character-set.ts
├── defaults.ts
├── effective-length-calculator.ts
├── factory.ts
├── index.ts                       # публичный вход
├── password-entropy-calculator.ts
├── password-entropy.ts
├── password-validator.ts
├── strength.ts
├── validate.ts
├── collapsers/
│   ├── index.ts
│   ├── repeat-collapser.ts
│   └── sequence-collapser.ts
├── commands/                      # Zod-схемы + выведенные типы
│   ├── index.ts
│   ├── assert.ts
│   ├── character-set.command.ts
│   ├── collapser.command.ts
│   ├── password.command.ts
│   ├── strength.command.ts
│   └── validator-options.command.ts
├── constants/
│   ├── index.ts
│   ├── character-sets.constant.ts
│   ├── collapsers.constant.ts
│   ├── min-entropy.constant.ts
│   ├── password-strength.constant.ts
│   ├── sequences.constant.ts
│   └── strength-thresholds.constant.ts
└── interfaces/
    ├── index.ts
    ├── entropy-details.interface.ts
    ├── pattern-collapser.interface.ts
    └── validation-result.interface.ts

Импорты всегда идут через барель папки — from './constants', from './interfaces', from './collapsers', from './commands' — без указания конкретного *.constant.ts / *.interface.ts / *.command.ts файла снаружи его собственной папки.

Скрипты

npm test          # vitest (86 тестов: логика + валидация входов)
npm run typecheck # tsc --noEmit
npm run lint      # eslint
npm run format    # prettier --write
npm run build     # tsup → dist/index.js (ESM) + dist/index.cjs + типы

Сборка (tsup + esbuild + rollup-plugin-dts) выдаёт плоский dist/:

dist/
├── index.js       # ESM-бандл
├── index.cjs      # CJS-бандл
├── index.d.ts     # ESM-типы
├── index.d.cts    # CJS-типы
└── *.map          # sourcemaps

Лицензия

MIT © 2026 tsforge7