@tagadapay/plugin-sdk 3.1.22 → 3.1.25

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.
Files changed (89) hide show
  1. package/build-cdn.js +274 -6
  2. package/dist/external-tracker.js +476 -6774
  3. package/dist/external-tracker.min.js +2 -25
  4. package/dist/external-tracker.min.js.map +4 -4
  5. package/dist/react/config/payment.d.ts +14 -4
  6. package/dist/react/config/payment.js +47 -9
  7. package/dist/react/hooks/useCheckout.d.ts +3 -0
  8. package/dist/react/hooks/useCheckout.js +11 -3
  9. package/dist/react/hooks/usePluginConfig.js +9 -10
  10. package/dist/react/providers/TagadaProvider.js +1 -1
  11. package/dist/tagada-react-sdk-minimal.min.js +36 -0
  12. package/dist/tagada-react-sdk-minimal.min.js.map +7 -0
  13. package/dist/tagada-react-sdk.js +37988 -0
  14. package/dist/tagada-react-sdk.min.js +78 -0
  15. package/dist/tagada-react-sdk.min.js.map +7 -0
  16. package/dist/tagada-sdk.js +7847 -6420
  17. package/dist/tagada-sdk.min.js +4 -22
  18. package/dist/tagada-sdk.min.js.map +4 -4
  19. package/dist/v2/cdn-react-minimal.d.ts +23 -0
  20. package/dist/v2/cdn-react-minimal.js +26 -0
  21. package/dist/v2/core/client.js +2 -1
  22. package/dist/v2/core/config/environment.js +2 -1
  23. package/dist/v2/core/funnelClient.d.ts +106 -10
  24. package/dist/v2/core/funnelClient.js +122 -28
  25. package/dist/v2/core/index.d.ts +0 -1
  26. package/dist/v2/core/index.js +0 -2
  27. package/dist/v2/core/isoData.d.ts +4 -4
  28. package/dist/v2/core/isoData.js +7 -7
  29. package/dist/v2/core/pixelMapping.js +64 -26
  30. package/dist/v2/core/resources/apiClient.d.ts +18 -14
  31. package/dist/v2/core/resources/apiClient.js +151 -109
  32. package/dist/v2/core/resources/checkout.d.ts +10 -0
  33. package/dist/v2/core/resources/checkout.js +6 -0
  34. package/dist/v2/core/resources/expressPaymentMethods.d.ts +1 -0
  35. package/dist/v2/core/resources/index.d.ts +1 -1
  36. package/dist/v2/core/resources/index.js +1 -1
  37. package/dist/v2/core/resources/offers.js +4 -4
  38. package/dist/v2/core/resources/payments.d.ts +8 -2
  39. package/dist/v2/core/resources/payments.js +1 -0
  40. package/dist/v2/core/resources/postPurchases.d.ts +17 -0
  41. package/dist/v2/core/resources/postPurchases.js +20 -0
  42. package/dist/v2/core/utils/currency.d.ts +3 -0
  43. package/dist/v2/core/utils/currency.js +40 -2
  44. package/dist/v2/core/utils/deviceInfo.d.ts +1 -10
  45. package/dist/v2/core/utils/deviceInfo.js +153 -76
  46. package/dist/v2/core/utils/order.d.ts +2 -0
  47. package/dist/v2/core/utils/pluginConfig.js +18 -22
  48. package/dist/v2/core/utils/previewMode.js +12 -0
  49. package/dist/v2/index.d.ts +4 -3
  50. package/dist/v2/index.js +4 -2
  51. package/dist/v2/react/components/ApplePayButton.js +39 -16
  52. package/dist/v2/react/components/FunnelScriptInjector.js +145 -77
  53. package/dist/v2/react/components/StripeExpressButton.d.ts +13 -0
  54. package/dist/v2/react/components/StripeExpressButton.js +170 -0
  55. package/dist/v2/react/components/WhopCheckout.js +7 -1
  56. package/dist/v2/react/hooks/payment-actions/useAirwallexRadarAction.js +1 -0
  57. package/dist/v2/react/hooks/payment-actions/useProcessorAuthAction.js +21 -3
  58. package/dist/v2/react/hooks/useApiQuery.d.ts +1 -1
  59. package/dist/v2/react/hooks/useApiQuery.js +1 -1
  60. package/dist/v2/react/hooks/useApplePayCheckout.js +8 -8
  61. package/dist/v2/react/hooks/useCheckoutQuery.d.ts +10 -0
  62. package/dist/v2/react/hooks/useCheckoutQuery.js +27 -15
  63. package/dist/v2/react/hooks/useFunnel.d.ts +15 -4
  64. package/dist/v2/react/hooks/useFunnel.js +8 -4
  65. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +2 -0
  66. package/dist/v2/react/hooks/useGoogleAutocomplete.js +29 -15
  67. package/dist/v2/react/hooks/useISOData.d.ts +2 -5
  68. package/dist/v2/react/hooks/useISOData.js +25 -26
  69. package/dist/v2/react/hooks/usePaymentPolling.d.ts +2 -2
  70. package/dist/v2/react/hooks/usePixelTracking.js +151 -70
  71. package/dist/v2/react/hooks/usePostPurchasesQuery.js +34 -2
  72. package/dist/v2/react/hooks/usePreviewOffer.js +1 -1
  73. package/dist/v2/react/hooks/useRemappableParams.d.ts +2 -6
  74. package/dist/v2/react/hooks/useRemappableParams.js +23 -23
  75. package/dist/v2/react/hooks/useSetPaymentMethod.d.ts +16 -0
  76. package/dist/v2/react/hooks/useSetPaymentMethod.js +33 -0
  77. package/dist/v2/react/hooks/useStepConfig.d.ts +23 -6
  78. package/dist/v2/react/hooks/useStepConfig.js +14 -7
  79. package/dist/v2/react/hooks/useTranslation.js +23 -8
  80. package/dist/v2/react/index.d.ts +8 -1
  81. package/dist/v2/react/index.js +3 -0
  82. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +8 -0
  83. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +106 -10
  84. package/dist/v2/react/providers/TagadaProvider.js +5 -5
  85. package/dist/v2/standalone/index.d.ts +21 -3
  86. package/dist/v2/standalone/index.js +25 -3
  87. package/dist/v2/standalone/payment-service.d.ts +134 -0
  88. package/dist/v2/standalone/payment-service.js +929 -0
  89. package/package.json +4 -2
