@funnelsgrove/payments 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +13 -7
  2. package/dist/index.d.ts +1 -19
  3. package/dist/index.js +4 -25
  4. package/dist/providers/stripe/{ApplePaySubscriptionCheckoutSlot.js → components/ApplePaySubscriptionCheckoutSlot.js} +1 -1
  5. package/dist/providers/stripe/{GooglePaySubscriptionCheckoutSlot.js → components/GooglePaySubscriptionCheckoutSlot.js} +1 -1
  6. package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutDialog.d.ts +1 -1
  7. package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutDialog.js +1 -1
  8. package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutV2Dialog.d.ts +1 -1
  9. package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutV2Dialog.js +9 -3
  10. package/dist/{components/shared → providers/stripe/components}/StripeCheckoutExpressCheckoutButton.d.ts +1 -1
  11. package/dist/{components/shared → providers/stripe/components}/StripeCheckoutExpressCheckoutButton.js +4 -1
  12. package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutButton.d.ts +1 -1
  13. package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutButton.js +4 -1
  14. package/dist/{components/shared → providers/stripe/components}/StripePlanSelector.d.ts +1 -1
  15. package/dist/{components/shared → providers/stripe/components}/StripePlanSelector.js +1 -1
  16. package/dist/providers/stripe/{StripeSubscriptionWalletSurface.d.ts → components/StripeSubscriptionWalletSurface.d.ts} +3 -3
  17. package/dist/providers/stripe/{StripeSubscriptionWalletSurface.js → components/StripeSubscriptionWalletSurface.js} +2 -2
  18. package/dist/providers/stripe/{WalletSubscriptionCheckoutSlot.d.ts → components/WalletSubscriptionCheckoutSlot.d.ts} +2 -2
  19. package/dist/providers/stripe/{WalletSubscriptionCheckoutSlot.js → components/WalletSubscriptionCheckoutSlot.js} +4 -4
  20. package/dist/providers/stripe/components/index.d.ts +13 -0
  21. package/dist/providers/stripe/components/index.js +13 -0
  22. package/dist/providers/stripe/hooks/index.d.ts +3 -0
  23. package/dist/providers/stripe/hooks/index.js +3 -0
  24. package/dist/{hooks → providers/stripe/hooks}/useResolvedPaywallPlans.d.ts +1 -1
  25. package/dist/{hooks → providers/stripe/hooks}/useResolvedPaywallPlans.js +1 -1
  26. package/dist/providers/stripe/{useStripeOneTimeCheckoutSession.d.ts → hooks/useStripeOneTimeCheckoutSession.d.ts} +2 -2
  27. package/dist/providers/stripe/{useStripeOneTimeCheckoutSession.js → hooks/useStripeOneTimeCheckoutSession.js} +3 -3
  28. package/dist/providers/stripe/{useStripeSubscriptionCheckoutSession.d.ts → hooks/useStripeSubscriptionCheckoutSession.d.ts} +3 -3
  29. package/dist/providers/stripe/{useStripeSubscriptionCheckoutSession.js → hooks/useStripeSubscriptionCheckoutSession.js} +3 -3
  30. package/dist/providers/stripe/index.d.ts +4 -0
  31. package/dist/providers/stripe/index.js +4 -0
  32. package/dist/{services → providers/stripe/services}/checkoutCompletionAnalytics.service.d.ts +5 -0
  33. package/dist/{services → providers/stripe/services}/checkoutCompletionAnalytics.service.js +41 -1
  34. package/dist/providers/stripe/services/index.d.ts +2 -0
  35. package/dist/providers/stripe/services/index.js +2 -0
  36. package/dist/{services → providers/stripe/services}/stripe.service.d.ts +18 -4
  37. package/dist/{services → providers/stripe/services}/stripe.service.js +40 -8
  38. package/dist/providers/stripe/testing/index.d.ts +1 -0
  39. package/dist/providers/stripe/testing/index.js +1 -0
  40. package/dist/services/paywallOffer.service.d.ts +1 -1
  41. package/dist/services/publishedBillingRuntime.service.d.ts +1 -1
  42. package/dist/services/publishedBillingRuntime.service.js +1 -1
  43. package/package.json +3 -3
  44. /package/dist/{components/shared → providers/stripe/components}/ApplePaySubscribeButton.d.ts +0 -0
  45. /package/dist/{components/shared → providers/stripe/components}/ApplePaySubscribeButton.js +0 -0
  46. /package/dist/providers/stripe/{ApplePaySubscriptionCheckoutSlot.d.ts → components/ApplePaySubscriptionCheckoutSlot.d.ts} +0 -0
  47. /package/dist/{components/shared → providers/stripe/components}/CheckoutBrandAssets.d.ts +0 -0
  48. /package/dist/{components/shared → providers/stripe/components}/CheckoutBrandAssets.js +0 -0
  49. /package/dist/{components/shared → providers/stripe/components}/GooglePaySubscribeButton.d.ts +0 -0
  50. /package/dist/{components/shared → providers/stripe/components}/GooglePaySubscribeButton.js +0 -0
  51. /package/dist/providers/stripe/{GooglePaySubscriptionCheckoutSlot.d.ts → components/GooglePaySubscriptionCheckoutSlot.d.ts} +0 -0
  52. /package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutElement.d.ts +0 -0
  53. /package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutElement.js +0 -0
  54. /package/dist/{components/shared → providers/stripe/components}/checkoutCountries.d.ts +0 -0
  55. /package/dist/{components/shared → providers/stripe/components}/checkoutCountries.js +0 -0
  56. /package/dist/{components/shared → providers/stripe/components}/walletPlatform.d.ts +0 -0
  57. /package/dist/{components/shared → providers/stripe/components}/walletPlatform.js +0 -0
  58. /package/dist/{testing → providers/stripe/testing}/walletCheckoutSmoke.d.ts +0 -0
  59. /package/dist/{testing → providers/stripe/testing}/walletCheckoutSmoke.js +0 -0
package/README.md CHANGED
@@ -9,7 +9,7 @@ Read this file before editing checkout code. Deeper implementation docs:
9
9
 
10
10
  ## Owns provider-backed checkout primitives
11
11
 
