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

@ackrate/ap2

v0.3.1

Published

Signed AP2 mandate validation and binding for ackrate contract-enforced Stellar payments.

Downloads

318

Readme

@ackrate/ap2 0.3.1

Signed AP2 v0.1 ackrate profile validation for contract-enforced Stellar payments.

@ackrate/ap2 turns the supported AP2 v0.1 IntentMandate subset into a versioned Stellar Ed25519 credential, validates it at mandate admission, and returns the exact ackrate mandate that must be registered on-chain. The validator checks the signature, trusted user, merchant scope, amount, expiry, binding hash, and one-time admission replay state.

This is deliberately a narrow ackrate profile for AP2 v0.1, not a universal verifier for every upstream AP2 VC or JWS format. It has no HTTP or x402 dependency, so later AP2 or x402 wire changes can be handled by adapters without redesigning MandateRegistry.

Install

npm install @ackrate/[email protected] @ackrate/[email protected] @stellar/[email protected]

Signed validator quick start

import {
  InMemoryAp2ReplayStore,
  createAp2ComplianceValidator,
  signAp2Mandate,
} from "@ackrate/ap2";
import { ackrate } from "@ackrate/core";

const credential = signAp2Mandate({
  intent: {
    user_cart_confirmation_required: false,
    natural_language_description: "Buy one research dataset",
    merchants: [MERCHANT_ADDRESS],
    intent_expiry: new Date((Math.floor(Date.now() / 1000) + 3600) * 1000).toISOString(),
  },
  stellar: {
    user: USER_KEY.publicKey(),
    agent: AGENT_KEY.publicKey(),
    asset: ackrate.testnet.nativeSac,
    maxAmount: "5.00",
  },
}, USER_KEY);

const validator = createAp2ComplianceValidator({
  replayStore: new InMemoryAp2ReplayStore(), // development only
  replayNamespace: `stellar-testnet:${ackrate.testnet.mandateRegistryId}`,
});

const accepted = await validator.validateAndConsume({
  credential,
  expectedUser: USER_KEY.publicKey(), // trusted session/account identity
  merchant: MERCHANT_ADDRESS,         // trusted endpoint configuration
  amount: "1.00",                    // semantic amount, not a wire-format claim
});

await ackrate.registerMandate(accepted.binding.mandate, { signer: USER_KEY });
await ackrate.approveBudget(accepted.binding.mandate, { signer: USER_KEY });
await ackrate.agent({ mandate: accepted.binding.mandate, signer: AGENT_KEY }).pay("1.00", {
  onPrepared: (pending) => paymentJournal.save(pending),
});

expectedUser, merchant, and amount must come from trusted application state. The validator never authorizes a payment from untrusted HTTP fields.

Replay semantics

validateAndConsume consumes a mandate hash once at signed-mandate admission or registration. It is not called before every purchase: a ackrate mandate is intentionally multi-use.

After admission, every payment still goes through MandateRegistry.execute_payment. The contract atomically enforces the stored merchant, cumulative budget, expiry, agent authorization, and monotonic sequence. The SDK and this validator are untrusted infrastructure; neither can bypass the on-chain money path.

InMemoryAp2ReplayStore is only for tests, demos, and one-process development. Production must provide a durable, shared, linearizable consumeOnce(record) implementation. A store error or unsupported result fails closed.

import type { Ap2ReplayStore } from "@ackrate/ap2";

const replayStore: Ap2ReplayStore = {
  async consumeOnce(record) {
    // Atomically insert record.key with a uniqueness constraint.
    // Return "consumed" only for the winning insert, otherwise "duplicate".
    return durableAtomicInsert(record);
  },
};

What is signed

signAp2Mandate first runs the same fail-closed AP2-to-ackrate binding used by bindIntentMandate. The credential contains:

  • exact credential, AP2, data-key, binding, and signature algorithm versions;
  • the normalized one-merchant AP2 intent;
  • the Stellar user, agent, asset, maximum amount, decimals, and binding nonce;
  • the recomputed ackrate mandate hash; and
  • a canonical 64-byte Stellar Ed25519 signature.

