@tagadapay/plugin-sdk 2.7.14 → 2.7.16

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.
@@ -23,12 +23,26 @@ export interface PathInfo {
23
23
  /** URL hash without the # symbol */
24
24
  hash: string;
25
25
  }
26
+ /**
27
+ * Result of route matching with extracted parameters
28
+ */
29
+ export interface RouteMatchResult {
30
+ /** Whether the route matched */
31
+ matched: boolean;
32
+ /** Extracted URL parameters (empty object if no match or no params) */
33
+ params: Record<string, string>;
34
+ }
26
35
  /**
27
36
  * Get the internal path that the plugin expects
28
37
  *
29
38
  * Reads from the meta tag injected by TagadaPay middleware.
30
39
  * Results are cached for performance.
31
40
  *
41
+ * **Development/Testing Mode (localhost only):**
42
+ * You can simulate path remapping in two ways:
43
+ * 1. Query parameter: `?__remap=/internal-path`
44
+ * 2. localStorage with explicit external → internal mapping
45
+ *
32
46
  * @returns The internal path from meta tag, or null if no remapping is active
33
47
  * @throws {Error} If called in a non-browser environment (SSR)
34
48
  *
@@ -39,6 +53,40 @@ export interface PathInfo {
39
53
  * console.log('Remapped from external to:', internalPath);
40
54
  * }
41
55
  * ```
56
+ *
57
+ * @example Simulating remapping in localhost - RECOMMENDED FORMAT
58
+ * ```typescript
59
+ * // NEW: Explicit mapping (clear which path remaps to which)
60
+ * localStorage.setItem('tagadapay-remap', JSON.stringify({
61
+ * externalPath: '/myremap/:param',
62
+ * internalPath: '/hello-with-param/:myparam'
63
+ * }));
64
+ * // Then navigate to: http://localhost:5173/myremap/test123
65
+ * // Result: Matches external pattern, uses internal path /hello-with-param/:myparam
66
+ *
67
+ * // Option 2: Query parameter (for quick tests)
68
+ * // Navigate to: http://localhost:5173/custom-page?__remap=/hello
69
+ *
70
+ * // Clear simulation
71
+ * localStorage.removeItem('tagadapay-remap');
72
+ * ```
73
+ *
74
+ * @example More Examples
75
+ * ```typescript
76
+ * // Remap /products/:id to /hello-with-param/:myparam
77
+ * localStorage.setItem('tagadapay-remap', JSON.stringify({
78
+ * externalPath: '/products/:id',
79
+ * internalPath: '/hello-with-param/:myparam'
80
+ * }));
81
+ * // Visit: http://localhost:5173/products/abc123
82
+ *
83
+ * // Remap /custom-hello to /hello
84
+ * localStorage.setItem('tagadapay-remap', JSON.stringify({
85
+ * externalPath: '/custom-hello',
86
+ * internalPath: '/hello'
87
+ * }));
88
+ * // Visit: http://localhost:5173/custom-hello
89
+ * ```
42
90
  */
43
91
  export declare function getInternalPath(): string | null;
44
92
  /**
@@ -72,6 +120,50 @@ export declare function isPathRemapped(): boolean;
72
120
  * ```
73
121
  */
74
122
  export declare function getPathInfo(): PathInfo;
123
+ /**
124
+ * Match a route and extract URL parameters
125
+ *
126
+ * Handles path remapping automatically and extracts parameters from the URL.
127
+ * This is the preferred method when you need both match status and parameters.
128
+ *
129
+ * @param internalPath - The plugin's defined path (must start with /)
130
+ * @returns Object with `matched` boolean and `params` object
131
+ * @throws {Error} If internalPath is invalid
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * // In a catch-all route handler
136
+ * const result = matchRoute('/hello-with-param/:myparam');
137
+ * if (result.matched) {
138
+ * console.log('Matched! Param:', result.params.myparam);
139
+ * return <HelloPage myparam={result.params.myparam} />;
140
+ * }
141
+ * ```
142
+ */
143
+ export declare function matchRoute(internalPath: string): RouteMatchResult;
144
+ /**
145
+ * Check if the current URL should match a given internal path
146
+ *
147
+ * Handles path remapping automatically. Use this for catch-all routing
148
+ * implementations where you only need to check if a path matches.
149
+ *
150
+ * For extracting parameters, use `matchRoute()` instead.
151
+ *
152
+ * @param internalPath - The plugin's defined path (must start with /)
153
+ * @returns true if current URL should render this path's component
154
+ * @throws {Error} If internalPath is invalid
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * // In a catch-all route handler
159
+ * if (shouldMatchRoute('/hello')) {
160
+ * return <HelloPage />;
161
+ * }
162
+ * if (shouldMatchRoute('/about')) {
163
+ * return <AboutPage />;
164
+ * }
165
+ * ```
166
+ */
75
167
  export declare function shouldMatchRoute(internalPath: string): boolean;
