@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
|
@@ -1,36 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TagadaPay External Page Tracker
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Standalone script for tracking users on external pages that are part of a
|
|
5
|
+
* TagadaPay funnel but not hosted on the TagadaPay platform.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Use cases:
|
|
8
|
+
* - WooCommerce / WordPress storefronts
|
|
9
|
+
* - Custom landing pages
|
|
10
|
+
* - Any external page that is a funnel step
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* @example CDN usage
|
|
13
|
+
* ```html
|
|
13
14
|
* <script src="https://cdn.jsdelivr.net/npm/@tagadapay/plugin-sdk/dist/external-tracker.min.js"></script>
|
|
14
15
|
* <script>
|
|
15
16
|
* TagadaTracker.init({
|
|
16
17
|
* storeId: 'store_xxx',
|
|
17
18
|
* accountId: 'acc_xxx',
|
|
18
|
-
* funnelId: 'funnel_xxx', // Optional: detected from URL
|
|
19
19
|
* stepId: 'step_xxx',
|
|
20
|
-
* stepName: 'External Offer Page',
|
|
21
|
-
* stepType: 'external'
|
|
22
|
-
* });
|
|
23
|
-
*
|
|
24
|
-
* // Navigate to next step (tracking automatic)
|
|
25
|
-
* TagadaTracker.navigate({
|
|
26
|
-
* eventType: 'form.submitted',
|
|
27
|
-
* eventData: { email: 'user@example.com' }
|
|
28
20
|
* });
|
|
29
21
|
* </script>
|
|
22
|
+
* ```
|
|
30
23
|
*/
|
|
31
24
|
import { createTagadaClient } from './index';
|
|
32
25
|
import { setClientToken } from '../core/utils/tokenStorage';
|
|
33
26
|
// ============================================================================
|
|
27
|
+
// VERSION
|
|
28
|
+
// ============================================================================
|
|
29
|
+
export const TRACKER_VERSION = '1.0.0';
|
|
30
|
+
// ============================================================================
|
|
34
31
|
// UTILITIES
|
|
35
32
|
// ============================================================================
|
|
36
33
|
function getUrlParam(name) {
|
|
@@ -44,6 +41,45 @@ function log(debug, ...args) {
|
|
|
44
41
|
console.log('[TagadaTracker]', ...args);
|
|
45
42
|
}
|
|
46
43
|
}
|
|
44
|
+
function warn(...args) {
|
|
45
|
+
console.warn('[TagadaTracker]', ...args);
|
|
46
|
+
}
|
|
47
|
+
function validate(config) {
|
|
48
|
+
if (!config.storeId || typeof config.storeId !== 'string') {
|
|
49
|
+
throw new Error('TagadaTracker: storeId is required and must be a non-empty string.');
|
|
50
|
+
}
|
|
51
|
+
if (!config.accountId || typeof config.accountId !== 'string') {
|
|
52
|
+
throw new Error('TagadaTracker: accountId is required and must be a non-empty string.');
|
|
53
|
+
}
|
|
54
|
+
if (!config.stepId || typeof config.stepId !== 'string') {
|
|
55
|
+
throw new Error('TagadaTracker: stepId is required and must be a non-empty string.');
|
|
56
|
+
}
|
|
57
|
+
if (config.apiBaseUrl) {
|
|
58
|
+
try {
|
|
59
|
+
new URL(config.apiBaseUrl);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw new Error(`TagadaTracker: apiBaseUrl is not a valid URL: "${config.apiBaseUrl}"`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function retryWithBackoff(fn, maxRetries, debug) {
|
|
67
|
+
let lastError;
|
|
68
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
69
|
+
try {
|
|
70
|
+
return await fn();
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
74
|
+
if (attempt < maxRetries) {
|
|
75
|
+
const delay = Math.min(1000 * 2 ** attempt, 8000);
|
|
76
|
+
log(debug, `Retry ${attempt + 1}/${maxRetries} in ${delay}ms...`);
|
|
77
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
throw lastError;
|
|
82
|
+
}
|
|
47
83
|
// ============================================================================
|
|
48
84
|
// MAIN CLASS
|
|
49
85
|
// ============================================================================
|
|
@@ -53,41 +89,67 @@ class TagadaExternalTracker {
|
|
|
53
89
|
this.client = null;
|
|
54
90
|
this.initialized = false;
|
|
55
91
|
this.initializing = false;
|
|
92
|
+
this.unsubscribe = null;
|
|
93
|
+
/** Tracker version */
|
|
94
|
+
this.version = TRACKER_VERSION;
|
|
56
95
|
}
|
|
57
96
|
/**
|
|
58
|
-
* Initialize the tracker
|
|
97
|
+
* Initialize the tracker.
|
|
98
|
+
* When `onError` is provided, errors are passed to the callback and init()
|
|
99
|
+
* resolves to `null` instead of throwing.
|
|
59
100
|
*/
|
|
60
101
|
async init(config) {
|
|
61
|
-
if (this.initialized
|
|
62
|
-
log(config.debug || false, 'Already initialized
|
|
102
|
+
if (this.initialized) {
|
|
103
|
+
log(config.debug || false, 'Already initialized — returning existing session.');
|
|
63
104
|
return this.getSession();
|
|
64
105
|
}
|
|
106
|
+
if (this.initializing) {
|
|
107
|
+
log(config.debug || false, 'Initialization in progress — skipping duplicate call.');
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
65
110
|
this.initializing = true;
|
|
66
|
-
this.config = {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
111
|
+
this.config = { debug: false, ...config };
|
|
112
|
+
const debug = this.config.debug;
|
|
113
|
+
try {
|
|
114
|
+
validate(this.config);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
this.initializing = false;
|
|
118
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
119
|
+
if (this.config.onError) {
|
|
120
|
+
this.config.onError(error);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
log(debug, `🚀 Initializing external tracker v${TRACKER_VERSION}`, {
|
|
126
|
+
storeId: config.storeId,
|
|
127
|
+
accountId: config.accountId,
|
|
128
|
+
stepId: config.stepId,
|
|
129
|
+
funnelId: config.funnelId,
|
|
130
|
+
});
|
|
71
131
|
try {
|
|
72
|
-
// 1. Check for token in URL and save to storage (bootstrap auth)
|
|
73
|
-
// TagadaClient will automatically pick it up from storage
|
|
74
132
|
const urlToken = getUrlParam('token');
|
|
75
133
|
if (urlToken) {
|
|
76
134
|
setClientToken(urlToken);
|
|
77
|
-
log(
|
|
135
|
+
log(debug, '🔑 Bootstrapped token from URL');
|
|
78
136
|
}
|
|
79
|
-
// 2. Create TagadaClient
|
|
80
137
|
this.client = createTagadaClient({
|
|
81
|
-
debugMode:
|
|
82
|
-
features: { funnel: true },
|
|
138
|
+
debugMode: debug,
|
|
139
|
+
features: { funnel: { skipAutoInit: true } },
|
|
140
|
+
rawPluginConfig: {
|
|
141
|
+
storeId: this.config.storeId,
|
|
142
|
+
accountId: this.config.accountId,
|
|
143
|
+
},
|
|
144
|
+
customApiConfig: this.config.apiBaseUrl ? {
|
|
145
|
+
apiConfig: {
|
|
146
|
+
baseUrl: this.config.apiBaseUrl.trim(),
|
|
147
|
+
},
|
|
148
|
+
} : undefined,
|
|
83
149
|
});
|
|
84
|
-
// 3. Wait for client to be ready (load token, init auth state)
|
|
85
150
|
await this.waitForClientReady();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// Orchestrator automatically tracks session start and step view
|
|
89
|
-
const funnelContext = await this.initializeFunnel();
|
|
90
|
-
log(this.config.debug, '✅ Session initialized (tracking handled by orchestrator):', funnelContext);
|
|
151
|
+
const funnelContext = await retryWithBackoff(() => this.initializeFunnel(), 2, debug);
|
|
152
|
+
log(debug, '✅ Session initialized:', funnelContext);
|
|
91
153
|
this.initialized = true;
|
|
92
154
|
const session = this.getSession();
|
|
93
155
|
if (session) {
|
|
@@ -95,19 +157,20 @@ class TagadaExternalTracker {
|
|
|
95
157
|
}
|
|
96
158
|
return session;
|
|
97
159
|
}
|
|
98
|
-
catch (
|
|
99
|
-
const
|
|
100
|
-
log(
|
|
101
|
-
this.config.onError
|
|
102
|
-
|
|
160
|
+
catch (err) {
|
|
161
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
162
|
+
log(debug, '❌ Initialization failed:', error);
|
|
163
|
+
if (this.config.onError) {
|
|
164
|
+
this.config.onError(error);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
throw error;
|
|
103
168
|
}
|
|
104
169
|
finally {
|
|
105
170
|
this.initializing = false;
|
|
106
171
|
}
|
|
107
172
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Get current session from SDK state
|
|
110
|
-
*/
|
|
173
|
+
/** Get current session data. */
|
|
111
174
|
getSession() {
|
|
112
175
|
if (!this.client?.funnel?.state.context)
|
|
113
176
|
return null;
|
|
@@ -121,31 +184,27 @@ class TagadaExternalTracker {
|
|
|
121
184
|
cmsToken: this.client.state.token || undefined,
|
|
122
185
|
};
|
|
123
186
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Check if tracker is ready
|
|
126
|
-
*/
|
|
187
|
+
/** Whether the tracker is fully initialized and ready. */
|
|
127
188
|
isReady() {
|
|
128
189
|
return this.initialized && !!this.client?.funnel?.state.context;
|
|
129
190
|
}
|
|
130
191
|
/**
|
|
131
|
-
* Navigate to next step in
|
|
192
|
+
* Navigate to the next step in the funnel.
|
|
193
|
+
* By default, auto-redirects the browser window.
|
|
132
194
|
*/
|
|
133
195
|
async navigate(options) {
|
|
134
196
|
if (!this.isReady()) {
|
|
135
|
-
throw new Error('
|
|
197
|
+
throw new Error('TagadaTracker: not initialized. Call init() first.');
|
|
136
198
|
}
|
|
137
199
|
log(this.config.debug, '🚀 Navigating:', options);
|
|
138
|
-
// Determine if we should auto-redirect (default: true)
|
|
139
200
|
const shouldAutoRedirect = options.autoRedirect !== false;
|
|
140
201
|
try {
|
|
141
202
|
const result = await this.client.funnel.navigate({
|
|
142
203
|
type: options.eventType,
|
|
143
204
|
data: options.eventData || {},
|
|
144
|
-
}, { autoRedirect: false }
|
|
145
|
-
);
|
|
205
|
+
}, { autoRedirect: false });
|
|
146
206
|
if (result?.url) {
|
|
147
207
|
log(this.config.debug, '✅ Navigation result:', result.url);
|
|
148
|
-
// Only redirect if autoRedirect is enabled
|
|
149
208
|
if (shouldAutoRedirect && typeof window !== 'undefined') {
|
|
150
209
|
window.location.href = options.returnUrl || result.url;
|
|
151
210
|
}
|
|
@@ -159,37 +218,51 @@ class TagadaExternalTracker {
|
|
|
159
218
|
}
|
|
160
219
|
}
|
|
161
220
|
/**
|
|
162
|
-
*
|
|
221
|
+
* Track a custom event (e.g., button click, scroll depth, video play).
|
|
222
|
+
* Events are sent through the funnel orchestrator for unified analytics.
|
|
163
223
|
*/
|
|
224
|
+
async trackEvent(options) {
|
|
225
|
+
if (!this.isReady()) {
|
|
226
|
+
warn('trackEvent called before init — event dropped:', options.name);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
log(this.config.debug, '📊 Tracking event:', options.name, options.data);
|
|
230
|
+
try {
|
|
231
|
+
await this.client.funnel.navigate({
|
|
232
|
+
type: options.name,
|
|
233
|
+
data: options.data || {},
|
|
234
|
+
}, { autoRedirect: false });
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Non-critical — swallow errors for tracking events
|
|
238
|
+
log(this.config.debug, '⚠️ Event tracking failed (non-critical):', options.name);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** Get customer ID. */
|
|
164
242
|
getCustomerId() {
|
|
165
|
-
return this.client?.state.auth.customer?.id
|
|
243
|
+
return this.client?.state.auth.customer?.id
|
|
244
|
+
|| this.client?.funnel?.state.context?.customerId
|
|
245
|
+
|| null;
|
|
166
246
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Get funnel session ID
|
|
169
|
-
*/
|
|
247
|
+
/** Get funnel session ID. */
|
|
170
248
|
getFunnelSessionId() {
|
|
171
249
|
return this.client?.funnel?.state.context?.sessionId || null;
|
|
172
250
|
}
|
|
173
251
|
/**
|
|
174
|
-
* Build a URL
|
|
175
|
-
*
|
|
252
|
+
* Build a URL that preserves funnel session context.
|
|
253
|
+
* Use this to link to other external pages within the same funnel.
|
|
176
254
|
*/
|
|
177
255
|
buildUrl(baseUrl, additionalParams) {
|
|
178
256
|
const session = this.getSession();
|
|
179
|
-
if (!session)
|
|
257
|
+
if (!session)
|
|
180
258
|
return baseUrl;
|
|
181
|
-
}
|
|
182
259
|
const url = new URL(baseUrl, typeof window !== 'undefined' ? window.location.origin : undefined);
|
|
183
|
-
// Add funnel session context
|
|
184
260
|
url.searchParams.set('funnelSessionId', session.sessionId);
|
|
185
|
-
if (session.cmsToken)
|
|
261
|
+
if (session.cmsToken)
|
|
186
262
|
url.searchParams.set('token', session.cmsToken);
|
|
187
|
-
|
|
188
|
-
if (session.funnelId) {
|
|
263
|
+
if (session.funnelId)
|
|
189
264
|
url.searchParams.set('funnelId', session.funnelId);
|
|
190
|
-
}
|
|
191
265
|
url.searchParams.set('storeId', session.storeId);
|
|
192
|
-
// Add any additional params
|
|
193
266
|
if (additionalParams) {
|
|
194
267
|
Object.entries(additionalParams).forEach(([key, value]) => {
|
|
195
268
|
url.searchParams.set(key, value);
|
|
@@ -197,60 +270,94 @@ class TagadaExternalTracker {
|
|
|
197
270
|
}
|
|
198
271
|
return url.toString();
|
|
199
272
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Get the underlying SDK client (for advanced usage)
|
|
202
|
-
*/
|
|
273
|
+
/** Get the underlying SDK client (advanced usage). */
|
|
203
274
|
getClient() {
|
|
204
275
|
return this.client;
|
|
205
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Reset the tracker to a new step without re-creating the session.
|
|
279
|
+
* Useful for SPAs that navigate between funnel steps client-side.
|
|
280
|
+
*/
|
|
281
|
+
async reset(newStepId) {
|
|
282
|
+
if (!this.client || !this.config) {
|
|
283
|
+
throw new Error('TagadaTracker: not initialized. Call init() first.');
|
|
284
|
+
}
|
|
285
|
+
log(this.config.debug, '🔄 Resetting to step:', newStepId);
|
|
286
|
+
this.config.stepId = newStepId;
|
|
287
|
+
const ctx = await this.initializeFunnel();
|
|
288
|
+
const session = this.getSession();
|
|
289
|
+
if (session)
|
|
290
|
+
this.config.onReady?.(session);
|
|
291
|
+
return session;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Destroy the tracker, clean up event listeners and state.
|
|
295
|
+
* Call this when the tracker is no longer needed (e.g., SPA teardown).
|
|
296
|
+
*/
|
|
297
|
+
destroy() {
|
|
298
|
+
if (this.unsubscribe) {
|
|
299
|
+
this.unsubscribe();
|
|
300
|
+
this.unsubscribe = null;
|
|
301
|
+
}
|
|
302
|
+
if (this.client) {
|
|
303
|
+
this.client.destroy?.();
|
|
304
|
+
}
|
|
305
|
+
this.client = null;
|
|
306
|
+
this.config = null;
|
|
307
|
+
this.initialized = false;
|
|
308
|
+
this.initializing = false;
|
|
309
|
+
log(false, '🗑️ Tracker destroyed');
|
|
310
|
+
}
|
|
206
311
|
// ========================================================================
|
|
207
312
|
// PRIVATE METHODS
|
|
208
313
|
// ========================================================================
|
|
209
314
|
async waitForClientReady() {
|
|
210
315
|
if (!this.client)
|
|
211
316
|
return;
|
|
212
|
-
// Wait for
|
|
317
|
+
// Wait for isInitialized which is set AFTER the full init sequence:
|
|
318
|
+
// anonymous token → session/v2/init → isInitialized=true
|
|
319
|
+
// Do NOT resolve on token alone — that fires before session init.
|
|
213
320
|
return new Promise((resolve) => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
321
|
+
if (this.client?.state.isInitialized) {
|
|
322
|
+
resolve();
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
let resolved = false;
|
|
326
|
+
const timeout = setTimeout(() => {
|
|
327
|
+
if (!resolved) {
|
|
328
|
+
resolved = true;
|
|
329
|
+
log(this.config?.debug || false, '⏱️ Client ready timeout — proceeding');
|
|
218
330
|
resolve();
|
|
219
331
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
332
|
+
}, 10000);
|
|
333
|
+
this.unsubscribe = this.client.subscribe(() => {
|
|
334
|
+
if (!resolved && this.client?.state.isInitialized) {
|
|
335
|
+
resolved = true;
|
|
336
|
+
clearTimeout(timeout);
|
|
337
|
+
resolve();
|
|
226
338
|
}
|
|
227
|
-
};
|
|
228
|
-
checkReady();
|
|
339
|
+
});
|
|
229
340
|
});
|
|
230
341
|
}
|
|
231
342
|
async initializeFunnel() {
|
|
232
343
|
if (!this.client?.funnel)
|
|
233
344
|
return null;
|
|
234
|
-
|
|
345
|
+
const customerId = this.client.state.auth.customer?.id;
|
|
346
|
+
const sessionId = this.client.state.auth.session?.sessionId;
|
|
347
|
+
if (!customerId && !sessionId) {
|
|
348
|
+
warn('No auth session available — funnel init may fail.');
|
|
349
|
+
}
|
|
235
350
|
const authSession = {
|
|
236
|
-
customerId:
|
|
237
|
-
sessionId:
|
|
351
|
+
customerId: customerId || 'anon_placeholder',
|
|
352
|
+
sessionId: sessionId || 'sess_placeholder',
|
|
238
353
|
};
|
|
239
354
|
const store = {
|
|
240
355
|
id: this.config.storeId,
|
|
241
|
-
accountId: this.config.accountId
|
|
356
|
+
accountId: this.config.accountId,
|
|
242
357
|
};
|
|
243
|
-
// IMPORTANT: For external pages, we must explicitly pass stepId as entryStepId
|
|
244
|
-
// because URL-to-step mapping won't work for external URLs not hosted on Tagadapay
|
|
245
358
|
const entryStepId = this.config.stepId;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
log(this.config.debug, '🔍 Initializing external page at step:', entryStepId);
|
|
250
|
-
// Use initialize() (not autoInitialize()) to explicitly specify the step
|
|
251
|
-
// Orchestrator will automatically track session start and step view at this step
|
|
252
|
-
return this.client.funnel.initialize(authSession, store, this.config.funnelId || getUrlParam('funnelId') || undefined, entryStepId // ✅ Explicitly tell orchestrator which step we're on
|
|
253
|
-
);
|
|
359
|
+
log(this.config.debug, '🔍 Initializing funnel at step:', entryStepId);
|
|
360
|
+
return this.client.funnel.initialize(authSession, store, this.config.funnelId || getUrlParam('funnelId') || undefined, entryStepId);
|
|
254
361
|
}
|
|
255
362
|
}
|
|
256
363
|
// ============================================================================
|
|
@@ -9,15 +9,55 @@
|
|
|
9
9
|
import { TagadaClient, TagadaClientConfig, TagadaState } from '../core/client';
|
|
10
10
|
import { ApiClient } from '../core/resources/apiClient';
|
|
11
11
|
import { CheckoutResource } from '../core/resources/checkout';
|
|
12
|
+
import { getAssignedPaymentFlowId } from '../core/funnelClient';
|
|
13
|
+
/**
|
|
14
|
+
* Auto-inject all stepConfig scripts
|
|
15
|
+
* Called automatically when SDK loads
|
|
16
|
+
* Can also be called manually if needed (e.g., after dynamic config update)
|
|
17
|
+
*/
|
|
18
|
+
export declare function injectStepConfigScripts(): void;
|
|
12
19
|
/**
|
|
13
20
|
* Factory function to create a Tagada Client instance.
|
|
14
21
|
* Features (like funnel) can be toggled via the config.
|
|
15
22
|
*/
|
|
16
23
|
export declare function createTagadaClient(config?: TagadaClientConfig): TagadaClient;
|
|
17
24
|
export { TagadaClient, ApiClient, CheckoutResource };
|
|
25
|
+
export { ShippingRatesResource } from '../core/resources/shippingRates';
|
|
26
|
+
export { PaymentsResource } from '../core/resources/payments';
|
|
27
|
+
export { OrdersResource } from '../core/resources/orders';
|
|
28
|
+
export { ExpressPaymentMethodsResource } from '../core/resources/expressPaymentMethods';
|
|
29
|
+
export type { PaymentMethod as ExpressPaymentMethod } from '../core/resources/expressPaymentMethods';
|
|
30
|
+
export type { ShippingRate, ShippingRatesResponse, ShippingRatesPreviewParams } from '../core/resources/shippingRates';
|
|
31
|
+
export type { Payment, PaymentResponse, CardPaymentMethod, BasisTheoryInstance, GooglePayToken, ApplePayToken, PaymentInstrumentInput, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse, } from '../core/resources/payments';
|
|
32
|
+
export { StoreConfigResource } from '../core/resources/storeConfig';
|
|
33
|
+
export type { StoreConfig } from '../core/resources/storeConfig';
|
|
34
|
+
export { ThreedsResource } from '../core/resources/threeds';
|
|
35
|
+
export { ISODataCore } from '../core/isoData';
|
|
36
|
+
export type { ISOCountry, ISORegion } from '../core/isoData';
|
|
37
|
+
export { GoogleAutocompleteCore } from '../core/googleAutocomplete';
|
|
38
|
+
export type { GooglePrediction, GooglePlaceDetails, AddressComponents } from '../core/googleAutocomplete';
|
|
39
|
+
export { TagadaError, TagadaApiError, TagadaNetworkError, TagadaAuthError, TagadaValidationError, TagadaCircuitBreakerError, TagadaErrorCode, } from '../core/errors';
|
|
40
|
+
export type { TagadaErrorOptions, TagadaErrorCodeValue } from '../core/errors';
|
|
18
41
|
export type { TagadaClientConfig, TagadaState };
|
|
19
42
|
export { FunnelActionType } from '../core/resources/funnel';
|
|
20
43
|
export type { FunnelAction, FunnelNavigationResult, SimpleFunnelContext } from '../core/resources/funnel';
|
|
44
|
+
export type { CheckoutData, CheckoutSession, CheckoutSummary, CheckoutSummaryItem, CheckoutLineItem, CheckoutInitParams, Promotion, } from '../core/resources/checkout';
|
|
45
|
+
export type { Order, OrderItem, OrderAddress, OrderSummary, OrderWithRelations, PaymentSummary, PromotionSummary, Subscription, DeviceInfo, PromotionCode, Customer, Store, PickupPoint, } from '../core/types';
|
|
21
46
|
export * from '../core/utils';
|
|
47
|
+
export { matchRoute, getInternalPath, isPathRemapped, getPathInfo, } from '../core/pathRemapping';
|
|
48
|
+
export { getAssignedPaymentFlowId };
|
|
49
|
+
export { getAssignedStepConfig } from '../core/funnelClient';
|
|
50
|
+
export type { RuntimeStepConfig } from '../core/funnelClient';
|
|
51
|
+
export { PaymentService } from './payment-service';
|
|
52
|
+
export type { PaymentServiceConfig, PaymentResult, PaymentCallbacks, CardData, ApmData, } from './payment-service';
|
|
53
|
+
/**
|
|
54
|
+
* Get BasisTheory public API key based on hostname detection.
|
|
55
|
+
* Delegates to the centralized isProductionBasisTheory() logic.
|
|
56
|
+
*/
|
|
57
|
+
export declare function getBasisTheoryApiKey(): string;
|
|
58
|
+
/**
|
|
59
|
+
* Get BasisTheory tenant ID based on hostname detection.
|
|
60
|
+
*/
|
|
61
|
+
export declare function getBasisTheoryTenantId(): string;
|
|
22
62
|
export { TagadaTracker, TagadaExternalTracker, } from './external-tracker';
|
|
23
63
|
export type { TagadaTrackerConfig, ExternalTrackerSession, NavigateOptions, } from './external-tracker';
|
|
@@ -9,6 +9,118 @@
|
|
|
9
9
|
import { TagadaClient } from '../core/client';
|
|
10
10
|
import { ApiClient } from '../core/resources/apiClient';
|
|
11
11
|
import { CheckoutResource } from '../core/resources/checkout';
|
|
12
|
+
import { getAssignedStepConfig, getAssignedPaymentFlowId } from '../core/funnelClient';
|
|
13
|
+
import { getBasisTheoryApiKey as _getBtApiKey, getBasisTheoryTenantId as _getBtTenantId } from '../../react/config/payment';
|
|
14
|
+
/**
|
|
15
|
+
* Parse step config from window variable or meta tag
|
|
16
|
+
*/
|
|
17
|
+
function parseStepConfigScripts() {
|
|
18
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
// Try to get stepConfig (uses same logic as getAssignedStepConfig)
|
|
22
|
+
const stepConfig = getAssignedStepConfig();
|
|
23
|
+
if (stepConfig?.scripts) {
|
|
24
|
+
return stepConfig.scripts.filter(s => s.enabled);
|
|
25
|
+
}
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Inject a script at the specified position
|
|
30
|
+
*/
|
|
31
|
+
function injectScript(script, index) {
|
|
32
|
+
const position = script.position || 'body-end';
|
|
33
|
+
const scriptId = `tagada-stepconfig-script-${index}`;
|
|
34
|
+
// Skip if already injected
|
|
35
|
+
if (document.getElementById(scriptId)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Extract script content (remove <script> tags if present)
|
|
39
|
+
let scriptBody = script.content.trim();
|
|
40
|
+
const scriptTagMatch = scriptBody.match(/^<script[^>]*>([\s\S]*)<\/script>$/i);
|
|
41
|
+
if (scriptTagMatch) {
|
|
42
|
+
scriptBody = scriptTagMatch[1].trim();
|
|
43
|
+
}
|
|
44
|
+
if (!scriptBody)
|
|
45
|
+
return;
|
|
46
|
+
// Wrap script content with error handling
|
|
47
|
+
// NOTE: Use string concatenation instead of template literals to avoid breaking
|
|
48
|
+
// when scriptBody contains backticks or ${...} expressions
|
|
49
|
+
const wrappedScript = '(function() {\n' +
|
|
50
|
+
' try {\n' +
|
|
51
|
+
' // Script: ' + script.name + '\n' +
|
|
52
|
+
scriptBody + '\n' +
|
|
53
|
+
' } catch (error) {\n' +
|
|
54
|
+
' console.error("[TagadaPay] StepConfig script error:", error);\n' +
|
|
55
|
+
' }\n' +
|
|
56
|
+
'})();';
|
|
57
|
+
// Create script element
|
|
58
|
+
const scriptElement = document.createElement('script');
|
|
59
|
+
scriptElement.id = scriptId;
|
|
60
|
+
scriptElement.setAttribute('data-tagada-stepconfig-script', 'true');
|
|
61
|
+
scriptElement.setAttribute('data-script-name', script.name);
|
|
62
|
+
scriptElement.textContent = wrappedScript;
|
|
63
|
+
// Inject at the correct position
|
|
64
|
+
switch (position) {
|
|
65
|
+
case 'head-start':
|
|
66
|
+
if (document.head.firstChild) {
|
|
67
|
+
document.head.insertBefore(scriptElement, document.head.firstChild);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
document.head.appendChild(scriptElement);
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
case 'head-end':
|
|
74
|
+
document.head.appendChild(scriptElement);
|
|
75
|
+
break;
|
|
76
|
+
case 'body-start':
|
|
77
|
+
if (document.body.firstChild) {
|
|
78
|
+
document.body.insertBefore(scriptElement, document.body.firstChild);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
document.body.appendChild(scriptElement);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
case 'body-end':
|
|
85
|
+
default:
|
|
86
|
+
document.body.appendChild(scriptElement);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Auto-inject all stepConfig scripts
|
|
92
|
+
* Called automatically when SDK loads
|
|
93
|
+
* Can also be called manually if needed (e.g., after dynamic config update)
|
|
94
|
+
*/
|
|
95
|
+
export function injectStepConfigScripts() {
|
|
96
|
+
const scripts = parseStepConfigScripts();
|
|
97
|
+
if (scripts.length === 0)
|
|
98
|
+
return;
|
|
99
|
+
scripts.forEach((script, index) => {
|
|
100
|
+
injectScript(script, index);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Auto-run script injection when SDK loads
|
|
104
|
+
// Uses requestIdleCallback or setTimeout fallback for non-blocking execution
|
|
105
|
+
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
106
|
+
const runInjection = () => {
|
|
107
|
+
// Wait for body to be available
|
|
108
|
+
if (document.body) {
|
|
109
|
+
injectStepConfigScripts();
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Body not ready, wait for DOMContentLoaded
|
|
113
|
+
document.addEventListener('DOMContentLoaded', injectStepConfigScripts, { once: true });
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
// Run after current script execution completes
|
|
117
|
+
if ('requestIdleCallback' in window) {
|
|
118
|
+
window.requestIdleCallback(runInjection, { timeout: 100 });
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
setTimeout(runInjection, 0);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
12
124
|
/**
|
|
13
125
|
* Factory function to create a Tagada Client instance.
|
|
14
126
|
* Features (like funnel) can be toggled via the config.
|
|
@@ -18,9 +130,44 @@ export function createTagadaClient(config = {}) {
|
|
|
18
130
|
}
|
|
19
131
|
// Re-export Core Classes
|
|
20
132
|
export { TagadaClient, ApiClient, CheckoutResource };
|
|
133
|
+
// Re-export Resource Classes (for standalone resolvers / builders)
|
|
134
|
+
export { ShippingRatesResource } from '../core/resources/shippingRates';
|
|
135
|
+
export { PaymentsResource } from '../core/resources/payments';
|
|
136
|
+
export { OrdersResource } from '../core/resources/orders';
|
|
137
|
+
export { ExpressPaymentMethodsResource } from '../core/resources/expressPaymentMethods';
|
|
138
|
+
// Re-export Store Config (for standalone resolvers / builders)
|
|
139
|
+
export { StoreConfigResource } from '../core/resources/storeConfig';
|
|
140
|
+
// Re-export 3DS Resource (for standalone resolvers / builders)
|
|
141
|
+
export { ThreedsResource } from '../core/resources/threeds';
|
|
142
|
+
// Re-export ISO Data Core (for standalone address form / resolvers)
|
|
143
|
+
export { ISODataCore } from '../core/isoData';
|
|
144
|
+
// Re-export Google Autocomplete Core (for standalone address form)
|
|
145
|
+
export { GoogleAutocompleteCore } from '../core/googleAutocomplete';
|
|
146
|
+
// Re-export Error Types
|
|
147
|
+
export { TagadaError, TagadaApiError, TagadaNetworkError, TagadaAuthError, TagadaValidationError, TagadaCircuitBreakerError, TagadaErrorCode, } from '../core/errors';
|
|
21
148
|
export { FunnelActionType } from '../core/resources/funnel';
|
|
22
|
-
// Re-export Utilities
|
|
149
|
+
// Re-export Utilities (includes formatMoney from core/utils/currency)
|
|
23
150
|
export * from '../core/utils';
|
|
151
|
+
// Re-export path remapping utilities (for SPA routing)
|
|
152
|
+
export { matchRoute, getInternalPath, isPathRemapped, getPathInfo, } from '../core/pathRemapping';
|
|
153
|
+
// Re-export Step Config / Payment Flow helpers (for standalone resolvers / builders)
|
|
154
|
+
export { getAssignedPaymentFlowId };
|
|
155
|
+
export { getAssignedStepConfig } from '../core/funnelClient';
|
|
156
|
+
// Re-export Payment Service (standalone payment processing — no React)
|
|
157
|
+
export { PaymentService } from './payment-service';
|
|
158
|
+
/**
|
|
159
|
+
* Get BasisTheory public API key based on hostname detection.
|
|
160
|
+
* Delegates to the centralized isProductionBasisTheory() logic.
|
|
161
|
+
*/
|
|
162
|
+
export function getBasisTheoryApiKey() {
|
|
163
|
+
return _getBtApiKey();
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get BasisTheory tenant ID based on hostname detection.
|
|
167
|
+
*/
|
|
168
|
+
export function getBasisTheoryTenantId() {
|
|
169
|
+
return _getBtTenantId();
|
|
170
|
+
}
|
|
24
171
|
// ============================================================================
|
|
25
172
|
// EXTERNAL PAGE TRACKER
|
|
26
173
|
// ============================================================================
|