@funnelsgrove/payments 0.11.16 → 0.11.18
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/dist/providers/stripe/components/WalletSubscriptionCheckoutSlot.js +69 -0
- package/dist/providers/stripe/hooks/checkoutAttempt.d.ts +3 -0
- package/dist/providers/stripe/hooks/checkoutAttempt.js +7 -3
- package/dist/providers/stripe/hooks/checkoutIdentity.d.ts +7 -0
- package/dist/providers/stripe/hooks/checkoutIdentity.js +6 -0
- package/dist/providers/stripe/hooks/useStripeOneTimeCheckoutSession.d.ts +1 -1
- package/dist/providers/stripe/hooks/useStripeOneTimeCheckoutSession.js +7 -0
- package/dist/providers/stripe/hooks/useStripeSubscriptionCheckoutSession.d.ts +1 -0
- package/dist/providers/stripe/hooks/useStripeSubscriptionCheckoutSession.js +7 -0
- package/dist/providers/stripe/services/checkout/requests.d.ts +53 -0
- package/dist/providers/stripe/services/checkout/requests.js +8 -51
- package/dist/services/checkoutObservability.service.d.ts +11 -0
- package/dist/services/checkoutObservability.service.js +50 -0
- package/package.json +2 -2
|
@@ -5,6 +5,7 @@ import { StripeExpressCheckoutElement } from './StripeExpressCheckoutElement.js'
|
|
|
5
5
|
import { trackStripeSubscriptionCheckoutStarted, } from '../services/checkoutCompletionAnalytics.service.js';
|
|
6
6
|
import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
|
|
7
7
|
import { isInactiveCheckoutSessionError, } from '../hooks/useStripeSubscriptionCheckoutSession.js';
|
|
8
|
+
import { trackCheckoutWalletReady } from '../../../services/checkoutObservability.service.js';
|
|
8
9
|
export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, walletPreparing, }) {
|
|
9
10
|
const shouldRenderExpressCheckout = !suspended &&
|
|
10
11
|
expressCheckoutAllowed &&
|
|
@@ -42,6 +43,23 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availa
|
|
|
42
43
|
const [walletCheckoutStartedAfterClickIntentKey, setWalletCheckoutStartedAfterClickIntentKey] = useState(null);
|
|
43
44
|
const autoWalletPreparationIntentKeyRef = useRef(null);
|
|
44
45
|
const walletCheckoutStartedAfterClickSessionIdRef = useRef(null);
|
|
46
|
+
const walletReadinessCycleRef = useRef(null);
|
|
47
|
+
if (!walletReadinessCycleRef.current
|
|
48
|
+
|| walletReadinessCycleRef.current.intentKey !== session.intentKey) {
|
|
49
|
+
walletReadinessCycleRef.current = {
|
|
50
|
+
clientSecretReceivedAtMs: null,
|
|
51
|
+
intentKey: session.intentKey,
|
|
52
|
+
mountedAtMs: null,
|
|
53
|
+
reportedCheckoutSessionId: null,
|
|
54
|
+
requestStartedAtMs: null,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const cycle = walletReadinessCycleRef.current;
|
|
59
|
+
if ((cycle === null || cycle === void 0 ? void 0 : cycle.intentKey) === session.intentKey && cycle.mountedAtMs === null) {
|
|
60
|
+
cycle.mountedAtMs = performance.now();
|
|
61
|
+
}
|
|
62
|
+
}, [session.intentKey]);
|
|
45
63
|
const slotDisabled = disabled || !session.configured;
|
|
46
64
|
const analyticsPaymentMethod = toAnalyticsPaymentMethod(availabilityPaymentMethod);
|
|
47
65
|
const walletAvailable = walletAvailability.intentKey === session.intentKey
|
|
@@ -76,6 +94,25 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availa
|
|
|
76
94
|
intentKey,
|
|
77
95
|
});
|
|
78
96
|
}, []);
|
|
97
|
+
const startWalletPreparationTiming = useCallback((intentKey) => {
|
|
98
|
+
var _a;
|
|
99
|
+
const cycle = walletReadinessCycleRef.current;
|
|
100
|
+
if (!cycle || cycle.intentKey !== intentKey) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const requestStartedAtMs = performance.now();
|
|
104
|
+
(_a = cycle.mountedAtMs) !== null && _a !== void 0 ? _a : (cycle.mountedAtMs = requestStartedAtMs);
|
|
105
|
+
cycle.requestStartedAtMs = requestStartedAtMs;
|
|
106
|
+
cycle.clientSecretReceivedAtMs = null;
|
|
107
|
+
cycle.reportedCheckoutSessionId = null;
|
|
108
|
+
}, []);
|
|
109
|
+
const finishWalletPreparationTiming = useCallback((intentKey, readyClientSecret) => {
|
|
110
|
+
const cycle = walletReadinessCycleRef.current;
|
|
111
|
+
if (!readyClientSecret || !cycle || cycle.intentKey !== intentKey) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
cycle.clientSecretReceivedAtMs = performance.now();
|
|
115
|
+
}, []);
|
|
79
116
|
const autoWalletClientSecret = session.activeClientSecret;
|
|
80
117
|
const autoWalletIntentKey = session.intentKey;
|
|
81
118
|
const autoWalletLoading = session.loading.wallet;
|
|
@@ -93,11 +130,13 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availa
|
|
|
93
130
|
return;
|
|
94
131
|
}
|
|
95
132
|
autoWalletPreparationIntentKeyRef.current = autoWalletIntentKey;
|
|
133
|
+
startWalletPreparationTiming(autoWalletIntentKey);
|
|
96
134
|
void prepareWalletCheckout({
|
|
97
135
|
checkoutStartSource: 'wallet_render',
|
|
98
136
|
paymentMethod: analyticsPaymentMethod,
|
|
99
137
|
})
|
|
100
138
|
.then((readyClientSecret) => {
|
|
139
|
+
finishWalletPreparationTiming(autoWalletIntentKey, readyClientSecret);
|
|
101
140
|
if (!readyClientSecret) {
|
|
102
141
|
reportWalletPreparationFailure(autoWalletIntentKey);
|
|
103
142
|
}
|
|
@@ -108,9 +147,11 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availa
|
|
|
108
147
|
autoWalletIntentKey,
|
|
109
148
|
autoWalletLoading,
|
|
110
149
|
expressCheckoutAllowed,
|
|
150
|
+
finishWalletPreparationTiming,
|
|
111
151
|
prepareWalletCheckout,
|
|
112
152
|
reportWalletPreparationFailure,
|
|
113
153
|
slotDisabled,
|
|
154
|
+
startWalletPreparationTiming,
|
|
114
155
|
suspended,
|
|
115
156
|
walletAvailable,
|
|
116
157
|
]);
|
|
@@ -149,7 +190,33 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availa
|
|
|
149
190
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
150
191
|
};
|
|
151
192
|
const handleAvailabilityChange = (available) => {
|
|
193
|
+
var _a;
|
|
152
194
|
reportWalletAvailability(session.intentKey, available);
|
|
195
|
+
const cycle = walletReadinessCycleRef.current;
|
|
196
|
+
const checkoutSessionId = ((_a = session.checkoutSessionId) === null || _a === void 0 ? void 0 : _a.trim()) || '';
|
|
197
|
+
if (!available
|
|
198
|
+
|| !checkoutAnalytics
|
|
199
|
+
|| !checkoutSessionId
|
|
200
|
+
|| !cycle
|
|
201
|
+
|| cycle.intentKey !== session.intentKey
|
|
202
|
+
|| cycle.mountedAtMs === null
|
|
203
|
+
|| cycle.requestStartedAtMs === null
|
|
204
|
+
|| cycle.clientSecretReceivedAtMs === null
|
|
205
|
+
|| cycle.reportedCheckoutSessionId === checkoutSessionId) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const readyAtMs = performance.now();
|
|
209
|
+
cycle.reportedCheckoutSessionId = checkoutSessionId;
|
|
210
|
+
trackCheckoutWalletReady({
|
|
211
|
+
analytics: checkoutAnalytics,
|
|
212
|
+
checkoutSessionId,
|
|
213
|
+
paymentMethod: availabilityPaymentMethod,
|
|
214
|
+
provider: 'stripe',
|
|
215
|
+
walletClientSecretToReadyMs: Math.max(0, readyAtMs - cycle.clientSecretReceivedAtMs),
|
|
216
|
+
walletMountToReadyMs: Math.max(0, readyAtMs - cycle.mountedAtMs),
|
|
217
|
+
walletMountToRequestMs: Math.max(0, cycle.requestStartedAtMs - cycle.mountedAtMs),
|
|
218
|
+
walletRequestMs: Math.max(0, cycle.clientSecretReceivedAtMs - cycle.requestStartedAtMs),
|
|
219
|
+
});
|
|
153
220
|
};
|
|
154
221
|
const handlePlaceholderClick = async () => {
|
|
155
222
|
if (slotDisabled || session.loading.wallet) {
|
|
@@ -160,10 +227,12 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availa
|
|
|
160
227
|
return;
|
|
161
228
|
}
|
|
162
229
|
setWalletCheckoutStartedAfterClickIntentKey(session.intentKey);
|
|
230
|
+
startWalletPreparationTiming(session.intentKey);
|
|
163
231
|
const readyClientSecret = await session.prepareWalletCheckout({
|
|
164
232
|
checkoutStartSource: 'wallet_click',
|
|
165
233
|
paymentMethod: analyticsPaymentMethod,
|
|
166
234
|
});
|
|
235
|
+
finishWalletPreparationTiming(session.intentKey, readyClientSecret);
|
|
167
236
|
if (!readyClientSecret) {
|
|
168
237
|
setWalletCheckoutStartedAfterClickIntentKey(null);
|
|
169
238
|
reportWalletPreparationFailure(session.intentKey);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
export type StripeCheckoutAttempt = {
|
|
2
2
|
key: string;
|
|
3
3
|
id: string;
|
|
4
|
+
createdAtMs: number;
|
|
4
5
|
};
|
|
6
|
+
export declare const STRIPE_CHECKOUT_ATTEMPT_RETRY_WINDOW_MS: number;
|
|
5
7
|
export declare const resolveStripeCheckoutAttempt: (input: {
|
|
6
8
|
current: StripeCheckoutAttempt | null;
|
|
7
9
|
forceNew: boolean;
|
|
8
10
|
intentKey: string;
|
|
9
11
|
paymentsApiVersion?: "v1" | "v2" | null;
|
|
10
12
|
createId: () => string;
|
|
13
|
+
nowMs?: number;
|
|
11
14
|
}) => StripeCheckoutAttempt | null;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
export const STRIPE_CHECKOUT_ATTEMPT_RETRY_WINDOW_MS = 20 * 60 * 1000;
|
|
1
2
|
export const resolveStripeCheckoutAttempt = (input) => {
|
|
2
|
-
var _a;
|
|
3
|
+
var _a, _b;
|
|
3
4
|
if (input.paymentsApiVersion !== 'v2') {
|
|
4
5
|
return null;
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
+
const nowMs = (_a = input.nowMs) !== null && _a !== void 0 ? _a : Date.now();
|
|
8
|
+
if (!input.forceNew
|
|
9
|
+
&& ((_b = input.current) === null || _b === void 0 ? void 0 : _b.key) === input.intentKey
|
|
10
|
+
&& nowMs - input.current.createdAtMs <= STRIPE_CHECKOUT_ATTEMPT_RETRY_WINDOW_MS) {
|
|
7
11
|
return input.current;
|
|
8
12
|
}
|
|
9
|
-
return { key: input.intentKey, id: input.createId() };
|
|
13
|
+
return { key: input.intentKey, id: input.createId(), createdAtMs: nowMs };
|
|
10
14
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type CheckoutIdentityStatus } from '@funnelsgrove/runtime';
|
|
2
|
+
export declare const isStripeCheckoutIdentityReady: (input: {
|
|
3
|
+
runtimeConfig?: {
|
|
4
|
+
paymentsApiVersion?: "v1" | "v2" | null;
|
|
5
|
+
} | null;
|
|
6
|
+
userId?: string | null;
|
|
7
|
+
}, getIdentityStatus?: (userId: string | null | undefined) => CheckoutIdentityStatus) => boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { getCheckoutIdentityStatus, } from '@funnelsgrove/runtime';
|
|
2
|
+
export const isStripeCheckoutIdentityReady = (input, getIdentityStatus = getCheckoutIdentityStatus) => {
|
|
3
|
+
var _a;
|
|
4
|
+
return ((_a = input.runtimeConfig) === null || _a === void 0 ? void 0 : _a.paymentsApiVersion) !== 'v2'
|
|
5
|
+
|| getIdentityStatus(input.userId) !== 'pending';
|
|
6
|
+
};
|
|
@@ -2,6 +2,7 @@ import type { Stripe } from '@stripe/stripe-js';
|
|
|
2
2
|
import type { RuntimeMode } from '@funnelsgrove/runtime';
|
|
3
3
|
import { type CheckoutPreparationLoading, type CheckoutPreparationSource } from '../../paymentProvider.types.js';
|
|
4
4
|
import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '../services/stripe.service.js';
|
|
5
|
+
export { isStripeCheckoutIdentityReady as isStripeOneTimeCheckoutIdentityReady, } from './checkoutIdentity.js';
|
|
5
6
|
type StripeOneTimeCheckoutPlanInput = Pick<PaywallPlan, 'amountCents' | 'analyticsPurchaseValue' | 'description' | 'id' | 'providerPlanId' | 'title' | 'funnelPlanKey' | 'offerSetId' | 'offerSetKey'>;
|
|
6
7
|
export type StripeOneTimeCheckoutSessionInput = {
|
|
7
8
|
runtimeConfigRevisionId?: string | null;
|
|
@@ -49,4 +50,3 @@ export type StripeOneTimeCheckoutIntentKeyInput = Pick<StripeOneTimeCheckoutSess
|
|
|
49
50
|
export declare function buildStripeOneTimeCheckoutIntentKey({ runtimeConfigRevisionId, paymentProfileId, provider, checkoutMode, couponId, customerEmail, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }: StripeOneTimeCheckoutIntentKeyInput): string;
|
|
50
51
|
export declare function shouldResetStripeOneTimeCheckoutSessionForIntentKey(previousIntentKey: string | null, nextIntentKey: string): boolean;
|
|
51
52
|
export declare function useStripeOneTimeCheckoutSession({ runtimeConfigRevisionId, paymentProfileId, provider, analyticsMetadata, checkoutMode, couponId, customerEmail, enabled, onError, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }: StripeOneTimeCheckoutSessionInput): StripeOneTimeCheckoutSession;
|
|
52
|
-
export {};
|
|
@@ -16,6 +16,8 @@ import { createStripeOneTimeCheckout, getStripePromise, isStripeConfigured, } fr
|
|
|
16
16
|
import { isInactiveCheckoutSessionError } from './useStripeSubscriptionCheckoutSession.js';
|
|
17
17
|
import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
|
|
18
18
|
import { resolveStripeCheckoutAttempt, } from './checkoutAttempt.js';
|
|
19
|
+
import { isStripeCheckoutIdentityReady } from './checkoutIdentity.js';
|
|
20
|
+
export { isStripeCheckoutIdentityReady as isStripeOneTimeCheckoutIdentityReady, } from './checkoutIdentity.js';
|
|
19
21
|
export function resolveStripeOneTimeCheckoutPreparationOptions(source, options = {}) {
|
|
20
22
|
var _a, _b;
|
|
21
23
|
const checkoutStartSource = (_a = options.checkoutStartSource) !== null && _a !== void 0 ? _a : (source === 'wallet' ? 'wallet_render' : 'card_click');
|
|
@@ -85,7 +87,12 @@ export function useStripeOneTimeCheckoutSession({ runtimeConfigRevisionId, payme
|
|
|
85
87
|
const requestIdRef = useRef(0);
|
|
86
88
|
const attemptRef = useRef(null);
|
|
87
89
|
const anonymousUserIdRef = useRef(null);
|
|
90
|
+
const checkoutIdentityReady = isStripeCheckoutIdentityReady({
|
|
91
|
+
runtimeConfig,
|
|
92
|
+
userId,
|
|
93
|
+
});
|
|
88
94
|
const configured = enabled &&
|
|
95
|
+
checkoutIdentityReady &&
|
|
89
96
|
(isStripeConfigured(checkoutMode) ||
|
|
90
97
|
Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)) ||
|
|
91
98
|
Boolean(normalizeRuntimeConfigValue(stripePublishableKey)));
|
|
@@ -4,6 +4,7 @@ import { type CheckoutPreparationLoading, type CheckoutPreparationSource } from
|
|
|
4
4
|
import type { PaywallDisplayPlan } from '../../../services/paywallOffer.service.js';
|
|
5
5
|
import { type PaywallPlan, type StripeRuntimeConfigOverrides } from '../services/stripe.service.js';
|
|
6
6
|
import { type CheckoutObservabilityAnalyticsContext } from '../../../services/checkoutObservability.service.js';
|
|
7
|
+
export { isStripeCheckoutIdentityReady as isStripeSubscriptionCheckoutIdentityReady, } from './checkoutIdentity.js';
|
|
7
8
|
export type StripeSubscriptionCheckoutSessionInput = {
|
|
8
9
|
analyticsMetadata?: Record<string, unknown> | null;
|
|
9
10
|
checkoutAnalytics?: CheckoutObservabilityAnalyticsContext | null;
|
|
@@ -16,6 +16,8 @@ import { createStripeSubscriptionCheckout, getStripePromise, isStripeConfigured,
|
|
|
16
16
|
import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
|
|
17
17
|
import { resolveCheckoutObservabilityAnalyticsContext, trackCheckoutFailureShown, } from '../../../services/checkoutObservability.service.js';
|
|
18
18
|
import { resolveStripeCheckoutAttempt, } from './checkoutAttempt.js';
|
|
19
|
+
import { isStripeCheckoutIdentityReady } from './checkoutIdentity.js';
|
|
20
|
+
export { isStripeCheckoutIdentityReady as isStripeSubscriptionCheckoutIdentityReady, } from './checkoutIdentity.js';
|
|
19
21
|
export function resolveStripeSubscriptionCheckoutPreparationOptions(source, options = {}) {
|
|
20
22
|
var _a, _b;
|
|
21
23
|
const checkoutStartSource = (_a = options.checkoutStartSource) !== null && _a !== void 0 ? _a : (source === 'wallet' ? 'wallet_render' : 'card_click');
|
|
@@ -90,7 +92,12 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
90
92
|
const recoveredIntentKeyRef = useRef(null);
|
|
91
93
|
const handledRecoveryRequestRef = useRef(0);
|
|
92
94
|
const anonymousUserIdRef = useRef(null);
|
|
95
|
+
const checkoutIdentityReady = isStripeCheckoutIdentityReady({
|
|
96
|
+
runtimeConfig,
|
|
97
|
+
userId,
|
|
98
|
+
});
|
|
93
99
|
const configured = enabled &&
|
|
100
|
+
checkoutIdentityReady &&
|
|
94
101
|
(isStripeConfigured(checkoutMode) ||
|
|
95
102
|
Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)) ||
|
|
96
103
|
Boolean(normalizeRuntimeConfigValue(stripePublishableKey)));
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { CreateOneTimeCheckoutInput, CreateSubscriptionCheckoutInput, UpdateSubscriptionCheckoutPlanInput, VerifySubscriptionCheckoutPaymentInput } from './types.js';
|
|
2
2
|
export declare const toOneTimeCheckoutRequest: (input: CreateOneTimeCheckoutInput) => {
|
|
3
|
+
environment: import("@funnelsgrove/runtime").RuntimeMode | undefined;
|
|
4
|
+
runtimeConfig: import("@funnelsgrove/runtime").FunnelSdkRuntimeConfigOverrides | undefined;
|
|
5
|
+
checkoutIdentityToken: string;
|
|
3
6
|
planKey: string;
|
|
4
7
|
runtimeConfigRevisionId: string | null | undefined;
|
|
5
8
|
paymentProfileId: string | null | undefined;
|
|
@@ -18,10 +21,33 @@ export declare const toOneTimeCheckoutRequest: (input: CreateOneTimeCheckoutInpu
|
|
|
18
21
|
customerEmail: string | undefined;
|
|
19
22
|
returnUrl: string;
|
|
20
23
|
userId: string | undefined;
|
|
24
|
+
} | {
|
|
21
25
|
environment: import("@funnelsgrove/runtime").RuntimeMode | undefined;
|
|
22
26
|
runtimeConfig: import("@funnelsgrove/runtime").FunnelSdkRuntimeConfigOverrides | undefined;
|
|
27
|
+
checkoutIdentityToken?: undefined;
|
|
28
|
+
planKey: string;
|
|
29
|
+
runtimeConfigRevisionId: string | null | undefined;
|
|
30
|
+
paymentProfileId: string | null | undefined;
|
|
31
|
+
provider: "stripe" | null | undefined;
|
|
32
|
+
anonymousUserId: string | null | undefined;
|
|
33
|
+
idempotencyKey: string | null | undefined;
|
|
34
|
+
offerSetId: string | undefined;
|
|
35
|
+
offerSetKey: string | undefined;
|
|
36
|
+
planId: string;
|
|
37
|
+
providerPlanId: string | undefined;
|
|
38
|
+
title: string;
|
|
39
|
+
description: string | undefined;
|
|
40
|
+
amountCents: number;
|
|
41
|
+
couponId: string | undefined;
|
|
42
|
+
analyticsMetadata: Record<string, unknown> | undefined;
|
|
43
|
+
customerEmail: string | undefined;
|
|
44
|
+
returnUrl: string;
|
|
45
|
+
userId: string | undefined;
|
|
23
46
|
};
|
|
24
47
|
export declare const toSubscriptionCheckoutRequest: (input: CreateSubscriptionCheckoutInput) => {
|
|
48
|
+
environment: import("@funnelsgrove/runtime").RuntimeMode | undefined;
|
|
49
|
+
runtimeConfig: import("@funnelsgrove/runtime").FunnelSdkRuntimeConfigOverrides | undefined;
|
|
50
|
+
checkoutIdentityToken: string;
|
|
25
51
|
offerSetId: string | undefined;
|
|
26
52
|
offerSetKey: string | undefined;
|
|
27
53
|
planId: string;
|
|
@@ -47,8 +73,35 @@ export declare const toSubscriptionCheckoutRequest: (input: CreateSubscriptionCh
|
|
|
47
73
|
customerEmail: string | undefined;
|
|
48
74
|
returnUrl: string;
|
|
49
75
|
userId: string | undefined;
|
|
76
|
+
} | {
|
|
50
77
|
environment: import("@funnelsgrove/runtime").RuntimeMode | undefined;
|
|
51
78
|
runtimeConfig: import("@funnelsgrove/runtime").FunnelSdkRuntimeConfigOverrides | undefined;
|
|
79
|
+
checkoutIdentityToken?: undefined;
|
|
80
|
+
offerSetId: string | undefined;
|
|
81
|
+
offerSetKey: string | undefined;
|
|
82
|
+
planId: string;
|
|
83
|
+
planKey: string;
|
|
84
|
+
providerPlanId: string | undefined;
|
|
85
|
+
provider: "stripe" | null | undefined;
|
|
86
|
+
paymentProfileId: string | undefined;
|
|
87
|
+
runtimeConfigRevisionId: string | undefined;
|
|
88
|
+
anonymousUserId: string | undefined;
|
|
89
|
+
idempotencyKey: string | undefined;
|
|
90
|
+
title: string;
|
|
91
|
+
description: string | undefined;
|
|
92
|
+
amountCents: number;
|
|
93
|
+
billingInterval: import("../../../../index.js").BillingPlanInterval;
|
|
94
|
+
billingIntervalCount: number;
|
|
95
|
+
followUpProviderPlanId: string | undefined;
|
|
96
|
+
followUpPlanTitle: string | undefined;
|
|
97
|
+
followUpBillingInterval: import("../../../../index.js").BillingPlanInterval | undefined;
|
|
98
|
+
followUpBillingIntervalCount: number | undefined;
|
|
99
|
+
introIterations: number | undefined;
|
|
100
|
+
couponId: string | undefined;
|
|
101
|
+
analyticsMetadata: Record<string, unknown> | undefined;
|
|
102
|
+
customerEmail: string | undefined;
|
|
103
|
+
returnUrl: string;
|
|
104
|
+
userId: string | undefined;
|
|
52
105
|
};
|
|
53
106
|
export declare const toSubscriptionCheckoutPlanRequest: (input: UpdateSubscriptionCheckoutPlanInput) => {
|
|
54
107
|
checkoutSessionId: string;
|
|
@@ -1,63 +1,20 @@
|
|
|
1
1
|
import { getPaywallPlanRequestId } from '../../../../services/paywallPlans/selection.js';
|
|
2
2
|
import { normalizeCheckoutAnalyticsMetadata } from '../shared/checkoutMetadata.js';
|
|
3
3
|
import { requireCheckoutRecurringConfig, requireCheckoutSessionId, } from '../shared/checkout.validator.js';
|
|
4
|
+
import { getCheckoutIdentityToken } from '@funnelsgrove/runtime';
|
|
5
|
+
const toCheckoutIdentityRequestFields = (userId) => {
|
|
6
|
+
const canonicalUserId = userId === null || userId === void 0 ? void 0 : userId.trim();
|
|
7
|
+
const checkoutIdentityToken = getCheckoutIdentityToken(canonicalUserId);
|
|
8
|
+
return checkoutIdentityToken ? { checkoutIdentityToken } : {};
|
|
9
|
+
};
|
|
4
10
|
export const toOneTimeCheckoutRequest = (input) => {
|
|
5
11
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
6
|
-
return {
|
|
7
|
-
planKey: ((_a = input.plan.funnelPlanKey) === null || _a === void 0 ? void 0 : _a.trim()) || input.plan.id,
|
|
8
|
-
runtimeConfigRevisionId: input.runtimeConfigRevisionId,
|
|
9
|
-
paymentProfileId: input.paymentProfileId,
|
|
10
|
-
provider: input.provider,
|
|
11
|
-
anonymousUserId: input.anonymousUserId,
|
|
12
|
-
idempotencyKey: input.idempotencyKey,
|
|
13
|
-
offerSetId: ((_b = input.plan.offerSetId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
14
|
-
offerSetKey: ((_c = input.plan.offerSetKey) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
15
|
-
planId: getPaywallPlanRequestId(input.plan),
|
|
16
|
-
providerPlanId: ((_d = input.plan.providerPlanId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
17
|
-
title: input.plan.title,
|
|
18
|
-
description: ((_e = input.plan.description) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
19
|
-
amountCents: input.plan.amountCents,
|
|
20
|
-
couponId: ((_f = input.couponId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
|
|
21
|
-
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
22
|
-
customerEmail: ((_g = input.customerEmail) === null || _g === void 0 ? void 0 : _g.trim()) || undefined,
|
|
23
|
-
returnUrl: input.returnUrl,
|
|
24
|
-
userId: ((_h = input.user_id) === null || _h === void 0 ? void 0 : _h.trim()) || undefined,
|
|
25
|
-
environment: input.environment,
|
|
26
|
-
runtimeConfig: input.runtimeConfig,
|
|
27
|
-
};
|
|
12
|
+
return Object.assign(Object.assign({ planKey: ((_a = input.plan.funnelPlanKey) === null || _a === void 0 ? void 0 : _a.trim()) || input.plan.id, runtimeConfigRevisionId: input.runtimeConfigRevisionId, paymentProfileId: input.paymentProfileId, provider: input.provider, anonymousUserId: input.anonymousUserId, idempotencyKey: input.idempotencyKey, offerSetId: ((_b = input.plan.offerSetId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, offerSetKey: ((_c = input.plan.offerSetKey) === null || _c === void 0 ? void 0 : _c.trim()) || undefined, planId: getPaywallPlanRequestId(input.plan), providerPlanId: ((_d = input.plan.providerPlanId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined, title: input.plan.title, description: ((_e = input.plan.description) === null || _e === void 0 ? void 0 : _e.trim()) || undefined, amountCents: input.plan.amountCents, couponId: ((_f = input.couponId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined, analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan), customerEmail: ((_g = input.customerEmail) === null || _g === void 0 ? void 0 : _g.trim()) || undefined, returnUrl: input.returnUrl, userId: ((_h = input.user_id) === null || _h === void 0 ? void 0 : _h.trim()) || undefined }, toCheckoutIdentityRequestFields(input.user_id)), { environment: input.environment, runtimeConfig: input.runtimeConfig });
|
|
28
13
|
};
|
|
29
14
|
export const toSubscriptionCheckoutRequest = (input) => {
|
|
30
15
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
31
16
|
const recurring = requireCheckoutRecurringConfig(input.plan);
|
|
32
|
-
return {
|
|
33
|
-
offerSetId: ((_a = input.plan.offerSetId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
|
|
34
|
-
offerSetKey: ((_b = input.plan.offerSetKey) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
35
|
-
planId: getPaywallPlanRequestId(input.plan),
|
|
36
|
-
planKey: ((_c = input.plan.funnelPlanKey) === null || _c === void 0 ? void 0 : _c.trim()) || input.plan.id,
|
|
37
|
-
providerPlanId: ((_d = input.plan.providerPlanId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
38
|
-
provider: input.provider,
|
|
39
|
-
paymentProfileId: ((_e = input.paymentProfileId) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
40
|
-
runtimeConfigRevisionId: ((_f = input.runtimeConfigRevisionId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
|
|
41
|
-
anonymousUserId: ((_g = input.anonymousUserId) === null || _g === void 0 ? void 0 : _g.trim()) || undefined,
|
|
42
|
-
idempotencyKey: ((_h = input.idempotencyKey) === null || _h === void 0 ? void 0 : _h.trim()) || undefined,
|
|
43
|
-
title: input.plan.title,
|
|
44
|
-
description: ((_j = input.plan.description) === null || _j === void 0 ? void 0 : _j.trim()) || undefined,
|
|
45
|
-
amountCents: input.plan.amountCents,
|
|
46
|
-
billingInterval: recurring.interval,
|
|
47
|
-
billingIntervalCount: recurring.intervalCount,
|
|
48
|
-
followUpProviderPlanId: ((_k = input.plan.followUpProviderPlanId) === null || _k === void 0 ? void 0 : _k.trim()) || undefined,
|
|
49
|
-
followUpPlanTitle: ((_l = input.plan.followUpPlanTitle) === null || _l === void 0 ? void 0 : _l.trim()) || undefined,
|
|
50
|
-
followUpBillingInterval: input.plan.followUpBillingInterval,
|
|
51
|
-
followUpBillingIntervalCount: input.plan.followUpBillingIntervalCount,
|
|
52
|
-
introIterations: input.plan.introIterations,
|
|
53
|
-
couponId: ((_m = input.couponId) === null || _m === void 0 ? void 0 : _m.trim()) || undefined,
|
|
54
|
-
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
55
|
-
customerEmail: ((_o = input.customerEmail) === null || _o === void 0 ? void 0 : _o.trim()) || undefined,
|
|
56
|
-
returnUrl: input.returnUrl,
|
|
57
|
-
userId: ((_p = input.user_id) === null || _p === void 0 ? void 0 : _p.trim()) || undefined,
|
|
58
|
-
environment: input.environment,
|
|
59
|
-
runtimeConfig: input.runtimeConfig,
|
|
60
|
-
};
|
|
17
|
+
return Object.assign(Object.assign({ offerSetId: ((_a = input.plan.offerSetId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined, offerSetKey: ((_b = input.plan.offerSetKey) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, planId: getPaywallPlanRequestId(input.plan), planKey: ((_c = input.plan.funnelPlanKey) === null || _c === void 0 ? void 0 : _c.trim()) || input.plan.id, providerPlanId: ((_d = input.plan.providerPlanId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined, provider: input.provider, paymentProfileId: ((_e = input.paymentProfileId) === null || _e === void 0 ? void 0 : _e.trim()) || undefined, runtimeConfigRevisionId: ((_f = input.runtimeConfigRevisionId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined, anonymousUserId: ((_g = input.anonymousUserId) === null || _g === void 0 ? void 0 : _g.trim()) || undefined, idempotencyKey: ((_h = input.idempotencyKey) === null || _h === void 0 ? void 0 : _h.trim()) || undefined, title: input.plan.title, description: ((_j = input.plan.description) === null || _j === void 0 ? void 0 : _j.trim()) || undefined, amountCents: input.plan.amountCents, billingInterval: recurring.interval, billingIntervalCount: recurring.intervalCount, followUpProviderPlanId: ((_k = input.plan.followUpProviderPlanId) === null || _k === void 0 ? void 0 : _k.trim()) || undefined, followUpPlanTitle: ((_l = input.plan.followUpPlanTitle) === null || _l === void 0 ? void 0 : _l.trim()) || undefined, followUpBillingInterval: input.plan.followUpBillingInterval, followUpBillingIntervalCount: input.plan.followUpBillingIntervalCount, introIterations: input.plan.introIterations, couponId: ((_m = input.couponId) === null || _m === void 0 ? void 0 : _m.trim()) || undefined, analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan), customerEmail: ((_o = input.customerEmail) === null || _o === void 0 ? void 0 : _o.trim()) || undefined, returnUrl: input.returnUrl, userId: ((_p = input.user_id) === null || _p === void 0 ? void 0 : _p.trim()) || undefined }, toCheckoutIdentityRequestFields(input.user_id)), { environment: input.environment, runtimeConfig: input.runtimeConfig });
|
|
61
18
|
};
|
|
62
19
|
export const toSubscriptionCheckoutPlanRequest = (input) => {
|
|
63
20
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
@@ -34,4 +34,15 @@ export type CheckoutFailureClassificationInput = Pick<CheckoutFailureShownInput,
|
|
|
34
34
|
export declare const classifyCheckoutFailure: (input: CheckoutFailureClassificationInput) => CheckoutFailureCategory;
|
|
35
35
|
export declare const trackCheckoutFailureShown: (input: CheckoutFailureShownInput) => string | null;
|
|
36
36
|
export declare const trackCheckoutCanceled: (input: CheckoutObservabilityInput) => string | null;
|
|
37
|
+
export type CheckoutWalletReadyInput = {
|
|
38
|
+
analytics: CheckoutObservabilityAnalyticsContext;
|
|
39
|
+
checkoutSessionId: string;
|
|
40
|
+
paymentMethod: unknown;
|
|
41
|
+
provider: 'stripe';
|
|
42
|
+
walletClientSecretToReadyMs: number;
|
|
43
|
+
walletMountToReadyMs: number;
|
|
44
|
+
walletMountToRequestMs: number;
|
|
45
|
+
walletRequestMs: number;
|
|
46
|
+
};
|
|
47
|
+
export declare const trackCheckoutWalletReady: (input: CheckoutWalletReadyInput) => string | null;
|
|
37
48
|
export {};
|
|
@@ -103,6 +103,10 @@ const reportCheckoutObservability = (input) => {
|
|
|
103
103
|
providerDeclineCode: input.providerDeclineCode,
|
|
104
104
|
providerErrorCode: input.providerErrorCode,
|
|
105
105
|
providerErrorType: input.providerErrorType,
|
|
106
|
+
walletClientSecretToReadyMs: input.walletClientSecretToReadyMs,
|
|
107
|
+
walletMountToReadyMs: input.walletMountToReadyMs,
|
|
108
|
+
walletMountToRequestMs: input.walletMountToRequestMs,
|
|
109
|
+
walletRequestMs: input.walletRequestMs,
|
|
106
110
|
}),
|
|
107
111
|
keepalive: true,
|
|
108
112
|
}).then(() => undefined);
|
|
@@ -184,3 +188,49 @@ export const trackCheckoutFailureShown = (input) => {
|
|
|
184
188
|
});
|
|
185
189
|
};
|
|
186
190
|
export const trackCheckoutCanceled = (input) => emitCheckoutObservability('checkout_canceled', input);
|
|
191
|
+
const normalizeWalletTiming = (value) => (Number.isFinite(value) && value >= 0 && value <= 300000 ? value : null);
|
|
192
|
+
export const trackCheckoutWalletReady = (input) => {
|
|
193
|
+
var _a;
|
|
194
|
+
const checkoutSessionId = input.checkoutSessionId.trim();
|
|
195
|
+
const paymentMethod = toAnalyticsPaymentMethod(input.paymentMethod);
|
|
196
|
+
const walletClientSecretToReadyMs = normalizeWalletTiming(input.walletClientSecretToReadyMs);
|
|
197
|
+
const walletMountToReadyMs = normalizeWalletTiming(input.walletMountToReadyMs);
|
|
198
|
+
const walletMountToRequestMs = normalizeWalletTiming(input.walletMountToRequestMs);
|
|
199
|
+
const walletRequestMs = normalizeWalletTiming(input.walletRequestMs);
|
|
200
|
+
if (!checkoutSessionId
|
|
201
|
+
|| !paymentMethod
|
|
202
|
+
|| walletClientSecretToReadyMs === null
|
|
203
|
+
|| walletMountToReadyMs === null
|
|
204
|
+
|| walletMountToRequestMs === null
|
|
205
|
+
|| walletRequestMs === null) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const eventId = publicAnalyticsSdk.track({
|
|
209
|
+
environment: input.analytics.environment,
|
|
210
|
+
eventId: `wallet-ready:${checkoutSessionId}:${paymentMethod}`,
|
|
211
|
+
eventType: 'checkout_wallet_ready',
|
|
212
|
+
featureFlags: input.analytics.featureFlags,
|
|
213
|
+
metadata: Object.assign(Object.assign({}, ((_a = input.analytics.metadata) !== null && _a !== void 0 ? _a : {})), { checkout_session_id: checkoutSessionId, payment_method: paymentMethod, payment_provider: input.provider, wallet_client_secret_to_ready_ms: walletClientSecretToReadyMs, wallet_mount_to_ready_ms: walletMountToReadyMs, wallet_mount_to_request_ms: walletMountToRequestMs, wallet_checkout_request_ms: walletRequestMs }),
|
|
214
|
+
stepContractVersion: input.analytics.stepContractVersion,
|
|
215
|
+
stepId: input.analytics.stepId,
|
|
216
|
+
stepName: input.analytics.stepName,
|
|
217
|
+
stepType: input.analytics.stepType,
|
|
218
|
+
});
|
|
219
|
+
if (!eventId) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
void reportCheckoutObservability({
|
|
223
|
+
analytics: input.analytics,
|
|
224
|
+
checkoutSessionId,
|
|
225
|
+
eventId,
|
|
226
|
+
eventType: 'checkout_wallet_ready',
|
|
227
|
+
paymentMethod,
|
|
228
|
+
provider: input.provider,
|
|
229
|
+
walletClientSecretToReadyMs,
|
|
230
|
+
walletMountToReadyMs,
|
|
231
|
+
walletMountToRequestMs,
|
|
232
|
+
walletRequestMs,
|
|
233
|
+
}).catch(() => undefined);
|
|
234
|
+
void publicAnalyticsSdk.flush().catch(() => 0);
|
|
235
|
+
return eventId;
|
|
236
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnelsgrove/payments",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.18",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@funnelsgrove/analytics": "^0.1.86",
|
|
36
|
-
"@funnelsgrove/runtime": "^0.11.
|
|
36
|
+
"@funnelsgrove/runtime": "^0.11.5",
|
|
37
37
|
"@solidgate/react-sdk": "1.34.0",
|
|
38
38
|
"@stripe/react-stripe-js": "^5.6.0",
|
|
39
39
|
"@stripe/stripe-js": "^8.7.0",
|