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

@uwmd/signing

v0.2.17

Published

Block and receipt signing for UW Markdown (RFC 0010) — Ed25519 / ES256 / ES384 over the normative signing inputs, with a file-backed reference key store. Kept out of @uwmd/core so the library stays crypto-free.

Readme

@uwmd/signing

Block, receipt, and module-manifest signatures for UW Markdown — the implementation of protocol §V.11 (RFC 0010) and §X.1 (RFC 0002).

Why this is a separate package

@uwmd/core is deliberately zero-cryptography. Reading, validating, editing, and computing over a .uw.md file requires no crypto, and the overwhelming majority of adopters should never take a crypto dependency to do any of it.

Signed blocks are for the deployments that genuinely need chain of custody: regulated lender data rooms, multi-party deal flow where sponsor, lender, and appraiser each sign their own sections, and agent-host accountability where a signature proves which agent instance wrote a block rather than merely what the actor field claims.

Core owns the normative, crypto-free half — the wire shape (_meta.signature) and the canonical signing input. This package owns the algorithms. Two seams connect them:

verifyChain(parsed, { signatureVerifier })   // blocks
verifyReceipt(receipt, source, { signatureVerifier })  // receipts (RFC 0016)

Without a verifier, core reports signatures as present and unchecked — never as valid.

Install

npm install @uwmd/signing

Needs Node ≥ 18.4 (Ed25519 in Web Crypto) or a modern browser. ed25519, es256, and es384 are the admitted algorithms.

Signing a block

import { computeBlockHash, parseUWFile } from '@uwmd/core';
import { generateSigningKeyPair, signBlock, stampBlockSignature } from '@uwmd/signing';

const { signing, verifying } = await generateSigningKeyPair('ed25519', 'sponsor-2026');

const parsed = parseUWFile(source);
const block = parsed.sections.rent_roll;

// A block must already carry `content_hash`: a signature over an absent hash
// commits to nothing, and validates as INT-05.
const signature = await signBlock(block, signing);
const signed = stampBlockSignature(block, signature);

signBlock does not mutate the block, and generateSigningKeyPair is for tests and local development — production keys belong in an HSM or cloud KMS behind a custom KeyStore.

Verifying

import { verifyChain } from '@uwmd/core';
import { createBlockSignatureVerifier, loadKeyStoreFile } from '@uwmd/signing';

const store = await loadKeyStoreFile('./keystore.json');
const result = await verifyChain(parsed, {
  signatureVerifier: createBlockSignatureVerifier(store),
});

result.signatures_present;   // how many blocks carry a signature
result.signatures_verified;  // how many actually verified

Or from the CLI:

uwmd verify deal.uwx.md --signing --keystore=./keystore.json

What each code means

| Code | Severity | Trigger | |---|---|---| | INT-05 | error | signature present with no content_hash. | | INT-06 | error | kid names a key the store does not hold. | | INT-07 | error | The signature does not verify, the algorithm is unadmitted, or the stamped content_hash no longer recomputes. | | INT-08 | warning | The algorithm is in the deployment's deprecation list. |

INT-06 and INT-07 are deliberately distinct. "I cannot check this" and "this is forged" call for opposite responses — load a key versus reject the document — and a verifier that merges them tells an operator to re-sign when the real fix is to configure their key store.

Key store format

Key distribution is out of scope: a public key that travels inside the document it authenticates proves nothing. The file format below is a reference, not a normative one — back a KeyStore with an HSM and never touch it.

{
  "keystore_version": "1",
  "keys": [
    {
      "kid": "sponsor-2026",
      "alg": "ed25519",
      "public_key_jwk": { "kty": "OKP", "crv": "Ed25519", "x": "..." }
    },
    {
      "kid": "lender-2026",
      "alg": "es256",
      "public_key_spki": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..."
    }
  ]
}

Exactly one of public_key_jwk / public_key_spki per entry. Every key is imported eagerly at load time, so a typo fails once, loudly, instead of appearing later as a per-block INT-07 that reads like tampering.

Rotation is "issue new blocks under a new kid and keep the old key loaded". A kid names one key and MUST NOT be reused; blocks signed under a retired kid stay verifiable for as long as the store retains it.

Module manifests

Module signing (RFC 0002, protocol §X.1) uses the same keys and the same verifier. The signed bytes are the RFC 8785 canonical manifest with signature removed.

import { loadModuleManifestAsync } from '@uwmd/core';
import { createModuleSignatureVerifier, signModule, stampModuleSignature } from '@uwmd/signing';

const signed = stampModuleSignature(
  manifest,
  await signModule(manifest, signing, { identity: '[email protected]' }),
);

const result = await loadModuleManifestAsync(signed, {
  signaturePolicy: 'require',           // or 'verify-if-present' / 'ignore'
  signatureVerifier: createModuleSignatureVerifier(store),
});

The three policies are ignore (default), verify-if-present (an unsigned module loads, a broken signature refuses), and require. Both checking policies refuse when the key store lacks the kid — a host that cannot check a signature has established nothing about the module.

identity is advisory. A signature proves the key holder asserted it, never that the assertion is true; an allowedIdentities allow-list is worth only as much as your decision to bind that kid to that identity.

Receipts

Receipt signing (RFC 0016) uses the same keys:

import { verifyReceipt } from '@uwmd/core';
import { createReceiptSignatureVerifier, signReceipt, stampReceiptSignature } from '@uwmd/signing';

const signed = stampReceiptSignature(receipt, await signReceipt(receipt, signing));

const verdict = await verifyReceipt(signed, source, {
  signatureVerifier: createReceiptSignatureVerifier(store),
});

Without a verifier, a signed receipt verifies as unverifiable with RCP-08.

Limits

  • signed_at is self-asserted. Audit-grade non-repudiation needs a timestamping authority countersignature, which protocol 1.x does not define.
  • No selective disclosure. Signing a redacted block would need Merkle commitments over fields; the current design has none.
  • Re-rooting a chain requires re-signing. content_hash covers _meta, and parent_hash lives there — see the erratum in RFC 0010.
  • No Sigstore. Keyless signing needs a Fulcio trust root and a Rekor inclusion proof — a vendored snapshot that fails closed when stale, or network access at verify time. scheme: "sigstore" is reserved in §X.1.2 so adding it later stays additive.

MIT. Part of the UW Markdown monorepo.