npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@funnelsgrove/payments

v0.25.0

Published

Shared billing and checkout helpers for funnels.

Downloads

10,925

Readme

@funnelsgrove/payments

Shared billing and checkout helpers for funnels.

Read this file before editing checkout code. Deeper implementation docs:

Owns provider-backed checkout primitives

@funnelsgrove/payments owns reusable payment contracts, provider adapters, checkout-session helpers, wallet slots, checkout UI primitives, and Checkout Session-scoped semantic analytics. Funnel code owns paywall layout, copy, when an offer opens, post-payment navigation, and the lifecycle completion callback after verified payment success.

Current Checkout Path

Render every visible wallet placement with StripeSubscriptionWalletSurface or StripeOneTimeWalletSurface, matching the resolved plan's payment mode. They are the normal current path for Apple Pay and Google Pay:

  • Each surface owns one private Checkout Session per simultaneously visible wallet placement, isolated by its own surfaceId.
  • Simultaneously visible placements may use the same plan and coupon; nothing is shared because each surface keeps its own session.
  • Changing the selected plan replaces the surface’s Checkout Session and clientSecret. A stable surfaceId identifies the placement; it does not guarantee that the Stripe iframe survives a plan change.
  • If payment confirmation is already in flight when the selection changes, the success callback remains bound to the original confirmed Checkout Session.

Use these for new subscription paywalls:

  • StripeSubscriptionWalletSurface
  • useStripeSubscriptionCheckoutSession
  • SharedStripeCheckoutV2Dialog
  • trackPaidStripeSubscriptionCheckoutCompleted
  • trackStripeSubscriptionPaymentInfoSubmitted

Use these for new one-time paywall plans:

  • StripeOneTimeWalletSurface
  • useStripeOneTimeCheckoutSession
  • createStripeOneTimeCheckout
  • SharedStripeCheckoutV2Dialog

SharedStripeCheckoutV2Dialog defaults to the existing full-screen standard surface. Pass variant='compact' for a centered desktop modal with the same Stripe-owned wallet/card flow; mobile remains full-screen and all checkout analytics and verified-success behavior are unchanged.

Pass presentation='inline' to embed a card-only form in the paywall. The host owns the offer summary and renewal disclosure. Inline checkout has no modal semantics, close button, Escape dismissal, or shared wallet session; analytics and verified-success callbacks are unchanged.

Use completeStripeOneClickPayment for normal post-checkout one-click upsells. It delegates the charge to funnelSdkService.chargeOneClickPayment and owns any required Stripe confirmation. Pass its optional checkoutAnalytics context to let the shared package emit checkout_completed only after succeeded, including after required confirmation. The context uses StripeSubscriptionCheckoutAnalyticsContext; completion is deduplicated by PaymentIntent ID, and analytics failures do not fail the payment. Funnel code supplies the context and completes its step; the shared package owns the analytics callback. chargeStripeOneClickPayment remains the lower-level charge-only primitive.

Solidgate browser checkout is available for controlled provider-routed funnels through SolidgateCheckoutDialog, prepareSolidgateCheckout, and pollSolidgateCheckoutStatus. The dialog mounts one official Solidgate form per attempt, destroys the remote form on replacement/unmount, and never treats iframe success as funnel completion. Its onSuccess callback runs only after the provider-neutral status endpoint finds canonical shared-ledger payment evidence.

Localized funnel copy

Funnel content files own translated strings. Pass a complete SharedStripeCheckoutV2Copy as the dialog's copy prop to translate its method tabs, country label and payment status/fallback messages. Existing callers keep the English defaults. Stripe-owned fields and provider errors use the stripeLocale option on both checkout-session hooks; wallet surfaces accept it through their checkout input. Stripe clients are cached by publishable key and locale so changing language cannot reuse another language's client. Locale does not change a plan, currency or billing interval.

ManageSubscriptionContent exported by this package extends the runtime content with optional labels: ManageSubscriptionLabels. A localized funnel should make labels required in its own content type and provide the complete English and translated objects. The labels own section/status text, date locale and interval templates ({count}), while subscription data and cancellation behavior remain unchanged. Set errorMessagePolicy: 'content' to render load/cancel failures from the content's errorMessages. The default 'server' policy preserves existing error rendering independently of the selected labels.

Checkout email prompt

When the access email is missing or invalid, wallet surfaces render nothing. The funnel's primary payment CTA (such as Get My Plan) opens CheckoutEmailDialog and saves the email through the existing caller-owned identity update. Once the caller adopts the saved email, wallet controls can mount. Provider email rejections still open the surface's repair dialog; saving never confirms the old session.

