feat(paykit): harden subscription checkout sessions

Closed
PA
3mo ago
+1002-19

Summary

This PR hardens subscription Checkout Sessions without adding app-specific billing behavior.

It is stacked on #201 (subscription-quantity). After #201 merges, this branch should be rebased so this PR contains only the checkout hardening commit.

Changes

  • Add optional subscription Checkout options for idempotency, promotion codes, automatic tax, billing address collection, Tax ID collection, and customer update behavior.
  • Return checkoutSessionId from subscription checkout results.
  • Add a server-side expireCheckoutSession PayKit method that verifies provider customer ownership before expiring a Stripe Checkout Session.
  • Pass Checkout hardening options through the provider contract and Stripe provider.
  • Add generic PayKit error codes for checkout session not found, customer mismatch, and non-expireable sessions.
  • Add a changeset for a minor paykitjs release.

Out of scope

  • Automatic resume of open Checkout Sessions.
  • Application-level storage of checkout attempts.
  • Fooodly-specific org mapping or reconciliation.
  • Annual/monthly multi-price logic.

Verification

  • pnpm --filter paykitjs typecheck
  • pnpm lint
  • pnpm test:unit
  • pnpm --filter paykitjs build
  • pnpm exec oxfmt --check <touched files>

Note: pnpm format:check currently fails on this Windows shell because the quoted glob is not expanded for oxfmt, so touched files were checked explicitly instead.


Summary by cubic

Hardens subscription Checkout Sessions and adds quantity-aware subscriptions across paykitjs. Adds a secure server method to expire Stripe sessions, returns checkoutSessionId from subscribe, and avoids top‑level eval during runtime init.

  • New Features

    • Checkout hardening for subscription Checkout: promotion codes, automatic tax, billing/tax ID collection, customer update, and idempotency; passed through the provider to Stripe.
    • New server method expireCheckoutSession that verifies customer ownership, treats already-expired sessions as idempotent, and expires only open sessions.
    • subscribe now returns checkoutSessionId and supports quantity; quantity is persisted and synced across create/update/schedule flows.
    • Added PayKit error codes: checkout session not found, customer mismatch, and not-expireable.
  • Migration

    • Custom providers: implement expireCheckoutSession; add quantity to createSubscription, updateSubscription, scheduleSubscriptionChange, and createSubscriptionCheckout; include quantity in returned subscriptions.
    • API usage: subscribe accepts checkout and quantity; handle checkoutSessionId in the result.

Summary by CodeRabbit

  • New Features

    • Added support for subscription quantities across checkout, updates, scheduling, and syncing.
    • Added a new option to include checkout session hardening settings such as tax, billing, promotion codes, and idempotency.
    • Added a way to expire checkout sessions, with customer ownership checks.
  • Bug Fixes

    • Subscription results can now include checkout session IDs.
    • Improved validation and error handling for checkout session expiration and invalid checkout options.