@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,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling Finix fraud detection
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
export function useFinixRadarAction({ paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef, }) {
|
|
6
|
+
const handleFinixRadar = useCallback(async (payment, actionData, options = {}, handlePaymentAction) => {
|
|
7
|
+
const radarConfig = actionData.metadata?.radar;
|
|
8
|
+
if (!radarConfig) {
|
|
9
|
+
console.error('Finix radar config missing from payment action');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
// Dynamically load Finix SDK if not already loaded
|
|
14
|
+
if (typeof window !== 'undefined' && typeof window.Finix?.Auth !== 'function') {
|
|
15
|
+
const existingScript = document.querySelector('script[src="https://js.finix.com/v/1/finix.js"]');
|
|
16
|
+
if (!existingScript) {
|
|
17
|
+
const script = document.createElement('script');
|
|
18
|
+
script.src = 'https://js.finix.com/v/1/finix.js';
|
|
19
|
+
script.async = true;
|
|
20
|
+
document.head.appendChild(script);
|
|
21
|
+
await new Promise((resolve, reject) => {
|
|
22
|
+
script.onload = () => {
|
|
23
|
+
console.log('Finix SDK loaded successfully');
|
|
24
|
+
resolve();
|
|
25
|
+
};
|
|
26
|
+
script.onerror = () => reject(new Error('Failed to load Finix SDK'));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Wait for existing script to load
|
|
31
|
+
await new Promise((resolve, reject) => {
|
|
32
|
+
const checkFinix = () => {
|
|
33
|
+
if (typeof window.Finix?.Auth === 'function') {
|
|
34
|
+
resolve();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
setTimeout(checkFinix, 100);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
checkFinix();
|
|
41
|
+
setTimeout(() => reject(new Error('Timeout waiting for Finix SDK')), 10000);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Get session key from Finix using callback to ensure initialization is complete
|
|
46
|
+
const sessionKey = await new Promise((resolve, reject) => {
|
|
47
|
+
const timeoutId = setTimeout(() => {
|
|
48
|
+
reject(new Error('Timeout waiting for Finix Auth initialization'));
|
|
49
|
+
}, 10000);
|
|
50
|
+
// Initialize Finix Auth with callback
|
|
51
|
+
const FinixAuth = window.Finix.Auth(radarConfig.environment, radarConfig.merchantId, () => {
|
|
52
|
+
// Callback fired when Finix Auth is ready
|
|
53
|
+
clearTimeout(timeoutId);
|
|
54
|
+
const key = FinixAuth.getSessionKey();
|
|
55
|
+
console.log('Finix Auth initialized, session key:', key);
|
|
56
|
+
if (key) {
|
|
57
|
+
resolve(key);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
reject(new Error('No session key returned from Finix after initialization'));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
// Also try getting session key immediately in case it's already ready
|
|
64
|
+
const immediateKey = FinixAuth.getSessionKey();
|
|
65
|
+
if (immediateKey) {
|
|
66
|
+
clearTimeout(timeoutId);
|
|
67
|
+
console.log('Finix session key obtained immediately:', immediateKey);
|
|
68
|
+
resolve(immediateKey);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
console.log('Finix fraud session key obtained:', sessionKey);
|
|
72
|
+
// Save radar session to database
|
|
73
|
+
await paymentsResource.saveRadarSession({
|
|
74
|
+
orderId: radarConfig.orderId,
|
|
75
|
+
finixRadarSessionId: sessionKey,
|
|
76
|
+
finixRadarSessionData: {
|
|
77
|
+
sessionKey,
|
|
78
|
+
merchantId: radarConfig.merchantId,
|
|
79
|
+
environment: radarConfig.environment,
|
|
80
|
+
createdAt: new Date().toISOString(),
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
console.log('Finix radar session saved to database');
|
|
84
|
+
// Resume payment by calling completePaymentAfterAction
|
|
85
|
+
const resumedPayment = await paymentsResource.completePaymentAfterAction(payment.id);
|
|
86
|
+
console.log('Payment resumed after Finix radar:', resumedPayment);
|
|
87
|
+
// Handle the resumed payment response
|
|
88
|
+
if (resumedPayment.status === 'declined' || resumedPayment.status === 'failed') {
|
|
89
|
+
// Payment declined or failed - extract error message from response
|
|
90
|
+
const errorMsg = resumedPayment.error?.message
|
|
91
|
+
|| resumedPayment.error?.processorMessage
|
|
92
|
+
|| 'Payment declined';
|
|
93
|
+
console.error('❌ [usePayment] Payment declined after Finix radar:', errorMsg);
|
|
94
|
+
setError(errorMsg);
|
|
95
|
+
setIsLoading(false);
|
|
96
|
+
options.onFailure?.(errorMsg);
|
|
97
|
+
options.onPaymentFailed?.({
|
|
98
|
+
code: resumedPayment.error?.code || 'PAYMENT_DECLINED',
|
|
99
|
+
message: errorMsg,
|
|
100
|
+
payment: resumedPayment,
|
|
101
|
+
});
|
|
102
|
+
// Hook-level callback (universal handler)
|
|
103
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
104
|
+
hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
105
|
+
isRedirectReturn: false,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (resumedPayment.status === 'succeeded') {
|
|
110
|
+
// Payment succeeded
|
|
111
|
+
setIsLoading(false);
|
|
112
|
+
const response = {
|
|
113
|
+
paymentId: resumedPayment.id,
|
|
114
|
+
payment: resumedPayment,
|
|
115
|
+
order: resumedPayment.order,
|
|
116
|
+
};
|
|
117
|
+
// Hook-level callback (universal handler)
|
|
118
|
+
if (hookOptionsRef.current?.onPaymentCompleted) {
|
|
119
|
+
await hookOptionsRef.current.onPaymentCompleted(resumedPayment, {
|
|
120
|
+
isRedirectReturn: false,
|
|
121
|
+
order: response.order,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
options.onSuccess?.(response);
|
|
125
|
+
options.onPaymentSuccess?.(response);
|
|
126
|
+
}
|
|
127
|
+
else if (resumedPayment.requireAction !== 'none' && resumedPayment.requireActionData) {
|
|
128
|
+
// Payment requires another action (e.g., 3DS)
|
|
129
|
+
await handlePaymentAction(resumedPayment, options);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Start polling for final status
|
|
133
|
+
startPolling(resumedPayment.id, {
|
|
134
|
+
onRequireAction: (updatedPayment) => {
|
|
135
|
+
void handlePaymentAction(updatedPayment, options);
|
|
136
|
+
},
|
|
137
|
+
onSuccess: async (successPayment) => {
|
|
138
|
+
setIsLoading(false);
|
|
139
|
+
const response = {
|
|
140
|
+
paymentId: successPayment.id,
|
|
141
|
+
payment: successPayment,
|
|
142
|
+
order: successPayment.order,
|
|
143
|
+
};
|
|
144
|
+
// Hook-level callback (universal handler)
|
|
145
|
+
if (hookOptionsRef.current?.onPaymentCompleted) {
|
|
146
|
+
await hookOptionsRef.current.onPaymentCompleted(successPayment, {
|
|
147
|
+
isRedirectReturn: false,
|
|
148
|
+
order: response.order,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
options.onSuccess?.(response);
|
|
152
|
+
options.onPaymentSuccess?.(response);
|
|
153
|
+
},
|
|
154
|
+
onFailure: async (errorMsg) => {
|
|
155
|
+
setError(errorMsg);
|
|
156
|
+
setIsLoading(false);
|
|
157
|
+
// Hook-level callback (universal handler)
|
|
158
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
159
|
+
await hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
160
|
+
isRedirectReturn: false,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
options.onFailure?.(errorMsg);
|
|
164
|
+
options.onPaymentFailed?.({
|
|
165
|
+
code: 'PAYMENT_FAILED',
|
|
166
|
+
message: errorMsg,
|
|
167
|
+
payment,
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (radarError) {
|
|
174
|
+
const errorMsg = radarError instanceof Error ? radarError.message : 'Finix fraud detection failed';
|
|
175
|
+
console.error('Finix radar error:', radarError);
|
|
176
|
+
setError(errorMsg);
|
|
177
|
+
setIsLoading(false);
|
|
178
|
+
options.onFailure?.(errorMsg);
|
|
179
|
+
options.onPaymentFailed?.({
|
|
180
|
+
code: 'FINIX_RADAR_FAILED',
|
|
181
|
+
message: errorMsg,
|
|
182
|
+
payment,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}, [paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef]);
|
|
186
|
+
return { handleFinixRadar };
|
|
187
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Payment, PaymentOptions } from '../../../core/resources/payments';
|
|
2
|
+
import type { UsePaymentOptions } from '../usePaymentQuery';
|
|
3
|
+
interface UseKessPayActionParams {
|
|
4
|
+
setError: (error: string | null) => void;
|
|
5
|
+
setIsLoading: (loading: boolean) => void;
|
|
6
|
+
hookOptionsRef: React.MutableRefObject<UsePaymentOptions | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export declare function useKessPayAction({ setError, setIsLoading, hookOptionsRef, }: UseKessPayActionParams): {
|
|
9
|
+
handleKessPayAuth: (payment: Payment, actionData: any, options?: PaymentOptions) => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling KessPay 3DS authentication
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback, useRef } from 'react';
|
|
5
|
+
export function useKessPayAction({ setError, setIsLoading, hookOptionsRef, }) {
|
|
6
|
+
const challengeInProgressRef = useRef(false);
|
|
7
|
+
const handleKessPayAuth = useCallback(async (payment, actionData, options = {}) => {
|
|
8
|
+
if (challengeInProgressRef.current) {
|
|
9
|
+
console.log('KessPay 3DS challenge already in progress');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const threeDSData = actionData?.metadata?.threeds;
|
|
13
|
+
if (!threeDSData?.challengeHtml) {
|
|
14
|
+
const errorMsg = 'Missing KessPay 3DS challenge HTML';
|
|
15
|
+
console.error(errorMsg);
|
|
16
|
+
setError(errorMsg);
|
|
17
|
+
setIsLoading(false);
|
|
18
|
+
options.onFailure?.(errorMsg);
|
|
19
|
+
options.onPaymentFailed?.({
|
|
20
|
+
code: 'KESSPAY_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('🔐 [KessPay] Starting 3DS authentication:', {
|
|
30
|
+
sessionId: threeDSData.sessionId,
|
|
31
|
+
orderId: threeDSData.orderId,
|
|
32
|
+
hasHtml: !!threeDSData.challengeHtml,
|
|
33
|
+
});
|
|
34
|
+
// Create a temporary document to execute the challenge HTML
|
|
35
|
+
// This will trigger the auto-submit form and redirect
|
|
36
|
+
const tempDoc = document.implementation.createHTMLDocument('KessPay 3DS Challenge');
|
|
37
|
+
tempDoc.body.innerHTML = threeDSData.challengeHtml;
|
|
38
|
+
// Find and submit the form directly
|
|
39
|
+
const form = tempDoc.querySelector('form');
|
|
40
|
+
if (form) {
|
|
41
|
+
// Create a new form in the current document and submit it
|
|
42
|
+
const redirectForm = document.createElement('form');
|
|
43
|
+
redirectForm.method = form.method || 'POST';
|
|
44
|
+
redirectForm.action = form.action || '';
|
|
45
|
+
redirectForm.style.display = 'none';
|
|
46
|
+
// Copy all form inputs
|
|
47
|
+
const inputs = form.querySelectorAll('input');
|
|
48
|
+
inputs.forEach(input => {
|
|
49
|
+
const newInput = document.createElement('input');
|
|
50
|
+
newInput.type = input.type;
|
|
51
|
+
newInput.name = input.name;
|
|
52
|
+
newInput.value = input.value;
|
|
53
|
+
redirectForm.appendChild(newInput);
|
|
54
|
+
});
|
|
55
|
+
// Add form to document and submit
|
|
56
|
+
document.body.appendChild(redirectForm);
|
|
57
|
+
redirectForm.submit();
|
|
58
|
+
console.log('🔐 [KessPay] Redirecting to 3DS challenge...');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Fallback: write the HTML directly to current document
|
|
62
|
+
// This should trigger the auto-submit script
|
|
63
|
+
document.open();
|
|
64
|
+
document.write(threeDSData.challengeHtml);
|
|
65
|
+
document.close();
|
|
66
|
+
}
|
|
67
|
+
// Note: Success callback will be triggered after redirect return
|
|
68
|
+
// Payment status will be updated via webhook
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
challengeInProgressRef.current = false;
|
|
72
|
+
const errorMsg = error instanceof Error ? error.message : 'Failed to process KessPay 3DS authentication';
|
|
73
|
+
console.error('🔐 [KessPay] 3DS authentication error:', error);
|
|
74
|
+
setError(errorMsg);
|
|
75
|
+
setIsLoading(false);
|
|
76
|
+
options.onFailure?.(errorMsg);
|
|
77
|
+
options.onPaymentFailed?.({
|
|
78
|
+
code: 'KESSPAY_AUTH_FAILED',
|
|
79
|
+
message: errorMsg,
|
|
80
|
+
payment,
|
|
81
|
+
});
|
|
82
|
+
// Hook-level callback (universal handler)
|
|
83
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
84
|
+
hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
85
|
+
isRedirectReturn: false,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}, [setError, setIsLoading, hookOptionsRef]);
|
|
90
|
+
return { handleKessPayAuth };
|
|
91
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
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 UseMasterCardActionParams {
|
|
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
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
ThreeDS: {
|
|
14
|
+
configure: (config: any) => void;
|
|
15
|
+
isConfigured: () => boolean;
|
|
16
|
+
initiateAuthentication: (orderId: string, transactionId: string, callback: (result: any) => void, optionalParams?: any) => void;
|
|
17
|
+
authenticatePayer: (orderId: string, transactionId: string, callback: (result: any) => void, optionalParams?: any) => void;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export declare function useMasterCardAction({ paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef, }: UseMasterCardActionParams): {
|
|
22
|
+
handleMasterCardAuth: (payment: Payment, actionData: any, options: PaymentOptions | undefined, handlePaymentAction: any) => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for handling MasterCard 3DS authentication
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback, useRef, useState } from 'react';
|
|
5
|
+
import { useThreedsModal } from '../useThreedsModal';
|
|
6
|
+
export function useMasterCardAction({ paymentsResource, startPolling, setError, setIsLoading, hookOptionsRef, }) {
|
|
7
|
+
const challengeInProgressRef = useRef(false);
|
|
8
|
+
const [isShowingChallenge, setIsShowingChallenge] = useState(false);
|
|
9
|
+
const { createThreedsModal, closeThreedsModal } = useThreedsModal();
|
|
10
|
+
// Load MasterCard 3DS script
|
|
11
|
+
const loadScript = useCallback(async (scriptUrl) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
if (window.ThreeDS) {
|
|
14
|
+
resolve();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const existingScript = document.querySelector(`script[src="${scriptUrl}"]`);
|
|
18
|
+
if (existingScript) {
|
|
19
|
+
existingScript.addEventListener('load', () => resolve());
|
|
20
|
+
existingScript.addEventListener('error', () => reject(new Error('Failed to load 3DS script')));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const script = document.createElement('script');
|
|
24
|
+
script.src = scriptUrl;
|
|
25
|
+
script.onload = () => resolve();
|
|
26
|
+
script.onerror = () => reject(new Error('Failed to load 3DS script'));
|
|
27
|
+
document.head.appendChild(script);
|
|
28
|
+
});
|
|
29
|
+
}, []);
|
|
30
|
+
const handleMasterCardAuth = useCallback(async (payment, actionData, options = {}, handlePaymentAction) => {
|
|
31
|
+
if (challengeInProgressRef.current) {
|
|
32
|
+
console.log('MasterCard 3DS challenge already in progress');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const threeDSData = actionData?.metadata?.threeds;
|
|
36
|
+
if (!threeDSData?.sessionId || !threeDSData?.merchantId) {
|
|
37
|
+
const errorMsg = 'Missing MasterCard 3DS authentication data';
|
|
38
|
+
console.error(errorMsg);
|
|
39
|
+
setError(errorMsg);
|
|
40
|
+
setIsLoading(false);
|
|
41
|
+
options.onFailure?.(errorMsg);
|
|
42
|
+
options.onPaymentFailed?.({
|
|
43
|
+
code: 'MASTERCARD_MISSING_DATA',
|
|
44
|
+
message: errorMsg,
|
|
45
|
+
payment,
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
challengeInProgressRef.current = true;
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
console.log('[MasterCard 3DS] Starting authentication:', {
|
|
53
|
+
sessionId: threeDSData.sessionId,
|
|
54
|
+
orderId: threeDSData.orderId,
|
|
55
|
+
transactionId: threeDSData.transactionId,
|
|
56
|
+
});
|
|
57
|
+
// Load the MasterCard 3DS script
|
|
58
|
+
await loadScript(threeDSData.scriptUrl);
|
|
59
|
+
// Create hidden container for 3DS iframe
|
|
60
|
+
const containerId = 'mastercard-3ds-container';
|
|
61
|
+
let container = document.getElementById(containerId);
|
|
62
|
+
if (!container) {
|
|
63
|
+
container = document.createElement('div');
|
|
64
|
+
container.id = containerId;
|
|
65
|
+
container.style.cssText = 'position: absolute; top: -9999px; left: -9999px; width: 1px; height: 1px; overflow: hidden;';
|
|
66
|
+
document.body.appendChild(container);
|
|
67
|
+
}
|
|
68
|
+
// Configure ThreeDS API
|
|
69
|
+
console.log('[MasterCard 3DS] Configuring ThreeDS API');
|
|
70
|
+
await new Promise((resolve, reject) => {
|
|
71
|
+
window.ThreeDS.configure({
|
|
72
|
+
merchantId: threeDSData.merchantId,
|
|
73
|
+
sessionId: threeDSData.sessionId,
|
|
74
|
+
containerId,
|
|
75
|
+
callback: function () {
|
|
76
|
+
if (window.ThreeDS.isConfigured()) {
|
|
77
|
+
console.log('[MasterCard 3DS] Configuration completed');
|
|
78
|
+
resolve();
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
reject(new Error('ThreeDS configuration failed'));
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
configuration: {
|
|
85
|
+
userLanguage: 'en-US',
|
|
86
|
+
wsVersion: threeDSData.version ? parseInt(threeDSData.version, 10) : 72,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
// Authenticate payer
|
|
91
|
+
const authResult = await new Promise((resolve) => {
|
|
92
|
+
window.ThreeDS.authenticatePayer(threeDSData.orderId, threeDSData.transactionId, (payerResult) => {
|
|
93
|
+
console.log('[MasterCard 3DS] authenticatePayer result:', payerResult);
|
|
94
|
+
resolve(payerResult);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
// Check if challenge HTML is present
|
|
98
|
+
const challengeHtml = authResult?.htmlRedirectCode || authResult?.restApiResponse?.authentication?.redirect?.html;
|
|
99
|
+
if (challengeHtml) {
|
|
100
|
+
setIsShowingChallenge(true);
|
|
101
|
+
// Create modal for challenge
|
|
102
|
+
const modal = createThreedsModal({
|
|
103
|
+
containerId: 'mastercard-3ds-modal',
|
|
104
|
+
mode: 'auto-fit',
|
|
105
|
+
onClose: () => {
|
|
106
|
+
console.log('[MasterCard 3DS] Modal closed by user');
|
|
107
|
+
setIsShowingChallenge(false);
|
|
108
|
+
challengeInProgressRef.current = false;
|
|
109
|
+
const errorMsg = 'User closed the authentication modal';
|
|
110
|
+
setError(errorMsg);
|
|
111
|
+
options.onFailure?.(errorMsg);
|
|
112
|
+
options.onPaymentFailed?.({
|
|
113
|
+
code: 'MASTERCARD_CANCELLED',
|
|
114
|
+
message: errorMsg,
|
|
115
|
+
payment,
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
const contentElement = modal.getContentElement();
|
|
120
|
+
if (contentElement) {
|
|
121
|
+
contentElement.innerHTML = challengeHtml;
|
|
122
|
+
// Auto-submit form if present
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
const frictionlessForm = contentElement.querySelector('#threedsFrictionLessRedirectForm');
|
|
125
|
+
const challengeForm = contentElement.querySelector('#threedsChallengeRedirectForm');
|
|
126
|
+
const form = frictionlessForm ?? challengeForm;
|
|
127
|
+
if (form) {
|
|
128
|
+
console.log('[MasterCard 3DS] Auto-submitting form');
|
|
129
|
+
form.submit();
|
|
130
|
+
// For frictionless flow, close modal and complete payment
|
|
131
|
+
if (frictionlessForm) {
|
|
132
|
+
setTimeout(async () => {
|
|
133
|
+
closeThreedsModal('mastercard-3ds-modal');
|
|
134
|
+
setIsShowingChallenge(false);
|
|
135
|
+
challengeInProgressRef.current = false;
|
|
136
|
+
// Complete payment after frictionless 3DS
|
|
137
|
+
if (threeDSData.paymentId) {
|
|
138
|
+
const resumedPayment = await paymentsResource.completePaymentAfterAction(threeDSData.paymentId);
|
|
139
|
+
await handlePaymentAction(resumedPayment, options);
|
|
140
|
+
}
|
|
141
|
+
}, 1000);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// Challenge flow - listen for completion
|
|
145
|
+
const handleIframeMessage = async (event) => {
|
|
146
|
+
const messageData = event.data;
|
|
147
|
+
let isComplete = false;
|
|
148
|
+
if (typeof messageData === 'string') {
|
|
149
|
+
isComplete = messageData.toLowerCase().includes('complete') ||
|
|
150
|
+
messageData.toLowerCase().includes('success');
|
|
151
|
+
}
|
|
152
|
+
else if (typeof messageData === 'object' && messageData !== null) {
|
|
153
|
+
isComplete = messageData.result === 'SUCCESS' ||
|
|
154
|
+
messageData.transStatus === 'Y' ||
|
|
155
|
+
messageData.type === '3DSAuthenticationComplete';
|
|
156
|
+
}
|
|
157
|
+
if (isComplete) {
|
|
158
|
+
console.log('[MasterCard 3DS] Challenge completed');
|
|
159
|
+
window.removeEventListener('message', handleIframeMessage);
|
|
160
|
+
closeThreedsModal('mastercard-3ds-modal');
|
|
161
|
+
setIsShowingChallenge(false);
|
|
162
|
+
challengeInProgressRef.current = false;
|
|
163
|
+
// Complete payment after challenge
|
|
164
|
+
if (threeDSData.paymentId) {
|
|
165
|
+
const resumedPayment = await paymentsResource.completePaymentAfterAction(threeDSData.paymentId);
|
|
166
|
+
await handlePaymentAction(resumedPayment, options);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
window.addEventListener('message', handleIframeMessage);
|
|
171
|
+
// Timeout after 5 minutes
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
window.removeEventListener('message', handleIframeMessage);
|
|
174
|
+
closeThreedsModal('mastercard-3ds-modal');
|
|
175
|
+
setIsShowingChallenge(false);
|
|
176
|
+
challengeInProgressRef.current = false;
|
|
177
|
+
const errorMsg = '3DS authentication timed out';
|
|
178
|
+
setError(errorMsg);
|
|
179
|
+
options.onFailure?.(errorMsg);
|
|
180
|
+
}, 300000);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}, 100);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
// No challenge required - frictionless flow
|
|
188
|
+
console.log('[MasterCard 3DS] No challenge required');
|
|
189
|
+
challengeInProgressRef.current = false;
|
|
190
|
+
if (threeDSData.paymentId) {
|
|
191
|
+
const resumedPayment = await paymentsResource.completePaymentAfterAction(threeDSData.paymentId);
|
|
192
|
+
await handlePaymentAction(resumedPayment, options);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Cleanup container
|
|
196
|
+
const cleanupContainer = document.getElementById('mastercard-3ds-container');
|
|
197
|
+
if (cleanupContainer && document.body.contains(cleanupContainer)) {
|
|
198
|
+
document.body.removeChild(cleanupContainer);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
challengeInProgressRef.current = false;
|
|
203
|
+
const errorMsg = error instanceof Error ? error.message : 'MasterCard 3DS authentication failed';
|
|
204
|
+
console.error('[MasterCard 3DS] Error:', error);
|
|
205
|
+
setError(errorMsg);
|
|
206
|
+
setIsLoading(false);
|
|
207
|
+
options.onFailure?.(errorMsg);
|
|
208
|
+
options.onPaymentFailed?.({
|
|
209
|
+
code: 'MASTERCARD_AUTH_FAILED',
|
|
210
|
+
message: errorMsg,
|
|
211
|
+
payment,
|
|
212
|
+
});
|
|
213
|
+
if (hookOptionsRef.current?.onPaymentFailed) {
|
|
214
|
+
hookOptionsRef.current.onPaymentFailed(errorMsg, {
|
|
215
|
+
isRedirectReturn: false,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}, [paymentsResource, loadScript, createThreedsModal, closeThreedsModal, setError, setIsLoading, hookOptionsRef]);
|
|
220
|
+
return { handleMasterCardAuth };
|
|
221
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
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 UsePaymentActionHandlerParams {
|
|
5
|
+
paymentsResource: PaymentsResource;
|
|
6
|
+
startChallenge: any;
|
|
7
|
+
startPolling: any;
|
|
8
|
+
setIsLoading: (loading: boolean) => void;
|
|
9
|
+
setError: (error: string | null) => void;
|
|
10
|
+
hookOptionsRef: React.MutableRefObject<UsePaymentOptions | undefined>;
|
|
11
|
+
}
|
|
12
|
+
export declare function usePaymentActionHandler({ paymentsResource, startChallenge, startPolling, setIsLoading, setError, hookOptionsRef, }: UsePaymentActionHandlerParams): {
|
|
13
|
+
handlePaymentAction: (payment: Payment, options?: PaymentOptions) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|