@aranova/tracking-next 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -56,6 +56,7 @@ __export(src_exports, {
56
56
  parsePhone: () => parsePhone,
57
57
  phoneField: () => phoneField,
58
58
  resetConsent: () => resetConsent,
59
+ resolveConversionConfig: () => resolveConversionConfig,
59
60
  saleCreateSchema: () => saleCreateSchema,
60
61
  saleItemSchema: () => saleItemSchema,
61
62
  saleServiceSchema: () => saleServiceSchema,
@@ -76,6 +77,13 @@ module.exports = __toCommonJS(src_exports);
76
77
  // ../tracking-core/src/consent.ts
77
78
  var CONSENT_STATE_KEY = "consent_state";
78
79
  var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
80
+ var grantedListeners = /* @__PURE__ */ new Set();
81
+ function onConsentGranted(listener) {
82
+ grantedListeners.add(listener);
83
+ return () => {
84
+ grantedListeners.delete(listener);
85
+ };
86
+ }
79
87
  function buildConsentPayload(state) {
80
88
  return {
81
89
  ad_storage: state,
@@ -104,6 +112,14 @@ function setConsentState(state) {
104
112
  window.gtag("consent", "update", buildConsentPayload(state));
105
113
  if (typeof window.fbq === "function")
106
114
  window.fbq("consent", state === "granted" ? "grant" : "revoke");
115
+ if (state === "granted") {
116
+ for (const listener of grantedListeners) {
117
+ try {
118
+ listener();
119
+ } catch {
120
+ }
121
+ }
122
+ }
107
123
  }
108
124
  function resetConsent() {
109
125
  if (typeof window === "undefined") return;
@@ -260,6 +276,24 @@ try {
260
276
  } catch (e) {}
261
277
  `.trim();
262
278
  }
279
+ var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
280
+ function isValidSendTo(sendTo) {
281
+ return SEND_TO_RE.test(sendTo);
282
+ }
283
+ function fireGtagConversion(input) {
284
+ if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
285
+ if (!isValidSendTo(input.sendTo)) return false;
286
+ const params = { send_to: input.sendTo };
287
+ if (input.value != null) params.value = input.value;
288
+ if (input.currency) params.currency = input.currency;
289
+ if (input.transactionId) params.transaction_id = input.transactionId;
290
+ try {
291
+ window.gtag("event", "conversion", params);
292
+ return true;
293
+ } catch {
294
+ return false;
295
+ }
296
+ }
263
297
  function createGtagInitScriptMulti(gtagIds) {
264
298
  const safeIds = gtagIds.filter(isValidGtagId);
265
299
  const configs = safeIds.map((id) => `gtag('config', '${id}');`).join("\n");
@@ -388,6 +422,289 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
388
422
  };
389
423
  }
390
424
 
425
+ // ../tracking-core/src/resources/conversion-firing.ts
426
+ var DEDUP_PREFIX = "_aranova_conv_";
427
+ var MAX_PENDING = 100;
428
+ var pendingQueue = [];
429
+ function dedupKey(input) {
430
+ return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
431
+ }
432
+ function alreadyFired(input) {
433
+ if (!input.transactionId || typeof window === "undefined") return false;
434
+ try {
435
+ return window.sessionStorage.getItem(dedupKey(input)) !== null;
436
+ } catch {
437
+ return false;
438
+ }
439
+ }
440
+ function markFired(input) {
441
+ if (!input.transactionId || typeof window === "undefined") return;
442
+ try {
443
+ window.sessionStorage.setItem(dedupKey(input), "1");
444
+ } catch {
445
+ }
446
+ }
447
+ function fireOnce(input) {
448
+ if (alreadyFired(input)) return;
449
+ if (fireGtagConversion(input)) markFired(input);
450
+ }
451
+ function fireConversionWithConsent(input) {
452
+ const state = getConsentState();
453
+ if (state === "denied") return;
454
+ if (state === "pending") {
455
+ if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
456
+ pendingQueue.push(input);
457
+ return;
458
+ }
459
+ fireOnce(input);
460
+ }
461
+ function flushPendingConversions() {
462
+ if (getConsentState() !== "granted") return;
463
+ while (pendingQueue.length > 0) {
464
+ const input = pendingQueue.shift();
465
+ if (input) fireOnce(input);
466
+ }
467
+ }
468
+ if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
469
+
470
+ // ../tracking-core/src/resources/conversion-config.ts
471
+ function isStringMap(value) {
472
+ return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
473
+ }
474
+ function parseFiring(value) {
475
+ if (!value || typeof value !== "object") return null;
476
+ const f = value;
477
+ if (typeof f.send_to !== "string") return null;
478
+ return {
479
+ send_to: f.send_to,
480
+ value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
481
+ currency: typeof f.currency === "string" ? f.currency : null
482
+ };
483
+ }
484
+ function parseTrigger(value) {
485
+ if (!value || typeof value !== "object") return null;
486
+ const t = value;
487
+ if (typeof t.event_type !== "string") return null;
488
+ const spec = { event_type: t.event_type };
489
+ if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
490
+ if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
491
+ if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
492
+ if (typeof t.page_name === "string") spec.page_name = t.page_name;
493
+ return spec;
494
+ }
495
+ function parseConversionConfig(raw) {
496
+ if (!raw || typeof raw !== "object") return null;
497
+ const obj = raw;
498
+ const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
499
+ const services = servicesRaw.flatMap((entry) => {
500
+ if (!entry || typeof entry !== "object") return [];
501
+ const s = entry;
502
+ if (typeof s.key !== "string") return [];
503
+ return [
504
+ {
505
+ key: s.key,
506
+ label: typeof s.label === "string" ? s.label : void 0,
507
+ firing: parseFiring(s.firing)
508
+ }
509
+ ];
510
+ });
511
+ const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
512
+ const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
513
+ if (!entry || typeof entry !== "object") return [];
514
+ const g = entry;
515
+ if (typeof g.key !== "string") return [];
516
+ return [
517
+ {
518
+ key: g.key,
519
+ label: typeof g.label === "string" ? g.label : void 0,
520
+ kind: g.kind === "event" ? "event" : "sale",
521
+ trigger: parseTrigger(g.trigger),
522
+ firing: parseFiring(g.firing)
523
+ }
524
+ ];
525
+ }) : services.map((s) => ({
526
+ key: s.key,
527
+ label: s.label,
528
+ kind: "sale",
529
+ trigger: null,
530
+ firing: s.firing
531
+ }));
532
+ return {
533
+ schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
534
+ config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
535
+ business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
536
+ customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
537
+ environment: typeof obj.environment === "string" ? obj.environment : void 0,
538
+ gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
539
+ meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
540
+ services,
541
+ goals
542
+ };
543
+ }
544
+ var CACHE_PREFIX = "_aranova_cfg_";
545
+ function cacheKey(url) {
546
+ return `${CACHE_PREFIX}${url}`;
547
+ }
548
+ function readCache(url) {
549
+ if (typeof window === "undefined") return null;
550
+ try {
551
+ const raw = window.sessionStorage.getItem(cacheKey(url));
552
+ if (!raw) return null;
553
+ const parsed = JSON.parse(raw);
554
+ const config = parseConversionConfig(parsed.config);
555
+ if (!config) return null;
556
+ return {
557
+ etag: typeof parsed.etag === "string" ? parsed.etag : null,
558
+ config
559
+ };
560
+ } catch {
561
+ return null;
562
+ }
563
+ }
564
+ function writeCache(url, entry) {
565
+ if (typeof window === "undefined") return;
566
+ try {
567
+ window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
568
+ } catch {
569
+ }
570
+ }
571
+ function resolveConversionConfig(options) {
572
+ const cached = readCache(options.cdnUrl);
573
+ let current = cached?.config ?? options.baked ?? null;
574
+ let etag = cached?.etag ?? null;
575
+ const goalsByKey = /* @__PURE__ */ new Map();
576
+ function rebuildIndex() {
577
+ goalsByKey.clear();
578
+ for (const goal of current?.goals ?? []) {
579
+ goalsByKey.set(goal.key, goal);
580
+ }
581
+ }
582
+ function adopt(next, nextEtag) {
583
+ if (!next) return;
584
+ if (current && next.config_version <= current.config_version) return;
585
+ current = next;
586
+ etag = nextEtag;
587
+ rebuildIndex();
588
+ writeCache(options.cdnUrl, { etag, config: next });
589
+ }
590
+ async function revalidate() {
591
+ if (typeof window === "undefined") return;
592
+ try {
593
+ const doFetch = options.fetchImpl ?? globalThis.fetch;
594
+ if (!doFetch) return;
595
+ const headers = {};
596
+ if (etag) headers["If-None-Match"] = etag;
597
+ const response = await doFetch(options.cdnUrl, {
598
+ method: "GET",
599
+ headers
600
+ });
601
+ if (response.status === 304 || !response.ok) return;
602
+ adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
603
+ } catch {
604
+ }
605
+ }
606
+ rebuildIndex();
607
+ void revalidate();
608
+ return {
609
+ getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
610
+ getGoal: (key) => goalsByKey.get(key) ?? null,
611
+ listGoals: () => [...goalsByKey.values()],
612
+ current: () => current,
613
+ revalidate
614
+ };
615
+ }
616
+
617
+ // ../tracking-core/src/resources/sales/money.ts
618
+ var MINOR_UNIT_EXPONENT = {
619
+ USD: 2,
620
+ CAD: 2
621
+ };
622
+ function exponentFor(currency) {
623
+ return MINOR_UNIT_EXPONENT[currency] ?? 2;
624
+ }
625
+ function toMinor(amount, currency) {
626
+ return Math.round(amount * 10 ** exponentFor(currency));
627
+ }
628
+ function fromMinor(cents, currency) {
629
+ return cents / 10 ** exponentFor(currency);
630
+ }
631
+ function formatMoney(cents, currency, locale) {
632
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
633
+ fromMinor(cents, currency)
634
+ );
635
+ }
636
+ function formatDateInTz(iso, timeZone, opts, locale) {
637
+ const date = new Date(iso);
638
+ if (Number.isNaN(date.getTime())) return iso;
639
+ return new Intl.DateTimeFormat(locale, {
640
+ year: "numeric",
641
+ month: "short",
642
+ day: "2-digit",
643
+ hour: "2-digit",
644
+ minute: "2-digit",
645
+ ...opts,
646
+ timeZone
647
+ }).format(date);
648
+ }
649
+
650
+ // ../tracking-core/src/resources/conversion-autofire.ts
651
+ function thresholdMet(goal, eventType, metadata) {
652
+ const t = goal.trigger;
653
+ if (!t || t.event_type !== eventType) return false;
654
+ switch (eventType) {
655
+ case "scroll_depth":
656
+ return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
657
+ case "time_on_site":
658
+ return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
659
+ case "multi_page_session":
660
+ return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
661
+ case "specific_page_visit":
662
+ return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
663
+ case "page_view":
664
+ case "form_start":
665
+ return true;
666
+ // no threshold — fire whenever the detector emits
667
+ default:
668
+ return false;
669
+ }
670
+ }
671
+ function currentPath() {
672
+ return typeof window === "undefined" ? "" : window.location.pathname;
673
+ }
674
+ function createConversionAutoFire(store) {
675
+ return {
676
+ onAutomaticEvent(eventType, metadata) {
677
+ for (const goal of store.listGoals()) {
678
+ if (goal.kind !== "event" || !goal.firing) continue;
679
+ if (!thresholdMet(goal, eventType, metadata)) continue;
680
+ const firing = goal.firing;
681
+ const cents = firing.value_cents ?? null;
682
+ const currency = firing.currency ?? null;
683
+ fireConversionWithConsent({
684
+ sendTo: firing.send_to,
685
+ value: cents != null && currency ? fromMinor(cents, currency) : null,
686
+ currency,
687
+ // Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
688
+ // shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
689
+ transactionId: `auto:${goal.key}:${currentPath()}`
690
+ });
691
+ }
692
+ }
693
+ };
694
+ }
695
+ function withConversionAutoFire(client, autoFire) {
696
+ return {
697
+ ...client,
698
+ trackEvent: (input) => {
699
+ client.trackEvent(input);
700
+ try {
701
+ autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
702
+ } catch {
703
+ }
704
+ }
705
+ };
706
+ }
707
+
391
708
  // ../tracking-core/src/session.ts
392
709
  var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
393
710
  var SESSION_STORAGE_KEY = "aranova_tracking_session";
@@ -1124,7 +1441,7 @@ function attachScrollDepth(client, config) {
1124
1441
  }
1125
1442
  const thresholds = new Set(config.thresholds);
1126
1443
  let firedForPath = /* @__PURE__ */ new Set();
1127
- let currentPath = window.location.pathname;
1444
+ let currentPath2 = window.location.pathname;
1128
1445
  let rafId = null;
1129
1446
  function getScrollPercent() {
1130
1447
  const doc = document.documentElement;
@@ -1143,7 +1460,7 @@ function attachScrollDepth(client, config) {
1143
1460
  eventType: "scroll_depth",
1144
1461
  metadata: {
1145
1462
  depth_percent: threshold,
1146
- page: { path: currentPath }
1463
+ page: { path: currentPath2 }
1147
1464
  },
1148
1465
  pageUrl: window.location.href,
1149
1466
  occurredAt: null
@@ -1160,8 +1477,8 @@ function attachScrollDepth(client, config) {
1160
1477
  }
1161
1478
  function resetIfPathChanged() {
1162
1479
  const newPath = window.location.pathname;
1163
- if (newPath === currentPath) return;
1164
- currentPath = newPath;
1480
+ if (newPath === currentPath2) return;
1481
+ currentPath2 = newPath;
1165
1482
  firedForPath = /* @__PURE__ */ new Set();
1166
1483
  setTimeout(checkThresholds, 0);
1167
1484
  }
@@ -1197,7 +1514,7 @@ function attachFormStart(client, config) {
1197
1514
  }
1198
1515
  const selector = config.selector ?? "form";
1199
1516
  let firedForms = /* @__PURE__ */ new Set();
1200
- let currentPath = window.location.pathname;
1517
+ let currentPath2 = window.location.pathname;
1201
1518
  function getFormKey(form) {
1202
1519
  if (form.id) return `id:${form.id}`;
1203
1520
  const explicitAction = form.getAttribute("action");
@@ -1228,8 +1545,8 @@ function attachFormStart(client, config) {
1228
1545
  }
1229
1546
  function resetIfPathChanged() {
1230
1547
  const newPath = window.location.pathname;
1231
- if (newPath === currentPath) return;
1232
- currentPath = newPath;
1548
+ if (newPath === currentPath2) return;
1549
+ currentPath2 = newPath;
1233
1550
  firedForms = /* @__PURE__ */ new Set();
1234
1551
  }
1235
1552
  const originalPushState = history.pushState.bind(history);
@@ -1308,21 +1625,64 @@ async function salesRequest(config, method, path, body) {
1308
1625
  }
1309
1626
 
1310
1627
  // ../tracking-core/src/resources/sales/client.ts
1628
+ function fireRecordedConversions(firing, input, recorded, sale, currency) {
1629
+ if (!firing) return;
1630
+ const txnBase = input.external_id ?? sale.id;
1631
+ for (const item of recorded) {
1632
+ if (!item.service) continue;
1633
+ const config = firing.getFiring(item.service);
1634
+ if (!config) continue;
1635
+ const cents = item.amount_cents ?? config.value_cents ?? null;
1636
+ fireConversionWithConsent({
1637
+ sendTo: config.send_to,
1638
+ value: cents != null ? fromMinor(cents, currency) : null,
1639
+ currency: config.currency ?? currency,
1640
+ transactionId: `${txnBase}:${item.service}`
1641
+ });
1642
+ }
1643
+ }
1311
1644
  function createSalesClient(config) {
1312
- return {
1313
- async record(input) {
1314
- const currency = input.currency ?? config.defaultCurrency;
1315
- if (!currency) {
1316
- throw new Error(
1317
- "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1318
- );
1645
+ async function record(input) {
1646
+ const currency = input.currency ?? config.defaultCurrency;
1647
+ if (!currency) {
1648
+ throw new Error(
1649
+ "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1650
+ );
1651
+ }
1652
+ const body = {
1653
+ ...input,
1654
+ currency,
1655
+ occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1656
+ };
1657
+ const sale = await salesRequest(config, "POST", "/sales", body);
1658
+ const recorded = input.services?.length ? input.services.map((s) => ({
1659
+ service: s.service,
1660
+ amount_cents: s.amount_cents
1661
+ })) : [
1662
+ {
1663
+ service: input.service,
1664
+ amount_cents: input.amount_total_cents ?? null
1319
1665
  }
1320
- const body = {
1321
- ...input,
1666
+ ];
1667
+ fireRecordedConversions(config.firing, input, recorded, sale, currency);
1668
+ return sale;
1669
+ }
1670
+ return {
1671
+ record,
1672
+ // recordSale is the intent-revealing alias — same behavior, clearer call site.
1673
+ recordSale: record,
1674
+ trackConversion(key, options) {
1675
+ const firing = config.firing?.getFiring(key);
1676
+ if (!firing) return;
1677
+ const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
1678
+ const cents = firing.value_cents ?? null;
1679
+ const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
1680
+ fireConversionWithConsent({
1681
+ sendTo: firing.send_to,
1682
+ value,
1322
1683
  currency,
1323
- occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1324
- };
1325
- return salesRequest(config, "POST", "/sales", body);
1684
+ transactionId: options?.transactionId ?? null
1685
+ });
1326
1686
  },
1327
1687
  async list(query) {
1328
1688
  const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
@@ -1416,39 +1776,6 @@ function createSalesClient(config) {
1416
1776
  };
1417
1777
  }
1418
1778
 
1419
- // ../tracking-core/src/resources/sales/money.ts
1420
- var MINOR_UNIT_EXPONENT = {
1421
- USD: 2,
1422
- CAD: 2
1423
- };
1424
- function exponentFor(currency) {
1425
- return MINOR_UNIT_EXPONENT[currency] ?? 2;
1426
- }
1427
- function toMinor(amount, currency) {
1428
- return Math.round(amount * 10 ** exponentFor(currency));
1429
- }
1430
- function fromMinor(cents, currency) {
1431
- return cents / 10 ** exponentFor(currency);
1432
- }
1433
- function formatMoney(cents, currency, locale) {
1434
- return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
1435
- fromMinor(cents, currency)
1436
- );
1437
- }
1438
- function formatDateInTz(iso, timeZone, opts, locale) {
1439
- const date = new Date(iso);
1440
- if (Number.isNaN(date.getTime())) return iso;
1441
- return new Intl.DateTimeFormat(locale, {
1442
- year: "numeric",
1443
- month: "short",
1444
- day: "2-digit",
1445
- hour: "2-digit",
1446
- minute: "2-digit",
1447
- ...opts,
1448
- timeZone
1449
- }).format(date);
1450
- }
1451
-
1452
1779
  // ../tracking-core/src/resources/sales/schema.ts
1453
1780
  var import_zod11 = require("zod");
1454
1781
  var SUPPORTED_CURRENCIES = ["USD", "CAD"];
@@ -1913,7 +2240,7 @@ function GoogleAdsTracking(props) {
1913
2240
  var import_navigation = require("next/navigation");
1914
2241
 
1915
2242
  // package.json
1916
- var version = "0.13.0";
2243
+ var version = "0.14.0";
1917
2244
 
1918
2245
  // src/factory.tsx
1919
2246
  var import_react4 = require("react");
@@ -2007,7 +2334,7 @@ var PhoneField = (0, import_react3.forwardRef)(function PhoneField2({ country, v
2007
2334
  // src/factory.tsx
2008
2335
  var import_jsx_runtime5 = require("react/jsx-runtime");
2009
2336
  function createTracking(options) {
2010
- const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone } = options;
2337
+ const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone, conversionConfig } = options;
2011
2338
  if (!apiKey || !endpoint) {
2012
2339
  if (apiKey || endpoint) {
2013
2340
  console.warn(
@@ -2051,6 +2378,17 @@ function createTracking(options) {
2051
2378
  ),
2052
2379
  []
2053
2380
  );
2381
+ const conversionStore = (0, import_react4.useMemo)(
2382
+ () => conversionConfig ? resolveConversionConfig({
2383
+ cdnUrl: conversionConfig.cdnUrl,
2384
+ baked: conversionConfig.baked
2385
+ }) : null,
2386
+ []
2387
+ );
2388
+ const wrapClient = (0, import_react4.useMemo)(() => {
2389
+ const autoFire = conversionStore ? createConversionAutoFire(conversionStore) : null;
2390
+ return (c) => autoFire ? withConversionAutoFire(c, autoFire) : c;
2391
+ }, [conversionStore]);
2054
2392
  (0, import_react4.useEffect)(() => {
2055
2393
  const rawClient = getOrCreateTrackingClient({
2056
2394
  apiKey,
@@ -2062,7 +2400,7 @@ function createTracking(options) {
2062
2400
  activeGtagIds: gtagIds,
2063
2401
  debug
2064
2402
  });
2065
- fireManualPageView(rawClient);
2403
+ fireManualPageView(wrapClient(rawClient));
2066
2404
  }, [pathname, searchParams]);
2067
2405
  const firedPagesRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
2068
2406
  (0, import_react4.useEffect)(() => {
@@ -2077,14 +2415,18 @@ function createTracking(options) {
2077
2415
  activeGtagIds: gtagIds,
2078
2416
  debug
2079
2417
  });
2418
+ const detectorClient = wrapClient(rawClient);
2080
2419
  for (const { name, pathPattern } of specificPageVisitConfig.pages) {
2081
2420
  if (!pathPattern.test(pathname)) continue;
2082
2421
  const key = `${name}:${pathname}`;
2083
2422
  if (firedPagesRef.current.has(key)) continue;
2084
2423
  firedPagesRef.current.add(key);
2085
- rawClient.trackEvent({
2424
+ detectorClient.trackEvent({
2086
2425
  eventType: "specific_page_visit",
2087
- metadata: { page_name: name, page: { path: pathname } },
2426
+ metadata: {
2427
+ page_name: name,
2428
+ page: { path: pathname }
2429
+ },
2088
2430
  pageUrl: null,
2089
2431
  occurredAt: null
2090
2432
  });
@@ -2101,7 +2443,7 @@ function createTracking(options) {
2101
2443
  activeGtagIds: gtagIds,
2102
2444
  debug
2103
2445
  });
2104
- return attachBfcacheRestore(rawClient);
2446
+ return attachBfcacheRestore(wrapClient(rawClient));
2105
2447
  }, []);
2106
2448
  (0, import_react4.useEffect)(() => {
2107
2449
  if (!timeOnSiteConfig) return;
@@ -2115,7 +2457,7 @@ function createTracking(options) {
2115
2457
  activeGtagIds: gtagIds,
2116
2458
  debug
2117
2459
  });
2118
- return attachTimeOnSite(rawClient, timeOnSiteConfig);
2460
+ return attachTimeOnSite(wrapClient(rawClient), timeOnSiteConfig);
2119
2461
  }, []);
2120
2462
  const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
2121
2463
  const mpsLastPathRef = (0, import_react4.useRef)(null);
@@ -2153,7 +2495,7 @@ function createTracking(options) {
2153
2495
  activeGtagIds: gtagIds,
2154
2496
  debug
2155
2497
  });
2156
- rawClient.trackEvent({
2498
+ wrapClient(rawClient).trackEvent({
2157
2499
  eventType: "multi_page_session",
2158
2500
  metadata: {
2159
2501
  page_count: paths.size,
@@ -2178,13 +2520,14 @@ function createTracking(options) {
2178
2520
  activeGtagIds: gtagIds,
2179
2521
  debug
2180
2522
  });
2523
+ const detectorClient = wrapClient(rawClient);
2181
2524
  const scrollDepth = triggers.automatic.scroll_depth;
2182
2525
  if (scrollDepth) {
2183
- detachers.push(attachScrollDepth(rawClient, scrollDepth));
2526
+ detachers.push(attachScrollDepth(detectorClient, scrollDepth));
2184
2527
  }
2185
2528
  const formStart = triggers.automatic.form_start;
2186
2529
  if (formStart) {
2187
- detachers.push(attachFormStart(rawClient, formStart));
2530
+ detachers.push(attachFormStart(detectorClient, formStart));
2188
2531
  }
2189
2532
  return () => {
2190
2533
  for (let i = detachers.length - 1; i >= 0; i--) {
@@ -2233,6 +2576,7 @@ function createTracking(options) {
2233
2576
  parsePhone,
2234
2577
  phoneField,
2235
2578
  resetConsent,
2579
+ resolveConversionConfig,
2236
2580
  saleCreateSchema,
2237
2581
  saleItemSchema,
2238
2582
  saleServiceSchema,