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

@thecrossroads42/crypto

v0.1.1

Published

The Crossroads — client-side encryption primitives (audit kit). AES-GCM record envelope with Argon2id passphrase / device / managed key tiers. The privacy-critical code, published so the claims can be verified rather than trusted.

Readme

The Crossroads — client-side encryption (audit kit)

This is the privacy-critical encryption code from The Crossroads, published so you can check our claims instead of trusting them. It is the real code that runs in the browser — the part that decides whether your stored record is readable by anyone but you — separated from the rest of the app (which stays closed; it holds no secret that affects your privacy).

The security here does not depend on this code being secret (Kerckhoffs's principle): publishing it costs us nothing and lets you verify it. Licensed MIT (see LICENSE).

One honest limit, stated up front. Opening this code lets you audit the design, and lets you spot-check your own session (below). It does not cryptographically guarantee that the JavaScript your browser ran on a given day is byte-for-byte this code — a web app serves its code each load, so a compromised or coerced server could serve different code to a targeted user, and this repo would not catch that. That is the standard limit of in-browser crypto. The path to closing it (subresource integrity, reproducible builds, a pinning browser extension, a native client) is on our roadmap; until then, treat web delivery as a soft boundary, the same way we label the in-visit moment as soft.

Run the proofs yourself

No build step, no dependencies beyond Node 20+ and @noble/hashes:

node demo.mjs          # the §11 envelope + all three tiers + the re-wrap upgrade
node roundtrip.mjs     # encrypt-before-PUT round-trip (content opaque at rest, etc.)
node keyring.mjs       # tier manager: provision / unlock / upgrade / labeling
node longitudinal.mjs  # the consent gate (a declined read never resurfaces)

Each harness verifies its claims and prints a pass/fail count.

Claims → code

| Claim | Where it lives | |---|---| | Stored content is opaque at rest (AES-256-GCM, unique IV per record) | encryptRecord / decryptRecord in envelope.js | | A passphrase account is unreadable to the operator | wrapCEK_passphrase / unwrapCEK_passphrase + deriveKEKFromPassphrase (envelope.js); the server stores only { kdf, salt, iv, wrapped } — never the passphrase or key | | The passphrase key is Argon2id (memory-hard), not a fast hash | deriveKEKFromPassphrase (envelope.js), params recorded per record | | A device account is unreadable to the operator | wrapCEK_device / unwrapCEK_device (envelope.js); the device key never leaves local storage | | The managed tier is operator-readable by design (the honest soft tier) | TIER_INFO.managed (keyring.js); its key is held server-side | | Switching tiers re-wraps the key without re-encrypting your data | changeTier (keyring.js) — see keyring.mjs step 4 | | Consent gate: a rejected read never resurfaces; only accepted reads carry | reconcilePendingJudgments (dedup vs all statuses) + confirmedJudgments (accepted only) in longitudinalLogic.js | | A forgotten passphrase is unrecoverable (the proof the guarantee is real) | reset (keyring.js) — see keyring.mjs step 6 |

What the server actually sees

Every stored content object is an envelope { v, alg:"AES-GCM", iv, ct }ct is ciphertext. The shapes at rest:

  • Visit: cleartext operational metadata (id, dates, draft, cost) plus encrypted:true and enc: { card, content } — both opaque envelopes.
  • Held forks / judgments, profile, action plan, notes: stored as { encrypted:true, enc }.
  • Key record (server-side): { tier, env }. For passphrase, env is { kdf, salt, iv, wrapped } — the operator cannot derive the key without your passphrase. For device, env is { iv, wrapped } and the unwrapping key is only in your browser. For managed, the key is held server-side and the operator can unwrap (that tier's stated trade).

What the server never receives: your passphrase, the device key, or the unwrapped content key, for the passphrase and device tiers.

Verify your own session (no code required)

Open your browser's dev tools → Network, start and end a visit, and inspect the PUT /api/visits/:id body: you should see enc: { content: { iv, ct } } ciphertext and no plaintext of what you wrote. Then check that your passphrase never appears in any request.

What's here, and what isn't

Here: the pure, security-determining code — envelope.js, visitEnvelope.js, longitudinalLogic.js, keyring.js — and the runnable harnesses.

Not here (and not where your privacy lives): the glue that wires this core to auth, HTTP, and local storage; the server; and the app's content (the voices and prompts). None of that holds a secret that affects whether your stored record is readable.

KIT-MANIFEST.txt lists the SHA-256 of each file in this kit; verify-kit.mjs regenerates and checks it, so this published copy can be shown to match the code that builds the app.