76
168
  /**
77
169
  * Get the current matched path
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
+ import { match } from 'path-to-regexp';
9
10
  // ============================================================================
10
11
  // Private Cache
11
12
  // ============================================================================
@@ -56,6 +57,11 @@ if (isBrowser) {
56
57
  * Reads from the meta tag injected by TagadaPay middleware.
57
58
  * Results are cached for performance.
58
59
  *
60
+ * **Development/Testing Mode (localhost only):**
61
+ * You can simulate path remapping in two ways:
62
+ * 1. Query parameter: `?__remap=/internal-path`
63
+ * 2. localStorage with explicit external → internal mapping
64
+ *
59
65
  * @returns The internal path from meta tag, or null if no remapping is active
60
66
  * @throws {Error} If called in a non-browser environment (SSR)
61
67
  *
@@ -66,6 +72,40 @@ if (isBrowser) {
66
72
  * console.log('Remapped from external to:', internalPath);
67
73
  * }
68
74
  * ```
75
+ *
76
+ * @example Simulating remapping in localhost - RECOMMENDED FORMAT
77
+ * ```typescript
78
+ * // NEW: Explicit mapping (clear which path remaps to which)
79
+ * localStorage.setItem('tagadapay-remap', JSON.stringify({
80
+ * externalPath: '/myremap/:param',
81
+ * internalPath: '/hello-with-param/:myparam'
82
+ * }));
83
+ * // Then navigate to: http://localhost:5173/myremap/test123
84
+ * // Result: Matches external pattern, uses internal path /hello-with-param/:myparam
85
+ *
86
+ * // Option 2: Query parameter (for quick tests)
87
+ * // Navigate to: http://localhost:5173/custom-page?__remap=/hello
88
+ *
89
+ * // Clear simulation
90
+ * localStorage.removeItem('tagadapay-remap');
91
+ * ```
92
+ *
93
+ * @example More Examples
94
+ * ```typescript
95
+ * // Remap /products/:id to /hello-with-param/:myparam
96
+ * localStorage.setItem('tagadapay-remap', JSON.stringify({
97
+ * externalPath: '/products/:id',
98
+ * internalPath: '/hello-with-param/:myparam'
99
+ * }));
100
+ * // Visit: http://localhost:5173/products/abc123
101
+ *
102
+ * // Remap /custom-hello to /hello
103
+ * localStorage.setItem('tagadapay-remap', JSON.stringify({
104
+ * externalPath: '/custom-hello',
105
+ * internalPath: '/hello'
106
+ * }));
107
+ * // Visit: http://localhost:5173/custom-hello
108
+ * ```
69
109
  */
