8.0 KiB
Add @suaveplan/payment-provider-stripe sibling adapter
Package: @suaveplan/payment-provider-stripe
Status: PROPOSED
Type: new-package
Why
The 2026-05-17-slim-payment-providers change extracted the five
concrete provider adapters (Stripe, PayPal, Square, Mollie, Adyen) out
of @suaveplan/payment-providers and into sibling packages so
consumers pay only for the providers they install. This change lands
the Stripe sibling.
@suaveplan/payment-provider-stripe re-lands the StripeProvider
class (previously @suaveplan/payment-providers.StripeProvider prior
to the slim-down) verbatim against the slim foundation. It implements
PaymentProvider from @suaveplan/payment, uses httpRequest from
the slim foundation for every HTTP call, forwards Bearer auth and the
caller-supplied Idempotency-Key header on every mutating request,
maps Stripe payment-intent / refund status codes to the domain
PaymentStatus / RefundStatus enums, and raises only
PaymentProviderError.
What changes
- ADDED:
@suaveplan/payment-provider-stripepackage atpackages/universal/payment-provider-stripe/(0.1.0, universal tier,sideEffects: false). - ADDED:
class StripeProvider implements PaymentProviderwith literalname: "stripe". Constructor accepts aStripeConfigextendingApiKeyConfig(Stripe secret key + optionalwebhookSecret, plus the sharedProviderCommonOptions). - ADDED: All six
PaymentProvidermethods —createIntent,confirmIntent,captureIntent,cancelIntent,refund,getIntent— each routed throughhttpRequestagainst the Stripe REST API. - ADDED: Stripe-domain →
PaymentIntent/Refundmappers (mapIntent,mapRefund,mapStatus,mapRefundStatus,mapRefundReason) that translate every Stripe lifecycle state into the@suaveplan/paymentenums. - ADDED:
StripeConfigtype re-export so consumers can pin the construction shape without reaching into the slim core forApiKeyConfig. - ADDED: Subpath exports for
./stripe/stripeso consumers can tree-shake the provider class directly.
Out of scope
- Webhook signature verification —
@suaveplan/paymentalready ships theWebhookVerifier; this package only carries thewebhookSecretfield onStripeConfigfor downstream wiring. - OpenTelemetry spans / counters on the provider — defers to a
monorepo-wide observability pass tracking
@suaveplan/payment-level instrumentation. - Stripe Connect, Customer / Setup-intent / Subscription APIs — the
PaymentProvidercontract only covers payment-intent + refund lifecycle; non-contract Stripe surfaces are deferred to dedicated follow-up packages. - Currency conversion — Stripe's minor-unit (cents) amount is mapped
to
MoneyLike.amount: bigint1:1 with currency uppercased; no zero-decimal currency adjustment is performed in this change (parity with the pre-slim shape).
Source mapping
This change derives from ../suaveplan/enterprise/payment-providers.md
and the verbatim upstream Stripe implementation that was bundled into
the just-slimmed @suaveplan/payment-providers package.
| Requirement | Source lines | Notes |
|---|---|---|
| Universal-tier purity (no Node / browser / React deps) | enterprise/payment-providers.md L37 |
verbatim cross-cutting rule |
Zero Math.random / Date.now at module scope; injectable seams |
enterprise/payment-providers.md L40 |
satisfied via shared ProviderCommonOptions (fetch/timeoutMs/signal) |
Structured errors extending @suaveplan/error |
enterprise/payment-providers.md L42, L61 |
uses PaymentProviderError from the slim core; raises no raw Error |
AbortSignal everywhere async, per-call timeout |
enterprise/payment-providers.md L43 |
inherits httpRequest composition of caller signal + internal timeout |
| Idempotency-key wiring on mutating calls | enterprise/payment-providers.md L44 |
createIntent / refund forward Idempotency-Key when caller supplies it |
Tree-shakeable, sideEffects: false |
enterprise/payment-providers.md L55 |
verbatim |
workspace:^ internal deps + Bun catalog externals |
enterprise/payment-providers.md L56 |
verbatim |
| 100% Istanbul coverage + 100% docs coverage | enterprise/payment-providers.md L50-L51 |
genesis-wide policy as well |
| File-size budget (250 soft / 300 hard / 500 test) | enterprise/payment-providers.md L52 |
verbatim |
StripeProvider full lifecycle (createIntent / confirmIntent / captureIntent / cancelIntent / refund / getIntent) |
/mnt/s/web/suaveplan/packages/universal/payment-providers/src/stripe.ts L130-L209 |
verbatim port against slim foundation; previously folded as a removed requirement by 2026-05-17-slim-payment-providers (specs/payment-providers/spec.md "Requirement: StripeProvider full lifecycle") |
Stripe status → PaymentStatus mapping table |
/mnt/s/web/suaveplan/packages/universal/payment-providers/src/stripe.ts L45-L56 |
verbatim 7-row mapping including unknown → failed fallback |
Stripe refund status → RefundStatus mapping |
/mnt/s/web/suaveplan/packages/universal/payment-providers/src/stripe.ts L58-L62 |
verbatim 3-branch mapping (succeeded / pending / failed) |
Stripe refund reason → RefundReason mapping |
/mnt/s/web/suaveplan/packages/universal/payment-providers/src/stripe.ts L104-L111 |
verbatim 4-branch mapping (duplicate / fraudulent / requested_by_customer / other) |
| Bearer auth header on every request | /mnt/s/web/suaveplan/packages/universal/payment-providers/src/stripe.ts L211-L217 |
verbatim Authorization: Bearer <apiKey> header |
StripeProvider.name === "stripe" |
/mnt/s/web/suaveplan/packages/universal/payment-providers/src/stripe.ts L119 |
verbatim literal name |
Requirements with no source line
| Requirement | Justification |
|---|---|
provider: "stripe" discriminant on every raised PaymentProviderError |
Slim-foundation httpRequest accepts a provider field on HttpOptions; wiring it on every call lets consumers discriminate Stripe failures from sibling-package failures without parsing messages. Not required by the upstream file but mandatory for the slim-core contract. |
Injectable fetch / signal / timeoutMs forwarded to httpRequest on every call |
The upstream file held its own timeoutMs but never forwarded the caller's external signal or fetch. Required by the slim foundation (every sibling MUST flow through ProviderCommonOptions); upgraded from the upstream surface in this migration. |
Verification approach
Every requirement in specs/payment-provider-stripe/spec.md carries a
**Verified by:** line citing concrete it(...) titles in:
src/stripe/stripe.test.ts— everyPaymentProvidermethod, the Bearer /Idempotency-Keyheader forwarding, every status / refund- status / refund-reason branch,providerdiscriminant on raised errors, injectedFetchLike+signalforwarding.tests/dep-graph.test.ts— pins universal-tier purity (nonode:/bun:/fs/path/ etc imports undersrc/).
Tests use a real recording FetchLike closure — no vi.mock, no
vi.stubGlobal. The Stripe REST API surface is exercised purely
through the injected fetch.
Migration impact
None — additive only. This package is brand new under
packages/universal/payment-provider-stripe/ and is not yet consumed
by any other package in the monorepo. Consumers that previously
imported StripeProvider from @suaveplan/payment-providers (none
exist on genesis; that surface was removed by
2026-05-17-slim-payment-providers before any consumer landed) will
import from the new package per the slim-core migration table.
Impact
Affected dependents
Run bunx turbo ls --filter=...@suaveplan/payment-provider-stripe to
enumerate. The package is brand new with no current dependents.
| Dependent | Action |
|---|---|
| (none) | [x] no action needed — new package, no consumers yet |
Future dependents will be: @suaveplan/api-plugin-payment (when it
lands as a Stripe-configurable host) and any application-layer
package that wires the PaymentEngine to Stripe.