@@ -8,9 +8,9 @@ export interface Payment {
8
8
  id: string;
9
9
  status: string;
10
10
  subStatus: string;
11
- requireAction: 'none' | 'redirect' | 'redirect_to_payment' | 'error' | 'radar';
11
+ requireAction: 'none' | 'redirect' | 'redirect_to_payment' | 'error' | 'radar' | 'stripe_express_checkout';
12
12
  requireActionData?: {
13
- type: 'redirect' | 'redirect_to_payment' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar' | 'radar' | 'kesspay_auth' | 'trustflow_auth' | 'mastercard_auth';
13
+ type: 'redirect' | 'redirect_to_payment' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar' | 'radar' | 'kesspay_auth' | 'trustflow_auth' | 'mastercard_auth' | 'stripe_express_checkout';
14
14
  url?: string;
15
15
  processed: boolean;
16
16
  processorId?: string;
@@ -32,6 +32,10 @@ export interface Payment {
32
32
  orderId?: string;
33
33
  publishableKey?: string;
34
34
  };
35
+ stripeExpressCheckout?: {
36
+ clientSecret: string;
37
+ publishableKey?: string;
38
+ };
35
39
  provider?: string;
36
40
  isTest?: boolean;
37
41
  };
@@ -242,6 +246,7 @@ export declare class PaymentsResource {
242
246
  paymentFlowId?: string;
243
247
  processorId?: string;
244
248
  paymentMethod?: string;
249
+ isExpress?: boolean;
245
250
  }): Promise<PaymentResponse>;
246
251
  /**
247
252
  * Get card payment instruments for customer
@@ -274,6 +279,7 @@ export declare class PaymentsResource {
274
279
  error?: string;
275
280
  }>;
276
281
  saveRadarSession(data: {
282
+ paymentId?: string;
277
283
  orderId?: string;
278
284
  checkoutSessionId?: string;
279
285
  finixRadarSessionId?: string;
@@ -147,6 +147,7 @@ export class PaymentsResource {
147
147
  ...(options.paymentFlowId && { paymentFlowId: options.paymentFlowId }),
148
148
  ...(options.processorId && { processorId: options.processorId }),
149
149
  ...(options.paymentMethod && { paymentMethod: options.paymentMethod }),
150
+ ...(options.isExpress && { isExpress: options.isExpress }),
150
151
  };
151
152
  console.log('[PaymentsResource] Request body being sent:', JSON.stringify(requestBody, null, 2));
152
153
  const response = await this.apiClient.post('/api/public/v1/checkout/pay-v2', requestBody);
@@ -110,6 +110,7 @@ export interface CheckoutSessionState {
110
110
  selectedVariants: Record<string, string>;
111
111
  loadingVariants: Record<string, boolean>;
112
112
  isUpdatingSummary: boolean;
113
+ isWhop?: boolean;
113
114
  }
114
115
  export declare class PostPurchasesResource {
115
116
  private apiClient;
@@ -172,6 +173,22 @@ export declare class PostPurchasesResource {
172
173
  * Get order summary for a checkout session
173
174
  */
