@tagadapay/plugin-sdk 3.1.5 → 3.1.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.
Files changed (71) hide show
  1. package/README.md +1129 -1129
  2. package/build-cdn.js +220 -113
  3. package/dist/external-tracker.js +1225 -558
  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/tagada-sdk.js +10142 -0
  13. package/dist/tagada-sdk.min.js +43 -0
  14. package/dist/tagada-sdk.min.js.map +7 -0
  15. package/dist/v2/core/client.js +34 -2
  16. package/dist/v2/core/config/environment.js +9 -2
  17. package/dist/v2/core/funnelClient.d.ts +180 -2
  18. package/dist/v2/core/funnelClient.js +289 -6
  19. package/dist/v2/core/resources/apiClient.js +1 -1
  20. package/dist/v2/core/resources/checkout.d.ts +68 -0
  21. package/dist/v2/core/resources/funnel.d.ts +25 -0
  22. package/dist/v2/core/resources/payments.d.ts +70 -3
  23. package/dist/v2/core/resources/payments.js +72 -7
  24. package/dist/v2/core/utils/index.d.ts +1 -0
  25. package/dist/v2/core/utils/index.js +2 -0
  26. package/dist/v2/core/utils/pluginConfig.d.ts +8 -0
  27. package/dist/v2/core/utils/pluginConfig.js +68 -5
  28. package/dist/v2/core/utils/previewMode.d.ts +7 -0
  29. package/dist/v2/core/utils/previewMode.js +72 -14
  30. package/dist/v2/core/utils/previewModeIndicator.d.ts +19 -0
  31. package/dist/v2/core/utils/previewModeIndicator.js +414 -0
  32. package/dist/v2/core/utils/tokenStorage.d.ts +4 -0
  33. package/dist/v2/core/utils/tokenStorage.js +15 -1
  34. package/dist/v2/index.d.ts +9 -3
  35. package/dist/v2/index.js +8 -3
  36. package/dist/v2/react/components/ApplePayButton.d.ts +22 -123
  37. package/dist/v2/react/components/ApplePayButton.js +247 -317
  38. package/dist/v2/react/components/FunnelScriptInjector.d.ts +3 -1
  39. package/dist/v2/react/components/FunnelScriptInjector.js +255 -162
  40. package/dist/v2/react/components/GooglePayButton.d.ts +2 -0
  41. package/dist/v2/react/components/GooglePayButton.js +80 -64
  42. package/dist/v2/react/components/PreviewModeIndicator.d.ts +46 -0
  43. package/dist/v2/react/components/PreviewModeIndicator.js +113 -0
  44. package/dist/v2/react/hooks/useApplePayCheckout.d.ts +16 -0
  45. package/dist/v2/react/hooks/useApplePayCheckout.js +193 -0
  46. package/dist/v2/react/hooks/useFunnel.d.ts +48 -6
  47. package/dist/v2/react/hooks/useFunnel.js +25 -5
  48. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +10 -0
  49. package/dist/v2/react/hooks/useGoogleAutocomplete.js +48 -0
  50. package/dist/v2/react/hooks/useGooglePayCheckout.d.ts +21 -0
  51. package/dist/v2/react/hooks/useGooglePayCheckout.js +198 -0
  52. package/dist/v2/react/hooks/usePaymentPolling.d.ts +15 -3
  53. package/dist/v2/react/hooks/usePaymentPolling.js +31 -9
  54. package/dist/v2/react/hooks/usePaymentQuery.d.ts +34 -2
  55. package/dist/v2/react/hooks/usePaymentQuery.js +731 -7
  56. package/dist/v2/react/hooks/usePaymentRetrieve.d.ts +26 -0
  57. package/dist/v2/react/hooks/usePaymentRetrieve.js +175 -0
  58. package/dist/v2/react/hooks/usePixelTracking.d.ts +56 -0
  59. package/dist/v2/react/hooks/usePixelTracking.js +508 -0
  60. package/dist/v2/react/hooks/useStepConfig.d.ts +64 -0
  61. package/dist/v2/react/hooks/useStepConfig.js +53 -0
  62. package/dist/v2/react/index.d.ts +15 -5
  63. package/dist/v2/react/index.js +8 -2
  64. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +1 -0
  65. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +41 -13
  66. package/dist/v2/react/providers/TagadaProvider.js +24 -23
  67. package/dist/v2/standalone/external-tracker.d.ts +2 -0
  68. package/dist/v2/standalone/external-tracker.js +6 -3
  69. package/package.json +112 -112
  70. package/dist/v2/react/hooks/useApplePay.d.ts +0 -16
  71. package/dist/v2/react/hooks/useApplePay.js +0 -247
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TagadaPay External Tracker v3.1.5
2
+ * TagadaPay External Tracker v3.1.9
3
3
  * CDN Bundle - Standalone tracking for external pages (Debug Build)
4
4
  * @license MIT
5
5
  */
