feat(core): gateway-agnostic PaymentProvider interface (Stripe adapter + mock) - #18
feat(core): gateway-agnostic PaymentProvider interface (Stripe adapter + mock)#18moset15 wants to merge 1 commit into
Conversation
…nd mock Adds a gateway-agnostic payment seam so additional processors (e.g. Paystack for the African market) can plug in without touching core checkout code: - payment-provider/types.ts: the PaymentProvider interface — init hosted checkout, verify webhook (constant-time, algorithm-agnostic), parse webhook event into a normalised shape, refund, format amount. - payment-provider/stripe-provider.ts: thin adapter implementing the interface over the existing stripe/* modules — no changes to any file under src/stripe/. - payment-provider/mock-provider.ts: in-memory implementation for tests and credential-free local checkout runs. - payment-provider/registry.ts: runtime provider selection via settings:paymentProvider (plugin KV), defaulting to "stripe" so existing installs behave identically. - New ./payment-provider subpath export + tsdown entry. - 19 unit tests (bun test) across the three new modules; tsc --noEmit clean; Biome formatted. Routes (checkout.ts / webhook.ts) still call stripe/* directly — wiring them onto resolveProvider() is staged as a follow-up commit so this diff stays reviewable and behaviour-neutral. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for putting this together. The direction is good, and I like the intent of introducing a gateway-agnostic seam with a Stripe adapter. Kudos to the additional mock provider, registry, and separate package export. I’m going to request changes before merging, because I don’t think the abstraction is safe enough yet to become the foundation for the follow-up checkout/webhook wiring. Main blockers:
There are also a few smaller issues worth cleaning up:
Overall: I’m supportive of the approach, but I’d like the seam tightened before merge so the follow-up wiring does not introduce payment, refund, or webhook regressions. |
What
Introduces a payment seam so processors beyond Stripe can plug into core without forking it:
initCheckout(hosted),verifyWebhook(constant-time, hash-algorithm-agnostic),parseWebhookEvent(normalised event shape),refund,formatAmount.Why
We are building a Paystack provider (cards + M-Pesa STK — the dominant payment rail in Kenya) for a production store on DashCommerce. Paystack's webhook signing is HMAC-SHA512 and its checkout is hosted-page-first, so the seam is deliberately shaped around what both gateways share rather than around Stripe's API surface.
What this PR does not do
src/stripe/*is untouched — the Stripe adapter (payment-provider/stripe-provider.ts) wraps the existing modules.routes/checkout.tsandroutes/webhook.tsstill callstripe/*directly; wiring them ontoregistry.resolveProvider()is staged as a follow-up commit so this diff stays reviewable and behaviour-neutral (the registry defaults to"stripe", so existing installs behave identically).payment-provider/types.ts).Testing
19 unit tests (
bun test) across types/adapter/mock/registry;tsc --noEmitclean; Biome formatted;tsdownbuild emits the new./payment-providerentry.Happy to reshape the interface if you'd prefer different seams — the Paystack implementation living at FIKANOVA/dashcommerce-paystack is the second consumer and keeps this honest.
🤖 Generated with Claude Code