70
110
  export function getInternalPath() {
71
111
  // SSR check
@@ -77,12 +117,111 @@ export function getInternalPath() {
77
117
  }
78
118
  // Return cached value if available
79
119
  if (internalPathCache !== undefined) {
120
+ console.log('[TagadaPay SDK] 📦 Returning cached internal path:', internalPathCache);
80
121
  return internalPathCache;
81
122
  }
123
+ console.log('[TagadaPay SDK] 🔍 getInternalPath() called for:', window.location.pathname);
82
124
  try {
83
- // Query the meta tag
125
+ // Development/Testing: Check for simulation via query parameter or localStorage
126
+ // Only works on localhost for security
127
+ const isLocalhost = window.location.hostname === 'localhost' ||
128
+ window.location.hostname === '127.0.0.1' ||
129
+ window.location.hostname.endsWith('.localhost');
130
+ console.log('[TagadaPay SDK] 🏠 isLocalhost:', isLocalhost);
131
+ if (isLocalhost) {
132
+ // Priority 1: Query parameter ?__remap=/internal-path
133
+ const urlParams = new URLSearchParams(window.location.search);
134
+ const queryRemap = urlParams.get('__remap');
135
+ console.log('[TagadaPay SDK] 🔍 Query parameter __remap:', queryRemap);
136
+ if (queryRemap) {
137
+ internalPathCache = queryRemap;
138
+ if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
139
+ console.log(`[TagadaPay SDK] 🔧 Simulating path remap via query: ${window.location.pathname} → ${queryRemap}`);
140
+ }
141
+ return queryRemap;
142
+ }
143
+ // Priority 2: localStorage tagadapay-remap
144
+ // Format: JSON object with external -> internal mapping
145
+ // Example: {"externalPath": "/myremap/:param", "internalPath": "/hello-with-param/:myparam"}
146
+ try {
147
+ const storageRemap = localStorage.getItem('tagadapay-remap');
148
+ console.log('[TagadaPay SDK] 🔍 localStorage tagadapay-remap:', storageRemap);
149
+ if (storageRemap) {
150
+ try {
151
+ // Try parsing as JSON first (new explicit format)
152
+ const remapConfig = JSON.parse(storageRemap);
153
+ console.log('[TagadaPay SDK] 📝 Parsed remap config:', remapConfig);
154
+ if (remapConfig.externalPath && remapConfig.internalPath) {
155
+ const currentPath = window.location.pathname;
156
+ console.log('[TagadaPay SDK] 🔍 Checking if', currentPath, 'matches pattern', remapConfig.externalPath);
157
+ // Check if current path matches the external path pattern
158
+ const matchFn = match(remapConfig.externalPath, {
159
+ decode: decodeURIComponent,
160
+ end: true
161
+ });
162
+ const result = matchFn(currentPath);
163
+ console.log('[TagadaPay SDK] 🎯 Match result:', result);
164
+ if (result !== false) {
165
+ // Current path matches the external pattern, return internal path
166
+ internalPathCache = remapConfig.internalPath;
167
+ console.log(`[TagadaPay SDK] ✅ Path remap: ${remapConfig.externalPath} → ${remapConfig.internalPath}`);
168
+ console.log(`[TagadaPay SDK] ✅ Current URL ${currentPath} matches external pattern`);
169
+ console.log('[TagadaPay SDK] 📦 Caching and returning:', remapConfig.internalPath);
170
+ return remapConfig.internalPath;
171
+ }
172
+ else {
173
+ // Current path doesn't match the external pattern, no remap
174
+ console.log(`[TagadaPay SDK] ❌ Current URL ${currentPath} does NOT match external pattern ${remapConfig.externalPath}`);
175
+ internalPathCache = null;
176
+ return null;
177
+ }
178
+ }
179
+ else {
180
+ console.log('[TagadaPay SDK] ⚠️ Parsed config missing externalPath or internalPath');
181
+ }
182
+ }
183
+ catch (jsonError) {
184
+ // Not JSON, treat as legacy format (just internal path)
185
+ console.log('[TagadaPay SDK] ⚠️ Failed to parse as JSON, using legacy format:', jsonError);
186
+ internalPathCache = storageRemap;
187
+ if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
188
+ console.log(`[TagadaPay SDK] 🔧 Simulating path remap (legacy): ${window.location.pathname} → ${storageRemap}`);
189
+ }
190
+ return storageRemap;
191
+ }
192
+ }
193
+ else {
194
+ console.log('[TagadaPay SDK] 📭 No localStorage tagadapay-remap found');
195
+ }
196
+ }
197
+ catch (e) {
198
+ console.log('[TagadaPay SDK] ❌ localStorage error:', e);
199
+ }
200
+ }
201
+ // Production: Try to get internal path from full remap config first (new way)
202
+ const fullRemapMetaTag = document.querySelector('meta[name="tagadapay-path-remap"]');
203
+ if (fullRemapMetaTag) {
204
+ try {
205
+ const content = fullRemapMetaTag.getAttribute('content');
206
+ if (content) {
207
+ const decodedContent = decodeURIComponent(content);
208
+ const parsed = JSON.parse(decodedContent);
209
+ if (parsed.internal) {
210
+ console.log('[TagadaPay SDK] ✅ Got internal path from full remap config:', parsed.internal);
211
+ internalPathCache = parsed.internal;
212
+ return parsed.internal;
213
+ }
214
+ }
215
+ }
216
+ catch (e) {
217
+ console.error('[TagadaPay SDK] Error parsing full remap config:', e);
218
+ // Fall through to try legacy meta tag
219
+ }
220
+ }
221
+ // Fallback: Try legacy meta tag (old way, for backward compatibility)
84
222
  const metaTag = document.querySelector('meta[name="x-plugin-internal-path"]');
