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

@djangocfg/payments

v2.1.468

Published

Provider-agnostic React payments module (Stripe-first): checkout state machine, Payment Element wrapper, close-guard context, mock adapter for keyless development

Downloads

734

Readme

@djangocfg/payments

Provider-agnostic React payments module. Stripe-first, but the package never depends on a concrete SDK — the host injects an adapter. Battle-tested in production (one-time PaymentIntent checkout + recurring subscriptions with Stripe Link) before extraction into @djangocfg/*.

The seam

The host picks one adapter and injects it via <PaymentProvider>. Package hooks/components read it through usePaymentAdapter() and never import Stripe or a generated API client directly.

import { PaymentProvider, createMockPaymentAdapter } from '@djangocfg/payments';

// Mock-first: build & verify the whole checkout UX before any backend exists.
<PaymentProvider adapter={createMockPaymentAdapter()}>
  {children}
</PaymentProvider>

Swapping to real Stripe is a one-line host change:

// loadStripe is re-exported by this package — the host never declares @stripe/*.
import { PaymentProvider, createStripeAdapter, loadStripe } from '@djangocfg/payments';

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PK!); // once, module scope
const adapter = createStripeAdapter({
  getStripe: () => stripePromise,
  createIntentOnBackend: (input) => api.payments.createIntent(input), // host transport
});

<PaymentProvider adapter={adapter}>{children}</PaymentProvider>;

Layering

domain/      pure types + money helpers   (no React, no Stripe)
context/     <PaymentProvider> + usePaymentAdapter()  (the injected seam)
transport/   mock-adapter | stripe-adapter  (only stripe-adapter touches @stripe/*)
hooks/       useCheckout, usePaymentHistory  (state machine over the adapter)
components/  CheckoutForm, StripePaymentElement, PaymentHistory, PaymentStatusBadge

@stripe/* is touched in exactly two files (transport/stripe-adapter.ts, components/StripePaymentElement.tsx) and ships as a regular dependency — @stripe/stripe-js is only the tiny CDN loader (the real SDK loads from js.stripe.com at runtime), and tree-shaking drops the Stripe components from mock-only bundles.

Styles (Tailwind v4) — required wiring

This package is consumed from source and styled with Tailwind utility classes. Tailwind v4 only generates classes it can see, so the consumer's global CSS must import the package's styles entry (it carries the @source directive that points Tailwind at this package's sources):

/* your app's globals.css */
@import "@djangocfg/ui-core/styles/full";
@import "@djangocfg/ui-tools/styles";
@import "@djangocfg/payments/styles";   /* ← add this */

Symptom when missing: components render unstyled in spots — e.g. PaymentStatusBadge chips lose their background tint and show as plain text. Next.js hosts also add the package to transpilePackages.

Public API

| Export | Kind | Purpose | |---|---|---| | PaymentProvider / usePaymentAdapter | context | inject / read the adapter | | createMockPaymentAdapter | adapter | full fake state machine (success / declined / 3DS) | | createStripeAdapter | adapter | real Stripe (host supplies key + create-intent call) | | useCheckout | hook | idle → creating → requires_payment → processing → succeeded\|failed\|requires_action | | usePaymentHistory | hook | paginated history via adapter.listPayments | | CheckoutDialog | component | close-locked dialog shell (CheckoutGuard + ui-core Dialog); wrap your checkout body in it | | CheckoutForm | component | provider-agnostic form shell (ui-core only); inject the provider field via paymentField | | StripePaymentElement | component | <Elements> + <PaymentElement>; render-props the live Elements to the host | | PaymentHistory | component | DataTable of PaymentRecord | | PaymentStatusBadge | component | status pill on ui-core semantic tokens (success/warning/info/destructive) | | toMinorUnits / toMajorUnits / formatAmount | util | money at the boundary (amounts cross as integer minor units) |

