@tagadapay/plugin-sdk 3.1.2 → 3.1.8

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 (56) hide show
  1. package/README.md +1129 -1129
  2. package/build-cdn.js +113 -113
  3. package/dist/external-tracker.js +1104 -491
  4. package/dist/external-tracker.min.js +2 -2
  5. package/dist/external-tracker.min.js.map +4 -4
  6. package/dist/react/hooks/useApplePay.js +25 -36
  7. package/dist/react/hooks/usePaymentPolling.d.ts +9 -3
  8. package/dist/react/providers/TagadaProvider.js +5 -5
  9. package/dist/react/utils/money.d.ts +4 -3
  10. package/dist/react/utils/money.js +39 -6
  11. package/dist/react/utils/trackingUtils.js +1 -0
  12. package/dist/v2/core/client.js +34 -2
  13. package/dist/v2/core/config/environment.js +9 -2
  14. package/dist/v2/core/funnelClient.d.ts +92 -1
  15. package/dist/v2/core/funnelClient.js +247 -3
  16. package/dist/v2/core/resources/apiClient.js +1 -1
  17. package/dist/v2/core/resources/checkout.d.ts +68 -0
  18. package/dist/v2/core/resources/funnel.d.ts +15 -0
  19. package/dist/v2/core/resources/payments.d.ts +50 -3
  20. package/dist/v2/core/resources/payments.js +38 -7
  21. package/dist/v2/core/utils/pluginConfig.js +40 -5
  22. package/dist/v2/core/utils/previewMode.d.ts +3 -0
  23. package/dist/v2/core/utils/previewMode.js +44 -14
  24. package/dist/v2/core/utils/previewModeIndicator.d.ts +19 -0
  25. package/dist/v2/core/utils/previewModeIndicator.js +414 -0
  26. package/dist/v2/core/utils/tokenStorage.d.ts +4 -0
  27. package/dist/v2/core/utils/tokenStorage.js +15 -1
  28. package/dist/v2/index.d.ts +6 -1
  29. package/dist/v2/index.js +6 -1
  30. package/dist/v2/react/components/ApplePayButton.d.ts +21 -121
  31. package/dist/v2/react/components/ApplePayButton.js +221 -290
  32. package/dist/v2/react/components/FunnelScriptInjector.d.ts +3 -1
  33. package/dist/v2/react/components/FunnelScriptInjector.js +128 -24
  34. package/dist/v2/react/components/PreviewModeIndicator.d.ts +46 -0
  35. package/dist/v2/react/components/PreviewModeIndicator.js +113 -0
  36. package/dist/v2/react/hooks/useApplePayCheckout.d.ts +16 -0
  37. package/dist/v2/react/hooks/useApplePayCheckout.js +193 -0
  38. package/dist/v2/react/hooks/useFunnel.d.ts +42 -6
  39. package/dist/v2/react/hooks/useFunnel.js +25 -5
  40. package/dist/v2/react/hooks/usePaymentPolling.d.ts +9 -3
  41. package/dist/v2/react/hooks/usePaymentPolling.js +31 -9
  42. package/dist/v2/react/hooks/usePaymentQuery.d.ts +32 -2
  43. package/dist/v2/react/hooks/usePaymentQuery.js +304 -7
  44. package/dist/v2/react/hooks/usePaymentRetrieve.d.ts +26 -0
  45. package/dist/v2/react/hooks/usePaymentRetrieve.js +175 -0
  46. package/dist/v2/react/hooks/useStepConfig.d.ts +62 -0
  47. package/dist/v2/react/hooks/useStepConfig.js +52 -0
  48. package/dist/v2/react/index.d.ts +9 -3
  49. package/dist/v2/react/index.js +5 -1
  50. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +27 -19
  51. package/dist/v2/react/providers/TagadaProvider.js +7 -7
  52. package/dist/v2/standalone/external-tracker.d.ts +2 -0
  53. package/dist/v2/standalone/external-tracker.js +6 -3
  54. package/package.json +112 -112
  55. package/dist/v2/react/hooks/useApplePay.d.ts +0 -16
  56. package/dist/v2/react/hooks/useApplePay.js +0 -247
