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

@zkp2p/zkp2p-attestation

v1.3.1

Published

Browser, React Native, and Node verifier/encrypter for ZKP2P Nitro attested uploads

Readme

@zkp2p/zkp2p-attestation

Client-side verifier and encryptor for ZKP2P Nitro seller credential uploads and buyer TEE session-material requests.

The package runs in Chrome MV3 service workers, browser DOM contexts, React Native with a Web Crypto polyfill, and Node >= 20. Library entrypoints use fetch, SubtleCrypto, crypto.getRandomValues, and Uint8Array; they do not import node:* modules or use Buffer.

Install

yarn add @zkp2p/zkp2p-attestation

During monorepo development, point clients at attestation-service/package/zkp2p-attestation.

Environment Init

Use the client factory when the host owns an environment variable:

import { createNitroAttestationClient } from "@zkp2p/zkp2p-attestation";

const nitro = createNitroAttestationClient({
  environment: process.env.ZKP2P_ATTESTATION_ENV === "production" ? "production" : "staging",
});

Environment defaults:

| Environment | Service URL | PCR8 source | |---|---|---| | staging | https://attestation-service-staging.zkp2p.xyz | bundled staging pin | | production | https://attestation-service-preprod.zkp2p.xyz | bundled production/preprod pin |

Callers can still pass attestationServiceUrl and trust.expectedPcr8Hex directly. Explicit trust pins always win.

Fast Path

Wise uploads use the server-derived payee id path:

const encryptedUpload = await nitro.createEncryptedSellerCredentialUpload({
  platform: "wise",
  sessionMaterial: {
    apiToken: "<wise-api-token>",
    // Optional. Omit for single-profile PATs; include after a
    // WISE_PROFILE_SELECTION_REQUIRED response for multi-profile PATs.
    profileId: "41246868",
  },
});

await fetch(`${attestationServiceUrl}/seller/credentials/wise`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ encryptedUpload }),
});

This fetches GET /attestation?nonce=..., verifies the Nitro document to the pinned AWS root and PCR8, extracts the attested seller-upload RSA SPKI, and returns a compact JWE for POST /seller/credentials/:platform.

For the same flow without hand-rolling the POST:

const credentialBundle = await nitro.uploadSellerCredential({
  platform: "wise",
  sessionMaterial: {
    apiToken: "<wise-api-token>",
  },
});

Venmo, Cash App, and PayPal still require a top-level payeeId; existing callers can keep using the same call shape:

const encryptedUpload = await nitro.createEncryptedSellerCredentialUpload({
  payeeId: "1130030979",
  sessionMaterial: venmoSessionMaterial,
});

Buyer TEE requests use the same attested upload key and compact JWE envelope. The typed helper encrypts the captured session material, posts { encryptedSessionMaterial, params, chainId, intent } to POST /buyer/verify/:platform/:actionType, unwraps the service envelope, and returns a typed AttestationOutput. The service does not enforce capture-age or one-use replay limits for buyer TEE session material; verification depends on the upstream session still being active. A leaked encrypted JWE is therefore valid for the upstream session lifetime — treat any accidental disclosure as equivalent to leaking the underlying upstream credential (cookies, PAT, etc.) and rotate the upstream session.

const attestation = await nitro.verifyBuyerTeePayment({
  platform: "venmo",
  actionType: "transfer_venmo",
  sessionMaterial: {
    Cookie: "<captured-cookie-header>",
    "User-Agent": "<captured-user-agent>",
  },
  params: { senderId: "<venmo-account-id>", index: 0 },
  chainId,
  intent,
});

The helper is a thin wrapper over the existing wire format; callers can still hand-roll the final POST:

const encryptedSessionMaterial = await nitro.createEncryptedBuyerTeeSessionMaterial({
  platform: "wise",
  actionType: "transfer_wise",
  sessionMaterial: { "X-Access-Token": "<captured-token>" },
});

await fetch(`${attestationServiceUrl}/buyer/verify/wise/transfer_wise`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    encryptedSessionMaterial,
    params: { profileId: "41246868", transactionId: "123456789" },
    chainId,
    intent,
  }),
});