12
- `@funnelsgrove/payments` owns reusable payment contracts, provider adapters, checkout-session helpers, wallet slots, and checkout UI primitives. Funnel code owns paywall layout, copy, when an offer opens, post-payment navigation, and funnel-specific analytics timing.
12
+ `@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.
13
13
 
14
14
  ## Current Checkout Path
15
15
 
@@ -25,13 +25,14 @@ Use these for new subscription paywalls:
25
25
  - `useStripeSubscriptionCheckoutSession`
26
26
  - `SharedStripeCheckoutV2Dialog`
27
27
  - `trackPaidStripeSubscriptionCheckoutCompleted`
28
+ - `trackStripeSubscriptionPaymentInfoSubmitted`
28
29
 
29
30
  Use these for new one-time paywall plans:
30
31
 
31
32
  - `createStripeOneTimeCheckout`
32
33
  - `SharedStripeCheckoutV2Dialog`
33
34
 
34
- Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the shared client helper fits the funnel. It delegates to `funnelSdkService.chargeOneClickPayment`.
35
+ Use `completeStripeOneClickPayment` for normal post-checkout one-click upsells. It delegates the charge to `funnelSdkService.chargeOneClickPayment` and owns any required Stripe confirmation. `chargeStripeOneClickPayment` remains the lower-level charge-only primitive.
35
36
 
36
37
  ## Advanced Wallet Primitives
37
38
 
@@ -78,21 +79,26 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
78
79
  - `services/planCatalog.service`: plan resolution and selection helpers.
79
80
  - `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
80
81
  - `services/paywallOffer.service`: timed discount and display-plan helpers.