@@ -282,9 +282,7 @@ export function useApplePay(options = {}) {
282
282
  // Tokenize the Apple Pay payment
283
283
  const applePayToken = await tokenizeApplePay(event);
284
284
  // Complete the Apple Pay session
285
- session.completePayment({
286
- status: window.ApplePaySession.STATUS_SUCCESS,
287
- });
285
+ session.completePayment(window.ApplePaySession.STATUS_SUCCESS);
288
286
  // Process the payment using the SDK's payment methods
289
287
  await processApplePayPayment(checkoutSessionId, applePayToken, {
290
288
  onSuccess: (payment) => {
@@ -300,9 +298,7 @@ export function useApplePay(options = {}) {
300
298
  }
301
299
  catch (error) {
302
300
  console.error('Payment processing failed:', error);
303
- session.completePayment({
304
- status: window.ApplePaySession.STATUS_FAILURE,
305
- });
301
+ session.completePayment(window.ApplePaySession.STATUS_FAILURE);
306
302
  setProcessingPayment(false);
307
303
  const errorMsg = error instanceof Error ? error.message : 'Payment processing failed';
308
304
  setError(errorMsg);
@@ -321,18 +317,15 @@ export function useApplePay(options = {}) {
321
317
  return;
322
318
  }
323
319
  const { lineItems: newLineItems, total: newTotal } = newOrderSummary;
324
- session.completeShippingMethodSelection({
325
- newTotal: {
326
- label: newTotal.label,
327
- amount: newTotal.amount,
328
- type: 'final',
329
- },
330
- newLineItems: newLineItems.map(item => ({
331
- label: item.label,
332
- amount: item.amount,
333
- type: 'final',
334
- })),
335
- });
320
+ session.completeShippingMethodSelection(window.ApplePaySession.STATUS_SUCCESS, {
321
+ label: newTotal.label,
322
+ amount: newTotal.amount,
323
+ type: 'final',
324
+ }, newLineItems.map(item => ({
325
+ label: item.label,
326
+ amount: item.amount,
327
+ type: 'final',
328
+ })));
336
329
  }
337
330
  catch (error) {
338
331
  console.error('Shipping method selection failed:', error);
@@ -358,24 +351,20 @@ export function useApplePay(options = {}) {
358
351
  console.log('======= APPLE PAY ON SHIPPING CONTACT SELECTED ======');
359
352
  console.log('newOrderSummary', newOrderSummary);
360
353
  console.log(newLineItems, newTotal, newShippingMethods);
361
- session.completeShippingContactSelection({
362
- newShippingMethods: newShippingMethods.map(method => ({
363
- label: method.label,
364
- amount: method.amount,
365
- detail: method.detail,
366
- identifier: method.identifier,
367
- })),
368
- newTotal: {
369
- label: newTotal.label,
370
- amount: newTotal.amount,
371
- type: 'final',
372
- },
373
- newLineItems: newLineItems.map(item => ({
374
- label: item.label,
375
- amount: item.amount,
376
- type: 'final',
377
- })),
378
- });
354
+ session.completeShippingContactSelection(window.ApplePaySession.STATUS_SUCCESS, newShippingMethods.map(method => ({
355
+ label: method.label,
356
+ amount: method.amount,
357
+ detail: method.detail,
358
+ identifier: method.identifier,
359
+ })), {
360
+ label: newTotal.label,
361
+ amount: newTotal.amount,
362
+ type: 'final',
363
+ }, newLineItems.map(item => ({
364
+ label: item.label,
365
+ amount: item.amount,
366
+ type: 'final',
367
+ })));
379
368
  }
380
369
  catch (error) {
381
370
  console.error('Shipping contact selection failed:', error);
@@ -2,14 +2,14 @@ export interface Payment {
2
2
  id: string;
3
3
  status: string;
4
4
  subStatus: string;
5
- requireAction: 'none' | 'redirect' | 'error';
5
+ requireAction: 'none' | 'redirect' | 'error' | 'radar';
6
6
  requireActionData?: {
7
- type: 'redirect' | 'threeds_auth' | 'processor_auth' | 'error';
7
+ type: 'redirect' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar';
8
8
  url?: string;
9
9
  processed: boolean;
10
10
  processorId?: string;
11
11
  metadata?: {
12
- type: 'redirect';
12
+ type: 'redirect' | 'stripe_radar' | 'finix_radar';
13
13
  redirect?: {
14
14
  redirectUrl: string;
15
15
  returnUrl: string;
@@ -20,6 +20,12 @@ export interface Payment {
20
20
  acsTransID: string;
21
21
  messageVersion: string;
22
22
  };
23
+ radar?: {
24
+ merchantId: string;
25
+ environment: 'sandbox' | 'live';
26
+ orderId?: string;
27
+ publishableKey?: string;
28
+ };
23
29
  };
24
30
  redirectUrl?: string;
25
31
  resumeToken?: string;
@@ -38,11 +38,11 @@ const InitializationLoader = () => (_jsxs("div", { style: {
38
38
  borderTop: '1.5px solid #9ca3af',
39
39
  borderRadius: '50%',
40
40
  animation: 'tagada-spin 1s linear infinite',
41
- } }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
42
- @keyframes tagada-spin {
43
- 0% { transform: rotate(0deg); }
44
- 100% { transform: rotate(360deg); }
45
- }
41
+ } }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
42
+ @keyframes tagada-spin {
43
+ 0% { transform: rotate(0deg); }
44
+ 100% { transform: rotate(360deg); }
45
+ }
46
46
  ` })] }));
47
47
  const TagadaContext = createContext(null);
48
48
  export function TagadaProvider({ children, environment, customApiConfig, debugMode, // Remove default, will be set based on environment
@@ -2251,12 +2251,11 @@ export declare function getCurrencyInfo(currencyCode: string): {
2251
2251
  * Convert a money string or number to minor units
2252
2252
  */
2253
2253
  export declare function moneyStringOrNumberToMinorUnits(moneyStringOrNumber: string | number, currencyCode: string): number;
2254
- /**
2255
- * Convert minor units to major units (decimal value)
2256
- */
2257
2254
  export declare function minorUnitsToMajorUnits(amountMinorUnits: number, currencyCode: string): number;
2258
2255
  /**
2259
2256
  * Format money without currency symbol, just the numeric value
2257
+ * Note: The backend stores all amounts with 2 decimal places (multiplied by 100),
2258
+ * even for currencies with 0 decimal places like JPY.
2260
2259
  */
2261
2260
  export declare const formatMoneyWithoutSymbol: ({ amount, currencyCode, fromCents, }: {
2262
2261
  amount: number;
@@ -2269,5 +2268,7 @@ export declare const formatMoneyWithoutSymbol: ({ amount, currencyCode, fromCent
2269
2268
  export declare const convertCurrency: (amount: number, fromCurrency: string, toCurrency: string, rate: number) => number;
2270
2269
  /**
2271
2270
  * Simple money formatter for quick use (similar to the existing useCurrency format function)
2271
+ * Note: The backend stores all amounts with 2 decimal places (multiplied by 100),
2272
+ * even for currencies with 0 decimal places like JPY.
2272
2273
  */
2273
2274
  export declare function formatSimpleMoney(amount: number, currencyCode: string): string;
@@ -42,7 +42,22 @@ export function formatMoney(amountMinorUnits, currencyCode = 'USD', locale) {
42
42
  throw new Error(`Currency ${currencyCode} not found in currency data.`);
43
43
  }
44
44
  // Convert minor units to major units
45
- const value = amountMinorUnits / Math.pow(10, currencyInfo.ISOdigits);
45
+ // Note: The backend stores all amounts with 2 decimal places (multiplied by 100),
46
+ // regardless of the currency's ISOdigits. This means:
47
+ // - For ISOdigits: 0 (JPY, KRW, etc.) → divide by 100 (not 10^0 = 1)
48
+ // - For ISOdigits: 2 (USD, EUR, etc.) → divide by 100 (matches 10^2)
49
+ // - For ISOdigits: 3 (KWD, BHD, etc.) → divide by 100 (not 10^3 = 1000)
50
+ // Note: This means currencies with 3 decimal places lose precision (3rd decimal is lost)
51
+ let value;
52
+ if (currencyInfo.ISOdigits === 0 || currencyInfo.ISOdigits === 3) {
53
+ // Backend stores amounts with 2 decimal places for all currencies
54
+ // For currencies with 0 or 3 decimal places, divide by 100 to convert from backend format
55
+ value = amountMinorUnits / 100;
56
+ }
57
+ else {
58
+ // For currencies with 2 decimal places (most common), use the standard conversion
59
+ value = amountMinorUnits / Math.pow(10, currencyInfo.ISOdigits);
60
+ }
46
61
  return formatCurrency(value, safeLocale, currencyCode);
47
62
  }
48
63
  /**
@@ -63,23 +78,36 @@ export function moneyStringOrNumberToMinorUnits(moneyStringOrNumber, currencyCod
63
78
  const value = typeof moneyStringOrNumber === 'string' ? parseFloat(moneyStringOrNumber) : moneyStringOrNumber;
64
79
  return Math.round(value * Math.pow(10, currencyInfo.ISOdigits));
65
80
  }
66
- /**
67
- * Convert minor units to major units (decimal value)
68
- */
69
81
  export function minorUnitsToMajorUnits(amountMinorUnits, currencyCode) {
70
82
  const currencyInfo = currencyData[currencyCode];
71
83
  if (!currencyInfo) {
72
84
  throw new Error(`Currency ${currencyCode} not found in currency data.`);
73
85
  }
86
+ // Backend stores amounts with 2 decimal places for all currencies
87
+ // For currencies with 0 or 3 decimal places, divide by 100 to convert from backend format
88
+ if (currencyInfo.ISOdigits === 0 || currencyInfo.ISOdigits === 3) {
89
+ return amountMinorUnits / 100;
90
+ }
74
91
  return amountMinorUnits / Math.pow(10, currencyInfo.ISOdigits);
75
92
  }
76
93
  /**
77
94
  * Format money without currency symbol, just the numeric value
95
+ * Note: The backend stores all amounts with 2 decimal places (multiplied by 100),
96
+ * even for currencies with 0 decimal places like JPY.
78
97
  */
79
98
  export const formatMoneyWithoutSymbol = ({ amount, currencyCode, fromCents = true, }) => {
80
99
  const currencyInfo = currencyData[currencyCode];
81
100
  const digits = currencyInfo?.ISOdigits || 2;
82
- const value = fromCents ? amount / Math.pow(10, digits) : amount;
101
+ let value;
102
+ if (fromCents) {
103
+ // Backend stores amounts with 2 decimal places for all currencies
104
+ // For currencies with 0 or 3 decimal places, divide by 100 to convert from backend format
105
+ const divisor = digits === 0 || digits === 3 ? 100 : Math.pow(10, digits);
106
+ value = amount / divisor;
107
+ }
108
+ else {
109
+ value = amount;
110
+ }
83
111
  return new Intl.NumberFormat('en-US', {
84
112
  minimumFractionDigits: digits,
85
113
  maximumFractionDigits: digits,
@@ -95,10 +123,15 @@ export const convertCurrency = (amount, fromCurrency, toCurrency, rate) => {
95
123
  };
96
124
  /**
97
125
  * Simple money formatter for quick use (similar to the existing useCurrency format function)
126
+ * Note: The backend stores all amounts with 2 decimal places (multiplied by 100),
127
+ * even for currencies with 0 decimal places like JPY.
98
128
  */
99
129
  export function formatSimpleMoney(amount, currencyCode) {
100
130
  const currencyInfo = currencyData[currencyCode];
101
131
  const symbol = currencyInfo?.symbol || currencyCode;
102
132
  const digits = currencyInfo?.ISOdigits || 2;
103
- return `${symbol}${(amount / Math.pow(10, digits)).toFixed(digits)}`;
133
+ // Backend stores amounts with 2 decimal places for all currencies
134
+ // For currencies with 0 or 3 decimal places, divide by 100 to convert from backend format
135
+ const divisor = digits === 0 || digits === 3 ? 100 : Math.pow(10, digits);
136
+ return `${symbol}${(amount / divisor).toFixed(digits)}`;
104
137
  }
@@ -70,6 +70,7 @@ export const trackingCookiePatterns = [
70
70
  /^utm_/,
71
71
  /^_clck/,
72
72
  /^_clsk/,
73
+ /^_wtp/
73
74
  ];
74
75
  /**
75
76
  * Function to get cookies with retry logic
@@ -334,10 +334,22 @@ export class TagadaClient {
334
334
  * Normal token initialization flow (no cross-domain handoff)
335
335
  */
336
336
  async fallbackToNormalFlow() {
337
- // Check for existing token in URL or storage
338
- const existingToken = getClientToken();
337
+ // 🔒 CRITICAL: Read URL token FIRST before any async operations
338
+ // This prevents race conditions where anonymous token creation overwrites URL token
339
339
  const urlParams = new URLSearchParams(typeof window !== 'undefined' ? window.location.search : '');
340
340
  const queryToken = urlParams.get('token');
341
+ // If URL has token, set it IMMEDIATELY to prevent any race condition
342
+ if (queryToken) {
343
+ if (this.state.debugMode) {
344
+ console.log(`[TagadaClient ${this.instanceId}] 🔒 URL token detected, setting immediately to prevent race condition`);
345
+ }
346
+ // Set token on API client immediately
347
+ this.apiClient.updateToken(queryToken);
348
+ // Also persist to localStorage
349
+ setClientToken(queryToken);
350
+ }
351
+ // Now check storage (which should have the URL token if we just set it)
352
+ const existingToken = getClientToken();
341
353
  console.log(`[TagadaClient ${this.instanceId}] Initializing token (normal flow)...`, {
342
354
  hasExistingToken: !!existingToken,
343
355
  hasQueryToken: !!queryToken,
@@ -425,6 +437,26 @@ export class TagadaClient {
425
437
  * Create anonymous token
426
438
  */
427
439
  async createAnonymousToken(storeId) {
440
+ // 🔒 CRITICAL: Never create anonymous token if URL has a token
441
+ // This prevents race conditions during forceReset
442
+ if (typeof window !== 'undefined') {
443
+ const urlParams = new URLSearchParams(window.location.search);
444
+ const urlToken = urlParams.get('token');
445
+ if (urlToken) {
446
+ if (this.state.debugMode) {
447
+ console.log(`[TagadaClient ${this.instanceId}] 🔒 URL has token, skipping anonymous token creation`);
448
+ }
449
+ // Use the URL token instead
450
+ this.setToken(urlToken);
451
+ setClientToken(urlToken);
452
+ const decodedSession = decodeJWTClient(urlToken);
453
+ if (decodedSession) {
454
+ this.updateState({ session: decodedSession });
455
+ await this.initializeSession(decodedSession);
456
+ }
457
+ return;
458
+ }
459
+ }
428
460
  // Prevent concurrent anonymous token creation
429
461
  if (this.isInitializingSession) {
430
462
  if (this.state.debugMode) {
@@ -160,6 +160,7 @@ export function getEndpointUrl(config, category, endpoint) {
160
160
  * 4. Default fallback - Production (safest)
161
161
  */
162
162
  export function detectEnvironment() {
163
+ console.log('[SDK] detectEnvironment() called');
163
164
  // Check if we're in browser
164
165
  if (typeof window === 'undefined') {
165
166
  return 'local'; // SSR fallback
@@ -185,15 +186,21 @@ export function detectEnvironment() {
185
186
  }
186
187
  const hostname = window.location.hostname;
187
188
  const href = window.location.href;
189
+ console.log(`[SDK] detectEnvironment() - hostname: "${hostname}"`);
188
190
  // 1. Check for LOCAL environment first (highest priority for dev)
189
- // Local: localhost, local IPs, or local domains
191
+ // Local: localhost, local IPs, local domains, or ngrok tunnels (used for local dev)
190
192
  if (hostname === 'localhost' ||
191
193
  hostname.startsWith('127.') ||
192
194
  hostname.startsWith('192.168.') ||
193
195
  hostname.startsWith('10.') ||
194
196
  hostname.includes('.local') ||
195
197
  hostname === '' ||
196
- hostname === '0.0.0.0') {
198
+ hostname === '0.0.0.0' ||
199
+ hostname.includes('ngrok-free.dev') ||
200
+ hostname.includes('ngrok-free.app') ||
201
+ hostname.includes('ngrok.io') ||
202
+ hostname.includes('ngrok.app')) {
203
+ console.log('[SDK] detectEnvironment() - returning LOCAL');
197
204
  // For local development, allow override via window.__TAGADA_ENV__ (injected by dev server)
198
205
  if (typeof window !== 'undefined' && window?.__TAGADA_ENV__?.TAGADA_ENVIRONMENT) {
199
206
  const override = window.__TAGADA_ENV__.TAGADA_ENVIRONMENT.toLowerCase();
@@ -1,6 +1,90 @@
1
1
  import { ApiClient } from './resources/apiClient';
2
2
  import { SimpleFunnelContext, FunnelAction, FunnelNavigationResult } from './resources/funnel';
3
3
  import { PluginConfig } from './utils/pluginConfig';
4
+ /**
5
+ * Runtime step configuration injected from the CRM
6
+ * Contains payment flows, static resources, scripts, and pixel tracking configs
7
+ */
8
+ export interface RuntimeStepConfig {
9
+ payment?: {
10
+ paymentFlowId?: string;
11
+ };
12
+ staticResources?: Record<string, string>;
13
+ scripts?: Array<{
14
+ name: string;
15
+ enabled: boolean;
16
+ content: string;
17
+ position?: 'head-start' | 'head-end' | 'body-start' | 'body-end';
18
+ }>;
19
+ pixels?: Record<string, string>;
20
+ }
21
+ /**
22
+ * Local funnel configuration for development
23
+ * Loaded from /config/funnel.local.json
24
+ */
25
+ export interface LocalFunnelConfig {
26
+ /** Funnel ID to use in local dev */
27
+ funnelId?: string;
28
+ /** Step ID to simulate */
29
+ stepId?: string;
30
+ /** Static resources (offer ID, product ID, etc.) */
31
+ staticResources?: Record<string, string>;
32
+ /** Payment flow ID override */
33
+ paymentFlowId?: string;
34
+ /** Custom scripts for local testing */
35
+ scripts?: RuntimeStepConfig['scripts'];
36
+ /** Pixel tracking config */
37
+ pixels?: Record<string, string>;
38
+ }
39
+ /**
40
+ * Load local funnel config from /config/funnel.local.json (for local dev only)
41
+ * This replaces the old resources.static.json with a more complete structure
42
+ *
43
+ * Example funnel.local.json:
44
+ * {
45
+ * "funnelId": "funnelv2_xxx",
46
+ * "stepId": "step_checkout",
47
+ * "staticResources": {
48
+ * "offer": "offer_xxx",
49
+ * "product": "product_xxx"
50
+ * },
51
+ * "paymentFlowId": "flow_xxx"
52
+ * }
53
+ */
54
+ export declare function loadLocalFunnelConfig(): Promise<LocalFunnelConfig | null>;
55
+ /**
56
+ * Get the cached local funnel config (sync access after loadLocalFunnelConfig)
57
+ */
58
+ export declare function getLocalFunnelConfig(): LocalFunnelConfig | null;
59
+ /**
60
+ * Get the runtime step configuration
61
+ * Contains payment flow, static resources, scripts, and pixel tracking
62
+ *
63
+ * Priority:
64
+ * 1. Local funnel config (local dev only - /config/funnel.local.json) - HIGHEST in local dev
65
+ * 2. Window variable (production - HTML injection)
66
+ * 3. Meta tag (production - HTML injection fallback)
67
+ *
68
+ * This allows local developers to override injected config for testing.
69
+ *
70
+ * Returns undefined if not available
71
+ */
72
+ export declare function getAssignedStepConfig(): RuntimeStepConfig | undefined;
73
+ /**
74
+ * Get the assigned payment flow ID from step config or legacy injection
75
+ * Returns undefined if not available
76
+ */
77
+ export declare function getAssignedPaymentFlowId(): string | undefined;
78
+ /**
79
+ * Get the assigned static resources from step config
80
+ * Returns undefined if not available
81
+ */
82
+ export declare function getAssignedStaticResources(): Record<string, string> | undefined;
83
+ /**
84
+ * Get the assigned scripts from step config
85
+ * Returns only enabled scripts, filtered by position if specified
86
+ */
87
+ export declare function getAssignedScripts(position?: 'head-start' | 'head-end' | 'body-start' | 'body-end'): RuntimeStepConfig['scripts'];
4
88
  export interface FunnelClientConfig {
5
89
  apiClient: ApiClient;
6
90
  debugMode?: boolean;
@@ -86,16 +170,23 @@ export declare class FunnelClient {
86
170
  * @param options.fireAndForget - If true, queues navigation to QStash and returns immediately without waiting for result
87
171
  * @param options.customerTags - Customer tags to set (merged with existing customer tags)
88
172
  * @param options.deviceId - Device ID for geo/device tag enrichment (optional, rarely needed)
173
+ * @param options.autoRedirect - Override global autoRedirect setting for this specific call (default: use config)
89
174
  */
90
175
  navigate(event: FunnelAction, options?: {
91
176
  fireAndForget?: boolean;
92
177
  customerTags?: string[];
93
178
  deviceId?: string;
179
+ autoRedirect?: boolean;
180
+ waitForSession?: boolean;
94
181
  }): Promise<FunnelNavigationResult>;
95
182
  /**
96
183
  * Go to a specific step (direct navigation)
184
+ * @param stepId - Target step ID
185
+ * @param options - Navigation options (autoRedirect, etc.)
97
186
  */
98
- goToStep(stepId: string): Promise<FunnelNavigationResult>;
187
+ goToStep(stepId: string, options?: {
188
+ autoRedirect?: boolean;
189
+ }): Promise<FunnelNavigationResult>;
99
190
  /**
100
191
  * Refresh session data
101
192
  */