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

@asqav/sdk

v0.5.4

Published

AI agent governance - audit trails, policy enforcement, ML-DSA cryptographic signatures

Readme

asqav

TypeScript SDK for asqav.com, the evidence layer for AI agents. Sign every agent action with ML-DSA-65 (FIPS 204), enforce policies before execution, and produce regulator-ready audit trails. All cryptography runs server-side; the package has zero native dependencies.

Install

npm install @asqav/sdk

Quick start

import { init, Agent } from "@asqav/sdk";

init({ apiKey: process.env.ASQAV_API_KEY });
const agent = await Agent.create({ name: "my-agent" });

const sig = await agent.sign({
  actionType: "payment.wire_transfer",
  context: { amountEur: 850000, beneficiaryIban: "DE89370400440532013000" },
  receiptType: "protectmcp:decision",
  riskClass: "high",
  issuerId: "legal:Acme GmbH",
  iterationId: "task-2026-Q2-4821",
});

console.log(sig.complianceMode);        // true (default; pass complianceMode: false to opt out)
console.log(sig.actionRef);             // "sha256:..." over the JCS-canonical action
console.log(sig.previousReceiptHash);   // 64 hex; "0".repeat(64) on the first record per agent
console.log(sig.verificationUrl);

Each signed action lands on a Compliance Receipt under IETF Internet-Draft draft-marques-asqav-compliance-receipts by default: ML-DSA-65 (FIPS 204) signature, chain hash, retained policy_digest, fail-closed anchoring, and a public verification URL. Pass complianceMode: false if you want a non-Compliance receipt.

CLI

The package ships an asqav binary mirroring the Python CLI surface. Set ASQAV_API_KEY and run:

asqav verify <signature_id> [--output json]   # IETF axes when present
asqav sign --agent-id ID --action-type T --action-json action.json \
           --receipt-type protectmcp:decision \
           --risk-class high --issuer-id legal:Acme
           # add --no-compliance-mode to opt out of the IETF profile (default is on)
asqav agents list / create / revoke
asqav sessions list / end <session_id>
asqav replay <agent_id> <session_id> [--json]              # Pro
asqav replay-verify <agent_id> <session_id> [--strict]     # Pro: IETF chain
asqav preflight <agent_id> <action_type> [--json]          # Pro
asqav budget check / record                                # Pro
asqav approve <session_id> <entity_id>                     # Pro
asqav compliance frameworks / export                       # Business
asqav audit-pack export --start ISO --end ISO --output-file bundle.json
asqav audit-pack policy <sha256:hex>
asqav payloads erase <signature_id> --yes                  # P4 right-to-erasure
asqav org set-compliance-strict <org_id> --enable|--disable
asqav keys generate --algorithm ed25519|es256 [--out priv.bin]
asqav migrate run v3-20|v3-21|v3-22                        # X-Maintenance-Key required

Pro and Business commands are gated client-side via GET /account so a free-tier key gets a clean upgrade message instead of a mid-pipeline 402. The server is the source of truth; self-hosted deployments without /account skip the gate.

Data handling modes

The SDK auto-detects whether you're pointing at the Asqav cloud or a self-hosted deployment and selects the safer default for each:

  • Cloud (*.asqav.com): hash-only by default. The SDK builds a fingerprint of your action context, computes a SHA-256 hash locally, and sends only the hash plus a small metadata bag (action_type, agent_id, session_id, model_name, tool_name). Raw prompts and tool arguments stay on your side.
  • Self-hosted: full-payload by default. The server can run policy checks, PII redaction, and richer audit. Recommended when you control the deployment.

Override anytime:

await init({ apiKey: "...", baseUrl: "https://api.asqav.com", mode: "hash-only" });

The fingerprint format is sorted JSON with no whitespace per JCS, hashed with SHA-256. See docs/fingerprint-spec.md and conformance/vectors.json for the spec and cross-language test vectors.

Compliance receipts (IETF profile)

Compliance Receipts are the SDK default. Each agent.sign(...) call produces a receipt that conforms to draft-marques-asqav-compliance-receipts: ML-DSA-65 signature, JCS canonicalization, retained policy_digest, hash-chained previous_receipt_hash, OpenTimestamps anchoring. Opt out with complianceMode: false if you want the older shape.

