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

@mrmelphin/otp-lib

v0.1.0

Published

OTP (One-Time Password) library with pluggable storage and delivery

Readme

otp-lib-ts

Lightweight OTP (One-Time Password) library for TypeScript/Node.js with pluggable storage and delivery.

Features

  • Cryptographically secure numeric OTP generation (crypto.randomInt)
  • SHA-256 hashed record storage (no plaintext codes persisted)
  • One active OTP per login (upsert semantics)
  • Configurable TTL and code length
  • Pluggable Repository and Sender interfaces — bring your own storage and delivery
  • Built-in repository implementations: In-Memory, PostgreSQL, SQLite, MongoDB

Install

npm install @mrmelphin/otp-lib

Quick Start

import { OtpService, DEFAULT_CONFIG } from "@mrmelphin/otp-lib";
import type { Repository, Sender } from "@mrmelphin/otp-lib";

import { createMemoryRepository } from "@mrmelphin/otp-lib";

const repo = createMemoryRepository();
const sender: Sender = /* your implementation */;

const svc = new OtpService(repo, sender, DEFAULT_CONFIG);

// Generate and send OTP
const result = await svc.generate("[email protected]");
if (result.sendError) {
  console.warn("OTP generated but send failed:", result.sendError);
}

// Verify OTP
const valid = await svc.verify("[email protected]", result.code);
if (!valid) {
  throw new Error("Invalid or expired OTP");
}
console.log("OTP verified!");

// Clean up expired records (call periodically)
await svc.cleanExpired();

Configuration

import type { OtpConfig } from "@mrmelphin/otp-lib";

const config: OtpConfig = {
  ttl: 10 * 60 * 1000, // 10 minutes (default: 300000 = 5 min)
  otpLength: 8,         // default: 6, minimum: 4
};

Interfaces

Repository

interface Repository {
  upsert(record: OtpRecord): Promise<void>;
  findByOtp(otpHash: string): Promise<OtpRecord | null>;
  deleteByOtpId(otpId: string): Promise<void>;
  deleteExpired(threshold: Date): Promise<void>;
}

Sender

interface Sender {
  send(login: string, code: string): Promise<void>;
}

Data Model

interface OtpRecord {
  otpId: string;     // SHA-256(login)
  otp: string;       // SHA-256(login + code)
  createdAt: Date;
}

Repositories

The library ships with four ready-to-use repository implementations. Each can be imported from the main package or directly from @mrmelphin/otp-lib/repo/*. Driver dependencies are optional peer deps — install only what you need.

In-Memory

Zero dependencies. Useful for tests and prototyping — data is lost on process restart.

import { createMemoryRepository } from "@mrmelphin/otp-lib";

const repo = createMemoryRepository();

PostgreSQL

Uses any pg-compatible client or pool.

npm install pg
import { Pool } from "pg";
import { createPostgresRepository, createPostgresSchema } from "@mrmelphin/otp-lib";

const pool = new Pool({ connectionString: "postgres://localhost:5432/mydb" });

// Create table and indexes (call once, e.g. on app startup)
await createPostgresSchema(pool);

const repo = createPostgresRepository(pool);
// Optional: createPostgresRepository(pool, { tableName: "custom_otp" })

SQLite

Uses better-sqlite3 (synchronous driver, wrapped in async interface).

npm install better-sqlite3
import Database from "better-sqlite3";
import { createSqliteRepository, createSqliteSchema } from "@mrmelphin/otp-lib";

const db = new Database("otp.db");

// Create table and indexes (call once)
createSqliteSchema(db);

const repo = createSqliteRepository(db);
// Optional: createSqliteRepository(db, { tableName: "custom_otp" })

MongoDB

Uses the official mongodb driver — pass a Collection.

npm install mongodb
import { MongoClient } from "mongodb";
import { createMongoRepository, createMongoSchema } from "@mrmelphin/otp-lib";

const client = new MongoClient("mongodb://localhost:27017");
const coll = client.db("mydb").collection("otp");

// Create indexes (call once)
await createMongoSchema(coll);

const repo = createMongoRepository(coll);

Testing

npm test

Design Decisions

  • SHA-256 without salt — OTP codes are short-lived and single-use; the threat model differs from password storage.
  • Lookup by OTP hash — verification uses findByOtp(hash) rather than looking up by login, preventing information leaks about active OTPs.
  • No rollback on send failure — if sending fails, the record stays; the caller can retry via generate (upsert overwrites), and TTL handles expiration.

License

MIT