CheckoutEmailDialog defaults to a light surface regardless of the browser or ancestor theme. It inherits the funnel font. Set inherited --checkout-email-* CSS variables on the funnel root or .checkout-email-dialog to customize it: background, foreground, muted, border, input-background, button-background, button-foreground, focus, and error. For example, --checkout-email-button-background: var(--color-primary) uses the funnel accent. Set foreground/background pairs together for custom dark surfaces. Existing dialog.checkout-email-dialog CSS overrides continue to work.

Advanced Wallet Primitives

ApplePaySubscriptionCheckoutSlot, GooglePaySubscriptionCheckoutSlot, and WalletSubscriptionCheckoutSlot stay exported and runtime-compatible. They are backward-compatible advanced low-level primitives: reach for them only when a placement needs wiring the shared wallet surfaces do not cover. Never share one checkout hook result across placements; give each visible placement its own session.

Compatibility-Only Surfaces

Keep these exports available for saved drafts, old published artifacts, and controlled migrations. Do not use them for new subscription checkout work:

  • SharedStripeCheckoutDialog
  • ApplePaySubscribeButton
  • GooglePaySubscribeButton
  • APPLE_PAY_QR_CODE_URL

When a live funnel still uses one of these, migrate the funnel deliberately with its own tests before removing the export.

Use This Package For

  • billing catalog types and normalization helpers
  • runtime-mode-aware plan catalog selection
  • Stripe SDK and public payment API client helpers
  • subscription checkout-session preparation, reuse, update, and recovery
  • reusable plan-selector UI
  • shared embedded checkout dialogs
  • Stripe Express Checkout wallet slots and lower-level wallet primitives
  • generic timed-offer display helpers
  • checkout completion analytics handoff to @funnelsgrove/analytics

Do Not Use This Package For

  • funnel routing
  • manifest validation
  • funnel-owned billing catalog entries
  • funnel-specific paywall layout or copy
  • funnel-specific decisions about when to activate, upgrade, or recover an offer
  • analytics transport internals
  • direct provider SDK calls inside funnel paywall steps; add provider adapters here first, then wire the funnel to the shared session or slot

