@funnelsgrove/payments 0.11.15 → 0.11.16
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/SharedStripeCheckoutV2Dialog.js +1 -1
- package/dist/providers/stripe/components/StripeCheckoutExpressCheckoutButton.d.ts +6 -1
- package/dist/providers/stripe/components/StripeCheckoutExpressCheckoutButton.js +43 -5
- package/dist/providers/stripe/hooks/useStripeSubscriptionCheckoutSession.d.ts +1 -0
- package/dist/providers/stripe/hooks/useStripeSubscriptionCheckoutSession.js +32 -5
- package/dist/services/checkoutObservability.service.d.ts +3 -0
- package/dist/services/checkoutObservability.service.js +37 -5
- package/package.json +1 -1
|
@@ -319,7 +319,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
319
319
|
effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
|
|
320
320
|
]
|
|
321
321
|
.filter(Boolean)
|
|
322
|
-
.join(' '), children: [_jsxs("p", { className: 'shared-checkout-v2-secure-pill', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] }), _jsxs("div", { className: 'shared-checkout-v2-wallet-shell', "aria-label": walletAriaLabel, children: [_jsx(StripeCheckoutExpressCheckoutButton, { amountCents: amountCents, availabilityPaymentMethods: walletPaymentMethods, beforeConfirm: ensureCustomerEmail, checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, className: 'shared-checkout-v2-express-buttons', confirmEmail: false, customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: (message) => setSharedError(message, true), onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: trackCheckoutSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel, supportedCountries: normalizedSupportedCountries, unsupportedCountryMessage: unsupportedCountryMessage }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
|
|
322
|
+
.join(' '), children: [_jsxs("p", { className: 'shared-checkout-v2-secure-pill', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] }), _jsxs("div", { className: 'shared-checkout-v2-wallet-shell', "aria-label": walletAriaLabel, children: [_jsx(StripeCheckoutExpressCheckoutButton, { amountCents: amountCents, availabilityPaymentMethods: walletPaymentMethods, beforeConfirm: ensureCustomerEmail, checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, className: 'shared-checkout-v2-express-buttons', confirmEmail: false, customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: (message) => setSharedError(message, true), onPaymentInfoSubmitted: onPaymentInfoSubmitted, onPaymentRejected: () => setSelectedMethod('card'), onSuccess: trackCheckoutSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel, supportedCountries: normalizedSupportedCountries, unsupportedCountryMessage: unsupportedCountryMessage }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
|
|
323
323
|
'shared-checkout-v2-card-panel',
|
|
324
324
|
effectiveSelectedMethod === 'card' ? 'is-visible' : '',
|
|
325
325
|
]
|
|
@@ -22,7 +22,12 @@ export type StripeCheckoutExpressCheckoutButtonProps = {
|
|
|
22
22
|
onCancel?: () => void;
|
|
23
23
|
onError?: (message: string | null) => void;
|
|
24
24
|
onPaymentInfoSubmitted?: () => void | Promise<void>;
|
|
25
|
+
onPaymentRejected?: (input: {
|
|
26
|
+
declineCode?: string;
|
|
27
|
+
message: string;
|
|
28
|
+
paymentMethod?: string;
|
|
29
|
+
}) => void;
|
|
25
30
|
onSuccess?: () => void | Promise<void>;
|
|
26
31
|
unsupportedCountryMessage?: string;
|
|
27
32
|
};
|
|
28
|
-
export declare function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail, customerEmail, className, options, availabilityPaymentMethods, initialAvailable, keepInitialAvailableOnReady, serverUpdateKey, supportedCountries, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, unsupportedCountryMessage, }: StripeCheckoutExpressCheckoutButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export declare function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail, customerEmail, className, options, availabilityPaymentMethods, initialAvailable, keepInitialAvailableOnReady, serverUpdateKey, supportedCountries, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onPaymentRejected, onSuccess, unsupportedCountryMessage, }: StripeCheckoutExpressCheckoutButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,7 +4,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
4
4
|
import { ExpressCheckoutElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
|
|
5
5
|
import { queueStripeSubscriptionCheckoutStarted, trackPaidStripeSubscriptionCheckoutCompleted, trackStripeSubscriptionPaymentInfoSubmitted, } from '../services/checkoutCompletionAnalytics.service.js';
|
|
6
6
|
import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
|
|
7
|
-
import { trackCheckoutCanceled, trackCheckoutFailureShown, } from '../../../services/checkoutObservability.service.js';
|
|
7
|
+
import { classifyCheckoutFailure, trackCheckoutCanceled, trackCheckoutFailureShown, } from '../../../services/checkoutObservability.service.js';
|
|
8
|
+
import { toAnalyticsPaymentMethod } from '../../../services/paymentMethodAnalytics.service.js';
|
|
8
9
|
const ExpressCheckoutElementWithCancel = ExpressCheckoutElement;
|
|
9
10
|
const buildDefaultOptions = () => ({
|
|
10
11
|
buttonHeight: 55,
|
|
@@ -29,7 +30,28 @@ const buildDefaultOptions = () => ({
|
|
|
29
30
|
paypal: 'never',
|
|
30
31
|
},
|
|
31
32
|
});
|
|
32
|
-
|
|
33
|
+
const normalizeStripeCheckoutProviderError = (error) => {
|
|
34
|
+
if (!error || typeof error !== 'object') {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
const record = error;
|
|
38
|
+
const paymentFailed = record.paymentFailed && typeof record.paymentFailed === 'object'
|
|
39
|
+
? record.paymentFailed
|
|
40
|
+
: null;
|
|
41
|
+
return {
|
|
42
|
+
code: typeof record.code === 'string' ? record.code : undefined,
|
|
43
|
+
decline_code: typeof record.decline_code === 'string' ? record.decline_code : undefined,
|
|
44
|
+
paymentFailed: paymentFailed
|
|
45
|
+
? {
|
|
46
|
+
declineCode: typeof paymentFailed.declineCode === 'string'
|
|
47
|
+
? paymentFailed.declineCode
|
|
48
|
+
: undefined,
|
|
49
|
+
}
|
|
50
|
+
: undefined,
|
|
51
|
+
type: typeof record.type === 'string' ? record.type : undefined,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail = true, customerEmail, className, options, availabilityPaymentMethods = ['applePay'], initialAvailable, keepInitialAvailableOnReady = false, serverUpdateKey, supportedCountries, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onPaymentRejected, onSuccess, unsupportedCountryMessage, }) {
|
|
33
55
|
const checkoutState = useCheckout();
|
|
34
56
|
const appliedServerUpdateKeyRef = useRef('');
|
|
35
57
|
const [appliedServerUpdateKey, setAppliedServerUpdateKey] = useState('');
|
|
@@ -143,6 +165,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
143
165
|
paymentMethod }));
|
|
144
166
|
};
|
|
145
167
|
const reportFailure = (message, failureStage, paymentMethod, providerError) => {
|
|
168
|
+
var _a, _b;
|
|
146
169
|
if (checkoutAnalytics) {
|
|
147
170
|
trackCheckoutFailureShown({
|
|
148
171
|
analytics: checkoutAnalytics,
|
|
@@ -151,7 +174,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
151
174
|
failureStage,
|
|
152
175
|
paymentMethod,
|
|
153
176
|
provider: 'stripe',
|
|
154
|
-
providerDeclineCode: providerError === null || providerError === void 0 ? void 0 : providerError.decline_code,
|
|
177
|
+
providerDeclineCode: (_a = providerError === null || providerError === void 0 ? void 0 : providerError.decline_code) !== null && _a !== void 0 ? _a : (_b = providerError === null || providerError === void 0 ? void 0 : providerError.paymentFailed) === null || _b === void 0 ? void 0 : _b.declineCode,
|
|
155
178
|
providerErrorCode: providerError === null || providerError === void 0 ? void 0 : providerError.code,
|
|
156
179
|
providerErrorType: providerError === null || providerError === void 0 ? void 0 : providerError.type,
|
|
157
180
|
});
|
|
@@ -159,7 +182,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
159
182
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
160
183
|
};
|
|
161
184
|
const handleConfirm = async (event) => {
|
|
162
|
-
var _a, _b, _c;
|
|
185
|
+
var _a, _b, _c, _d, _e, _f;
|
|
163
186
|
// Checkout Sessions omits the Express Checkout onClick callback. Confirmation
|
|
164
187
|
// and cancellation are the reliable wallet-intent boundaries for this provider.
|
|
165
188
|
// Session-based analytics deduplication keeps this idempotent if onClick fires.
|
|
@@ -227,7 +250,22 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
227
250
|
: {})), { expressCheckoutConfirmEvent: event, redirect: 'if_required' }));
|
|
228
251
|
if (result.type === 'error') {
|
|
229
252
|
const message = result.error.message || 'Wallet checkout failed.';
|
|
230
|
-
|
|
253
|
+
const providerError = normalizeStripeCheckoutProviderError(result.error);
|
|
254
|
+
reportFailure(message, 'wallet_confirmation', event.expressPaymentType, providerError);
|
|
255
|
+
const declineCode = (_f = (_d = providerError.decline_code) !== null && _d !== void 0 ? _d : (_e = providerError.paymentFailed) === null || _e === void 0 ? void 0 : _e.declineCode) !== null && _f !== void 0 ? _f : undefined;
|
|
256
|
+
if (classifyCheckoutFailure({
|
|
257
|
+
errorMessage: message,
|
|
258
|
+
provider: 'stripe',
|
|
259
|
+
providerDeclineCode: declineCode,
|
|
260
|
+
providerErrorCode: providerError.code,
|
|
261
|
+
providerErrorType: providerError.type,
|
|
262
|
+
}) === 'payment_rejection') {
|
|
263
|
+
onPaymentRejected === null || onPaymentRejected === void 0 ? void 0 : onPaymentRejected({
|
|
264
|
+
declineCode,
|
|
265
|
+
message,
|
|
266
|
+
paymentMethod: toAnalyticsPaymentMethod(event.expressPaymentType) || undefined,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
231
269
|
event.paymentFailed({ reason: 'fail', message });
|
|
232
270
|
return;
|
|
233
271
|
}
|
|
@@ -55,5 +55,6 @@ export type StripeSubscriptionCheckoutIntentKeyInput = Pick<StripeSubscriptionCh
|
|
|
55
55
|
export declare function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, runtimeConfigRevisionId, paymentProfileId, planKey, provider, stripePublishableKey, userId, }: StripeSubscriptionCheckoutIntentKeyInput): string;
|
|
56
56
|
export declare function shouldResetStripeSubscriptionCheckoutSessionForIntentKey(previousIntentKey: string | null, nextIntentKey: string): boolean;
|
|
57
57
|
export declare function isInactiveCheckoutSessionError(message?: string | null): boolean;
|
|
58
|
+
export declare function shouldAutoRecoverStripeSubscriptionCheckoutSession(message: string | null | undefined, alreadyRecovered: boolean): boolean;
|
|
58
59
|
export declare const shouldReportStripeCheckoutFailureShown: (message: string) => boolean;
|
|
59
60
|
export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, checkoutAnalytics, couponId, customerEmail, displayPlan, enabled, onError, plan, returnUrl, runtimeConfig, runtimeConfigRevisionId, paymentProfileId, provider, stripePublishableKey, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
|
|
@@ -70,6 +70,9 @@ export function isInactiveCheckoutSessionError(message) {
|
|
|
70
70
|
var _a;
|
|
71
71
|
return /\bcheckout session\b.*\bno longer active\b/i.test((_a = message === null || message === void 0 ? void 0 : message.trim()) !== null && _a !== void 0 ? _a : '');
|
|
72
72
|
}
|
|
73
|
+
export function shouldAutoRecoverStripeSubscriptionCheckoutSession(message, alreadyRecovered) {
|
|
74
|
+
return !alreadyRecovered && isInactiveCheckoutSessionError(message);
|
|
75
|
+
}
|
|
73
76
|
export const shouldReportStripeCheckoutFailureShown = (message) => !isInactiveCheckoutSessionError(message);
|
|
74
77
|
export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, checkoutAnalytics, couponId, customerEmail, displayPlan, enabled = true, onError, plan, returnUrl, runtimeConfig, runtimeConfigRevisionId, paymentProfileId, provider, stripePublishableKey, userId, }) {
|
|
75
78
|
var _a, _b, _c, _d, _e;
|
|
@@ -78,11 +81,14 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
78
81
|
const [checkoutSessionId, setCheckoutSessionId] = useState(null);
|
|
79
82
|
const [clientSecretPlanKey, setClientSecretPlanKey] = useState(null);
|
|
80
83
|
const [error, setErrorState] = useState(null);
|
|
84
|
+
const [recoveryRequest, setRecoveryRequest] = useState(0);
|
|
81
85
|
const [loading, setLoading] = useState(createEmptyCheckoutPreparationLoading);
|
|
82
86
|
const [runtimeStripePublishableKey, setRuntimeStripePublishableKey] = useState(null);
|
|
83
87
|
const creatingIntentRef = useRef(null);
|
|
84
88
|
const requestIdRef = useRef(0);
|
|
85
89
|
const attemptRef = useRef(null);
|
|
90
|
+
const recoveredIntentKeyRef = useRef(null);
|
|
91
|
+
const handledRecoveryRequestRef = useRef(0);
|
|
86
92
|
const anonymousUserIdRef = useRef(null);
|
|
87
93
|
const configured = enabled &&
|
|
88
94
|
(isStripeConfigured(checkoutMode) ||
|
|
@@ -127,21 +133,32 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
127
133
|
}, []);
|
|
128
134
|
const setError = useCallback((message) => {
|
|
129
135
|
if (isInactiveCheckoutSessionError(message)) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
const alreadyRecovered = recoveredIntentKeyRef.current === intentKey;
|
|
137
|
+
if (shouldAutoRecoverStripeSubscriptionCheckoutSession(message, alreadyRecovered)) {
|
|
138
|
+
clearActiveCheckoutSession();
|
|
139
|
+
setErrorState(null);
|
|
140
|
+
onError === null || onError === void 0 ? void 0 : onError(null);
|
|
141
|
+
recoveredIntentKeyRef.current = intentKey;
|
|
142
|
+
setRecoveryRequest((current) => current + 1);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
setErrorState(message);
|
|
146
|
+
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
147
|
+
}
|
|
133
148
|
return;
|
|
134
149
|
}
|
|
135
150
|
setErrorState(message);
|
|
136
151
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
137
|
-
}, [clearActiveCheckoutSession, onError]);
|
|
152
|
+
}, [clearActiveCheckoutSession, intentKey, onError]);
|
|
138
153
|
const reset = useCallback(() => {
|
|
139
154
|
attemptRef.current = null;
|
|
155
|
+
recoveredIntentKeyRef.current = null;
|
|
156
|
+
handledRecoveryRequestRef.current = recoveryRequest;
|
|
140
157
|
clearActiveCheckoutSession();
|
|
141
158
|
setLoading(createEmptyCheckoutPreparationLoading());
|
|
142
159
|
setRuntimeStripePublishableKey(null);
|
|
143
160
|
setError(null);
|
|
144
|
-
}, [clearActiveCheckoutSession, setError]);
|
|
161
|
+
}, [clearActiveCheckoutSession, recoveryRequest, setError]);
|
|
145
162
|
useIsomorphicLayoutEffect(() => {
|
|
146
163
|
const previousIntentKey = previousIntentKeyRef.current;
|
|
147
164
|
previousIntentKeyRef.current = intentKey;
|
|
@@ -304,6 +321,16 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
304
321
|
const prepareWalletCheckout = useCallback((options = {}) => prepareCheckout('wallet', options), [prepareCheckout]);
|
|
305
322
|
const restartCardCheckout = useCallback((options = {}) => prepareCheckout('card', Object.assign(Object.assign({}, options), { forceNew: true })), [prepareCheckout]);
|
|
306
323
|
const restartWalletCheckout = useCallback((options = {}) => prepareCheckout('wallet', Object.assign(Object.assign({}, options), { forceNew: true })), [prepareCheckout]);
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
if (recoveryRequest === 0
|
|
326
|
+
|| handledRecoveryRequestRef.current === recoveryRequest) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
handledRecoveryRequestRef.current = recoveryRequest;
|
|
330
|
+
void restartCardCheckout({
|
|
331
|
+
checkoutStartSource: 'checkout_render',
|
|
332
|
+
});
|
|
333
|
+
}, [recoveryRequest, restartCardCheckout]);
|
|
307
334
|
const updateCheckoutSessionPlan = useCallback(async () => {
|
|
308
335
|
if (!configured || !plan || !displayPlan || !activeCheckoutSessionId) {
|
|
309
336
|
return false;
|
|
@@ -29,6 +29,9 @@ type CheckoutFailureShownInput = CheckoutObservabilityInput & {
|
|
|
29
29
|
providerErrorCode?: string | null;
|
|
30
30
|
providerErrorType?: string | null;
|
|
31
31
|
};
|
|
32
|
+
export type CheckoutFailureCategory = 'network_failure' | 'payment_rejection' | 'platform_failure' | 'session_failure' | 'validation_failure';
|
|
33
|
+
export type CheckoutFailureClassificationInput = Pick<CheckoutFailureShownInput, 'errorMessage' | 'provider' | 'providerDeclineCode' | 'providerErrorCode' | 'providerErrorType'>;
|
|
34
|
+
export declare const classifyCheckoutFailure: (input: CheckoutFailureClassificationInput) => CheckoutFailureCategory;
|
|
32
35
|
export declare const trackCheckoutFailureShown: (input: CheckoutFailureShownInput) => string | null;
|
|
33
36
|
export declare const trackCheckoutCanceled: (input: CheckoutObservabilityInput) => string | null;
|
|
34
37
|
export {};
|
|
@@ -37,7 +37,31 @@ const STRIPE_PAYMENT_REJECTION_CODES = new Set([
|
|
|
37
37
|
'invalid_expiry_month',
|
|
38
38
|
'invalid_expiry_year',
|
|
39
39
|
'payment_intent_authentication_failure',
|
|
40
|
+
'paymentFailed',
|
|
40
41
|
]);
|
|
42
|
+
export const classifyCheckoutFailure = (input) => {
|
|
43
|
+
const providerDeclineCode = asNonEmptyString(input.providerDeclineCode);
|
|
44
|
+
const providerErrorCode = asNonEmptyString(input.providerErrorCode);
|
|
45
|
+
const providerErrorType = asNonEmptyString(input.providerErrorType);
|
|
46
|
+
if (input.provider === 'stripe' && (Boolean(providerDeclineCode)
|
|
47
|
+
|| providerErrorType === 'card_error'
|
|
48
|
+
|| (providerErrorCode ? STRIPE_PAYMENT_REJECTION_CODES.has(providerErrorCode) : false))) {
|
|
49
|
+
return 'payment_rejection';
|
|
50
|
+
}
|
|
51
|
+
const message = input.errorMessage.trim();
|
|
52
|
+
if (/checkout session.*no longer active/i.test(message)
|
|
53
|
+
|| /selected offer is no longer available/i.test(message)) {
|
|
54
|
+
return 'session_failure';
|
|
55
|
+
}
|
|
56
|
+
if (/failed to fetch|load failed|network|connection to (?:the )?provider|too many requests/i.test(message)) {
|
|
57
|
+
return 'network_failure';
|
|
58
|
+
}
|
|
59
|
+
if (/(?:email|card number|expiration|expiry|cvc|zip|postal code|billing address|country).*(?:required|incomplete|incorrect|invalid|unsupported)/i.test(message)
|
|
60
|
+
|| /(?:required|incomplete|incorrect|invalid|unsupported).*(?:email|card number|expiration|expiry|cvc|zip|postal code|billing address|country)/i.test(message)) {
|
|
61
|
+
return 'validation_failure';
|
|
62
|
+
}
|
|
63
|
+
return 'platform_failure';
|
|
64
|
+
};
|
|
41
65
|
const sanitizeErrorMessage = (value) => value
|
|
42
66
|
.replace(/[\r\n\t]+/g, ' ')
|
|
43
67
|
.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[redacted-email]')
|
|
@@ -68,6 +92,7 @@ const reportCheckoutObservability = (input) => {
|
|
|
68
92
|
environment,
|
|
69
93
|
errorCode: input.errorCode,
|
|
70
94
|
errorMessage: input.errorMessage,
|
|
95
|
+
failureCategory: input.failureCategory,
|
|
71
96
|
eventId: input.eventId,
|
|
72
97
|
eventType: input.eventType,
|
|
73
98
|
failureStage: input.failureStage,
|
|
@@ -96,9 +121,9 @@ const resolveErrorCode = (message, requestedCode) => {
|
|
|
96
121
|
return 'checkout_failure';
|
|
97
122
|
};
|
|
98
123
|
const emitCheckoutObservability = (eventType, input, failure) => {
|
|
99
|
-
var _a, _b;
|
|
124
|
+
var _a, _b, _c, _d;
|
|
100
125
|
const paymentMethod = toAnalyticsPaymentMethod(input.paymentMethod);
|
|
101
|
-
const metadata = Object.assign(Object.assign({}, ((_a = input.analytics.metadata) !== null && _a !== void 0 ? _a : {})), { checkout_session_id: ((_b = input.checkoutSessionId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, checkout_failure_stage: input.failureStage, payment_provider: input.provider, payment_method: paymentMethod || undefined, error_code: failure === null || failure === void 0 ? void 0 : failure.errorCode, error_message: failure === null || failure === void 0 ? void 0 : failure.errorMessage, provider_decline_code: failure === null || failure === void 0 ? void 0 : failure.providerDeclineCode, provider_error_code: failure === null || failure === void 0 ? void 0 : failure.providerErrorCode, provider_error_type: failure === null || failure === void 0 ? void 0 : failure.providerErrorType });
|
|
126
|
+
const metadata = Object.assign(Object.assign({}, ((_a = input.analytics.metadata) !== null && _a !== void 0 ? _a : {})), { checkout_session_id: ((_b = input.checkoutSessionId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, checkout_failure_stage: input.failureStage, payment_provider: input.provider, payment_method: paymentMethod || undefined, error_code: failure === null || failure === void 0 ? void 0 : failure.errorCode, error_message: failure === null || failure === void 0 ? void 0 : failure.errorMessage, checkout_failure_category: (_c = failure === null || failure === void 0 ? void 0 : failure.failureCategory) !== null && _c !== void 0 ? _c : (eventType === 'checkout_canceled' ? 'user_canceled' : undefined), provider_decline_code: failure === null || failure === void 0 ? void 0 : failure.providerDeclineCode, provider_error_code: failure === null || failure === void 0 ? void 0 : failure.providerErrorCode, provider_error_type: failure === null || failure === void 0 ? void 0 : failure.providerErrorType });
|
|
102
127
|
const eventId = publicAnalyticsSdk.track({
|
|
103
128
|
eventType,
|
|
104
129
|
environment: input.analytics.environment,
|
|
@@ -117,6 +142,7 @@ const emitCheckoutObservability = (eventType, input, failure) => {
|
|
|
117
142
|
checkoutSessionId: input.checkoutSessionId,
|
|
118
143
|
errorCode: failure === null || failure === void 0 ? void 0 : failure.errorCode,
|
|
119
144
|
errorMessage: failure === null || failure === void 0 ? void 0 : failure.errorMessage,
|
|
145
|
+
failureCategory: (_d = failure === null || failure === void 0 ? void 0 : failure.failureCategory) !== null && _d !== void 0 ? _d : (eventType === 'checkout_canceled' ? 'user_canceled' : undefined),
|
|
120
146
|
eventId,
|
|
121
147
|
eventType,
|
|
122
148
|
failureStage: input.failureStage,
|
|
@@ -138,14 +164,20 @@ export const trackCheckoutFailureShown = (input) => {
|
|
|
138
164
|
const providerDeclineCode = (_a = asNonEmptyString(input.providerDeclineCode)) === null || _a === void 0 ? void 0 : _a.slice(0, 120);
|
|
139
165
|
const providerErrorCode = (_b = asNonEmptyString(input.providerErrorCode)) === null || _b === void 0 ? void 0 : _b.slice(0, 120);
|
|
140
166
|
const providerErrorType = (_c = asNonEmptyString(input.providerErrorType)) === null || _c === void 0 ? void 0 : _c.slice(0, 120);
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
167
|
+
const failureCategory = classifyCheckoutFailure({
|
|
168
|
+
errorMessage,
|
|
169
|
+
provider: input.provider,
|
|
170
|
+
providerDeclineCode,
|
|
171
|
+
providerErrorCode,
|
|
172
|
+
providerErrorType,
|
|
173
|
+
});
|
|
174
|
+
const paymentRejected = failureCategory === 'payment_rejection';
|
|
144
175
|
return emitCheckoutObservability(paymentRejected ? 'checkout_payment_rejected' : 'checkout_failure_shown', input, {
|
|
145
176
|
errorCode: paymentRejected
|
|
146
177
|
? providerDeclineCode || providerErrorCode || 'payment_rejected'
|
|
147
178
|
: resolveErrorCode(errorMessage, input.errorCode),
|
|
148
179
|
errorMessage,
|
|
180
|
+
failureCategory,
|
|
149
181
|
providerDeclineCode,
|
|
150
182
|
providerErrorCode,
|
|
151
183
|
providerErrorType,
|