@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
@@ -85,9 +85,24 @@ export const useTranslation = (options = {}) => {
85
85
  // Even without params, we need to unescape any escaped characters
86
86
  return str.replace(/\\([{}<>])/g, '$1');
87
87
  }
88
+ // Replace escaped characters with sentinels so they are not matched
89
+ // by tag/placeholder regexes (avoids lookbehind which breaks older Safari)
90
+ const ESC_LT = '\x00ELT\x00';
91
+ const ESC_GT = '\x00EGT\x00';
92
+ const ESC_LB = '\x00ELB\x00';
93
+ const ESC_RB = '\x00ERB\x00';
94
+ const restoreSentinels = (s) => s.replace(/\x00ELT\x00/g, '<')
95
+ .replace(/\x00EGT\x00/g, '>')
96
+ .replace(/\x00ELB\x00/g, '{')
97
+ .replace(/\x00ERB\x00/g, '}');
98
+ str = str
99
+ .replace(/\\</g, ESC_LT)
100
+ .replace(/\\>/g, ESC_GT)
101
+ .replace(/\\{/g, ESC_LB)
102
+ .replace(/\\}/g, ESC_RB);
88
103
  // First, process tag-based interpolation for functions
89
- // Match tags like <i>content</i> but not \<i>content</i>
90
- const tagRegex = /(?<!\\)<(\w+)>(.*?)(?<!\\)<\/\1>/g;
104
+ // Match tags like <i>content</i> (escaped tags are already replaced with sentinels)
105
+ const tagRegex = /<(\w+)>(.*?)<\/\1>/g;
91
106
  const hasTags = tagRegex.test(str);
