@tagadapay/plugin-sdk 3.1.12 → 3.1.24
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/build-cdn.js +397 -11
- package/dist/data/iso3166.d.ts +23 -33
- package/dist/data/iso3166.js +134 -198
- package/dist/data/languages.d.ts +5 -64
- package/dist/data/languages.js +23 -143
- package/dist/external-tracker.js +623 -3426
- package/dist/external-tracker.min.js +2 -25
- package/dist/external-tracker.min.js.map +4 -4
- package/dist/react/config/payment.d.ts +14 -4
- package/dist/react/config/payment.js +47 -9
- package/dist/react/hooks/useCheckout.d.ts +3 -0
- package/dist/react/hooks/useCheckout.js +4 -1
- package/dist/react/hooks/useISOData.js +1 -1
- package/dist/react/hooks/usePaymentPolling.d.ts +3 -3
- package/dist/react/hooks/usePluginConfig.js +9 -10
- package/dist/react/providers/TagadaProvider.js +1 -1
- package/dist/tagada-react-sdk-minimal.min.js +36 -0
- package/dist/tagada-react-sdk-minimal.min.js.map +7 -0
- package/dist/tagada-react-sdk.js +37821 -0
- package/dist/tagada-react-sdk.min.js +78 -0
- package/dist/tagada-react-sdk.min.js.map +7 -0
- package/dist/tagada-sdk.js +16044 -0
- package/dist/tagada-sdk.min.js +32 -0
- package/dist/tagada-sdk.min.js.map +7 -0
- package/dist/v2/cdn-react-minimal.d.ts +23 -0
- package/dist/v2/cdn-react-minimal.js +26 -0
- package/dist/v2/core/client.d.ts +4 -2
- package/dist/v2/core/client.js +5 -4
- package/dist/v2/core/config/environment.js +2 -1
- package/dist/v2/core/errors.d.ts +75 -0
- package/dist/v2/core/errors.js +104 -0
- package/dist/v2/core/funnelClient.d.ts +100 -10
- package/dist/v2/core/funnelClient.js +121 -27
- package/dist/v2/core/isoData.d.ts +4 -4
- package/dist/v2/core/isoData.js +7 -7
- package/dist/v2/core/pixelMapping.d.ts +49 -0
- package/dist/v2/core/pixelMapping.js +363 -0
- package/dist/v2/core/resources/apiClient.d.ts +2 -0
- package/dist/v2/core/resources/apiClient.js +52 -9
- package/dist/v2/core/resources/checkout.d.ts +99 -30
- package/dist/v2/core/resources/checkout.js +14 -0
- package/dist/v2/core/resources/customer.d.ts +20 -19
- package/dist/v2/core/resources/expressPaymentMethods.d.ts +1 -0
- package/dist/v2/core/resources/funnel.d.ts +17 -17
- package/dist/v2/core/resources/payments.d.ts +89 -13
- package/dist/v2/core/resources/payments.js +27 -9
- package/dist/v2/core/resources/postPurchases.d.ts +17 -0
- package/dist/v2/core/resources/postPurchases.js +20 -0
- package/dist/v2/core/types.d.ts +50 -12
- package/dist/v2/core/types.js +0 -3
- package/dist/v2/core/utils/checkout.d.ts +2 -2
- package/dist/v2/core/utils/checkout.js +7 -2
- package/dist/v2/core/utils/currency.d.ts +14 -0
- package/dist/v2/core/utils/currency.js +40 -0
- package/dist/v2/core/utils/deviceInfo.d.ts +0 -10
- package/dist/v2/core/utils/deviceInfo.js +152 -76
- package/dist/v2/core/utils/index.d.ts +1 -0
- package/dist/v2/core/utils/index.js +2 -0
- package/dist/v2/core/utils/order.d.ts +13 -9
- package/dist/v2/core/utils/pluginConfig.d.ts +8 -0
- package/dist/v2/core/utils/pluginConfig.js +36 -12
- package/dist/v2/index.d.ts +6 -3
- package/dist/v2/index.js +4 -2
- package/dist/v2/react/components/FunnelScriptInjector.js +166 -77
- package/dist/v2/react/components/StripeExpressButton.d.ts +13 -0
- package/dist/v2/react/components/StripeExpressButton.js +171 -0
- package/dist/v2/react/components/WhopCheckout.d.ts +24 -0
- package/dist/v2/react/components/WhopCheckout.js +237 -0
- package/dist/v2/react/hooks/__examples__/FunnelContextExample.js +1 -1
- package/dist/v2/react/hooks/payment-actions/useAirwallexRadarAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useAirwallexRadarAction.js +181 -0
- package/dist/v2/react/hooks/payment-actions/useErrorAction.d.ts +9 -0
- package/dist/v2/react/hooks/payment-actions/useErrorAction.js +21 -0
- package/dist/v2/react/hooks/payment-actions/useFinixRadarAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useFinixRadarAction.js +187 -0
- package/dist/v2/react/hooks/payment-actions/useKessPayAction.d.ts +11 -0
- package/dist/v2/react/hooks/payment-actions/useKessPayAction.js +91 -0
- package/dist/v2/react/hooks/payment-actions/useMasterCardAction.d.ts +24 -0
- package/dist/v2/react/hooks/payment-actions/useMasterCardAction.js +221 -0
- package/dist/v2/react/hooks/payment-actions/usePaymentActionHandler.d.ts +15 -0
- package/dist/v2/react/hooks/payment-actions/usePaymentActionHandler.js +142 -0
- package/dist/v2/react/hooks/payment-actions/useProcessorAuthAction.d.ts +3 -0
- package/dist/v2/react/hooks/payment-actions/useProcessorAuthAction.js +31 -0
- package/dist/v2/react/hooks/payment-actions/useRedirectAction.d.ts +10 -0
- package/dist/v2/react/hooks/payment-actions/useRedirectAction.js +35 -0
- package/dist/v2/react/hooks/payment-actions/useStripeRadarAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useStripeRadarAction.js +192 -0
- package/dist/v2/react/hooks/payment-actions/useThreedsAuthAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useThreedsAuthAction.js +81 -0
- package/dist/v2/react/hooks/payment-actions/useTrustFlowAction.d.ts +11 -0
- package/dist/v2/react/hooks/payment-actions/useTrustFlowAction.js +84 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentInstruments.d.ts +14 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentInstruments.js +36 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentProcessors.d.ts +31 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentProcessors.js +212 -0
- package/dist/v2/react/hooks/payment-redirect/useAirwallex3dsReturn.d.ts +14 -0
- package/dist/v2/react/hooks/payment-redirect/useAirwallex3dsReturn.js +207 -0
- package/dist/v2/react/hooks/payment-redirect/useGenericPaymentReturn.d.ts +12 -0
- package/dist/v2/react/hooks/payment-redirect/useGenericPaymentReturn.js +101 -0
- package/dist/v2/react/hooks/useApplePayCheckout.js +8 -8
- package/dist/v2/react/hooks/useCheckoutQuery.d.ts +16 -0
- package/dist/v2/react/hooks/useCheckoutQuery.js +63 -10
- package/dist/v2/react/hooks/useFunnel.d.ts +15 -4
- package/dist/v2/react/hooks/useFunnel.js +8 -4
- package/dist/v2/react/hooks/useGeoLocation.d.ts +2 -1
- package/dist/v2/react/hooks/useGeoLocation.js +4 -2
- package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +2 -0
- package/dist/v2/react/hooks/useGoogleAutocomplete.js +29 -15
- package/dist/v2/react/hooks/useISOData.d.ts +2 -5
- package/dist/v2/react/hooks/useISOData.js +26 -27
- package/dist/v2/react/hooks/usePaymentPolling.d.ts +3 -3
- package/dist/v2/react/hooks/usePaymentQuery.d.ts +18 -5
- package/dist/v2/react/hooks/usePaymentQuery.js +63 -1015
- package/dist/v2/react/hooks/usePaymentRetrieve.d.ts +3 -2
- package/dist/v2/react/hooks/usePaymentRetrieve.js +3 -1
- package/dist/v2/react/hooks/usePixelTracking.d.ts +5 -48
- package/dist/v2/react/hooks/usePixelTracking.js +283 -504
- package/dist/v2/react/hooks/usePostPurchasesQuery.js +34 -2
- package/dist/v2/react/hooks/useRemappableParams.d.ts +2 -6
- package/dist/v2/react/hooks/useRemappableParams.js +23 -23
- package/dist/v2/react/hooks/useSetPaymentMethod.d.ts +16 -0
- package/dist/v2/react/hooks/useSetPaymentMethod.js +33 -0
- package/dist/v2/react/hooks/useShippingRatesQuery.js +13 -5
- package/dist/v2/react/hooks/useStepConfig.d.ts +23 -6
- package/dist/v2/react/hooks/useStepConfig.js +14 -7
- package/dist/v2/react/hooks/useTranslation.js +23 -8
- package/dist/v2/react/hooks/useWhopPaymentPolling.d.ts +30 -0
- package/dist/v2/react/hooks/useWhopPaymentPolling.js +61 -0
- package/dist/v2/react/index.d.ts +15 -1
- package/dist/v2/react/index.js +7 -0
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +3 -1
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +12 -2
- package/dist/v2/react/providers/TagadaProvider.js +74 -5
- package/dist/v2/standalone/external-tracker.d.ts +52 -46
- package/dist/v2/standalone/external-tracker.js +205 -98
- package/dist/v2/standalone/index.d.ts +40 -0
- package/dist/v2/standalone/index.js +148 -1
- package/dist/v2/standalone/payment-service.d.ts +134 -0
- package/dist/v2/standalone/payment-service.js +928 -0
- package/package.json +6 -4
- package/dist/react/utils/__tests__/urlUtils.test.d.ts +0 -1
- package/dist/react/utils/__tests__/urlUtils.test.js +0 -189
- package/dist/v2/core/__tests__/pathRemapping.test.d.ts +0 -11
- package/dist/v2/core/__tests__/pathRemapping.test.js +0 -776
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main payment action handler that routes to specific action handlers
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback, useRef } from 'react';
|
|
5
|
+
import { useThreedsAuthAction } from './useThreedsAuthAction';
|
|
6
|
+
import { useProcessorAuthAction } from './useProcessorAuthAction';
|
|
7
|
+
import { useRedirectAction } from './useRedirectAction';
|
|
8
|
+
import { useErrorAction } from './useErrorAction';
|
|
9
|
+
import { useFinixRadarAction } from './useFinixRadarAction';
|
|
10
|
+
import { useAirwallexRadarAction } from './useAirwallexRadarAction';
|
|
11
|
+
import { useStripeRadarAction } from './useStripeRadarAction';
|
|
12
|
+
import { useKessPayAction } from './useKessPayAction';
|
|
13
|
+
import { useTrustFlowAction } from './useTrustFlowAction';
|
|
14
|
+
import { useMasterCardAction } from './useMasterCardAction';
|
|
15
|
+
export function usePaymentActionHandler({ paymentsResource, startChallenge, startPolling, setIsLoading, setError, hookOptionsRef, }) {
|
|
16
|
+
// Track challenge in progress to prevent multiple challenges
|
|
17
|
+
const challengeInProgressRef = useRef(false);
|
|
18
|
+
// Initialize all action handlers
|
|
19
|
+
const { handleThreedsAuth } = useThreedsAuthAction({
|
|
20
|
+
startChallenge,
|
|
21
|
+
startPolling,
|
|
22
|
+
setIsLoading,
|
|
23
|
+
setError,
|
|
24
|
+
hookOptionsRef,
|
|
25
|
+
challengeInProgressRef,
|
|
26
|
+
});
|
|
27
|
+
const { handleProcessorAuth } = useProcessorAuthAction();
|
|
28
|
+
const { handleRedirect } = useRedirectAction({
|
|
29
|
+
setIsLoading,
|
|
30
|
+
hookOptionsRef,
|
|
31
|
+
});
|
|
32
|
+
const { handleError } = useErrorAction({
|
|
33
|
+
setError,
|
|
34
|
+
setIsLoading,
|
|
35
|
+
});
|
|
36
|
+
const { handleFinixRadar } = useFinixRadarAction({
|
|
37
|
+
paymentsResource,
|
|
38
|
+
startPolling,
|
|
39
|
+
setError,
|
|
40
|
+
setIsLoading,
|
|
41
|
+
hookOptionsRef,
|
|
42
|
+
});
|
|
43
|
+
const { handleAirwallexRadar } = useAirwallexRadarAction({
|
|
44
|
+
paymentsResource,
|
|
45
|
+
startPolling,
|
|
46
|
+
setError,
|
|
47
|
+
setIsLoading,
|
|
48
|
+
hookOptionsRef,
|
|
49
|
+
});
|
|
50
|
+
const { handleStripeRadar } = useStripeRadarAction({
|
|
51
|
+
paymentsResource,
|
|
52
|
+
startPolling,
|
|
53
|
+
setError,
|
|
54
|
+
setIsLoading,
|
|
55
|
+
hookOptionsRef,
|
|
56
|
+
});
|
|
57
|
+
const { handleKessPayAuth } = useKessPayAction({
|
|
58
|
+
setError,
|
|
59
|
+
setIsLoading,
|
|
60
|
+
hookOptionsRef,
|
|
61
|
+
});
|
|
62
|
+
const { handleTrustFlowAuth } = useTrustFlowAction({
|
|
63
|
+
setError,
|
|
64
|
+
setIsLoading,
|
|
65
|
+
hookOptionsRef,
|
|
66
|
+
});
|
|
67
|
+
const { handleMasterCardAuth } = useMasterCardAction({
|
|
68
|
+
paymentsResource,
|
|
69
|
+
startPolling,
|
|
70
|
+
setError,
|
|
71
|
+
setIsLoading,
|
|
72
|
+
hookOptionsRef,
|
|
73
|
+
});
|
|
74
|
+
// Main handler that routes to specific action handlers
|
|
75
|
+
const handlePaymentAction = useCallback(async (payment, options = {}) => {
|
|
76
|
+
if (payment.requireAction === 'none')
|
|
77
|
+
return;
|
|
78
|
+
if (payment?.requireActionData?.processed)
|
|
79
|
+
return;
|
|
80
|
+
const actionData = payment.requireActionData;
|
|
81
|
+
if (!actionData)
|
|
82
|
+
return;
|
|
83
|
+
// Mark action as processed
|
|
84
|
+
try {
|
|
85
|
+
await paymentsResource.markPaymentActionProcessed(payment.id);
|
|
86
|
+
}
|
|
87
|
+
catch (_error) {
|
|
88
|
+
// Error handling removed
|
|
89
|
+
}
|
|
90
|
+
// Route to appropriate action handler based on type
|
|
91
|
+
switch (actionData.type) {
|
|
92
|
+
case 'threeds_auth':
|
|
93
|
+
await handleThreedsAuth(payment, actionData, options);
|
|
94
|
+
break;
|
|
95
|
+
case 'processor_auth':
|
|
96
|
+
case 'redirect_to_payment':
|
|
97
|
+
await handleProcessorAuth(actionData);
|
|
98
|
+
break;
|
|
99
|
+
case 'redirect':
|
|
100
|
+
await handleRedirect(payment, actionData, options);
|
|
101
|
+
break;
|
|
102
|
+
case 'error':
|
|
103
|
+
await handleError(payment, actionData, options);
|
|
104
|
+
break;
|
|
105
|
+
case 'finix_radar':
|
|
106
|
+
await handleFinixRadar(payment, actionData, options, handlePaymentAction);
|
|
107
|
+
break;
|
|
108
|
+
case 'stripe_radar':
|
|
109
|
+
await handleStripeRadar(payment, actionData, options, handlePaymentAction);
|
|
110
|
+
break;
|
|
111
|
+
case 'kesspay_auth':
|
|
112
|
+
await handleKessPayAuth(payment, actionData, options);
|
|
113
|
+
break;
|
|
114
|
+
case 'trustflow_auth':
|
|
115
|
+
await handleTrustFlowAuth(payment, actionData, options);
|
|
116
|
+
break;
|
|
117
|
+
case 'mastercard_auth':
|
|
118
|
+
await handleMasterCardAuth(payment, actionData, options, handlePaymentAction);
|
|
119
|
+
break;
|
|
120
|
+
case 'radar':
|
|
121
|
+
// Check provider for specific implementation
|
|
122
|
+
if (actionData.metadata?.provider === 'airwallex') {
|
|
123
|
+
await handleAirwallexRadar(payment, actionData, options, handlePaymentAction);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
options.onRequireAction?.(payment);
|
|
128
|
+
}, [
|
|
129
|
+
paymentsResource,
|
|
130
|
+
handleThreedsAuth,
|
|
131
|
+
handleProcessorAuth,
|
|
132
|
+
handleRedirect,
|
|
133
|
+
handleError,
|
|
134
|
+
handleFinixRadar,
|
|
135
|
+
handleAirwallexRadar,
|
|
136
|
+
handleStripeRadar,
|
|
137
|
+
handleKessPayAuth,
|
|
138
|
+
handleTrustFlowAuth,
|
|
139
|
+
handleMasterCardAuth,
|
|
140
|
+
]);
|
|
141
|
+
return { handlePaymentAction };
|
|
142
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling processor-specific authentication redirects
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
export function useProcessorAuthAction() {
|
|
6
|
+
const handleProcessorAuth = useCallback(async (actionData) => {
|
|
7
|
+
const redirect = actionData.metadata?.redirect;
|
|
8
|
+
if (!redirect?.redirectUrl)
|
|
9
|
+
return;
|
|
10
|
+
if (redirect.method === 'POST') {
|
|
11
|
+
const form = document.createElement('form');
|
|
12
|
+
form.method = 'POST';
|
|
13
|
+
form.action = redirect.redirectUrl;
|
|
14
|
+
if (redirect.data && typeof redirect.data === 'object') {
|
|
15
|
+
Object.entries(redirect.data).forEach(([key, value]) => {
|
|
16
|
+
const input = document.createElement('input');
|
|
17
|
+
input.type = 'hidden';
|
|
18
|
+
input.name = key;
|
|
19
|
+
input.value = String(value);
|
|
20
|
+
form.appendChild(input);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
document.body.appendChild(form);
|
|
24
|
+
form.submit();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
window.location.href = redirect.redirectUrl;
|
|
28
|
+
}
|
|
29
|
+
}, []);
|
|
30
|
+
return { handleProcessorAuth };
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Payment, PaymentOptions } from '../../../core/resources/payments';
|
|
2
|
+
import type { UsePaymentOptions } from '../usePaymentQuery';
|
|
3
|
+
interface UseRedirectActionParams {
|
|
4
|
+
setIsLoading: (loading: boolean) => void;
|
|
5
|
+
hookOptionsRef: React.MutableRefObject<UsePaymentOptions | undefined>;
|
|
6
|
+
}
|
|
7
|
+
export declare function useRedirectAction({ setIsLoading, hookOptionsRef }: UseRedirectActionParams): {
|
|
8
|
+
handleRedirect: (payment: Payment, actionData: any, options?: PaymentOptions) => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling generic redirect actions
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
export function useRedirectAction({ setIsLoading, hookOptionsRef }) {
|
|
6
|
+
const handleRedirect = useCallback(async (payment, actionData, options = {}) => {
|
|
7
|
+
// For redirect type, let funnel orchestrator handle navigation via callbacks
|
|
8
|
+
// Only auto-redirect if explicitly enabled (disableAutoRedirect: false)
|
|
9
|
+
const shouldAutoRedirect = options.disableAutoRedirect === false;
|
|
10
|
+
if (shouldAutoRedirect && actionData.metadata?.redirect?.redirectUrl) {
|
|
11
|
+
window.location.href = actionData.metadata.redirect.redirectUrl;
|
|
12
|
+
}
|
|
13
|
+
else if (payment.status === 'succeeded') {
|
|
14
|
+
// Payment succeeded - call success callbacks for funnel navigation
|
|
15
|
+
setIsLoading(false);
|
|
16
|
+
const response = {
|
|
17
|
+
paymentId: payment.id,
|
|
18
|
+
payment,
|
|
19
|
+
order: payment.order,
|
|
20
|
+
};
|
|
21
|
+
// Hook-level callback (universal handler)
|
|
22
|
+
if (hookOptionsRef.current?.onPaymentCompleted) {
|
|
23
|
+
await hookOptionsRef.current.onPaymentCompleted(payment, {
|
|
24
|
+
isRedirectReturn: false,
|
|
25
|
+
order: response.order,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// Legacy callback (backwards compatibility)
|
|
29
|
+
options.onSuccess?.(response);
|
|
30
|
+
// Funnel-aligned callback (recommended)
|
|
31
|
+
options.onPaymentSuccess?.(response);
|
|
32
|
+
}
|
|
33
|
+
}, [setIsLoading, hookOptionsRef]);
|
|
34
|
+
return { handleRedirect };
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Payment, PaymentOptions } from '../../../core/resources/payments';
|
|
2
|
+
import type { PaymentsResource } from '../../../core/resources/payments';
|
|
3
|
+
import type { UsePaymentOptions } from '../usePaymentQuery';
|
|
4
|
+
interface UseStripeRadarActionParams {
|
|
5
|
+
paymentsResource: PaymentsResource;
|
|
6
|
+
startPolling: any;
|
|
7
|
+
setError: (error: string | null) => void;
|
|
8
|
+
setIsLoading: (loading: boolean) => void;
|
|
9
|
+
hookOptionsRef: React.MutableRefObject<UsePaymentOptions | undefined>;
|
|
10
|
+
}
|
|
11
|
+
export declare function useStripeRadarAction({ paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef, }: UseStripeRadarActionParams): {
|
|
12
|
+
handleStripeRadar: (payment: Payment, actionData: any, options: PaymentOptions | undefined, handlePaymentAction: any) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling Stripe Radar fraud detection
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback, useRef } from 'react';
|
|
5
|
+
export function useStripeRadarAction({ paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef, }) {
|
|
6
|
+
const scriptLoadingRef = useRef(false);
|
|
7
|
+
const handleStripeRadar = useCallback(async (payment, actionData, options = {}, handlePaymentAction) => {
|
|
8
|
+
const radarConfig = actionData.metadata?.radar;
|
|
9
|
+
if (!radarConfig?.publishableKey) {
|
|
10
|
+
console.error('Stripe radar config missing from payment action');
|
|
11
|
+
setError('Missing Stripe Radar configuration');
|
|
12
|
+
setIsLoading(false);
|
|
13
|
+
options.onFailure?.('Missing Stripe Radar configuration');
|
|
14
|
+
options.onPaymentFailed?.({
|
|
15
|
+
code: 'STRIPE_RADAR_MISSING_CONFIG',
|
|
16
|
+
message: 'Missing Stripe Radar configuration',
|
|
17
|
+
payment,
|
|
18
|
+
});
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
// Load Stripe if not already loaded
|
|
23
|
+
if (typeof window !== 'undefined' && typeof window.Stripe !== 'function' && !scriptLoadingRef.current) {
|
|
24
|
+
console.log('Loading Stripe script...');
|
|
25
|
+
scriptLoadingRef.current = true;
|
|
26
|
+
// Check if script already exists
|
|
27
|
+
const existingScript = document.querySelector('script[src="https://js.stripe.com/v3/"]');
|
|
28
|
+
if (existingScript) {
|
|
29
|
+
console.log('Stripe script already exists, waiting for load...');
|
|
30
|
+
if (typeof window.Stripe === 'function') {
|
|
31
|
+
console.log('Stripe already loaded');
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Wait for existing script to load
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
const checkStripe = () => {
|
|
37
|
+
if (typeof window.Stripe === 'function') {
|
|
38
|
+
resolve();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
setTimeout(checkStripe, 100);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
checkStripe();
|
|
45
|
+
setTimeout(() => reject(new Error('Timeout waiting for Stripe')), 10000);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const script = document.createElement('script');
|
|
51
|
+
script.src = 'https://js.stripe.com/v3/';
|
|
52
|
+
script.async = true;
|
|
53
|
+
document.head.appendChild(script);
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
script.onload = () => {
|
|
56
|
+
console.log('Stripe script loaded successfully');
|
|
57
|
+
scriptLoadingRef.current = false;
|
|
58
|
+
resolve();
|
|
59
|
+
};
|
|
60
|
+
script.onerror = () => {
|
|
61
|
+
scriptLoadingRef.current = false;
|
|
62
|
+
reject(new Error('Failed to load Stripe'));
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
console.log('Initializing Stripe with public key:', radarConfig.publishableKey);
|
|
68
|
+
const stripe = window.Stripe(radarConfig.publishableKey);
|
|
69
|
+
const result = await stripe.createRadarSession();
|
|
70
|
+
console.log('Stripe Radar result:', result);
|
|
71
|
+
if (result.error) {
|
|
72
|
+
const errorMessage = result.error.message || 'Failed to create Radar session';
|
|
73
|
+
console.error('Stripe Radar error:', errorMessage);
|
|
74
|
+
throw new Error(errorMessage);
|
|
75
|
+
}
|
|
76
|
+
if (!result.radarSession) {
|
|
77
|
+
const errorMessage = 'No radar session returned from Stripe';
|
|
78
|
+
console.error(errorMessage);
|
|
79
|
+
throw new Error(errorMessage);
|
|
80
|
+
}
|
|
81
|
+
console.log('Stripe Radar session created:', result.radarSession);
|
|
82
|
+
// Save radar session to database
|
|
83
|
+
await paymentsResource.saveRadarSession({
|
|
84
|
+
orderId: radarConfig.orderId,
|
|
85
|
+
stripeRadarSessionId: result.radarSession.id,
|
|
86
|
+
stripeRadarSessionData: result.radarSession,
|
|
87
|
+
});
|
|
88
|
+
console.log('Radar session saved to database');
|
|
89
|
+
// Resume payment by calling completePaymentAfterAction
|
|
90
|
+
const resumedPayment = await paymentsResource.completePaymentAfterAction(payment.id);
|
|
91
|
+
console.log('Payment resumed after Stripe radar:', resumedPayment);
|
|
92
|
+
// Handle the resumed payment response
|
|
93
|
+
if (resumedPayment.status === 'declined' || resumedPayment.status === 'failed') {
|
|
94
|
+
// Payment declined or failed - extract error message from response
|
|
95
|
+
const errorMsg = resumedPayment.error?.message
|
|
96
|
+
|| resumedPayment.error?.processorMessage
|
|
97
|
+
|| 'Payment declined';
|
|
98
|
+
console.error('❌ [usePayment] Payment declined after Stripe radar:', errorMsg);
|
|
99
|
+
setError(errorMsg);
|
|
100
|
+
setIsLoading(false);
|
|
101
|
+
options.onFailure?.(errorMsg);
|
|
102
|
+
options.onPaymentFailed?.({
|
|
103
|
+
code: resumedPayment.error?.code || 'PAYMENT_DECLINED',
|
|
104
|
+
message: errorMsg,
|
|
105
|
+
payment: resumedPayment,
|
|
106
|
+
});
|
|
107
|
+
// Hook-level callback (universal handler)
|
|
108
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
109
|
+
hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
110
|
+
isRedirectReturn: false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (resumedPayment.status === 'succeeded') {
|
|
115
|
+
// Payment succeeded
|
|
116
|
+
setIsLoading(false);
|
|
117
|
+
const response = {
|
|
118
|
+
paymentId: resumedPayment.id,
|
|
119
|
+
payment: resumedPayment,
|
|
120
|
+
order: resumedPayment.order,
|
|
121
|
+
};
|
|
122
|
+
// Hook-level callback (universal handler)
|
|
123
|
+
if (hookOptionsRef.current?.onPaymentCompleted) {
|
|
124
|
+
await hookOptionsRef.current.onPaymentCompleted(resumedPayment, {
|
|
125
|
+
isRedirectReturn: false,
|
|
126
|
+
order: response.order,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
options.onSuccess?.(response);
|
|
130
|
+
options.onPaymentSuccess?.(response);
|
|
131
|
+
}
|
|
132
|
+
else if (resumedPayment.requireAction !== 'none' && resumedPayment.requireActionData) {
|
|
133
|
+
// Payment requires another action (e.g., 3DS)
|
|
134
|
+
await handlePaymentAction(resumedPayment, options);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Start polling for final status
|
|
138
|
+
startPolling(resumedPayment.id, {
|
|
139
|
+
onRequireAction: (updatedPayment) => {
|
|
140
|
+
void handlePaymentAction(updatedPayment, options);
|
|
141
|
+
},
|
|
142
|
+
onSuccess: async (successPayment) => {
|
|
143
|
+
setIsLoading(false);
|
|
144
|
+
const response = {
|
|
145
|
+
paymentId: successPayment.id,
|
|
146
|
+
payment: successPayment,
|
|
147
|
+
order: successPayment.order,
|
|
148
|
+
};
|
|
149
|
+
// Hook-level callback (universal handler)
|
|
150
|
+
if (hookOptionsRef.current?.onPaymentCompleted) {
|
|
151
|
+
await hookOptionsRef.current.onPaymentCompleted(successPayment, {
|
|
152
|
+
isRedirectReturn: false,
|
|
153
|
+
order: response.order,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
options.onSuccess?.(response);
|
|
157
|
+
options.onPaymentSuccess?.(response);
|
|
158
|
+
},
|
|
159
|
+
onFailure: async (errorMsg) => {
|
|
160
|
+
setError(errorMsg);
|
|
161
|
+
setIsLoading(false);
|
|
162
|
+
// Hook-level callback (universal handler)
|
|
163
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
164
|
+
await hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
165
|
+
isRedirectReturn: false,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
options.onFailure?.(errorMsg);
|
|
169
|
+
options.onPaymentFailed?.({
|
|
170
|
+
code: 'PAYMENT_FAILED',
|
|
171
|
+
message: errorMsg,
|
|
172
|
+
payment,
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (radarError) {
|
|
179
|
+
const errorMsg = radarError instanceof Error ? radarError.message : 'Stripe Radar failed';
|
|
180
|
+
console.error('Stripe radar error:', radarError);
|
|
181
|
+
setError(errorMsg);
|
|
182
|
+
setIsLoading(false);
|
|
183
|
+
options.onFailure?.(errorMsg);
|
|
184
|
+
options.onPaymentFailed?.({
|
|
185
|
+
code: 'STRIPE_RADAR_FAILED',
|
|
186
|
+
message: errorMsg,
|
|
187
|
+
payment,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}, [paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef]);
|
|
191
|
+
return { handleStripeRadar };
|
|
192
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Payment, PaymentOptions } from '../../../core/resources/payments';
|
|
2
|
+
import type { UsePaymentOptions } from '../usePaymentQuery';
|
|
3
|
+
interface UseThreedsAuthActionParams {
|
|
4
|
+
startChallenge: any;
|
|
5
|
+
startPolling: any;
|
|
6
|
+
setIsLoading: (loading: boolean) => void;
|
|
7
|
+
setError: (error: string | null) => void;
|
|
8
|
+
hookOptionsRef: React.MutableRefObject<UsePaymentOptions | undefined>;
|
|
9
|
+
challengeInProgressRef: React.MutableRefObject<boolean>;
|
|
10
|
+
}
|
|
11
|
+
export declare function useThreedsAuthAction({ startChallenge, startPolling, setIsLoading, setError, hookOptionsRef, challengeInProgressRef, }: UseThreedsAuthActionParams): {
|
|
12
|
+
handleThreedsAuth: (payment: Payment, actionData: any, options?: PaymentOptions) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling 3DS authentication actions
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
export function useThreedsAuthAction({ startChallenge, startPolling, setIsLoading, setError, hookOptionsRef, challengeInProgressRef, }) {
|
|
6
|
+
const handleThreedsAuth = useCallback(async (payment, actionData, options = {}) => {
|
|
7
|
+
if (actionData.metadata?.threedsSession && !challengeInProgressRef.current) {
|
|
8
|
+
try {
|
|
9
|
+
challengeInProgressRef.current = true;
|
|
10
|
+
await startChallenge({
|
|
11
|
+
sessionId: actionData.metadata.threedsSession.externalSessionId,
|
|
12
|
+
acsChallengeUrl: actionData.metadata.threedsSession.acsChallengeUrl,
|
|
13
|
+
acsTransactionId: actionData.metadata.threedsSession.acsTransID,
|
|
14
|
+
threeDSVersion: actionData.metadata.threedsSession.messageVersion,
|
|
15
|
+
}, { provider: options.threedsProvider || 'basis_theory' });
|
|
16
|
+
challengeInProgressRef.current = false;
|
|
17
|
+
// Start polling after challenge completion
|
|
18
|
+
if (payment.id) {
|
|
19
|
+
startPolling(payment.id, {
|
|
20
|
+
onRequireAction: (updatedPayment) => {
|
|
21
|
+
// Will be handled by parent
|
|
22
|
+
options.onRequireAction?.(updatedPayment);
|
|
23
|
+
},
|
|
24
|
+
onSuccess: async (successPayment) => {
|
|
25
|
+
setIsLoading(false);
|
|
26
|
+
const response = {
|
|
27
|
+
paymentId: successPayment.id,
|
|
28
|
+
payment: successPayment,
|
|
29
|
+
order: successPayment.order,
|
|
30
|
+
};
|
|
31
|
+
// Hook-level callback (universal handler)
|
|
32
|
+
if (hookOptionsRef.current?.onPaymentCompleted) {
|
|
33
|
+
await hookOptionsRef.current.onPaymentCompleted(successPayment, {
|
|
34
|
+
isRedirectReturn: false,
|
|
35
|
+
order: response.order,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// Legacy callback (backwards compatibility)
|
|
39
|
+
options.onSuccess?.(response);
|
|
40
|
+
// Funnel-aligned callback (recommended)
|
|
41
|
+
options.onPaymentSuccess?.(response);
|
|
42
|
+
},
|
|
43
|
+
onFailure: async (errorMsg) => {
|
|
44
|
+
setError(errorMsg);
|
|
45
|
+
setIsLoading(false);
|
|
46
|
+
// Hook-level callback (universal handler)
|
|
47
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
48
|
+
await hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
49
|
+
isRedirectReturn: false,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Legacy callback (backwards compatibility)
|
|
53
|
+
options.onFailure?.(errorMsg);
|
|
54
|
+
// Funnel-aligned callback (recommended)
|
|
55
|
+
options.onPaymentFailed?.({
|
|
56
|
+
code: 'PAYMENT_FAILED',
|
|
57
|
+
message: errorMsg,
|
|
58
|
+
payment,
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (_error) {
|
|
65
|
+
challengeInProgressRef.current = false;
|
|
66
|
+
const errorMsg = _error instanceof Error ? _error.message : 'Failed to start 3DS challenge';
|
|
67
|
+
setError(errorMsg);
|
|
68
|
+
setIsLoading(false);
|
|
69
|
+
// Legacy callback (backwards compatibility)
|
|
70
|
+
options.onFailure?.(errorMsg);
|
|
71
|
+
// Funnel-aligned callback (recommended)
|
|
72
|
+
options.onPaymentFailed?.({
|
|
73
|
+
code: '3DS_CHALLENGE_FAILED',
|
|
74
|
+
message: errorMsg,
|
|
75
|
+
payment,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}, [startChallenge, startPolling, setIsLoading, setError, hookOptionsRef, challengeInProgressRef]);
|
|
80
|
+
return { handleThreedsAuth };
|
|
81
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Payment, PaymentOptions } from '../../../core/resources/payments';
|
|
2
|
+
import type { UsePaymentOptions } from '../usePaymentQuery';
|
|
3
|
+
interface UseTrustFlowActionParams {
|
|
4
|
+
setError: (error: string | null) => void;
|
|
5
|
+
setIsLoading: (loading: boolean) => void;
|
|
6
|
+
hookOptionsRef: React.MutableRefObject<UsePaymentOptions | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export declare function useTrustFlowAction({ setError, setIsLoading, hookOptionsRef, }: UseTrustFlowActionParams): {
|
|
9
|
+
handleTrustFlowAuth: (payment: Payment, actionData: any, options?: PaymentOptions) => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling Trust Flow 3DS authentication
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback, useRef } from 'react';
|
|
5
|
+
export function useTrustFlowAction({ setError, setIsLoading, hookOptionsRef, }) {
|
|
6
|
+
const challengeInProgressRef = useRef(false);
|
|
7
|
+
const handleTrustFlowAuth = useCallback(async (payment, actionData, options = {}) => {
|
|
8
|
+
if (challengeInProgressRef.current) {
|
|
9
|
+
console.log('Trust Flow 3DS challenge already in progress');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const authData = actionData?.metadata?.trustflow;
|
|
13
|
+
if (!authData?.appId || !authData?.txnId || !authData?.hash) {
|
|
14
|
+
const errorMsg = 'Missing Trust Flow 3DS authentication data';
|
|
15
|
+
console.error(errorMsg);
|
|
16
|
+
setError(errorMsg);
|
|
17
|
+
setIsLoading(false);
|
|
18
|
+
options.onFailure?.(errorMsg);
|
|
19
|
+
options.onPaymentFailed?.({
|
|
20
|
+
code: 'TRUSTFLOW_MISSING_DATA',
|
|
21
|
+
message: errorMsg,
|
|
22
|
+
payment,
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
challengeInProgressRef.current = true;
|
|
28
|
+
setIsLoading(false); // Stop loading before redirect
|
|
29
|
+
console.log('🔐 [Trust Flow] Starting 3DS authentication:', {
|
|
30
|
+
appId: authData.appId,
|
|
31
|
+
txnId: authData.txnId,
|
|
32
|
+
captureUrl: authData.captureUrl,
|
|
33
|
+
testMode: authData.testMode,
|
|
34
|
+
});
|
|
35
|
+
// Create form for Trust Flow 3DS capture request
|
|
36
|
+
const form = document.createElement('form');
|
|
37
|
+
form.method = 'POST';
|
|
38
|
+
form.action = authData.captureUrl;
|
|
39
|
+
form.style.display = 'none';
|
|
40
|
+
// Add required fields for Trust Flow capture
|
|
41
|
+
const appIdInput = document.createElement('input');
|
|
42
|
+
appIdInput.type = 'hidden';
|
|
43
|
+
appIdInput.name = 'APP_ID';
|
|
44
|
+
appIdInput.value = authData.appId;
|
|
45
|
+
form.appendChild(appIdInput);
|
|
46
|
+
const txnIdInput = document.createElement('input');
|
|
47
|
+
txnIdInput.type = 'hidden';
|
|
48
|
+
txnIdInput.name = 'TXN_ID';
|
|
49
|
+
txnIdInput.value = authData.txnId;
|
|
50
|
+
form.appendChild(txnIdInput);
|
|
51
|
+
const hashInput = document.createElement('input');
|
|
52
|
+
hashInput.type = 'hidden';
|
|
53
|
+
hashInput.name = 'HASH';
|
|
54
|
+
hashInput.value = authData.hash;
|
|
55
|
+
form.appendChild(hashInput);
|
|
56
|
+
// Add form to document and submit
|
|
57
|
+
document.body.appendChild(form);
|
|
58
|
+
form.submit();
|
|
59
|
+
console.log('🔐 [Trust Flow] Redirecting to 3DS challenge...');
|
|
60
|
+
// Note: Success callback will be triggered after redirect return
|
|
61
|
+
// Payment status will be updated via webhook
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
challengeInProgressRef.current = false;
|
|
65
|
+
const errorMsg = error instanceof Error ? error.message : 'Failed to process Trust Flow 3DS authentication';
|
|
66
|
+
console.error('🔐 [Trust Flow] 3DS authentication error:', error);
|
|
67
|
+
setError(errorMsg);
|
|
68
|
+
setIsLoading(false);
|
|
69
|
+
options.onFailure?.(errorMsg);
|
|
70
|
+
options.onPaymentFailed?.({
|
|
71
|
+
code: 'TRUSTFLOW_AUTH_FAILED',
|
|
72
|
+
message: errorMsg,
|
|
73
|
+
payment,
|
|
74
|
+
});
|
|
75
|
+
// Hook-level callback (universal handler)
|
|
76
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
77
|
+
hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
78
|
+
isRedirectReturn: false,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, [setError, setIsLoading, hookOptionsRef]);
|
|
83
|
+
return { handleTrustFlowAuth };
|
|
84
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CardPaymentMethod, ApplePayToken, GooglePayToken, BasisTheoryInstance, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse } from '../../../core/resources/payments';
|
|
2
|
+
import type { PaymentsResource } from '../../../core/resources/payments';
|
|
3
|
+
interface UsePaymentInstrumentsParams {
|
|
4
|
+
basisTheory: BasisTheoryInstance | undefined;
|
|
5
|
+
paymentsResource: PaymentsResource;
|
|
6
|
+
setError: (error: string | null) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function usePaymentInstruments({ basisTheory, paymentsResource, setError, }: UsePaymentInstrumentsParams): {
|
|
9
|
+
createCardPaymentInstrument: (cardData: CardPaymentMethod) => Promise<PaymentInstrumentResponse>;
|
|
10
|
+
createApplePayPaymentInstrument: (applePayToken: ApplePayToken) => Promise<PaymentInstrumentResponse>;
|
|
11
|
+
createGooglePayPaymentInstrument: (googlePayToken: GooglePayToken) => Promise<PaymentInstrumentResponse>;
|
|
12
|
+
getCardPaymentInstruments: () => Promise<PaymentInstrumentCustomerResponse>;
|
|
13
|
+
};
|
|
14
|
+
export {};
|