85
223
  if (!metaTag) {
224
+ console.log('[TagadaPay SDK] ℹ️ No path remap meta tags found');
86
225
  internalPathCache = null;
87
226
  return null;
88
227
  }
@@ -104,6 +243,7 @@ export function getInternalPath() {
104
243
  internalPathCache = null;
105
244
  return null;
106
245
  }
246
+ console.log('[TagadaPay SDK] ✅ Got internal path from legacy meta tag:', trimmedContent);
107
247
  // Cache and return
108
248
  internalPathCache = trimmedContent;
109
249
  return trimmedContent;
@@ -207,36 +347,75 @@ export function getPathInfo() {
207
347
  /**
208
348
  * Helper function to match a path against a pattern using path-to-regexp
209
349
  * @param pathname - The actual path to test
210
- * @param pattern - The pattern to match against (can include :params)
211
- * @returns true if the path matches the pattern
350
+ * @param pattern - The pattern to match against (can include :params, wildcards, etc.)
351
+ * @returns Object with matched status and extracted params
212
352
  */
213
353
  function matchesPathPattern(pathname, pattern) {
214
354
  try {
215
355
  // Exact match (no pattern)
216
356
  if (pathname === pattern) {
217
- return true;
357
+ return { matched: true, params: {} };
218
358
  }
219
- // Check if pattern contains parameters (e.g., :id, :name)
220
- if (!pattern.includes(':')) {
221
- // No parameters - use simple prefix matching
222
- return pathname.startsWith(pattern);
359
+ // Check if pattern contains special characters that require path-to-regexp
360
+ // :param, *wildcard, {optional}, etc.
361
+ const hasPatternSyntax = pattern.includes(':') || pattern.includes('*') || pattern.includes('{');
362
+ if (!hasPatternSyntax) {
363
+ // No pattern syntax - use exact match only
364
+ // For paths without parameters, we should match exactly, not with prefix
365
+ return { matched: pathname === pattern, params: {} };
223
366
  }
224
- // Use path-to-regexp for parameterized patterns
225
- // Import dynamically to avoid bundle size issues
226
- const { match } = require('path-to-regexp');
227
- const matchFn = match(pattern, { decode: decodeURIComponent, end: false });
367
+ // Use path-to-regexp for patterns with parameters, wildcards, or optional segments
368
+ const matchFn = match(pattern, {
369
+ decode: decodeURIComponent,
370
+ end: true
371
+ });
228
372
  const result = matchFn(pathname);
229
- return result !== false;
373
+ if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
374
+ console.log(`[TagadaPay SDK] Pattern match: "${pathname}" against "${pattern}" =`, result !== false);
375
+ }
376
+ if (result === false) {
377
+ return { matched: false, params: {} };
378
+ }
379
+ // Extract params from result
380
+ const params = {};
381
+ if (typeof result === 'object' && result.params) {
382
+ Object.keys(result.params).forEach(key => {
383
+ const value = result.params[key];
384
+ // Convert to string and handle arrays (for splat params)
385
+ params[key] = Array.isArray(value) ? value.join('/') : String(value);
386
+ });
387
+ }
388
+ return { matched: true, params };
230
389
  }
231
390
  catch (error) {
232
391
  // Fallback to exact match if path-to-regexp fails
233
392
  if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
234
393
  console.warn(`[TagadaPay SDK] Pattern matching failed for "${pattern}":`, error);
235
394
  }
236
- return pathname === pattern || pathname.startsWith(pattern);
395
+ return { matched: pathname === pattern, params: {} };
237
396
  }
238
397
  }