92
107
  if (hasTags) {
93
108
  // Reset regex lastIndex for reuse
@@ -125,13 +140,13 @@ export const useTranslation = (options = {}) => {
125
140
  // Process {key} placeholders in string parts
126
141
  let processed = Object.entries(params).reduce((acc, [key, value]) => {
127
142
  if (typeof value !== 'function') {
128
- const regex = new RegExp(`(?<!\\\\)\\{${key}\\}`, 'g');
143
+ const regex = new RegExp(`\\{${key}\\}`, 'g');
129
144
  return acc.replace(regex, String(value));
130
145
  }
131
146
  return acc;
132
147
  }, part);
133
- // Unescape escaped characters
134
- processed = processed.replace(/\\([{}<>])/g, '$1');
148
+ // Restore sentinels to literal characters
149
+ processed = restoreSentinels(processed);
135
150
  return processed;
136
151
  }
137
152
  return part;
@@ -149,13 +164,13 @@ export const useTranslation = (options = {}) => {
149
164
  // Process {key} placeholders for string/number values
150
165
  let result = Object.entries(params).reduce((acc, [key, value]) => {
151
166
  if (typeof value !== 'function') {
152
- const regex = new RegExp(`(?<!\\\\)\\{${key}\\}`, 'g');
167
+ const regex = new RegExp(`\\{${key}\\}`, 'g');
153
168
  return acc.replace(regex, String(value));
154
169
  }
155
170
  return acc;
156
171
  }, str);
157
- // Remove escape characters from escaped characters (\{ -> {, \} -> }, \< -> <, \> -> >)
158
- result = result.replace(/\\([{}<>])/g, '$1');
172
+ // Restore sentinels to literal characters (\{ -> {, \} -> }, \< -> <, \> -> >)
173
+ result = restoreSentinels(result);
159
174
  return result;
160
175
  };
161
176
  if (!text)
@@ -6,6 +6,7 @@ export { ExpressPaymentMethodsProvider } from './providers/ExpressPaymentMethods
6
6
  export { TagadaProvider, useTagadaContext } from './providers/TagadaProvider';
7
7
  export type { DebugScript } from './providers/TagadaProvider';
8
8
  export { ApplePayButton } from './components/ApplePayButton';
9
+ export { StripeExpressButton } from './components/StripeExpressButton';
9
10
  export { GooglePayButton } from './components/GooglePayButton';
10
11
  export { PreviewModeIndicator } from './components/PreviewModeIndicator';
11
12
  export { WhopCheckout } from './components/WhopCheckout';
@@ -41,6 +42,7 @@ export { usePostPurchasesQuery as usePostPurchases } from './hooks/usePostPurcha
41
42
  export { usePreviewOffer } from './hooks/usePreviewOffer';
42
43
  export { useProductsQuery as useProducts } from './hooks/useProductsQuery';
43
44
  export { usePromotionsQuery as usePromotions } from './hooks/usePromotionsQuery';
45
+ export { useSetPaymentMethod } from './hooks/useSetPaymentMethod';
44
46
  export { useShippingRatesQuery as useShippingRates } from './hooks/useShippingRatesQuery';
45
47
  export { useStoreConfigQuery as useStoreConfig } from './hooks/useStoreConfigQuery';
46
48
  export { useThreeds } from './hooks/useThreeds';
@@ -63,6 +65,7 @@ export type { ExpressPaymentMethodsContextType, ExpressPaymentMethodsProviderPro
63
65
  export type { UseGooglePayCheckoutOptions } from './hooks/useGooglePayCheckout';
64
66
  export type { UseLoginOptions, UseLoginResult } from './hooks/useLogin';
65
67
  export type { ApplePayButtonProps } from './components/ApplePayButton';
68
+ export type { StripeExpressButtonProps } from './components/StripeExpressButton';
66
69
  export type { GooglePayButtonProps } from './components/GooglePayButton';
67
70
  export type { PreviewModeIndicatorProps } from './components/PreviewModeIndicator';
68
71
  export type { WhopCheckoutHandle, WhopCheckoutProps } from './components/WhopCheckout';
@@ -73,11 +76,13 @@ export type { ISOCountry, ISORegion, UseISODataResult } from './hooks/useISOData
73
76
  export type { UsePluginConfigOptions, UsePluginConfigResult } from './hooks/usePluginConfig';
74
77
  export type { TranslateFunction, UseTranslationOptions, UseTranslationResult } from './hooks/useTranslation';
75
78
  export { FunnelActionType } from '../core/resources/funnel';
76
- export type { UseCheckoutQueryOptions as UseCheckoutOptions, UseCheckoutQueryResult as UseCheckoutResult } from './hooks/useCheckoutQuery';
79
+ export type { CheckoutMessages, UseCheckoutQueryOptions as UseCheckoutOptions, UseCheckoutQueryResult as UseCheckoutResult } from './hooks/useCheckoutQuery';
77
80
  export type { UseDiscountsQueryOptions as UseDiscountsOptions, UseDiscountsQueryResult as UseDiscountsResult } from './hooks/useDiscountsQuery';
78
81
  export type { FunnelAction, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from '../core/resources/funnel';
79
82
  export type { FunnelContextValue, StepConfigValue } from './hooks/useFunnel';
80
83
  export type { UseStepConfigResult } from './hooks/useStepConfig';
84
+ export type { RuntimeStepConfig, PaymentMethodConfig, PaymentSetupConfig, PaymentSetupMethod } from '../core/funnelClient';
85
+ export { getEnabledMethods, getExpressMethods, getExpressMethodsByProcessor, findMethod, isMethodEnabled } from '../core/funnelClient';
81
86
  export type { UseFunnelOptions as UseFunnelLegacyOptions, UseFunnelResult as UseFunnelLegacyResult } from './hooks/useFunnelLegacy';
82
87
  export type { AvailableVariant, LineItemSelection, OfferLineItem, OfferPreviewSummary, UseOfferQueryOptions as UseOfferOptions, UseOfferQueryResult as UseOfferResult } from './hooks/useOfferQuery';
83
88
  export type { UseOrderBumpQueryOptions as UseOrderBumpOptions, UseOrderBumpQueryResult as UseOrderBumpResult } from './hooks/useOrderBumpQuery';
@@ -88,6 +93,7 @@ export type { UsePostPurchasesQueryOptions as UsePostPurchasesOptions, UsePostPu
88
93
  export type { PreviewOfferSummary, UsePreviewOfferOptions, UsePreviewOfferResult } from './hooks/usePreviewOffer';
89
94
  export type { UseProductsQueryOptions as UseProductsOptions, UseProductsQueryResult as UseProductsResult } from './hooks/useProductsQuery';
90
95
  export type { UsePromotionsQueryOptions as UsePromotionsOptions, UsePromotionsQueryResult as UsePromotionsResult } from './hooks/usePromotionsQuery';
96
+ export type { UseSetPaymentMethodOptions, UseSetPaymentMethodResult } from './hooks/useSetPaymentMethod';
91
97
  export type { UseShippingRatesQueryOptions as UseShippingRatesOptions, UseShippingRatesQueryResult as UseShippingRatesResult } from './hooks/useShippingRatesQuery';
92
98
  export type { UseStoreConfigQueryOptions as UseStoreConfigOptions, UseStoreConfigQueryResult as UseStoreConfigResult } from './hooks/useStoreConfigQuery';
93
99
  export type { PaymentInstrument, ThreedsChallenge, ThreedsHook, ThreedsOptions, ThreedsProvider, ThreedsSession } from './hooks/useThreeds';
@@ -95,5 +101,6 @@ export type { UseVipOffersQueryOptions as UseVipOffersOptions, UseVipOffersQuery
95
101
  export { formatMoney } from '../../react/utils/money';
96
102
  export { TagadaError, TagadaApiError, TagadaNetworkError, TagadaAuthError, TagadaValidationError, TagadaCircuitBreakerError, TagadaErrorCode, } from '../core/errors';
97
103
  export type { TagadaErrorOptions, TagadaErrorCodeValue } from '../core/errors';
104
+ export type { PaymentMethodName } from '../core/resources/checkout';
98
105
  export type { Order, OrderItem as CoreOrderItem, OrderAddress, OrderSummary, OrderWithRelations, PaymentSummary, PromotionSummary, Subscription, DeviceInfo, PromotionCode, Customer, Store, PickupPoint, } from '../core/types';
99
106
  export type OrderItem = import('../core/utils/order').OrderLineItem;
@@ -7,6 +7,7 @@ export { ExpressPaymentMethodsProvider } from './providers/ExpressPaymentMethods
7
7
  export { TagadaProvider, useTagadaContext } from './providers/TagadaProvider';
8
8
  // Components
9
9
  export { ApplePayButton } from './components/ApplePayButton';
10
+ export { StripeExpressButton } from './components/StripeExpressButton';
10
11
  export { GooglePayButton } from './components/GooglePayButton';
11
12
  export { PreviewModeIndicator } from './components/PreviewModeIndicator';
12
13
  export { WhopCheckout } from './components/WhopCheckout';
@@ -43,6 +44,7 @@ export { usePostPurchasesQuery as usePostPurchases } from './hooks/usePostPurcha
43
44
  export { usePreviewOffer } from './hooks/usePreviewOffer';
44
45
  export { useProductsQuery as useProducts } from './hooks/useProductsQuery';
45
46
  export { usePromotionsQuery as usePromotions } from './hooks/usePromotionsQuery';
47
+ export { useSetPaymentMethod } from './hooks/useSetPaymentMethod';
46
48
  export { useShippingRatesQuery as useShippingRates } from './hooks/useShippingRatesQuery';
47
49
  export { useStoreConfigQuery as useStoreConfig } from './hooks/useStoreConfigQuery';
48
50
  export { useThreeds } from './hooks/useThreeds';
@@ -58,6 +60,7 @@ export { useStepConfig } from './hooks/useStepConfig';
58
60
  export { useFunnel as useFunnelLegacy, useSimpleFunnel } from './hooks/useFunnelLegacy';
59
61
  // TanStack Query types
60
62
  export { FunnelActionType } from '../core/resources/funnel';
63
+ export { getEnabledMethods, getExpressMethods, getExpressMethodsByProcessor, findMethod, isMethodEnabled } from '../core/funnelClient';
61
64
  // Re-export utilities from main react
62
65
  export { formatMoney } from '../../react/utils/money';
63
66
  // Error types
@@ -1,9 +1,14 @@
1
1
  /**
2
2
  * Express Payment Methods Context Provider using v2 Architecture
3
3
  * Manages express payment methods (Apple Pay, Google Pay, PayPal, Klarna)
4
+ *
5
+ * Payment methods are resolved from:
6
+ * 1. paymentSetupConfig prop (from __TGD_STEP_CONFIG__ or useStepConfig)
7
+ * 2. API fallback (GET /api/v1/payment-methods) for legacy integrations
4
8
  */
5
9
  import React, { ReactNode } from 'react';
6
10
  import { TagadaError } from '../../core/errors';
11
+ import type { PaymentSetupConfig } from '../../core/funnelClient';
7
12
  import { CheckoutData } from '../../core/resources/checkout';
8
13
  import { Address, PaymentMethod } from '../../core/resources/expressPaymentMethods';
9
14
  type ExpressOrderLineItem = {
@@ -22,6 +27,7 @@ interface ExpressPaymentMethodsContextType {
22
27
  googlePayPaymentMethod?: PaymentMethod;
23
28
  paypalPaymentMethod?: PaymentMethod;
24
29
  klarnaPaymentMethod?: PaymentMethod;
30
+ stripeExpressPaymentMethod?: PaymentMethod;
25
31
  availableExpressPaymentMethodIds: string[];
26
32
  setAvailableExpressPaymentMethodIds: (value: string[]) => void;
27
33
  handleAddExpressId: (id: string) => void;
@@ -55,6 +61,8 @@ interface ExpressPaymentMethodsProviderProps {
55
61
  children: ReactNode;
56
62
  customerId?: string;
57
63
  checkout?: CheckoutData;
64
+ /** Step-level payment config from __TGD_STEP_CONFIG__ / useStepConfig(). */
65
+ paymentSetupConfig?: PaymentSetupConfig;
58
66
  }
59
67
  export declare const ExpressPaymentMethodsContext: React.Context<ExpressPaymentMethodsContextType | undefined>;
60
68
  export declare const ExpressPaymentMethodsProvider: React.FC<ExpressPaymentMethodsProviderProps>;
@@ -2,19 +2,66 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
2
  /**
3
3
  * Express Payment Methods Context Provider using v2 Architecture
4
4
  * Manages express payment methods (Apple Pay, Google Pay, PayPal, Klarna)
5
+ *
6
+ * Payment methods are resolved from:
7
+ * 1. paymentSetupConfig prop (from __TGD_STEP_CONFIG__ or useStepConfig)
8
+ * 2. API fallback (GET /api/v1/payment-methods) for legacy integrations
5
9
  */
6
10
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
7
- import { createContext, useCallback, useMemo, useState } from 'react';
11
+ import { createContext, useCallback, useEffect, useMemo, useState } from 'react';
8
12
  import { TagadaError, TagadaErrorCode } from '../../core/errors';
9
13
  import { ExpressPaymentMethodsResource, } from '../../core/resources/expressPaymentMethods';
10
14
  import { getGlobalApiClient } from '../hooks/useApiQuery';
11
15
  import { useShippingRatesQuery } from '../hooks/useShippingRatesQuery';
12
16
  export const ExpressPaymentMethodsContext = createContext(undefined);
13
- export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout, }) => {
17
+ /**
18
+ * Synthesize PaymentMethod[] from paymentSetupConfig entries.
19
+ * Converts express_checkout:processorId entries into the shape the provider expects.
20
+ */
21
+ function paymentMethodsFromSetupConfig(config) {
22
+ const methods = [];
23
+ for (const [key, entry] of Object.entries(config)) {
24
+ if (!entry.enabled)
25
+ continue;
26
+ // express_checkout:processorId entries → synthesize a stripe_apm-style method
27
+ if (key.startsWith('express_checkout:') && entry.methods) {
28
+ methods.push({
29
+ id: key,
30
+ type: 'stripe_apm',
31
+ title: entry.label || 'Express Checkout',
32
+ iconUrl: entry.logoUrl || '',
33
+ default: false,
34
+ settings: {
35
+ publishableKey: entry.publishableKey,
36
+ processors: [{
37
+ processorId: entry.processorId,
38
+ methods: entry.methods,
39
+ }],
40
+ },
41
+ });
42
+ continue;
43
+ }
44
+ // Individual express methods (apple_pay, google_pay, etc.)
45
+ if (entry.express || entry.type === 'apple_pay' || entry.type === 'google_pay') {
46
+ methods.push({
47
+ id: key,
48
+ type: entry.type || entry.method || key,
49
+ title: entry.label || key,
50
+ iconUrl: entry.logoUrl || '',
51
+ default: false,
52
+ settings: { processorId: entry.processorId, publishableKey: entry.publishableKey },
53
+ });
54
+ }
55
+ }
56
+ return methods;
57
+ }
58
+ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout, paymentSetupConfig, }) => {
14
59
  const queryClient = useQueryClient();
15
60
  const [availableExpressPaymentMethodIds, setAvailableExpressPaymentMethodIds] = useState([]);
16
61
  const [error, setError] = useState(null);
17
62
  const checkoutSessionId = checkout?.checkoutSession?.id;
63
+ // If paymentSetupConfig is provided, derive payment methods from it (no API call needed)
64
+ const configDerivedMethods = useMemo(() => paymentSetupConfig ? paymentMethodsFromSetupConfig(paymentSetupConfig) : undefined, [paymentSetupConfig]);
18
65
  // Create express payment methods resource client
19
66
  const expressPaymentResource = useMemo(() => {
20
67
  try {
@@ -25,14 +72,15 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
25
72
  (error instanceof Error ? error.message : 'Unknown error'));
26
73
  }
27
74
  }, []);
28
- // Fetch payment methods using TanStack Query
29
- const { data: paymentMethods, isLoading: isLoadingPaymentMethods } = useQuery({
75
+ // Only fetch from API when paymentSetupConfig is NOT provided
76
+ const { data: apiPaymentMethods, isLoading: isLoadingPaymentMethods } = useQuery({
30
77
  queryKey: ['payment-methods', checkoutSessionId],
31
78
  queryFn: () => expressPaymentResource.getPaymentMethods(checkoutSessionId),
32
- enabled: !!checkoutSessionId,
33
- staleTime: 60000, // 1 minute
79
+ enabled: !!checkoutSessionId && !configDerivedMethods,
80
+ staleTime: 60000,
34
81
  refetchOnWindowFocus: false,
35
82
  });
83
+ const paymentMethods = configDerivedMethods ?? apiPaymentMethods;
36
84
  // Use v2 shipping rates hook
37
85
  const { shippingRates, refetch: refetchRates } = useShippingRatesQuery({ checkout });
38
86
  // Get order summary from checkout data
@@ -161,8 +209,48 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
161
209
  return;
162
210
  await updateEmailMutation.mutateAsync(input.data);
163
211
  }, [customerId, updateEmailMutation]);
164
- // Check if Apple Pay is available (window.ApplePaySession only exists on Apple devices)
165
- const isApplePayAvailable = typeof window !== 'undefined' && typeof window.ApplePaySession !== 'undefined';
212
+ // Check if Apple Pay is available load SDK on demand then re-check reactively
213
+ const [isApplePayAvailable, setIsApplePayAvailable] = useState(() => typeof window !== 'undefined' && typeof window.ApplePaySession !== 'undefined');
214
+ const [isApplePaySdkLoading, setIsApplePaySdkLoading] = useState(false);
215
+ const hasApplePayConfig = paymentMethods?.some((p) => p.type === 'apple_pay');
216
+ useEffect(() => {
217
+ if (isApplePayAvailable || !hasApplePayConfig)
218
+ return;
219
+ const APPLE_PAY_SDK_URL = 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js';
220
+ const onSdkReady = () => {
221
+ if (typeof window.ApplePaySession !== 'undefined') {
222
+ setIsApplePayAvailable(true);
223
+ }
224
+ setIsApplePaySdkLoading(false);
225
+ };
226
+ // Check if script is already in DOM (may still be loading)
227
+ const existing = document.querySelector(`script[src="${APPLE_PAY_SDK_URL}"]`);
228
+ if (existing) {
229
+ setIsApplePaySdkLoading(true);
230
+ // Script may already be loaded or still loading
231
+ if (typeof window.ApplePaySession !== 'undefined') {
232
+ onSdkReady();
233
+ }
234
+ else {
235
+ existing.addEventListener('load', onSdkReady);
236
+ // Fallback timeout in case we missed the load event
237
+ const timer = setTimeout(onSdkReady, 2000);
238
+ return () => {
239
+ existing.removeEventListener('load', onSdkReady);
240
+ clearTimeout(timer);
241
+ };
242
+ }
243
+ return;
244
+ }
245
+ setIsApplePaySdkLoading(true);
246
+ const script = document.createElement('script');
247
+ script.src = APPLE_PAY_SDK_URL;
248
+ script.crossOrigin = 'anonymous';
249
+ script.async = true;
250
+ script.onload = onSdkReady;
251
+ script.onerror = () => setIsApplePaySdkLoading(false);
252
+ document.head.appendChild(script);
253
+ }, [isApplePayAvailable, hasApplePayConfig]);
166
254
  // Identify specific payment method types
167
255
  const applePayPaymentMethod = useMemo(() => {
168
256
  return isApplePayAvailable ? paymentMethods?.find((p) => p.type === 'apple_pay') : undefined;
@@ -170,7 +258,14 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
170
258
  const googlePayPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'google_pay'), [paymentMethods]);
171
259
  const paypalPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'paypal'), [paymentMethods]);
172
260
  const klarnaPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'klarna'), [paymentMethods]);