The envelope extensions most callers reach for (camelCase on the SDK, snake_case on the JSON wire):

  • receiptType -> receipt_type - protectmcp:decision, protectmcp:restraint, protectmcp:lifecycle, protectmcp:lifecycle:configuration_change, protectmcp:acknowledgment, protectmcp:observation, or protectmcp:observation:result_bound (observation receipts that bind tool output via resultDigest).
  • riskClass -> risk_class - controlled vocabulary: unacceptable | high | limited | minimal | gpai | low | medium | unknown.
  • iterationId -> iteration_id - logical task id, distinct from session.
  • sandboxState -> sandbox_state - enabled | disabled | unavailable for high-risk gating.
  • incidentClass -> incident_class - DORA / NYDFS / CIRCIA token (or array of tokens).
  • issuerId -> issuer_id - LEI (ISO 17442), EIN, CIK, or a W3C DID for non-LEI deployers.

Shadow AI capture (passive_telemetry)

Two receiptType values cover the gating axis: protectmcp:decision records that a policy ran and gated the action; protectmcp:observation records that a passive monitor saw the event without gating it. Pick observation when the producer never had the option to block (SIEM forwarder, browser extension in observe-only mode, NetFlow-style proxy with no enforcement hook).

Set captureTopology: "passive_telemetry" to declare the producer is observing after the fact. The SDK client-side check pre-flights the Asqav cloud's full rule 8 gate: a captureTopology: "passive_telemetry" receipt MUST use receiptType: "protectmcp:observation". Any other receiptType paired with passive_telemetry (:decision, :restraint, :lifecycle, :lifecycle:configuration_change, :acknowledgment) throws AsqavError with the verbatim false_attestation_guard: capture_topology=passive_telemetry receipts must use receipt_type=protectmcp:observation, not :<offending> (rule 8) message before the HTTP roundtrip (see false_attestation_guard in typescript/src/index.ts).

const sig = await agent.sign({
  actionType: "mcp:tool_call",
  context: { server: "filesystem", tool: "read" },
  receiptType: "protectmcp:observation",
  captureTopology: "passive_telemetry",
  issuerId: "legal:Acme GmbH",
});

captureTopology is stamped on the audit-pack manifest entry but never on the signed payload. The other accepted topologies are in_process_sdk, network_proxy, browser_extension, ebpf_observer, and mcp_proxy; only passive_telemetry triggers the false-attestation guard. The full topology semantics live in the cloud's docs/capture-topology.md, and the wire vocabulary is published live at https://api.asqav.com/.well-known/governance.json for discovery.

Configuration change receipts (rule 9)

A receiptType: "protectmcp:lifecycle:configuration_change" receipt declares the agent's runtime configuration was mutated. The SDK pre-flights the Asqav cloud's rule 9 cross-field gate (NSA CSI U/OO/6030316-26 alignment): the receipt MUST carry configManifestDigest. Omitting it throws AsqavError with the verbatim false_attestation_guard: receipt_type=protectmcp:lifecycle:configuration_change requires config_manifest_digest (rule 9) message before the HTTP roundtrip.

const sig = await agent.sign({
  actionType: "mcp:config_update",
  context: { server: "filesystem", delta: "tool_added" },
  receiptType: "protectmcp:lifecycle:configuration_change",
  policyDecision: "none",
  configManifestDigest: "sha256:<hex of manifest>",
  cveInventoryDigest: "sha256:<hex of cve snapshot>",
});

Expiry precedence (rule 10)

validSeconds (legacy, server computes valid_until = signed_at + valid_seconds) and expiresAt (caller-supplied horizon) are mutually exclusive. Pass exactly one of the two: validSeconds: 3600 for "expire one hour after signing", or expiresAt: "2026-06-01T00:00:00Z" for an explicit horizon. Passing both throws AsqavError with the verbatim expiry_collision_guard: pass either valid_seconds or expires_at, not both (rule 10) message before the HTTP roundtrip. Passing neither falls back to the server-side default (valid_seconds=86400).

Digest format (rule 11)

Every caller-supplied self-describing digest field (configManifestDigest, cveInventoryDigest, executableHash, sbomDigest) MUST match the regex ^sha256:[a-f0-9]{64}$. toolFingerprint is the exception: it uses the cloud wire form of 32 bare lowercase hex chars (SHA-256[:32], ^[0-9a-f]{32}$, no sha256: prefix); anything else throws AsqavError with the verbatim tool_fingerprint_not_32_hex_chars: must be 32 lowercase hex chars (SHA-256[:32]). message before the HTTP roundtrip. To avoid wire drift, use the SDK's deterministic helpers (each is byte-deterministic under JCS):

import {
  computeToolFingerprint,
  computeConfigManifestDigest,
  computeCveInventoryDigest,
} from "@asqav/sdk";

const fp = computeToolFingerprint("search", { args: { q: "string" } });
const cfg = computeConfigManifestDigest({ server: "filesystem", tools: ["read"] });
const cve = computeCveInventoryDigest([{ id: "CVE-2026-0001", severity: "high" }]);

NSA-aligned receipt fields

