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

@delegus/sdk

v0.3.3

Published

Delegus SDK and CLI (spec §15 step 4): org.create, agent.create, grant.create, agent.sign, delegus.verify, outcome reporting.

Readme

@delegus/sdk

Spec §15 step 4: the three roles of the protocol as one small library, plus the delegus CLI. Zero runtime dependencies beyond @delegus/core; Node ≥ 22.18 (type stripping, no build step). Signers are pluggable (§2.2): the in-memory Ed25519 signer is the dev default; anything that produces a 64-byte Ed25519 signature over raw bytes (KMS, HSM, TPM) fits the Signer interface.

Relying Party: the afternoon integration

import { Delegus, actions } from "@delegus/sdk";

const delegus = new Delegus({ apiKey: process.env.DELEGUS_API_KEY, publicBaseUrl: "https://seller.example" });

app.post("/orders", async (req, res) => {
  const d = await delegus.verify({
    grant: req.header("Delegus-Grant"),
    proof: req.header("Delegus-Proof"),
    action: actions.purchase({ resource: req.body.orderId, amount: req.body.amountMinor, currency: req.body.currency }),
    request: { method: req.method, path: req.originalUrl },   // optional §4.3 binding check
  });
  if (d.decision !== "ALLOW") return res.status(403).json({ reason: d.reason });
  // proceed; persist d.receipt (the signed JWS) with the order
});

verify() returns the signed Receipt for ALLOW and DENY alike (§5.6). With request given, the SDK first checks the Proof's htm/htu against the request the RP actually received (publicBaseUrl + path, normalized per §4.3) and throws ProofBindingError on mismatch, so a Proof made for one endpoint cannot be presented at another.

Delegus answers with the receipt of the relying party's own profile: a delegus-receipt-v1 for a v0.2 relying party, a delegus-receipt-v2 (with authority, authority_opening, relies_on and opening beside it) for one on the v0.3 profile (delegus-base-v3). The default, protocol: "auto", takes either: it reads the version from inside the signed receipt, checks a v1 receipt's signature under the service's published keys and returns it as before, and checks a v2 response in full (signature, the authority opened against its commitment, every hash and opening), failing closed on anything else. Receipt keys come from the service DID document (/.well-known/did.json, did:web:delegus.ai in production), fetched once per client and cached; if they cannot be fetched, verify() throws. isVerifyResponseV3(d) tells the two apart. requires (the prior decisions an action must rest on) is for v0.3 relying parties only; a v1 receipt in answer to it is refused. protocol: "v0.2" and protocol: "v0.3" pin one profile: a receipt of the other one throws ResponseIntegrityError naming the pin and the receipt version received. Later: delegus.outcomes.report(receiptId, { type: "fulfilled", occurred_at }) and delegus.decisions.get(receiptId).

Agent

import { Agent, actions } from "@delegus/sdk";
const agent = Agent.create();                       // did:key, in-memory Ed25519 (or new Agent(customSigner))
// … the Principal issues a Grant naming agent.did …
const headers = await agent.headers({ grant: grantJws, audience: rpDid, method: "POST", url: "https://seller.example/orders", action });
await fetch("https://seller.example/orders", { method: "POST", headers: { ...headers, "content-type": "application/json" }, body });

Both sides build the Action with actions.purchase() / actions.apiCall() from the same wire fields, which is what makes action_hash and request_hash agree (§4.3).

Principal

const admin = new Delegus({ adminToken });
const org = await admin.org.create({ slug: "acme" });         // managed: key generated locally, public key registered
const grant = await org.principal.grant.create({
  agent: agent.did,
  authority: [{ action: "commerce:purchase", constraints: { maxAmount: 50000, currency: "USD" } }],
});                                                          // allocates the status entry at Delegus, signs locally
await org.principal.grant.revoke(grant.id);                  // resolves once every later /verify anywhere will deny
await org.principal.agents.disable(agent.did);               // kill switch
await org.principal.keys.compromise(org.kid);                // §11

const hosted = await admin.org.register({ did: "did:web:acme.com", kid: "did:web:acme.com#key-1", signer });
hosted.verification;                                         // DNS TXT / well-known instructions
await hosted.principal.verifyDomain();

