@tagadapay/plugin-sdk 3.0.3 → 3.0.12

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 (49) hide show
  1. package/build-cdn.js +113 -0
  2. package/dist/config/basisTheory.d.ts +26 -0
  3. package/dist/config/basisTheory.js +29 -0
  4. package/dist/external-tracker.js +5072 -0
  5. package/dist/external-tracker.min.js +11 -0
  6. package/dist/external-tracker.min.js.map +7 -0
  7. package/dist/react/config/payment.d.ts +8 -8
  8. package/dist/react/config/payment.js +17 -21
  9. package/dist/react/hooks/useApplePay.js +1 -1
  10. package/dist/react/hooks/usePayment.js +1 -3
  11. package/dist/react/hooks/useThreeds.js +2 -2
  12. package/dist/v2/core/client.d.ts +30 -3
  13. package/dist/v2/core/client.js +326 -8
  14. package/dist/v2/core/config/environment.d.ts +16 -3
  15. package/dist/v2/core/config/environment.js +72 -3
  16. package/dist/v2/core/funnelClient.d.ts +4 -0
  17. package/dist/v2/core/funnelClient.js +106 -4
  18. package/dist/v2/core/resources/funnel.d.ts +22 -0
  19. package/dist/v2/core/resources/offers.d.ts +64 -3
  20. package/dist/v2/core/resources/offers.js +112 -10
  21. package/dist/v2/core/resources/postPurchases.js +4 -1
  22. package/dist/v2/core/utils/configHotReload.d.ts +39 -0
  23. package/dist/v2/core/utils/configHotReload.js +75 -0
  24. package/dist/v2/core/utils/eventBus.d.ts +11 -0
  25. package/dist/v2/core/utils/eventBus.js +34 -0
  26. package/dist/v2/core/utils/pluginConfig.d.ts +14 -5
  27. package/dist/v2/core/utils/pluginConfig.js +74 -59
  28. package/dist/v2/core/utils/previewMode.d.ts +114 -0
  29. package/dist/v2/core/utils/previewMode.js +379 -0
  30. package/dist/v2/core/utils/sessionStorage.d.ts +5 -0
  31. package/dist/v2/core/utils/sessionStorage.js +22 -0
  32. package/dist/v2/index.d.ts +4 -1
  33. package/dist/v2/index.js +3 -1
  34. package/dist/v2/react/components/DebugDrawer.js +68 -46
  35. package/dist/v2/react/hooks/useOfferQuery.js +50 -17
  36. package/dist/v2/react/hooks/usePaymentQuery.js +1 -3
  37. package/dist/v2/react/hooks/usePreviewOffer.d.ts +84 -0
  38. package/dist/v2/react/hooks/usePreviewOffer.js +290 -0
  39. package/dist/v2/react/hooks/useThreeds.js +2 -2
  40. package/dist/v2/react/index.d.ts +2 -0
  41. package/dist/v2/react/index.js +1 -0
  42. package/dist/v2/react/providers/TagadaProvider.js +49 -32
  43. package/dist/v2/standalone/external-tracker.d.ts +119 -0
  44. package/dist/v2/standalone/external-tracker.js +260 -0
  45. package/dist/v2/standalone/index.d.ts +2 -0
  46. package/dist/v2/standalone/index.js +6 -0
  47. package/package.json +11 -3
  48. package/dist/v2/react/hooks/useOffersQuery.d.ts +0 -12
  49. package/dist/v2/react/hooks/useOffersQuery.js +0 -404
