@funnelsgrove/payments 0.7.0 → 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.
- package/README.md +16 -7
- package/dist/index.d.ts +2 -19
- package/dist/index.js +5 -25
- package/dist/providers/stripe/{ApplePaySubscriptionCheckoutSlot.js → components/ApplePaySubscriptionCheckoutSlot.js} +1 -1
- package/dist/providers/stripe/{GooglePaySubscriptionCheckoutSlot.js → components/GooglePaySubscriptionCheckoutSlot.js} +1 -1
- package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutDialog.d.ts +1 -1
- package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutDialog.js +1 -1
- package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutV2Dialog.d.ts +1 -1
- package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutV2Dialog.js +9 -3
- package/dist/{components/shared → providers/stripe/components}/StripeCheckoutExpressCheckoutButton.d.ts +1 -1
- package/dist/{components/shared → providers/stripe/components}/StripeCheckoutExpressCheckoutButton.js +4 -1
- package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutButton.d.ts +1 -1
- package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutButton.js +4 -1
- package/dist/{components/shared → providers/stripe/components}/StripePlanSelector.d.ts +1 -1
- package/dist/{components/shared → providers/stripe/components}/StripePlanSelector.js +1 -1
- package/dist/providers/stripe/{StripeSubscriptionWalletSurface.d.ts → components/StripeSubscriptionWalletSurface.d.ts} +3 -3
- package/dist/providers/stripe/{StripeSubscriptionWalletSurface.js → components/StripeSubscriptionWalletSurface.js} +2 -2
- package/dist/providers/stripe/{WalletSubscriptionCheckoutSlot.d.ts → components/WalletSubscriptionCheckoutSlot.d.ts} +2 -2
- package/dist/providers/stripe/{WalletSubscriptionCheckoutSlot.js → components/WalletSubscriptionCheckoutSlot.js} +4 -4
- package/dist/providers/stripe/components/index.d.ts +13 -0
- package/dist/providers/stripe/components/index.js +13 -0
- package/dist/providers/stripe/hooks/index.d.ts +3 -0
- package/dist/providers/stripe/hooks/index.js +3 -0
- package/dist/{hooks → providers/stripe/hooks}/useResolvedPaywallPlans.d.ts +1 -1
- package/dist/{hooks → providers/stripe/hooks}/useResolvedPaywallPlans.js +1 -1
- package/dist/providers/stripe/{useStripeOneTimeCheckoutSession.d.ts → hooks/useStripeOneTimeCheckoutSession.d.ts} +2 -2
- package/dist/providers/stripe/{useStripeOneTimeCheckoutSession.js → hooks/useStripeOneTimeCheckoutSession.js} +3 -3
- package/dist/providers/stripe/{useStripeSubscriptionCheckoutSession.d.ts → hooks/useStripeSubscriptionCheckoutSession.d.ts} +3 -3
- package/dist/providers/stripe/{useStripeSubscriptionCheckoutSession.js → hooks/useStripeSubscriptionCheckoutSession.js} +3 -3
- package/dist/providers/stripe/index.d.ts +4 -0
- package/dist/providers/stripe/index.js +4 -0
- package/dist/{services → providers/stripe/services}/checkoutCompletionAnalytics.service.d.ts +5 -0
- package/dist/{services → providers/stripe/services}/checkoutCompletionAnalytics.service.js +41 -1
- package/dist/providers/stripe/services/index.d.ts +2 -0
- package/dist/providers/stripe/services/index.js +2 -0
- package/dist/{services → providers/stripe/services}/stripe.service.d.ts +18 -4
- package/dist/{services → providers/stripe/services}/stripe.service.js +40 -8
- package/dist/providers/stripe/testing/index.d.ts +1 -0
- package/dist/providers/stripe/testing/index.js +1 -0
- package/dist/services/paywallOffer.service.d.ts +1 -1
- package/dist/services/publishedBillingRuntime.service.d.ts +29 -0
- package/dist/services/publishedBillingRuntime.service.js +40 -0
- package/package.json +3 -3
- /package/dist/{components/shared → providers/stripe/components}/ApplePaySubscribeButton.d.ts +0 -0
- /package/dist/{components/shared → providers/stripe/components}/ApplePaySubscribeButton.js +0 -0
- /package/dist/providers/stripe/{ApplePaySubscriptionCheckoutSlot.d.ts → components/ApplePaySubscriptionCheckoutSlot.d.ts} +0 -0
- /package/dist/{components/shared → providers/stripe/components}/CheckoutBrandAssets.d.ts +0 -0
- /package/dist/{components/shared → providers/stripe/components}/CheckoutBrandAssets.js +0 -0
- /package/dist/{components/shared → providers/stripe/components}/GooglePaySubscribeButton.d.ts +0 -0
- /package/dist/{components/shared → providers/stripe/components}/GooglePaySubscribeButton.js +0 -0
- /package/dist/providers/stripe/{GooglePaySubscriptionCheckoutSlot.d.ts → components/GooglePaySubscriptionCheckoutSlot.d.ts} +0 -0
- /package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutElement.d.ts +0 -0
- /package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutElement.js +0 -0
- /package/dist/{components/shared → providers/stripe/components}/checkoutCountries.d.ts +0 -0
- /package/dist/{components/shared → providers/stripe/components}/checkoutCountries.js +0 -0
- /package/dist/{components/shared → providers/stripe/components}/walletPlatform.d.ts +0 -0
- /package/dist/{components/shared → providers/stripe/components}/walletPlatform.js +0 -0
- /package/dist/{testing → providers/stripe/testing}/walletCheckoutSmoke.d.ts +0 -0
- /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,
|
|
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 `
|
|
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
|
|
|
@@ -74,22 +75,30 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
|
|
|
74
75
|
## Public Surfaces
|
|
75
76
|
|
|
76
77
|
- `config/billing.config`: billing catalog, mapping, plan, and discount contracts.
|
|
78
|
+
- `services/publishedBillingRuntime.service`: resolves one published runtime artifact into component-ready plans, defaults, upsells, downsells, discounts, and flow experiments.
|
|
77
79
|
- `services/planCatalog.service`: plan resolution and selection helpers.
|
|
78
80
|
- `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
|
|
79
81
|
- `services/paywallOffer.service`: timed discount and display-plan helpers.
|
|
80
|
-
- `
|
|
81
|
-
- `providers/*`:
|
|
82
|
-
- `
|
|
83
|
-
- `
|
|
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.
|
|
88
|
+
|
|
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.
|
|
84
90
|
|
|
85
91
|
## Engineering Rules
|
|
86
92
|
|
|
87
|
-
- Keep provider-specific
|
|
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`.
|
|
88
94
|
- Stripe owns real card fields and wallet controls. Local wallet buttons are placeholders until Stripe confirms availability.
|
|
89
95
|
- Wallet unavailable state must fall back to card/manual checkout or disappear.
|
|
90
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.
|
|
91
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`.
|
|
92
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.
|
|
93
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.
|
|
94
103
|
- Keep discount math reusable here, but keep offer activation timing in funnel code.
|
|
95
104
|
- Checkout metadata must avoid sensitive raw query params and use `@funnelsgrove/analytics` metadata helpers.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,26 +3,9 @@ export * from './services/preview-frame.service.js';
|
|
|
3
3
|
export * from './services/runtime-mode.service.js';
|
|
4
4
|
export * from './services/planCatalog.service.js';
|
|
5
5
|
export * from './services/runtimeBillingPlanCatalog.service.js';
|
|
6
|
+
export * from './services/publishedBillingRuntime.service.js';
|
|
6
7
|
export * from './services/paywallOffer.service.js';
|
|
7
|
-
export * from './services/stripe.service.js';
|
|
8
|
-
export * from './services/checkoutCompletionAnalytics.service.js';
|
|
9
8
|
export * from './services/paymentMethodAnalytics.service.js';
|
|
10
|
-
export * from './hooks/useResolvedPaywallPlans.js';
|
|
11
9
|
export * from './providers/paymentProvider.types.js';
|
|
12
|
-
export * from './providers/stripe/
|
|
13
|
-
export * from './providers/stripe/useStripeOneTimeCheckoutSession.js';
|
|
14
|
-
export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
|
|
15
|
-
export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
|
|
16
|
-
export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
|
|
17
|
-
export * from './providers/stripe/StripeSubscriptionWalletSurface.js';
|
|
10
|
+
export * from './providers/stripe/index.js';
|
|
18
11
|
export { ManageSubscriptionScreen, type ManageSubscriptionContent, type ManageSubscriptionScreenProps, } from './components/ManageSubscriptionScreen.js';
|
|
19
|
-
export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
|
|
20
|
-
export * from './components/shared/StripeExpressCheckoutElement.js';
|
|
21
|
-
export * from './components/shared/StripePlanSelector.js';
|
|
22
|
-
export * from './components/shared/walletPlatform.js';
|
|
23
|
-
export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
|
|
24
|
-
export * from './components/shared/StripeExpressCheckoutButton.js';
|
|
25
|
-
export * from './components/shared/SharedStripeCheckoutDialog.js';
|
|
26
|
-
export * from './components/shared/ApplePaySubscribeButton.js';
|
|
27
|
-
export * from './components/shared/GooglePaySubscribeButton.js';
|
|
28
|
-
export * from './testing/walletCheckoutSmoke.js';
|
package/dist/index.js
CHANGED
|
@@ -1,34 +1,14 @@
|
|
|
1
|
-
//
|
|
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';
|
|
5
5
|
export * from './services/planCatalog.service.js';
|
|
6
6
|
export * from './services/runtimeBillingPlanCatalog.service.js';
|
|
7
|
+
export * from './services/publishedBillingRuntime.service.js';
|
|
7
8
|
export * from './services/paywallOffer.service.js';
|
|
8
|
-
// Stripe API clients and checkout completion handoff.
|
|
9
|
-
export * from './services/stripe.service.js';
|
|
10
|
-
export * from './services/checkoutCompletionAnalytics.service.js';
|
|
11
9
|
export * from './services/paymentMethodAnalytics.service.js';
|
|
12
|
-
export * from './hooks/useResolvedPaywallPlans.js';
|
|
13
|
-
// Provider-neutral and Stripe subscription checkout primitives.
|
|
14
10
|
export * from './providers/paymentProvider.types.js';
|
|
15
|
-
|
|
16
|
-
export * from './providers/stripe/
|
|
17
|
-
|
|
18
|
-
export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
|
|
19
|
-
export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
|
|
20
|
-
export * from './providers/stripe/StripeSubscriptionWalletSurface.js';
|
|
21
|
-
// 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.
|
|
22
14
|
export { ManageSubscriptionScreen, } from './components/ManageSubscriptionScreen.js';
|
|
23
|
-
export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
|
|
24
|
-
export * from './components/shared/StripeExpressCheckoutElement.js';
|
|
25
|
-
export * from './components/shared/StripePlanSelector.js';
|
|
26
|
-
export * from './components/shared/walletPlatform.js';
|
|
27
|
-
export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
|
|
28
|
-
export * from './components/shared/StripeExpressCheckoutButton.js';
|
|
29
|
-
// Compatibility-only surfaces kept for saved drafts and published artifacts.
|
|
30
|
-
export * from './components/shared/SharedStripeCheckoutDialog.js';
|
|
31
|
-
export * from './components/shared/ApplePaySubscribeButton.js';
|
|
32
|
-
export * from './components/shared/GooglePaySubscribeButton.js';
|
|
33
|
-
// QA helpers.
|
|
34
|
-
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 '
|
|
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 '
|
|
14
|
+
import { GooglePaySubscribeButton } from './GooglePaySubscribeButton.js';
|
|
15
15
|
import { WalletSubscriptionCheckoutLoadingPlaceholder, WalletSubscriptionCheckoutSlot, } from './WalletSubscriptionCheckoutSlot.js';
|
|
16
16
|
const googlePayExpressCheckoutOptions = {
|
|
17
17
|
buttonHeight: 55,
|
package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutDialog.d.ts
RENAMED
|
@@ -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 '
|
|
3
|
+
import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
|
|
4
4
|
export type SharedStripeCheckoutSummaryRow = {
|
|
5
5
|
id: string;
|
|
6
6
|
label: string;
|
package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutDialog.js
RENAMED
|
@@ -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 '
|
|
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) => {
|
package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutV2Dialog.d.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Stripe } from '@stripe/stripe-js';
|
|
2
|
-
import { type StripeSubscriptionCheckoutAnalyticsContext } from '
|
|
2
|
+
import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
|
|
3
3
|
export type SharedStripeCheckoutV2DialogProps = {
|
|
4
4
|
amountCents: number;
|
|
5
5
|
buttonColor: string;
|
package/dist/{components/shared → providers/stripe/components}/SharedStripeCheckoutV2Dialog.js
RENAMED
|
@@ -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 '
|
|
19
|
+
import { isInactiveCheckoutSessionError } from '../hooks/useStripeSubscriptionCheckoutSession.js';
|
|
20
20
|
import { getStripeWalletPaymentMethodOrder, usePlatformWalletPaymentMethods, } from './walletPlatform.js';
|
|
21
|
-
import { queueStripeSubscriptionCheckoutStarted, trackPaidStripeSubscriptionCheckoutCompleted, } from '
|
|
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 (
|
|
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 '
|
|
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 '
|
|
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 }
|
package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutButton.d.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AvailablePaymentMethods, StripeExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
2
|
-
import { type StripeSubscriptionCheckoutAnalyticsContext } from '
|
|
2
|
+
import { type StripeSubscriptionCheckoutAnalyticsContext } from '../services/checkoutCompletionAnalytics.service.js';
|
|
3
3
|
export type StripeExpressCheckoutButtonProps = {
|
|
4
4
|
amountCents: number;
|
|
5
5
|
beforeConfirm?: () => Promise<string | null>;
|
package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutButton.js
RENAMED
|
@@ -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 '
|
|
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 '
|
|
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 '
|
|
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 '
|
|
4
|
-
import type { StripeSubscriptionCheckoutAnalyticsContext } from '
|
|
5
|
-
import { type StripeSubscriptionCheckoutSessionInput } from '
|
|
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 '
|
|
15
|
+
import { usePlatformWalletPaymentMethods, } from './walletPlatform.js';
|
|
16
16
|
import { ApplePaySubscriptionCheckoutSlot } from './ApplePaySubscriptionCheckoutSlot.js';
|
|
17
17
|
import { GooglePaySubscriptionCheckoutSlot } from './GooglePaySubscriptionCheckoutSlot.js';
|
|
18
|
-
import { useStripeSubscriptionCheckoutSession, } from '
|
|
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 '
|
|
4
|
-
import { type StripeSubscriptionCheckoutSession } from '
|
|
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 '
|
|
5
|
-
import { trackStripeSubscriptionCheckoutStarted, } from '
|
|
6
|
-
import { toAnalyticsPaymentMethod } from '
|
|
7
|
-
import { isInactiveCheckoutSessionError, } from '
|
|
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';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RuntimeMode } from '@funnelsgrove/runtime';
|
|
2
|
-
import type { BillingFallbackPlanConfig, BillingPlanInputCatalog } from '
|
|
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 '
|
|
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 '
|
|
4
|
-
import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '
|
|
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 '
|
|
15
|
-
import { createStripeOneTimeCheckout, getStripePromise, isStripeConfigured, } from '
|
|
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 '
|
|
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 '
|
|
4
|
-
import type { PaywallDisplayPlan } from '
|
|
5
|
-
import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '
|
|
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 '
|
|
15
|
-
import { createStripeSubscriptionCheckout, getStripePromise, isStripeConfigured, updateStripeSubscriptionCheckoutPlan, } from '
|
|
16
|
-
import { toAnalyticsPaymentMethod } from '
|
|
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');
|
package/dist/{services → providers/stripe/services}/checkoutCompletionAnalytics.service.d.ts
RENAMED
|
@@ -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 '
|
|
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()) || '';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Stripe } from '@stripe/stripe-js';
|
|
2
|
-
import { type BillingFallbackPlanConfig, type BillingPlanCatalog, type BillingPlanInterval, type BillingPlanInputCatalog } from '
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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: ((
|
|
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: ((
|
|
596
|
-
stripeCustomerId: ((
|
|
597
|
-
checkoutSessionId: ((
|
|
598
|
-
idempotencyKey: ((
|
|
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 '
|
|
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'>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type FunnelExperimentDefinition, type FunnelManifestExperiment, type OfferSetRuntimePlanOverrides, type ResolvedFunnelRuntimeConfig, type ResolvedPublishedExperiments, type RuntimeMode } from '@funnelsgrove/runtime';
|
|
2
|
+
import type { BillingDiscountCatalog, BillingDiscountList, BillingFallbackPlanConfig, BillingPlanCatalog } from '../config/billing.config.js';
|
|
3
|
+
import { type PaywallPlan } from '../providers/stripe/services/stripe.service.js';
|
|
4
|
+
export type PublishedBillingPlan = BillingFallbackPlanConfig & OfferSetRuntimePlanOverrides;
|
|
5
|
+
export type ResolvedPublishedBillingRuntime = {
|
|
6
|
+
revisionId: string | null;
|
|
7
|
+
mode: RuntimeMode;
|
|
8
|
+
offerSetId: string;
|
|
9
|
+
experimentId: string | null;
|
|
10
|
+
variantKey: string | null;
|
|
11
|
+
experiments: readonly FunnelExperimentDefinition[];
|
|
12
|
+
flowExperiments: readonly FunnelManifestExperiment[];
|
|
13
|
+
plans: readonly PaywallPlan[];
|
|
14
|
+
planCatalog: Record<string, PublishedBillingPlan>;
|
|
15
|
+
defaultPlanKey: string;
|
|
16
|
+
discounts: BillingDiscountCatalog | null;
|
|
17
|
+
upsells: readonly PublishedBillingPlan[];
|
|
18
|
+
downsells: readonly PublishedBillingPlan[];
|
|
19
|
+
};
|
|
20
|
+
export declare const resolvePublishedBillingRuntime: ({ config, featureFlags, mode, search, defaultOfferSetId, baseCatalogsByMode, fallbackDiscounts, resolvedExperiments, }: {
|
|
21
|
+
config: ResolvedFunnelRuntimeConfig | null;
|
|
22
|
+
featureFlags: Readonly<Record<string, string>>;
|
|
23
|
+
mode: RuntimeMode;
|
|
24
|
+
search?: string;
|
|
25
|
+
defaultOfferSetId?: string;
|
|
26
|
+
baseCatalogsByMode?: Partial<Record<RuntimeMode, BillingPlanCatalog>>;
|
|
27
|
+
fallbackDiscounts?: BillingDiscountList;
|
|
28
|
+
resolvedExperiments?: ResolvedPublishedExperiments;
|
|
29
|
+
}) => ResolvedPublishedBillingRuntime;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { resolveGeneratedOfferSetRuntime, resolvePublishedOfferSetSelection, resolvePublishedRuntimeExperiments, } from '@funnelsgrove/runtime';
|
|
2
|
+
import { buildBillingDiscountCatalog } from './paywallOffer.service.js';
|
|
3
|
+
import { buildConfigPaywallPlans, } from '../providers/stripe/services/stripe.service.js';
|
|
4
|
+
export const resolvePublishedBillingRuntime = ({ config, featureFlags, mode, search = '', defaultOfferSetId, baseCatalogsByMode, fallbackDiscounts, resolvedExperiments = resolvePublishedRuntimeExperiments(config), }) => {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const offerSets = (_a = config === null || config === void 0 ? void 0 : config.offerSets) !== null && _a !== void 0 ? _a : [];
|
|
7
|
+
const selection = resolvePublishedOfferSetSelection({
|
|
8
|
+
offerSets,
|
|
9
|
+
pricingExperiments: resolvedExperiments.pricingExperiments,
|
|
10
|
+
featureFlags,
|
|
11
|
+
search,
|
|
12
|
+
defaultOfferSetId,
|
|
13
|
+
});
|
|
14
|
+
const runtime = resolveGeneratedOfferSetRuntime({
|
|
15
|
+
offerSets,
|
|
16
|
+
offerSetId: selection.offerSetId,
|
|
17
|
+
baseCatalogsByMode,
|
|
18
|
+
fallbackDiscounts,
|
|
19
|
+
});
|
|
20
|
+
const planCatalog = runtime.getPlanCatalog(mode);
|
|
21
|
+
const getPlans = (keys) => keys
|
|
22
|
+
.map((key) => planCatalog[key])
|
|
23
|
+
.filter((plan) => Boolean(plan));
|
|
24
|
+
const discountList = runtime.getDiscountList(mode);
|
|
25
|
+
return {
|
|
26
|
+
revisionId: (_b = config === null || config === void 0 ? void 0 : config.revisionId) !== null && _b !== void 0 ? _b : null,
|
|
27
|
+
mode,
|
|
28
|
+
offerSetId: selection.offerSetId,
|
|
29
|
+
experimentId: selection.experimentId,
|
|
30
|
+
variantKey: selection.variantKey,
|
|
31
|
+
experiments: resolvedExperiments.experiments,
|
|
32
|
+
flowExperiments: resolvedExperiments.flowExperiments,
|
|
33
|
+
plans: buildConfigPaywallPlans(planCatalog, runtime.planKeys),
|
|
34
|
+
planCatalog,
|
|
35
|
+
defaultPlanKey: runtime.defaultPlanKey,
|
|
36
|
+
discounts: discountList.length > 0 ? buildBillingDiscountCatalog(discountList) : null,
|
|
37
|
+
upsells: getPlans(runtime.upsellPlanKeys),
|
|
38
|
+
downsells: getPlans(runtime.downsellPlanKeys),
|
|
39
|
+
};
|
|
40
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnelsgrove/payments",
|
|
3
|
-
"version": "0.7.
|
|
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.
|
|
36
|
-
"@funnelsgrove/runtime": "^0.7.
|
|
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",
|
/package/dist/{components/shared → providers/stripe/components}/ApplePaySubscribeButton.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{components/shared → providers/stripe/components}/GooglePaySubscribeButton.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutElement.d.ts
RENAMED
|
File without changes
|
/package/dist/{components/shared → providers/stripe/components}/StripeExpressCheckoutElement.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|