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

arxid

v0.2.0

Published

Keyed, reversible permutation for obfuscating sequential integer IDs: a 40-bit format-preserving Feistel network with an ARX round function, plus an optional base62 encoding.

Readme

arxid (TypeScript)

arxid obfuscates a sequential integer id into a keyed, unordered, reversible form. It is a balanced Feistel network with an ARX (Add-Rotate-XOR) round function, format-preserving over 40 bits, plus an optional 7-character base62 encoding.

This is a native TypeScript port of spec/SPEC.md, not a WASM wrapper. It is validated against the same canonical vectors as the Rust reference implementation, so ids obfuscated in either language decode identically in the other.

ESM, zero runtime dependencies.

Install

npm install arxid

Usage

import { Arxid } from "arxid";

// Load your own random key. Never hardcode one, and never copy a key out of
// documentation - including this page.
const arxid = new Arxid(BigInt(process.env.ARXID_KEY!));

const code = arxid.obfuscate(1001);
arxid.deobfuscate(code); // 1001

const s = arxid.obfuscateStr(1001); // 7-character base62
arxid.deobfuscateStr(s);            // 1001

Keys stored as raw bytes are read big-endian, so a key written by a Rust service is read identically here:

Arxid.fromKeyBytes(new Uint8Array([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));

Consecutive ids do not produce codes in any recoverable order:

const arxid = new Arxid(0x0123456789abcdefn);
const codes = Array.from({ length: 100 }, (_, i) => arxid.obfuscate(100 + i));
// no monotone structure: roughly half the steps ascend

Note what is not claimed: that neighbouring ids never land on adjacent codes. That is not a property of a good permutation, and spec v1 was wrong to assert it. See SPEC.md §11.

The key can also be passed per call, though Arxid is faster for repeated use because it derives the round subkeys once:

import { obfuscate, deobfuscate } from "arxid";

deobfuscate(obfuscate(7, 42n), 42n); // 7

Types

The key is a bigint, because a u64 does not fit safely in number (2^64 far exceeds 2^53). Values outside [0, 2^64) are reduced modulo 2^64.

Ids and codes are plain numbers. The 40-bit domain tops out at 1099511627775, well inside the safe integer range, so no big-integer type is needed for the public values.

import { MAX_ID, WIDTH_BITS, ROUNDS, CODE_LEN, ALPHABET, SPEC_VERSION } from "arxid";

API

| Export | Signature | |---|---| | Arxid | new Arxid(key: bigint) | | Arxid.fromKeyBytes | (bytes: Uint8Array \| readonly number[]) => Arxid (8 bytes, big-endian) | | Arxid#obfuscate | (id: number) => number | | Arxid#deobfuscate | (code: number) => number | | Arxid#obfuscateStr | (id: number) => string | | Arxid#deobfuscateStr | (s: string) => number \| null | | obfuscate | (id: number, key: bigint) => number | | deobfuscate | (code: number, key: bigint) => number | | toBase62 | (n: number) => string | | fromBase62 | (s: string) => number \| null |

The permutation is total: values outside [0, MAX_ID] are reduced modulo 2^40 rather than rejected, and nothing throws. Only string decoding can fail, and it returns null:

fromBase62("abc");      // null - wrong length
fromBase62("!!!!!!!");  // null - invalid character
fromBase62("zzzzzzz");  // null - above MAX_ID

Security

Full threat model: SPEC.md §9.

Recovering an id from a code without the key is not computationally infeasible. arxid raises enumeration from "count upward" to "do some work". It is not encryption, not a MAC (no authentication, no integrity), and has had no independent cryptographic audit. Any well-formed 7-character code decodes to some id, so a code decoding successfully does not mean you issued it. ID obfuscation is not access control.

Operationally: random key per deployment, loaded from the environment or a secret manager and never committed; a separate key per resource type, since there is no tweak and one key is one global mapping; and do not echo internal ids back in responses or errors.

This package implements spec v2. Spec v1 (0.1.x) is withdrawn — it used 4 rounds, which review showed to be separable from a random permutation at ~2^13 chosen queries. Codes issued by 0.1.x do not decode here.

Development

npm install
npm run typecheck
npm test        # includes the canonical vectors
npm run build

License

MIT. See LICENSE.