The signature is over a SHA-256 digest with the fixed REAPP\0AP2\0SIGNED-MANDATE\0V1\0 domain, all version identifiers, the SHA-256 of the full canonical credential payload, and the 32-byte mandate hash. The payload hash also binds client interpretation fields such as token decimals, even when they are not part of the core mandate id. The user public key is taken from the signed payload and must equal the separately trusted expectedUser; an attacker cannot authorize their own self-signed replacement.

The validator rejects unknown keys at every credential level. That is intentional: if a later AP2 version adds a constraint this implementation does not understand, it fails closed instead of silently dropping the field.

Supported AP2 subset

The profile is pinned to AP2 v0.1.0 and its sample IntentMandate data shape.

| AP2 field | ackrate behavior | |---|---| | user_cart_confirmation_required | Must be explicitly false; cart-confirmation state is not enforced by the contract. | | natural_language_description | Canonically bound into intentHash; evidence, not contract policy. | | merchants | Exactly one valid Stellar address; becomes the contract-enforced merchant scope. | | intent_expiry | Future ISO 8601 timestamp with timezone and whole-second precision; the signed credential stores canonical UTC. | | skus | Absent or empty because MandateRegistry does not enforce SKU constraints. | | requires_refundability | Absent or false because MandateRegistry does not enforce refundability. |

Binding algorithm

The bridge normalizes the supported AP2 fields, recursively sorts JSON object keys, and computes:

intent_hash = SHA-256(canonical AP2 JSON)
core_nonce  = "reapp-ap2/1:" + intent_hash + ":" + binding_nonce
vc_hash     = existing @ackrate/core mandate hash, including core_nonce

The default binding nonce comes from Web Crypto. Supply stellar.nonce only for reproducible test vectors. Existing non-AP2 mandate ids and core field ordering are unchanged.

Errors

validateAndConsume throws Ap2ValidationError with a stable code:

| Code | Meaning | |---|---| | INVALID_CREDENTIAL | Malformed, unknown, noncanonical, or invalid identity data. | | UNSUPPORTED_VERSION | Credential, AP2, data-key, binding, or signature version is unsupported. | | INVALID_SIGNATURE | Signature encoding or Ed25519 verification failed. | | SIGNER_MISMATCH | Signed user differs from trusted expectedUser. | | BINDING_MISMATCH | Payload does not recompute to the envelope mandate hash. | | MERCHANT_MISMATCH | Requested merchant is outside signed scope. | | INVALID_AMOUNT | Amount is zero, negative, malformed, over-precision, or outside i128. | | AMOUNT_EXCEEDS_MANDATE | Requested amount is greater than the signed maximum. | | EXPIRED | Expiry is equal to or earlier than the trusted clock. | | REPLAYED | The same mandate hash was already admitted in this namespace. | | REPLAY_STORE_UNAVAILABLE | Atomic replay storage failed or returned an invalid result. |

API

| Export | Purpose | |---|---| | signAp2Mandate(input, signer) | Bind and sign the supported AP2 intent with the Stellar user key. | | createAp2ComplianceValidator(options) | Create the signature/scope/amount/expiry/replay validator with an injected store and clock. | | Ap2ValidationError | Typed fail-closed error with stable codes. | | InMemoryAp2ReplayStore | Single-process development and test replay store. | | bindIntentMandate(input) | Validate and bind without producing a signed envelope. | | normalizeAp2Intent(intent) | Normalize the exact enforceable AP2 subset. | | canonicalizeJson(value) | Deterministic recursively key-sorted JSON for binding evidence. |

TypeScript declarations also expose the credential, validator input/result, replay-store, intent, binding, and authorization interfaces.

Verification

npm run build -w @ackrate/ap2
npm run test -w @ackrate/ap2

The package has 59 tests: 12 stable binding/vector tests plus 47 validator tests covering valid credentials, tampering, every version boundary, malformed signatures, trusted signer and merchant scope, exact amount limits, overspend, expiry, replay, 100-way concurrent admission, store outages, replay poisoning, and namespace isolation.

Current contract target

The default is the upgradeable simple MandateRegistry on Stellar testnet:

Apache-2.0.