239
- export function shouldMatchRoute(internalPath) {
398
+ /**
399
+ * Match a route and extract URL parameters
400
+ *
401
+ * Handles path remapping automatically and extracts parameters from the URL.
402
+ * This is the preferred method when you need both match status and parameters.
403
+ *
404
+ * @param internalPath - The plugin's defined path (must start with /)
405
+ * @returns Object with `matched` boolean and `params` object
406
+ * @throws {Error} If internalPath is invalid
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * // In a catch-all route handler
411
+ * const result = matchRoute('/hello-with-param/:myparam');
412
+ * if (result.matched) {
413
+ * console.log('Matched! Param:', result.params.myparam);
414
+ * return <HelloPage myparam={result.params.myparam} />;
415
+ * }
416
+ * ```
417
+ */
418
+ export function matchRoute(internalPath) {
240
419
  // Validate input
241
420
  if (typeof internalPath !== 'string') {
242
421
  throw new Error(`[TagadaPay SDK] internalPath must be a string, got ${typeof internalPath}`);
@@ -249,25 +428,120 @@ export function shouldMatchRoute(internalPath) {
249
428
  }
250
429
  // SSR check
251
430
  if (!isBrowser) {
252
- return false;
431
+ return { matched: false, params: {} };
253
432
  }
254
433
  try {
255
434
  const currentPath = window.location.pathname;
256
435
  const remappedInternalPath = getInternalPath();
257
- // If remapped, check if the remapped internal path matches the pattern
436
+ // If remapped, need to extract params from external URL using external pattern
258
437
  if (remappedInternalPath) {
259
- return matchesPathPattern(remappedInternalPath, internalPath);
438
+ const internalMatch = matchesPathPattern(remappedInternalPath, internalPath);
439
+ if (!internalMatch.matched) {
440
+ return { matched: false, params: {} };
441
+ }
442
+ // Get the external pattern from remap config
443
+ let externalPattern = null;
444
+ // Check localStorage for remap config (development/testing)
445
+ if (typeof localStorage !== 'undefined') {
446
+ try {
447
+ const remapData = localStorage.getItem('tagadapay-remap');
448
+ if (remapData) {
449
+ const parsed = JSON.parse(remapData);
450
+ if (parsed.externalPath && parsed.internalPath === remappedInternalPath) {
451
+ externalPattern = parsed.externalPath;
452
+ }
453
+ }
454
+ }
455
+ catch (e) {
456
+ // Ignore parsing errors
457
+ }
458
+ }
459
+ // Check meta tag for production remap config
460
+ if (!externalPattern && typeof document !== 'undefined') {
461
+ console.log('[TagadaPay SDK] 🔍 Checking for production path remap meta tag...');
462
+ const metaTag = document.querySelector('meta[name="tagadapay-path-remap"]');
463
+ if (metaTag) {
464
+ try {
465
+ const content = metaTag.getAttribute('content');
466
+ console.log('[TagadaPay SDK] 📄 Found meta tag content (encoded):', content?.substring(0, 100) + '...');
467
+ if (content) {
468
+ // Decode URL-encoded content before parsing
469
+ const decodedContent = decodeURIComponent(content);
470
+ console.log('[TagadaPay SDK] 📄 Decoded content:', decodedContent);
471
+ const parsed = JSON.parse(decodedContent);
472
+ console.log('[TagadaPay SDK] 📦 Parsed remap config:', parsed);
473
+ console.log('[TagadaPay SDK] 🔍 Checking if internal path matches:', {
474
+ parsedInternal: parsed.internal,
475
+ remappedInternalPath
476
+ });
477
+ if (parsed.external && parsed.internal === remappedInternalPath) {
478
+ externalPattern = parsed.external;
479
+ console.log('[TagadaPay SDK] ✅ Using external pattern from meta tag:', externalPattern);
480
+ }
481
+ else {
482
+ console.log('[TagadaPay SDK] ⚠️ Internal path mismatch - not using meta tag config');
483
+ }
484
+ }
485
+ }
486
+ catch (e) {
487
+ // Ignore parsing errors
488
+ console.error('[TagadaPay SDK] ❌ Error parsing path remap meta tag:', e);
489
+ }
490
+ }
491
+ else {
492
+ console.log('[TagadaPay SDK] ❌ No tagadapay-path-remap meta tag found');
493
+ }
494
+ }
495
+ // Extract params from current URL using external pattern
496
+ if (externalPattern) {
497
+ const externalMatch = matchesPathPattern(currentPath, externalPattern);
498
+ if (externalMatch.matched) {
499
+ // Since we enforce matching parameter names in CRM,
500
+ // the params extracted from external pattern will have the correct names
501
+ return { matched: true, params: externalMatch.params };
502
+ }
503
+ }
504
+ // Fallback: try to extract from current URL using internal pattern
505
+ // (in case external pattern not found or doesn't match)
506
+ const currentMatch = matchesPathPattern(currentPath, internalPath);
507
+ return { matched: true, params: currentMatch.params };
260
508
  }
261
- // No remapping - check if current path matches the pattern
509
+ // No remapping - match and extract from current path
262
510
  return matchesPathPattern(currentPath, internalPath);
263
511
  }
264
512
  catch (error) {
265
513
  if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
266
- console.error('[TagadaPay SDK] Error in shouldMatchRoute:', error);
514
+ console.error('[TagadaPay SDK] Error in matchRoute:', error);
267
515
  }
268
- return false;
516
+ return { matched: false, params: {} };
269
517
  }
270
518
  }
519
+ /**
520
+ * Check if the current URL should match a given internal path
521
+ *
522
+ * Handles path remapping automatically. Use this for catch-all routing
523
+ * implementations where you only need to check if a path matches.
524
+ *
525
+ * For extracting parameters, use `matchRoute()` instead.
526
+ *
527
+ * @param internalPath - The plugin's defined path (must start with /)
528
+ * @returns true if current URL should render this path's component
529
+ * @throws {Error} If internalPath is invalid
530
+ *
531
+ * @example
532
+ * ```typescript
533
+ * // In a catch-all route handler
534
+ * if (shouldMatchRoute('/hello')) {
535
+ * return <HelloPage />;
536
+ * }
537
+ * if (shouldMatchRoute('/about')) {
538
+ * return <AboutPage />;
539
+ * }
540
+ * ```
541
+ */
542
+ export function shouldMatchRoute(internalPath) {
543
+ return matchRoute(internalPath).matched;
544
+ }
271
545
  /**
272
546
  * Get the current matched path
273
547
  *
@@ -6,6 +6,12 @@ export interface FunnelEvent {
6
6
  type: string;
7
7
  data?: any;
8
8
  timestamp?: string;
9
+ /**
10
+ * Current URL for session synchronization (browser back/forward handling)
11
+ * If not provided, SDK will automatically use window.location.href
12
+ * @example '/checkout', 'https://store.com/payment'
13
+ */
14
+ currentUrl?: string;
9
15
  }