81
- - `services/stripe.service`: Stripe loader, Checkout Session, hosted checkout, one-click, one-time Checkout Session clients, and deprecated PaymentIntent compatibility clients.
82
- - `providers/*`: provider-neutral checkout state, the Stripe subscription wallet surface, and Stripe subscription checkout slots.
83
- - `components/shared/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet placeholders, and trust assets.
84
- - `testing/walletCheckoutSmoke`: wallet checkout smoke assertions.
82
+ - `providers/paymentProvider.types`: provider-neutral checkout state shared by every adapter.
83
+ - `providers/stripe/services/*`: Stripe loader, Checkout Session, hosted checkout, one-click, analytics, and deprecated PaymentIntent compatibility clients.
84
+ - `providers/stripe/hooks/*`: Stripe-backed plan resolution and isolated card/wallet checkout-session state.
85
+ - `providers/stripe/components/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet slots, placeholders, and trust assets.
86
+ - `providers/stripe/testing/*`: Stripe wallet checkout smoke assertions.
87
+ - `components/ManageSubscriptionScreen`: provider-neutral subscription management UI.
85
88
 
86
89
  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.
87
90
 
88
91
  ## Engineering Rules
89
92
 
90
- - Keep provider-specific implementation under `src/providers/<provider>`.
93
+ - 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`.
91
94
  - Stripe owns real card fields and wallet controls. Local wallet buttons are placeholders until Stripe confirms availability.
92
95
  - Wallet unavailable state must fall back to card/manual checkout or disappear.
93
96
  - Count `checkout_started` only at shared UI boundaries: when a shared card dialog opens or when Stripe reports an Apple Pay / Google Pay button click.
97
+ - 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.
98
+ - Call funnel lifecycle `completeStep` only from the shared checkout `onSuccess` callback. Payment-info submission is not step completion.
94
99
  - 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`.
95
100
  - Shared checkout analytics deduplicates `checkout_started` by Checkout Session id. Card submit and wallet confirmation must not emit it again.
101
+ - Do not call `publicAnalyticsSdk.trackCheckoutStarted`, `trackPaymentInfoSubmitted`, or `trackCheckoutCompleted` directly from funnel checkout components.
96
102
  - 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.
97
103
  - Keep discount math reusable here, but keep offer activation timing in funnel code.
98
104
  - Checkout metadata must avoid sensitive raw query params and use `@funnelsgrove/analytics` metadata helpers.
package/dist/index.d.ts CHANGED
@@ -5,25 +5,7 @@ export * from './services/planCatalog.service.js';
5
5
  export * from './services/runtimeBillingPlanCatalog.service.js';
6
6
  export * from './services/publishedBillingRuntime.service.js';
7
7
  export * from './services/paywallOffer.service.js';
8
- export * from './services/stripe.service.js';
9
- export * from './services/checkoutCompletionAnalytics.service.js';
10
8
  export * from './services/paymentMethodAnalytics.service.js';
11
- export * from './hooks/useResolvedPaywallPlans.js';
12
9
  export * from './providers/paymentProvider.types.js';
13
- export * from './providers/stripe/useStripeSubscriptionCheckoutSession.js';
14
- export * from './providers/stripe/useStripeOneTimeCheckoutSession.js';
15
- export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
16
- export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
17
- export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
18
- export * from './providers/stripe/StripeSubscriptionWalletSurface.js';
10
+ export * from './providers/stripe/index.js';
19
11
  export { ManageSubscriptionScreen, type ManageSubscriptionContent, type ManageSubscriptionScreenProps, } from './components/ManageSubscriptionScreen.js';
20
- export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
21
- export * from './components/shared/StripeExpressCheckoutElement.js';
22
- export * from './components/shared/StripePlanSelector.js';
23
- export * from './components/shared/walletPlatform.js';
24
- export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
25
- export * from './components/shared/StripeExpressCheckoutButton.js';
26
- export * from './components/shared/SharedStripeCheckoutDialog.js';
27
- export * from './components/shared/ApplePaySubscribeButton.js';
28
- export * from './components/shared/GooglePaySubscribeButton.js';
29
- export * from './testing/walletCheckoutSmoke.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // Billing contracts and plan resolution.
1
+ // Provider-neutral billing contracts, plan resolution, and shared runtime helpers.
2
2
  export * from './config/billing.config.js';
3
3
  export * from './services/preview-frame.service.js';
4
4
  export * from './services/runtime-mode.service.js';
@@ -6,30 +6,9 @@ export * from './services/planCatalog.service.js';
6
6
  export * from './services/runtimeBillingPlanCatalog.service.js';
7
7
  export * from './services/publishedBillingRuntime.service.js';
8
8
  export * from './services/paywallOffer.service.js';
9
- // Stripe API clients and checkout completion handoff.
10
- export * from './services/stripe.service.js';
11
- export * from './services/checkoutCompletionAnalytics.service.js';
12
9
  export * from './services/paymentMethodAnalytics.service.js';
13
- export * from './hooks/useResolvedPaywallPlans.js';
14
- // Provider-neutral and Stripe subscription checkout primitives.
15
10
  export * from './providers/paymentProvider.types.js';
16
- export * from './providers/stripe/useStripeSubscriptionCheckoutSession.js';
17
- export * from './providers/stripe/useStripeOneTimeCheckoutSession.js';
18
- export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
19
- export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
20
- export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
21
- export * from './providers/stripe/StripeSubscriptionWalletSurface.js';
22
- // Shared checkout and subscription-management UI.
11
+ // Provider-specific integrations are grouped behind provider barrels.
12
+ export * from './providers/stripe/index.js';
13
+ // Provider-neutral subscription management UI.
23
14
  export { ManageSubscriptionScreen, } from './components/ManageSubscriptionScreen.js';
24
- export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
25
- export * from './components/shared/StripeExpressCheckoutElement.js';
26
- export * from './components/shared/StripePlanSelector.js';
27
- export * from './components/shared/walletPlatform.js';
28
- export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
29
- export * from './components/shared/StripeExpressCheckoutButton.js';
30
- // Compatibility-only surfaces kept for saved drafts and published artifacts.
31
- export * from './components/shared/SharedStripeCheckoutDialog.js';
32
- export * from './components/shared/ApplePaySubscribeButton.js';
33
- export * from './components/shared/GooglePaySubscribeButton.js';
34
- // QA helpers.
35
- export * from './testing/walletCheckoutSmoke.js';
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
- import { ApplePaySubscribeButton } from '../../components/shared/ApplePaySubscribeButton.js';
14
+ import { ApplePaySubscribeButton } from './ApplePaySubscribeButton.js';
15
15
  import { WalletSubscriptionCheckoutLoadingPlaceholder, WalletSubscriptionCheckoutSlot, } from './WalletSubscriptionCheckoutSlot.js';
16
16
  const applePayExpressCheckoutOptions = {
17
17
  buttonHeight: 55,
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
- import { GooglePaySubscribeButton } from '../../components/shared/GooglePaySubscribeButton.js';
14
+ import { GooglePaySubscribeButton } from './GooglePaySubscribeButton.js';
15
15
  import { WalletSubscriptionCheckoutLoadingPlaceholder, WalletSubscriptionCheckoutSlot, } from './WalletSubscriptionCheckoutSlot.js';
16
16
  const googlePayExpressCheckoutOptions = {
17
17
  buttonHeight: 55,
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { Stripe } from '@stripe/stripe-js';
3
- import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
3
+ import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
4
4
  export type SharedStripeCheckoutSummaryRow = {
5
5
  id: string;
6
6
  label: string;
@@ -16,7 +16,7 @@ import { CardCvcElement, CardExpiryElement, CardNumberElement, Elements, useElem
16
16
  import { ApplePaySubscribeButton } from './ApplePaySubscribeButton.js';
17
17
  import { PaymentBrandMark, SecurityLockIcon, StripeWordmark, } from './CheckoutBrandAssets.js';
18
18
  import { StripeExpressCheckoutButton } from './StripeExpressCheckoutButton.js';
19
- import { queueStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
19
+ import { queueStripeSubscriptionCheckoutStarted, } from '../services/checkoutCompletionAnalytics.service.js';
20
20
  const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
21
21
  const defaultPaymentMethodLabels = ['Visa', 'Mastercard', 'PayPal', 'G Pay', 'Apple Pay'];
22
22
  const normalizeBillingName = (input) => {
@@ -1,5 +1,5 @@
1
1
  import type { Stripe } from '@stripe/stripe-js';
2
- import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
2
+ import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
3
3
  export type SharedStripeCheckoutV2DialogProps = {
4
4
  amountCents: number;
5
5
  buttonColor: string;
@@ -16,9 +16,9 @@ import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-st
16
16
  import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
17
17
  import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
18
18
  import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
19
- import { isInactiveCheckoutSessionError } from '../../providers/stripe/useStripeSubscriptionCheckoutSession.js';
19
+ import { isInactiveCheckoutSessionError } from '../hooks/useStripeSubscriptionCheckoutSession.js';
20
20
  import { getStripeWalletPaymentMethodOrder, usePlatformWalletPaymentMethods, } from './walletPlatform.js';
21
- import { queueStripeSubscriptionCheckoutStarted, trackPaidStripeSubscriptionCheckoutCompleted, } from '../../services/checkoutCompletionAnalytics.service.js';
21
+ import { queueStripeSubscriptionCheckoutStarted, trackPaidStripeSubscriptionCheckoutCompleted, trackStripeSubscriptionPaymentInfoSubmitted, } from '../services/checkoutCompletionAnalytics.service.js';
22
22
  const defaultPaymentMethodLabels = ['Visa', 'Mastercard', 'Maestro', 'Discover'];
23
23
  const stripeCheckoutV2Appearance = {
24
24
  labels: 'above',
@@ -185,6 +185,12 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
185
185
  }
186
186
  await (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess());
187
187
  };
188
+ const trackPaymentInfoSubmitted = async () => {
189
+ if (checkoutAnalytics) {
190
+ await trackStripeSubscriptionPaymentInfoSubmitted(Object.assign({ checkoutSessionId }, checkoutAnalytics)).catch(() => 'analytics_rejected');
191
+ }
192
+ await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
193
+ };
188
194
  useEffect(() => {
189
195
  if (effectiveSelectedMethod !== 'card' || typeof window === 'undefined') {
190
196
  return;
@@ -250,7 +256,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
250
256
  setSubmitting(false);
251
257
  return;
252
258
  }
253
- await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
259
+ await trackPaymentInfoSubmitted();
254
260
  const result = await checkoutState.checkout.confirm({
255
261
  redirect: 'if_required',
256
262
  });
@@ -1,5 +1,5 @@
1
1
  import type { AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
2
- import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
2
+ import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
3
3
  export type StripeCheckoutExpressCheckoutButtonProps = {
4
4
  amountCents: number;
5
5
  beforeConfirm?: () => Promise<string | null>;
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { ExpressCheckoutElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
5
- import { queueStripeSubscriptionCheckoutStarted, trackPaidStripeSubscriptionCheckoutCompleted, } from '../../services/checkoutCompletionAnalytics.service.js';
5
+ import { queueStripeSubscriptionCheckoutStarted, trackPaidStripeSubscriptionCheckoutCompleted, trackStripeSubscriptionPaymentInfoSubmitted, } from '../services/checkoutCompletionAnalytics.service.js';
6
6
  import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
7
7
  const ExpressCheckoutElementWithCancel = ExpressCheckoutElement;
8
8
  const buildDefaultOptions = () => ({
@@ -143,6 +143,9 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
143
143
  event.paymentFailed({ reason: 'invalid_payment_data', message });
144
144
  return;
145
145
  }
146
+ if (checkoutAnalytics) {
147
+ await trackStripeSubscriptionPaymentInfoSubmitted(Object.assign({ checkoutSessionId }, checkoutAnalytics)).catch(() => 'analytics_rejected');
148
+ }
146
149
  await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
147
150
  const result = await checkoutState.checkout.confirm(Object.assign(Object.assign({}, (confirmEmail
148
151
  ? { email: preparedCustomerEmail || (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || undefined }
@@ -1,5 +1,5 @@
1
1
  import type { AvailablePaymentMethods, StripeExpressCheckoutElementOptions } from '@stripe/stripe-js';
2
- import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
2
+ import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
3
3
  export type StripeExpressCheckoutButtonProps = {
4
4
  amountCents: number;
5
5
  beforeConfirm?: () => Promise<string | null>;
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useMemo, useState } from 'react';
4
4
  import { ExpressCheckoutElement, useElements, useStripe } from '@stripe/react-stripe-js';
5
- import { queueStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
5
+ import { queueStripeSubscriptionCheckoutStarted, trackStripeSubscriptionPaymentInfoSubmitted, } from '../services/checkoutCompletionAnalytics.service.js';
6
6
  const normalizeBillingName = (input) => {
7
7
  var _a, _b, _c;
8
8
  const normalizedName = (_a = input.name) === null || _a === void 0 ? void 0 : _a.trim();
@@ -105,6 +105,9 @@ export function StripeExpressCheckoutButton({ amountCents, beforeConfirm, checko
105
105
  event.paymentFailed({ reason: 'invalid_payment_data', message });
106
106
  return;
107
107
  }
108
+ if (checkoutAnalytics) {
109
+ await trackStripeSubscriptionPaymentInfoSubmitted(Object.assign({ checkoutSessionId }, checkoutAnalytics)).catch(() => 'analytics_rejected');
110
+ }
108
111
  await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
109
112
  const result = await stripe.confirmPayment({
110
113
  elements,
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import { type PaywallPlan } from '../../services/stripe.service.js';
2
+ import { type PaywallPlan } from '../services/stripe.service.js';
3
3
  type StripePlanSelectorProps = {
4
4
  plans?: readonly PaywallPlan[] | null;
5
5
  selectedPlanId: string | null;
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useMemo } from 'react';
4
- import { findPaywallPlan, getDefaultPlanSelectionValue, } from '../../services/stripe.service.js';
4
+ import { findPaywallPlan, getDefaultPlanSelectionValue, } from '../services/stripe.service.js';
5
5
  export function StripePlanSelector({ plans, selectedPlanId, onSelectPlan, loading = false, error = null, className, loadingClassName, errorClassName, renderPlan, }) {
6
6
  const safePlans = useMemo(() => {
7
7
  return Array.isArray(plans) ? plans : [];
@@ -1,8 +1,8 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { Appearance, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
3
- import { type PlatformWalletPaymentMethod } from '../../components/shared/walletPlatform.js';
4
- import type { StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
5
- import { type StripeSubscriptionCheckoutSessionInput } from './useStripeSubscriptionCheckoutSession.js';
3
+ import { type PlatformWalletPaymentMethod } from './walletPlatform.js';
4
+ import type { StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
5
+ import { type StripeSubscriptionCheckoutSessionInput } from '../hooks/useStripeSubscriptionCheckoutSession.js';
6
6
  export type StripeSubscriptionWalletSurfaceCheckoutInput = Omit<StripeSubscriptionCheckoutSessionInput, 'onError'> & {
7
7
  customerName?: string | null;
8
8
  };
@@ -12,10 +12,10 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
15
- import { usePlatformWalletPaymentMethods, } from '../../components/shared/walletPlatform.js';
15
+ import { usePlatformWalletPaymentMethods, } from './walletPlatform.js';
16
16
  import { ApplePaySubscriptionCheckoutSlot } from './ApplePaySubscriptionCheckoutSlot.js';
17
17
  import { GooglePaySubscriptionCheckoutSlot } from './GooglePaySubscriptionCheckoutSlot.js';
18
- import { useStripeSubscriptionCheckoutSession, } from './useStripeSubscriptionCheckoutSession.js';
18
+ import { useStripeSubscriptionCheckoutSession, } from '../hooks/useStripeSubscriptionCheckoutSession.js';
19
19
  export function buildStripeSubscriptionWalletSurfaceAnalyticsMetadata(analyticsMetadata, surfaceId) {
20
20
  return Object.assign(Object.assign({}, (analyticsMetadata !== null && analyticsMetadata !== void 0 ? analyticsMetadata : {})), { checkoutSurfaceId: surfaceId });
21
21
  }
@@ -1,7 +1,7 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { Appearance, AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
3
- import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
4
- import { type StripeSubscriptionCheckoutSession } from './useStripeSubscriptionCheckoutSession.js';
3
+ import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
4
+ import { type StripeSubscriptionCheckoutSession } from '../hooks/useStripeSubscriptionCheckoutSession.js';
5
5
  export type WalletSubscriptionCheckoutRenderStateInput = {
6
6
  expressCheckoutAllowed: boolean;
7
7
  hasActiveClientSecret: boolean;
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useRef, useState } from 'react';
4
- import { StripeExpressCheckoutElement } from '../../components/shared/StripeExpressCheckoutElement.js';
5
- import { trackStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
6
- import { toAnalyticsPaymentMethod } from '../../services/paymentMethodAnalytics.service.js';
7
- import { isInactiveCheckoutSessionError, } from './useStripeSubscriptionCheckoutSession.js';
4
+ import { StripeExpressCheckoutElement } from './StripeExpressCheckoutElement.js';
5
+ import { trackStripeSubscriptionCheckoutStarted, } from '../services/checkoutCompletionAnalytics.service.js';
6
+ import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
7
+ import { isInactiveCheckoutSessionError, } from '../hooks/useStripeSubscriptionCheckoutSession.js';
8
8
  export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, walletPreparing, }) {
9
9
  const shouldRenderExpressCheckout = !suspended &&
10
10
  expressCheckoutAllowed &&
@@ -0,0 +1,13 @@
1
+ export * from './ApplePaySubscribeButton.js';
2
+ export * from './ApplePaySubscriptionCheckoutSlot.js';
3
+ export * from './GooglePaySubscribeButton.js';
4
+ export * from './GooglePaySubscriptionCheckoutSlot.js';
5
+ export * from './SharedStripeCheckoutDialog.js';
6
+ export * from './SharedStripeCheckoutV2Dialog.js';
7
+ export * from './StripeCheckoutExpressCheckoutButton.js';
8
+ export * from './StripeExpressCheckoutButton.js';
9
+ export * from './StripeExpressCheckoutElement.js';
10
+ export * from './StripePlanSelector.js';
11
+ export * from './StripeSubscriptionWalletSurface.js';
12
+ export * from './WalletSubscriptionCheckoutSlot.js';
13
+ export * from './walletPlatform.js';
@@ -0,0 +1,13 @@
1
+ export * from './ApplePaySubscribeButton.js';
2
+ export * from './ApplePaySubscriptionCheckoutSlot.js';
3
+ export * from './GooglePaySubscribeButton.js';
4
+ export * from './GooglePaySubscriptionCheckoutSlot.js';
5
+ export * from './SharedStripeCheckoutDialog.js';
6
+ export * from './SharedStripeCheckoutV2Dialog.js';
7
+ export * from './StripeCheckoutExpressCheckoutButton.js';
8
+ export * from './StripeExpressCheckoutButton.js';
9
+ export * from './StripeExpressCheckoutElement.js';
10
+ export * from './StripePlanSelector.js';
11
+ export * from './StripeSubscriptionWalletSurface.js';
12
+ export * from './WalletSubscriptionCheckoutSlot.js';
13
+ export * from './walletPlatform.js';
@@ -0,0 +1,3 @@
1
+ export * from './useResolvedPaywallPlans.js';
2
+ export * from './useStripeOneTimeCheckoutSession.js';
3
+ export * from './useStripeSubscriptionCheckoutSession.js';
@@ -0,0 +1,3 @@
1
+ export * from './useResolvedPaywallPlans.js';
2
+ export * from './useStripeOneTimeCheckoutSession.js';
3
+ export * from './useStripeSubscriptionCheckoutSession.js';
@@ -1,5 +1,5 @@
1
1
  import { type RuntimeMode } from '@funnelsgrove/runtime';
2
- import type { BillingFallbackPlanConfig, BillingPlanInputCatalog } from '../config/billing.config.js';
2
+ import type { BillingFallbackPlanConfig, BillingPlanInputCatalog } from '../../../config/billing.config.js';
3
3
  import { type PaywallPlan, type PaywallPlanResolutionOptions } from '../services/stripe.service.js';
4
4
  type UseResolvedPaywallPlansInput = {
5
5
  runtimeMode: RuntimeMode;
@@ -2,7 +2,7 @@
2
2
  import { useEffect, useMemo, useState } from 'react';
3
3
  import { isPreviewFrameRuntime } from '@funnelsgrove/runtime';
4
4
  import { getFallbackPlans, getPaywallPlans, } from '../services/stripe.service.js';
5
- import { isBillingPlanMappingCatalog } from '../services/planCatalog.service.js';
5
+ import { isBillingPlanMappingCatalog } from '../../../services/planCatalog.service.js';
6
6
  export const useResolvedPaywallPlans = ({ runtimeMode, planCatalog, resolutionOptions, previewPlans, }) => {
7
7
  const fallbackPlans = useMemo(() => getFallbackPlans(planCatalog, resolutionOptions), [planCatalog, resolutionOptions]);
8
8
  const isMappingCatalog = Boolean(planCatalog) && !Array.isArray(planCatalog) && isBillingPlanMappingCatalog(planCatalog);
@@ -1,7 +1,7 @@
1
1
  import type { Stripe } from '@stripe/stripe-js';
2
2
  import type { RuntimeMode } from '@funnelsgrove/runtime';
3
- import { type CheckoutPreparationLoading, type CheckoutPreparationSource } from '../paymentProvider.types.js';
4
- import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '../../services/stripe.service.js';
3
+ import { type CheckoutPreparationLoading, type CheckoutPreparationSource } from '../../paymentProvider.types.js';
4
+ import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '../services/stripe.service.js';
5
5
  type StripeOneTimeCheckoutPlanInput = Pick<PaywallPlan, 'amountCents' | 'analyticsPurchaseValue' | 'description' | 'id' | 'providerPlanId' | 'title'>;
6
6
  export type StripeOneTimeCheckoutSessionInput = {
7
7
  analyticsMetadata?: Record<string, unknown> | null;
@@ -11,10 +11,10 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
14
- import { createEmptyCheckoutPreparationLoading, } from '../paymentProvider.types.js';
15
- import { createStripeOneTimeCheckout, getStripePromise, isStripeConfigured, } from '../../services/stripe.service.js';
14
+ import { createEmptyCheckoutPreparationLoading, } from '../../paymentProvider.types.js';
15
+ import { createStripeOneTimeCheckout, getStripePromise, isStripeConfigured, } from '../services/stripe.service.js';
16
16
  import { isInactiveCheckoutSessionError } from './useStripeSubscriptionCheckoutSession.js';
17
- import { toAnalyticsPaymentMethod } from '../../services/paymentMethodAnalytics.service.js';
17
+ import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
18
18
  export function resolveStripeOneTimeCheckoutPreparationOptions(source, options = {}) {
19
19
  var _a, _b;
20
20
  const checkoutStartSource = (_a = options.checkoutStartSource) !== null && _a !== void 0 ? _a : (source === 'wallet' ? 'wallet_render' : 'card_click');
@@ -1,8 +1,8 @@
1
1
  import type { Stripe } from '@stripe/stripe-js';
2
2
  import type { RuntimeMode } from '@funnelsgrove/runtime';
3
- import { type CheckoutPreparationLoading, type CheckoutPreparationSource } from '../paymentProvider.types.js';
4
- import type { PaywallDisplayPlan } from '../../services/paywallOffer.service.js';
5
- import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '../../services/stripe.service.js';
3
+ import { type CheckoutPreparationLoading, type CheckoutPreparationSource } from '../../paymentProvider.types.js';
4
+ import type { PaywallDisplayPlan } from '../../../services/paywallOffer.service.js';
5
+ import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '../services/stripe.service.js';
6
6
  export type StripeSubscriptionCheckoutSessionInput = {
7
7
  analyticsMetadata?: Record<string, unknown> | null;
8
8
  checkoutMode: RuntimeMode;
@@ -11,9 +11,9 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
14
- import { createEmptyCheckoutPreparationLoading, } from '../paymentProvider.types.js';
15
- import { createStripeSubscriptionCheckout, getStripePromise, isStripeConfigured, updateStripeSubscriptionCheckoutPlan, } from '../../services/stripe.service.js';
16
- import { toAnalyticsPaymentMethod } from '../../services/paymentMethodAnalytics.service.js';
14
+ import { createEmptyCheckoutPreparationLoading, } from '../../paymentProvider.types.js';
15
+ import { createStripeSubscriptionCheckout, getStripePromise, isStripeConfigured, updateStripeSubscriptionCheckoutPlan, } from '../services/stripe.service.js';
16
+ import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
17
17
  export function resolveStripeSubscriptionCheckoutPreparationOptions(source, options = {}) {
18
18
  var _a, _b;
19
19
  const checkoutStartSource = (_a = options.checkoutStartSource) !== null && _a !== void 0 ? _a : (source === 'wallet' ? 'wallet_render' : 'card_click');
@@ -0,0 +1,4 @@
1
+ export * from './components/index.js';
2
+ export * from './hooks/index.js';
3
+ export * from './services/index.js';
4
+ export * from './testing/index.js';
@@ -0,0 +1,4 @@
1
+ export * from './components/index.js';
2
+ export * from './hooks/index.js';
3
+ export * from './services/index.js';
4
+ export * from './testing/index.js';
@@ -18,8 +18,13 @@ export type TrackStripeSubscriptionCheckoutStartedInput = StripeSubscriptionChec
18
18
  export type TrackPaidStripeSubscriptionCheckoutCompletedInput = StripeSubscriptionCheckoutAnalyticsContext & {
19
19
  checkoutSessionId?: string | null;
20
20
  };
21
+ export type TrackStripeSubscriptionPaymentInfoSubmittedInput = StripeSubscriptionCheckoutAnalyticsContext & {
22
+ checkoutSessionId?: string | null;
23
+ };
21
24
  export type TrackStripeSubscriptionCheckoutStartedResult = 'already_tracked' | 'analytics_rejected' | 'missing_checkout_session' | 'tracked';
22
25
  export type TrackPaidStripeSubscriptionCheckoutCompletedResult = 'already_tracked' | 'analytics_rejected' | 'missing_checkout_session' | 'tracked' | 'unpaid';
26
+ export type TrackStripeSubscriptionPaymentInfoSubmittedResult = 'already_tracked' | 'analytics_rejected' | 'missing_checkout_session' | 'tracked';
23
27
  export declare function trackStripeSubscriptionCheckoutStarted(input: TrackStripeSubscriptionCheckoutStartedInput): Promise<TrackStripeSubscriptionCheckoutStartedResult>;
24
28
  export declare function queueStripeSubscriptionCheckoutStarted(input: TrackStripeSubscriptionCheckoutStartedInput): void;
29
+ export declare function trackStripeSubscriptionPaymentInfoSubmitted(input: TrackStripeSubscriptionPaymentInfoSubmittedInput): Promise<TrackStripeSubscriptionPaymentInfoSubmittedResult>;
25
30
  export declare function trackPaidStripeSubscriptionCheckoutCompleted(input: TrackPaidStripeSubscriptionCheckoutCompletedInput): Promise<TrackPaidStripeSubscriptionCheckoutCompletedResult>;
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { publicAnalyticsSdk, } from '@funnelsgrove/analytics';
13
13
  import { verifyStripeSubscriptionCheckoutPayment, } from './stripe.service.js';
14
- import { toAnalyticsPaymentMethod } from './paymentMethodAnalytics.service.js';
14
+ import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
15
15
  const asRecord = (value) => {
16
16
  return value && typeof value === 'object' && !Array.isArray(value)
17
17
  ? value
@@ -19,6 +19,7 @@ const asRecord = (value) => {
19
19
  };
20
20
  const activeCheckoutCompletionKeys = new Set();
21
21
  const activeCheckoutStartedKeys = new Set();
22
+ const activePaymentInfoSubmittedKeys = new Set();
22
23
  const buildCheckoutStorageKey = (eventName, checkoutSessionId, runtimeConfig) => {
23
24
  var _a;
24
25
  const funnelId = ((_a = runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId) === null || _a === void 0 ? void 0 : _a.trim()) || 'unknown_funnel';
@@ -92,6 +93,45 @@ export async function trackStripeSubscriptionCheckoutStarted(input) {
92
93
  export function queueStripeSubscriptionCheckoutStarted(input) {
93
94
  void trackStripeSubscriptionCheckoutStarted(input).catch(() => undefined);
94
95
  }
96
+ export async function trackStripeSubscriptionPaymentInfoSubmitted(input) {
97
+ var _a;
98
+ const checkoutSessionId = ((_a = input.checkoutSessionId) === null || _a === void 0 ? void 0 : _a.trim()) || '';
99
+ if (!checkoutSessionId) {
100
+ return 'missing_checkout_session';
101
+ }
102
+ const storageKey = buildCheckoutStorageKey('add_payment_info', checkoutSessionId, input.runtimeConfig);
103
+ if (activePaymentInfoSubmittedKeys.has(storageKey)
104
+ || hasTrackedCheckoutSession('add_payment_info', checkoutSessionId, input.runtimeConfig)) {
105
+ return 'already_tracked';
106
+ }
107
+ activePaymentInfoSubmittedKeys.add(storageKey);
108
+ try {
109
+ let eventId = null;
110
+ try {
111
+ eventId = publicAnalyticsSdk.trackPaymentInfoSubmitted({
112
+ eventId: `add_payment_info:${checkoutSessionId}`,
113
+ featureFlags: input.featureFlags,
114
+ stepId: input.stepId,
115
+ stepName: input.stepName,
116
+ stepType: input.stepType,
117
+ stepContractVersion: input.stepContractVersion,
118
+ metadata: Object.assign(Object.assign({}, asRecord(input.metadata)), { checkoutSessionId, checkout_session_id: checkoutSessionId, environment: input.environment || asRecord(input.metadata).environment, payment_provider: 'stripe' }),
119
+ });
120
+ }
121
+ catch (_b) {
122
+ // Analytics must not prevent Stripe confirmation.
123
+ }
124
+ if (!eventId) {
125
+ return 'analytics_rejected';
126
+ }
127
+ markCheckoutSessionTracked('add_payment_info', checkoutSessionId, input.runtimeConfig);
128
+ await publicAnalyticsSdk.flush().catch(() => 0);
129
+ return 'tracked';
130
+ }
131
+ finally {
132
+ activePaymentInfoSubmittedKeys.delete(storageKey);
133
+ }
134
+ }
95
135
  export async function trackPaidStripeSubscriptionCheckoutCompleted(input) {
96
136
  var _a;
97
137
  const checkoutSessionId = ((_a = input.checkoutSessionId) === null || _a === void 0 ? void 0 : _a.trim()) || '';
@@ -0,0 +1,2 @@
1
+ export * from './checkoutCompletionAnalytics.service.js';
2
+ export * from './stripe.service.js';
@@ -0,0 +1,2 @@
1
+ export * from './checkoutCompletionAnalytics.service.js';
2
+ export * from './stripe.service.js';
@@ -1,8 +1,8 @@
1
1
  import { type Stripe } from '@stripe/stripe-js';
2
- import { type BillingFallbackPlanConfig, type BillingPlanCatalog, type BillingPlanInterval, type BillingPlanInputCatalog } from '../config/billing.config.js';
2
+ import { type BillingFallbackPlanConfig, type BillingPlanCatalog, type BillingPlanInterval, type BillingPlanInputCatalog } from '../../../config/billing.config.js';
3
3
  import { type FunnelSdkRuntimeConfigOverrides, type ResolvedCountryPricing } from '@funnelsgrove/runtime';
4
4
  import type { RuntimeMode } from '@funnelsgrove/runtime';
5
- import { type RemoteProjectBillingPlan } from './planCatalog.service.js';
5
+ import { type RemoteProjectBillingPlan } from '../../../services/planCatalog.service.js';
6
6
  export type PaywallPlan = {
7
7
  id: string;
8
8
  offerSetId?: string;
@@ -94,19 +94,25 @@ export declare function createStripeOneTimeCheckout(input: CreateOneTimeCheckout
94
94
  * @deprecated Use createStripeOneTimeCheckout for one-time paywall checkout.
95
95
  */