@@ -4,7 +4,7 @@ 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 { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
7
+ import { createContext, 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';
@@ -51,6 +51,9 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
51
51
  (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development');
52
52
  // Initialize client
53
53
  const client = useMemo(() => {
54
+ // Merge features with defaults, ensuring autoRedirect is always false in provider
55
+ const mergedFeatures = features ?? { funnel: true };
56
+ const funnelFeature = mergedFeatures.funnel;
54
57
  const config = {
55
58
  environment,
56
59
  customApiConfig,
@@ -58,9 +61,21 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
58
61
  localConfig,
59
62
  rawPluginConfig,
60
63
  blockUntilSessionReady,
61
- // For now we always enable funnel by default; callers can disable via features if needed
62
- features: features ?? {
63
- funnel: true,
64
+ features: {
65
+ ...mergedFeatures,
66
+ funnel: typeof funnelFeature === 'object'
67
+ ? {
68
+ ...funnelFeature,
69
+ // Always disable auto-redirect in core because we handle it in the provider
70
+ // to set pendingRedirect state and prevent UI flashes
71
+ autoRedirect: false,
72
+ }
73
+ : funnelFeature === false
74
+ ? false
75
+ : {
76
+ // Default: enable funnel with auto-redirect disabled
77
+ autoRedirect: false,
78
+ },
64
79
  },
65
80
  };
66
81
  return new TagadaClient(config);
@@ -70,6 +85,17 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
70
85
  useEffect(() => {
71
86
  return client.subscribe(setState);
72
87
  }, [client]);
88
+ // Listen for config hot-reload updates
89
+ useEffect(() => {
90
+ const cleanup = client.bus.on('CONFIG_UPDATED', () => {
91
+ // Force re-render when config is updated
92
+ setState(client.getState());
93
+ if (state.debugMode) {
94
+ console.log('[TagadaProvider] Config updated, re-rendering...');
95
+ }
96
+ });
97
+ return cleanup;
98
+ }, [client, state.debugMode]);
73
99
  // Cleanup client on unmount
74
100
  useEffect(() => {
75
101
  return () => {
@@ -151,39 +177,29 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
151
177
  lastUpdated: new Date(),
152
178
  });
153
179
  }, []);
154
- // Refresh Coordinator
155
- const checkoutRefreshRefs = useRef(new Set());
156
- const orderBumpRefreshRefs = useRef(new Set());
180
+ // Refresh Coordinator (backed by EventBus in core)
157
181
  const refreshCoordinator = useMemo(() => ({
158
182
  registerCheckoutRefresh: (refreshFn, name) => {
159
- checkoutRefreshRefs.current.add(refreshFn);
183
+ client.bus.on('CHECKOUT_REFRESH', refreshFn);
160
184
  },
161
185
  registerOrderBumpRefresh: (refreshFn) => {
162
- orderBumpRefreshRefs.current.add(refreshFn);
186
+ client.bus.on('ORDER_BUMP_REFRESH', refreshFn);
163
187
  },
164
188
  notifyCheckoutChanged: async () => {
165
- if (orderBumpRefreshRefs.current.size > 0) {
166
- await Promise.all(Array.from(orderBumpRefreshRefs.current).map((fn) => fn().catch(console.warn)));
167
- }
189
+ await client.bus.emit('ORDER_BUMP_REFRESH'); // Notify bumps that checkout changed? Wait logic
168
190
  },
169
191
  notifyOrderBumpChanged: async () => {
170
- if (checkoutRefreshRefs.current.size > 0) {
171
- await Promise.all(Array.from(checkoutRefreshRefs.current).map((fn) => fn().catch(console.warn)));
172
- }
192
+ await client.bus.emit('CHECKOUT_REFRESH'); // Notify checkout that bumps changed
173
193
  },
174
194
  unregisterCheckoutRefresh: (refreshFn) => {
175
195
  if (refreshFn)
176
- checkoutRefreshRefs.current.delete(refreshFn);
177
- else
178
- checkoutRefreshRefs.current.clear();
196
+ client.bus.off('CHECKOUT_REFRESH', refreshFn);
179
197
  },
180
198
  unregisterOrderBumpRefresh: (refreshFn) => {
181
199
  if (refreshFn)
182
- orderBumpRefreshRefs.current.delete(refreshFn);
183
- else
184
- orderBumpRefreshRefs.current.clear();
200
+ client.bus.off('ORDER_BUMP_REFRESH', refreshFn);
185
201
  },
186
- }), []);
202
+ }), [client]);
187
203
  // Money Utils
188
204
  const moneyUtils = useMemo(() => ({
189
205
  formatMoney,
@@ -212,8 +228,8 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
212
228
  refetch: noopAsync,
213
229
  };
214
230
  }
215
- const next = async (event) => {
216
- const result = await client.funnel.navigate(event);
231
+ // Helper to handle navigation result with optional auto-redirect
232
+ const handleNavigationResult = (result) => {
217
233
  // Call custom onNavigate handler if provided
218
234
  let shouldAutoRedirect = true;
219
235
  if (onNavigate) {
@@ -230,22 +246,23 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
230
246
  setPendingRedirect(true);
231
247
  window.location.href = result.url;
232
248
  }
249
+ };
250
+ const next = async (event) => {
251
+ const result = await client.funnel.navigate(event);
252
+ handleNavigationResult(result);
233
253
  return result;
234
254
  };
235
255
  const goToStep = async (stepId) => {
236
- return await next({
237
- type: 'DIRECT_NAVIGATION',
238
- data: { targetStepId: stepId },
239
- });
256
+ const result = await client.funnel.goToStep(stepId);
257
+ handleNavigationResult(result);
258
+ return result;
240
259
  };
241
- // Helper to resolve accountId with fallbacks
242
- const getAccountId = () => state.store?.accountId || state.pluginConfig?.accountId || state.session?.accountId || '';
243
260
  return {
244
261
  next,
245
262
  goToStep,
246
263
  updateContext: (updates) => client.funnel.updateContext(updates),
247
264
  initializeSession: async (entryStepId) => {
248
- const accountId = getAccountId();
265
+ const accountId = client.getAccountId();
249
266
  if (!accountId || !state.auth.session || !state.store) {
250
267
  throw new Error('Cannot initialize funnel: missing required data (accountId, session, or store)');
251
268
  }
@@ -253,7 +270,7 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
253
270
  },
254
271
  endSession: () => client.funnel.endSession(),
255
272
  retryInitialization: () => {
256
- const accountId = getAccountId();
273
+ const accountId = client.getAccountId();
257
274
  if (!accountId || !state.auth.session || !state.store) {
258
275
  return Promise.reject(new Error('Cannot retry initialization: missing required data'));
259
276
  }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * TagadaPay External Page Tracker
3
+ *
4
+ * A lightweight standalone script for tracking users on external pages
5
+ * that are part of a Tagadapay funnel but not hosted on the Tagadapay platform.
6
+ *
7
+ * ARCHITECTURE:
8
+ * - Reuses core SDK infrastructure (TagadaClient) for authentication and API handling
9
+ * - All tracking handled automatically by funnelOrchestrator via autoInitialize() and navigate()
10
+ * - No separate tracking endpoints needed - unified tracking through orchestrator
11
+ *
12
+ * Usage (via CDN):
13
+ * <script src="https://cdn.jsdelivr.net/npm/@tagadapay/plugin-sdk/dist/external-tracker.min.js"></script>
14
+ * <script>
15
+ * TagadaTracker.init({
16
+ * storeId: 'store_xxx',
17
+ * accountId: 'acc_xxx',
18
+ * funnelId: 'funnel_xxx', // Optional: detected from URL
19
+ * stepId: 'step_xxx',
20
+ * stepName: 'External Offer Page',
21
+ * stepType: 'external'
22
+ * });
23
+ *
24
+ * // Navigate to next step (tracking automatic)
25
+ * TagadaTracker.navigate({
26
+ * eventType: 'form.submitted',
27
+ * eventData: { email: 'user@example.com' }
28
+ * });
29
+ * </script>
30
+ */
31
+ import type { TagadaClient } from '../core/client';
32
+ export interface TagadaTrackerConfig {
33
+ /** Store ID (required) */
34
+ storeId: string;
35
+ /** Account ID (required for session init) */
36
+ accountId?: string;
37
+ /** Funnel ID (optional - can be extracted from URL param) */
38
+ funnelId?: string;
39
+ /**
40
+ * Step ID (REQUIRED for external pages)
41
+ *
42
+ * External URLs cannot be mapped to steps via URL matching (only works for Tagadapay-hosted pages).
43
+ * You must explicitly specify which step this external page represents.
44
+ */
45
+ stepId: string;
46
+ /** Step name (optional - for analytics/debugging) */
47
+ stepName?: string;
48
+ /** Step type (optional - e.g., 'landing', 'offer', 'external') */
49
+ stepType?: string;
50
+ /** API base URL (defaults to production) */
51
+ apiBaseUrl?: string;
52
+ /** Enable debug logging */
53
+ debug?: boolean;
54
+ /** Callback when session is ready */
55
+ onReady?: (session: ExternalTrackerSession) => void;
56
+ /** Callback on error */
57
+ onError?: (error: Error) => void;
58
+ }
59
+ export interface ExternalTrackerSession {
60
+ sessionId: string;
61
+ customerId: string;
62
+ storeId: string;
63
+ funnelId?: string;
64
+ currentStepId?: string;
65
+ cmsToken?: string;
66
+ }
67
+ export interface NavigateOptions {
68
+ /** Event type for navigation (e.g., 'offer.accepted', 'form.submitted') */
69
+ eventType: string;
70
+ /** Event data */
71
+ eventData?: Record<string, unknown>;
72
+ /** Override return URL */
73
+ returnUrl?: string;
74
+ }
75
+ declare class TagadaExternalTracker {
76
+ private config;
77
+ private client;
78
+ private initialized;
79
+ private initializing;
80
+ /**
81
+ * Initialize the tracker using SDK infrastructure
82
+ */
83
+ init(config: TagadaTrackerConfig): Promise<ExternalTrackerSession | null>;
84
+ /**
85
+ * Get current session from SDK state
86
+ */
87
+ getSession(): ExternalTrackerSession | null;
88
+ /**
89
+ * Check if tracker is ready
90
+ */
91
+ isReady(): boolean;
92
+ /**
93
+ * Navigate to next step in funnel using SDK's funnel client
94
+ */
95
+ navigate(options: NavigateOptions): Promise<{
96
+ url: string;
97
+ } | null>;
98
+ /**
99
+ * Get customer ID (for identifying the user)
100
+ */
101
+ getCustomerId(): string | null;
102
+ /**
103
+ * Get funnel session ID
104
+ */
105
+ getFunnelSessionId(): string | null;
106
+ /**
107
+ * Build a URL with funnel context parameters
108
+ * Useful for linking to other external pages while preserving session
109
+ */
110
+ buildUrl(baseUrl: string, additionalParams?: Record<string, string>): string;
111
+ /**
112
+ * Get the underlying SDK client (for advanced usage)
113
+ */
114
+ getClient(): TagadaClient | null;
115
+ private waitForClientReady;
116
+ private initializeFunnel;
117
+ }
118
+ declare const TagadaTracker: TagadaExternalTracker;
119
+ export { TagadaTracker, TagadaExternalTracker };
@@ -0,0 +1,260 @@
1
+ /**
2
+ * TagadaPay External Page Tracker
3
+ *
4
+ * A lightweight standalone script for tracking users on external pages
5
+ * that are part of a Tagadapay funnel but not hosted on the Tagadapay platform.
6
+ *
7
+ * ARCHITECTURE:
8
+ * - Reuses core SDK infrastructure (TagadaClient) for authentication and API handling
9
+ * - All tracking handled automatically by funnelOrchestrator via autoInitialize() and navigate()
10
+ * - No separate tracking endpoints needed - unified tracking through orchestrator
11
+ *
12
+ * Usage (via CDN):
13
+ * <script src="https://cdn.jsdelivr.net/npm/@tagadapay/plugin-sdk/dist/external-tracker.min.js"></script>
14
+ * <script>
15
+ * TagadaTracker.init({
16
+ * storeId: 'store_xxx',
17
+ * accountId: 'acc_xxx',
18
+ * funnelId: 'funnel_xxx', // Optional: detected from URL
19
+ * stepId: 'step_xxx',
20
+ * stepName: 'External Offer Page',
21
+ * stepType: 'external'
22
+ * });
23
+ *
24
+ * // Navigate to next step (tracking automatic)
25
+ * TagadaTracker.navigate({
26
+ * eventType: 'form.submitted',
27
+ * eventData: { email: 'user@example.com' }
28
+ * });
29
+ * </script>
30
+ */
31
+ import { createTagadaClient } from './index';
32
+ import { setClientToken } from '../core/utils/tokenStorage';
33
+ // ============================================================================
34
+ // UTILITIES
35
+ // ============================================================================
36
+ function getUrlParam(name) {
37
+ if (typeof window === 'undefined')
38
+ return null;
39
+ const params = new URLSearchParams(window.location.search);
40
+ return params.get(name);
41
+ }
42
+ function log(debug, ...args) {
43
+ if (debug) {
44
+ console.log('[TagadaTracker]', ...args);
45
+ }
46
+ }
47
+ // ============================================================================
48
+ // MAIN CLASS
49
+ // ============================================================================
50
+ class TagadaExternalTracker {
51
+ constructor() {
52
+ this.config = null;
53
+ this.client = null;
54
+ this.initialized = false;
55
+ this.initializing = false;
56
+ }
57
+ /**
58
+ * Initialize the tracker using SDK infrastructure
59
+ */
60
+ async init(config) {
61
+ if (this.initialized || this.initializing) {
62
+ log(config.debug || false, 'Already initialized or initializing');
63
+ return this.getSession();
64
+ }
65
+ this.initializing = true;
66
+ this.config = {
67
+ debug: false,
68
+ ...config,
69
+ };
70
+ log(this.config.debug, '🚀 Initializing external tracker with SDK...', config);
71
+ try {
72
+ // 1. Check for token in URL and save to storage (bootstrap auth)
73
+ // TagadaClient will automatically pick it up from storage
74
+ const urlToken = getUrlParam('token');
75
+ if (urlToken) {
76
+ setClientToken(urlToken);
77
+ log(this.config.debug, '🔑 Bootstrapped token from URL');
78
+ }
79
+ // 2. Create TagadaClient
80
+ this.client = createTagadaClient({
81
+ debugMode: this.config.debug,
82
+ features: { funnel: true },
83
+ });
84
+ // 3. Wait for client to be ready (load token, init auth state)
85
+ await this.waitForClientReady();
86
+ // 4. Auto-initialize funnel session
87
+ // FunnelClient handles cookies, existing session restoration, etc.
88
+ // Orchestrator automatically tracks session start and step view
89
+ const funnelContext = await this.initializeFunnel();
90
+ log(this.config.debug, '✅ Session initialized (tracking handled by orchestrator):', funnelContext);
91
+ this.initialized = true;
92
+ const session = this.getSession();
93
+ if (session) {
94
+ this.config.onReady?.(session);
95
+ }
96
+ return session;
97
+ }
98
+ catch (error) {
99
+ const err = error instanceof Error ? error : new Error(String(error));
100
+ log(this.config.debug, '❌ Initialization failed:', err);
101
+ this.config.onError?.(err);
102
+ throw err;
103
+ }
104
+ finally {
105
+ this.initializing = false;
106
+ }
107
+ }
108
+ /**
109
+ * Get current session from SDK state
110
+ */
111
+ getSession() {
112
+ if (!this.client?.funnel?.state.context)
113
+ return null;
114
+ const ctx = this.client.funnel.state.context;
115
+ return {
116
+ sessionId: ctx.sessionId,
117
+ customerId: ctx.customerId,
118
+ storeId: ctx.storeId,
119
+ funnelId: ctx.funnelId,
120
+ currentStepId: ctx.currentStepId,
121
+ cmsToken: this.client.state.token || undefined,
122
+ };
123
+ }
124
+ /**
125
+ * Check if tracker is ready
126
+ */
127
+ isReady() {
128
+ return this.initialized && !!this.client?.funnel?.state.context;
129
+ }
130
+ /**
131
+ * Navigate to next step in funnel using SDK's funnel client
132
+ */
133
+ async navigate(options) {
134
+ if (!this.isReady()) {
135
+ throw new Error('Tracker not initialized. Call init() first.');
136
+ }
137
+ log(this.config.debug, '🚀 Navigating:', options);
138
+ try {
139
+ const result = await this.client.funnel.navigate({
140
+ type: options.eventType,
141
+ data: options.eventData || {},
142
+ });
143
+ if (result?.url) {
144
+ log(this.config.debug, '✅ Navigation result:', result.url);
145
+ // Redirect to the next step
146
+ if (typeof window !== 'undefined') {
147
+ window.location.href = options.returnUrl || result.url;
148
+ }
149
+ return { url: result.url };
150
+ }
151
+ return null;
152
+ }
153
+ catch (error) {
154
+ log(this.config.debug, '❌ Navigation failed:', error);
155
+ throw error;
156
+ }
157
+ }
158
+ /**
159
+ * Get customer ID (for identifying the user)
160
+ */
161
+ getCustomerId() {
162
+ return this.client?.state.auth.customer?.id || this.client?.funnel?.state.context?.customerId || null;
163
+ }
164
+ /**
165
+ * Get funnel session ID
166
+ */
167
+ getFunnelSessionId() {
168
+ return this.client?.funnel?.state.context?.sessionId || null;
169
+ }
170
+ /**
171
+ * Build a URL with funnel context parameters
172
+ * Useful for linking to other external pages while preserving session
173
+ */
174
+ buildUrl(baseUrl, additionalParams) {
175
+ const session = this.getSession();
176
+ if (!session) {
177
+ return baseUrl;
178
+ }
179
+ const url = new URL(baseUrl, typeof window !== 'undefined' ? window.location.origin : undefined);
180
+ // Add funnel session context
181
+ url.searchParams.set('funnelSessionId', session.sessionId);
182
+ if (session.cmsToken) {
183
+ url.searchParams.set('token', session.cmsToken);
184
+ }
185
+ if (session.funnelId) {
186
+ url.searchParams.set('funnelId', session.funnelId);
187
+ }
188
+ url.searchParams.set('storeId', session.storeId);
189
+ // Add any additional params
190
+ if (additionalParams) {
191
+ Object.entries(additionalParams).forEach(([key, value]) => {
192
+ url.searchParams.set(key, value);
193
+ });
194
+ }
195
+ return url.toString();
196
+ }
197
+ /**
198
+ * Get the underlying SDK client (for advanced usage)
199
+ */
200
+ getClient() {
201
+ return this.client;
202
+ }
203
+ // ========================================================================
204
+ // PRIVATE METHODS
205
+ // ========================================================================
206
+ async waitForClientReady() {
207
+ if (!this.client)
208
+ return;
209
+ // Wait for token/auth to be resolved
210
+ return new Promise((resolve) => {
211
+ let retries = 0;
212
+ const checkReady = () => {
213
+ // Check if initialized OR if we have a token (sometimes isInitialized is lazy)
214
+ if (this.client?.state.isInitialized || this.client?.state.token) {
215
+ resolve();
216
+ }
217
+ else if (retries > 40) { // 2 seconds timeout
218
+ resolve(); // Proceed anyway (might be anonymous)
219
+ }
220
+ else {
221
+ retries++;
222
+ setTimeout(checkReady, 50);
223
+ }
224
+ };
225
+ checkReady();
226
+ });
227
+ }
228
+ async initializeFunnel() {
229
+ if (!this.client?.funnel)
230
+ return null;
231
+ // Prepare auth session object
232
+ const authSession = {
233
+ customerId: this.client.state.auth.customer?.id || 'anon_placeholder',
234
+ sessionId: this.client.state.auth.session?.sessionId || 'sess_placeholder',
235
+ };
236
+ const store = {
237
+ id: this.config.storeId,
238
+ accountId: this.config.accountId || '',
239
+ };
240
+ // IMPORTANT: For external pages, we must explicitly pass stepId as entryStepId
241
+ // because URL-to-step mapping won't work for external URLs not hosted on Tagadapay
242
+ const entryStepId = this.config.stepId;
243
+ if (!entryStepId) {
244
+ throw new Error('stepId is required for external page tracking (URL mapping does not work for external pages)');
245
+ }
246
+ log(this.config.debug, '🔍 Initializing external page at step:', entryStepId);
247
+ // Use initialize() (not autoInitialize()) to explicitly specify the step
248
+ // Orchestrator will automatically track session start and step view at this step
249
+ return this.client.funnel.initialize(authSession, store, this.config.funnelId || getUrlParam('funnelId') || undefined, entryStepId // ✅ Explicitly tell orchestrator which step we're on
250
+ );
251
+ }
252
+ }
253
+ // ============================================================================
254
+ // GLOBAL INSTANCE
255
+ // ============================================================================
256
+ const TagadaTracker = new TagadaExternalTracker();
257
+ export { TagadaTracker, TagadaExternalTracker };
258
+ if (typeof window !== 'undefined') {
259
+ window.TagadaTracker = TagadaTracker;
260
+ }
@@ -18,3 +18,5 @@ export type { TagadaClientConfig, TagadaState };
18
18
  export { FunnelActionType } from '../core/resources/funnel';
19
19
  export type { FunnelAction, FunnelNavigationResult, SimpleFunnelContext } from '../core/resources/funnel';
20
20
  export * from '../core/utils';
21
+ export { TagadaTracker, TagadaExternalTracker, } from './external-tracker';
22
+ export type { TagadaTrackerConfig, ExternalTrackerSession, NavigateOptions, } from './external-tracker';
@@ -20,3 +20,9 @@ export { TagadaClient, ApiClient };
20
20
  export { FunnelActionType } from '../core/resources/funnel';
21
21
  // Re-export Utilities
22
22
  export * from '../core/utils';
23
+ // ============================================================================
24
+ // EXTERNAL PAGE TRACKER
25
+ // ============================================================================
26
+ // Lightweight tracker for external pages not hosted on Tagadapay
27
+ // NOTE: This is also available as a standalone CDN bundle (external-tracker.min.js)
28
+ export { TagadaTracker, TagadaExternalTracker, } from './external-tracker';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tagadapay/plugin-sdk",
3
- "version": "3.0.3",
3
+ "version": "3.0.12",
4
4
  "description": "Modern React SDK for building Tagada Pay plugins",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -24,10 +24,16 @@
24
24
  "types": "./dist/v2/standalone/index.d.ts",
25
25
  "import": "./dist/v2/standalone/index.js",
26
26
  "require": "./dist/v2/standalone/index.js"
27
+ },
28
+ "./external-tracker": {
29
+ "browser": "./dist/external-tracker.min.js",
30
+ "default": "./dist/external-tracker.min.js"
27
31
  }
28
32
  },
29
33
  "scripts": {
30
- "build": "tsc",
34
+ "build": "tsc && npm run build:cdn",
35
+ "build:cdn": "node build-cdn.js",
36
+ "build:ts": "tsc",
31
37
  "clean": "rm -rf dist",
32
38
  "lint": "echo \"No linting configured\"",
33
39
  "test": "jest --no-watchman",
@@ -79,6 +85,7 @@
79
85
  "@types/node": "^18.0.0",
80
86
  "@types/react": "^19",
81
87
  "@types/react-dom": "^19",
88
+ "esbuild": "^0.24.2",
82
89
  "jest": "^29.5.0",
83
90
  "ts-jest": "^29.1.0",
84
91
  "typescript": "^5.0.0"
@@ -89,7 +96,8 @@
89
96
  },
90
97
  "files": [
91
98
  "dist/**/*",
92
- "README.md"
99
+ "README.md",
100
+ "build-cdn.js"
93
101
  ],
94
102
  "repository": {
95
103
  "type": "git",
@@ -1,12 +0,0 @@
1
- export function useOffersQuery(options?: {}): {
2
- offers: import("../../core/resources/offers").Offer[];
3
- isLoading: boolean;
4
- error: Error | null;
5
- activeSummary: any;
6
- isActiveSummaryLoading: boolean;
7
- payOffer: (offerId: any, orderId: any) => Promise<void>;
8
- preview: (offerId: any) => Promise<any>;
9
- getAvailableVariants: (offerId: any, productId: any) => any;
10
- selectVariant: (offerId: any, productId: any, variantId: any) => Promise<any>;
11
- isLoadingVariants: (offerId: any, productId: any) => any;
12
- };