Conventions

  • Source-consumed (no bundler); main/types/exports./src/index.ts.
  • ui-core flat import; ui-tools subpath-only (@djangocfg/ui-tools/data-table).
  • Does not mount its own <UiProviders> — the host provides it once.
  • Locale-free: user-facing labels are props/slots (host supplies i18n).
  • Verify with pnpm -F @djangocfg/payments check (tsc).

Configuration & keys

Payments need three Stripe keys, split by where they're safe to live. Stripe ships them in two flavours — test (sk_test_…, pk_test_…) and live (sk_live_…, pk_live_…) — with the same variable names; only the values differ. Bring up test first, verify end-to-end, then switch to live.

| Key | Prefix | Lives in | Exposed to browser? | |---|---|---|---| | Secret key | sk_test_… / sk_live_… | Backend only (STRIPE__SECRET_KEY) | ❌ never | | Webhook signing secret | whsec_… | Backend only (STRIPE__WEBHOOK_SECRET) | ❌ never | | Publishable key | pk_test_… / pk_live_… | Backend + Frontend | ✅ safe (it's public by design) |

The publishable key is typically returned to the browser by the backend's create-checkout response (publishable_key) and/or read from NEXT_PUBLIC_STRIPE_PK. The secret and webhook keys never leave the server.

Backend (Django) — STRIPE__*

This package is frontend-only; it pairs with any Django backend that creates PaymentIntents (a built-in django_cfg.apps.payments module is planned — see @plans/plan-payments-v1). Paths below are the reference host's; adjust env names to your backend. Set the keys server-side (git-ignored secrets file):

# --- Stripe (test) ---
STRIPE__SECRET_KEY=sk_test_xxx
STRIPE__PUBLISHABLE_KEY=pk_test_xxx
STRIPE__WEBHOOK_SECRET=whsec_xxx          # comma-separate to rotate: whsec_new,whsec_old

# --- Stripe (live) — same names, live values ---
# STRIPE__SECRET_KEY=sk_live_xxx
# STRIPE__PUBLISHABLE_KEY=pk_live_xxx
# STRIPE__WEBHOOK_SECRET=whsec_live_xxx

Frontend — NEXT_PUBLIC_STRIPE_PK

# your Next.js app .env  (test → pk_test_…, live → pk_live_…)
NEXT_PUBLIC_STRIPE_PK=pk_test_xxx

With no NEXT_PUBLIC_STRIPE_PK set, the host falls back to the mock adapter — the whole checkout UX still renders (no real charge), which is the mock-first dev path.

⚠️ Security: the secret (sk_) and webhook (whsec_) keys must live in a git-ignored file or a secret manager — never commit them. If the project's .env* files are tracked by git, add the secrets file to .gitignore and git rm --cached it first. Only pk_… (publishable) is safe in tracked config.

Stripe setup (test mode)

  1. Get test keys — Stripe Dashboard → Developers → API keys (toggle "test mode"): copy pk_test_… and sk_test_….
  2. Webhook — for local dev, use the Stripe CLI (it prints a whsec_… signing secret for the forwarded endpoint):
    stripe login
    stripe listen --forward-to localhost:8000/<your-webhook-path>/
    # → copy the "whsec_…" it prints into STRIPE__WEBHOOK_SECRET
    For a deployed env, create the endpoint in Dashboard → Developers → Webhooks pointing at your backend's webhook URL and subscribe to: payment_intent.succeeded, payment_intent.payment_failed, charge.refunded.
  3. Test a payment — open an order, hit Pay, use a Stripe test card (4242 4242 4242 4242, any future expiry/CVC). Trigger events directly with:
    stripe trigger payment_intent.succeeded
    stripe events resend <evt_id>   # test idempotency / replay

Going live

  1. Switch all three STRIPE__* values to their …_live_… counterparts and NEXT_PUBLIC_STRIPE_PK to pk_live_….
  2. Create a live webhook endpoint in the Dashboard (live mode has its own signing secret — set it in STRIPE__WEBHOOK_SECRET).
  3. Register your domain for Apple Pay / Google Pay if you enable wallets.
  4. Do a small real charge to confirm end-to-end.