Six wire fields on agent.sign(...) carry the NSA CSI U/OO/6030316-26 alignment for MCP server lifecycle and tool output binding:

The protectmcp:observation:result_bound receiptType variant carries resultDigest and lets observation receipts bind to a specific tool result without claiming the policy gated the call.

Build-provenance 4-tuple

Four optional wire fields bind build-side provenance into the signed receipt, subsuming standalone SBOM or SLSA verifiers in a single envelope. All four are independent and may be set together or individually:

  • executableHash - sha256:<hex> of the executable that invoked the action. MUST match sha256:<64-hex>.
  • sbomDigest - sha256:<hex> of the canonical CycloneDX or SPDX SBOM document.
  • slsaProvenancePointer - https URL to the SLSA attestation envelope for the executing build.
  • supplyChainPointer - https URL to the in-toto, Sigstore, or Rekor entry covering the build.
import { Agent } from "@asqav/sdk";

const agent = await Agent.create({ apiKey: process.env.ASQAV_API_KEY! });
const receipt = await agent.sign({
  action: "tool.invoke",
  toolName: "exec_query",
  executableHash: "sha256:" + "a".repeat(64),
  sbomDigest: "sha256:" + "b".repeat(64),
  slsaProvenancePointer: "https://example.com/slsa/build-123.json",
  supplyChainPointer: "https://rekor.sigstore.dev/api/v1/log/entries/abc",
});

See https://www.asqav.com/docs/executable-hash-and-sbom-provenance for the field semantics and a worked policy example.

Threat-framework mappings (optional)

Seven optional wire fields let a caller pin the receipt to industry threat-and-control taxonomies. Each list is caller-supplied and Asqav-preserved verbatim; the cloud sets framework_mappings_self_declared=true on the receipt whenever any of the six list fields is populated, so verifiers can tell self-declared classifications apart from cloud-verified ones.

  • mitreTechniques - list of MITRE ATT&CK technique ids (e.g. ["T1059", "T1078"]).
  • mitreAtlas - list of MITRE ATLAS ids for AI-system threats (e.g. ["AML.T0051"]).
  • owaspLlmTop10 - list of OWASP Top 10 for LLM ids (e.g. ["LLM01", "LLM02"]).
  • nistAiRmf - list of NIST AI RMF function ids (e.g. ["GOVERN-1.1", "MEASURE-2.7"]).
  • iso42001 - list of ISO/IEC 42001 control ids (e.g. ["A.6.2.6"]).
  • euAiActArticles - list of EU AI Act article ids (e.g. ["Article-12", "Article-15"]).
  • rfc3161Timestamp - caller-supplied base64-encoded RFC 3161 TimeStampResp (DER).
const receipt = await agent.sign({
  actionType: "api:call",
  context: { user: "..." },
  complianceMode: true,
  mitreTechniques: ["T1059", "T1078"],
  owaspLlmTop10: ["LLM01"],
  nistAiRmf: ["GOVERN-1.1", "MEASURE-2.7"],
  euAiActArticles: ["Article-12"],
});

Each list must be a non-empty array of strings, each entry up to 128 characters; empty arrays, non-string entries, or oversize entries throw AsqavError with verbatim guard messages (<field>_must_be_non_empty_list, <field>_entry_invalid) and skip the HTTP roundtrip. The rfc3161Timestamp must be valid base64 or throws rfc3161_timestamp_not_base64. Camel-case props project onto snake_case wire keys via the SDK's IETF_OPTIONAL_FIELD_MAP.

See https://www.asqav.com/docs/threat-framework-mapping.

Witness policy (optional)

witnessPolicy lets a caller declare an N-of-M durable-anchoring quorum on the receipt. The receipt reaches witness_quorum_met only when required witnesses hold a real inclusion proof. It projects onto the snake_case witness_policy wire key via the SDK's IETF_OPTIONAL_FIELD_MAP.

  • Shape: { required: number, witnesses: Array<"rfc3161" | "opentimestamps"> }.
  • required must be an integer in [1, witnesses.length].
  • witnesses must be a non-empty subset of the two shipped witnesses: rfc3161 and opentimestamps.
  • rekor is rejected. It is not a shipped witness.
const sig = await agent.sign({
  actionType: "deploy:release",
  context: { build: "..." },
  complianceMode: true,
  witnessPolicy: { required: 1, witnesses: ["rfc3161", "opentimestamps"] },
});

Bad input throws AsqavError with a verbatim guard message before the HTTP roundtrip: witness_policy_unknown_witness (e.g. rekor), witness_policy_required_out_of_range, witness_policy_witnesses_must_be_non_empty_list, witness_policy_required_must_be_int, or witness_policy_duplicate_witness. Omit the field for today's behaviour.

