@funnelsgrove/payments 0.11.7 → 0.11.10
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/solidgate/components/SolidgateCheckoutDialog.js +12 -2
- package/dist/providers/solidgate/services/solidgate.service.d.ts +4 -0
- package/dist/providers/solidgate/services/solidgate.service.js +43 -17
- package/dist/providers/stripe/components/SharedStripeCheckoutDialog.js +5 -2
- package/dist/providers/stripe/components/SharedStripeCheckoutV2Dialog.js +11 -3
- package/dist/providers/stripe/components/StripeCheckoutExpressCheckoutButton.js +5 -2
- package/dist/providers/stripe/components/StripeExpressCheckoutButton.js +5 -2
- package/dist/services/checkoutObservability.service.d.ts +3 -0
- package/dist/services/checkoutObservability.service.js +33 -3
- package/package.json +1 -1
|
@@ -211,14 +211,18 @@ export function SolidgateCheckoutDialog({ open, request, customerEmail, checkout
|
|
|
211
211
|
setCommittedEmail(normalizedCustomerEmail);
|
|
212
212
|
setEmailError(null);
|
|
213
213
|
}, [customerEmail, normalizedCustomerEmail]);
|
|
214
|
-
const { discountKeyOrProviderId, failUrl, funnelPlanKey, funnelEndUserId, funnelId, idempotencyKey, offerSetId, returnUrl, runtimeConfig, successUrl, } = request;
|
|
215
|
-
const { apiBaseUrl, funnelId: runtimeFunnelId, funnelSdkPublishableKey, funnelVersionId, } = runtimeConfig || {};
|
|
214
|
+
const { discountKeyOrProviderId, failUrl, funnelPlanKey, paymentProfileId, providerPlanId, checkoutType, environment, funnelEndUserId, funnelId, idempotencyKey, offerSetId, returnUrl, runtimeConfig, successUrl, } = request;
|
|
215
|
+
const { apiBaseUrl, funnelId: runtimeFunnelId, funnelSdkPublishableKey, funnelVersionId, paymentsApiVersion, } = runtimeConfig || {};
|
|
216
216
|
const hasRuntimeConfig = runtimeConfig !== undefined;
|
|
217
217
|
const normalizedRequest = useMemo(() => ({
|
|
218
218
|
funnelId: (funnelId === null || funnelId === void 0 ? void 0 : funnelId.trim()) || null,
|
|
219
219
|
funnelEndUserId: funnelEndUserId.trim(),
|
|
220
220
|
offerSetId: offerSetId.trim(),
|
|
221
221
|
funnelPlanKey: funnelPlanKey.trim(),
|
|
222
|
+
paymentProfileId: (paymentProfileId === null || paymentProfileId === void 0 ? void 0 : paymentProfileId.trim()) || null,
|
|
223
|
+
providerPlanId: (providerPlanId === null || providerPlanId === void 0 ? void 0 : providerPlanId.trim()) || null,
|
|
224
|
+
checkoutType: checkoutType || null,
|
|
225
|
+
environment: environment || null,
|
|
222
226
|
idempotencyKey: idempotencyKey.trim(),
|
|
223
227
|
discountKeyOrProviderId: (discountKeyOrProviderId === null || discountKeyOrProviderId === void 0 ? void 0 : discountKeyOrProviderId.trim()) || null,
|
|
224
228
|
returnUrl: returnUrl.trim(),
|
|
@@ -229,16 +233,22 @@ export function SolidgateCheckoutDialog({ open, request, customerEmail, checkout
|
|
|
229
233
|
funnelId: (runtimeFunnelId === null || runtimeFunnelId === void 0 ? void 0 : runtimeFunnelId.trim()) || null,
|
|
230
234
|
funnelVersionId: (funnelVersionId === null || funnelVersionId === void 0 ? void 0 : funnelVersionId.trim()) || null,
|
|
231
235
|
funnelSdkPublishableKey: (funnelSdkPublishableKey === null || funnelSdkPublishableKey === void 0 ? void 0 : funnelSdkPublishableKey.trim()) || null,
|
|
236
|
+
paymentsApiVersion: paymentsApiVersion || null,
|
|
232
237
|
} : undefined,
|
|
233
238
|
}), [
|
|
234
239
|
apiBaseUrl,
|
|
235
240
|
discountKeyOrProviderId,
|
|
236
241
|
failUrl,
|
|
237
242
|
funnelPlanKey,
|
|
243
|
+
paymentProfileId,
|
|
244
|
+
providerPlanId,
|
|
245
|
+
checkoutType,
|
|
246
|
+
environment,
|
|
238
247
|
funnelEndUserId,
|
|
239
248
|
funnelId,
|
|
240
249
|
funnelSdkPublishableKey,
|
|
241
250
|
funnelVersionId,
|
|
251
|
+
paymentsApiVersion,
|
|
242
252
|
idempotencyKey,
|
|
243
253
|
offerSetId,
|
|
244
254
|
returnUrl,
|
|
@@ -26,6 +26,10 @@ export type PrepareSolidgateCheckoutInput = {
|
|
|
26
26
|
funnelEndUserId: string;
|
|
27
27
|
offerSetId: string;
|
|
28
28
|
funnelPlanKey: string;
|
|
29
|
+
paymentProfileId?: string | null;
|
|
30
|
+
providerPlanId?: string | null;
|
|
31
|
+
checkoutType?: 'subscription' | 'one_time' | null;
|
|
32
|
+
environment?: 'test' | 'live' | null;
|
|
29
33
|
idempotencyKey: string;
|
|
30
34
|
discountKeyOrProviderId?: string | null;
|
|
31
35
|
returnUrl: string;
|
|
@@ -32,6 +32,18 @@ const postJson = async (path, body, runtimeConfig, signal) => {
|
|
|
32
32
|
}
|
|
33
33
|
return response.json();
|
|
34
34
|
};
|
|
35
|
+
const getJson = async (path, runtimeConfig, signal) => {
|
|
36
|
+
const publishableKey = resolvePublishableKey(runtimeConfig);
|
|
37
|
+
const response = await fetch(resolveApiUrl(path, runtimeConfig), {
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: Object.assign({}, (publishableKey ? { 'x-sdk-publishable-key': publishableKey } : {})),
|
|
40
|
+
signal,
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
throw new Error('Solidgate checkout is temporarily unavailable');
|
|
44
|
+
}
|
|
45
|
+
return response.json();
|
|
46
|
+
};
|
|
35
47
|
const isRecord = (value) => (Boolean(value) && typeof value === 'object' && !Array.isArray(value));
|
|
36
48
|
const parsePreparation = (value) => {
|
|
37
49
|
if (!isRecord(value) || !isRecord(value.display) || !isRecord(value.initialization)) {
|
|
@@ -98,26 +110,40 @@ const parseStatus = (value) => {
|
|
|
98
110
|
};
|
|
99
111
|
};
|
|
100
112
|
export const prepareSolidgateCheckout = async (input) => {
|
|
101
|
-
var _a;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
var _a, _b, _c, _d;
|
|
114
|
+
const useV2 = ((_a = input.runtimeConfig) === null || _a === void 0 ? void 0 : _a.paymentsApiVersion) === 'v2';
|
|
115
|
+
const paymentProfileId = ((_b = input.paymentProfileId) === null || _b === void 0 ? void 0 : _b.trim()) || null;
|
|
116
|
+
const providerPlanId = ((_c = input.providerPlanId) === null || _c === void 0 ? void 0 : _c.trim()) || null;
|
|
117
|
+
const checkoutType = input.checkoutType || null;
|
|
118
|
+
const environment = input.environment || null;
|
|
119
|
+
if (useV2 && (!paymentProfileId || !providerPlanId || !checkoutType || !environment)) {
|
|
120
|
+
throw new Error('Solidgate V2 checkout selection is incomplete');
|
|
121
|
+
}
|
|
122
|
+
return parsePreparation(await postJson(useV2
|
|
123
|
+
? '/sdk/public/v2/payments/checkout-sessions'
|
|
124
|
+
: '/sdk/public/payments/solidgate/checkout', Object.assign(Object.assign({}, (useV2 ? {
|
|
125
|
+
checkoutType,
|
|
126
|
+
uiMode: 'custom',
|
|
127
|
+
environment,
|
|
128
|
+
paymentProfileId,
|
|
129
|
+
provider: 'solidgate',
|
|
130
|
+
providerPlanId,
|
|
131
|
+
planKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'),
|
|
132
|
+
} : {})), { funnelId: resolveFunnelId(input.funnelId, input.runtimeConfig), funnelEndUserId: requiredString(input.funnelEndUserId, 'funnelEndUserId'), offerSetId: requiredString(input.offerSetId, 'offerSetId'), funnelPlanKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'), idempotencyKey: requiredString(input.idempotencyKey, 'idempotencyKey'), discountKeyOrProviderId: ((_d = input.discountKeyOrProviderId) === null || _d === void 0 ? void 0 : _d.trim()) || null, returnUrl: requiredString(input.returnUrl, 'returnUrl'), successUrl: requiredString(input.successUrl, 'successUrl'), failUrl: requiredString(input.failUrl, 'failUrl') }), input.runtimeConfig, input.signal));
|
|
113
133
|
};
|
|
114
134
|
export const retrieveSolidgateCheckoutStatus = async (input) => {
|
|
135
|
+
var _a;
|
|
115
136
|
const attemptId = requiredString(input.attemptId, 'attemptId');
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
137
|
+
const useV2 = ((_a = input.runtimeConfig) === null || _a === void 0 ? void 0 : _a.paymentsApiVersion) === 'v2';
|
|
138
|
+
const funnelId = resolveFunnelId(input.funnelId, input.runtimeConfig);
|
|
139
|
+
const funnelEndUserId = requiredString(input.funnelEndUserId, 'funnelEndUserId');
|
|
140
|
+
const result = parseStatus(await (useV2
|
|
141
|
+
? getJson(`/sdk/public/v2/payments/checkout-sessions/${encodeURIComponent(attemptId)}?provider=solidgate&funnelId=${encodeURIComponent(funnelId)}&funnelEndUserId=${encodeURIComponent(funnelEndUserId)}`, input.runtimeConfig, input.signal)
|
|
142
|
+
: postJson('/sdk/public/payments/solidgate/checkout/status', {
|
|
143
|
+
funnelId: resolveFunnelId(input.funnelId, input.runtimeConfig),
|
|
144
|
+
funnelEndUserId,
|
|
145
|
+
attemptId,
|
|
146
|
+
}, input.runtimeConfig, input.signal)));
|
|
121
147
|
if (result.attemptId !== attemptId) {
|
|
122
148
|
throw new Error('Solidgate checkout status returned the wrong attempt');
|
|
123
149
|
}
|
|
@@ -142,7 +142,7 @@ function SharedStripeCheckoutForm({ amountCents, checkoutAnalytics, checkoutSess
|
|
|
142
142
|
!submitting;
|
|
143
143
|
const walletCheckoutAllowed = allowApplePayExpressCheckout || allowApplePayQrFallback;
|
|
144
144
|
const walletFallbackDisabled = !walletCheckoutAllowed || walletAvailable === false;
|
|
145
|
-
const setSharedError = (message, alreadyTracked = false) => {
|
|
145
|
+
const setSharedError = (message, alreadyTracked = false, providerError) => {
|
|
146
146
|
if (message && checkoutAnalytics && !alreadyTracked) {
|
|
147
147
|
trackCheckoutFailureShown({
|
|
148
148
|
analytics: checkoutAnalytics,
|
|
@@ -151,6 +151,9 @@ function SharedStripeCheckoutForm({ amountCents, checkoutAnalytics, checkoutSess
|
|
|
151
151
|
failureStage: 'card_form',
|
|
152
152
|
paymentMethod: 'card',
|
|
153
153
|
provider: 'stripe',
|
|
154
|
+
providerDeclineCode: providerError === null || providerError === void 0 ? void 0 : providerError.decline_code,
|
|
155
|
+
providerErrorCode: providerError === null || providerError === void 0 ? void 0 : providerError.code,
|
|
156
|
+
providerErrorType: providerError === null || providerError === void 0 ? void 0 : providerError.type,
|
|
154
157
|
});
|
|
155
158
|
}
|
|
156
159
|
setError(message);
|
|
@@ -216,7 +219,7 @@ function SharedStripeCheckoutForm({ amountCents, checkoutAnalytics, checkoutSess
|
|
|
216
219
|
return_url: returnUrl,
|
|
217
220
|
});
|
|
218
221
|
if (result.error) {
|
|
219
|
-
setSharedError(result.error.message || 'Payment failed.');
|
|
222
|
+
setSharedError(result.error.message || 'Payment failed.', false, result.error);
|
|
220
223
|
setSubmitting(false);
|
|
221
224
|
return;
|
|
222
225
|
}
|
|
@@ -70,6 +70,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
70
70
|
? true
|
|
71
71
|
: walletAvailable;
|
|
72
72
|
const [submitting, setSubmitting] = useState(false);
|
|
73
|
+
const [paymentElementReady, setPaymentElementReady] = useState(false);
|
|
73
74
|
const [error, setError] = useState(null);
|
|
74
75
|
const [billingCountry, setBillingCountry] = useState(null);
|
|
75
76
|
const initialCustomerEmail = (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || '';
|
|
@@ -152,7 +153,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
152
153
|
setError(null);
|
|
153
154
|
onInactiveCheckoutSession === null || onInactiveCheckoutSession === void 0 ? void 0 : onInactiveCheckoutSession();
|
|
154
155
|
};
|
|
155
|
-
const setSharedError = (message, alreadyTracked = false) => {
|
|
156
|
+
const setSharedError = (message, alreadyTracked = false, providerError) => {
|
|
156
157
|
if (isInactiveCheckoutSessionError(message)) {
|
|
157
158
|
handleInactiveCheckoutSession();
|
|
158
159
|
return;
|
|
@@ -165,6 +166,9 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
165
166
|
failureStage: 'card_form',
|
|
166
167
|
paymentMethod: 'card',
|
|
167
168
|
provider: 'stripe',
|
|
169
|
+
providerDeclineCode: providerError === null || providerError === void 0 ? void 0 : providerError.decline_code,
|
|
170
|
+
providerErrorCode: providerError === null || providerError === void 0 ? void 0 : providerError.code,
|
|
171
|
+
providerErrorType: providerError === null || providerError === void 0 ? void 0 : providerError.type,
|
|
168
172
|
});
|
|
169
173
|
}
|
|
170
174
|
setError(message);
|
|
@@ -260,6 +264,10 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
260
264
|
: 'Payment form is not ready yet.');
|
|
261
265
|
return;
|
|
262
266
|
}
|
|
267
|
+
if (!paymentElementReady) {
|
|
268
|
+
setSharedError('Payment form is not ready yet.', true);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
263
271
|
setSubmitting(true);
|
|
264
272
|
setSharedError(null);
|
|
265
273
|
try {
|
|
@@ -274,7 +282,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
274
282
|
});
|
|
275
283
|
if (result.type === 'error') {
|
|
276
284
|
const message = result.error.message || 'Payment failed.';
|
|
277
|
-
setSharedError(message);
|
|
285
|
+
setSharedError(message, false, result.error);
|
|
278
286
|
setSubmitting(false);
|
|
279
287
|
return;
|
|
280
288
|
}
|
|
@@ -322,7 +330,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
322
330
|
}
|
|
323
331
|
setEmailDraft(event.target.value);
|
|
324
332
|
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
325
|
-
} }) })] }), _jsx(PaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
|
|
333
|
+
} }) })] }), _jsx(PaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange, onReady: () => setPaymentElementReady(true) }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting || !paymentElementReady, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
|
|
326
334
|
}
|
|
327
335
|
function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry, stripePromise, variant, }) {
|
|
328
336
|
const providerChildren = children;
|
|
@@ -120,7 +120,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
120
120
|
checkoutStartSource,
|
|
121
121
|
paymentMethod }));
|
|
122
122
|
};
|
|
123
|
-
const reportFailure = (message, failureStage, paymentMethod) => {
|
|
123
|
+
const reportFailure = (message, failureStage, paymentMethod, providerError) => {
|
|
124
124
|
if (checkoutAnalytics) {
|
|
125
125
|
trackCheckoutFailureShown({
|
|
126
126
|
analytics: checkoutAnalytics,
|
|
@@ -129,6 +129,9 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
129
129
|
failureStage,
|
|
130
130
|
paymentMethod,
|
|
131
131
|
provider: 'stripe',
|
|
132
|
+
providerDeclineCode: providerError === null || providerError === void 0 ? void 0 : providerError.decline_code,
|
|
133
|
+
providerErrorCode: providerError === null || providerError === void 0 ? void 0 : providerError.code,
|
|
134
|
+
providerErrorType: providerError === null || providerError === void 0 ? void 0 : providerError.type,
|
|
132
135
|
});
|
|
133
136
|
}
|
|
134
137
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
@@ -202,7 +205,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
202
205
|
: {})), { expressCheckoutConfirmEvent: event, redirect: 'if_required' }));
|
|
203
206
|
if (result.type === 'error') {
|
|
204
207
|
const message = result.error.message || 'Wallet checkout failed.';
|
|
205
|
-
reportFailure(message, 'wallet_confirmation', event.expressPaymentType);
|
|
208
|
+
reportFailure(message, 'wallet_confirmation', event.expressPaymentType, result.error);
|
|
206
209
|
event.paymentFailed({ reason: 'fail', message });
|
|
207
210
|
return;
|
|
208
211
|
}
|
|
@@ -70,7 +70,7 @@ export function StripeExpressCheckoutButton({ amountCents, beforeConfirm, checko
|
|
|
70
70
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
71
71
|
return Object.assign(Object.assign(Object.assign({}, baseOptions), (options !== null && options !== void 0 ? options : {})), { buttonTheme: Object.assign(Object.assign({}, ((_a = baseOptions.buttonTheme) !== null && _a !== void 0 ? _a : {})), ((_b = options === null || options === void 0 ? void 0 : options.buttonTheme) !== null && _b !== void 0 ? _b : {})), buttonType: Object.assign(Object.assign({}, ((_c = baseOptions.buttonType) !== null && _c !== void 0 ? _c : {})), ((_d = options === null || options === void 0 ? void 0 : options.buttonType) !== null && _d !== void 0 ? _d : {})), layout: Object.assign(Object.assign({}, ((_e = baseOptions.layout) !== null && _e !== void 0 ? _e : {})), ((_f = options === null || options === void 0 ? void 0 : options.layout) !== null && _f !== void 0 ? _f : {})), paymentMethods: Object.assign(Object.assign({}, ((_g = baseOptions.paymentMethods) !== null && _g !== void 0 ? _g : {})), ((_h = options === null || options === void 0 ? void 0 : options.paymentMethods) !== null && _h !== void 0 ? _h : {})), lineItems: (_j = options === null || options === void 0 ? void 0 : options.lineItems) !== null && _j !== void 0 ? _j : baseOptions.lineItems, paymentMethodOrder: (_k = options === null || options === void 0 ? void 0 : options.paymentMethodOrder) !== null && _k !== void 0 ? _k : baseOptions.paymentMethodOrder });
|
|
72
72
|
}, [baseOptions, options]);
|
|
73
|
-
const reportFailure = (message, failureStage, paymentMethod) => {
|
|
73
|
+
const reportFailure = (message, failureStage, paymentMethod, providerError) => {
|
|
74
74
|
if (checkoutAnalytics) {
|
|
75
75
|
trackCheckoutFailureShown({
|
|
76
76
|
analytics: checkoutAnalytics,
|
|
@@ -79,6 +79,9 @@ export function StripeExpressCheckoutButton({ amountCents, beforeConfirm, checko
|
|
|
79
79
|
failureStage,
|
|
80
80
|
paymentMethod,
|
|
81
81
|
provider: 'stripe',
|
|
82
|
+
providerDeclineCode: providerError === null || providerError === void 0 ? void 0 : providerError.decline_code,
|
|
83
|
+
providerErrorCode: providerError === null || providerError === void 0 ? void 0 : providerError.code,
|
|
84
|
+
providerErrorType: providerError === null || providerError === void 0 ? void 0 : providerError.type,
|
|
82
85
|
});
|
|
83
86
|
}
|
|
84
87
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
@@ -150,7 +153,7 @@ export function StripeExpressCheckoutButton({ amountCents, beforeConfirm, checko
|
|
|
150
153
|
});
|
|
151
154
|
if (result.error) {
|
|
152
155
|
const message = result.error.message || 'Wallet checkout failed.';
|
|
153
|
-
reportFailure(message, 'wallet_confirmation', event.expressPaymentType);
|
|
156
|
+
reportFailure(message, 'wallet_confirmation', event.expressPaymentType, result.error);
|
|
154
157
|
event.paymentFailed({ reason: 'fail', message });
|
|
155
158
|
return;
|
|
156
159
|
}
|
|
@@ -25,6 +25,9 @@ type CheckoutObservabilityInput = {
|
|
|
25
25
|
type CheckoutFailureShownInput = CheckoutObservabilityInput & {
|
|
26
26
|
errorCode?: string | null;
|
|
27
27
|
errorMessage: string;
|
|
28
|
+
providerDeclineCode?: string | null;
|
|
29
|
+
providerErrorCode?: string | null;
|
|
30
|
+
providerErrorType?: string | null;
|
|
28
31
|
};
|
|
29
32
|
export declare const trackCheckoutFailureShown: (input: CheckoutFailureShownInput) => string | null;
|
|
30
33
|
export declare const trackCheckoutCanceled: (input: CheckoutObservabilityInput) => string | null;
|
|
@@ -26,6 +26,18 @@ export const resolveCheckoutObservabilityAnalyticsContext = (input) => {
|
|
|
26
26
|
stepContractVersion: (_x = (_w = input.analytics) === null || _w === void 0 ? void 0 : _w.stepContractVersion) !== null && _x !== void 0 ? _x : validStepContractVersion,
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
|
+
const STRIPE_PAYMENT_REJECTION_CODES = new Set([
|
|
30
|
+
'card_declined',
|
|
31
|
+
'expired_card',
|
|
32
|
+
'incorrect_cvc',
|
|
33
|
+
'incorrect_number',
|
|
34
|
+
'incorrect_zip',
|
|
35
|
+
'insufficient_funds',
|
|
36
|
+
'invalid_cvc',
|
|
37
|
+
'invalid_expiry_month',
|
|
38
|
+
'invalid_expiry_year',
|
|
39
|
+
'payment_intent_authentication_failure',
|
|
40
|
+
]);
|
|
29
41
|
const sanitizeErrorMessage = (value) => value
|
|
30
42
|
.replace(/[\r\n\t]+/g, ' ')
|
|
31
43
|
.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[redacted-email]')
|
|
@@ -63,6 +75,9 @@ const reportCheckoutObservability = (input) => {
|
|
|
63
75
|
funnelVersionId: ((_g = runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelVersionId) === null || _g === void 0 ? void 0 : _g.trim()) || FUNNEL_VERSION_ID.trim() || undefined,
|
|
64
76
|
paymentMethod: input.paymentMethod || undefined,
|
|
65
77
|
provider: input.provider,
|
|
78
|
+
providerDeclineCode: input.providerDeclineCode,
|
|
79
|
+
providerErrorCode: input.providerErrorCode,
|
|
80
|
+
providerErrorType: input.providerErrorType,
|
|
66
81
|
}),
|
|
67
82
|
keepalive: true,
|
|
68
83
|
}).then(() => undefined);
|
|
@@ -83,7 +98,7 @@ const resolveErrorCode = (message, requestedCode) => {
|
|
|
83
98
|
const emitCheckoutObservability = (eventType, input, failure) => {
|
|
84
99
|
var _a, _b;
|
|
85
100
|
const paymentMethod = toAnalyticsPaymentMethod(input.paymentMethod);
|
|
86
|
-
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 });
|
|
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 });
|
|
87
102
|
const eventId = publicAnalyticsSdk.track({
|
|
88
103
|
eventType,
|
|
89
104
|
environment: input.analytics.environment,
|
|
@@ -107,18 +122,33 @@ const emitCheckoutObservability = (eventType, input, failure) => {
|
|
|
107
122
|
failureStage: input.failureStage,
|
|
108
123
|
paymentMethod,
|
|
109
124
|
provider: input.provider,
|
|
125
|
+
providerDeclineCode: failure === null || failure === void 0 ? void 0 : failure.providerDeclineCode,
|
|
126
|
+
providerErrorCode: failure === null || failure === void 0 ? void 0 : failure.providerErrorCode,
|
|
127
|
+
providerErrorType: failure === null || failure === void 0 ? void 0 : failure.providerErrorType,
|
|
110
128
|
}).catch(() => undefined);
|
|
111
129
|
void publicAnalyticsSdk.flush().catch(() => 0);
|
|
112
130
|
return eventId;
|
|
113
131
|
};
|
|
114
132
|
export const trackCheckoutFailureShown = (input) => {
|
|
133
|
+
var _a, _b, _c;
|
|
115
134
|
const errorMessage = sanitizeErrorMessage(input.errorMessage);
|
|
116
135
|
if (!errorMessage) {
|
|
117
136
|
return null;
|
|
118
137
|
}
|
|
119
|
-
|
|
120
|
-
|
|
138
|
+
const providerDeclineCode = (_a = asNonEmptyString(input.providerDeclineCode)) === null || _a === void 0 ? void 0 : _a.slice(0, 120);
|
|
139
|
+
const providerErrorCode = (_b = asNonEmptyString(input.providerErrorCode)) === null || _b === void 0 ? void 0 : _b.slice(0, 120);
|
|
140
|
+
const providerErrorType = (_c = asNonEmptyString(input.providerErrorType)) === null || _c === void 0 ? void 0 : _c.slice(0, 120);
|
|
141
|
+
const paymentRejected = input.provider === 'stripe' && (Boolean(providerDeclineCode)
|
|
142
|
+
|| providerErrorType === 'card_error'
|
|
143
|
+
|| (providerErrorCode ? STRIPE_PAYMENT_REJECTION_CODES.has(providerErrorCode) : false));
|
|
144
|
+
return emitCheckoutObservability(paymentRejected ? 'checkout_payment_rejected' : 'checkout_failure_shown', input, {
|
|
145
|
+
errorCode: paymentRejected
|
|
146
|
+
? providerDeclineCode || providerErrorCode || 'payment_rejected'
|
|
147
|
+
: resolveErrorCode(errorMessage, input.errorCode),
|
|
121
148
|
errorMessage,
|
|
149
|
+
providerDeclineCode,
|
|
150
|
+
providerErrorCode,
|
|
151
|
+
providerErrorType,
|
|
122
152
|
});
|
|
123
153
|
};
|
|
124
154
|
export const trackCheckoutCanceled = (input) => emitCheckoutObservability('checkout_canceled', input);
|