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

@ralalabs/rid

v1.0.3

Published

Fast deterministic reversible ID encoding for numbers and strings using AES-128-CTR with base62 output

Readme

@ralalabs/rid

Deterministic, reversible ID obfuscation for Node.js and WebCrypto runtimes. The exporter produces tokens and Atlas decodes them using the same key and prefix. There are no runtime dependencies.

RID is obfuscation, not a confidentiality or authorization boundary. Keep sensitive values and their tokens behind the application's access controls.

Usage

npm install @ralalabs/rid
import { createCodec } from '@ralalabs/rid';

const key = process.env.RID_KEY;
if (!key) throw new Error('RID_KEY is required');

const codec = createCodec({ key, prefix: 'media' });
const token = await codec.encodeString('media:123');
const id = await codec.decodeString(token);

Generate a key once with await generateKey(), imported from @ralalabs/rid or @ralalabs/rid/generate. Store it in the application's secret configuration and share it with the services that decode those tokens. Generating a new key on startup makes existing tokens unreadable.

API

createCodec(options) validates configuration synchronously and returns an asynchronous codec.

| Option | Accepted values | | ----------- | ----------------------------------------------------------------------------------- | | key | A 32-character hexadecimal string (optional 0x prefix), or a 16-byte Uint8Array | | prefix | Optional letters, digits and hyphens; an empty string omits the prefix | | separator | A non-empty string without ASCII letters or digits; defaults to - |

The body uses base62 (0-9A-Za-z). Use URL-safe prefixes and separators when placing tokens in URLs. Decode requires the configured prefix and separator exactly.

| Method | Result | | ----------------------------------------------- | -------------------------------------------------------- | | encode(number \| string) | Promise<string> | | decode(token) | Promise<number \| string> | | encodeNumber(number) / encodeString(string) | Promise<string>; validates the input type | | decodeNumber(token) / decodeString(token) | A promise of the requested type; rejects a type mismatch | | encodeBatch(values) / decodeBatch(tokens) | Results in input order; rejects if any item fails |

Numbers must be non-negative safe integers, including zero. Strings may be empty and must contain well-formed Unicode, with at most 65,535 UTF-8 bytes. Leading Unicode BOM characters are preserved. Numeric 42 and string "42" have different tokens.

Validation failures use RidError. Crypto backend failures can propagate their native errors. Structural validation rejects malformed payloads; successful decoding does not prove authenticity.

Format and runtime

A six-byte header contains the RI marker, version, value type and payload length. Numbers use eight big-endian bytes; strings use UTF-8. AES-128-CTR transforms this payload with a fixed zero counter, then base62 represents the result. The prefix is outside the transformed payload.

The same value and key produce the same body across runtimes. Changing only the prefix does not change that body. Keep keys, prefixes and separators consistent between producers and consumers. Key or format changes require a coordinated strategy for persisted tokens.

Node.js uses node:crypto; environments without a Node version marker use WebCrypto AES-CTR. The build targets ES2022 and exports ESM, CommonJS and TypeScript declarations. Tests exercise both crypto adapters using fixed compatibility vectors.

Reuse codec instances. Adapter selection and imported WebCrypto keys are cached, and the payload avoids JSON serialization. Base62 uses BigInt conversion: this is an ID codec, not a bulk-data encoder. Decode bounds token size before conversion; callers should also limit request sizes and batch lengths for their workload. The batch methods use Promise.all without a concurrency limit.

Security boundary

The fixed counter preserves determinism but reuses the CTR keystream. Known plaintext can expose other values encrypted under the same key over the corresponding bytes. Tokens also have no authentication tag and can be modified. CTR counter reuse does not provide confidentiality; see RFC 9459, Security Considerations.

Prefixes are labels, not cryptographic separation. RID must not protect secrets from a party who can read the tokens, and must not replace authorization or authenticated encryption. Private storage and the application's access controls remain responsible for protecting server-side values.

Development

Use npm for this repository. Commit changes to package-lock.json alongside dependency updates; it is the authoritative lockfile. Use npm ci for reproducible installs and npm install when changing dependencies.

npm ci
npm run prepublishOnly

The verification script runs lint, formatting, type checking, ESM/CommonJS builds and tests. It does not publish. Source lives in src/, tests in test/, and build output in dist/.

License

MIT