Audit Pack export

The SDK exposes the public audit-trail endpoint as exportAuditJson for filtered windows of receipts (Pro tier and above):

import { exportAuditJson } from "@asqav/sdk";

const bundle = await exportAuditJson({
  startDate: "2026-05-01T00:00Z",
  endDate: "2026-06-01T00:00Z",
  agentId: "agt_abc",
});
console.log(bundle.records.length, bundle.bundleDigest);

For offline chain verification, verifyChain(records) walks an ordered list of signed envelopes for one agent and re-derives each previous_receipt_hash. The first record's seed is "0".repeat(64). The cloud is the authoritative verifier; this helper is a convenience.

Algorithm agility is exposed via SUPPORTED_ALGORITHMS. Pass algorithm: "ed25519" or "es256" to Agent.create(...) for non-post-quantum identities, or generateKeypair("ed25519") for offline scenarios. ES256 signatures emit in IEEE-P1363 (raw r||s) form so they match the cloud verifier byte-for-byte.

Integrations

The SDK ships native callbacks and adapters for common agent frameworks:

  • Vercel AI SDK - import createAsqavExporter from @asqav/sdk/extras/vercel-ai, pass to experimental_telemetry: { tracer }. Every span (text generation, tool calls, embeddings) becomes a signed Asqav action.
  • LangChain.js - import AsqavCallbackHandler from @asqav/sdk/extras/langchain, construct via await AsqavCallbackHandler.create({ agent }) then pass to callbacks: [handler]. Requires @langchain/core as a peer dep.
  • Mastra - import AsqavMastraHook from @asqav/sdk/extras/mastra, attach via await new AsqavMastraHook({ agent }).attach(mastraAgent). Requires @mastra/core as a peer dep.
  • OpenAI Agents JS - import AsqavOpenAIAgentsAdapter from @asqav/sdk/extras/openai-agents, wrap individual tools via new AsqavOpenAIAgentsAdapter({ agent }).wrapTool(tool). Each invocation signs tool:start / tool:end / tool:error. Requires @openai/agents as a peer dep.
  • CrewAI, LiteLLM, LlamaIndex, Haystack - same pattern via the Hooks API (Python SDK has the richer ecosystem; see https://asqav.com/docs/integrations for parity status).

Span names are mapped to Asqav action types: ai.generateText -> ai:completion, ai.streamText -> ai:completion_stream, ai.toolCall -> ai:tool_call, errors -> ai:error. Signing is fire-and-forget and never blocks generation; failures log a warning instead of throwing.

Errors

All thrown errors extend AsqavError. AuthenticationError (401), RateLimitError (429), and APIError (with statusCode) are exported for fine-grained handling:

import { AsqavError, AuthenticationError, RateLimitError, APIError } from "@asqav/sdk";

try {
  await agent.sign({ actionType: "api:call", context: { model: "gpt-4" } });
} catch (err) {
  if (err instanceof AuthenticationError) throw err;     // rotate ASQAV_API_KEY
  if (err instanceof RateLimitError) throw err;          // err.retryAfter holds the cooldown
  if (err instanceof APIError) throw err;                // err.statusCode holds the HTTP status
  throw err;
}

TypeError is thrown before the HTTP roundtrip for the verbatim rule 8 / 9 / 10 / 11 guards listed above. Catch TypeError separately so guard violations surface as developer errors, not API errors.

Requirements

Node 20 or newer. Uses the built-in fetch. Zero native dependencies; ML-DSA cryptography runs server-side.

Standards

Asqav's compliance receipts are profiled in IETF Internet-Draft draft-marques-asqav-compliance-receipts, an Independent Submission that profiles draft-farley-acta-signed-receipts for EU AI Act Articles 12 and 26, and DORA Article 17 bindings. The SDK aligns with NIST FIPS 204 (ML-DSA), JCS canonicalization, and the NSA Cybersecurity Information Sheet U/OO/6030316-26 on MCP server lifecycle telemetry.

Roadmap

What ships on Asqav today. Each item is available on main:

  • Hash-only mode for cloud - default for *.asqav.com.
  • Self-hosted signer (split-trust) - compose file in the Asqav backend repo.
  • Bring-your-own KMS (AWS KMS / GCP KMS) - Enterprise tier.
  • Customer-owned storage - self-hosted; relay payload allowlist enforced in code.
  • SCITT / COSE_Sign1 receipt export - public GET /api/v1/signatures/{id}/cose returns application/cose.
  • Air-gapped / on-prem mode - offline license + zero-egress; see the backend repo docs/airgapped-mode.md.

See https://asqav.com/docs for the live feature set.

Documentation

License

Apache-2.0. Get an API key at asqav.com.