Organizations (dashboards, consoles)

An organization is a customer account that owns Principals and relying parties. Org keys (dk_org_read_…, dk_org_admin_…) read everything about the members and, with role admin, administer them. They are never accepted by verify or by grant.create. A console holds one org key per tenant server-side and keeps its own users out of this API.

const admin = new Delegus({ adminToken });
const org = await admin.orgs.create({ slug: "acme", name: "Acme Inc" });
await admin.orgs.addMember(org.org_id, "did:web:acme.com");
const { api_key } = await admin.orgs.apiKeys.create(org.org_id, "admin", "console tenant");

const tenant = new Delegus({ apiKey: api_key });
await tenant.orgs.get(org.org_id);                              // members with verification state and RP settings
await tenant.decisions.list({ keyId: "9d44dd608cfe" });         // receipts across the org's relying parties
await tenant.usage({ byKey: true });                            // verifies per day, per RP API key
await tenant.grants.list({ state: "active" });
await tenant.audit({ action: "grant.revoke" });
await tenant.apiKeys.create("seller prod", sellerDid);         // mint a member's verify key (shown once)
await tenant.orgs.principal("did:web:acme.com").grant.revoke(grantId); // act for a member Principal

MCP server (Policy Enforcement Point)

Make a Node (Express-style) MCP server authorization-aware in one line. Every JSON-RPC tools/call is verified; nothing runs without an ALLOW, and each verified call returns a signed Decision Receipt you keep. Fail closed. initialize, tools/list, ping and notifications pass through.

Install

npm install @delegus/sdk

One line

import express from "express";
import { Delegus } from "@delegus/sdk";

const app = express();
app.use(express.json());

const delegus = new Delegus({ apiKey: process.env.DELEGUS_RP_KEY, publicBaseUrl: "https://tools.acme.com" });
app.use("/mcp", delegus.mcp());   // every tools/call is now verified