Buyer TEE platform matrix:

| Platform | actionType | Required encrypted session material | Public params fields | |---|---|---|---| | venmo | transfer_venmo | Cookie | senderId, index | | cashapp | transfer_cashapp | Cookie, x-csrf-token, x-device-name, x-request-signature, x-request-uuid, cash-web-request, x-web-device-info, x-web-context, x-bt-id | senderId, index | | luxon | transfer_luxon | X-Auth-Token | transferId | | monzo | transfer_monzo | Authorization | txId | | n26 | transfer_n26 | Cookie, csrf-token, body | {} | | wise | transfer_wise | Cookie or X-Access-Token | profileId, transactionId | | revolut | transfer_revolut | Cookie, x-device-id | index | | idfc | transfer_idfc | Cookie | senderId, index | | citi | transfer_zelle | Cookie | index | | chime | transfer_chime | Cookie, body | {} | | chase | transfer_zelle | Cookie, x-jpmc-channel, x-jpmc-csrf-token, Referer, Origin | index | | bankofamerica | transfer_zelle | Cookie | index | | mercadopago | transfer_mercadopago | Cookie | paymentId, urlParamsFrom | | paypal | transfer_paypal | Cookie | index | | alipay | transfer_alipay | Cookie | tradeNo |

Per-platform session-material types require these headers using the canonical names shown above while still allowing additional captured headers. Captured request bodies are session material because they can contain sensitive data and are encrypted before being sent to the service.

Cache-Friendly Path

const verified = await nitro.fetchAndVerifyAttestation();

const encryptedUpload = await nitro.encryptSellerCredentialUpload({
  key: verified.attestedSellerUploadKey,
  platform: "wise",
  sessionMaterial: {
    apiToken: "<wise-api-token>",
  },
});

For buyer TEE flows with a cached attestation:

const encryptedSessionMaterial = await nitro.encryptBuyerTeeSessionMaterial({
  key: verified.attestedSellerUploadKey,
  platform: "venmo",
  actionType: "transfer_venmo",
  sessionMaterial: {
    Cookie: "<captured-cookie-header>",
  },
});

The attested SPKI is stable within one enclave process. If the enclave restarts, cached keys become stale and upload decrypt will fail; fetch a fresh attestation for a new session.

React Native Wiring

React Native must provide Web Crypto-compatible primitives when they are not on globalThis.crypto:

const nitro = createNitroAttestationClient({
  environment: "staging",
  subtle: webCrypto.subtle,
  getRandomValues: (out) => webCrypto.getRandomValues(out),
  fetch,
});

Any conforming SubtleCrypto works. The package does not require Buffer.

Direct Entrypoints

import {
  createEncryptedBuyerTeeSessionMaterial,
  createEncryptedSellerCredentialUpload,
  encryptBuyerTeeSessionMaterial,
  encryptSellerCredentialUpload,
  fetchAndVerifyAttestation,
  uploadSellerCredential,
  verifyBuyerTeePayment,
} from "@zkp2p/zkp2p-attestation";

Direct functions accept attestationServiceUrl, trust, fetch, subtle, getRandomValues, now, onWarning, and timeoutMs overrides. If no caller or bundled PCR8 pin exists and trust.strictPin !== true, the verifier falls back to the service-advertised PCR8 and emits TRUST_PIN_NOT_PROVIDED; production callers should pin.

PCR8 Rotation Runbook

  1. Update src/trust/pins.ts from the deployment STATE.md published by the attestation-service team.
  2. Refresh tests/golden/staging-2026-05-05.raw.json and expected metadata if staging rotates.
  3. Run yarn test:coverage and STAGING_E2E=true yarn test:integration.
  4. Release a patch version for PCR8-only rotations. Use a major version for wire-format or algorithm changes.

CLI

The existing verifier is preserved on top of the library:

yarn verify --service https://attestation-service-staging.zkp2p.xyz

Optional EIP-712 signer cross-check remains available through --verify-signature.