@@ -30,6 +30,9 @@ var TagadaTrackerBundle = (() => {
30
30
  return a;
31
31
  };
32
32
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
33
+ var __esm = (fn, res) => function __init() {
34
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
35
+ };
33
36
  var __export = (target, all3) => {
34
37
  for (var name in all3)
35
38
  __defProp(target, name, { get: all3[name], enumerable: true });
@@ -88,13 +91,6 @@ var TagadaTrackerBundle = (() => {
88
91
  };
89
92
  var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
90
93
 
91
- // src/v2/standalone/external-tracker.ts
92
- var external_tracker_exports = {};
93
- __export(external_tracker_exports, {
94
- TagadaExternalTracker: () => TagadaExternalTracker,
95
- TagadaTracker: () => TagadaTracker
96
- });
97
-
98
94
  // src/v2/core/config/environment.ts
99
95
  function getCookie(name) {
100
96
  var _a;
@@ -104,62 +100,6 @@ var TagadaTrackerBundle = (() => {
104
100
  if (parts.length === 2) return ((_a = parts.pop()) == null ? void 0 : _a.split(";").shift()) || null;
105
101
  return null;
106
102
  }
107
- var ENVIRONMENT_CONFIGS = {
108
- production: {
109
- baseUrl: "https://app.tagadapay.com",
110
- endpoints: {
111
- checkout: {
112
- sessionInit: "/api/v1/checkout/session/init",
113
- sessionInitAsync: "/api/v1/checkout/session/init-async",
114
- sessionStatus: "/api/v1/checkout/session/status",
115
- asyncStatus: "/api/public/v1/checkout/async-status"
116
- },
117
- customer: {
118
- profile: "/api/v1/customer/profile",
119
- session: "/api/v1/customer/session"
120
- },
121
- store: {
122
- config: "/api/v1/store/config"
123
- }
124
- }
125
- },
126
- development: {
127
- baseUrl: "https://app.tagadapay.dev",
128
- endpoints: {
129
- checkout: {
130
- sessionInit: "/api/v1/checkout/session/init",
131
- sessionInitAsync: "/api/v1/checkout/session/init-async",
132
- sessionStatus: "/api/v1/checkout/session/status",
133
- asyncStatus: "/api/public/v1/checkout/async-status"
134
- },
135
- customer: {
136
- profile: "/api/v1/customer/profile",
137
- session: "/api/v1/customer/session"
138
- },
139
- store: {
140
- config: "/api/v1/store/config"
141
- }
142
- }
143
- },
144
- local: {
145
- baseUrl: "http://app.localhost:3000",
146
- endpoints: {
147
- checkout: {
148
- sessionInit: "/api/v1/checkout/session/init",
149
- sessionInitAsync: "/api/v1/checkout/session/init-async",
150
- sessionStatus: "/api/v1/checkout/session/status",
151
- asyncStatus: "/api/public/v1/checkout/async-status"
152
- },
153
- customer: {
154
- profile: "/api/v1/customer/profile",
155
- session: "/api/v1/customer/session"
156
- },
157
- store: {
158
- config: "/api/v1/store/config"
159
- }
160
- }
161
- }
162
- };
163
103
  function getEnvironmentConfig(environment = "local") {
164
104
  const apiConfig = ENVIRONMENT_CONFIGS[environment];
165
105
  if (!apiConfig) {
@@ -196,6 +136,7 @@ var TagadaTrackerBundle = (() => {
196
136
  }
197
137
  function detectEnvironment() {
198
138
  var _a;
139
+ console.log("[SDK] detectEnvironment() called");
199
140
  if (typeof window === "undefined") {
200
141
  return "local";
201
142
  }
@@ -215,7 +156,9 @@ var TagadaTrackerBundle = (() => {
215
156
  }
216
157
  const hostname = window.location.hostname;
217
158
  const href = window.location.href;
218
- if (hostname === "localhost" || hostname.startsWith("127.") || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.includes(".local") || hostname === "" || hostname === "0.0.0.0") {
159
+ console.log('[SDK] detectEnvironment() - hostname: "'.concat(hostname, '"'));
160
+ if (hostname === "localhost" || hostname.startsWith("127.") || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.includes(".local") || hostname === "" || hostname === "0.0.0.0" || hostname.includes("ngrok-free.dev") || hostname.includes("ngrok-free.app") || hostname.includes("ngrok.io") || hostname.includes("ngrok.app")) {
161
+ console.log("[SDK] detectEnvironment() - returning LOCAL");
219
162
  if (typeof window !== "undefined" && ((_a = window == null ? void 0 : window.__TAGADA_ENV__) == null ? void 0 : _a.TAGADA_ENVIRONMENT)) {
220
163
  const override = window.__TAGADA_ENV__.TAGADA_ENVIRONMENT.toLowerCase();
221
164
  if (override === "production" || override === "development" || override === "local") {
@@ -244,103 +187,163 @@ var TagadaTrackerBundle = (() => {
244
187
  }
245
188
  return true;
246
189
  }
190
+ var ENVIRONMENT_CONFIGS;
191
+ var init_environment = __esm({
192
+ "src/v2/core/config/environment.ts"() {
193
+ "use strict";
194
+ ENVIRONMENT_CONFIGS = {
195
+ production: {
196
+ baseUrl: "https://app.tagadapay.com",
197
+ endpoints: {
198
+ checkout: {
199
+ sessionInit: "/api/v1/checkout/session/init",
200
+ sessionInitAsync: "/api/v1/checkout/session/init-async",
201
+ sessionStatus: "/api/v1/checkout/session/status",
202
+ asyncStatus: "/api/public/v1/checkout/async-status"
203
+ },
204
+ customer: {
205
+ profile: "/api/v1/customer/profile",
206
+ session: "/api/v1/customer/session"
207
+ },
208
+ store: {
209
+ config: "/api/v1/store/config"
210
+ }
211
+ }
212
+ },
213
+ development: {
214
+ baseUrl: "https://app.tagadapay.dev",
215
+ endpoints: {
216
+ checkout: {
217
+ sessionInit: "/api/v1/checkout/session/init",
218
+ sessionInitAsync: "/api/v1/checkout/session/init-async",
219
+ sessionStatus: "/api/v1/checkout/session/status",
220
+ asyncStatus: "/api/public/v1/checkout/async-status"
221
+ },
222
+ customer: {
223
+ profile: "/api/v1/customer/profile",
224
+ session: "/api/v1/customer/session"
225
+ },
226
+ store: {
227
+ config: "/api/v1/store/config"
228
+ }
229
+ }
230
+ },
231
+ local: {
232
+ baseUrl: "http://app.localhost:3000",
233
+ endpoints: {
234
+ checkout: {
235
+ sessionInit: "/api/v1/checkout/session/init",
236
+ sessionInitAsync: "/api/v1/checkout/session/init-async",
237
+ sessionStatus: "/api/v1/checkout/session/status",
238
+ asyncStatus: "/api/public/v1/checkout/async-status"
239
+ },
240
+ customer: {
241
+ profile: "/api/v1/customer/profile",
242
+ session: "/api/v1/customer/session"
243
+ },
244
+ store: {
245
+ config: "/api/v1/store/config"
246
+ }
247
+ }
248
+ }
249
+ };
250
+ }
251
+ });
247
252
 
248
253
  // src/v2/core/resources/funnel.ts
249
- var FunnelResource = class {
250
- constructor(apiClient) {
251
- this.apiClient = apiClient;
252
- }
253
- /**
254
- * Initialize a funnel session
255
- */
256
- async initialize(request) {
257
- return this.apiClient.post("/api/v1/funnel/initialize", request);
258
- }
259
- /**
260
- * Navigate to next step in funnel
261
- */
262
- async navigate(request) {
263
- return this.apiClient.post("/api/v1/funnel/navigate", request);
264
- }
265
- /**
266
- * Update funnel context
267
- */
268
- async updateContext(sessionId, request) {
269
- return this.apiClient.patch("/api/v1/funnel/context/".concat(sessionId), request);
270
- }
271
- /**
272
- * End funnel session
273
- */
274
- async endSession(sessionId) {
275
- return this.apiClient.delete("/api/v1/funnel/session/".concat(sessionId));
276
- }
277
- /**
278
- * Get funnel session by ID
279
- * @param sessionId - The session ID to fetch
280
- * @param currentUrl - Optional current URL for session synchronization on page load
281
- */
282
- async getSession(sessionId, currentUrl, includeDebugData) {
283
- const params = new URLSearchParams();
284
- if (currentUrl) {
285
- params.append("currentUrl", currentUrl);
286
- }
287
- if (includeDebugData) {
288
- params.append("includeDebugData", "true");
289
- }
290
- const url = "/api/v1/funnel/session/".concat(sessionId).concat(params.toString() ? "?".concat(params) : "");
291
- return this.apiClient.get(url);
254
+ var FunnelResource;
255
+ var init_funnel = __esm({
256
+ "src/v2/core/resources/funnel.ts"() {
257
+ "use strict";
258
+ FunnelResource = class {
259
+ constructor(apiClient) {
260
+ this.apiClient = apiClient;
261
+ }
262
+ /**
263
+ * Initialize a funnel session
264
+ */
265
+ async initialize(request) {
266
+ return this.apiClient.post("/api/v1/funnel/initialize", request);
267
+ }
268
+ /**
269
+ * Navigate to next step in funnel
270
+ */
271
+ async navigate(request) {
272
+ return this.apiClient.post("/api/v1/funnel/navigate", request);
273
+ }
274
+ /**
275
+ * Update funnel context
276
+ */
277
+ async updateContext(sessionId, request) {
278
+ return this.apiClient.patch("/api/v1/funnel/context/".concat(sessionId), request);
279
+ }
280
+ /**
281
+ * End funnel session
282
+ */
283
+ async endSession(sessionId) {
284
+ return this.apiClient.delete("/api/v1/funnel/session/".concat(sessionId));
285
+ }
286
+ /**
287
+ * Get funnel session by ID
288
+ * @param sessionId - The session ID to fetch
289
+ * @param currentUrl - Optional current URL for session synchronization on page load
290
+ */
291
+ async getSession(sessionId, currentUrl, includeDebugData) {
292
+ const params = new URLSearchParams();
293
+ if (currentUrl) {
294
+ params.append("currentUrl", currentUrl);
295
+ }
296
+ if (includeDebugData) {
297
+ params.append("includeDebugData", "true");
298
+ }
299
+ const url = "/api/v1/funnel/session/".concat(sessionId).concat(params.toString() ? "?".concat(params) : "");
300
+ return this.apiClient.get(url);
301
+ }
302
+ };
292
303
  }
293
- };
304
+ });
294
305
 
295
306
  // src/v2/core/utils/eventDispatcher.ts
296
- var EventDispatcher = class {
297
- constructor() {
298
- this.listeners = /* @__PURE__ */ new Set();
299
- }
300
- subscribe(listener) {
301
- this.listeners.add(listener);
302
- return () => {
303
- this.listeners.delete(listener);
304
- };
305
- }
306
- notify(data) {
307
- this.listeners.forEach((listener) => {
308
- try {
309
- listener(data);
310
- } catch (error) {
311
- console.error("Error in event listener:", error);
307
+ var EventDispatcher;
308
+ var init_eventDispatcher = __esm({
309
+ "src/v2/core/utils/eventDispatcher.ts"() {
310
+ "use strict";
311
+ EventDispatcher = class {
312
+ constructor() {
313
+ this.listeners = /* @__PURE__ */ new Set();
314
+ }
315
+ subscribe(listener) {
316
+ this.listeners.add(listener);
317
+ return () => {
318
+ this.listeners.delete(listener);
319
+ };
312
320
  }
313
- });
314
- }
315
- clear() {
316
- this.listeners.clear();
321
+ notify(data) {
322
+ this.listeners.forEach((listener) => {
323
+ try {
324
+ listener(data);
325
+ } catch (error) {
326
+ console.error("Error in event listener:", error);
327
+ }
328
+ });
329
+ }
330
+ clear() {
331
+ this.listeners.clear();
332
+ }
333
+ };
317
334
  }
318
- };
319
-
320
- // src/v2/core/utils/sessionStorage.ts
321
- var FUNNEL_SESSION_COOKIE_NAME = "tgd-funnel-session-id";
322
- var SESSION_MAX_AGE = 30 * 24 * 60 * 60;
323
- function setFunnelSessionCookie(sessionId) {
324
- if (typeof document === "undefined") return;
325
- document.cookie = "".concat(FUNNEL_SESSION_COOKIE_NAME, "=").concat(sessionId, "; path=/; max-age=").concat(SESSION_MAX_AGE, "; SameSite=Lax");
326
- }
327
- function getFunnelSessionCookie() {
328
- if (typeof document === "undefined") return void 0;
329
- const cookie = document.cookie.split("; ").find((row) => row.startsWith("".concat(FUNNEL_SESSION_COOKIE_NAME, "=")));
330
- return cookie ? cookie.split("=")[1] : void 0;
331
- }
332
- function clearFunnelSessionCookie() {
333
- if (typeof document === "undefined") return;
334
- document.cookie = "".concat(FUNNEL_SESSION_COOKIE_NAME, "=; path=/; max-age=0");
335
- }
335
+ });
336
336
 
337
337
  // src/v2/core/utils/tokenStorage.ts
338
- var TOKEN_KEY = "cms_token";
339
338
  function setClientToken(token) {
340
339
  if (typeof window !== "undefined") {
341
340
  try {
341
+ const currentToken = localStorage.getItem(TOKEN_KEY);
342
+ const tokenChanged = currentToken !== token;
342
343
  localStorage.setItem(TOKEN_KEY, token);
343
- window.dispatchEvent(new Event("storage"));
344
+ if (tokenChanged) {
345
+ window.dispatchEvent(new Event("storage"));
346
+ }
344
347
  } catch (error) {
345
348
  console.error("Failed to save token to localStorage:", error);
346
349
  }
@@ -366,15 +369,38 @@ var TagadaTrackerBundle = (() => {
366
369
  }
367
370
  }
368
371
  }
372
+ var TOKEN_KEY;
373
+ var init_tokenStorage = __esm({
374
+ "src/v2/core/utils/tokenStorage.ts"() {
375
+ "use strict";
376
+ TOKEN_KEY = "cms_token";
377
+ }
378
+ });
379
+
380
+ // src/v2/core/utils/sessionStorage.ts
381
+ function setFunnelSessionCookie(sessionId) {
382
+ if (typeof document === "undefined") return;
383
+ document.cookie = "".concat(FUNNEL_SESSION_COOKIE_NAME, "=").concat(sessionId, "; path=/; max-age=").concat(SESSION_MAX_AGE, "; SameSite=Lax");
384
+ }
385
+ function getFunnelSessionCookie() {
386
+ if (typeof document === "undefined") return void 0;
387
+ const cookie = document.cookie.split("; ").find((row) => row.startsWith("".concat(FUNNEL_SESSION_COOKIE_NAME, "=")));
388
+ return cookie ? cookie.split("=")[1] : void 0;
389
+ }
390
+ function clearFunnelSessionCookie() {
391
+ if (typeof document === "undefined") return;
392
+ document.cookie = "".concat(FUNNEL_SESSION_COOKIE_NAME, "=; path=/; max-age=0");
393
+ }
394
+ var FUNNEL_SESSION_COOKIE_NAME, SESSION_MAX_AGE;
395
+ var init_sessionStorage = __esm({
396
+ "src/v2/core/utils/sessionStorage.ts"() {
397
+ "use strict";
398
+ FUNNEL_SESSION_COOKIE_NAME = "tgd-funnel-session-id";
399
+ SESSION_MAX_AGE = 30 * 24 * 60 * 60;
400
+ }
401
+ });
369
402
 
370
403
  // src/v2/core/utils/previewMode.ts
371
- var STORAGE_KEYS = {
372
- DRAFT: "tgd_draft",
373
- FUNNEL_TRACKING: "tgd_funnel_tracking",
374
- FORCE_RESET: "tgd_force_reset",
375
- CLIENT_ENV: "tgd_client_env",
376
- CLIENT_BASE_URL: "tgd_client_base_url"
377
- };
378
404
  function getFromStorage(key) {
379
405
  if (typeof window === "undefined") return null;
380
406
  try {
@@ -399,6 +425,10 @@ var TagadaTrackerBundle = (() => {
399
425
  }
400
426
  function setInCookie(key, value, maxAge = 86400) {
401
427
  if (typeof document === "undefined") return;
428
+ if (key === "tgd_draft" || key === "tgd-draft") {
429
+ console.warn("\u{1F6E1}\uFE0F [SDK] Blocked attempt to set ".concat(key, " as cookie - this should only be in localStorage"));
430
+ return;
431
+ }
402
432
  document.cookie = "".concat(key, "=").concat(value, "; path=/; max-age=").concat(maxAge);
403
433
  }
404
434
  function clearFromCookie(key) {
@@ -415,7 +445,7 @@ var TagadaTrackerBundle = (() => {
415
445
  if (urlDraft !== null) {
416
446
  draft = urlDraft === "true";
417
447
  } else {
418
- const storageDraft = getFromStorage(STORAGE_KEYS.DRAFT) || getFromCookie(STORAGE_KEYS.DRAFT);
448
+ const storageDraft = getFromStorage(STORAGE_KEYS.DRAFT);
419
449
  if (storageDraft !== null) {
420
450
  draft = storageDraft === "true";
421
451
  }
@@ -433,6 +463,11 @@ var TagadaTrackerBundle = (() => {
433
463
  const token = urlParams.get("token") || getClientToken() || null;
434
464
  const funnelSessionId = urlParams.get("funnelSessionId") || null;
435
465
  const funnelId = urlParams.get("funnelId") || null;
466
+ let funnelEnv;
467
+ const urlFunnelEnv = urlParams.get("funnelEnv");
468
+ if (urlFunnelEnv && (urlFunnelEnv === "staging" || urlFunnelEnv === "production")) {
469
+ funnelEnv = urlFunnelEnv;
470
+ }
436
471
  const forceReset = urlParams.get("forceReset") === "true";
437
472
  let tagadaClientEnv;
438
473
  const urlEnv = urlParams.get("tagadaClientEnv");
@@ -454,6 +489,26 @@ var TagadaTrackerBundle = (() => {
454
489
  tagadaClientBaseUrl = storageBaseUrl;
455
490
  }
456
491
  }
492
+ let currency;
493
+ const urlCurrency = urlParams.get("currency");
494
+ if (urlCurrency) {
495
+ currency = urlCurrency;
496
+ } else {
497
+ const storageCurrency = getFromStorage(STORAGE_KEYS.CURRENCY) || getFromCookie(STORAGE_KEYS.CURRENCY);
498
+ if (storageCurrency) {
499
+ currency = storageCurrency;
500
+ }
501
+ }
502
+ let locale;
503
+ const urlLocale = urlParams.get("locale");
504
+ if (urlLocale) {
505
+ locale = urlLocale;
506
+ } else {
507
+ const storageLocale = getFromStorage(STORAGE_KEYS.LOCALE) || getFromCookie(STORAGE_KEYS.LOCALE);
508
+ if (storageLocale) {
509
+ locale = storageLocale;
510
+ }
511
+ }
457
512
  return {
458
513
  forceReset,
459
514
  token,
@@ -461,8 +516,11 @@ var TagadaTrackerBundle = (() => {
461
516
  funnelId,
462
517
  draft,
463
518
  funnelTracking,
519
+ funnelEnv,
464
520
  tagadaClientEnv,
465
- tagadaClientBaseUrl
521
+ tagadaClientBaseUrl,
522
+ currency,
523
+ locale
466
524
  };
467
525
  }
468
526
  function isDraftMode() {
@@ -474,13 +532,19 @@ var TagadaTrackerBundle = (() => {
474
532
  if (typeof window === "undefined") return;
475
533
  if (draft) {
476
534
  setInStorage(STORAGE_KEYS.DRAFT, "true");
477
- setInCookie(STORAGE_KEYS.DRAFT, "true", 86400);
478
535
  } else {
479
- setInStorage(STORAGE_KEYS.DRAFT, "false");
480
- clearFromCookie(STORAGE_KEYS.DRAFT);
536
+ try {
537
+ localStorage.removeItem(STORAGE_KEYS.DRAFT);
538
+ } catch (e) {
539
+ }
481
540
  }
482
541
  }
483
542
  function handlePreviewMode(debugMode = false) {
543
+ let urlToken = null;
544
+ if (typeof window !== "undefined") {
545
+ const urlParams = new URLSearchParams(window.location.search);
546
+ urlToken = urlParams.get("token");
547
+ }
484
548
  const params = getSDKParams();
485
549
  const shouldReset = params.forceReset || false;
486
550
  if (!shouldReset && !params.token) {
@@ -489,6 +553,7 @@ var TagadaTrackerBundle = (() => {
489
553
  }
490
554
  if (debugMode) {
491
555
  console.log("[SDK] Detected params:", params);
556
+ console.log("[SDK] URL token (direct read):", urlToken ? urlToken.substring(0, 20) + "..." : "none");
492
557
  }
493
558
  if (shouldReset) {
494
559
  if (debugMode) {
@@ -508,18 +573,22 @@ var TagadaTrackerBundle = (() => {
508
573
  });
509
574
  }
510
575
  }
511
- if (params.token !== null && params.token !== void 0) {
576
+ const tokenToSet = urlToken || params.token;
577
+ if (tokenToSet !== null && tokenToSet !== void 0) {
512
578
  if (debugMode) {
513
- console.log("[SDK] Using token from URL:", params.token.substring(0, 20) + "...");
579
+ console.log("[SDK] Setting token from URL:", tokenToSet.substring(0, 20) + "...");
514
580
  }
515
- if (params.token === "" || params.token === "null") {
581
+ if (tokenToSet === "" || tokenToSet === "null") {
516
582
  clearClientToken();
517
583
  } else {
518
- setClientToken(params.token);
584
+ setClientToken(tokenToSet);
585
+ if (debugMode) {
586
+ console.log("[SDK] \u2705 Token set in localStorage immediately after clear");
587
+ }
519
588
  }
520
589
  } else if (shouldReset) {
521
590
  if (debugMode) {
522
- console.log("[SDK] Force reset mode (no token)");
591
+ console.log("[SDK] Force reset mode (no token in URL)");
523
592
  }
524
593
  clearClientToken();
525
594
  }
@@ -560,13 +629,331 @@ var TagadaTrackerBundle = (() => {
560
629
  setInStorage(STORAGE_KEYS.CLIENT_ENV, env);
561
630
  setInCookie(STORAGE_KEYS.CLIENT_ENV, env, 86400);
562
631
  }
632
+ function clearClientEnvironment() {
633
+ if (typeof window === "undefined") return;
634
+ try {
635
+ localStorage.removeItem(STORAGE_KEYS.CLIENT_ENV);
636
+ clearFromCookie(STORAGE_KEYS.CLIENT_ENV);
637
+ } catch (e) {
638
+ }
639
+ }
563
640
  function setClientBaseUrl(baseUrl) {
564
641
  if (typeof window === "undefined") return;
565
642
  setInStorage(STORAGE_KEYS.CLIENT_BASE_URL, baseUrl);
566
643
  setInCookie(STORAGE_KEYS.CLIENT_BASE_URL, baseUrl, 86400);
567
644
  }
645
+ function clearClientBaseUrl() {
646
+ if (typeof window === "undefined") return;
647
+ try {
648
+ localStorage.removeItem(STORAGE_KEYS.CLIENT_BASE_URL);
649
+ clearFromCookie(STORAGE_KEYS.CLIENT_BASE_URL);
650
+ } catch (e) {
651
+ }
652
+ }
653
+ function isFunnelTrackingEnabled() {
654
+ var _a;
655
+ const params = getSDKParams();
656
+ return (_a = params.funnelTracking) != null ? _a : true;
657
+ }
658
+ var STORAGE_KEYS;
659
+ var init_previewMode = __esm({
660
+ "src/v2/core/utils/previewMode.ts"() {
661
+ "use strict";
662
+ init_tokenStorage();
663
+ init_sessionStorage();
664
+ STORAGE_KEYS = {
665
+ DRAFT: "tgd_draft",
666
+ FUNNEL_TRACKING: "tgd_funnel_tracking",
667
+ FORCE_RESET: "tgd_force_reset",
668
+ CLIENT_ENV: "tgd_client_env",
669
+ CLIENT_BASE_URL: "tgd_client_base_url",
670
+ CURRENCY: "tgd_currency",
671
+ LOCALE: "tgd_locale"
672
+ };
673
+ }
674
+ });
675
+
676
+ // src/v2/core/utils/previewModeIndicator.ts
677
+ function clearSpecificCookie(cookieName) {
678
+ if (typeof window === "undefined" || typeof document === "undefined") return;
679
+ const hostname = window.location.hostname;
680
+ const parts = hostname.split(".");
681
+ const domains = [
682
+ "",
683
+ // No domain (current)
684
+ hostname,
685
+ // Full hostname
686
+ "." + hostname
687
+ // Wildcard current
688
+ ];
689
+ for (let i = 1; i < parts.length; i++) {
690
+ const domain = parts.slice(i).join(".");
691
+ domains.push(domain);
692
+ domains.push("." + domain);
693
+ }
694
+ const pathParts = window.location.pathname.split("/").filter((p) => p);
695
+ const paths = ["/"];
696
+ let currentPath = "";
697
+ pathParts.forEach((part) => {
698
+ currentPath += "/" + part;
699
+ paths.push(currentPath);
700
+ });
701
+ domains.forEach((domain) => {
702
+ paths.forEach((path) => {
703
+ const baseDelete = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=").concat(path);
704
+ const domainPart = domain ? "; domain=".concat(domain) : "";
705
+ document.cookie = baseDelete + domainPart;
706
+ document.cookie = baseDelete + domainPart + "; secure";
707
+ document.cookie = baseDelete + domainPart + "; SameSite=None; secure";
708
+ document.cookie = baseDelete + domainPart + "; SameSite=Lax";
709
+ document.cookie = baseDelete + domainPart + "; SameSite=Strict";
710
+ });
711
+ });
712
+ }
713
+ function leavePreviewMode() {
714
+ if (typeof window === "undefined") return;
715
+ const confirmed = confirm(
716
+ "\u{1F6AA} Leave Preview Mode?\n\nThis will clear ALL cookies and localStorage (including Shopify session, cart, and preview settings) and reload the page.\n\nAre you sure?"
717
+ );
718
+ if (!confirmed) return;
719
+ const url = new URL(window.location.href);
720
+ const previewParams = [
721
+ "draft",
722
+ "funnelEnv",
723
+ "funnelTracking",
724
+ "tagadaClientEnv",
725
+ "tagadaClientBaseUrl",
726
+ "forceReset",
727
+ "funnelId",
728
+ "funnelSessionId",
729
+ "token"
730
+ ];
731
+ previewParams.forEach((param) => url.searchParams.delete(param));
732
+ window.history.replaceState({}, "", url.href);
733
+ try {
734
+ const cookieDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, "cookie") || Object.getOwnPropertyDescriptor(HTMLDocument.prototype, "cookie");
735
+ if (cookieDescriptor && cookieDescriptor.set) {
736
+ Object.defineProperty(document, "cookie", {
737
+ configurable: true,
738
+ enumerable: true,
739
+ get: function() {
740
+ return cookieDescriptor.get ? cookieDescriptor.get.call(this) : "";
741
+ },
742
+ set: function(val) {
743
+ if (typeof val === "string") {
744
+ const normalizedVal = val.toLowerCase();
745
+ if (normalizedVal.includes("tgd_draft") || normalizedVal.includes("tgd-draft") || normalizedVal.includes("tgd.draft") || normalizedVal.includes("tgddraft")) {
746
+ if (normalizedVal.includes("max-age=0") || normalizedVal.includes("expires=thu, 01 jan 1970")) {
747
+ if (cookieDescriptor.set) {
748
+ cookieDescriptor.set.call(this, val);
749
+ }
750
+ return;
751
+ }
752
+ console.warn("\u{1F6E1}\uFE0F [TagadaPay] BLOCKED: tgd_draft should never be a cookie");
753
+ return;
754
+ }
755
+ }
756
+ if (cookieDescriptor.set) {
757
+ cookieDescriptor.set.call(this, val);
758
+ }
759
+ }
760
+ });
761
+ }
762
+ } catch (e) {
763
+ console.warn("[TagadaPay] Could not install cookie blocker:", e);
764
+ }
765
+ if (window.localStorage) {
766
+ try {
767
+ localStorage.removeItem("tgd_draft");
768
+ localStorage.removeItem("tgd_funnel_tracking");
769
+ localStorage.removeItem("tgd_client_env");
770
+ localStorage.removeItem("tgd_client_base_url");
771
+ localStorage.removeItem("cms_token");
772
+ } catch (e) {
773
+ console.warn("[TagadaPay] Failed to clear some localStorage keys:", e);
774
+ }
775
+ }
776
+ clearClientToken();
777
+ clearFunnelSessionCookie();
778
+ clearClientEnvironment();
779
+ clearClientBaseUrl();
780
+ if (window.localStorage) {
781
+ localStorage.clear();
782
+ }
783
+ if (window.sessionStorage) {
784
+ sessionStorage.clear();
785
+ }
786
+ const tagadaCookies = [
787
+ "tgd-funnel-session-id",
788
+ "tgd_draft",
789
+ "tgd_funnel_tracking",
790
+ "tgd_client_env",
791
+ "tgd_client_base_url",
792
+ "cms_token",
793
+ "tagadapay_session"
794
+ ];
795
+ tagadaCookies.forEach((cookieName) => clearSpecificCookie(cookieName));
796
+ const alternativeNames = ["tgd-draft", "tgd_draft", "tgd.draft", "tgddraft"];
797
+ alternativeNames.forEach((cookieName) => clearSpecificCookie(cookieName));
798
+ if (document.cookie) {
799
+ const cookies = document.cookie.split(";");
800
+ cookies.forEach((cookie) => {
801
+ const cookieName = cookie.split("=")[0].trim();
802
+ if (!cookieName) return;
803
+ const hostname = window.location.hostname;
804
+ const parts = hostname.split(".");
805
+ const domains = ["", hostname, "." + hostname];
806
+ for (let i = 1; i < parts.length; i++) {
807
+ const domain = parts.slice(i).join(".");
808
+ domains.push(domain);
809
+ domains.push("." + domain);
810
+ }
811
+ const pathParts = window.location.pathname.split("/").filter((p) => p);
812
+ const paths = ["/"];
813
+ let currentPath = "";
814
+ pathParts.forEach((part) => {
815
+ currentPath += "/" + part;
816
+ paths.push(currentPath);
817
+ });
818
+ domains.forEach((domain) => {
819
+ paths.forEach((path) => {
820
+ const baseDelete = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=").concat(path);
821
+ const domainPart = domain ? "; domain=".concat(domain) : "";
822
+ document.cookie = baseDelete + domainPart;
823
+ document.cookie = baseDelete + domainPart + "; secure";
824
+ document.cookie = baseDelete + domainPart + "; SameSite=None; secure";
825
+ document.cookie = baseDelete + domainPart + "; SameSite=Lax";
826
+ document.cookie = baseDelete + domainPart + "; SameSite=Strict";
827
+ document.cookie = baseDelete + domainPart + "; secure; SameSite=None";
828
+ document.cookie = baseDelete + domainPart + "; secure; SameSite=Lax";
829
+ document.cookie = baseDelete + domainPart + "; secure; SameSite=Strict";
830
+ });
831
+ });
832
+ });
833
+ }
834
+ setTimeout(() => {
835
+ if (window.localStorage && localStorage.length > 0) {
836
+ localStorage.clear();
837
+ }
838
+ clearSpecificCookie("tgd_draft");
839
+ if (typeof window.stop === "function") {
840
+ window.stop();
841
+ }
842
+ window.location.replace(url.href);
843
+ }, 10);
844
+ }
845
+ function injectPreviewModeIndicator() {
846
+ if (isInjected || typeof window === "undefined" || typeof document === "undefined") {
847
+ return;
848
+ }
849
+ const params = getSDKParams();
850
+ const draftMode = isDraftMode();
851
+ const trackingDisabled = !isFunnelTrackingEnabled();
852
+ const hasCustomEnv = !!(params.tagadaClientEnv || params.tagadaClientBaseUrl);
853
+ if (!draftMode && !trackingDisabled && !hasCustomEnv) {
854
+ return;
855
+ }
856
+ const container = document.createElement("div");
857
+ container.id = "tgd-preview-indicator";
858
+ container.style.cssText = '\n position: fixed;\n bottom: 16px;\n right: 16px;\n z-index: 999999;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\n ';
859
+ const badge = document.createElement("div");
860
+ badge.style.cssText = "\n background: ".concat(draftMode ? "#ff9500" : "#007aff", ";\n color: white;\n padding: 8px 12px;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 600;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n ");
861
+ badge.innerHTML = '\n <span style="font-size: 16px;">\u{1F50D}</span>\n <span>'.concat(draftMode ? "Preview Mode" : "Dev Mode", "</span>\n ");
862
+ const details = document.createElement("div");
863
+ details.style.cssText = "\n position: absolute;\n bottom: calc(100% + 8px);\n right: 0;\n background: white;\n border: 1px solid #e5e5e5;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n padding: 12px;\n min-width: 250px;\n font-size: 12px;\n line-height: 1.5;\n display: none;\n ";
864
+ details.style.paddingTop = "20px";
865
+ const bridge = document.createElement("div");
866
+ bridge.style.cssText = "\n position: absolute;\n bottom: 100%;\n left: 0;\n right: 0;\n height: 8px;\n display: none;\n ";
867
+ let detailsHTML = '<div style="margin-bottom: 8px; font-weight: 600; color: #1d1d1f;">Current Environment</div>';
868
+ detailsHTML += '<div style="display: flex; flex-direction: column; gap: 6px;">';
869
+ if (draftMode) {
870
+ detailsHTML += '\n <div style="display: flex; justify-content: space-between; color: #86868b;">\n <span>Draft Mode:</span>\n <span style="color: #ff9500; font-weight: 600;">ON</span>\n </div>\n ';
871
+ }
872
+ if (trackingDisabled) {
873
+ detailsHTML += '\n <div style="display: flex; justify-content: space-between; color: #86868b;">\n <span>Tracking:</span>\n <span style="color: #ff3b30; font-weight: 600;">DISABLED</span>\n </div>\n ';
874
+ }
875
+ if (params.funnelEnv) {
876
+ detailsHTML += '\n <div style="display: flex; justify-content: space-between; color: #86868b;">\n <span>Funnel Env:</span>\n <span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">\n '.concat(params.funnelEnv, "\n </span>\n </div>\n ");
877
+ }
878
+ if (params.tagadaClientEnv) {
879
+ detailsHTML += '\n <div style="display: flex; justify-content: space-between; color: #86868b;">\n <span>API Env:</span>\n <span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">\n '.concat(params.tagadaClientEnv, "\n </span>\n </div>\n ");
880
+ }
881
+ if (params.tagadaClientBaseUrl) {
882
+ detailsHTML += '\n <div style="color: #86868b;">\n <div style="margin-bottom: 4px;">API URL:</div>\n <div style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">\n '.concat(params.tagadaClientBaseUrl, "\n </div>\n </div>\n ");
883
+ }
884
+ if (params.funnelId) {
885
+ detailsHTML += '\n <div style="color: #86868b; margin-top: 4px; padding-top: 8px; border-top: 1px solid #e5e5e5;">\n <div style="margin-bottom: 4px;">Funnel ID:</div>\n <div style="color: #1d1d1f; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">\n '.concat(params.funnelId, "\n </div>\n </div>\n ");
886
+ }
887
+ detailsHTML += "</div>";
888
+ detailsHTML += '\n <div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5; font-size: 11px; color: #86868b; text-align: center;">\n Add <code style="background: #f5f5f7; padding: 2px 4px; border-radius: 3px;">?forceReset=true</code> to reset\n </div>\n ';
889
+ detailsHTML += '\n <div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5;">\n <button id="tgd-leave-preview" style="\n background: #ff3b30;\n color: white;\n border: none;\n border-radius: 6px;\n padding: 10px 12px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.2s;\n width: 100%;\n ">\n \u{1F6AA} Leave Preview Mode\n </button>\n </div>\n ';
890
+ details.innerHTML = detailsHTML;
891
+ let isHovering = false;
892
+ const showDetails = () => {
893
+ isHovering = true;
894
+ details.style.display = "block";
895
+ bridge.style.display = "block";
896
+ };
897
+ const hideDetails = () => {
898
+ isHovering = false;
899
+ setTimeout(() => {
900
+ if (!isHovering) {
901
+ details.style.display = "none";
902
+ bridge.style.display = "none";
903
+ }
904
+ }, 100);
905
+ };
906
+ badge.addEventListener("mouseenter", showDetails);
907
+ badge.addEventListener("mouseleave", hideDetails);
908
+ bridge.addEventListener("mouseenter", showDetails);
909
+ bridge.addEventListener("mouseleave", hideDetails);
910
+ details.addEventListener("mouseenter", showDetails);
911
+ details.addEventListener("mouseleave", hideDetails);
912
+ const leavePreviewBtn = details.querySelector("#tgd-leave-preview");
913
+ if (leavePreviewBtn) {
914
+ leavePreviewBtn.addEventListener("mouseenter", () => {
915
+ leavePreviewBtn.style.opacity = "0.8";
916
+ });
917
+ leavePreviewBtn.addEventListener("mouseleave", () => {
918
+ leavePreviewBtn.style.opacity = "1";
919
+ });
920
+ leavePreviewBtn.addEventListener("click", (e) => {
921
+ e.stopPropagation();
922
+ leavePreviewMode();
923
+ });
924
+ }
925
+ container.appendChild(badge);
926
+ container.appendChild(bridge);
927
+ container.appendChild(details);
928
+ document.body.appendChild(container);
929
+ indicatorElement = container;
930
+ isInjected = true;
931
+ }
932
+ var indicatorElement, isInjected;
933
+ var init_previewModeIndicator = __esm({
934
+ "src/v2/core/utils/previewModeIndicator.ts"() {
935
+ "use strict";
936
+ init_previewMode();
937
+ init_tokenStorage();
938
+ init_sessionStorage();
939
+ indicatorElement = null;
940
+ isInjected = false;
941
+ }
942
+ });
568
943
 
569
944
  // src/v2/core/funnelClient.ts
945
+ var funnelClient_exports = {};
946
+ __export(funnelClient_exports, {
947
+ FunnelClient: () => FunnelClient,
948
+ TrackingProvider: () => TrackingProvider,
949
+ getAssignedPaymentFlowId: () => getAssignedPaymentFlowId,
950
+ getAssignedPixels: () => getAssignedPixels,
951
+ getAssignedScripts: () => getAssignedScripts,
952
+ getAssignedStaticResources: () => getAssignedStaticResources,
953
+ getAssignedStepConfig: () => getAssignedStepConfig,
954
+ getLocalFunnelConfig: () => getLocalFunnelConfig,
955
+ loadLocalFunnelConfig: () => loadLocalFunnelConfig
956
+ });
570
957
  function getAssignedFunnelId() {
571
958
  if (typeof window === "undefined") return void 0;
572
959
  if (window.__TGD_FUNNEL_ID__) {
@@ -600,376 +987,587 @@ var TagadaTrackerBundle = (() => {
600
987
  }
601
988
  return void 0;
602
989
  }
603
- var FunnelClient = class {
604
- constructor(config) {
605
- this.eventDispatcher = new EventDispatcher();
606
- // Guards
607
- this.isInitializing = false;
608
- this.initializationAttempted = false;
609
- this.config = config;
610
- this.resource = new FunnelResource(config.apiClient);
611
- this.state = {
612
- context: null,
613
- isLoading: false,
614
- isInitialized: false,
615
- isNavigating: false,
616
- error: null,
617
- sessionError: null
618
- };
990
+ function parseStepConfig(value) {
991
+ if (!value || typeof value !== "string") return void 0;
992
+ const trimmed = value.trim();
993
+ if (!trimmed) return void 0;
994
+ const strategies = [
995
+ // Strategy 1: Direct JSON parse (for properly escaped window variable)
996
+ () => JSON.parse(trimmed),
997
+ // Strategy 2: URL decode then JSON parse (for meta tag)
998
+ () => JSON.parse(decodeURIComponent(trimmed)),
999
+ // Strategy 3: Double URL decode (edge case: double-encoded)
1000
+ () => JSON.parse(decodeURIComponent(decodeURIComponent(trimmed)))
1001
+ ];
1002
+ for (const strategy of strategies) {
1003
+ try {
1004
+ const result = strategy();
1005
+ if (result && typeof result === "object") {
1006
+ return result;
1007
+ }
1008
+ } catch (e) {
1009
+ }
619
1010
  }
620
- /**
621
- * Update configuration (e.g. when plugin config loads)
622
- */
623
- setConfig(config) {
624
- this.config = __spreadValues(__spreadValues({}, this.config), config);
1011
+ if (typeof console !== "undefined") {
1012
+ console.warn("[SDK] Failed to parse stepConfig:", trimmed.substring(0, 100));
625
1013
  }
626
- /**
627
- * Subscribe to state changes
628
- */
629
- subscribe(listener) {
630
- return this.eventDispatcher.subscribe(listener);
1014
+ return void 0;
1015
+ }
1016
+ function isLocalDevelopment() {
1017
+ if (typeof window === "undefined") return false;
1018
+ const hostname = window.location.hostname;
1019
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".localhost") && !hostname.includes(".cdn.");
1020
+ }
1021
+ async function loadLocalFunnelConfig() {
1022
+ if (!isLocalDevelopment()) return null;
1023
+ if (localFunnelConfigCache !== void 0) {
1024
+ return localFunnelConfigCache;
631
1025
  }
632
- /**
633
- * Get current state
634
- */
635
- getState() {
636
- return this.state;
1026
+ if (localFunnelConfigLoading) {
1027
+ await new Promise((resolve) => setTimeout(resolve, 100));
1028
+ return localFunnelConfigCache != null ? localFunnelConfigCache : null;
637
1029
  }
638
- /**
639
- * Get the session ID that would be used for initialization (URL params or cookie)
640
- * This allows getting the session ID even before the client is fully initialized.
641
- */
642
- getDetectedSessionId() {
643
- var _a;
644
- if ((_a = this.state.context) == null ? void 0 : _a.sessionId) {
645
- return this.state.context.sessionId;
1030
+ localFunnelConfigLoading = true;
1031
+ try {
1032
+ console.log("\u{1F6E0}\uFE0F [SDK] Loading local funnel config from /config/funnel.local.json...");
1033
+ const response = await fetch("/config/funnel.local.json");
1034
+ if (!response.ok) {
1035
+ console.log("\u{1F6E0}\uFE0F [SDK] funnel.local.json not found (this is fine in production)");
1036
+ localFunnelConfigCache = null;
1037
+ return null;
646
1038
  }
647
- if (typeof window === "undefined") return null;
648
- const params = new URLSearchParams(window.location.search);
649
- const urlSessionId = params.get("funnelSessionId");
650
- if (urlSessionId) return urlSessionId;
651
- return getFunnelSessionCookie() || null;
1039
+ const config = await response.json();
1040
+ console.log("\u{1F6E0}\uFE0F [SDK] \u2705 Loaded local funnel config:", config);
1041
+ localFunnelConfigCache = config;
1042
+ return config;
1043
+ } catch (error) {
1044
+ console.log("\u{1F6E0}\uFE0F [SDK] funnel.local.json not available:", error);
1045
+ localFunnelConfigCache = null;
1046
+ return null;
1047
+ } finally {
1048
+ localFunnelConfigLoading = false;
652
1049
  }
653
- /**
654
- * Reset initialization state (used for back-button restores)
655
- */
656
- resetInitialization() {
657
- this.initializationAttempted = false;
658
- this.isInitializing = false;
659
- this.updateState({
660
- context: null,
661
- isInitialized: false
662
- });
1050
+ }
1051
+ function getLocalFunnelConfig() {
1052
+ return localFunnelConfigCache != null ? localFunnelConfigCache : null;
1053
+ }
1054
+ function localConfigToStepConfig(local) {
1055
+ return {
1056
+ payment: local.paymentFlowId ? { paymentFlowId: local.paymentFlowId } : void 0,
1057
+ staticResources: local.staticResources,
1058
+ scripts: local.scripts,
1059
+ pixels: local.pixels
1060
+ };
1061
+ }
1062
+ function getAssignedStepConfig() {
1063
+ if (typeof window === "undefined") return void 0;
1064
+ const localConfig = getLocalFunnelConfig();
1065
+ if (localConfig) {
1066
+ console.log("\u{1F6E0}\uFE0F [SDK] Using local funnel.local.json (overrides injected)");
1067
+ return localConfigToStepConfig(localConfig);
663
1068
  }
664
- /**
665
- * Initialize session with automatic detection (cookies, URL, etc.)
666
- */
667
- async autoInitialize(authSession, store, funnelId) {
668
- if (this.state.context) return this.state.context;
669
- if (this.isInitializing) return null;
670
- if (this.initializationAttempted) return null;
671
- this.initializationAttempted = true;
672
- this.isInitializing = true;
673
- this.updateState({ isLoading: true, error: null });
674
- try {
675
- const existingSessionId = this.getDetectedSessionId();
676
- const params = new URLSearchParams(typeof window !== "undefined" ? window.location.search : "");
677
- const urlFunnelId = params.get("funnelId");
678
- const effectiveFunnelId = urlFunnelId || funnelId;
679
- const injectedFunnelId = getAssignedFunnelId();
680
- const funnelVariantId = getAssignedFunnelVariant();
681
- const injectedStepId = getAssignedFunnelStep();
682
- const sdkParams = getSDKParams();
683
- const finalFunnelId = this.config.funnelId || injectedFunnelId || effectiveFunnelId;
684
- const finalStepId = this.config.stepId || injectedStepId;
685
- if (this.config.debugMode) {
686
- console.log("\u{1F680} [FunnelClient] Auto-initializing...", {
687
- existingSessionId,
688
- effectiveFunnelId: finalFunnelId,
689
- funnelVariantId,
690
- // 🎯 Log variant ID for debugging
691
- funnelStepId: finalStepId,
692
- // 🎯 Log step ID for debugging
693
- draft: sdkParams.draft,
694
- // 🎯 Log draft mode
695
- funnelTracking: sdkParams.funnelTracking,
696
- // 🎯 Log tracking flag
697
- source: {
698
- funnelId: this.config.funnelId ? "config" : injectedFunnelId ? "injected" : effectiveFunnelId ? "url/prop" : "none",
699
- stepId: this.config.stepId ? "config" : injectedStepId ? "injected" : "none"
700
- }
701
- });
702
- }
703
- const response = await this.resource.initialize({
704
- cmsSession: {
705
- customerId: authSession.customerId,
706
- sessionId: authSession.sessionId,
707
- storeId: store.id,
708
- accountId: store.accountId
709
- },
710
- funnelId: finalFunnelId,
711
- existingSessionId: existingSessionId || void 0,
712
- currentUrl: typeof window !== "undefined" ? window.location.href : void 0,
713
- funnelVariantId,
714
- // 🎯 Pass A/B test variant ID to backend
715
- funnelStepId: finalStepId,
716
- // 🎯 Pass step ID to backend (with config override)
717
- draft: sdkParams.draft,
718
- // 🎯 Pass draft mode explicitly (more robust than URL parsing)
719
- funnelTracking: sdkParams.funnelTracking
720
- // 🎯 Pass funnel tracking flag explicitly
721
- });
722
- if (response.success && response.context) {
723
- const enriched = this.enrichContext(response.context);
724
- this.handleSessionSuccess(enriched);
725
- return enriched;
726
- } else {
727
- throw new Error(response.error || "Failed to initialize funnel session");
728
- }
729
- } catch (error) {
730
- const err = error instanceof Error ? error : new Error(String(error));
731
- this.updateState({ error: err, isLoading: false });
732
- if (this.config.debugMode) {
733
- console.error("\u274C [FunnelClient] Init failed:", err);
734
- }
735
- throw err;
736
- } finally {
737
- this.isInitializing = false;
1069
+ const windowValue = window.__TGD_STEP_CONFIG__;
1070
+ if (windowValue) {
1071
+ const parsed = parseStepConfig(windowValue);
1072
+ if (parsed) return parsed;
1073
+ }
1074
+ if (typeof document !== "undefined") {
1075
+ const meta = document.querySelector('meta[name="x-step-config"]');
1076
+ const content = meta == null ? void 0 : meta.getAttribute("content");
1077
+ if (content) {
1078
+ const parsed = parseStepConfig(content);
1079
+ if (parsed) return parsed;
738
1080
  }
739
1081
  }
740
- /**
741
- * Manual initialization
742
- */
743
- async initialize(authSession, store, funnelId, entryStepId) {
744
- this.updateState({ isLoading: true, error: null });
745
- try {
746
- const funnelVariantId = getAssignedFunnelVariant();
747
- const funnelStepId = getAssignedFunnelStep();
748
- if (this.config.debugMode) {
749
- if (funnelVariantId) console.log("\u{1F3AF} [FunnelClient] Detected A/B test variant:", funnelVariantId);
750
- if (funnelStepId) console.log("\u{1F3AF} [FunnelClient] Detected step ID:", funnelStepId);
751
- }
752
- const response = await this.resource.initialize({
753
- cmsSession: {
754
- customerId: authSession.customerId,
755
- sessionId: authSession.sessionId,
756
- storeId: store.id,
757
- accountId: store.accountId
758
- },
759
- funnelId,
760
- entryStepId,
761
- currentUrl: typeof window !== "undefined" ? window.location.href : void 0,
762
- funnelVariantId,
763
- // 🎯 Pass A/B test variant ID to backend
764
- funnelStepId
765
- // 🎯 Pass step ID to backend
766
- });
767
- if (response.success && response.context) {
768
- const enriched = this.enrichContext(response.context);
769
- this.handleSessionSuccess(enriched);
770
- return enriched;
771
- } else {
772
- throw new Error(response.error || "Failed to initialize");
773
- }
774
- } catch (error) {
775
- const err = error instanceof Error ? error : new Error(String(error));
776
- this.updateState({ error: err, isLoading: false });
777
- throw err;
1082
+ return void 0;
1083
+ }
1084
+ function getAssignedPaymentFlowId() {
1085
+ var _a;
1086
+ const stepConfig = getAssignedStepConfig();
1087
+ if ((_a = stepConfig == null ? void 0 : stepConfig.payment) == null ? void 0 : _a.paymentFlowId) {
1088
+ return stepConfig.payment.paymentFlowId;
1089
+ }
1090
+ if (typeof window !== "undefined") {
1091
+ if (window.__TGD_PAYMENT_FLOW_ID__) {
1092
+ return window.__TGD_PAYMENT_FLOW_ID__;
1093
+ }
1094
+ if (typeof document !== "undefined") {
1095
+ const meta = document.querySelector('meta[name="x-payment-flow-id"]');
1096
+ return (meta == null ? void 0 : meta.getAttribute("content")) || void 0;
778
1097
  }
779
1098
  }
780
- /**
781
- * Navigate
782
- * @param event - Navigation event/action
783
- * @param options - Navigation options
784
- * @param options.fireAndForget - If true, queues navigation to QStash and returns immediately without waiting for result
785
- * @param options.customerTags - Customer tags to set (merged with existing customer tags)
786
- * @param options.deviceId - Device ID for geo/device tag enrichment (optional, rarely needed)
787
- */
788
- async navigate(event, options) {
789
- var _a, _b, _c;
790
- if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) throw new Error("No active session");
791
- this.updateState({ isNavigating: true, isLoading: true });
792
- try {
793
- let funnelVariantId = getAssignedFunnelVariant();
794
- let funnelStepId = getAssignedFunnelStep();
795
- const currentUrl = typeof window !== "undefined" ? window.location.href : void 0;
796
- if (!funnelStepId && this.config.stepId) {
797
- funnelStepId = this.config.stepId;
798
- if (this.config.debugMode) {
799
- console.log("\u{1F50D} [FunnelClient.navigate] Using stepId from config (no injection):", funnelStepId);
800
- }
1099
+ return void 0;
1100
+ }
1101
+ function getAssignedStaticResources() {
1102
+ const stepConfig = getAssignedStepConfig();
1103
+ return stepConfig == null ? void 0 : stepConfig.staticResources;
1104
+ }
1105
+ function getAssignedScripts(position) {
1106
+ const stepConfig = getAssignedStepConfig();
1107
+ if (!(stepConfig == null ? void 0 : stepConfig.scripts)) return void 0;
1108
+ let scripts = stepConfig.scripts.filter((s) => s.enabled);
1109
+ if (position) {
1110
+ scripts = scripts.filter((s) => s.position === position || !s.position && position === "head-end");
1111
+ }
1112
+ return scripts.length > 0 ? scripts : void 0;
1113
+ }
1114
+ function getAssignedPixels() {
1115
+ const stepConfig = getAssignedStepConfig();
1116
+ const rawPixels = stepConfig == null ? void 0 : stepConfig.pixels;
1117
+ if (!rawPixels || typeof rawPixels !== "object") return void 0;
1118
+ const normalized = {};
1119
+ for (const [key, value] of Object.entries(rawPixels)) {
1120
+ if (!value) continue;
1121
+ if (Array.isArray(value)) {
1122
+ normalized[key] = value;
1123
+ } else if (typeof value === "object") {
1124
+ normalized[key] = [value];
1125
+ }
1126
+ }
1127
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
1128
+ }
1129
+ var TrackingProvider, localFunnelConfigCache, localFunnelConfigLoading, FunnelClient;
1130
+ var init_funnelClient = __esm({
1131
+ "src/v2/core/funnelClient.ts"() {
1132
+ "use strict";
1133
+ init_environment();
1134
+ init_funnel();
1135
+ init_eventDispatcher();
1136
+ init_previewMode();
1137
+ init_previewModeIndicator();
1138
+ init_sessionStorage();
1139
+ TrackingProvider = /* @__PURE__ */ ((TrackingProvider2) => {
1140
+ TrackingProvider2["FACEBOOK"] = "facebook";
1141
+ TrackingProvider2["TIKTOK"] = "tiktok";
1142
+ TrackingProvider2["SNAPCHAT"] = "snapchat";
1143
+ TrackingProvider2["META_CONVERSION"] = "meta_conversion";
1144
+ TrackingProvider2["GTM"] = "gtm";
1145
+ return TrackingProvider2;
1146
+ })(TrackingProvider || {});
1147
+ localFunnelConfigCache = void 0;
1148
+ localFunnelConfigLoading = false;
1149
+ FunnelClient = class {
1150
+ constructor(config) {
1151
+ this.eventDispatcher = new EventDispatcher();
1152
+ // Guards
1153
+ this.isInitializing = false;
1154
+ this.initializationAttempted = false;
1155
+ this.config = config;
1156
+ this.resource = new FunnelResource(config.apiClient);
1157
+ this.state = {
1158
+ context: null,
1159
+ isLoading: false,
1160
+ isInitialized: false,
1161
+ isNavigating: false,
1162
+ error: null,
1163
+ sessionError: null
1164
+ };
801
1165
  }
802
- if (!funnelVariantId && this.config.variantId) {
803
- funnelVariantId = this.config.variantId;
804
- if (this.config.debugMode) {
805
- console.log("\u{1F50D} [FunnelClient.navigate] Using variantId from config (no injection):", funnelVariantId);
1166
+ /**
1167
+ * Update configuration (e.g. when plugin config loads)
1168
+ */
1169
+ setConfig(config) {
1170
+ this.config = __spreadValues(__spreadValues({}, this.config), config);
1171
+ }
1172
+ /**
1173
+ * Subscribe to state changes
1174
+ */
1175
+ subscribe(listener) {
1176
+ return this.eventDispatcher.subscribe(listener);
1177
+ }
1178
+ /**
1179
+ * Get current state
1180
+ */
1181
+ getState() {
1182
+ return this.state;
1183
+ }
1184
+ /**
1185
+ * Get the session ID that would be used for initialization (URL params or cookie)
1186
+ * This allows getting the session ID even before the client is fully initialized.
1187
+ */
1188
+ getDetectedSessionId() {
1189
+ var _a;
1190
+ if ((_a = this.state.context) == null ? void 0 : _a.sessionId) {
1191
+ return this.state.context.sessionId;
806
1192
  }
807
- }
808
- if (this.config.debugMode) {
809
- console.log("\u{1F50D} [FunnelClient.navigate] Sending to backend:", {
810
- sessionId: this.state.context.sessionId,
811
- currentUrl,
812
- funnelStepId: funnelStepId || "(not found)",
813
- funnelVariantId: funnelVariantId || "(not found)",
814
- hasInjectedStepId: !!getAssignedFunnelStep(),
815
- hasInjectedVariantId: !!getAssignedFunnelVariant(),
816
- usedConfigFallback: !getAssignedFunnelStep() && !!this.config.stepId,
817
- customerTags: (options == null ? void 0 : options.customerTags) || "(none)",
818
- deviceId: (options == null ? void 0 : options.deviceId) || "(none)"
1193
+ if (typeof window === "undefined") return null;
1194
+ const params = new URLSearchParams(window.location.search);
1195
+ const urlSessionId = params.get("funnelSessionId");
1196
+ if (urlSessionId) return urlSessionId;
1197
+ return getFunnelSessionCookie() || null;
1198
+ }
1199
+ /**
1200
+ * Reset initialization state (used for back-button restores)
1201
+ */
1202
+ resetInitialization() {
1203
+ this.initializationAttempted = false;
1204
+ this.isInitializing = false;
1205
+ this.updateState({
1206
+ context: null,
1207
+ isInitialized: false
819
1208
  });
820
1209
  }
821
- const fireAndForget = (options == null ? void 0 : options.fireAndForget) || false;
822
- const response = await this.resource.navigate({
823
- sessionId: this.state.context.sessionId,
824
- event,
825
- currentUrl,
826
- funnelStepId,
827
- funnelVariantId,
828
- fireAndForget,
829
- customerTags: options == null ? void 0 : options.customerTags,
830
- deviceId: options == null ? void 0 : options.deviceId
831
- });
832
- if (!response.success || !response.result) {
833
- throw new Error(response.error || "Navigation failed");
1210
+ /**
1211
+ * Initialize session with automatic detection (cookies, URL, etc.)
1212
+ */
1213
+ async autoInitialize(authSession, store, funnelId) {
1214
+ if (this.state.context) return this.state.context;
1215
+ if (this.isInitializing) return null;
1216
+ if (this.initializationAttempted) return null;
1217
+ this.initializationAttempted = true;
1218
+ this.isInitializing = true;
1219
+ this.updateState({ isLoading: true, error: null });
1220
+ try {
1221
+ const existingSessionId = this.getDetectedSessionId();
1222
+ const params = new URLSearchParams(typeof window !== "undefined" ? window.location.search : "");
1223
+ const urlFunnelId = params.get("funnelId");
1224
+ const effectiveFunnelId = urlFunnelId || funnelId;
1225
+ const injectedFunnelId = getAssignedFunnelId();
1226
+ const funnelVariantId = getAssignedFunnelVariant();
1227
+ const injectedStepId = getAssignedFunnelStep();
1228
+ const sdkParams = getSDKParams();
1229
+ const finalFunnelId = this.config.funnelId || injectedFunnelId || effectiveFunnelId;
1230
+ const finalStepId = this.config.stepId || injectedStepId;
1231
+ const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
1232
+ const funnelEnv = urlParams == null ? void 0 : urlParams.get("funnelEnv");
1233
+ if (this.config.debugMode) {
1234
+ console.log("\u{1F680} [FunnelClient] Auto-initializing...", {
1235
+ existingSessionId,
1236
+ effectiveFunnelId: finalFunnelId,
1237
+ funnelVariantId,
1238
+ // 🎯 Log variant ID for debugging
1239
+ funnelStepId: finalStepId,
1240
+ // 🎯 Log step ID for debugging
1241
+ draft: sdkParams.draft,
1242
+ // 🎯 Log draft mode
1243
+ funnelTracking: sdkParams.funnelTracking,
1244
+ // 🎯 Log tracking flag
1245
+ funnelEnv,
1246
+ // 🎯 Log funnel environment
1247
+ tagadaClientEnv: sdkParams.tagadaClientEnv,
1248
+ // 🎯 Log client environment
1249
+ tagadaClientBaseUrl: sdkParams.tagadaClientBaseUrl,
1250
+ // 🎯 Log custom API URL
1251
+ source: {
1252
+ funnelId: this.config.funnelId ? "config" : injectedFunnelId ? "injected" : effectiveFunnelId ? "url/prop" : "none",
1253
+ stepId: this.config.stepId ? "config" : injectedStepId ? "injected" : "none"
1254
+ }
1255
+ });
1256
+ }
1257
+ const response = await this.resource.initialize({
1258
+ cmsSession: {
1259
+ customerId: authSession.customerId,
1260
+ sessionId: authSession.sessionId,
1261
+ storeId: store.id,
1262
+ accountId: store.accountId
1263
+ },
1264
+ funnelId: finalFunnelId,
1265
+ existingSessionId: existingSessionId || void 0,
1266
+ currentUrl: typeof window !== "undefined" ? window.location.href : void 0,
1267
+ funnelVariantId,
1268
+ // 🎯 Pass A/B test variant ID to backend
1269
+ funnelStepId: finalStepId,
1270
+ // 🎯 Pass step ID to backend (with config override)
1271
+ draft: sdkParams.draft,
1272
+ // 🎯 Pass draft mode explicitly (more robust than URL parsing)
1273
+ funnelTracking: sdkParams.funnelTracking,
1274
+ // 🎯 Pass funnel tracking flag explicitly
1275
+ funnelEnv: funnelEnv || void 0,
1276
+ // 🎯 Pass funnel environment (staging/production)
1277
+ tagadaClientEnv: sdkParams.tagadaClientEnv,
1278
+ // 🎯 Pass client environment override
1279
+ tagadaClientBaseUrl: sdkParams.tagadaClientBaseUrl,
1280
+ // 🎯 Pass custom API base URL
1281
+ currency: sdkParams.currency,
1282
+ // 🌍 Pass display currency override
1283
+ locale: sdkParams.locale
1284
+ // 🌍 Pass display locale override
1285
+ });
1286
+ if (response.success && response.context) {
1287
+ const enriched = this.enrichContext(response.context);
1288
+ this.handleSessionSuccess(enriched);
1289
+ injectPreviewModeIndicator();
1290
+ return enriched;
1291
+ } else {
1292
+ throw new Error(response.error || "Failed to initialize funnel session");
1293
+ }
1294
+ } catch (error) {
1295
+ const err = error instanceof Error ? error : new Error(String(error));
1296
+ this.updateState({ error: err, isLoading: false });
1297
+ if (this.config.debugMode) {
1298
+ console.error("\u274C [FunnelClient] Init failed:", err);
1299
+ }
1300
+ throw err;
1301
+ } finally {
1302
+ this.isInitializing = false;
1303
+ }
834
1304
  }
835
- const result = response.result;
836
- if (result.queued) {
837
- this.updateState({ isNavigating: false, isLoading: false });
838
- if (result.sessionId && result.sessionId !== ((_b = this.state.context) == null ? void 0 : _b.sessionId)) {
1305
+ /**
1306
+ * Manual initialization
1307
+ */
1308
+ async initialize(authSession, store, funnelId, entryStepId) {
1309
+ this.updateState({ isLoading: true, error: null });
1310
+ try {
1311
+ const funnelVariantId = getAssignedFunnelVariant();
1312
+ const funnelStepId = getAssignedFunnelStep();
839
1313
  if (this.config.debugMode) {
840
- console.log("\u{1F525} [FunnelClient] Session ID updated: ".concat((_c = this.state.context) == null ? void 0 : _c.sessionId, " \u2192 ").concat(result.sessionId));
1314
+ if (funnelVariantId) console.log("\u{1F3AF} [FunnelClient] Detected A/B test variant:", funnelVariantId);
1315
+ if (funnelStepId) console.log("\u{1F3AF} [FunnelClient] Detected step ID:", funnelStepId);
841
1316
  }
842
- if (this.state.context) {
843
- this.state.context.sessionId = result.sessionId;
1317
+ const response = await this.resource.initialize({
1318
+ cmsSession: {
1319
+ customerId: authSession.customerId,
1320
+ sessionId: authSession.sessionId,
1321
+ storeId: store.id,
1322
+ accountId: store.accountId
1323
+ },
1324
+ funnelId,
1325
+ entryStepId,
1326
+ currentUrl: typeof window !== "undefined" ? window.location.href : void 0,
1327
+ funnelVariantId,
1328
+ // 🎯 Pass A/B test variant ID to backend
1329
+ funnelStepId
1330
+ // 🎯 Pass step ID to backend
1331
+ });
1332
+ if (response.success && response.context) {
1333
+ const enriched = this.enrichContext(response.context);
1334
+ this.handleSessionSuccess(enriched);
1335
+ injectPreviewModeIndicator();
1336
+ return enriched;
1337
+ } else {
1338
+ throw new Error(response.error || "Failed to initialize");
844
1339
  }
1340
+ } catch (error) {
1341
+ const err = error instanceof Error ? error : new Error(String(error));
1342
+ this.updateState({ error: err, isLoading: false });
1343
+ throw err;
845
1344
  }
846
- if (this.config.debugMode) {
847
- console.log("\u{1F525} [FunnelClient] Navigation queued (fire-and-forget mode)");
1345
+ }
1346
+ /**
1347
+ * Navigate
1348
+ * @param event - Navigation event/action
1349
+ * @param options - Navigation options
1350
+ * @param options.fireAndForget - If true, queues navigation to QStash and returns immediately without waiting for result
1351
+ * @param options.customerTags - Customer tags to set (merged with existing customer tags)
1352
+ * @param options.deviceId - Device ID for geo/device tag enrichment (optional, rarely needed)
1353
+ * @param options.autoRedirect - Override global autoRedirect setting for this specific call (default: use config)
1354
+ */
1355
+ async navigate(event, options) {
1356
+ var _a, _b, _c, _d, _e, _f;
1357
+ if ((options == null ? void 0 : options.waitForSession) && !((_a = this.state.context) == null ? void 0 : _a.sessionId)) {
1358
+ if (this.config.debugMode) {
1359
+ console.log("\u23F3 [FunnelClient] Waiting for session before navigation...");
1360
+ }
1361
+ const maxWaitTime = 5e3;
1362
+ const startTime = Date.now();
1363
+ while (!((_b = this.state.context) == null ? void 0 : _b.sessionId) && Date.now() - startTime < maxWaitTime) {
1364
+ await new Promise((resolve) => setTimeout(resolve, 100));
1365
+ }
1366
+ if (((_c = this.state.context) == null ? void 0 : _c.sessionId) && this.config.debugMode) {
1367
+ console.log("\u2705 [FunnelClient] Session ready, proceeding with navigation");
1368
+ }
1369
+ }
1370
+ if (!((_d = this.state.context) == null ? void 0 : _d.sessionId)) throw new Error("No active session");
1371
+ this.updateState({ isNavigating: true, isLoading: true });
1372
+ try {
1373
+ let funnelVariantId = getAssignedFunnelVariant();
1374
+ let funnelStepId = getAssignedFunnelStep();
1375
+ const currentUrl = typeof window !== "undefined" ? window.location.href : void 0;
1376
+ if (!funnelStepId && this.config.stepId) {
1377
+ funnelStepId = this.config.stepId;
1378
+ if (this.config.debugMode) {
1379
+ console.log("\u{1F50D} [FunnelClient.navigate] Using stepId from config (no injection):", funnelStepId);
1380
+ }
1381
+ }
1382
+ if (!funnelVariantId && this.config.variantId) {
1383
+ funnelVariantId = this.config.variantId;
1384
+ if (this.config.debugMode) {
1385
+ console.log("\u{1F50D} [FunnelClient.navigate] Using variantId from config (no injection):", funnelVariantId);
1386
+ }
1387
+ }
1388
+ if (this.config.debugMode) {
1389
+ console.log("\u{1F50D} [FunnelClient.navigate] Sending to backend:", {
1390
+ sessionId: this.state.context.sessionId,
1391
+ currentUrl,
1392
+ funnelStepId: funnelStepId || "(not found)",
1393
+ funnelVariantId: funnelVariantId || "(not found)",
1394
+ hasInjectedStepId: !!getAssignedFunnelStep(),
1395
+ hasInjectedVariantId: !!getAssignedFunnelVariant(),
1396
+ usedConfigFallback: !getAssignedFunnelStep() && !!this.config.stepId,
1397
+ customerTags: (options == null ? void 0 : options.customerTags) || "(none)",
1398
+ deviceId: (options == null ? void 0 : options.deviceId) || "(none)"
1399
+ });
1400
+ }
1401
+ const fireAndForget = (options == null ? void 0 : options.fireAndForget) || false;
1402
+ const response = await this.resource.navigate({
1403
+ sessionId: this.state.context.sessionId,
1404
+ event,
1405
+ currentUrl,
1406
+ funnelStepId,
1407
+ funnelVariantId,
1408
+ fireAndForget,
1409
+ customerTags: options == null ? void 0 : options.customerTags,
1410
+ deviceId: options == null ? void 0 : options.deviceId
1411
+ });
1412
+ if (!response.success || !response.result) {
1413
+ throw new Error(response.error || "Navigation failed");
1414
+ }
1415
+ const result = response.result;
1416
+ if (result.queued) {
1417
+ this.updateState({ isNavigating: false, isLoading: false });
1418
+ if (result.sessionId && result.sessionId !== ((_e = this.state.context) == null ? void 0 : _e.sessionId)) {
1419
+ if (this.config.debugMode) {
1420
+ console.log("\u{1F525} [FunnelClient] Session ID updated: ".concat((_f = this.state.context) == null ? void 0 : _f.sessionId, " \u2192 ").concat(result.sessionId));
1421
+ }
1422
+ if (this.state.context) {
1423
+ this.state.context.sessionId = result.sessionId;
1424
+ }
1425
+ }
1426
+ if (this.config.debugMode) {
1427
+ console.log("\u{1F525} [FunnelClient] Navigation queued (fire-and-forget mode)");
1428
+ }
1429
+ return result;
1430
+ }
1431
+ const shouldAutoRedirect = (options == null ? void 0 : options.autoRedirect) !== void 0 ? options.autoRedirect : this.config.autoRedirect !== false;
1432
+ if (!shouldAutoRedirect) {
1433
+ if (this.config.debugMode) {
1434
+ console.log("\u{1F504} [FunnelClient] Refreshing session (no auto-redirect)");
1435
+ }
1436
+ await this.refreshSession();
1437
+ }
1438
+ this.updateState({ isNavigating: false, isLoading: false });
1439
+ if (shouldAutoRedirect && (result == null ? void 0 : result.url) && typeof window !== "undefined") {
1440
+ if (this.config.debugMode) {
1441
+ console.log("\u{1F680} [FunnelClient] Auto-redirecting to:", result.url, "(skipped session refresh - next page will initialize)");
1442
+ }
1443
+ window.location.href = result.url;
1444
+ }
1445
+ return result;
1446
+ } catch (error) {
1447
+ const err = error instanceof Error ? error : new Error(String(error));
1448
+ this.updateState({ error: err, isNavigating: false, isLoading: false });
1449
+ throw err;
848
1450
  }
849
- return result;
850
1451
  }
851
- const shouldAutoRedirect = this.config.autoRedirect !== false;
852
- if (!shouldAutoRedirect) {
853
- if (this.config.debugMode) {
854
- console.log("\u{1F504} [FunnelClient] Refreshing session (no auto-redirect)");
1452
+ /**
1453
+ * Go to a specific step (direct navigation)
1454
+ * @param stepId - Target step ID
1455
+ * @param options - Navigation options (autoRedirect, etc.)
1456
+ */
1457
+ async goToStep(stepId, options) {
1458
+ return this.navigate(
1459
+ {
1460
+ type: "direct_navigation" /* DIRECT_NAVIGATION */,
1461
+ data: { targetStepId: stepId }
1462
+ },
1463
+ options
1464
+ );
1465
+ }
1466
+ /**
1467
+ * Refresh session data
1468
+ */
1469
+ async refreshSession() {
1470
+ var _a;
1471
+ if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) return;
1472
+ try {
1473
+ const response = await this.resource.getSession(this.state.context.sessionId);
1474
+ if (response.success && response.context) {
1475
+ const enriched = this.enrichContext(response.context);
1476
+ this.updateState({ context: enriched, sessionError: null });
1477
+ return enriched;
1478
+ }
1479
+ } catch (error) {
1480
+ this.updateState({ sessionError: error instanceof Error ? error : new Error(String(error)) });
855
1481
  }
856
- await this.refreshSession();
857
1482
  }
858
- this.updateState({ isNavigating: false, isLoading: false });
859
- if (shouldAutoRedirect && (result == null ? void 0 : result.url) && typeof window !== "undefined") {
860
- if (this.config.debugMode) {
861
- console.log("\u{1F680} [FunnelClient] Auto-redirecting to:", result.url, "(skipped session refresh - next page will initialize)");
1483
+ /**
1484
+ * Update context data
1485
+ */
1486
+ async updateContext(updates) {
1487
+ var _a;
1488
+ if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) throw new Error("No active session");
1489
+ this.updateState({ isLoading: true });
1490
+ try {
1491
+ const response = await this.resource.updateContext(this.state.context.sessionId, { contextUpdates: updates });
1492
+ if (response.success) {
1493
+ await this.refreshSession();
1494
+ } else {
1495
+ throw new Error(response.error || "Failed to update context");
1496
+ }
1497
+ } finally {
1498
+ this.updateState({ isLoading: false });
862
1499
  }
863
- window.location.href = result.url;
864
1500
  }
865
- return result;
866
- } catch (error) {
867
- const err = error instanceof Error ? error : new Error(String(error));
868
- this.updateState({ error: err, isNavigating: false, isLoading: false });
869
- throw err;
870
- }
871
- }
872
- /**
873
- * Go to a specific step (direct navigation)
874
- */
875
- async goToStep(stepId) {
876
- return this.navigate({
877
- type: "direct_navigation" /* DIRECT_NAVIGATION */,
878
- data: { targetStepId: stepId }
879
- });
880
- }
881
- /**
882
- * Refresh session data
883
- */
884
- async refreshSession() {
885
- var _a;
886
- if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) return;
887
- try {
888
- const response = await this.resource.getSession(this.state.context.sessionId);
889
- if (response.success && response.context) {
890
- const enriched = this.enrichContext(response.context);
891
- this.updateState({ context: enriched, sessionError: null });
892
- return enriched;
1501
+ /**
1502
+ * End session
1503
+ */
1504
+ async endSession() {
1505
+ var _a;
1506
+ if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) return;
1507
+ try {
1508
+ await this.resource.endSession(this.state.context.sessionId);
1509
+ } finally {
1510
+ this.state.context = null;
1511
+ this.updateState({ context: null, isInitialized: false });
1512
+ if (typeof document !== "undefined") {
1513
+ }
1514
+ }
893
1515
  }
894
- } catch (error) {
895
- this.updateState({ sessionError: error instanceof Error ? error : new Error(String(error)) });
896
- }
897
- }
898
- /**
899
- * Update context data
900
- */
901
- async updateContext(updates) {
902
- var _a;
903
- if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) throw new Error("No active session");
904
- this.updateState({ isLoading: true });
905
- try {
906
- const response = await this.resource.updateContext(this.state.context.sessionId, { contextUpdates: updates });
907
- if (response.success) {
908
- await this.refreshSession();
909
- } else {
910
- throw new Error(response.error || "Failed to update context");
1516
+ // Private helpers
1517
+ updateState(updates) {
1518
+ this.state = __spreadValues(__spreadValues({}, this.state), updates);
1519
+ this.eventDispatcher.notify(this.state);
1520
+ }
1521
+ handleSessionSuccess(context) {
1522
+ setFunnelSessionCookie(context.sessionId);
1523
+ this.updateState({
1524
+ context,
1525
+ isLoading: false,
1526
+ isInitialized: true,
1527
+ error: null,
1528
+ sessionError: null
1529
+ });
911
1530
  }
912
- } finally {
913
- this.updateState({ isLoading: false });
914
- }
915
- }
916
- /**
917
- * End session
918
- */
919
- async endSession() {
920
- var _a;
921
- if (!((_a = this.state.context) == null ? void 0 : _a.sessionId)) return;
922
- try {
923
- await this.resource.endSession(this.state.context.sessionId);
924
- } finally {
925
- this.state.context = null;
926
- this.updateState({ context: null, isInitialized: false });
927
- if (typeof document !== "undefined") {
1531
+ enrichContext(ctx) {
1532
+ var _a, _b;
1533
+ const env = ((_a = this.config.environment) == null ? void 0 : _a.environment) || detectEnvironment();
1534
+ if (env !== "local") return ctx;
1535
+ const localResources = ((_b = this.config.pluginConfig) == null ? void 0 : _b.staticResources) || {};
1536
+ if (Object.keys(localResources).length === 0) return ctx;
1537
+ const existingStatic = ctx.static || {};
1538
+ const hasAllResources = Object.keys(localResources).every(
1539
+ (key) => existingStatic[key] === localResources[key]
1540
+ );
1541
+ if (hasAllResources && Object.keys(existingStatic).length === Object.keys(localResources).length) {
1542
+ return ctx;
1543
+ }
1544
+ return __spreadProps(__spreadValues({}, ctx), {
1545
+ static: __spreadValues(__spreadValues({}, localResources), existingStatic)
1546
+ });
928
1547
  }
929
- }
930
- }
931
- // Private helpers
932
- updateState(updates) {
933
- this.state = __spreadValues(__spreadValues({}, this.state), updates);
934
- this.eventDispatcher.notify(this.state);
935
- }
936
- handleSessionSuccess(context) {
937
- setFunnelSessionCookie(context.sessionId);
938
- this.updateState({
939
- context,
940
- isLoading: false,
941
- isInitialized: true,
942
- error: null,
943
- sessionError: null
944
- });
945
- }
946
- enrichContext(ctx) {
947
- var _a, _b;
948
- const env = ((_a = this.config.environment) == null ? void 0 : _a.environment) || detectEnvironment();
949
- if (env !== "local") return ctx;
950
- const localResources = ((_b = this.config.pluginConfig) == null ? void 0 : _b.staticResources) || {};
951
- if (Object.keys(localResources).length === 0) return ctx;
952
- const existingStatic = ctx.static || {};
953
- const hasAllResources = Object.keys(localResources).every(
954
- (key) => existingStatic[key] === localResources[key]
955
- );
956
- if (hasAllResources && Object.keys(existingStatic).length === Object.keys(localResources).length) {
957
- return ctx;
958
- }
959
- return __spreadProps(__spreadValues({}, ctx), {
960
- static: __spreadValues(__spreadValues({}, localResources), existingStatic)
961
- });
1548
+ };
962
1549
  }
963
- };
1550
+ });
1551
+
1552
+ // src/v2/standalone/external-tracker.ts
1553
+ var external_tracker_exports = {};
1554
+ __export(external_tracker_exports, {
1555
+ TagadaExternalTracker: () => TagadaExternalTracker,
1556
+ TagadaTracker: () => TagadaTracker
1557
+ });
1558
+
1559
+ // src/v2/core/client.ts
1560
+ init_environment();
1561
+ init_funnelClient();
964
1562
 
965
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/bind.js
1563
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/bind.js
966
1564
  function bind(fn, thisArg) {
967
1565
  return function wrap() {
968
1566
  return fn.apply(thisArg, arguments);
969
1567
  };
970
1568
  }
971
1569
 
972
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/utils.js
1570
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/utils.js
973
1571
  var { toString } = Object.prototype;
974
1572
  var { getPrototypeOf } = Object;
975
1573
  var { iterator, toStringTag } = Symbol;
@@ -1354,7 +1952,7 @@ var TagadaTrackerBundle = (() => {
1354
1952
  isIterable
1355
1953
  };
1356
1954
 
1357
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/AxiosError.js
1955
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/AxiosError.js
1358
1956
  function AxiosError(message, code, config, request, response) {
1359
1957
  Error.call(this);
1360
1958
  if (Error.captureStackTrace) {
@@ -1433,10 +2031,10 @@ var TagadaTrackerBundle = (() => {
1433
2031
  };
1434
2032
  var AxiosError_default = AxiosError;
1435
2033
 
1436
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/null.js
2034
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/null.js
1437
2035
  var null_default = null;
1438
2036
 
1439
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/toFormData.js
2037
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/toFormData.js
1440
2038
  function isVisitable(thing) {
1441
2039
  return utils_default.isPlainObject(thing) || utils_default.isArray(thing);
1442
2040
  }
@@ -1551,7 +2149,7 @@ var TagadaTrackerBundle = (() => {
1551
2149
  }
1552
2150
  var toFormData_default = toFormData;
1553
2151
 
1554
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/AxiosURLSearchParams.js
2152
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/AxiosURLSearchParams.js
1555
2153
  function encode(str) {
1556
2154
  const charMap = {
1557
2155
  "!": "%21",
@@ -1584,7 +2182,7 @@ var TagadaTrackerBundle = (() => {
1584
2182
  };
1585
2183
  var AxiosURLSearchParams_default = AxiosURLSearchParams;
1586
2184
 
1587
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/buildURL.js
2185
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/buildURL.js
1588
2186
  function encode2(val) {
1589
2187
  return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+");
1590
2188
  }
@@ -1615,7 +2213,7 @@ var TagadaTrackerBundle = (() => {
1615
2213
  return url;
1616
2214
  }
1617
2215
 
1618
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/InterceptorManager.js
2216
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/InterceptorManager.js
1619
2217
  var InterceptorManager = class {
1620
2218
  constructor() {
1621
2219
  this.handlers = [];
@@ -1679,23 +2277,23 @@ var TagadaTrackerBundle = (() => {
1679
2277
  };
1680
2278
  var InterceptorManager_default = InterceptorManager;
1681
2279
 
1682
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/defaults/transitional.js
2280
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/defaults/transitional.js
1683
2281
  var transitional_default = {
1684
2282
  silentJSONParsing: true,
1685
2283
  forcedJSONParsing: true,
1686
2284
  clarifyTimeoutError: false
1687
2285
  };
1688
2286
 
1689
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js
2287
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js
1690
2288
  var URLSearchParams_default = typeof URLSearchParams !== "undefined" ? URLSearchParams : AxiosURLSearchParams_default;
1691
2289
 
1692
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/platform/browser/classes/FormData.js
2290
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/platform/browser/classes/FormData.js
1693
2291
  var FormData_default = typeof FormData !== "undefined" ? FormData : null;
1694
2292
 
1695
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/platform/browser/classes/Blob.js
2293
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/platform/browser/classes/Blob.js
1696
2294
  var Blob_default = typeof Blob !== "undefined" ? Blob : null;
1697
2295
 
1698
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/platform/browser/index.js
2296
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/platform/browser/index.js
1699
2297
  var browser_default = {
1700
2298
  isBrowser: true,
1701
2299
  classes: {
@@ -1706,7 +2304,7 @@ var TagadaTrackerBundle = (() => {
1706
2304
  protocols: ["http", "https", "file", "blob", "url", "data"]
1707
2305
  };
1708
2306
 
1709
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/platform/common/utils.js
2307
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/platform/common/utils.js
1710
2308
  var utils_exports = {};
1711
2309
  __export(utils_exports, {
1712
2310
  hasBrowserEnv: () => hasBrowserEnv,
@@ -1724,10 +2322,10 @@ var TagadaTrackerBundle = (() => {
1724
2322
  })();
1725
2323
  var origin = hasBrowserEnv && window.location.href || "http://localhost";
1726
2324
 
1727
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/platform/index.js
2325
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/platform/index.js
1728
2326
  var platform_default = __spreadValues(__spreadValues({}, utils_exports), browser_default);
1729
2327
 
1730
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/toURLEncodedForm.js
2328
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/toURLEncodedForm.js
1731
2329
  function toURLEncodedForm(data, options) {
1732
2330
  return toFormData_default(data, new platform_default.classes.URLSearchParams(), __spreadValues({
1733
2331
  visitor: function(value, key, path, helpers) {
@@ -1740,7 +2338,7 @@ var TagadaTrackerBundle = (() => {
1740
2338
  }, options));
1741
2339
  }
1742
2340
 
1743
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/formDataToJSON.js
2341
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/formDataToJSON.js
1744
2342
  function parsePropPath(name) {
1745
2343
  return utils_default.matchAll(/\w+|\[(\w*)]/g, name).map((match) => {
1746
2344
  return match[0] === "[]" ? "" : match[1] || match[0];
@@ -1793,7 +2391,7 @@ var TagadaTrackerBundle = (() => {
1793
2391
  }
1794
2392
  var formDataToJSON_default = formDataToJSON;
1795
2393
 
1796
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/defaults/index.js
2394
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/defaults/index.js
1797
2395
  function stringifySafely(rawValue, parser, encoder) {
1798
2396
  if (utils_default.isString(rawValue)) {
1799
2397
  try {
@@ -1902,7 +2500,7 @@ var TagadaTrackerBundle = (() => {
1902
2500
  });
1903
2501
  var defaults_default = defaults;
1904
2502
 
1905
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/parseHeaders.js
2503
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/parseHeaders.js
1906
2504
  var ignoreDuplicateOf = utils_default.toObjectSet([
1907
2505
  "age",
1908
2506
  "authorization",
@@ -1947,7 +2545,7 @@ var TagadaTrackerBundle = (() => {
1947
2545
  return parsed;
1948
2546
  };
1949
2547
 
1950
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/AxiosHeaders.js
2548
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/AxiosHeaders.js
1951
2549
  var $internals = Symbol("internals");
1952
2550
  function normalizeHeader(header) {
1953
2551
  return header && String(header).trim().toLowerCase();
@@ -2176,7 +2774,7 @@ var TagadaTrackerBundle = (() => {
2176
2774
  utils_default.freezeMethods(AxiosHeaders);
2177
2775
  var AxiosHeaders_default = AxiosHeaders;
2178
2776
 
2179
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/transformData.js
2777
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/transformData.js
2180
2778
  function transformData(fns, response) {
2181
2779
  const config = this || defaults_default;
2182
2780
  const context = response || config;
@@ -2189,12 +2787,12 @@ var TagadaTrackerBundle = (() => {
2189
2787
  return data;
2190
2788
  }
2191
2789
 
2192
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/cancel/isCancel.js
2790
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/cancel/isCancel.js
2193
2791
  function isCancel(value) {
2194
2792
  return !!(value && value.__CANCEL__);
2195
2793
  }
2196
2794
 
2197
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/cancel/CanceledError.js
2795
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/cancel/CanceledError.js
2198
2796
  function CanceledError(message, config, request) {
2199
2797
  AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);
2200
2798
  this.name = "CanceledError";
@@ -2204,7 +2802,7 @@ var TagadaTrackerBundle = (() => {
2204
2802
  });
2205
2803
  var CanceledError_default = CanceledError;
2206
2804
 
2207
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/settle.js
2805
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/settle.js
2208
2806
  function settle(resolve, reject, response) {
2209
2807
  const validateStatus2 = response.config.validateStatus;
2210
2808
  if (!response.status || !validateStatus2 || validateStatus2(response.status)) {
@@ -2220,13 +2818,13 @@ var TagadaTrackerBundle = (() => {
2220
2818
  }
2221
2819
  }
2222
2820
 
2223
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/parseProtocol.js
2821
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/parseProtocol.js
2224
2822
  function parseProtocol(url) {
2225
2823
  const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url);
2226
2824
  return match && match[1] || "";
2227
2825
  }
2228
2826
 
2229
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/speedometer.js
2827
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/speedometer.js
2230
2828
  function speedometer(samplesCount, min) {
2231
2829
  samplesCount = samplesCount || 10;
2232
2830
  const bytes = new Array(samplesCount);
@@ -2262,7 +2860,7 @@ var TagadaTrackerBundle = (() => {
2262
2860
  }
2263
2861
  var speedometer_default = speedometer;
2264
2862
 
2265
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/throttle.js
2863
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/throttle.js
2266
2864
  function throttle(fn, freq) {
2267
2865
  let timestamp = 0;
2268
2866
  let threshold = 1e3 / freq;
@@ -2297,7 +2895,7 @@ var TagadaTrackerBundle = (() => {
2297
2895
  }
2298
2896
  var throttle_default = throttle;
2299
2897
 
2300
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/progressEventReducer.js
2898
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/progressEventReducer.js
2301
2899
  var progressEventReducer = (listener, isDownloadStream, freq = 3) => {
2302
2900
  let bytesNotified = 0;
2303
2901
  const _speedometer = speedometer_default(50, 250);
@@ -2332,7 +2930,7 @@ var TagadaTrackerBundle = (() => {
2332
2930
  };
2333
2931
  var asyncDecorator = (fn) => (...args) => utils_default.asap(() => fn(...args));
2334
2932
 
2335
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/isURLSameOrigin.js
2933
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/isURLSameOrigin.js
2336
2934
  var isURLSameOrigin_default = platform_default.hasStandardBrowserEnv ? /* @__PURE__ */ ((origin2, isMSIE) => (url) => {
2337
2935
  url = new URL(url, platform_default.origin);
2338
2936
  return origin2.protocol === url.protocol && origin2.host === url.host && (isMSIE || origin2.port === url.port);
@@ -2341,7 +2939,7 @@ var TagadaTrackerBundle = (() => {
2341
2939
  platform_default.navigator && /(msie|trident)/i.test(platform_default.navigator.userAgent)
2342
2940
  ) : () => true;
2343
2941
 
2344
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/cookies.js
2942
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/cookies.js
2345
2943
  var cookies_default = platform_default.hasStandardBrowserEnv ? (
2346
2944
  // Standard browser envs support document.cookie
2347
2945
  {
@@ -2387,17 +2985,17 @@ var TagadaTrackerBundle = (() => {
2387
2985
  }
2388
2986
  );
2389
2987
 
2390
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/isAbsoluteURL.js
2988
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/isAbsoluteURL.js
2391
2989
  function isAbsoluteURL(url) {
2392
2990
  return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
2393
2991
  }
2394
2992
 
2395
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/combineURLs.js
2993
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/combineURLs.js
2396
2994
  function combineURLs(baseURL, relativeURL) {
2397
2995
  return relativeURL ? baseURL.replace(/\/?\/$/, "") + "/" + relativeURL.replace(/^\/+/, "") : baseURL;
2398
2996
  }
2399
2997
 
2400
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/buildFullPath.js
2998
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/buildFullPath.js
2401
2999
  function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
2402
3000
  let isRelativeUrl = !isAbsoluteURL(requestedURL);
2403
3001
  if (baseURL && (isRelativeUrl || allowAbsoluteUrls == false)) {
@@ -2406,7 +3004,7 @@ var TagadaTrackerBundle = (() => {
2406
3004
  return requestedURL;
2407
3005
  }
2408
3006
 
2409
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/mergeConfig.js
3007
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/mergeConfig.js
2410
3008
  var headersToObject = (thing) => thing instanceof AxiosHeaders_default ? __spreadValues({}, thing) : thing;
2411
3009
  function mergeConfig(config1, config2) {
2412
3010
  config2 = config2 || {};
@@ -2486,7 +3084,7 @@ var TagadaTrackerBundle = (() => {
2486
3084
  return config;
2487
3085
  }
2488
3086
 
2489
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/resolveConfig.js
3087
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/resolveConfig.js
2490
3088
  var resolveConfig_default = (config) => {
2491
3089
  const newConfig = mergeConfig({}, config);
2492
3090
  let { data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth } = newConfig;
@@ -2523,7 +3121,7 @@ var TagadaTrackerBundle = (() => {
2523
3121
  return newConfig;
2524
3122
  };
2525
3123
 
2526
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/adapters/xhr.js
3124
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/adapters/xhr.js
2527
3125
  var isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined";
2528
3126
  var xhr_default = isXHRAdapterSupported && function(config) {
2529
3127
  return new Promise(function dispatchXhrRequest(resolve, reject) {
@@ -2653,7 +3251,7 @@ var TagadaTrackerBundle = (() => {
2653
3251
  });
2654
3252
  };
2655
3253
 
2656
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/composeSignals.js
3254
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/composeSignals.js
2657
3255
  var composeSignals = (signals, timeout) => {
2658
3256
  const { length } = signals = signals ? signals.filter(Boolean) : [];
2659
3257
  if (timeout || length) {
@@ -2689,7 +3287,7 @@ var TagadaTrackerBundle = (() => {
2689
3287
  };
2690
3288
  var composeSignals_default = composeSignals;
2691
3289
 
2692
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/trackStream.js
3290
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/trackStream.js
2693
3291
  var streamChunk = function* (chunk, chunkSize) {
2694
3292
  let len = chunk.byteLength;
2695
3293
  if (!chunkSize || len < chunkSize) {
@@ -2782,7 +3380,7 @@ var TagadaTrackerBundle = (() => {
2782
3380
  });
2783
3381
  };
2784
3382
 
2785
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/adapters/fetch.js
3383
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/adapters/fetch.js
2786
3384
  var DEFAULT_CHUNK_SIZE = 64 * 1024;
2787
3385
  var { isFunction: isFunction2 } = utils_default;
2788
3386
  var globalFetchAPI = (({ Request, Response }) => ({
@@ -2990,7 +3588,7 @@ var TagadaTrackerBundle = (() => {
2990
3588
  };
2991
3589
  var adapter = getFetch();
2992
3590
 
2993
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/adapters/adapters.js
3591
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/adapters/adapters.js
2994
3592
  var knownAdapters = {
2995
3593
  http: null_default,
2996
3594
  xhr: xhr_default,
@@ -3055,7 +3653,7 @@ var TagadaTrackerBundle = (() => {
3055
3653
  adapters: knownAdapters
3056
3654
  };
3057
3655
 
3058
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/dispatchRequest.js
3656
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/dispatchRequest.js
3059
3657
  function throwIfCancellationRequested(config) {
3060
3658
  if (config.cancelToken) {
3061
3659
  config.cancelToken.throwIfRequested();
@@ -3100,10 +3698,10 @@ var TagadaTrackerBundle = (() => {
3100
3698
  });
3101
3699
  }
3102
3700
 
3103
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/env/data.js
3104
- var VERSION = "1.13.0";
3701
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/env/data.js
3702
+ var VERSION = "1.13.2";
3105
3703
 
3106
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/validator.js
3704
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/validator.js
3107
3705
  var validators = {};
3108
3706
  ["object", "boolean", "number", "function", "string", "symbol"].forEach((type, i) => {
3109
3707
  validators[type] = function validator(thing) {
@@ -3167,7 +3765,7 @@ var TagadaTrackerBundle = (() => {
3167
3765
  validators
3168
3766
  };
3169
3767
 
3170
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/core/Axios.js
3768
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/core/Axios.js
3171
3769
  var validators2 = validator_default.validators;
3172
3770
  var Axios = class {
3173
3771
  constructor(instanceConfig) {
@@ -3339,7 +3937,7 @@ var TagadaTrackerBundle = (() => {
3339
3937
  });
3340
3938
  var Axios_default = Axios;
3341
3939
 
3342
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/cancel/CancelToken.js
3940
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/cancel/CancelToken.js
3343
3941
  var CancelToken = class _CancelToken {
3344
3942
  constructor(executor) {
3345
3943
  if (typeof executor !== "function") {
@@ -3437,19 +4035,19 @@ var TagadaTrackerBundle = (() => {
3437
4035
  };
3438
4036
  var CancelToken_default = CancelToken;
3439
4037
 
3440
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/spread.js
4038
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/spread.js
3441
4039
  function spread(callback) {
3442
4040
  return function wrap(arr) {
3443
4041
  return callback.apply(null, arr);
3444
4042
  };
3445
4043
  }
3446
4044
 
3447
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/isAxiosError.js
4045
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/isAxiosError.js
3448
4046
  function isAxiosError(payload) {
3449
4047
  return utils_default.isObject(payload) && payload.isAxiosError === true;
3450
4048
  }
3451
4049
 
3452
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/helpers/HttpStatusCode.js
4050
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/helpers/HttpStatusCode.js
3453
4051
  var HttpStatusCode = {
3454
4052
  Continue: 100,
3455
4053
  SwitchingProtocols: 101,
@@ -3526,7 +4124,7 @@ var TagadaTrackerBundle = (() => {
3526
4124
  });
3527
4125
  var HttpStatusCode_default = HttpStatusCode;
3528
4126
 
3529
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/lib/axios.js
4127
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/lib/axios.js
3530
4128
  function createInstance(defaultConfig) {
3531
4129
  const context = new Axios_default(defaultConfig);
3532
4130
  const instance = bind(Axios_default.prototype.request, context);
@@ -3559,7 +4157,7 @@ var TagadaTrackerBundle = (() => {
3559
4157
  axios.default = axios;
3560
4158
  var axios_default = axios;
3561
4159
 
3562
- // ../../node_modules/.pnpm/axios@1.13.0/node_modules/axios/index.js
4160
+ // ../../node_modules/.pnpm/axios@1.13.2/node_modules/axios/index.js
3563
4161
  var {
3564
4162
  Axios: Axios2,
3565
4163
  AxiosError: AxiosError2,
@@ -3592,7 +4190,8 @@ var TagadaTrackerBundle = (() => {
3592
4190
  this.MAX_REQUESTS = 30;
3593
4191
  this.axios = axios_default.create({
3594
4192
  baseURL: config.baseURL,
3595
- timeout: config.timeout || 3e4,
4193
+ timeout: config.timeout || 6e4,
4194
+ // 60 seconds for payment operations
3596
4195
  headers: __spreadValues({
3597
4196
  "Content-Type": "application/json"
3598
4197
  }, config.headers)
@@ -7108,6 +7707,9 @@ var TagadaTrackerBundle = (() => {
7108
7707
  }
7109
7708
  };
7110
7709
 
7710
+ // src/v2/core/client.ts
7711
+ init_eventDispatcher();
7712
+
7111
7713
  // src/v2/core/utils/jwtDecoder.ts
7112
7714
  function decodeJWTClient(token) {
7113
7715
  try {
@@ -7156,6 +7758,9 @@ var TagadaTrackerBundle = (() => {
7156
7758
  }
7157
7759
  }
7158
7760
 
7761
+ // src/v2/core/utils/pluginConfig.ts
7762
+ init_environment();
7763
+
7159
7764
  // src/v2/core/utils/env.ts
7160
7765
  var import_meta = {};
7161
7766
  var DEFAULT_PREFIXES = ["", "VITE_", "REACT_APP_", "NEXT_PUBLIC_"];
@@ -7250,14 +7855,34 @@ var TagadaTrackerBundle = (() => {
7250
7855
  if (!isLocalEnvironment(true)) {
7251
7856
  return null;
7252
7857
  }
7253
- console.log("\u{1F6E0}\uFE0F [V2] Attempting to load /config/resources.static.json...");
7858
+ try {
7859
+ console.log("\u{1F6E0}\uFE0F [V2] Attempting to load /config/funnel.local.json...");
7860
+ const funnelResponse = await fetch("/config/funnel.local.json");
7861
+ if (funnelResponse.ok) {
7862
+ const funnelConfig = await funnelResponse.json();
7863
+ console.log("\u{1F6E0}\uFE0F [V2] \u2705 Loaded local funnel config (NEW format):", funnelConfig);
7864
+ const { loadLocalFunnelConfig: loadLocalFunnelConfig2 } = await Promise.resolve().then(() => (init_funnelClient(), funnelClient_exports));
7865
+ await loadLocalFunnelConfig2();
7866
+ if (funnelConfig.staticResources) {
7867
+ const transformed = {};
7868
+ for (const [key, value] of Object.entries(funnelConfig.staticResources)) {
7869
+ transformed[key] = { id: value };
7870
+ }
7871
+ return transformed;
7872
+ }
7873
+ return null;
7874
+ }
7875
+ } catch (e) {
7876
+ console.log("\u{1F6E0}\uFE0F [V2] funnel.local.json not found, trying legacy format...");
7877
+ }
7878
+ console.log("\u{1F6E0}\uFE0F [V2] Attempting to load /config/resources.static.json (legacy)...");
7254
7879
  const response = await fetch("/config/resources.static.json");
7255
7880
  if (!response.ok) {
7256
- console.log("\u{1F6E0}\uFE0F [V2] resources.static.json not found or failed to load");
7881
+ console.log("\u{1F6E0}\uFE0F [V2] No local static resources found");
7257
7882
  return null;
7258
7883
  }
7259
7884
  const staticResources = await response.json();
7260
- console.log("\u{1F6E0}\uFE0F [V2] \u2705 Loaded local static resources:", staticResources);
7885
+ console.log("\u{1F6E0}\uFE0F [V2] \u2705 Loaded legacy static resources:", staticResources);
7261
7886
  return staticResources;
7262
7887
  } catch (error) {
7263
7888
  console.error("\u{1F6E0}\uFE0F [V2] \u274C Error loading static resources:", error);
@@ -7265,6 +7890,7 @@ var TagadaTrackerBundle = (() => {
7265
7890
  }
7266
7891
  };
7267
7892
  var getMetaContent = (name) => {
7893
+ if (typeof document === "undefined") return void 0;
7268
7894
  const metaTag = document.querySelector('meta[name="'.concat(name, '"]'));
7269
7895
  return (metaTag == null ? void 0 : metaTag.getAttribute("content")) || void 0;
7270
7896
  };
@@ -7418,7 +8044,12 @@ var TagadaTrackerBundle = (() => {
7418
8044
  }
7419
8045
  }
7420
8046
 
8047
+ // src/v2/core/client.ts
8048
+ init_previewMode();
8049
+ init_tokenStorage();
8050
+
7421
8051
  // src/v2/core/utils/authHandoff.ts
8052
+ init_tokenStorage();
7422
8053
  var resolutionCache = /* @__PURE__ */ new Map();
7423
8054
  var resolvedCodes = /* @__PURE__ */ new Set();
7424
8055
  function getAuthCode() {
@@ -7803,9 +8434,16 @@ var TagadaTrackerBundle = (() => {
7803
8434
  * Normal token initialization flow (no cross-domain handoff)
7804
8435
  */
7805
8436
  async fallbackToNormalFlow() {
7806
- const existingToken = getClientToken();
7807
8437
  const urlParams = new URLSearchParams(typeof window !== "undefined" ? window.location.search : "");
7808
8438
  const queryToken = urlParams.get("token");
8439
+ if (queryToken) {
8440
+ if (this.state.debugMode) {
8441
+ console.log("[TagadaClient ".concat(this.instanceId, "] \u{1F512} URL token detected, setting immediately to prevent race condition"));
8442
+ }
8443
+ this.apiClient.updateToken(queryToken);
8444
+ setClientToken(queryToken);
8445
+ }
8446
+ const existingToken = getClientToken();
7809
8447
  console.log("[TagadaClient ".concat(this.instanceId, "] Initializing token (normal flow)..."), {
7810
8448
  hasExistingToken: !!existingToken,
7811
8449
  hasQueryToken: !!queryToken,
@@ -7880,6 +8518,23 @@ var TagadaTrackerBundle = (() => {
7880
8518
  * Create anonymous token
7881
8519
  */
7882
8520
  async createAnonymousToken(storeId) {
8521
+ if (typeof window !== "undefined") {
8522
+ const urlParams = new URLSearchParams(window.location.search);
8523
+ const urlToken = urlParams.get("token");
8524
+ if (urlToken) {
8525
+ if (this.state.debugMode) {
8526
+ console.log("[TagadaClient ".concat(this.instanceId, "] \u{1F512} URL has token, skipping anonymous token creation"));
8527
+ }
8528
+ this.setToken(urlToken);
8529
+ setClientToken(urlToken);
8530
+ const decodedSession = decodeJWTClient(urlToken);
8531
+ if (decodedSession) {
8532
+ this.updateState({ session: decodedSession });
8533
+ await this.initializeSession(decodedSession);
8534
+ }
8535
+ return;
8536
+ }
8537
+ }
7883
8538
  if (this.isInitializingSession) {
7884
8539
  if (this.state.debugMode) {
7885
8540
  console.log("[TagadaClient ".concat(this.instanceId, "] Session initialization in progress, skipping anonymous token creation"));
@@ -8362,12 +9017,19 @@ var TagadaTrackerBundle = (() => {
8362
9017
  }
8363
9018
  };
8364
9019
 
9020
+ // src/v2/standalone/index.ts
9021
+ init_funnel();
9022
+
9023
+ // src/v2/core/utils/index.ts
9024
+ init_sessionStorage();
9025
+
8365
9026
  // src/v2/standalone/index.ts
8366
9027
  function createTagadaClient(config = {}) {
8367
9028
  return new TagadaClient(config);
8368
9029
  }
8369
9030
 
8370
9031
  // src/v2/standalone/external-tracker.ts
9032
+ init_tokenStorage();
8371
9033
  function getUrlParam(name) {
8372
9034
  if (typeof window === "undefined") return null;
8373
9035
  const params = new URLSearchParams(window.location.search);
@@ -8458,14 +9120,19 @@ var TagadaTrackerBundle = (() => {
8458
9120
  throw new Error("Tracker not initialized. Call init() first.");
8459
9121
  }
8460
9122
  log(this.config.debug, "\u{1F680} Navigating:", options);
9123
+ const shouldAutoRedirect = options.autoRedirect !== false;
8461
9124
  try {
8462
- const result = await this.client.funnel.navigate({
8463
- type: options.eventType,
8464
- data: options.eventData || {}
8465
- });
9125
+ const result = await this.client.funnel.navigate(
9126
+ {
9127
+ type: options.eventType,
9128
+ data: options.eventData || {}
9129
+ },
9130
+ { autoRedirect: false }
9131
+ // Always disable SDK auto-redirect, we handle it here
9132
+ );
8466
9133
  if (result == null ? void 0 : result.url) {
8467
9134
  log(this.config.debug, "\u2705 Navigation result:", result.url);
8468
- if (typeof window !== "undefined") {
9135
+ if (shouldAutoRedirect && typeof window !== "undefined") {
8469
9136
  window.location.href = options.returnUrl || result.url;
8470
9137
  }
8471
9138
  return { url: result.url };