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

primecaptcha

v1.1.3

Published

High-performance, buffer-first image captcha library for Node.js. Zero disk I/O, crypto-secure randomness.

Readme

🔐 primecaptcha - Node.js Image Captcha Library

The ultimate high-performance, buffer-first Image CAPTCHA library for Node.js. Supports both Alphanumeric Text CAPTCHA and Mathematical CAPTCHA equations. Built with Zero Disk I/O and Crypto-Secure randomness to prevent OCR bots and spam.

npm version License: MIT Node.js Version

primecaptcha is a highly optimized, TypeScript-ready captcha generator for Express, NestJS, and Fastify. By rendering images entirely in memory (RAM), it guarantees ultra-low latency. Perfect for securing login forms, protecting registrations, and preventing spam on your APIs.

🖼️ Preview

| Captcha Type | Example Output | | :---: | :---: | | Text | | | Math | |


✨ Key Features

| Feature | Details | |---|---| | 🔠 Dual Mode | Choose between Alphanumeric Text CAPTCHA or Mathematical CAPTCHA | | ⚡ Buffer-First | Zero Disk I/O — everything is processed directly in RAM for maximum speed | | 🔒 Crypto-Secure | Uses crypto.randomInt for secure randomness | | 🎨 Anti-OCR | Per-character rotation, Y-jitter, vector lines, grain noise | | 📦 Lightweight | Only requires @napi-rs/canvas as the main dependency | | 🔷 TypeScript | Full type definitions included |


📦 Installation

npm install primecaptcha

Note: This library requires Node.js version 20 or higher for optimal performance and compatibility.


🚀 Usage

Basic Usage

import { generate } from 'primecaptcha';

const captcha = generate();

console.log(captcha.text);   // "K3PQ7M"
console.log(captcha.image);  // <Buffer 89 50 4e 47 ...> (PNG Buffer)

Integration with Express.js

import express, { Request, Response } from 'express';
import { generate } from 'primecaptcha';
import crypto from 'crypto';

const app = express();

// Map to store captcha (use Redis in production)
const captchaStore = new Map<string, string>();

// Endpoint to generate captcha
app.get('/api/captcha/generate', (req: Request, res: Response) => {
    // Generate text-based captcha
    const captcha = generate({
        type: 'text',        // 'text' or 'math' (default: 'text')
        width: 150,          // Canvas width (default: 200)
        height: 50,          // Canvas height (default: 80)
        length: 4,           // Number of characters (default: 6)
        fontSize: 24,        // Font size (default: 42)
        noiseIntensity: 7,   // Noise intensity 1-10 (default: 5)
    });

    // Generate a unique session ID to track the user/request
    const sessionId = crypto.randomBytes(16).toString('hex');

    // Store the captcha text for validation later
    captchaStore.set(sessionId, captcha.text);

    // Clear from memory after 5 minutes (300000 ms) to prevent memory leaks
    setTimeout(() => {
        captchaStore.delete(sessionId);
    }, 300000);

    // Return the image as a Base64 string so it can be easily embedded in frontend <img> tags
    res.json({
        success: true,
        sessionId: sessionId,
        image: `data:image/png;base64,${captcha.image.toString('base64')}`
    });
});

// Endpoint to verify captcha
app.post('/api/captcha/verify', (req: Request, res: Response) => {
    const { sessionId, userInput } = req.body;

    // Validate payload
    if (!sessionId || !userInput) {
        return res.status(400).json({
            success: false,
            message: 'sessionId and userInput are required in the request body'
        });
    }

    // Retrieve the original captcha text from memory
    const expectedText = captchaStore.get(sessionId);

    // If not found, it means the session has expired or is invalid
    if (!expectedText) {
        return res.status(400).json({
            success: false,
            message: 'Invalid captcha or session has expired'
        });
    }

    // Delete from store immediately to prevent brute-force attacks (One-Time Use)
    captchaStore.delete(sessionId);

    // Verify the user input against the expected text 
    // (Case Insensitive since primecaptcha text is always uppercase)
    if (userInput.toUpperCase() === expectedText) {
        return res.json({
            success: true,
            message: 'Captcha verified successfully!'
        });
    } else {
        return res.status(400).json({
            success: false,
            message: 'Incorrect captcha, please try again!'
        });
    }
});

Custom Options

import { generate } from 'primecaptcha';

// Text CAPTCHA
const textCaptcha = generate({
  type: 'text',        // 'text' or 'math' (default: 'text')
  width: 250,          // Canvas width (default: 200)
  height: 90,          // Canvas height (default: 80)
  length: 8,           // Number of characters (default: 6)
  fontSize: 48,        // Font size (default: 42)
  noiseIntensity: 7,   // Noise intensity 1-10 (default: 5)
});

// Math CAPTCHA
const mathCaptcha = generate({
  type: 'math',        // Mathematical equations (e.g. "12 + 5 = ?")
  width: 250,
  height: 80,
});
console.log(mathCaptcha.text); // "17" (The answer to validate against)

Async Version (for high-concurrency)

import { generateAsync } from 'primecaptcha';

const captcha = await generateAsync({ length: 6 });

📐 API Reference

generate(options?): PrimeResult

Main function to generate captcha synchronously.

Parameters:

| Option | Type | Default | Description | |---|---|---|---| | type | 'text' \| 'math' | 'text' | Captcha type: random text or simple math equation | | width | number | 200 | Canvas width in pixels | | height | number | 80 | Canvas height in pixels | | length | number | 6 | Number of captcha characters (only for text type) | | fontSize | number | 42 | Font size in pixels | | noiseIntensity | number | 5 | Noise intensity (1-10) |

Return Value (PrimeResult):

| Field | Type | Description | |---|---|---| | image | Buffer | PNG image as a Buffer | | text | string | Plaintext captcha text |

generateAsync(options?): Promise<PrimeResult>

Async version of generate() for concurrent use.


🛡️ Security

  • Filtered alphabet: ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (removes ambiguous characters: 0, O, 1, I)
  • Crypto-grade randomness: All randomization uses crypto.randomInt and crypto.randomBytes (not Math.random)
  • Anti-OCR layers:
    • Per-character rotation: -20° to +20°
    • Y-axis jitter: varying vertical position
    • Vector interference lines: minimum 4 bezier curves
    • Grain noise: pixel dust covering the entire canvas

⚡ Performance

Benchmark results on a MacBook Pro M1 (for reference):

| Configuration | Throughput | |---|---| | Default (200x80, 6 char) | ~800-1200 captchas/sec | | Minimal (150x60, 4 char) | ~1500-2000 captchas/sec | | Large (400x150, 8 char) | ~300-500 captchas/sec |

Run the benchmark yourself:

npm run benchmark

📄 License

MIT © ideapedyudi