96
96
  export declare function createStripePaymentIntent(input: CreatePaymentIntentInput): Promise<CreatePaymentIntentResponse>;
97
- type ChargeOneClickPaymentInput = {
97
+ export type ChargeOneClickPaymentInput = {
98
98
  planId: string;
99
+ providerPlanId?: string | null;
99
100
  amountCents: number;
100
101
  analyticsMetadata?: Record<string, unknown> | null;
101
102
  checkoutSessionId?: string | null;
102
103
  currency?: string | null;
104
+ description?: string | null;
103
105
  idempotencyKey?: string | null;
106
+ stripeCustomerId?: string | null;
107
+ userId?: string | null;
108
+ /** @deprecated Use stripeCustomerId. */
104
109
  stripe_customer_id?: string | null;
110
+ /** @deprecated Use userId. */
105
111
  user_id?: string | null;
106
112
  environment?: RuntimeMode;
107
113
  runtimeConfig?: StripeRuntimeConfigOverrides;
108
114
  };
109
- type ChargeOneClickPaymentResponse = {
115
+ export type ChargeOneClickPaymentResponse = {
110
116
  paymentIntentId: string;
111
117
  status: string;
112
118
  amountCents?: number;
@@ -116,6 +122,14 @@ type ChargeOneClickPaymentResponse = {
116
122
  stripePublishableKey?: string;
117
123
  };
118
124
  export declare function chargeStripeOneClickPayment(input: ChargeOneClickPaymentInput): Promise<ChargeOneClickPaymentResponse>;
125
+ export type CompleteStripeOneClickPaymentInput = ChargeOneClickPaymentInput & {
126
+ returnUrl: string;
127
+ };
128
+ export type CompleteStripeOneClickPaymentResponse = ChargeOneClickPaymentResponse & {
129
+ confirmationAttempted: boolean;
130
+ };
131
+ export declare const requiresStripeOneClickConfirmation: (status: string) => boolean;
132
+ export declare function completeStripeOneClickPayment(input: CompleteStripeOneClickPaymentInput): Promise<CompleteStripeOneClickPaymentResponse>;
119
133
  type CreateSubscriptionCheckoutInput = {
120
134
  plan: CheckoutSessionPlanInput;
121
135
  couponId?: string | null;
@@ -1,7 +1,7 @@
1
1
  import { loadStripe } from '@stripe/stripe-js';
2
- import { billingPlanList, } from '../config/billing.config.js';
2
+ import { billingPlanList, } from '../../../config/billing.config.js';
3
3
  import { FUNNEL_ID, FUNNEL_SDK_PUBLISHABLE_KEY, funnelSdkService, } from '@funnelsgrove/runtime';
4
- import { isBillingPlanMappingCatalog, resolveMappedProjectPlans, } from './planCatalog.service.js';
4
+ import { isBillingPlanMappingCatalog, resolveMappedProjectPlans, } from '../../../services/planCatalog.service.js';
5
5
  const stripePromiseByKey = new Map();
6
6
  const syncedPlansPromiseByMode = new Map();
7
7
  export const buildPaywallPlanResolutionSignature = (options) => {
@@ -586,20 +586,52 @@ export async function createStripePaymentIntent(input) {
586
586
  });
587
587
  }
588
588
  export async function chargeStripeOneClickPayment(input) {
589
- var _a, _b, _c, _d, _e;
589
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
590
590
  return funnelSdkService.chargeOneClickPayment({
591
591
  planId: input.planId,
592
+ providerPlanId: ((_a = input.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
592
593
  amountCents: input.amountCents,
593
- currency: ((_a = input.currency) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
594
+ currency: ((_b = input.currency) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
595
+ description: ((_c = input.description) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
594
596
  analyticsMetadata: normalizeAnalyticsMetadata(input.analyticsMetadata),
595
- userId: ((_b = input.user_id) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
596
- stripeCustomerId: ((_c = input.stripe_customer_id) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
597
- checkoutSessionId: ((_d = input.checkoutSessionId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
598
- idempotencyKey: ((_e = input.idempotencyKey) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
597
+ userId: ((_d = input.userId) === null || _d === void 0 ? void 0 : _d.trim()) || ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
598
+ stripeCustomerId: ((_f = input.stripeCustomerId) === null || _f === void 0 ? void 0 : _f.trim()) || ((_g = input.stripe_customer_id) === null || _g === void 0 ? void 0 : _g.trim()) || undefined,
599
+ checkoutSessionId: ((_h = input.checkoutSessionId) === null || _h === void 0 ? void 0 : _h.trim()) || undefined,
600
+ idempotencyKey: ((_j = input.idempotencyKey) === null || _j === void 0 ? void 0 : _j.trim()) || undefined,
599
601
  environment: input.environment,
600
602
  runtimeConfig: input.runtimeConfig,
601
603
  });
602
604
  }
605
+ export const requiresStripeOneClickConfirmation = (status) => {
606
+ return status === 'requires_action' || status === 'requires_confirmation';
607
+ };
608
+ export async function completeStripeOneClickPayment(input) {
609
+ var _a, _b, _c, _d, _e, _f;
610
+ const payment = await chargeStripeOneClickPayment(input);
611
+ if (!requiresStripeOneClickConfirmation(payment.status)) {
612
+ return Object.assign(Object.assign({}, payment), { confirmationAttempted: false });
613
+ }
614
+ const clientSecret = (_a = payment.clientSecret) === null || _a === void 0 ? void 0 : _a.trim();
615
+ const stripePublishableKey = (_b = payment.stripePublishableKey) === null || _b === void 0 ? void 0 : _b.trim();
616
+ if (!clientSecret || !stripePublishableKey) {
617
+ throw new Error('One-click payment requires Stripe confirmation, but confirmation details are missing.');
618
+ }
619
+ const stripe = await getStripePromise((_d = (_c = payment.environment) !== null && _c !== void 0 ? _c : input.environment) !== null && _d !== void 0 ? _d : 'live', stripePublishableKey);
620
+ if (!stripe) {
621
+ throw new Error('Stripe could not be initialized for one-click payment confirmation.');
622
+ }
623
+ const confirmation = await stripe.confirmPayment({
624
+ clientSecret,
625
+ confirmParams: {
626
+ return_url: input.returnUrl,
627
+ },
628
+ redirect: 'if_required',
629
+ });
630
+ if (confirmation.error) {
631
+ throw new Error(confirmation.error.message || 'Unable to confirm one-click payment.');
632
+ }
633
+ return Object.assign(Object.assign({}, payment), { status: (_f = (_e = confirmation.paymentIntent) === null || _e === void 0 ? void 0 : _e.status) !== null && _f !== void 0 ? _f : payment.status, confirmationAttempted: true });
634
+ }
603
635
  export async function createStripeSubscriptionCheckout(input) {
604
636
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
605
637
  const recurring = resolveCheckoutPlanRecurringConfig(input.plan);
@@ -0,0 +1 @@
1
+ export * from './walletCheckoutSmoke.js';
@@ -0,0 +1 @@
1
+ export * from './walletCheckoutSmoke.js';
@@ -1,5 +1,5 @@
1
1
  import type { BillingDiscountCatalog, BillingDiscountList } from '../config/billing.config.js';
2
- import type { PaywallPlan } from './stripe.service.js';
2
+ import type { PaywallPlan } from '../providers/stripe/services/stripe.service.js';
3
3
  export type PaywallDiscountCatalog = BillingDiscountCatalog;
4
4
  export type PaywallDiscountStage = 'first' | 'second' | 'completed';
5
5
  export type PaywallActiveDiscountStage = Exclude<PaywallDiscountStage, 'completed'>;
@@ -1,6 +1,6 @@
1
1
  import { type FunnelExperimentDefinition, type FunnelManifestExperiment, type OfferSetRuntimePlanOverrides, type ResolvedFunnelRuntimeConfig, type ResolvedPublishedExperiments, type RuntimeMode } from '@funnelsgrove/runtime';
2
2
  import type { BillingDiscountCatalog, BillingDiscountList, BillingFallbackPlanConfig, BillingPlanCatalog } from '../config/billing.config.js';
3
- import { type PaywallPlan } from './stripe.service.js';
3
+ import { type PaywallPlan } from '../providers/stripe/services/stripe.service.js';
4
4
  export type PublishedBillingPlan = BillingFallbackPlanConfig & OfferSetRuntimePlanOverrides;
5
5
  export type ResolvedPublishedBillingRuntime = {
6
6
  revisionId: string | null;
@@ -1,6 +1,6 @@
1
1
  import { resolveGeneratedOfferSetRuntime, resolvePublishedOfferSetSelection, resolvePublishedRuntimeExperiments, } from '@funnelsgrove/runtime';
2
2
  import { buildBillingDiscountCatalog } from './paywallOffer.service.js';
3
- import { buildConfigPaywallPlans } from './stripe.service.js';
3
+ import { buildConfigPaywallPlans, } from '../providers/stripe/services/stripe.service.js';
4
4
  export const resolvePublishedBillingRuntime = ({ config, featureFlags, mode, search = '', defaultOfferSetId, baseCatalogsByMode, fallbackDiscounts, resolvedExperiments = resolvePublishedRuntimeExperiments(config), }) => {
5
5
  var _a, _b;
6
6
  const offerSets = (_a = config === null || config === void 0 ? void 0 : config.offerSets) !== null && _a !== void 0 ? _a : [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",
@@ -32,8 +32,8 @@
32
32
  "test:run": "vitest run --passWithNoTests"
33
33
  },
34
34
  "dependencies": {
35
- "@funnelsgrove/analytics": "^0.1.28",
36
- "@funnelsgrove/runtime": "^0.7.1",
35
+ "@funnelsgrove/analytics": "^0.1.52",
36
+ "@funnelsgrove/runtime": "^0.7.3",
37
37
  "@stripe/react-stripe-js": "^5.6.0",
38
38
  "@stripe/stripe-js": "^8.7.0",
39
39
  "react": "19.2.3",