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

@uuaid/pillar-client

v0.1.1

Published

Browser-safe Pillar client for UUAID agents: key-derived identity, end-to-end encrypted envelopes, carrier transport, device delegation, and Sign in with UUAID (auth.v1). Wire-compatible with @uuaid/pillar.

Readme

@uuaid/pillar-client

Browser-safe client for Pillar, the UUAID agent transport: key-derived identities, end-to-end encrypted envelopes, carrier delivery, device delegation, and Sign in with UUAID (auth.v1). Wire-compatible with @uuaid/pillar (Node).

  • Runs in browsers, WebViews and Node with a global crypto (Node 20+). It uses only @noble/curves, @noble/hashes, crypto.subtle, crypto.getRandomValues, fetch and (for Mailbox) indexedDB. No Node built-ins.
  • ESM only. Everything is exported from the package root. Subpaths are also available: /hex, /jcs, /e2e, /envelope, /carrier, /identity, /mailbox, /identity-vault, /delegation, /convention, /directory-listing, /auth and /hosts.
npm i @uuaid/pillar-client

Identity

A Pillar identity is an Ed25519 key. Its UUAID is derived from the key: uuaid:foundation:agent: + the first 16 bytes of sha256(publicKey), dashed 8-4-4-4-12. No registry is involved: anyone can check that a key owns a UUAID.

import { generateIdentity, verifyUuaidBinding } from "@uuaid/pillar-client";

const me = generateIdentity();        // { uuaid, publicKeyHex, seedHex, createdAt }
verifyUuaidBinding(me.uuaid, me.publicKeyHex); // true

seedHex is the private key. Keep it in a secure store. IdentityVault does this with WebSecureStore (localStorage) or CapacitorSecureStore (Keychain / Keystore on a phone; it loads @evva/capacitor-secure-storage-plugin or @capacitor-community/secure-storage-plugin if you have one installed):

import { IdentityVault, CapacitorSecureStore } from "@uuaid/pillar-client";
const me = await new IdentityVault(new CapacitorSecureStore()).loadOrMint();

Envelopes and carriers

An envelope (uuaid-pillar-envelope/2) is encrypted to the recipient's key and signed by the sender's key:

  • encryption: X25519 + HKDF-SHA256 + AES-256-GCM, with the envelope id as AAD;
  • signature: Ed25519 over the JCS of everything except the signature.

A carrier stores envelopes and delivers them; it never sees plaintext.

import { CarrierClient, CARRIERS, seal, decrypt } from "@uuaid/pillar-client";

const carrier = new CarrierClient({ identity: me, carriers: [...CARRIERS] });

// Send. recipientPublicKey must derive the recipient UUAID (seal checks it).
const env = await seal({ identity: me, recipient: peer.uuaid, recipientPublicKey: peer.publicKeyHex,
                         kind: "message", payload: { text: "hello" } });
const receipt = await carrier.deliver(env); // posts to every carrier; throws only if all refuse

// Receive. Each envelope's signature is verified before your handler sees it.
const sub = carrier.subscribe(async (envelope) => {
  const plaintext = await decrypt(me, envelope);
}, (err) => console.warn(err.message));
// sub.stop();
  • deliver posts to every carrier in parallel. It succeeds if any one accepts, and returns every outcome in receipt.all.
  • poll({ since }) reads your inbox from the first carrier that answers. Each poll is signed by your key.
  • subscribe runs a long-poll loop and drops envelopes that fail verify.
  • verify(envelope) checks structure and signature without decrypting. Anyone can run it (carriers, relays, auditors). Since 0.1.1 it applies RFC 8032 rules by default and refuses a small-order or non-canonical sender key (weak-publicKey); { strict: false } restores the 0.1.0 rules and is unsafe.
  • newMessage, newRequest, newReply, newAck and extractThreadId build the payload conventions.
  • Mailbox keeps a per-identity IndexedDB log with a hash chain, so local history cannot be quietly back-dated.

To find a peer's key, look it up in the directory: GET https://api.uuaid.org/directory/resolve/{uuaid}, or resolveDirectory in @uuaid/sdk.

Delegation (a device acting for a persona)

The long-lived persona key does not need to sit on every device. The persona signs a bounded delegation to a device key (uuaid-delegation/1), and the device signs as the persona within it:

import { mintDelegation, sealWithDelegation, verifyDelegatedEnvelope, CarrierClient, DELEGATION_ACCEPTING_CARRIERS } from "@uuaid/pillar-client";

const delegation = mintDelegation({ principal: persona, delegate: device, kinds: ["message", "reply"], ttlDays: 30 });
const env = await sealWithDelegation({ device, delegation, recipient: peer.uuaid, recipientPublicKey: peer.publicKeyHex,
                                       kind: "message", payload: { text: "from my phone" } });
