@funnelsgrove/payments 0.28.0 → 0.30.0
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/generated/package-version.d.ts +1 -1
- package/dist/generated/package-version.js +1 -1
- package/dist/providers/solidgate/components/SolidgateCheckoutDialog.js +29 -10
- package/dist/providers/solidgate/components/SolidgateCheckoutDialog.types.d.ts +1 -1
- package/dist/providers/solidgate/components/SolidgatePaymentForm.js +2 -2
- package/dist/providers/solidgate/components/SolidgateSdkPayment.js +1 -1
- package/dist/providers/solidgate/services/solidgate.service.d.ts +6 -0
- package/dist/providers/solidgate/services/solidgate.service.js +18 -22
- package/dist/providers/solidgate/services/solidgateDeclineMessage.d.ts +1 -0
- package/dist/providers/solidgate/services/solidgateDeclineMessage.js +24 -0
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PAYMENTS_PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PAYMENTS_PACKAGE_VERSION = "0.30.0";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/generate-package-version.mjs.
|
|
2
|
-
export const PAYMENTS_PACKAGE_VERSION = "0.
|
|
2
|
+
export const PAYMENTS_PACKAGE_VERSION = "0.30.0";
|
|
@@ -3,8 +3,9 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { completePaywallCheckout } from '@funnelsgrove/runtime';
|
|
4
4
|
import { publicAnalyticsSdk } from '@funnelsgrove/analytics';
|
|
5
5
|
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
6
|
-
import { pollSolidgateCheckoutStatus, prepareSolidgateCheckout, } from '../services/solidgate.service.js';
|
|
6
|
+
import { pollSolidgateCheckoutStatus, prepareSolidgateCheckout, SolidgateExistingSubscriptionError, } from '../services/solidgate.service.js';
|
|
7
7
|
import { trackCheckoutCanceled, trackCheckoutFailureShown, } from '../../../services/checkoutObservability.service.js';
|
|
8
|
+
import { solidgateDeclineMessage } from '../services/solidgateDeclineMessage.js';
|
|
8
9
|
import { SolidgateCheckoutSummary } from './SolidgateCheckoutSummary.js';
|
|
9
10
|
import { SolidgatePaymentForm } from './SolidgatePaymentForm.js';
|
|
10
11
|
import { solidgateCheckoutDialogStyles } from './SolidgateCheckoutDialog.styles.js';
|
|
@@ -75,6 +76,7 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
75
76
|
const [emailError, setEmailError] = useState(null);
|
|
76
77
|
const [emailSubmitting, setEmailSubmitting] = useState(false);
|
|
77
78
|
const [mountedPaymentAttemptId, setMountedPaymentAttemptId] = useState(null);
|
|
79
|
+
const declinedAttemptRef = useRef(null);
|
|
78
80
|
const prepareAbortRef = useRef(null);
|
|
79
81
|
const preparedRequestRef = useRef(null);
|
|
80
82
|
const statusAbortRef = useRef(null);
|
|
@@ -105,6 +107,7 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
105
107
|
const { discountKeyOrProviderId, failUrl, funnelPlanKey, paymentProfileId, providerPlanId, checkoutType, environment, funnelEndUserId, funnelId, idempotencyKey, offerSetId, returnUrl, runtimeConfig, successUrl, } = request;
|
|
106
108
|
const checkoutKey = (retryRequest === null || retryRequest === void 0 ? void 0 : retryRequest.originalKey) === idempotencyKey
|
|
107
109
|
? retryRequest.key : idempotencyKey;
|
|
110
|
+
const retryAttemptId = (retryRequest === null || retryRequest === void 0 ? void 0 : retryRequest.originalKey) === idempotencyKey ? retryRequest.attemptId : request.retryAttemptId;
|
|
108
111
|
const { apiBaseUrl, funnelId: runtimeFunnelId, funnelSdkPublishableKey, funnelVersionId, paymentsApiVersion, } = runtimeConfig || {};
|
|
109
112
|
const hasRuntimeConfig = runtimeConfig !== undefined;
|
|
110
113
|
const normalizedRequest = useMemo(() => ({
|
|
@@ -117,6 +120,7 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
117
120
|
checkoutType: checkoutType || null,
|
|
118
121
|
environment: environment || null,
|
|
119
122
|
idempotencyKey: checkoutKey.trim(),
|
|
123
|
+
retryAttemptId,
|
|
120
124
|
discountKeyOrProviderId: (discountKeyOrProviderId === null || discountKeyOrProviderId === void 0 ? void 0 : discountKeyOrProviderId.trim()) || null,
|
|
121
125
|
returnUrl: returnUrl.trim(),
|
|
122
126
|
successUrl: successUrl.trim(),
|
|
@@ -143,6 +147,7 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
143
147
|
funnelVersionId,
|
|
144
148
|
paymentsApiVersion,
|
|
145
149
|
checkoutKey,
|
|
150
|
+
retryAttemptId,
|
|
146
151
|
offerSetId,
|
|
147
152
|
returnUrl,
|
|
148
153
|
hasRuntimeConfig,
|
|
@@ -210,6 +215,7 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
210
215
|
void prepareSolidgateCheckout(Object.assign(Object.assign({}, preparedRequest), { signal: controller.signal }))
|
|
211
216
|
.then((checkout) => {
|
|
212
217
|
if (!controller.signal.aborted) {
|
|
218
|
+
declinedAttemptRef.current = null;
|
|
213
219
|
setState({ state: 'ready', checkout, canResumeVerification: false });
|
|
214
220
|
if (layout !== 'wallet') {
|
|
215
221
|
void trackSolidgateCheckoutEvent('checkout_started', checkout.attemptId, checkoutAnalyticsRef.current);
|
|
@@ -219,9 +225,11 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
219
225
|
.catch((error) => {
|
|
220
226
|
var _a;
|
|
221
227
|
if (!controller.signal.aborted && !isAbortError(error)) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
(
|
|
228
|
+
const failureMessage = error instanceof SolidgateExistingSubscriptionError
|
|
229
|
+
? error.message : copyRef.current.error;
|
|
230
|
+
setState({ state: 'recoverable_error', checkout: null, canResumeVerification: false, failureMessage });
|
|
231
|
+
trackFailure(failureMessage, 'checkout_session_creation');
|
|
232
|
+
(_a = onErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onErrorRef, failureMessage, error instanceof SolidgateExistingSubscriptionError ? error.code : undefined);
|
|
225
233
|
}
|
|
226
234
|
});
|
|
227
235
|
return () => controller.abort();
|
|
@@ -304,9 +312,11 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
304
312
|
trackFailure(copyRef.current.expired, 'payment_expired', checkout.attemptId);
|
|
305
313
|
}
|
|
306
314
|
else if (result.status === 'failed') {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
(
|
|
315
|
+
declinedAttemptRef.current = checkout.attemptId;
|
|
316
|
+
const failureMessage = solidgateDeclineMessage(result.failureCode);
|
|
317
|
+
setState({ state: 'recoverable_error', checkout, canResumeVerification: false, failureMessage });
|
|
318
|
+
trackFailure(failureMessage, 'payment_failed', checkout.attemptId);
|
|
319
|
+
(_c = onErrorRef.current) === null || _c === void 0 ? void 0 : _c.call(onErrorRef, failureMessage);
|
|
310
320
|
}
|
|
311
321
|
else if (result.status === 'requires_payment') {
|
|
312
322
|
setState({ state: 'ready', checkout, canResumeVerification: false });
|
|
@@ -380,20 +390,29 @@ export function SolidgateCheckoutDialog({ open, layout = 'dialog', request, cust
|
|
|
380
390
|
: view.state === 'expired'
|
|
381
391
|
? copy.expired
|
|
382
392
|
: view.state === 'recoverable_error'
|
|
383
|
-
? copy.error
|
|
393
|
+
? view.failureMessage || copy.error
|
|
384
394
|
: null;
|
|
385
395
|
const presentationStyle = presentation
|
|
386
396
|
? {
|
|
387
397
|
'--solidgate-checkout-theme-color': presentation.themeColor,
|
|
388
398
|
}
|
|
389
399
|
: undefined;
|
|
390
|
-
const recoveryActions = (_jsxs(_Fragment, { children: [view.canResumeVerification ? (_jsx("button", { type: 'button', onClick: () => void verifyCanonicalStatus(), className: 'solidgate-checkout-action solidgate-checkout-action--spaced', children: copy.resumeVerification })) : null, (view.state === 'recoverable_error' || view.state === 'expired') && !view.canResumeVerification ? (_jsx("button", { type: 'button', onClick:
|
|
400
|
+
const recoveryActions = (_jsxs(_Fragment, { children: [view.canResumeVerification ? (_jsx("button", { type: 'button', onClick: () => void verifyCanonicalStatus(), className: 'solidgate-checkout-action solidgate-checkout-action--spaced', children: copy.resumeVerification })) : null, (view.state === 'recoverable_error' || view.state === 'expired') && !view.canResumeVerification ? (_jsx("button", { type: 'button', onClick: () => {
|
|
401
|
+
var _a;
|
|
402
|
+
const source = checkoutType === 'subscription'
|
|
403
|
+
? declinedAttemptRef.current || (retryAttemptId ? ((_a = view.checkout) === null || _a === void 0 ? void 0 : _a.attemptId) || retryAttemptId : null)
|
|
404
|
+
: null;
|
|
405
|
+
if (!source && onRetry) {
|
|
406
|
+
onRetry();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
391
409
|
preparedRequestRef.current = null;
|
|
392
410
|
setRetryRequest({
|
|
393
411
|
originalKey: idempotencyKey,
|
|
394
412
|
key: crypto.randomUUID(),
|
|
413
|
+
attemptId: source,
|
|
395
414
|
});
|
|
396
|
-
}
|
|
415
|
+
}, className: 'solidgate-checkout-action solidgate-checkout-action--spaced', children: copy.retry })) : null] }));
|
|
397
416
|
const paymentForm = view.checkout ? (_jsx(SolidgatePaymentForm, { walletOnly: layout === 'wallet', secureLabel: presentation === null || presentation === void 0 ? void 0 : presentation.secureLabel, cardLabel: presentation === null || presentation === void 0 ? void 0 : presentation.cardLabel, paymentMethodLabel: presentation === null || presentation === void 0 ? void 0 : presentation.paymentMethodLabel, buttonColor: (presentation === null || presentation === void 0 ? void 0 : presentation.buttonColor) || '#3f51b5', cardSubmitLabel: (presentation === null || presentation === void 0 ? void 0 : presentation.cardSubmitLabel) || 'Pay securely', checkout: view.checkout, hidden: !showForm, loadingLabel: copy.loading, onMounted: () => {
|
|
398
417
|
var _a;
|
|
399
418
|
setMountedPaymentAttemptId(((_a = view.checkout) === null || _a === void 0 ? void 0 : _a.attemptId) || null);
|
|
@@ -56,7 +56,7 @@ export type SolidgateCheckoutDialogProps = {
|
|
|
56
56
|
onCustomerEmailCommit?: (email: string) => Promise<string>;
|
|
57
57
|
onSuccess?: (checkout: SolidgateCheckoutPreparation) => void | Promise<void>;
|
|
58
58
|
onRetry?: () => void;
|
|
59
|
-
onError?: (message: string) => void;
|
|
59
|
+
onError?: (message: string, code?: 'already_subscribed_to_product') => void;
|
|
60
60
|
onPreparationStart?: () => void;
|
|
61
61
|
/** True while a submitted payment still needs verification (including resumable errors). */
|
|
62
62
|
onPaymentPendingChange?: (pending: boolean) => void;
|
|
@@ -33,7 +33,7 @@ export function SolidgatePaymentForm({ buttonColor, walletOnly = false, cardSubm
|
|
|
33
33
|
].filter((method) => Boolean(method));
|
|
34
34
|
setWallets((previous) => previous.join() === available.join() ? previous : available);
|
|
35
35
|
if (!mountedReportedRef.current
|
|
36
|
-
&& boundary.querySelector('iframe#solid-payment-form-iframe, iframe[name="solid-payment-form-iframe"]')) {
|
|
36
|
+
&& boundary.querySelector('iframe#payment-form-iframe, iframe[name="payment-form-iframe"], iframe#solid-payment-form-iframe, iframe[name="solid-payment-form-iframe"]')) {
|
|
37
37
|
mountedReportedRef.current = true;
|
|
38
38
|
onMountedRef.current();
|
|
39
39
|
}
|
|
@@ -44,7 +44,7 @@ export function SolidgatePaymentForm({ buttonColor, walletOnly = false, cardSubm
|
|
|
44
44
|
return () => observer.disconnect();
|
|
45
45
|
}, [checkout.attemptId]);
|
|
46
46
|
const walletButtonType = checkout.display.billingInterval ? 'subscribe' : 'buy';
|
|
47
|
-
return (_jsxs("div", { ref: paymentBoundaryRef, className: `solidgate-checkout-payment${secureLabel && !walletOnly ? ' is-branded' : ''}`, "data-solidgate-attempt-id": checkout.attemptId, hidden: hidden, "aria-hidden": hidden || undefined, children: [showTabs ? (_jsxs("div", { className: 'solidgate-checkout-methods', role: 'tablist', "aria-label": paymentMethodLabel, children: [_jsx("button", { type: 'button', role: 'tab', id: `${panelId}-wallet-tab`, "aria-label": wallets.join(' / '), "aria-selected": selectedMethod === 'wallet', "aria-controls": `${panelId}-wallet`, className: 'solidgate-checkout-method', onClick: () => setSelectedMethod('wallet'), children: wallets.map((label) => _jsx(PaymentBrandMark, { label: label, className: 'solidgate-checkout-tab-wallet' }, label)) }), _jsxs("button", { type: 'button', role: 'tab', id: `${panelId}-card-tab`, "aria-selected": selectedMethod === 'card', "aria-controls": `${panelId}-card`, className: 'solidgate-checkout-method', onClick: () => setSelectedMethod('card'), children: [_jsx("strong", { children: cardLabel }), _jsx("span", { className: 'solidgate-checkout-tab-brands', "aria-hidden": 'true', children: ['Visa', 'Mastercard', 'Maestro', 'Discover'].map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'solidgate-checkout-tab-brand' }, label))) })] })] })) : null, !walletOnly && secureLabel && wallets.length > 0 && showWallet ? (_jsxs("p", { className: 'solidgate-checkout-secure', children: [_jsx(SecurityLockIcon, {}), secureLabel] })) : null, _jsxs("div", { className: 'solidgate-checkout-wallets', id: `${panelId}-wallet`, role: showTabs ? 'tabpanel' : undefined, "aria-labelledby": showTabs ? `${panelId}-wallet-tab` : undefined, hidden: !showWallet, children: [_jsx("div", { ref: applePayContainerRef, "data-solidgate-wallet": 'apple-pay' }), _jsx("div", { ref: googlePayContainerRef, "data-solidgate-wallet": 'google-pay' })] }), _jsx("div", { className: 'solidgate-checkout-card', id: `${panelId}-card`, role: showTabs ? 'tabpanel' : undefined, "aria-labelledby": showTabs ? `${panelId}-card-tab` : undefined, hidden: !showCard, children: _jsx(SolidgateSdkPayment, { onInitializationError: onError, merchantData: checkout.initialization.merchantData, width: '100%', formParams: Object.assign({ autoFocus: false, enabled: !walletOnly, isSolidLogoVisible:
|
|
47
|
+
return (_jsxs("div", { ref: paymentBoundaryRef, className: `solidgate-checkout-payment${secureLabel && !walletOnly ? ' is-branded' : ''}`, "data-solidgate-attempt-id": checkout.attemptId, hidden: hidden, "aria-hidden": hidden || undefined, children: [showTabs ? (_jsxs("div", { className: 'solidgate-checkout-methods', role: 'tablist', "aria-label": paymentMethodLabel, children: [_jsx("button", { type: 'button', role: 'tab', id: `${panelId}-wallet-tab`, "aria-label": wallets.join(' / '), "aria-selected": selectedMethod === 'wallet', "aria-controls": `${panelId}-wallet`, className: 'solidgate-checkout-method', onClick: () => setSelectedMethod('wallet'), children: wallets.map((label) => _jsx(PaymentBrandMark, { label: label, className: 'solidgate-checkout-tab-wallet' }, label)) }), _jsxs("button", { type: 'button', role: 'tab', id: `${panelId}-card-tab`, "aria-selected": selectedMethod === 'card', "aria-controls": `${panelId}-card`, className: 'solidgate-checkout-method', onClick: () => setSelectedMethod('card'), children: [_jsx("strong", { children: cardLabel }), _jsx("span", { className: 'solidgate-checkout-tab-brands', "aria-hidden": 'true', children: ['Visa', 'Mastercard', 'Maestro', 'Discover'].map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'solidgate-checkout-tab-brand' }, label))) })] })] })) : null, !walletOnly && secureLabel && wallets.length > 0 && showWallet ? (_jsxs("p", { className: 'solidgate-checkout-secure', children: [_jsx(SecurityLockIcon, {}), secureLabel] })) : null, _jsxs("div", { className: 'solidgate-checkout-wallets', id: `${panelId}-wallet`, role: showTabs ? 'tabpanel' : undefined, "aria-labelledby": showTabs ? `${panelId}-wallet-tab` : undefined, hidden: !showWallet, children: [_jsx("div", { ref: applePayContainerRef, "data-solidgate-wallet": 'apple-pay' }), _jsx("div", { ref: googlePayContainerRef, "data-solidgate-wallet": 'google-pay' })] }), _jsx("div", { className: 'solidgate-checkout-card', id: `${panelId}-card`, role: showTabs ? 'tabpanel' : undefined, "aria-labelledby": showTabs ? `${panelId}-card-tab` : undefined, hidden: !showCard, children: _jsx(SolidgateSdkPayment, { onInitializationError: onError, merchantData: checkout.initialization.merchantData, width: '100%', formParams: Object.assign({ autoFocus: false, enabled: !walletOnly, isSolidLogoVisible: false, submitButtonText: cardSubmitLabel }, (secureLabel ? { cardNumberLabel: 'Card number', cardExpiryDateLabel: 'Expiration date', cardCvvLabel: 'Security code' } : {})), styles: {
|
|
48
48
|
form_body: {
|
|
49
49
|
'font-family': 'Inter, Arial, sans-serif',
|
|
50
50
|
},
|
|
@@ -23,7 +23,7 @@ export function SolidgateSdkPayment(props) {
|
|
|
23
23
|
google.id = `${id}-google`;
|
|
24
24
|
void import('@solidgate/react-sdk').then(async (sdk) => {
|
|
25
25
|
var _a, _b;
|
|
26
|
-
const loaded = await sdk.SdkLoader.load();
|
|
26
|
+
const loaded = await sdk.SdkLoader.load('https://cdn.charge-auth.com/js/form.js');
|
|
27
27
|
if (!active || !loaded)
|
|
28
28
|
return;
|
|
29
29
|
client = loaded;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type FunnelSdkRuntimeConfigOverrides } from '@funnelsgrove/runtime';
|
|
2
2
|
export type SolidgateCheckoutStatus = 'preparing' | 'requires_payment' | 'verifying' | 'succeeded' | 'failed' | 'expired';
|
|
3
|
+
export declare class SolidgateExistingSubscriptionError extends Error {
|
|
4
|
+
readonly code: "already_subscribed_to_product";
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
3
7
|
export type SolidgateCheckoutPreparation = {
|
|
4
8
|
attemptId: string;
|
|
5
9
|
display: {
|
|
@@ -31,6 +35,7 @@ export type PrepareSolidgateCheckoutInput = {
|
|
|
31
35
|
checkoutType?: 'subscription' | 'one_time' | null;
|
|
32
36
|
environment?: 'test' | 'live' | null;
|
|
33
37
|
idempotencyKey: string;
|
|
38
|
+
retryAttemptId?: string | null;
|
|
34
39
|
discountKeyOrProviderId?: string | null;
|
|
35
40
|
returnUrl: string;
|
|
36
41
|
successUrl: string;
|
|
@@ -49,6 +54,7 @@ export type SolidgateCheckoutStatusResponse = {
|
|
|
49
54
|
attemptId: string;
|
|
50
55
|
status: SolidgateCheckoutStatus;
|
|
51
56
|
retryAfterMs: number | null;
|
|
57
|
+
failureCode?: string;
|
|
52
58
|
};
|
|
53
59
|
export type PollSolidgateCheckoutStatusResult = SolidgateCheckoutStatusResponse & {
|
|
54
60
|
timedOut: boolean;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { paywallCheckoutReturnUrl, retainPaywallCheckout, FUNNEL_ID, FUNNEL_SDK_PUBLISHABLE_KEY, buildMainApiUrl, resolvePreviewPaymentPublishableKey, } from '@funnelsgrove/runtime';
|
|
2
|
+
export class SolidgateExistingSubscriptionError extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super('You already have an active subscription to this product.');
|
|
5
|
+
this.code = 'already_subscribed_to_product';
|
|
6
|
+
this.name = 'SolidgateExistingSubscriptionError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
2
9
|
const trimTrailingSlash = (value) => value.replace(/\/+$/, '');
|
|
3
10
|
const requiredString = (value, name) => {
|
|
4
11
|
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
@@ -28,6 +35,13 @@ const postJson = async (path, body, runtimeConfig, signal) => {
|
|
|
28
35
|
signal,
|
|
29
36
|
});
|
|
30
37
|
if (!response.ok) {
|
|
38
|
+
if (response.status === 409) {
|
|
39
|
+
const payload = await response.json().catch(() => null);
|
|
40
|
+
if (payload && typeof payload === 'object' && 'code' in payload
|
|
41
|
+
&& payload.code === 'already_subscribed_to_product') {
|
|
42
|
+
throw new SolidgateExistingSubscriptionError();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
31
45
|
throw new Error('Solidgate checkout is temporarily unavailable');
|
|
32
46
|
}
|
|
33
47
|
return response.json();
|
|
@@ -103,11 +117,8 @@ const parseStatus = (value) => {
|
|
|
103
117
|
&& (typeof retryAfterMs !== 'number' || !Number.isFinite(retryAfterMs) || retryAfterMs < 0)) {
|
|
104
118
|
throw new Error('Solidgate checkout status returned an invalid retry delay');
|
|
105
119
|
}
|
|
106
|
-
return {
|
|
107
|
-
|
|
108
|
-
status: value.status,
|
|
109
|
-
retryAfterMs,
|
|
110
|
-
};
|
|
120
|
+
return Object.assign({ attemptId: requiredString(value.attemptId, 'attemptId'), status: value.status, retryAfterMs }, (value.status === 'failed' && typeof value.failureCode === 'string'
|
|
121
|
+
&& /^\d\.\d{2}$/.test(value.failureCode) ? { failureCode: value.failureCode } : {}));
|
|
111
122
|
};
|
|
112
123
|
export const prepareSolidgateCheckout = async (input) => {
|
|
113
124
|
var _a, _b, _c;
|
|
@@ -118,23 +129,8 @@ export const prepareSolidgateCheckout = async (input) => {
|
|
|
118
129
|
if (!paymentProfileId || !providerPlanId || !checkoutType || !environment) {
|
|
119
130
|
throw new Error('Solidgate V2 checkout selection is incomplete');
|
|
120
131
|
}
|
|
121
|
-
const result = parsePreparation(await postJson('/sdk/public/v2/payments/checkout-sessions', {
|
|
122
|
-
|
|
123
|
-
uiMode: 'custom',
|
|
124
|
-
environment,
|
|
125
|
-
paymentProfileId,
|
|
126
|
-
provider: 'solidgate',
|
|
127
|
-
providerPlanId,
|
|
128
|
-
planKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'),
|
|
129
|
-
funnelId: resolveFunnelId(input.funnelId, input.runtimeConfig),
|
|
130
|
-
funnelEndUserId: requiredString(input.funnelEndUserId, 'funnelEndUserId'),
|
|
131
|
-
offerSetId: requiredString(input.offerSetId, 'offerSetId'),
|
|
132
|
-
idempotencyKey: requiredString(input.idempotencyKey, 'idempotencyKey'),
|
|
133
|
-
couponId: ((_c = input.discountKeyOrProviderId) === null || _c === void 0 ? void 0 : _c.trim()) || null,
|
|
134
|
-
returnUrl: paywallCheckoutReturnUrl(requiredString(input.returnUrl, 'returnUrl'), 'solidgate'),
|
|
135
|
-
successUrl: paywallCheckoutReturnUrl(requiredString(input.successUrl, 'successUrl'), 'solidgate'),
|
|
136
|
-
failUrl: paywallCheckoutReturnUrl(requiredString(input.failUrl, 'failUrl'), 'solidgate', true),
|
|
137
|
-
}, input.runtimeConfig, input.signal));
|
|
132
|
+
const result = parsePreparation(await postJson('/sdk/public/v2/payments/checkout-sessions', Object.assign(Object.assign({ checkoutType, uiMode: 'custom', environment,
|
|
133
|
+
paymentProfileId, provider: 'solidgate', providerPlanId, planKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'), funnelId: resolveFunnelId(input.funnelId, input.runtimeConfig), funnelEndUserId: requiredString(input.funnelEndUserId, 'funnelEndUserId'), offerSetId: requiredString(input.offerSetId, 'offerSetId'), idempotencyKey: requiredString(input.idempotencyKey, 'idempotencyKey') }, (input.retryAttemptId ? { retryAttemptId: input.retryAttemptId } : {})), { couponId: ((_c = input.discountKeyOrProviderId) === null || _c === void 0 ? void 0 : _c.trim()) || null, returnUrl: paywallCheckoutReturnUrl(requiredString(input.returnUrl, 'returnUrl'), 'solidgate'), successUrl: paywallCheckoutReturnUrl(requiredString(input.successUrl, 'successUrl'), 'solidgate'), failUrl: paywallCheckoutReturnUrl(requiredString(input.failUrl, 'failUrl'), 'solidgate', true) }), input.runtimeConfig, input.signal));
|
|
138
134
|
retainPaywallCheckout('solidgate', result.attemptId);
|
|
139
135
|
return result;
|
|
140
136
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const solidgateDeclineMessage: (code?: string) => string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Customer-safe descriptions; never render raw processor messages or risk decisions.
|
|
2
|
+
// https://docs.solidgate.com/payments/payments-insights/error-codes/
|
|
3
|
+
const messages = {
|
|
4
|
+
'0.02': 'The payment session expired. Start a new checkout to continue.',
|
|
5
|
+
'2.04': 'This card type is not supported. Use another payment method.',
|
|
6
|
+
'2.06': 'The security code is incorrect. Check the code on your card and try again.',
|
|
7
|
+
'2.08': 'The card number is invalid. Check the number and try again.',
|
|
8
|
+
'2.09': 'The card expiration date is invalid. Check the date or use another card.',
|
|
9
|
+
'2.14': 'We could not start this subscription. Check whether you already have access, or contact support.',
|
|
10
|
+
'2.15': 'Your bank requires additional verification. Try again and complete the bank verification step.',
|
|
11
|
+
'3.01': 'Your bank has blocked this card. Contact your bank or use another payment method.',
|
|
12
|
+
'3.02': 'Your card has insufficient funds. Add funds or use another payment method.',
|
|
13
|
+
'3.03': 'This payment exceeds your card limit. Check your limit with your bank or use another card.',
|
|
14
|
+
'3.04': 'Your bank declined this payment. Contact your bank or use another payment method.',
|
|
15
|
+
'3.05': 'Contact your bank to authorize this payment, or use another payment method.',
|
|
16
|
+
'3.06': 'Debit cards cannot be used for this payment. Use a credit card or another payment method.',
|
|
17
|
+
'3.07': 'This card type is not supported. Use another payment method.',
|
|
18
|
+
'3.09': 'Your bank requires additional verification. Try again and complete the bank verification step.',
|
|
19
|
+
'3.11': 'Recurring payments are not authorized for this card. Use another payment method.',
|
|
20
|
+
'3.13': 'The payment was cancelled. Try again and keep the payment window open until it finishes.',
|
|
21
|
+
'4.08': 'The billing address does not match your card. Check the address with your bank and try again.',
|
|
22
|
+
};
|
|
23
|
+
export const solidgateDeclineMessage = (code) => ((code && Object.hasOwn(messages, code) ? messages[code] : undefined)
|
|
24
|
+
|| 'Your payment was declined. Use another payment method or contact your bank.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnelsgrove/payments",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"jsdom": "20.0.3",
|
|
47
47
|
"typescript": "^5",
|
|
48
48
|
"vitest": "^3.2.4",
|
|
49
|
-
"@funnelsgrove/runtime": "0.
|
|
50
|
-
"@funnelsgrove/analytics": "0.
|
|
49
|
+
"@funnelsgrove/runtime": "0.26.0",
|
|
50
|
+
"@funnelsgrove/analytics": "0.8.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@funnelsgrove/runtime": "^0.
|
|
54
|
-
"@funnelsgrove/analytics": "^0.
|
|
53
|
+
"@funnelsgrove/runtime": "^0.26.0",
|
|
54
|
+
"@funnelsgrove/analytics": "^0.8.0"
|
|
55
55
|
}
|
|
56
56
|
}
|