@tagadapay/plugin-sdk 3.0.2 → 3.0.9
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.
- package/build-cdn.js +113 -0
- package/dist/config/basisTheory.d.ts +26 -0
- package/dist/config/basisTheory.js +29 -0
- package/dist/external-tracker.js +4947 -0
- package/dist/external-tracker.min.js +11 -0
- package/dist/external-tracker.min.js.map +7 -0
- package/dist/react/config/payment.d.ts +8 -8
- package/dist/react/config/payment.js +17 -21
- package/dist/react/hooks/useApplePay.js +1 -1
- package/dist/react/hooks/usePayment.js +1 -3
- package/dist/react/hooks/useThreeds.js +2 -2
- package/dist/v2/core/client.d.ts +31 -3
- package/dist/v2/core/client.js +234 -9
- package/dist/v2/core/config/environment.d.ts +16 -3
- package/dist/v2/core/config/environment.js +72 -3
- package/dist/v2/core/funnelClient.d.ts +4 -0
- package/dist/v2/core/funnelClient.js +106 -4
- package/dist/v2/core/resources/funnel.d.ts +22 -0
- package/dist/v2/core/resources/offers.d.ts +64 -3
- package/dist/v2/core/resources/offers.js +112 -10
- package/dist/v2/core/resources/postPurchases.js +4 -1
- package/dist/v2/core/utils/configHotReload.d.ts +39 -0
- package/dist/v2/core/utils/configHotReload.js +75 -0
- package/dist/v2/core/utils/eventBus.d.ts +11 -0
- package/dist/v2/core/utils/eventBus.js +34 -0
- package/dist/v2/core/utils/pluginConfig.d.ts +14 -5
- package/dist/v2/core/utils/pluginConfig.js +74 -59
- package/dist/v2/core/utils/previewMode.d.ts +114 -0
- package/dist/v2/core/utils/previewMode.js +379 -0
- package/dist/v2/core/utils/sessionStorage.d.ts +5 -0
- package/dist/v2/core/utils/sessionStorage.js +22 -0
- package/dist/v2/index.d.ts +4 -1
- package/dist/v2/index.js +3 -1
- package/dist/v2/react/hooks/useOfferQuery.js +50 -17
- package/dist/v2/react/hooks/usePaymentQuery.js +1 -3
- package/dist/v2/react/hooks/usePreviewOffer.d.ts +84 -0
- package/dist/v2/react/hooks/usePreviewOffer.js +290 -0
- package/dist/v2/react/hooks/useThreeds.js +2 -2
- package/dist/v2/react/index.d.ts +2 -0
- package/dist/v2/react/index.js +1 -0
- package/dist/v2/react/providers/TagadaProvider.d.ts +1 -2
- package/dist/v2/react/providers/TagadaProvider.js +51 -34
- package/dist/v2/standalone/external-tracker.d.ts +119 -0
- package/dist/v2/standalone/external-tracker.js +260 -0
- package/dist/v2/standalone/index.d.ts +2 -0
- package/dist/v2/standalone/index.js +6 -0
- package/package.json +11 -3
- package/dist/v2/react/hooks/useOffersQuery.d.ts +0 -12
- package/dist/v2/react/hooks/useOffersQuery.js +0 -404
|
@@ -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
|
+
"version": "3.0.9",
|
|
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
|
-
};
|