On ALLOW the receipt is on req.delegus.receipt and Delegus-Receipt-Id is set; on DENY the middleware returns HTTP 403 with error.data.delegus = { decision, reason, receipt_id, receipt_url } (JSON-RPC error code -32040) and the tool never runs. A missing-credentials response adds Delegus-Relying-Party and Delegus-Verify: required for discovery. Options: mcp({ tools, onDecision, relyingParty, protocol, requires, map }) — tools limits enforcement to an allow-list or predicate (unlisted tools pass through unverified). protocol is passed to verify(): the default "auto" works against a relying party on either profile, and for one on the v0.3 profile (delegus-base-v3) req.delegus.receipt is the checked v0.3 response (the receipt with authority opened against authority_commitment). requires lists prior decisions every enforced call must rest on (v0.3 relying parties only). "v0.2" and "v0.3" pin one profile; a receipt the setting does not accept refuses the call with SERVICE_UNAVAILABLE (the cause is in onDecision's error), and the middleware never retries a check.

Anything the middleware cannot read is refused with the same 403, never passed through: a POST with no parsed body (mount express.json() before it), a body that is not JSON or not a JSON-RPC message, or that has duplicate member names, names that differ only by case, or an integer above 2^53 − 1 (REQUEST_UNREADABLE; the server behind could read a different value than the one checked), a JSON-RPC batch that carries an enforced tools/call (BATCH_NOT_SUPPORTED; batches left MCP in 2025-06-18), and a tools/call without a string tool name (TOOL_NAME_INVALID). These are the middleware's own refusals, like a missing Delegus-Grant: Delegus is never called, so they carry no signed receipt (receipt_id is null). A batch passes only when every message in it provably invokes no enforced tool. A raw string or byte body is parsed and enforced; hand your MCP server the same parsed body the middleware saw rather than re-parsing the raw bytes, so both read one message. GET (the SSE stream), HEAD, OPTIONS, a DELETE without a body (session end) and JSON-RPC responses pass; a body on any other verb is read like a POST.

The agent side

The agent presents two headers on the tools/call POST, bound to the same tool URI:

const headers = await agent.mcpHeaders({ grant, endpoint: "https://tools.acme.com/mcp", tool: "get_customer", rpDid });
// { "Delegus-Grant": "eyJ…", "Delegus-Proof": "eyJ…" }

When the server publishes a tool map (below), the agent fetches it once and signs through it, so it builds the same Action the server checks:

import { fetchToolMap } from "@delegus/sdk";
const found = await fetchToolMap("https://tools.acme.com/mcp");          // cached by hash; null when the server publishes none
const headers = await agent.mcpHeaders({ grant, endpoint: "https://tools.acme.com/mcp", tool: "git.push", rpDid,
  args: { branch: "feature/login" }, ...(found ? { map: found.map } : {}) });

What it covers: the tool, and with a map its arguments

Without a map the middleware covers the tool: each tools/call is one api:call on the tool URI <publicBaseUrl><path>/tools/<name>, so a Grant's resources decide which tools an agent may call, not what it calls them with. A tool map says how a tool's arguments become the Action's resource and amount, and the Grant can then constrain them:

app.use("/mcp", delegus.mcp({ map: {
  version: 1,
  tools: {
    "git.push":     { action: "api:call", resource: "refs/heads/{arg:/branch}" },
    "payment.send": { action: "commerce:purchase", resource: "payee:{arg:/recipient}",
                      amount: { value: "/amount_cents", currency: "/currency", unit: "minor" } },
  },
} }));

With that map, git.push with { branch: "feature/x" } is an api:call on <tool URI>/refs/heads/feature/x, so a Grant resource pattern https://tools.acme.com/mcp/tools/git.push/refs/heads/feature/* allows feature branches and nothing else, and payment.send with { recipient: "acme", amount_cents: 2400000, currency: "USD" } is a commerce:purchase of 2,400,000 minor units on payee:acme, refused with AMOUNT_EXCEEDS_AUTHORITY above the Grant's maxAmount. The receipt pins exactly the mapped values.

  • Placeholders are {arg:<JSON pointer>} into the call's arguments (RFC 6901, not RFC 6570); values are strings, or numbers and booleans in their JSON text. A value is split on / and each piece percent-encoded with only unreserved characters kept, so a value can never add a wildcard, climb with .. (plain, percent-encoded or in lookalike characters) or change the tool URI, while / inside a value keeps its meaning. Write resource patterns in NFC; values are not normalized.
  • action is api:call (the resource is appended to the tool URI) or one of commerce:purchase, commerce:quote, commerce:accept, commerce:fulfil (the resource is the template's result; the priced three need amount: unit minor, a non-negative integer, or major with decimals, a plain decimal such as "1.50" converted exactly and refused, never rounded, when it has more fraction digits). currency is a pointer or an ISO 4217 code.
  • Tools without an entry keep the tool-URI Action. A map the middleware cannot apply throws when the middleware is created (ToolMapError names the tool and field). A call whose arguments the map cannot resolve is refused before Delegus is asked: ARGUMENTS_UNMAPPABLE, the middleware's own refusal like MISSING_CREDENTIALS (no receipt), with the field named in error.data.delegus.hint and onDecision's error.
  • Agents must build the same Action. The middleware serves the map at <path>/delegus-tools.json (with Delegus-Tools-Hash) and names it in a Delegus-Tools: <url>; sha256=<hash> header when credentials are missing and when an agent signed for a mapped tool without the map (PROOF_ACTION_MISMATCH, with the hint to update the SDK or fetch the map).
  • Two tools mapped to the same commerce type with the same resource shape share one authority: a Grant for one authorizes the other (toolMapWarnings(map) lists such pairs). Only the fields a template names are bound; git.push's force: true is still authorized by a feature/* Grant, so validate it in the tool.

The shared vector set @delegus/conformance mcp/tool-map.json (src/mcp/tool-map.json in the repository) pins every rule; the Python middleware (delegus-mcp) and the gateway apply the same map.

Ordinary HTTP APIs (REST, any language)

Banks and suppliers run REST, not MCP. The same check sits in front of an HTTP API: the agent signs for the exact method and URL, and a route map says how a request becomes the Action Delegus checks.

import { Delegus } from "@delegus/sdk";
const delegus = new Delegus({ apiKey: process.env.DELEGUS_RP_KEY!, publicBaseUrl: "https://pay.example.com" });

// Express style
app.use(express.json());
app.use(delegus.http({ routeMap }));
// Fastify
import { fastifyDelegusHttp } from "@delegus/sdk";
fastify.addHook("preHandler", fastifyDelegusHttp(delegus, { routeMap }));
{ "version": 1, "routes": [
  { "id": "payments.create", "method": "POST", "path": "/payments",
    "action": "commerce:purchase", "resource": "payee:{arg:/body/payee}",
    "amount": { "value": "/body/amount", "currency": "/body/currency", "unit": "minor" } },
  { "id": "accounts.read", "method": "GET", "path": "/accounts/{id}", "action": "api:call" }
] }

Templates and pointers are the tool map's, resolved against { body, path, query, url }. A money route becomes commerce:purchase so the Grant can say payee:acme-* up to maxAmount; an api:call route binds the request URL itself, so the Grant names https://pay.example.com/accounts/*. A request matching no route is still checked as api:call on its URL; only OPTIONS passes unchecked. On ALLOW the handler runs with req.delegus = { receipt, action, route } and the response carries Delegus-Receipt-Id; on DENY the caller gets 403 with { error, message, delegus: { decision, reason, receipt_id, receipt_url } } and the handler never runs. A Proof signed for another method or URL is PROOF_BINDING_MISMATCH before Delegus is asked. Missing credentials: 401 with Delegus-Verify: required, Delegus-Relying-Party and Delegus-Routes: <origin>/delegus-routes.json; sha256=…; the middleware serves the map at that path.

The agent side builds the same Action from the same map:

const headers = await agent.httpHeaders({ grant, method: "POST", url: "https://pay.example.com/payments", rpDid, body, routes: routeMap });
await fetch("https://pay.example.com/payments", { method: "POST", headers: { ...headers, "content-type": "application/json" }, body: JSON.stringify(body) });

For an API in another language, @delegus/http-gateway runs this check as a reverse proxy in front of it.

Anyone checking the archive

Every ended UTC day gets a signed Merkle root over the receipt ids Delegus issued that day (RFC 6962, SHA-256), chained to the previous day and signed with the status key in the service DID document.

const d = new Delegus();                                   // no key needed
await d.checkpoints.verify("2026-09-15");                  // recompute the root from the published leaves, verify the signature
await d.receipts.inclusion("drc_01K4Q7ZP9X2M3N4R5S6T7V8W9Y"); // audit path for one receipt
await d.checkpoints.contains("2026-09-15", myReceiptIds);  // are my ids leaves of that day?

CLI: delegus checkpoint verify --day 2026-09-15, delegus receipt inclusion --id drc_…, delegus checkpoint contains --day … --ids ….

Anyone holding a receipt

const keys = await delegus.serviceKeys();                    // from the service DID document
delegus.receipts.verify(receipt.receipt, keys, "did:web:delegus.ai");
await delegus.receipts.reverify({ receipt, grant, proof, action }); // fetches artifacts by hash from /evidence, re-runs the open checks (v0.2 and v0.3) with now = evaluated_at; r.notReproduced names what needs entitled material

CLI

delegus --help. Environment: DELEGUS_API_URL, DELEGUS_API_KEY, DELEGUS_ADMIN_TOKEN. Keys live in Ed25519 private JWK files (mode 0600). Commands: keygen, org init|show|add-member|key-create|key-list|key-revoke, org create|register|verify, rp create, agent create|register|disable, grant create|revoke, key list|create|revoke|retire|compromise, proof sign, verify, outcome report, decision get, receipt verify|inclusion, checkpoint verify|contains, action purchase|api-call, doctor. verify exits 0 on ALLOW and 2 on DENY. org init creates an organization account; org create creates a managed Principal (did:web:<domain>:org:<slug>), optionally inside one (--org).

Tests

npm --workspace packages/sdk test runs the SDK against the in-process API from apps/api's test harness (memory adapters, fixed clock) and the CLI as a subprocess.

License

Apache-2.0. See LICENSE. The Delegus service (apps/api) is not part of this package and is not open source.