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

@myzonerocks/pact

v0.1.9

Published

TypeScript SDK for the PACT payment abstraction protocol

Readme

@myzonerocks/pact

The TypeScript SDK for PACT, a payment abstraction protocol. PACT expresses a payment as a small sequence of typed, signed messages that any settlement provider can fulfil, carried over any transport. Every payment is a corridor — collect from the payer, convert the money, deliver to the recipient — so any pay-in provider composes with any pay-out provider across any currency, whether the money moves over a card network, a mobile-money wallet, or a blockchain.

This package is the browser- and Node-ready kernel plus the provider adapters. It owns the protocol messages, the state machine, the event-sourced ledger, the corridor router, and the leg, bridge, and compliance seams. It does not own transport, key custody, liquidity, the FX feed, or KYC policy — those are seams you inject, so the same code serves a wallet app and a custodial backend alike.

Install

bun add @myzonerocks/pact
# or: npm install @myzonerocks/pact

The kernel is exported from the package root; each adapter is a subpath so a bundle pulls in only the providers it uses.

import { Client, Money, encodePayload, decodePayload } from "@myzonerocks/pact";
import { StripeLeg } from "@myzonerocks/pact/adapters/stripe";
import { Erc20Leg } from "@myzonerocks/pact/adapters/erc20";

Drive a corridor

intent.amount is what the recipient receives; the corridor grosses it up into what the payer pays, with exact-integer math that always rounds in the recipient's favour. Settlement is route-and-forget: initiate kicks off the pay-in and returns, and a normalized provider event feeds advance, which is idempotent so a payment settles once.

const client = new Client({ payIn: [stripe], payOut: [payout], verifier });

const intent = client.createIntent({
  senderRef: payer,
  recipientRef: merchantAccount,
  amount: Money.parse("USD", 2, "1500"), // recipient receives $15.00
  expiresAt: now + 600_000,
  allowedRails: ["card"],
});

const quotes = await client.quoteOptions(intent, [{ payInAdapterId: "stripe", currency: "USD", exponent: 2 }]);
const quote = await client.select(quotes, payer);
const auth = await client.authorize(intent, quote, signer);

// The payer confirms the card on their own device, so create the intent awaiting
// their confirmation and hand the client secret to the card form.
const { preparation } = await client.interactiveInitiate(intent, quote, auth);
// ...payer confirms; the provider's webhook is normalized and fed to advance:
await client.advance(intent.id, "stripe", event); // -> settled, once

For a server-side or saved-method charge, use initiate instead, which collects in one step rather than waiting on the payer.

Carry a payment over your transport

The kernel emits and consumes opaque bytes; it never touches transport. Wrap a message with encodePayload to get a self-identifying, versioned blob to place inside your own envelope — a chat message, a queue entry — and decodePayload on receipt. No plaintext ever needs to reach a relay.

const blob = encodePayload(intent);        // place inside your E2EE envelope
const message = decodePayload(received);   // recover on the other side

Adapters

An adapter translates between PACT messages and one provider, as a pay-in leg (collect), a pay-out leg (disburse), or both. Be honest in payInCapabilities / payOutCapabilities — the kernel refuses any operation you did not promise, so an irreversible rail declares a counter-transfer refund rather than fake a reversal.

| Subpath | Provider | Legs | |---|---|---| | @myzonerocks/pact/adapters/stripe | Stripe | card pay-in (brings Apple Pay, Google Pay, Cash App Pay as methods) | | @myzonerocks/pact/adapters/erc20 | ERC-20 | crypto pay-in + pay-out | | @myzonerocks/pact/adapters/mpesa | M-Pesa | STK pay-in + B2C pay-out | | @myzonerocks/pact/adapters/paypal | PayPal | Orders pay-in (Venmo) + Payouts pay-out |

Server-side adapters (Stripe, M-Pesa, PayPal) hold provider secrets and verify webhooks, so run them on a server, never in a browser bundle.

Design commitments

  • Money is exact integer minor units at arbitrary precision, never a float — an 18-decimal token overflows 64 bits at nine whole tokens.
  • Signing is over a canonical preimage, not JSON or protobuf bytes, with a domain-separation tag per message kind, so a signature verifies across every SDK and can never be replayed across message kinds, intents, or quotes.
  • Every step is idempotent and replay-safe; a duplicated webhook settles once.
  • The state machine is total: every illegal transition is rejected.
  • Cross-provider settlement is never faked as atomic: value rests in escrow between the legs, so a failed pay-out unwinds to a refund rather than a loss.

Conformance

The Go, TypeScript, Dart, Swift, and Kotlin SDKs are held to one wire format by shared vectors: a fixed intent produces a fixed canonical preimage, hash, and signature that every one of them reproduces byte-for-byte.

bun run test

Learn more

The protocol is specified in the repository at github.com/myzonerocks/pactspec/PACT.md for messages, canonical signing, the ledger, and conformance, and spec/cross-rail.md for the corridor model.

Licensed under Apache-2.0.