173
- const loading = !paymentMethods || isLoadingPaymentMethods;
261
+ // Find a stripe_apm or tagadapay_apm integration with any express method enabled in any processor group.
262
+ // Backward compatible: existing configs with only apple_pay/google_pay continue to match.
263
+ const stripeExpressPaymentMethod = useMemo(() => {
264
+ const EXPRESS_METHOD_KEYS = ['apple_pay', 'google_pay', 'paypal', 'link', 'klarna_express'];
265
+ return paymentMethods?.find((p) => (p.type === 'stripe_apm' || p.type === 'tagadapay_apm') &&
266
+ p.settings?.processors?.some((g) => EXPRESS_METHOD_KEYS.some((key) => g?.methods?.[key]?.enabled === true)));
267
+ }, [paymentMethods]);
268
+ const loading = !paymentMethods || (!configDerivedMethods && isLoadingPaymentMethods) || isApplePaySdkLoading;
174
269
  const tagadaError = useMemo(() => error ? new TagadaError(error, { code: TagadaErrorCode.PAYMENT_FAILED }) : null, [error]);
175
270
  const contextValue = {
176
271
  paymentMethods,
@@ -180,6 +275,7 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
180
275
  googlePayPaymentMethod,
181
276
  paypalPaymentMethod,
182
277
  klarnaPaymentMethod,
278
+ stripeExpressPaymentMethod,
183
279
  shippingMethods,
184
280
  lineItems,
185
281
  reComputeOrderSummary,
@@ -190,6 +286,6 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
190
286
  error: tagadaError,
191
287
  setError,
192
288
  };
