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

@sarrafjs/core

v0.2.1

Published

One payment API for Egypt and the Middle East. Core client, models, money, errors, HTTP, idempotency and webhook router.

Readme

@sarrafjs/core

The core of Sarraf: one payment API for Egypt and the Middle East. Paymob, Kashier and Fawry behind one typed interface: one way to create a checkout, one webhook format, one status model, one error type.

📖 Docs: sarraf-docs.vercel.app · Quick start · Accept payments with Paymob · Accept payments with Kashier

npm i @sarrafjs/core @sarrafjs/paymob      # and/or @sarrafjs/kashier, @sarrafjs/fawry

Quick start

import { Sarraf, toMinor } from "@sarrafjs/core";
import { paymob, paymobIntegrationIdsFromEnv } from "@sarrafjs/paymob";

const pay = new Sarraf({
  providers: {
    paymob: paymob({
      secretKey: process.env.PAYMOB_SECRET_KEY!,
      publicKey: process.env.PAYMOB_PUBLIC_KEY!,
      hmacSecret: process.env.PAYMOB_HMAC_SECRET!,
      integrationIds: paymobIntegrationIdsFromEnv(process.env),
    }),
  },
});

// 1. Checkout
const checkout = await pay.checkout.create({
  provider: "paymob",
  amount: { value: toMinor("250.00", "EGP"), currency: "EGP" },  // 25000
  reference: "order_8841",
  customer: { phone: "+201000000000" },
  returnUrl: "https://shop.example/thanks",
  webhookUrl: "https://shop.example/api/webhooks/paymob",
});
if (checkout.kind === "redirect") redirectTo(checkout.redirectUrl!);
else showCode(checkout.referenceCode!);                          // Fawry / kiosk reference codes

// 2. Webhooks: the only place an order becomes paid
const event = await pay.webhooks.verifyAndParse("paymob", { rawBody, headers, query });
if (event.type === "payment.succeeded") await markPaid(event.payment.reference);

Framework helpers do the webhook part for you: @sarrafjs/express, @sarrafjs/next, @sarrafjs/nestjs.

The client

| Call | Returns | | |---|---|---| | checkout.create(input) | Checkout | kind: "redirect" (redirectUrl) or "reference_code" (referenceCode) | | payments.get({ provider, providerPaymentId \| reference }) | Payment | Current status from the provider | | payments.reconcile(...) | Payment | Same as get; use it in scheduled jobs for orders still pending | | payments.cancel(...) | Payment | Void a same-day payment / cancel an unpaid one | | payments.capture({ provider, providerPaymentId, amount? }) | Payment | Capture an authorization (Paymob, beta) | | refunds.create({ provider, providerPaymentId, amount?, reason?, idempotencyKey? }) | Refund | Omit amount for a full refund | | webhooks.verifyAndParse(provider, req) | SarrafEvent | Throws WEBHOOK_SIGNATURE_INVALID | | webhooks.inspect(provider, req) | WebhookInspection | The exact signed string, expected vs received; never throws on mismatch | | redirects.verify(provider, query) | RedirectResult | For the thank-you page only | | capabilities(provider) | Capabilities | What each provider supports: "supported", "beta" or "unsupported" | | provider(id) | the adapter | Provider-only APIs, e.g. pay.provider("paymob").extras |

The client is typed by the providers you configure: provider: "fawry" doesn't compile unless Fawry is configured, and providerOptions is narrowed to that provider's options. Beta features throw CAPABILITY_NOT_SUPPORTED unless you pass new Sarraf({ allowBeta: true, … }).

What's inside

  • Models: Checkout, Payment, Refund, SarrafEvent (PaymentEvent | CardSavedEvent), with one status vocabulary for every provider. Narrow events with event.type, isPaymentEvent or assertPaymentEvent; name one with EventOf<"payment.succeeded">
  • Money: integer minor units with string math. toMinor / toMajorString handle 3-decimal KWD/BHD/OMR/JOD. A bare number doesn't compile (Money)
  • Errors: SarrafError with stable codes, provider, providerCode, retryable and docsUrl. TIMEOUT_UNKNOWN_OUTCOME marks money calls that timed out and may have happened (Errors)
  • HTTP: timeouts; retries only for safe calls (never for money-moving ones); redacted debug logs and hooks
  • Idempotency: pass idempotencyKey to money calls. MemoryStore by default, RedisStore from @sarrafjs/core/redis for more than one server (bring your own ioredis / node-redis client) (Idempotency)
  • Webhooks: constant-time signature checks over the raw body, stable event.id for dedupe (Webhooks)
  • Conformance: runConformanceTests() from @sarrafjs/core/conformance, for adapter authors

Server-side only: importing it in a browser throws, so secret keys can't leak into client bundles. Requires Node.js 22+.

Not affiliated with any payment provider. You use your own provider accounts; money flows customer → provider → you. Part of Sarraf. Apache-2.0.