@meetreeve/billing-kit
v0.1.0
Published
Shared Reeve.Commerce pricing table + paywall/upgrade primitives — catalog-driven <PricingTable/> and <UpgradePaywall/>, plus an AutoCheckout post-login/return resume helper. Companion to reeve-services' commerce catalog SSOT (DEV-1785) and Entitlements.m
Readme
@meetreeve/billing-kit
Shared Reeve.Commerce pricing surfaces (DEV-1786): a catalog-driven
<PricingTable />, a <UpgradePaywall /> that resolves the unlocking tier
for a gated feature client-side, and an <AutoCheckout /> post-login/return
resume helper. Every app currently hand-builds these two surfaces (tier
cards, credit-pack cards, a paywall modal) from its own hardcoded plan
constants — this package renders straight from the injected commerce
catalog (GET /api/v2/commerce/catalog/{host_app}) instead.
Workspace-local (workspace:*) — not published to npm. See
pnpm-workspace.yaml.
Design
- Data is injected, not fetched. Every component takes a
catalogprop. Callers own thegetCatalog(hostApp)call (RSC or client) — this keeps the package portable to any consumer app and means a price/bullet edit in the reeve-services catalog SSOT changes the rendered page with zero FE deploy. - Checkout is injected, not hardcoded.
onSelectPlan/onBuyPack/onUpgradehandlers are passed in — each app wires its own Stripe-checkout client (startStudioCheckout,startReeveCreditPurchase, ...). The package never imports an app-local API client. - Marketing copy stays app-side.
PricingTable'spresentationprop is a per-plan-id overlay (badge/tagline/className) — the plan's factual data (price, credits, feature bullets) always comes from the catalog. UpgradePaywallnever dead-ends. It resolves the lowest-tier plan whosefeature_limits[featureKey]is non-zero (mirrors reeve-services'Entitlements.min_tier_for); if no tier unlocks the feature (or the user is already on the top tier), the CTA still firesonUpgradewith a concrete plan so the caller can route somewhere useful — never a disabled button.
Extending (DEV-1787 and beyond)
The barrel (src/index.ts) is flat and extension-friendly by design — this
package has one React-only surface, unlike @meetreeve/auth's
core/react/nextjs split. To add a component:
- Add
src/<Component>.tsx(+src/<Component>.test.tsx). - Re-export it from
src/index.ts. - If it needs new shared types, add them to
src/types.ts(catalog mirrors) or a new file — re-export from the barrel either way.
tsup.config.ts has a single index entry, so no build config changes are
needed for a new component. vitest.config.ts picks up any
src/**/*.test.{ts,tsx} automatically.