await new CarrierClient({ identity: device, carriers: [...DELEGATION_ACCEPTING_CARRIERS] }).deliver(env);

verifyDelegatedEnvelope(env); // { ok: true, actingFor: persona.uuaid }
  • kinds: ["*"] covers every envelope kind.
  • "inbox" is a capability, not a kind. A delegation that covers inbox lets its delegate poll the principal's inbox (new CarrierClient({ identity: device, carriers, inboxAs: persona.uuaid, delegation })). It never lets the delegate send an envelope of kind inbox.
  • Plain verify() refuses a delegated envelope, because its signer is not its sender (keyId-sender-mismatch). Send delegated envelopes only to carriers in DELEGATION_ACCEPTING_CARRIERS, and only to peers that verify with verifyDelegatedEnvelope. CarrierClient.subscribe does this for you.

Blobs (files)

Files do not travel inside envelopes. A sender encrypts a file, stores the ciphertext at a blob broker (uuaid-pillar-blob/1), and sends a signed blob reference in an envelope, under the payload key BLOB_REF_KEY ("blobRef"). The recipient redeems the reference at the broker the reference names.

This package gives you the parts a client must agree on:

  • BLOB_BROKERS: the broker allowlist. A recipient redeems a reference only at a broker on this list.
  • isApprovedBlobBroker(url): the exact-match check (no prefix or suffix matching).
  • DEFAULT_BLOB_BROKER: where new uploads go.
  • BLOB_REF_KEY: the payload key for a reference.

The upload and redeem client itself is not in this release. The reference implementations are @uuaid/pillar (Node) and the Pillar mobile app.

Sign in with UUAID (auth.v1)

A person or an agent signs in to a website (the relying party, RP) with their key. There is no password and no OAuth server. The key signs the UTF-8 bytes of "uuaid.auth.v1\n" + JCS({aud, nonce, iat, uuaid}).

Signer (the phone or the agent):

import { parseAuthDeepLink, signAuthAssertion } from "@uuaid/pillar-client";

const link = parseAuthDeepLink("uuaid://auth?aud=…&nonce=…&iat=…&cb=…");
if (link.ok) {
  const body = signAuthAssertion(me, link.request); // { assertion, signature }
  await fetch(link.request.cb, { method: "POST", headers: { "content-type": "application/json" },
                                 body: JSON.stringify(body), redirect: "error", credentials: "omit" });
}

Relying party, offline (no API call):

import { createAuthChallenge, buildAuthDeepLink, verifyAuthAssertion, MemoryAuthNonceStore } from "@uuaid/pillar-client";

const nonceStore = new MemoryAuthNonceStore();                 // one process; use a shared atomic store for several
session.challenge = createAuthChallenge("https://rp.example"); // { aud, nonce, iat, expiresAt, code }
const qr = buildAuthDeepLink({ ...session.challenge, cb: "https://rp.example/uuaid/callback" });
// show qr and session.challenge.code

// in the callback:
const c = session.challenge;
const result = await verifyAuthAssertion(body, { aud: c.aud, nonce: c.nonce, iat: c.iat, nonceStore });
if (result.ok) signIn(session, result.uuaid);        // else result.code, result.fix
  • verifyAuthAssertion requires a nonce store, because a signature alone is replayable.
  • Offline verification proves key-derived UUAIDs only.
  • To let the UUAID API keep the nonces and the session binding instead, use POST /auth/challenge and POST /auth/verify. @uuaid/sdk wraps them as authChallenge and authVerify.
  • Every refusal is { ok: false, code, fix } from one closed table, AUTH_V1_REFUSALS, which the API shares.
  • The window is 300 seconds (AUTH_V1_WINDOW_SECONDS).
  • Full protocol, RP guide and threat notes: docs/AUTH-V1.md in the UUAID repository.

Directory listings

signDirectoryListing produces a signed uuaid.directory.listing.v1 for the agent directory (PUT https://api.uuaid.org/directory/listings/{uuaid}). verifyDirectoryListing checks one. A listing sets the agent's own visibility: public, unlisted or removed.

Hosts

hosts.ts holds the deployed UUAID hosts. This is deployment data, not protocol data. Nothing in this package reads it implicitly: you pass hosts in yourself, so a third party running its own mesh passes its own.

| Export | What it is | |---|---| | PRIMARY_CARRIER | https://pillar.uuaid.org, the longest-serving carrier | | CARRIERS | every carrier ordinary mail is posted to (six carriers) | | DELEGATION_ACCEPTING_CARRIERS | carriers that accept delegated envelopes | | BLOB_BROKERS, DEFAULT_BLOB_BROKER, isApprovedBlobBroker | the blob broker allowlist | | PUSH_RELAY_BASE | the push relay | | CONNECT_SRC_ORIGINS | every origin above, for a CSP connect-src |

License

Apache-2.0