Public Surfaces

  • config/billing.config: billing catalog, mapping, plan, and discount contracts.
  • services/publishedBillingRuntime.service: resolves one published runtime artifact into component-ready plans, defaults, upsells, downsells, discounts, and flow experiments.
  • services/planCatalog.service: plan resolution and selection helpers.
  • services/runtimeBillingPlanCatalog.service: test/live runtime catalog selection.
  • services/paywallOffer.service: timed discount and display-plan helpers.
  • providers/paymentProvider.types: provider-neutral checkout state shared by every adapter.
  • providers/stripe/services/*: Stripe loader, Checkout Session, hosted checkout, one-click, analytics, and one-click completion.
  • providers/stripe/hooks/*: Stripe-backed plan resolution and isolated card/wallet checkout-session state.
  • providers/stripe/components/*: plan selector, checkout dialogs, Express Checkout wrappers, wallet slots, placeholders, and trust assets.
  • providers/stripe/testing/*: Stripe wallet checkout smoke assertions.
  • providers/solidgate/services/*: strict Solidgate checkout preparation, status, and bounded polling clients.
  • providers/solidgate/components/*: the official-SDK checkout dialog and canonical verification lifecycle.
  • components/ManageSubscriptionScreen: provider-neutral subscription management UI.

Funnels should call resolvePublishedBillingRuntime once at their runtime-provider boundary. Screens consume its resolved view and should not parse offer sets or pricing-experiment variants themselves. Pass the resolved stripePublishableKey into shared Stripe checkout hooks so Stripe.js can load while the Checkout Session request is still in flight; the key returned by that request remains the compatibility fallback.

Client implementation structure

Provider-neutral plan types, selection and recurrence live in services/paywallPlans/, exposed through paywallPlans.service.ts. publishedBillingRuntime and timed-offer helpers must not import a provider service just to resolve or display plans. Shared config/services are checked for provider dependencies in paymentBoundaries.test.ts.

Stripe browser operations live in providers/stripe/services/checkout/, hostedCheckout/ and oneClick/. Keep request mappers (requests.ts) beside the short async operation functions; common validation and metadata normalization belong in the local shared/ folder. stripeClient.ts owns the Stripe.js cache. One-click orchestration calls the charge and confirmation functions in its own folder, without a workflow layer.

stripe.service.ts is the public export facade. From 0.12.0, all payment transport uses V2. createStripePaymentIntent is removed: migrate to createStripeOneTimeCheckout and its Checkout Session UI. Keep legacy published bundles on their pinned releases until their own migration passes checkout QA. Hosted checkout uses createStripeCheckoutSession with published profile, provider and plan selection plus successUrl and cancelUrl. Deploy hosted V2 support before releasing this SDK. Subscription mutation callers forward the listed subscriptionRef; no provider ownership is reconstructed in the browser. HTTP transport belongs to the runtime SDK. No charge retry, V1 fallback or extra conversion event is introduced.

Engineering Rules

  • Keep every provider-specific component, hook, service, and test helper under src/providers/<provider>. Add future providers as sibling folders; do not place provider SDK imports in root components, hooks, or services.
  • Stripe owns real card fields and wallet controls. Local wallet buttons are placeholders until Stripe confirms availability.
  • Keep planId as the funnel plan key and send Stripe's price id only as providerPlanId; the API uses both fields to resolve the active test/live offer mapping.
  • Wallet unavailable state must fall back to card/manual checkout or disappear.
  • Count checkout_started only at shared UI boundaries: when a shared card dialog opens or when Stripe reports Apple Pay / Google Pay intent. Checkout Sessions use confirmation or cancellation as a fallback because Stripe omits their click callback. Cancellation recovers the start with checkout_start_source: wallet_cancel; its timestamp is dismissal time, not wallet-open time. Closing the browser before either callback is still unobservable. Cancel has no payment-method field, so the method is included only when the element enables exactly one method.
  • Pass checkoutAnalytics to every current shared dialog and wallet surface. The package then owns checkout_started, add_payment_info, and verified checkout_completed, all deduplicated by the actual Checkout Session.
  • Payment submission triggers, validation, declines, and retry identity follow AE-BR-001–004. Keep that behavior inside shared checkout surfaces.
  • Call funnel lifecycle completeStep only from the shared checkout onSuccess callback. Payment-info submission is not step completion.
  • Wallet slots may create render-only Checkout Sessions on mount so Apple Pay and Google Pay render before the visitor taps. Session creation is technical preparation and must never emit checkout_started.
  • Shared checkout analytics deduplicates checkout_started by Checkout Session id. Wallet confirmation and cancellation may retry the start signal when the click callback is unavailable, without creating a duplicate. Cancellation never emits payment-info or purchase completion events.
  • Do not call publicAnalyticsSdk.trackCheckoutStarted, trackPaymentInfoSubmitted, or trackCheckoutCompleted directly from funnel checkout components.
  • Funnel paywalls should style wallet buttons through the shared slot API: className for the Stripe button/placeholder, slotClassName for the outer slot, appearance for Stripe Elements appearance, and options for Stripe Express Checkout options.
  • Keep discount math reusable here, but keep offer activation timing in funnel code.
  • Checkout metadata must avoid sensitive raw query params and use @funnelsgrove/analytics metadata helpers.

Build, Test, Publish

npm run test:run --workspace @funnelsgrove/payments
npm run build --workspace @funnelsgrove/payments
npm publish --workspace @funnelsgrove/payments --access public

The build normalizes generated relative ESM imports to explicit .js files for published package consumers.

Checkout email repair

Checkout email recovery owns the behavior. Pass onCustomerEmailCommit to wallet surfaces and the card checkout dialog. It must save the access email, adopt the returned Funnel User, and update the customerEmail and userId inputs used by checkout. A wallet surface renders a Continue control and CheckoutEmailDialog when repair is required. onResolveCustomerEmail can resolve a known identity before asking for input; its caller must also adopt the resolved identity. emailDialogContent customizes prompt copy. Keep beforeConfirm for immediate preparation only, without awaiting human input or changing the access identity.

CheckoutEmailDialog is also exported for funnel-owned checkout entry controls, including legacy wallet launchers. Mount it before wallet launch, persist through onSave, and close through onClose; its completion never launches a wallet. isValidCheckoutEmail and isCheckoutEmailError share validation and recovery classification. onCustomerEmailChange in the card dialog reports a committed email, not each draft keystroke, so typing cannot prepare sessions for unsaved input.

Offer price money

Published plans expose optional money: ProviderMoney; new mappings supply it. Discount presentation and purchase analytics use its amount, currency and exponent. amountCents remains a legacy wire alias and does not define the scale of structured money. Independent plans can use different currencies. Currency is selected by the provider price, not by an Offer Set setting.

Published offer selection and checkout attempts

Use resolvePublishedBillingRuntimeState with configuration, browser locale and experiment assignments that are ready. Its result is pending, resolved or error. Pending/error states must not prepare Stripe card/wallet or Solidgate checkout; the maintained templates render an inert zero-plan state rather than a starter catalog.

usePinnedPublishedBillingRuntime holds the complete resolved catalog at the first payment preparation. Wire its pin callback to preparation and release both the payment session and this snapshot on explicit reset. Displayed prices, provider, revision, source version, locale and experiment assignment then remain consistent through background updates. The visitor can still choose another plan within the pinned offer set. A new attempt after reset can adopt the latest configuration.