174
175
  getOrderSummary(sessionId: string, includeVariantOptions?: boolean): Promise<any>;
176
+ /**
177
+ * Get payment methods for a checkout session
178
+ */
179
+ getPaymentMethods(checkoutSessionId: string): Promise<{
180
+ type: string;
181
+ }[]>;
182
+ /**
183
+ * Charge a Whop post-purchase using the stored payment method from the original order
184
+ */
185
+ chargeWhopPostPurchase(params: {
186
+ checkoutSessionId: string;
187
+ orderId: string;
188
+ storeId: string;
189
+ }): Promise<{
190
+ checkoutRequestId: string;
191
+ }>;
175
192
  /**
176
193
  * Update line items for a checkout session
177
194
  */
@@ -108,6 +108,26 @@ export class PostPurchasesResource {
108
108
  includeVariantOptions,
109
109
  });
110
110
  }
111
+ /**
112
+ * Get payment methods for a checkout session
113
+ */
114
+ async getPaymentMethods(checkoutSessionId) {
115
+ return this.apiClient.get(`/api/v1/payment-methods?checkoutSessionId=${encodeURIComponent(checkoutSessionId)}`);
116
+ }
117
+ /**
118
+ * Charge a Whop post-purchase using the stored payment method from the original order
119
+ */
120
+ async chargeWhopPostPurchase(params) {
121
+ return this.apiClient.post(`/api/v1/checkout-sessions/${params.checkoutSessionId}/whop-charge-payment`, {
122
+ checkoutSessionId: params.checkoutSessionId,
123
+ orderId: params.orderId,
124
+ storeId: params.storeId,
125
+ metadata: {
126
+ comingFromPostPurchase: true,
127
+ originalOrderId: params.orderId,
128
+ },
129
+ });
130
+ }
111
131
  /**
112
132
  * Update line items for a checkout session
113
133
  */
@@ -7,6 +7,8 @@ export interface Currency {
7
7
  symbol: string;
8
8
  name: string;
9
9
  decimalPlaces: number;
10
+ /** True when the currency was explicitly set via URL param or persisted storage (not a SDK/store default) */
11
+ isExplicit: boolean;
10
12
  }
11
13
  /**
12
14
  * Format money amount from minor units (cents) to a formatted string
@@ -27,6 +29,7 @@ export declare class CurrencyUtils {
27
29
  * Get currency from context or fallback to default
28
30
  */
29
31
  static getCurrency(context: any, defaultCurrency?: string): Currency;
32
+ private static getCookieValue;
30
33
  /**
31
34
  * Get currency symbol
32
35
  */
