136 lines
8.0 KiB
Markdown
136 lines
8.0 KiB
Markdown
# 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-stripe` package at
|
|
`packages/universal/payment-provider-stripe/` (`0.1.0`, universal
|
|
tier, `sideEffects: false`).
|
|
- ADDED: `class StripeProvider implements PaymentProvider` with
|
|
literal `name: "stripe"`. Constructor accepts a `StripeConfig`
|
|
extending `ApiKeyConfig` (Stripe secret key + optional
|
|
`webhookSecret`, plus the shared `ProviderCommonOptions`).
|
|
- ADDED: All six `PaymentProvider` methods — `createIntent`,
|
|
`confirmIntent`, `captureIntent`, `cancelIntent`, `refund`,
|
|
`getIntent` — each routed through `httpRequest` against the Stripe
|
|
REST API.
|
|
- ADDED: Stripe-domain → `PaymentIntent` / `Refund` mappers
|
|
(`mapIntent`, `mapRefund`, `mapStatus`, `mapRefundStatus`,
|
|
`mapRefundReason`) that translate every Stripe lifecycle state into
|
|
the `@suaveplan/payment` enums.
|
|
- ADDED: `StripeConfig` type re-export so consumers can pin the
|
|
construction shape without reaching into the slim core for
|
|
`ApiKeyConfig`.
|
|
- ADDED: Subpath exports for `./stripe/stripe` so consumers can
|
|
tree-shake the provider class directly.
|
|
|
|
## Out of scope
|
|
|
|
- Webhook signature verification — `@suaveplan/payment` already ships
|
|
the `WebhookVerifier`; this package only carries the
|
|
`webhookSecret` field on `StripeConfig` for 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
|
|
`PaymentProvider` contract 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: bigint` 1: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` — every `PaymentProvider` method, the
|
|
Bearer / `Idempotency-Key` header forwarding, every status / refund-
|
|
status / refund-reason branch, `provider` discriminant on raised
|
|
errors, injected `FetchLike` + `signal` forwarding.
|
|
- `tests/dep-graph.test.ts` — pins universal-tier purity (no
|
|
`node:` / `bun:` / `fs` / `path` / etc imports under `src/`).
|
|
|
|
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.
|