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

@isubpay/sdk

v0.0.1

Published

iSub — non-custodial recurring/metered pull-payment primitive on Sui. TS SDK for subscriptions (Fixed), pay-as-you-go (PAYG), x402 mandate scheme, and MCP agent payments.

Readme

@isubpay/sdk

TypeScript SDK + runnable scripts for iSub — a non-custodial recurring/metered pull-payment primitive on Sui (Account + Mandate). The Sui equivalent of Stripe's "card on file": no pre-funding, a capped + revocable authorization, and cancel / withdraw anytime.

Contract: ../contracts (isub::subscription). Model + threat model: ../product-plan.

What's here

src/ — the SDK, isomorphic and signer-agnostic (runs in Node and the browser), over a gRPC SuiGrpcClient:

| Module | Purpose | |--------|---------| | IsubClient | Build → execute → parse over gRPC. Writes (openAccount, deposit, withdraw, createPlanFixed/Payg, deactivatePlan, authorizeFixed, authorizeMetered, charge, chargeMetered, refund, revoke, pause, resume, closeAccount, closeMandate, closePlan) and reads (getAccount, getPlan, getMandate, getMandates, quoteFromPlan). | | tx | Pure PTB builders — compose multiple calls into one transaction (transport-agnostic). | | accountExposure | Total authorization vs balance across an account's mandates — show before each authorize (H-2). | | IsubSigner / keypairSigner | The login() seam: one interface for a Node keypair, a browser wallet, or zkLogin. Normalizes execution into IsubExecResult (digest / success / structured abort code / events / created ids). | | IsubKeeper | Off-chain keeper with a persistent billing state machine: lifecycle active → past_due → recovered \| lapsed, dunning policy, event callbacks (the merchant webhook seam), failure classification, drift detection against the on-chain charge counter. | | store / store-file | Keeper persistence seam: durable watch set + append-only action journal + single-instance lock (memoryStore for tests, fileStore for servers). | | reconcile | Journal vs chain reconciliation — exact per-mandate drift via the on-chain charge_seq counter (no event indexer needed). | | errors | IsubAbortError (carries the real Move abort code) + abortCodeOf. | | constants / types | Mirror of the Move module: modes, statuses, abort codes, parsed object state. |

scripts/ — runnables (network via ISUB_NETWORK, default localnet): publish.ts, smoke.ts (lifecycle e2e), keeper-smoke.ts (scheduling), payg-smoke.ts (metered idempotency + refunds), dunning-smoke.ts (state machine + reconciliation), keeper.ts (service), reconcile.ts (audit CLI), fund.ts, grpc-probe.ts.

Run the e2e on localnet

Prereqs: sui CLI (tested on 1.71), Node ≥ 22.5 (matches the package's engines).

# 1. start an ephemeral localnet with a faucet (leave running)
sui start --with-faucet --force-regenesis

# 2. install, publish, and exercise the whole primitive
cd sdk
npm install
npm run publish:localnet   # compile + publish, writes isub.localnet.json
npm run smoke              # open→deposit→authorize→charge×2→revoke→withdraw→close (19 assertions)
npm run keeper:smoke       # keeper auto-charges on schedule, stops at budget (7 assertions)
npm run payg:smoke         # metered charges: seq idempotency, rate cap, refunds (16 assertions)
npm run dunning:smoke      # past_due→recovered→lapsed, restart recovery, reconcile (12 assertions)
npm run keeper             # optional: run the keeper as a long-lived service
npm run reconcile          # audit a keeper journal against the chain

smoke also asserts the adversarial paths — pre-interval charge aborts (EIntervalNotElapsed), post-revoke charge aborts (ENotActive) — and the core invariants (authorize moves no funds; exact debit; merchant receipt; non-custodial exit).

Run the e2e on testnet

The same scripts run on testnet over gRPC via ISUB_NETWORK=testnet. Actor keypairs persist under .secrets/testnet/ (gitignored). The testnet faucet is gated, so fund the actors from your own wallet (one transfer; fund.ts disperses):

cd sdk && npm install
npm run fund:testnet          # creates .secrets/testnet/*.key; prints the funder address + amount
# → send that amount to the `publisher` (funder); re-run to disperse to subscriber/merchant/keeper
npm run publish:testnet       # writes isub.testnet.json (persistent package id)
npm run smoke:testnet         # 19 assertions on testnet
npm run keeper-smoke:testnet  # 7 assertions on testnet

Verified deployment: package 0x573710f6…2616 — all four suites green on testnet (19 + 7 + 16 + 12 assertions).

Authorizing safely (terms binding)

authorizeFixed / authorizeMetered take the expected terms the user reviewed and the chain rejects a mismatch (ETermsMismatch) — defeating a UI that lies about price or a swapped plan. This only protects the user if those expected* values come from a surface the merchant doesn't control (a wallet rendering the on-chain Plan, a neutral checkout). Do not source them by re-reading the same plan — quoteFromPlan is for display only. PAYG adds a user-set maxPerCharge (a per-charge throttle, not a lifetime cap) and an optional firstChargeAfterMs review window.

Merchant integration notes

  • A Mandate is a revocable authorization intent, not a guaranteed receivable. A charge can legitimately fail (EInsufficientAccount) if the subscriber withdrew — this is the intended non-custodial exit right. Gate service on the keeper's mandate.past_due event; bad-debt is bounded to ≈ one billing period (no net-30 accrual). Recovery is signature-free: the user tops up, the next tick charges.
  • One Account backs many mandates (first-come-first-served). Call accountExposure() and show total authorization vs balance before the user signs another authorize.
  • Refunds go back into the Account via refund (merchant-only); they do not restore budget. See the security self-assessment (../product-plan/self-audit.md).

Coin type

The primitive is generic over <T>. The scripts default to SUI on localnet; switching to USDC / USDsui is a one-line change:

new IsubClient({ client, packageId, coinType: '0x…::usdc::USDC' });

Status

Phase 1 ✅ — SDK (gRPC) + keeper + e2e green on localnet and testnet (Sui 1.71, @mysten/sui v2). The browser / dApp surface is Phase 2 — see ../product-plan/phase2-demo-app.md.