@@ -47,9 +47,25 @@ export class CurrencyUtils {
47
47
  * Get currency from context or fallback to default
48
48
  */
49
49
  static getCurrency(context, defaultCurrency = 'USD') {
50
- // Handle case where context.currency might be a Currency object or string
51
50
  let currencyCode;
52
- if (typeof context?.currency === 'string') {
51
+ let isExplicit = false;
52
+ // 1. URL ?currency= param takes highest priority (set by CRM preview, storefront links, or currency selector)
53
+ const urlCurrency = typeof window !== 'undefined'
54
+ ? new URLSearchParams(window.location.search).get('currency')
55
+ : null;
56
+ // 2. Persisted tgd_currency from storage/cookie (survives navigation between funnel steps)
57
+ const storedCurrency = typeof window !== 'undefined'
58
+ ? (localStorage.getItem('tgd_currency') || CurrencyUtils.getCookieValue('tgd_currency'))
59
+ : null;
60
+ if (urlCurrency) {
61
+ currencyCode = urlCurrency.toUpperCase();
62
+ isExplicit = true;
63
+ }
64
+ else if (storedCurrency) {
65
+ currencyCode = storedCurrency.toUpperCase();
66
+ isExplicit = true;
67
+ }
68
+ else if (typeof context?.currency === 'string') {
53
69
  currencyCode = context.currency;
54
70
  }
55
71
  else if (context?.currency?.code) {
@@ -61,13 +77,35 @@ export class CurrencyUtils {
61
77
  else {
62
78
  currencyCode = defaultCurrency;
63
79
  }
80
+ // Validate against store's presentment currencies when available.
81
+ // This catches both explicit overrides (URL/storage) and fallback values that
82
+ // reference a currency the store doesn't support.
83
+ const presentment = context?.store?.presentmentCurrencies;
84
+ if (presentment?.length && !presentment.includes(currencyCode)) {
85
+ console.warn(`[CurrencyUtils] Currency "${currencyCode}" is not in store presentmentCurrencies [${presentment.join(', ')}]. Falling back to ${presentment[0]}.`);
86
+ currencyCode = presentment[0];
87
+ // Update persisted storage so subsequent renders don't keep requesting the unsupported currency
88
+ if (isExplicit && typeof window !== 'undefined') {
89
+ try {
90
+ localStorage.setItem('tgd_currency', currencyCode);
91
+ }
92
+ catch { }
93
+ }
94
+ }
64
95
  return {
65
96
  code: currencyCode,
66
97
  symbol: this.getCurrencySymbol(currencyCode),
67
98
  name: this.getCurrencyName(currencyCode),
68
99
  decimalPlaces: this.getDecimalPlaces(currencyCode),
100
+ isExplicit,
69
101
  };
70
102
  }
103
+ static getCookieValue(name) {
104
+ if (typeof document === 'undefined')
105
+ return null;
106
+ const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
107
+ return match ? decodeURIComponent(match[1]) : null;
108
+ }
71
109
  /**
72
110
  * Get currency symbol
73
111
  */
@@ -5,7 +5,6 @@ export interface DeviceInfo {
5
5
  major: string;
6
6
  name: string;
7
7
  version: string;
8
- type?: string;
9
8
  };
10
9
  os: {
11
10
  name: string;
@@ -36,21 +35,13 @@ export interface DeviceInfo {
36
35
  isAppleSilicon: boolean;
37
36
  };
38
37
  }
39
- /**
40
- * Get browser locale
41
- */
42
38
  export declare function getBrowserLocale(): string;
43
- /**
44
- * Collect all device information using UAParser
45
- */
46
39
  export declare function collectDeviceInfo(): DeviceInfo;
47
- /**
48
- * Get URL parameters for session initialization
49
- */
50
40
  export declare function getUrlParams(): {
51
41
  locale?: string;
52
42
  currency?: string;
53
43
  utmSource?: string;
54
44
  utmMedium?: string;
55
45
  utmCampaign?: string;
46
+ gclid?: string;
56
47
  };
@@ -1,44 +1,159 @@
1
- import { UAParser } from '@ua-parser-js/pro-enterprise';
2
- import { isBot, isChromeFamily, isStandalonePWA, isAppleSilicon, } from '@ua-parser-js/pro-enterprise/helpers';
3
- /**
4
- * Get screen resolution
5
- */
6
1
  function getScreenResolution() {
7
- return {
8
- width: window.screen.width,
9
- height: window.screen.height,
10
- };
2
+ return { width: window.screen.width, height: window.screen.height };
11
3
  }
12
- /**
13
- * Get timezone
14
- */
15
4
  function getTimeZone() {
16
5
  try {
17
6
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
18
7
  }
19
- catch (error) {
20
- console.error('Failed to get timezone:', error);
8
+ catch {
21
9
  return 'UTC';
22
10
  }
23
11
  }
24
- /**
25
- * Get browser locale
26
- */
27
12
  export function getBrowserLocale() {
28
13
  try {
29
14
  return navigator.language || 'en-US';
30
15
  }
31
- catch (error) {
32
- console.error('Failed to get browser locale:', error);
16
+ catch {
33
17
  return 'en-US';
34
18
  }
35
19
  }
36
- /**
37
- * Collect all device information using UAParser
38
- */
20
+ // ---------------------------------------------------------------------------
21
+ // Lightweight UA parsing no third-party library needed
22
+ // ---------------------------------------------------------------------------
23
+ const UA = typeof navigator !== 'undefined' ? navigator.userAgent : '';
24
+ /** Extract first match's groups from a UA string */
25
+ function match(ua, ...patterns) {
26
+ for (const p of patterns) {
27
+ const m = ua.match(p);
28
+ if (m)
29
+ return m;
30
+ }
31
+ return null;
32
+ }
33
+ function parseBrowser(ua) {
34
+ // Order matters — more specific first
35
+ const tests = [
36
+ [/EdgA?\/([\d.]+)/i, 'Edge'],
37
+ [/OPR\/([\d.]+)/i, 'Opera'],
38
+ [/Brave\/([\d.]+)/i, 'Brave'],
39
+ [/Vivaldi\/([\d.]+)/i, 'Vivaldi'],
40
+ [/SamsungBrowser\/([\d.]+)/i, 'Samsung Internet'],
41
+ [/UCBrowser\/([\d.]+)/i, 'UC Browser'],
42
+ [/Firefox\/([\d.]+)/i, 'Firefox'],
43
+ [/CriOS\/([\d.]+)/i, 'Chrome'], // Chrome on iOS
44
+ [/FxiOS\/([\d.]+)/i, 'Firefox'], // Firefox on iOS
45
+ [/Chrome\/([\d.]+)/i, 'Chrome'],
46
+ [/Version\/([\d.]+).*Safari/i, 'Safari'],
47
+ [/Safari\/([\d.]+)/i, 'Safari'],
48
+ ];
49
+ for (const [re, name] of tests) {
50
+ const m = ua.match(re);
51
+ if (m) {
52
+ const version = m[1] || '';
53
+ return { name, version, major: version.split('.')[0] || '' };
54
+ }
55
+ }
56
+ return { name: '', version: '', major: '' };
57
+ }
58
+ function parseOS(ua) {
59
+ const m = match(ua, /Windows NT ([\d.]+)/i) ||
60
+ match(ua, /Mac OS X ([\d_.]+)/i) ||
61
+ match(ua, /Android ([\d.]+)/i) ||
62
+ match(ua, /iPhone OS ([\d_]+)/i) ||
63
+ match(ua, /iPad.*OS ([\d_]+)/i) ||
64
+ match(ua, /CrOS[\w ]*\/([\d.]+)/i) ||
65
+ match(ua, /Linux/i);
66
+ if (!m)
67
+ return { name: '', version: '' };
68
+ const raw = m[0];
69
+ const version = (m[1] || '').replace(/_/g, '.');
70
+ if (/Windows/i.test(raw)) {
71
+ const ntMap = {
72
+ '10.0': '10', '6.3': '8.1', '6.2': '8', '6.1': '7', '6.0': 'Vista', '5.1': 'XP',
73
+ };
74
+ return { name: 'Windows', version: ntMap[version] || version };
75
+ }
76
+ if (/Mac OS X/i.test(raw))
77
+ return { name: 'macOS', version };
78
+ if (/Android/i.test(raw))
79
+ return { name: 'Android', version };
80
+ if (/iPhone|iPad/i.test(raw))
81
+ return { name: 'iOS', version };
82
+ if (/CrOS/i.test(raw))
83
+ return { name: 'Chrome OS', version };
84
+ if (/Linux/i.test(raw))
85
+ return { name: 'Linux', version: '' };
86
+ return { name: '', version: '' };
87
+ }
88
+ function parseDevice(ua) {
89
+ if (/iPad/i.test(ua))
90
+ return { type: 'tablet', vendor: 'Apple', model: 'iPad' };
91
+ if (/iPhone/i.test(ua))
92
+ return { type: 'mobile', vendor: 'Apple', model: 'iPhone' };
93
+ if (/iPod/i.test(ua))
94
+ return { type: 'mobile', vendor: 'Apple', model: 'iPod' };
95
+ if (/Android/i.test(ua)) {
96
+ const m = ua.match(/Android[\s\d.]+;\s*([^)]+?)(?:\s+Build)/i);
97
+ const mobile = /Mobile/i.test(ua);
98
+ return { type: mobile ? 'mobile' : 'tablet', model: m?.[1]?.trim() };
99
+ }
100
+ return undefined;
101
+ }
102
+ function parseEngine(ua) {
103
+ const m = match(ua, /AppleWebKit\/([\d.]+)/i) ||
104
+ match(ua, /Gecko\/([\d.]+)/i) ||
105
+ match(ua, /Trident\/([\d.]+)/i) ||
106
+ match(ua, /Presto\/([\d.]+)/i);
107
+ if (!m)
108
+ return { name: '', version: '' };
109
+ const raw = m[0];
110
+ const version = m[1] || '';
111
+ if (/AppleWebKit/i.test(raw))
112
+ return { name: 'WebKit', version };
113
+ if (/Gecko/i.test(raw))
114
+ return { name: 'Gecko', version };
115
+ if (/Trident/i.test(raw))
116
+ return { name: 'Trident', version };
117
+ if (/Presto/i.test(raw))
118
+ return { name: 'Presto', version };
119
+ return { name: '', version: '' };
120
+ }
121
+ function parseCPU(ua) {
122
+ if (/x86_64|x64|amd64|Win64/i.test(ua))
123
+ return { architecture: 'amd64' };
124
+ if (/ia32|x86/i.test(ua))
125
+ return { architecture: 'ia32' };
126
+ if (/aarch64|arm64/i.test(ua))
127
+ return { architecture: 'arm64' };
128
+ if (/arm/i.test(ua))
129
+ return { architecture: 'arm' };
130
+ return { architecture: '' };
131
+ }
132
+ // ---------------------------------------------------------------------------
133
+ // Flags
134
+ // ---------------------------------------------------------------------------
135
+ function detectIsBot() {
136
+ if (navigator.webdriver)
137
+ return true;
138
+ return /bot|crawl|spider|slurp|Googlebot|bingbot|yandex|baidu|duckduck|facebookexternalhit|Twitterbot|linkedinbot|embedly|quora|pinterest|redditbot|Slackbot|Discordbot|WhatsApp|TelegramBot|Applebot/i.test(UA);
139
+ }
140
+ function detectIsChromeFamily(browserName) {
141
+ return /Chrome|Chromium|Edge|Brave|Opera|Vivaldi|Arc/i.test(browserName);
142
+ }
143
+ function detectIsStandalonePWA() {
144
+ return window.matchMedia('(display-mode: standalone)').matches
145
+ || navigator.standalone === true;
146
+ }
147
+ function detectIsAppleSilicon(osName) {
148
+ if (!/mac/i.test(osName))
149
+ return false;
150
+ return navigator.maxTouchPoints > 0;
151
+ }
152
+ // ---------------------------------------------------------------------------
153
+ // Main
154
+ // ---------------------------------------------------------------------------
39
155
  export function collectDeviceInfo() {
40
156
  if (typeof window === 'undefined') {
41
- // Server-side fallback
42
157
  return {
43
158
  userAgent: {
44
159
  name: '',
@@ -50,75 +165,36 @@ export function collectDeviceInfo() {
50
165
  },
51
166
  screenResolution: { width: 0, height: 0 },
52
167
  timeZone: 'UTC',
53
- flags: {
54
- isBot: false,
55
- isChromeFamily: false,
56
- isStandalonePWA: false,
57
- isAppleSilicon: false,
58
- },
168
+ flags: { isBot: false, isChromeFamily: false, isStandalonePWA: false, isAppleSilicon: false },
59
169
  };
60
170
  }
61
- const parser = new UAParser();
62
- const result = parser.getResult();
63
- // Enhanced detection using UAParser official helpers
171
+ const browser = parseBrowser(UA);
172
+ const os = parseOS(UA);
173
+ const device = parseDevice(UA);
174
+ const engine = parseEngine(UA);
175
+ const cpu = parseCPU(UA);
64
176
  let flags;
65
177
  try {
66
178
  flags = {
67
- isBot: isBot(result),
68
- isChromeFamily: isChromeFamily(result),
69
- isStandalonePWA: isStandalonePWA(),
70
- isAppleSilicon: isAppleSilicon(result),
179
+ isBot: detectIsBot(),
180
+ isChromeFamily: detectIsChromeFamily(browser.name),
181
+ isStandalonePWA: detectIsStandalonePWA(),
182
+ isAppleSilicon: detectIsAppleSilicon(os.name),
71
183
  };
72
184
  }
73
- catch (error) {
74
- console.error('Failed to compute device flags:', error);
75
- flags = {
76
- isBot: false,
77
- isChromeFamily: false,
78
- isStandalonePWA: false,
79
- isAppleSilicon: false,
80
- };
185
+ catch {
186
+ flags = { isBot: false, isChromeFamily: false, isStandalonePWA: false, isAppleSilicon: false };
81
187
  }
82
188
  return {
83
- userAgent: {
84
- name: result.ua,
85
- browser: {
86
- major: result.browser.major || '',
87
- name: result.browser.name || '',
88
- version: result.browser.version || '',
89
- type: result.browser.type,
90
- },
91
- os: {
92
- name: result.os.name || '',
93
- version: result.os.version || '',
94
- },
95
- device: result.device.model || result.device.type || result.device.vendor
96
- ? {
97
- model: result.device.model,
98
- type: result.device.type,
99
- vendor: result.device.vendor,
100
- }
101
- : undefined,
102
- engine: {
103
- name: result.engine.name || '',
104
- version: result.engine.version || '',
105
- },
106
- cpu: {
107
- architecture: result.cpu.architecture || '',
108
- },
109
- },
189
+ userAgent: { name: UA, browser, os, device, engine, cpu },
110
190
  screenResolution: getScreenResolution(),
111
191
  timeZone: getTimeZone(),
112
192
  flags,
113
193
  };
114
194
  }
115
- /**
116
- * Get URL parameters for session initialization
117
- */
118
195
  export function getUrlParams() {
119
- if (typeof window === 'undefined') {
196
+ if (typeof window === 'undefined')
120
197
  return {};
121
- }
122
198
  const params = new URLSearchParams(window.location.search);
123
199
  return {
124
200
  locale: params.get('locale') || undefined,
@@ -126,5 +202,6 @@ export function getUrlParams() {
126
202
  utmSource: params.get('utm_source') || undefined,
127
203
  utmMedium: params.get('utm_medium') || undefined,
128
204
  utmCampaign: params.get('utm_campaign') || undefined,
205
+ gclid: params.get('gclid') || undefined,
129
206
  };
130
207
  }
@@ -24,6 +24,7 @@ export interface OrderLineItem {
24
24
  totalBillingCycles: number;
25
25
  unitAmountAfterFirstCycle: number;
26
26
  subscriptionSettings?: Record<string, unknown> | null;
27
+ properties?: Record<string, unknown>;
27
28
  orderLineItemProduct: {
28
29
  id: string;
29
30
  name: string;
@@ -46,6 +47,7 @@ export interface OrderLineItem {
46
47
  }
47
48
  export interface Order {
48
49
  id: string;
50
+ orderNumber: number;
49
51
  storeId: string;
50
52
  accountId: string;
51
53
  createdAt: string;
@@ -159,6 +159,22 @@ const getMetaContent = (name) => {
159
159
  const metaTag = document.querySelector(`meta[name="${name}"]`);
160
160
  return metaTag?.getAttribute('content') || undefined;
161
161
  };
162
+ /**
163
+ * Read config from window global (preferred) or fall back to x-plugin-config meta tag
164
+ * (retrocompat with old deployments that still inject the meta tag).
165
+ */
166
+ const readWindowConfig = () => {
167
+ if (typeof window !== 'undefined' && window.__TAGADA_PLUGIN_CONFIG__) {
168
+ return window.__TAGADA_PLUGIN_CONFIG__;
169
+ }
170
+ try {
171
+ const encoded = getMetaContent('x-plugin-config');
172
+ if (encoded)
173
+ return JSON.parse(decodeURIComponent(encoded));
174
+ }
175
+ catch { /* ignore */ }
176
+ return {};
177
+ };
162
178
  /**
163
179
  * Synchronously get plugin config from meta tags
164
180
  * This is a lightweight sync alternative to loadPluginConfig
@@ -173,16 +189,7 @@ export function getPluginConfig() {
173
189
  const storeId = getMetaContent('x-plugin-store-id');
174
190
  const accountId = getMetaContent('x-plugin-account-id');
175
191
  const basePath = getMetaContent('x-plugin-base-path') || '/';
176
- let config = {};
177
- try {
178
- const encodedConfig = getMetaContent('x-plugin-config');
179
- if (encodedConfig) {
180
- config = JSON.parse(decodeURIComponent(encodedConfig));
181
- }
182
- }
183
- catch (error) {
184
- console.warn('[TagadaSDK] Failed to parse plugin config from meta tag:', error);
185
- }
192
+ const config = readWindowConfig();
186
193
  return { storeId, accountId, basePath, config };
187
194
  }
188
195
  /**
@@ -206,18 +213,7 @@ const loadProductionConfig = async () => {
206
213
  return null;
207
214
  }
208
215
  const basePath = getMetaContent('x-plugin-base-path') || '/';
209
- // Get deployment config from meta tags
210
- let config = {};
211
- try {
212
- const encodedConfig = getMetaContent('x-plugin-config');
213
- if (encodedConfig) {
214
- const decodedConfig = decodeURIComponent(encodedConfig);
215
- config = JSON.parse(decodedConfig);
216
- }
217
- }
218
- catch (error) {
219
- console.warn('⚠️ Failed to parse plugin config from meta tag:', error);
220
- }
216
+ const config = readWindowConfig();
221
217
  // Final validation
222
218
  if (!accountId) {
223
219
  console.warn('⚠️ Plugin config: Account ID not found in meta tags');
@@ -360,6 +360,18 @@ function persistSDKParamsFromURL() {
360
360
  if (urlBaseUrl) {
361
361
  setClientBaseUrl(urlBaseUrl);
362
362
  }
363
+ // Persist currency if in URL (survives navigation between funnel steps)
364
+ const urlCurrency = urlParams.get('currency');
365
+ if (urlCurrency) {
366
+ setInStorage(STORAGE_KEYS.CURRENCY, urlCurrency.toUpperCase());
367
+ setInCookie(STORAGE_KEYS.CURRENCY, urlCurrency.toUpperCase(), 86400);
368
+ }
369
+ // Persist locale if in URL
370
+ const urlLocale = urlParams.get('locale');
371
+ if (urlLocale) {
372
+ setInStorage(STORAGE_KEYS.LOCALE, urlLocale);
373
+ setInCookie(STORAGE_KEYS.LOCALE, urlLocale, 86400);
374
+ }
363
375
  }
364
376
  /**
365
377
  * Set funnel tracking mode in storage for persistence
@@ -13,8 +13,8 @@ export * from './core/utils/pluginConfig';
13
13
  export * from './core/utils/previewMode';
14
14
  export { injectPreviewModeIndicator, isIndicatorInjected, removePreviewModeIndicator } from './core/utils/previewModeIndicator';
15
15
  export * from './core/utils/products';
16
- export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedStepConfig, getLocalFunnelConfig, loadLocalFunnelConfig } from './core/funnelClient';
17
- export type { LocalFunnelConfig, PixelsConfig, RuntimeStepConfig } from './core/funnelClient';
16
+ export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedResources, getAssignedStepConfig, getAssignedOrderBumpOfferIds, getAssignedUpsellOfferIds, getLocalFunnelConfig, getEnabledMethods, getExpressMethods, getExpressMethodsByProcessor, findMethod, isMethodEnabled, loadLocalFunnelConfig } from './core/funnelClient';
17
+ export type { LocalFunnelConfig, PaymentMethodConfig, PaymentSetupConfig, PaymentSetupMethod, PixelsConfig, RuntimeStepConfig } from './core/funnelClient';
18
18
  export * from './core/pathRemapping';
19
19
  export type { CheckoutData, CheckoutInitParams, CheckoutLineItem, CheckoutSession, CheckoutSessionPreview, Promotion } from './core/resources/checkout';
20
20
  export type { Order, OrderLineItem } from './core/utils/order';
@@ -28,8 +28,9 @@ export type { ToggleOrderBumpResponse, VipOffer, VipPreviewResponse } from './co
28
28
  export type { StoreConfig } from './core/resources/storeConfig';
29
29
  export { FunnelActionType } from './core/resources/funnel';
30
30
  export type { BackNavigationActionData, CartUpdatedActionData, DirectNavigationActionData, FormSubmitActionData, FunnelContextUpdateRequest, FunnelContextUpdateResponse, FunnelAction as FunnelEvent, FunnelInitializeRequest, FunnelInitializeResponse, FunnelNavigateRequest, FunnelNavigateResponse, FunnelNavigationAction, FunnelNavigationResult, NextAction, OfferAcceptedActionData, OfferDeclinedActionData, PaymentFailedActionData, PaymentSuccessActionData, SimpleFunnelContext } from './core/resources/funnel';
31
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useGooglePayCheckout, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePixelTracking, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers, WhopCheckout, useWhopPaymentPolling } from './react';
31
+ export { ApplePayButton, StripeExpressButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useGooglePayCheckout, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePixelTracking, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers, useSetPaymentMethod, WhopCheckout, useWhopPaymentPolling } from './react';
32
32
  export type { DebugScript } from './react';
33
+ export type { PaymentMethodName } from './react';
33
34
  export type { TranslateFunction, TranslationText, UseTranslationOptions, UseTranslationResult } from './react/hooks/useTranslation';
34
35
  export type { FunnelContextValue } from './react/hooks/useFunnel';
35
36
  export type { UseApplePayCheckoutOptions } from './react/hooks/useApplePayCheckout';
package/dist/v2/index.js CHANGED
@@ -15,11 +15,13 @@ export * from './core/utils/previewMode';
15
15
  export { injectPreviewModeIndicator, isIndicatorInjected, removePreviewModeIndicator } from './core/utils/previewModeIndicator';
16
16
  export * from './core/utils/products';
17
17
  // Step config utilities (for reading runtime configuration from HTML)
18
- export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedStepConfig, getLocalFunnelConfig,
18
+ export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedResources, getAssignedStepConfig, getAssignedOrderBumpOfferIds, getAssignedUpsellOfferIds, getLocalFunnelConfig,
19
+ // Payment setup config helpers
20
+ getEnabledMethods, getExpressMethods, getExpressMethodsByProcessor, findMethod, isMethodEnabled,
19
21
  // Local development helpers
20
22
  loadLocalFunnelConfig } from './core/funnelClient';
21
23
  // Path remapping helpers (framework-agnostic)
22
24
  export * from './core/pathRemapping';
23
25
  export { FunnelActionType } from './core/resources/funnel';
24
26
  // React exports (hooks and components only, types are exported above)
25
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useGooglePayCheckout, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePixelTracking, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers, WhopCheckout, useWhopPaymentPolling } from './react';
27
+ export { ApplePayButton, StripeExpressButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useGooglePayCheckout, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePixelTracking, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers, useSetPaymentMethod, WhopCheckout, useWhopPaymentPolling } from './react';