@suaveplan/payment-providers - Slim universal foundation for the @suaveplan/payment-provider-* sibling packages. Ships ProviderRegistry, definePaymentProvider factory, shared httpRequest/composeAbortSignal helpers, FetchLike, the ApiKeyConfig / OAuthConfig / MerchantKeyConfig / HttpOptions / ProviderResponse types, and the PAYMENT_PROVIDER_CODES + PaymentProviderError error model. Concrete Stripe / PayPal / Square / Mollie / Adyen adapters ship as separate @suaveplan/payment-provider- packages that depend on this foundation.
Universal foundation for the @suaveplan/payment-provider-*
sibling-package family. This package ships only the shared abstractions
every concrete adapter needs — the ProviderRegistry, the
definePaymentProvider factory, the httpRequest +
composeAbortSignal HTTP helpers, the FetchLike type, the shared
config shapes (ApiKeyConfig, OAuthConfig, MerchantKeyConfig,
HttpOptions, ProviderResponse), and the PAYMENT_PROVIDER_CODES
registry + PaymentProviderError class. Concrete adapters
(Stripe, PayPal, Square, Mollie, Adyen) live in sibling packages so
consumers pay only for the providers they install.
Documentation tree
- error-codes — Stable error registry and typed error class for
@suaveplan/payment-providers. Every production failure path — non-ok…- error-codes — Stable error registry and typed error class for
@suaveplan/payment-providers. Every production failure path — non-ok…
- error-codes — Stable error registry and typed error class for
- http — Universal HTTP helper used by every provider to issue typed, cancellable JSON requests. The helper is a thin wrapper ov…
- http — Universal HTTP helper used by every provider to issue typed, cancellable JSON requests. The helper is a thin wrapper ov…
- registry — Process-local, synchronous registry that indexes
PaymentProviderinstances (from@suaveplan/payment) by their `name… - types — Shared configuration interfaces and injectable seams consumed by every sibling
@suaveplan/payment-provider-*adapter…- provider — Shared configuration interfaces and injectable seams consumed by every sibling
@suaveplan/payment-provider-*adapter…
- provider — Shared configuration interfaces and injectable seams consumed by every sibling
Install
bun add @suaveplan/payment-providers @suaveplan/payment
# plus one or more of:
bun add @suaveplan/payment-provider-stripe
bun add @suaveplan/payment-provider-paypal
bun add @suaveplan/payment-provider-square
bun add @suaveplan/payment-provider-mollie
bun add @suaveplan/payment-provider-adyen
Quick start
import { ProviderRegistry } from "@suaveplan/payment-providers";
import { StripeProvider } from "@suaveplan/payment-provider-stripe";
import { PaymentEngine } from "@suaveplan/payment";
const registry = new ProviderRegistry();
registry.register(new StripeProvider({
apiKey: process.env.STRIPE_SECRET_KEY ?? "",
}));
const engine = new PaymentEngine({ provider: registry.get("stripe") });
const intent = await engine.createIntent({
amount: { amount: 5000n, currency: "USD" },
captureMethod: "automatic",
});
Features
ProviderRegistry— process-local, synchronous, insertion-ordered registry ofPaymentProviderinstances keyed byname; strictgetwith typed miss, duplicate-saferegister, idempotentunregister, frozenlist()snapshotdefinePaymentProvider<TName>(spec)— factory that returns a frozen, literal-typedPaymentProviderfor sibling packages that prefer a closure to a classhttpRequest<T>(options)— universalFetchLikewrapper with per-call timeout, JSON serialisation, custom-header passthrough, typed errors, empty-body handling, and external-AbortSignalcompositioncomposeAbortSignal(internal, external?)— reusable abort-signal composer (extracted fromhttpRequestso sibling packages can compose their own out-of-band HTTP calls with caller-supplied cancellation)PAYMENT_PROVIDER_CODES+PaymentProviderError— 6-code registry (HTTP_ERROR,TIMEOUT,PARSE_ERROR,OAUTH_TOKEN_FAILURE,PROVIDER_NOT_REGISTERED,PROVIDER_ALREADY_REGISTERED) with optionalprovider/httpStatus/url/bodyExcerptdiscriminants- Shared config shapes —
ApiKeyConfig,OAuthConfig,MerchantKeyConfig,HttpOptions,ProviderResponse,ProviderCommonOptions, plusNowFn/RandomIdFn/Base64EncodeFninjectable seams - Universal tier — zero Node, browser, React, or
node:cryptoimports; runs unchanged on Node, Bun, browsers, and Web Workers - Tree-shakeable —
sideEffects: falseplus per-feature subpath exports - 100% test coverage (Istanbul) + 100% docs coverage (sibling
.mdper implementation file)
Sibling provider packages
The five concrete provider adapters that used to ship in this package now live in dedicated sibling packages, each depending on this foundation:
@suaveplan/payment-provider-stripe—StripeProvider@suaveplan/payment-provider-paypal—PayPalProvider@suaveplan/payment-provider-square—SquareProvider+ the Square-specificSquareConfigtype@suaveplan/payment-provider-mollie—MollieProvider@suaveplan/payment-provider-adyen—AdyenProvider
Install one or more alongside this foundation. Every sibling exports
the same class name + PaymentProvider-interface contract as before
the slim-down, so migration from a bundled import is a one-line
package swap (see ## Migration below).
Migration
If you were importing a concrete provider from
@suaveplan/payment-providers, switch to the matching sibling
package. The class names are preserved verbatim:
// Before
import { StripeProvider } from "@suaveplan/payment-providers";
// After
import { StripeProvider } from "@suaveplan/payment-provider-stripe";
All shared types (ApiKeyConfig, OAuthConfig, MerchantKeyConfig,
HttpOptions, ProviderResponse, NowFn, RandomIdFn,
Base64EncodeFn), httpRequest, composeAbortSignal, the
PaymentProviderError class, and the PAYMENT_PROVIDER_CODES
registry continue to be exported from
@suaveplan/payment-providers unchanged. The Square-specific
SquareConfig type now ships with
@suaveplan/payment-provider-square.
Modules
src/types/provider.md—ApiKeyConfig,OAuthConfig,MerchantKeyConfig,HttpOptions,ProviderResponse, plusNowFn/RandomIdFn/Base64EncodeFnsrc/error-codes/error-codes.md—PAYMENT_PROVIDER_CODES,PaymentProviderError, factories (httpError,timeoutError,parseError,oauthTokenFailure,providerNotRegistered,providerAlreadyRegistered)src/http/http.md—httpRequest+composeAbortSignal+FetchLikesrc/registry/registry.md—ProviderRegistrysrc/registry/define.md—definePaymentProviderfactory
Building a custom provider
Sibling provider packages — and any consumer adding a non-standard
provider — implement the PaymentProvider interface from
@suaveplan/payment and use httpRequest from this foundation for
every HTTP call:
import {
type ApiKeyConfig,
httpRequest,
PaymentProviderError,
} from "@suaveplan/payment-providers";
import type {
CreatePaymentIntentInput,
PaymentIntent,
PaymentProvider,
} from "@suaveplan/payment";
export class CustomProvider implements PaymentProvider {
public readonly name = "custom";
private readonly config: ApiKeyConfig;
public constructor(config: ApiKeyConfig) {
this.config = config;
}
public async createIntent(
input: CreatePaymentIntentInput
): Promise<PaymentIntent> {
const { data } = await httpRequest<{ id: string }>({
method: "POST",
url: `${this.config.baseUrl ?? "https://api.custom.com"}/intents`,
headers: { "X-API-Key": this.config.apiKey },
body: { amount: Number(input.amount.amount) },
fetch: this.config.fetch,
signal: this.config.signal,
timeoutMs: this.config.timeoutMs,
provider: this.name,
});
return mapToPaymentIntent(data);
}
// ...implement remaining PaymentProvider methods
}
function mapToPaymentIntent(_raw: unknown): PaymentIntent {
throw new PaymentProviderError(
"PAYMENT_PROVIDER.PARSE_ERROR" as never,
"implement mapping"
);
}
Related
@suaveplan/payment—PaymentEngine,WebhookVerifier,PaymentProviderinterface@suaveplan/money— currency-aware arithmetic@suaveplan/error— base error class +defineCodesregistry helper
License
MIT