10
16
  export interface FunnelNavigationAction {
11
17
  type: 'redirect' | 'replace' | 'push' | 'external' | 'none';
@@ -30,6 +36,11 @@ export interface SimpleFunnelContext {
30
36
  funnelId: string;
31
37
  currentStepId: string;
32
38
  previousStepId?: string;
39
+ /**
40
+ * Furthest step reached in the funnel (for progress tracking in cyclic funnels)
41
+ * Only moves forward, never backward - used for analytics
42
+ */
43
+ furthestStepId?: string;
33
44
  startedAt: number;
34
45
  lastActivityAt: number;
35
46
  metadata?: Record<string, any>;
@@ -54,6 +65,11 @@ export interface FunnelNavigateRequest {
54
65
  sessionId: string;
55
66
  event: FunnelEvent;
56
67
  contextUpdates?: Partial<SimpleFunnelContext>;
68
+ /**
69
+ * Current URL for URL-to-Step mapping (browser back/forward sync)
70
+ * Automatically extracted from event.currentUrl or window.location.href
71
+ */
72
+ currentUrl?: string;
57
73
  }
58
74
  export interface FunnelNavigateResponse {
59
75
  success: boolean;
@@ -100,8 +116,10 @@ export declare class FunnelResource {
100
116
  }>;
101
117
  /**
102
118
  * Get funnel session by ID
119
+ * @param sessionId - The session ID to fetch
120
+ * @param currentUrl - Optional current URL for session synchronization on page load
103
121
  */
104
- getSession(sessionId: string): Promise<{
122
+ getSession(sessionId: string, currentUrl?: string): Promise<{
105
123
  success: boolean;
106
124
  context?: SimpleFunnelContext;
107
125
  error?: string;
@@ -31,8 +31,12 @@ export class FunnelResource {
31
31
  }
32
32
  /**
33
33
  * Get funnel session by ID
34
+ * @param sessionId - The session ID to fetch
35
+ * @param currentUrl - Optional current URL for session synchronization on page load
34
36
  */
35
- async getSession(sessionId) {
36
- return this.apiClient.get(`/api/v1/funnel/session/${sessionId}`);
37
+ async getSession(sessionId, currentUrl) {
38
+ const params = currentUrl ? new URLSearchParams({ currentUrl }) : undefined;
39
+ const url = `/api/v1/funnel/session/${sessionId}${params ? `?${params}` : ''}`;
40
+ return this.apiClient.get(url);
37
41
  }
38
42
  }
@@ -65,6 +65,7 @@ export interface Order {
65
65
  firstName: string;
66
66
  lastName: string;
67
67
  address1: string;
68
+ address2?: string;
68
69
  city: string;
69
70
  country: string;
70
71
  state: string;
@@ -41,6 +41,17 @@ export interface CreateRawPluginConfigOptions {
41
41
  * @returns A RawPluginConfig object or undefined if required fields are missing
42
42
  */
43
43
  export declare function createRawPluginConfig(options?: CreateRawPluginConfigOptions): Promise<RawPluginConfig | undefined>;
44
+ /**
45
+ * Simple helper to get local plugin config with minimal boilerplate
46
+ * Returns null if not in development or config not found
47
+ *
48
+ * @example
49
+ * const config = await localConfigIfAny('blue');
50
+ * if (config) {
51
+ * console.log('Config loaded:', config);
52
+ * }
53
+ */
54
+ export declare function localConfigIfAny(configName?: string): Promise<RawPluginConfig | null>;
44
55
  export declare class PluginConfigUtils {
45
56
  /**
46
57
  * Get plugin configuration from various sources
@@ -252,6 +252,34 @@ export async function createRawPluginConfig(options) {
252
252
  return undefined;
253
253
  }
254
254
  }
255
+ /**
256
+ * Simple helper to get local plugin config with minimal boilerplate
257
+ * Returns null if not in development or config not found
258
+ *
259
+ * @example
260
+ * const config = await localConfigIfAny('blue');
261
+ * if (config) {
262
+ * console.log('Config loaded:', config);
263
+ * }
264
+ */
265
+ export async function localConfigIfAny(configName) {
266
+ try {
267
+ // Only work in localhost
268
+ const isLocalhost = typeof window !== 'undefined' &&
269
+ (window.location.hostname === 'localhost' ||
270
+ window.location.hostname.includes('.localhost') ||
271
+ window.location.hostname.includes('127.0.0.1'));
272
+ if (!isLocalhost) {
273
+ return null;
274
+ }
275
+ const rawConfig = await createRawPluginConfig();
276
+ return rawConfig || null;
277
+ }
278
+ catch (error) {
279
+ console.warn('[localConfigIfAny] Failed to load config:', error);
280
+ return null;
281
+ }
282
+ }
255
283
  export class PluginConfigUtils {
256
284
  /**
257
285
  * Get plugin configuration from various sources
@@ -22,7 +22,7 @@ export type { ApplyDiscountResponse, Discount, DiscountCodeValidation, RemoveDis
22
22
  export type { ToggleOrderBumpResponse, VipOffer, VipPreviewResponse } from './core/resources/vipOffers';
23
23
  export type { StoreConfig } from './core/resources/storeConfig';
24
24
  export type { FunnelContextUpdateRequest, FunnelContextUpdateResponse, FunnelEvent, FunnelInitializeRequest, FunnelInitializeResponse, FunnelNavigateRequest, FunnelNavigateResponse, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from './core/resources/funnel';
25
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
25
+ export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useLocalPluginConfig, useLogin, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
26
26
  export type { TranslateFunction, TranslationText, UseTranslationOptions, UseTranslationResult } from './react/hooks/useTranslation';
27
27
  export type { ClubOffer, ClubOfferItem, ClubOfferLineItem, ClubOfferSummary, UseClubOffersOptions, UseClubOffersResult } from './react/hooks/useClubOffers';
28
28
  export type { UseLoginOptions, UseLoginResult } from './react/hooks/useLogin';
package/dist/v2/index.js CHANGED
@@ -14,4 +14,4 @@ export * from './core/utils/products';
14
14
  // Path remapping helpers (framework-agnostic)
15
15
  export * from './core/pathRemapping';
16
16
  // React exports (hooks and components only, types are exported above)
17
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
17
+ export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useLocalPluginConfig, useLogin, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';