Files
2026-05-27 23:47:53 +01:00

4.4 KiB

@suaveplan/payment-provider-paypal - PayPal payment provider for @suaveplan/payment-providers. Implements the PaymentProvider interface against the PayPal Orders v2 + Payments Captures Refund APIs, with an OAuth2 client-credentials token cache, injectable now/base64Encode/FetchLike seams, sandbox-endpoint shortcut, MoneyLike bigint marshalling, and structured PaymentProviderError surfaces. Universal — runs unchanged on Node, Bun, browsers, and Web Workers.

PayPal sibling adapter for the slim @suaveplan/payment-providers foundation. Ships PayPalProvider — a PaymentProvider implementation against the PayPal Orders v2 + Payments Captures Refund APIs, with an OAuth2 client-credentials token cache, injectable now / base64Encode / FetchLike seams, a sandbox shortcut, MoneyLike bigint marshalling, and structured PaymentProviderError surfaces. Universal — runs unchanged on Node, Bun, browsers, and Web Workers.

Documentation tree

  • paypal — PayPalProvider is the PayPal-flavoured implementation of the PaymentProvider contract exported by `@suaveplan/payme…
    • mapping — Pure mapping utilities used by PayPalProvider to bridge the PayPal Orders v2 + Payments Captures Refund wire shapes i…
    • paypal — PayPalProvider is the PayPal-flavoured implementation of the PaymentProvider contract exported by `@suaveplan/payme…

Install

bun add @suaveplan/payment-provider-paypal @suaveplan/payment-providers @suaveplan/payment

Quick start

import { ProviderRegistry } from "@suaveplan/payment-providers";
import { PayPalProvider } from "@suaveplan/payment-provider-paypal";

const registry = new ProviderRegistry();
registry.register(
    new PayPalProvider({
        clientId: process.env.PAYPAL_CLIENT_ID ?? "",
        clientSecret: process.env.PAYPAL_CLIENT_SECRET ?? "",
        sandbox: true,
    })
);

const paypal = registry.get("paypal");
const intent = await paypal.createIntent({
    amount: { amount: 5000n, currency: "USD" },
    description: "Order #1234",
    captureMethod: "automatic",
    idempotencyKey: "order-1234",
});
console.log(intent.id, intent.status);

Features

  • class PayPalProvider implements PaymentProvider with literal-typed name: "paypal"
  • OAuth2 client-credentials token cache with 60 s clock-skew buffer, refreshed transparently on expiry
  • Injectable now: NowFn, base64Encode: Base64EncodeFn, and fetch: FetchLike for universal determinism and testability
  • sandbox flag → https://api-m.sandbox.paypal.com; explicit baseUrl always wins
  • MoneyLike bigint minor-unit amounts marshalled to PayPal's major-unit decimal-string format
  • PayPal-Request-Id idempotency-header support on createIntent and refund
  • Exhaustive PayPal-status → PaymentStatus / RefundStatus mapping; unknown statuses map to failed
  • Structured PaymentProviderError (from @suaveplan/payment-providers) on every failure path — OAUTH_TOKEN_FAILURE, HTTP_ERROR, TIMEOUT, PARSE_ERROR — always with provider: "paypal"
  • Universal: zero Node / browser / React imports; sideEffects: false
  • 100% Istanbul coverage; sibling .md per implementation file

Modules

  • src/paypal/paypal.md — PayPalProvider class, PayPalConfig interface, lifecycle methods, OAuth token cache
  • src/paypal/mapping.md — pure helpers: mapStatus, mapRefundStatus, parseAmount, formatAmount, mapOrder

Foundation

This package depends on @suaveplan/payment-providers for:

  • httpRequest, composeAbortSignal, FetchLike
  • OAuthConfig, NowFn, Base64EncodeFn
  • PaymentProviderError, PAYMENT_PROVIDER_CODES, oauthTokenFailure

and on @suaveplan/payment for the structural PaymentProvider, PaymentIntent, Refund, PaymentStatus, RefundStatus, CreatePaymentIntentInput, and RefundInput types.

  • @suaveplan/payment-provider-stripe
  • @suaveplan/payment-provider-square
  • @suaveplan/payment-provider-mollie
  • @suaveplan/payment-provider-adyen

All four follow the same pattern: depend on the slim core, expose a single *Provider class, register cleanly into ProviderRegistry.

License

MIT