193
- const hasAnyEnabled = Boolean(applePayPaymentMethod || googlePayPaymentMethod || paypalPaymentMethod || klarnaPaymentMethod);
289
+ const hasAnyEnabled = Boolean(applePayPaymentMethod || googlePayPaymentMethod || paypalPaymentMethod || klarnaPaymentMethod || stripeExpressPaymentMethod);
194
290
  return (_jsx(ExpressPaymentMethodsContext.Provider, { value: contextValue, children: hasAnyEnabled ? _jsx(_Fragment, { children: children }) : _jsx(_Fragment, {}) }));
195
291
  };
@@ -4,14 +4,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  * TagadaProvider - Main provider component for the Tagada Pay React SDK
5
5
  */
6
6
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
7
- import { Suspense, createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
7
+ import { Suspense, createContext, lazy, useCallback, useContext, useEffect, useMemo, useState } from 'react';
8
8
  import { ApiService } from '../../../react/services/apiService';
9
9
  import { convertCurrency, formatMoney, formatMoneyWithoutSymbol, formatSimpleMoney, getCurrencyInfo, minorUnitsToMajorUnits, moneyStringOrNumberToMinorUnits, } from '../../../react/utils/money';
10
10
  import { TagadaClient } from '../../core/client';
11
- import { default as DebugDrawer } from '../components/DebugDrawer';
12
- import { FunnelScriptInjector } from '../components/FunnelScriptInjector';
13
11
  import { setGlobalApiClient } from '../hooks/useApiQuery';
14
12
  import { PixelTrackingProvider } from '../hooks/usePixelTracking';
13
+ const FunnelScriptInjector = lazy(() => import('../components/FunnelScriptInjector').then(m => ({ default: m.FunnelScriptInjector })));
14
+ const DebugDrawer = lazy(() => import('../components/DebugDrawer'));
15
15
  // Professional, subtle loading component for initialization
16
16
  const InitializationLoader = () => (_jsxs("div", { style: {
17
17
  position: 'fixed',
@@ -315,7 +315,7 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
315
315
  console.log('🚀 [TagadaProvider] Auto-redirecting to:', result.url);
316
316
  // Set pending redirect flag BEFORE navigation to prevent renders
317
317
  setPendingRedirect(true);
318
- window.location.href = result.url;
318
+ window.location.replace(result.url);
319
319
  }
320
320
  };
321
321
  const next = async (event, options) => {
@@ -389,7 +389,7 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
389
389
  // Loading State Logic
390
390
  const shouldShowLoading = state.isLoading || state.pluginConfigLoading || (blockUntilSessionReady && !state.isSessionInitialized);
391
391
  const canRenderChildren = !state.pluginConfigLoading && (!blockUntilSessionReady || state.isSessionInitialized);
392
- return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(TagadaContext.Provider, { value: contextValue, children: _jsxs(PixelTrackingProvider, { children: [_jsx(FunnelScriptInjector, { ...funnelState }), shouldShowLoading && _jsx(InitializationLoader, {}), state.debugMode && canRenderChildren && (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => setIsDebugDrawerOpen(true), style: {
392
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(TagadaContext.Provider, { value: contextValue, children: _jsxs(PixelTrackingProvider, { children: [_jsx(Suspense, { fallback: null, children: _jsx(FunnelScriptInjector, { ...funnelState }) }), shouldShowLoading && _jsx(InitializationLoader, {}), state.debugMode && canRenderChildren && (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => setIsDebugDrawerOpen(true), style: {
393
393
  position: 'fixed',
394
394
  bottom: '16px',
395
395
  right: '16px',
@@ -9,6 +9,7 @@
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';
12
13
  /**
13
14
  * Auto-inject all stepConfig scripts
14
15
  * Called automatically when SDK loads
@@ -24,8 +25,13 @@ export { TagadaClient, ApiClient, CheckoutResource };
24
25
  export { ShippingRatesResource } from '../core/resources/shippingRates';
25
26
  export { PaymentsResource } from '../core/resources/payments';
26
27
  export { OrdersResource } from '../core/resources/orders';
28
+ export { ExpressPaymentMethodsResource } from '../core/resources/expressPaymentMethods';
29
+ export type { PaymentMethod as ExpressPaymentMethod } from '../core/resources/expressPaymentMethods';
27
30
  export type { ShippingRate, ShippingRatesResponse, ShippingRatesPreviewParams } from '../core/resources/shippingRates';
28
- export type { Payment, PaymentResponse, CardPaymentMethod, BasisTheoryInstance, GooglePayToken, PaymentInstrumentInput, } from '../core/resources/payments';
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';
29
35
  export { ISODataCore } from '../core/isoData';
30
36
  export type { ISOCountry, ISORegion } from '../core/isoData';
31
37
  export { GoogleAutocompleteCore } from '../core/googleAutocomplete';
@@ -39,7 +45,19 @@ export type { CheckoutData, CheckoutSession, CheckoutSummary, CheckoutSummaryIte
39
45
  export type { Order, OrderItem, OrderAddress, OrderSummary, OrderWithRelations, PaymentSummary, PromotionSummary, Subscription, DeviceInfo, PromotionCode, Customer, Store, PickupPoint, } from '../core/types';
40
46
  export * from '../core/utils';
41
47
  export { matchRoute, getInternalPath, isPathRemapped, getPathInfo, } from '../core/pathRemapping';
42
- export { resolvePixelEvents, mapMetaEvent, mapTikTokEvent, mapSnapchatEvent, mapPinterestEvent, mapGTMEvent, isEventEnabled, getEligiblePixels, applyGoogleAdsConversion, } from '../core/pixelMapping';
43
- export type { StandardPixelEvent, PixelProviderKey, MappedEvent, ProviderEvent, } from '../core/pixelMapping';
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;
44
62
  export { TagadaTracker, TagadaExternalTracker, } from './external-tracker';
45
63
  export type { TagadaTrackerConfig, ExternalTrackerSession, NavigateOptions, } from './external-tracker';
@@ -9,7 +9,8 @@
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 } from '../core/funnelClient';
12
+ import { getAssignedStepConfig, getAssignedPaymentFlowId } from '../core/funnelClient';
13
+ import { getBasisTheoryApiKey as _getBtApiKey, getBasisTheoryTenantId as _getBtTenantId } from '../../react/config/payment';
13
14
  /**
14
15
  * Parse step config from window variable or meta tag
15
16
  */
@@ -133,6 +134,11 @@ export { TagadaClient, ApiClient, CheckoutResource };
133
134
  export { ShippingRatesResource } from '../core/resources/shippingRates';
134
135
  export { PaymentsResource } from '../core/resources/payments';
135
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';
136
142
  // Re-export ISO Data Core (for standalone address form / resolvers)
137
143
  export { ISODataCore } from '../core/isoData';
138
144
  // Re-export Google Autocomplete Core (for standalone address form)
@@ -144,8 +150,24 @@ export { FunnelActionType } from '../core/resources/funnel';
144
150
  export * from '../core/utils';
145
151
  // Re-export path remapping utilities (for SPA routing)
146
152
  export { matchRoute, getInternalPath, isPathRemapped, getPathInfo, } from '../core/pathRemapping';
147
- // Re-export pixel mapping (for standalone pixel tracking)
148
- export { resolvePixelEvents, mapMetaEvent, mapTikTokEvent, mapSnapchatEvent, mapPinterestEvent, mapGTMEvent, isEventEnabled, getEligiblePixels, applyGoogleAdsConversion, } from '../core/pixelMapping';
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
+ }
149
171
  // ============================================================================
150
172
  // EXTERNAL PAGE TRACKER
151
173
  // ============================================================================
@@ -0,0 +1,134 @@
1
+ /**
2
+ * PaymentService (Standalone / Vanilla JS)
3
+ *
4
+ * Complete standalone equivalent of the React SDK's payment system:
5
+ * - usePaymentQuery (orchestration)
6
+ * - usePaymentPolling (status polling)
7
+ * - usePaymentActionHandler (action routing)
8
+ * - usePaymentProcessors (card, APM, Apple Pay, Google Pay, saved instruments)
9
+ * - usePaymentInstruments (instrument creation)
10
+ * - useThreeds (3DS session + challenge)
11
+ * - useGenericPaymentReturn (generic redirect return)
12
+ * - useAirwallex3dsReturn (Airwallex-specific redirect return)
13
+ * - All action handlers: redirect, threeds_auth, processor_auth, error,
14
+ * kesspay_auth, trustflow_auth, finix_radar, stripe_radar, airwallex radar,
15
+ * mastercard_auth
16
+ *
17
+ * No React. No hooks. No DOM framework dependency.
18
+ */
19
+ import { PaymentsResource, type Payment, type CardPaymentMethod, type ApplePayToken, type GooglePayToken, type PaymentInstrumentResponse, type PaymentInstrumentCustomerResponse } from '../core/resources/payments';
20
+ import type { ApiClient } from '../core/resources/apiClient';
21
+ export interface PaymentServiceConfig {
22
+ apiClient: ApiClient;
23
+ storeId?: string;
24
+ }
25
+ export interface CardData {
26
+ cardNumber: string;
27
+ expiryDate: string;
28
+ cvc: string;
29
+ }
30
+ export interface ApmData {
31
+ processorId: string;
32
+ paymentMethod: string;
33
+ initiatedBy?: 'customer' | 'merchant';
34
+ source?: 'upsell' | 'checkout' | 'offer' | 'missing_club' | 'forced';
35
+ }
36
+ export interface PaymentResult {
37
+ success: boolean;
38
+ payment?: Payment;
39
+ order?: {
40
+ id: string;
41
+ checkoutSessionId?: string;
42
+ } | null;
43
+ error?: string;
44
+ /** True if the browser is being redirected (page will unload) */
45
+ redirecting?: boolean;
46
+ }
47
+ export interface PaymentCallbacks {
48
+ onProcessing?: (processing: boolean) => void;
49
+ onError?: (error: string | null) => void;
50
+ onCurrentPaymentId?: (paymentId: string | null) => void;
51
+ onSuccess?: (payment: Payment) => void;
52
+ onFailure?: (error: string) => void;
53
+ onRedirectReturn?: (paymentId: string) => void;
54
+ }
55
+ export interface PollingCallbacks {
56
+ onSuccess: (payment: Payment) => void;
57
+ onFailure: (error: string) => void;
58
+ onRequireAction?: (payment: Payment) => void;
59
+ }
60
+ export declare class PaymentService {
61
+ private paymentsResource;
62
+ private threedsResource;
63
+ private storeConfigResource;
64
+ private storeId?;
65
+ private callbacks;
66
+ private basisTheory;
67
+ private btInitPromise;
68
+ private bt3dsClass;
69
+ private bt3dsInitPromise;
70
+ private storeConfig;
71
+ private storeConfigPromise;
72
+ private pollTimer;
73
+ private pollAttempts;
74
+ private isPollingActive;
75
+ private redirectReturnProcessed;
76
+ constructor(config: PaymentServiceConfig);
77
+ /** Expose paymentsResource for advanced consumers */
78
+ get payments(): PaymentsResource;
79
+ setCallbacks(callbacks: PaymentCallbacks): void;
80
+ /** Pre-warm BasisTheory + store config (non-blocking). */
81
+ warmup(): void;
82
+ destroy(): void;
83
+ private initBasisTheory;
84
+ private getBtApiKey;
85
+ /** Lazy-load @basis-theory/web-threeds (BasisTheory3ds class) */
86
+ private initBt3ds;
87
+ private fetchStoreConfig;
88
+ stopPolling(): void;
89
+ startPolling(paymentId: string, callbacks: PollingCallbacks, maxAttempts?: number, interval?: number): void;
90
+ /**
91
+ * Internal: call processPaymentDirect and handle requireAction / polling.
92
+ * Shared by processCardPayment, processApplePayPayment, etc.
93
+ */
94
+ private processAndHandle;
95
+ /**
96
+ * After radar / completePaymentAfterAction, handle the resumed payment.
97
+ */
98
+ private handleResumedPayment;
99
+ handlePaymentAction(payment: Payment): Promise<void>;
100
+ private handleKessPayAuth;
101
+ private handleTrustFlowAuth;
102
+ private handleFinixRadar;
103
+ private handleStripeRadar;
104
+ private handleAirwallexRadar;
105
+ private handleMasterCardAuth;
106
+ private loadScript;
107
+ private waitFor;
108
+ /**
109
+ * Detect ALL redirect return types and resume.
110
+ * Handles both generic returns and Airwallex-specific 3DS returns.
111
+ * Call once during initialization. Returns true if a return was detected.
112
+ */
113
+ detectRedirectReturn(): boolean;
114
+ private detectGenericRedirectReturn;
115
+ private detectAirwallex3dsReturn;
116
+ private handleAirwallex3dsRedirectReturn;
117
+ cleanPaymentUrlParams(): void;
118
+ createCardPaymentInstrument(cardData: CardPaymentMethod): Promise<PaymentInstrumentResponse>;
119
+ createApplePayPaymentInstrument(token: ApplePayToken): Promise<PaymentInstrumentResponse>;
120
+ createGooglePayPaymentInstrument(token: GooglePayToken): Promise<PaymentInstrumentResponse>;
121
+ getCardPaymentInstruments(): Promise<PaymentInstrumentCustomerResponse>;
122
+ createThreedsSession(paymentInstrument: {
123
+ id: string;
124
+ token: string | null;
125
+ }): Promise<{
126
+ id: string;
127
+ sessionId: string;
128
+ }>;
129
+ processCardPayment(checkoutSessionId: string, cardData: CardData): Promise<PaymentResult>;
130
+ processApplePayPayment(checkoutSessionId: string, applePayToken: ApplePayToken): Promise<PaymentResult>;
131
+ processGooglePayPayment(checkoutSessionId: string, googlePayToken: GooglePayToken): Promise<PaymentResult>;
132
+ processPaymentWithInstrument(checkoutSessionId: string, paymentInstrumentId: string): Promise<PaymentResult>;
133
+ processApmPayment(checkoutSessionId: string, apmData: ApmData): Promise<PaymentResult>;
134
+ }