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

crudjt

v1.0.1

Published

Fast B-tree–backed token store for stateful sessions

Readme

Fast B-tree–backed token store for stateful user sessions
Provides authentication and authorization across multiple processes
Optimized for vertical scaling on a single server

Installation

NPM or (Yarn)
npm install crudjt

How to use

  • One process starts the master
  • All other processes connect to it

Start CRUDJT master (once)

Start the CRUDJT master when your application boots

Only one process should do this

The master is responsible for session state and coordination
All functions can also be used directly from it

For containerized deployments, see: Start CRUDJT master in Docker

Generate a new secret key (terminal)

export CRUDJT_SECRET_KEY=$(openssl rand -base64 48)

Start master (JavaScript)

const CRUDJT = require('crudjt');

await CRUDJT.Config.startMaster({
  secret_key: process.env.CRUDJT_SECRET_KEY,
  store_jt_path: 'path/to/local/storage', // optional
  grpc_host: '127.0.0.1', // default
  grpc_port: 50051 // default
});

// Use await CRUDJT.Config.shutdownServer() to shut down the gRPC server and let
// the process exit

Important: Use the same secret_key across all sessions. If the key changes, previously stored tokens cannot be decrypted and will return null or false

Start CRUDJT master in Docker

Create a docker-compose.yml file:

services:
  crudjt-server:
    image: crudjt/crudjt-server:latest
    restart: unless-stopped

    ports:
      - "${CRUDJT_CLIENT_PORT:-50051}:50051"

    volumes:
      - "${STORE_JT:-./store_jt}:/app/store_jt"
      - "${CRUDJT_SECRETS:-./crudjt_secrets}:/app/secrets"

    environment:
      CRUDJT_DOCKER_HOST: 0.0.0.0
      CRUDJT_DOCKER_PORT: 50051

Start the server:

docker-compose up -d

Ensure the secrets directory contains your secret key file at ./crudjt_secrets/secret_key.txt

For configuration details and image versions, see the CRUDJT Server on Docker Hub

Connect to an existing CRUDJT master

Use this in all other processes

Typical examples:

  • multiple local processes
  • background jobs
  • forked processes
const CRUDJT = require('crudjt');

CRUDJT.Config.connectToMaster({
  grpc_host: '127.0.0.1', // default
  grpc_port: 50051 // default
});

Process layout

App boot
├─ Process A → start_master
├─ Process B → connect_to_master
└─ Process C → connect_to_master

C

const data = { user_id: 42, role: 11 }; // required
const ttl = 3600 * 24 * 30; // optional: token lifetime (seconds)

// Optional: read limit
// Each read decrements the counter
// When it reaches zero — the token is deleted
const silenceRead = 10;

const token = await CRUDJT.create(data, ttl, silenceRead);
// token === 'HBmKFXoXgJ46mCqer1WXyQ'
// To disable token expiration or read limits, pass `null`
const token = await CRUDJT.create(
  { user_id: 42, role: 11 },
  null, // disable TTL
  null  // disable read limit
);

R

const result = await CRUDJT.read('HBmKFXoXgJ46mCqer1WXyQ');
// result === { metadata: { ttl: 101001, silence_read: 9 }, data: { user_id: 42, role: 11 } }
// When expired or not found token
const result = await CRUDJT.read('HBmKFXoXgJ46mCqer1WXyQ');
// result === null

U

const data = { user_id: 42, role: 8 };

// `null` disables limits
const ttl = 600;
const silenceRead = 100;

const result = await CRUDJT.update('HBmKFXoXgJ46mCqer1WXyQ', data, ttl, silenceRead);
// result === true
// When expired or not found token
const result = await CRUDJT.update('HBmKFXoXgJ46mCqer1WXyQ', { user_id: 42, role: 8 });
// result === false

D

const result = await CRUDJT.delete('HBmKFXoXgJ46mCqer1WXyQ');
// result === true
// When expired or not found token
const result = await CRUDJT.delete('HBmKFXoXgJ46mCqer1WXyQ');
// result === false

Performance

40 000 requests up to 256 bytes — median over 10 runs
macOS 15.7.4, ARM64 (Apple M1)
JavaScript 20.20.0
In-process benchmark; Redis accessed via localhost TCP

| Function | CRUDJT (JavaScript) | JWT (JavaScript) | redis-session-store (Ruby, Rails 8.0.2.1) | |----------|-------|------|------| | C | 0.372 second | 16.537 seconds | 2.909 seconds | | R | 0.010 second | 16.678 seconds | 4.436 seconds | | U | 0.684 second | X | 2.124 seconds | | D | 0.200 second | X | 3.984 seconds |

Benchmarks shown here are from a previous version of CRUDJT. For current performance metrics, see the GitHub repository

Full benchmark results

Storage (File-backed)

Disk footprint

40 000 tokens of 256 bytes each — median over 10 creates
darwin23, APFS

48 MB

Full disk footprint results

Path Lookup Order

Stored tokens are placed in the file system according to the following order

  1. Explicitly set via CRUDJT.Config.startMaster({store_jt_path: 'custom/path/to/file_system_db'});
  2. Default system location
    • Linux: /var/lib/store_jt
    • macOS: /usr/local/var/store_jt
    • Windows: C:\Program Files\store_jt
  3. Project root directory (fallback)

Storage Characteristics

  • CRUDJT automatically removing expired tokens after start and every 24 hours without blocking the main thread
  • Storage automatically fsyncs every 500ms, meanwhile tokens ​​are available from cache

Multi-process Coordination

For multi-process scenarios, CRUDJT uses gRPC over an insecure local port for same-host communication only. It is not intended for inter-machine or internet-facing usage

Limits

The library has the following limits and requirements

  • Node version: >= 18.0.0
  • Supported platforms: Linux, macOS, Windows (x86_64 / arm64)
  • Maximum json size per token: 256 bytes
  • secret_key format: must be Base64
  • secret_key size: must be 32, 48, or 64 bytes

Contact & Support

License

CRUDJT is released under the MIT License