@aranova/tracking-react 0.13.0 → 0.14.1

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.mjs CHANGED
@@ -7,6 +7,13 @@ import { useCallback, useEffect, useState } from "react";
7
7
  // ../tracking-core/src/consent.ts
8
8
  var CONSENT_STATE_KEY = "consent_state";
9
9
  var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
10
+ var grantedListeners = /* @__PURE__ */ new Set();
11
+ function onConsentGranted(listener) {
12
+ grantedListeners.add(listener);
13
+ return () => {
14
+ grantedListeners.delete(listener);
15
+ };
16
+ }
10
17
  function buildConsentPayload(state) {
11
18
  return {
12
19
  ad_storage: state,
@@ -35,6 +42,14 @@ function setConsentState(state) {
35
42
  window.gtag("consent", "update", buildConsentPayload(state));
36
43
  if (typeof window.fbq === "function")
37
44
  window.fbq("consent", state === "granted" ? "grant" : "revoke");
45
+ if (state === "granted") {
46
+ for (const listener of grantedListeners) {
47
+ try {
48
+ listener();
49
+ } catch {
50
+ }
51
+ }
52
+ }
38
53
  }
39
54
  function resetConsent() {
40
55
  if (typeof window === "undefined") return;
@@ -165,11 +180,30 @@ function isValidGtagId(id) {
165
180
  function ensureGtagFunction() {
166
181
  window.dataLayer = window.dataLayer || [];
167
182
  if (typeof window.gtag === "function") return window.gtag;
168
- window.gtag = (...args) => {
169
- window.dataLayer?.push(args);
170
- };
183
+ function gtag() {
184
+ window.dataLayer?.push(arguments);
185
+ }
186
+ window.gtag = gtag;
171
187
  return window.gtag;
172
188
  }
189
+ var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
190
+ function isValidSendTo(sendTo) {
191
+ return SEND_TO_RE.test(sendTo);
192
+ }
193
+ function fireGtagConversion(input) {
194
+ if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
195
+ if (!isValidSendTo(input.sendTo)) return false;
196
+ const params = { send_to: input.sendTo };
197
+ if (input.value != null) params.value = input.value;
198
+ if (input.currency) params.currency = input.currency;
199
+ if (input.transactionId) params.transaction_id = input.transactionId;
200
+ try {
201
+ window.gtag("event", "conversion", params);
202
+ return true;
203
+ } catch {
204
+ return false;
205
+ }
206
+ }
173
207
  function applyDefaultConsentState() {
174
208
  const gtag = ensureGtagFunction();
175
209
  gtag("consent", "default", {
@@ -376,6 +410,329 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
376
410
  };
377
411
  }
378
412
 
413
+ // ../tracking-core/src/resources/conversion-firing.ts
414
+ var DEDUP_PREFIX = "_aranova_conv_";
415
+ var MAX_PENDING = 100;
416
+ var pendingQueue = [];
417
+ function dedupKey(input) {
418
+ return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
419
+ }
420
+ function alreadyFired(input) {
421
+ if (!input.transactionId || typeof window === "undefined") return false;
422
+ try {
423
+ return window.sessionStorage.getItem(dedupKey(input)) !== null;
424
+ } catch {
425
+ return false;
426
+ }
427
+ }
428
+ function markFired(input) {
429
+ if (!input.transactionId || typeof window === "undefined") return;
430
+ try {
431
+ window.sessionStorage.setItem(dedupKey(input), "1");
432
+ } catch {
433
+ }
434
+ }
435
+ function fireOnce(input) {
436
+ if (alreadyFired(input)) return;
437
+ if (fireGtagConversion(input)) markFired(input);
438
+ }
439
+ function fireConversionWithConsent(input) {
440
+ const state = getConsentState();
441
+ if (state === "denied") return;
442
+ if (state === "pending") {
443
+ if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
444
+ pendingQueue.push(input);
445
+ return;
446
+ }
447
+ fireOnce(input);
448
+ }
449
+ function flushPendingConversions() {
450
+ if (getConsentState() !== "granted") return;
451
+ while (pendingQueue.length > 0) {
452
+ const input = pendingQueue.shift();
453
+ if (input) fireOnce(input);
454
+ }
455
+ }
456
+ if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
457
+
458
+ // ../tracking-core/src/resources/conversion-config.ts
459
+ function isStringMap(value) {
460
+ return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
461
+ }
462
+ function parseFiring(value) {
463
+ if (!value || typeof value !== "object") return null;
464
+ const f = value;
465
+ if (typeof f.send_to !== "string") return null;
466
+ return {
467
+ send_to: f.send_to,
468
+ value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
469
+ currency: typeof f.currency === "string" ? f.currency : null
470
+ };
471
+ }
472
+ function parseTrigger(value) {
473
+ if (!value || typeof value !== "object") return null;
474
+ const t = value;
475
+ if (typeof t.event_type !== "string") return null;
476
+ const spec = { event_type: t.event_type };
477
+ if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
478
+ if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
479
+ if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
480
+ if (typeof t.page_name === "string") spec.page_name = t.page_name;
481
+ return spec;
482
+ }
483
+ function parseConversionConfig(raw) {
484
+ if (!raw || typeof raw !== "object") return null;
485
+ const obj = raw;
486
+ const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
487
+ const services = servicesRaw.flatMap((entry) => {
488
+ if (!entry || typeof entry !== "object") return [];
489
+ const s = entry;
490
+ if (typeof s.key !== "string") return [];
491
+ return [
492
+ {
493
+ key: s.key,
494
+ label: typeof s.label === "string" ? s.label : void 0,
495
+ firing: parseFiring(s.firing)
496
+ }
497
+ ];
498
+ });
499
+ const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
500
+ const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
501
+ if (!entry || typeof entry !== "object") return [];
502
+ const g = entry;
503
+ if (typeof g.key !== "string") return [];
504
+ return [
505
+ {
506
+ key: g.key,
507
+ label: typeof g.label === "string" ? g.label : void 0,
508
+ kind: g.kind === "event" ? "event" : "sale",
509
+ trigger: parseTrigger(g.trigger),
510
+ firing: parseFiring(g.firing)
511
+ }
512
+ ];
513
+ }) : services.map((s) => ({
514
+ key: s.key,
515
+ label: s.label,
516
+ kind: "sale",
517
+ trigger: null,
518
+ firing: s.firing
519
+ }));
520
+ return {
521
+ schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
522
+ config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
523
+ business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
524
+ customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
525
+ environment: typeof obj.environment === "string" ? obj.environment : void 0,
526
+ gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
527
+ meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
528
+ services,
529
+ goals
530
+ };
531
+ }
532
+ var CACHE_PREFIX = "_aranova_cfg_";
533
+ function cacheKey(url) {
534
+ return `${CACHE_PREFIX}${url}`;
535
+ }
536
+ function readCache(url) {
537
+ if (typeof window === "undefined") return null;
538
+ try {
539
+ const raw = window.sessionStorage.getItem(cacheKey(url));
540
+ if (!raw) return null;
541
+ const parsed = JSON.parse(raw);
542
+ const config = parseConversionConfig(parsed.config);
543
+ if (!config) return null;
544
+ return {
545
+ etag: typeof parsed.etag === "string" ? parsed.etag : null,
546
+ config
547
+ };
548
+ } catch {
549
+ return null;
550
+ }
551
+ }
552
+ function writeCache(url, entry) {
553
+ if (typeof window === "undefined") return;
554
+ try {
555
+ window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
556
+ } catch {
557
+ }
558
+ }
559
+ function resolveConversionConfig(options) {
560
+ const cached = readCache(options.cdnUrl);
561
+ let current = cached?.config ?? options.baked ?? null;
562
+ let etag = cached?.etag ?? null;
563
+ const goalsByKey = /* @__PURE__ */ new Map();
564
+ const resolveListeners = /* @__PURE__ */ new Set();
565
+ function rebuildIndex() {
566
+ goalsByKey.clear();
567
+ for (const goal of current?.goals ?? []) {
568
+ goalsByKey.set(goal.key, goal);
569
+ }
570
+ }
571
+ function notifyResolved() {
572
+ const listeners = [...resolveListeners];
573
+ resolveListeners.clear();
574
+ for (const listener of listeners) {
575
+ try {
576
+ listener();
577
+ } catch {
578
+ }
579
+ }
580
+ }
581
+ function adopt(next, nextEtag) {
582
+ if (!next) return;
583
+ if (current && next.config_version <= current.config_version) return;
584
+ const wasEmpty = current === null;
585
+ current = next;
586
+ etag = nextEtag;
587
+ rebuildIndex();
588
+ writeCache(options.cdnUrl, { etag, config: next });
589
+ if (wasEmpty) notifyResolved();
590
+ }
591
+ async function revalidate() {
592
+ if (typeof window === "undefined") return;
593
+ try {
594
+ const doFetch = options.fetchImpl ?? globalThis.fetch;
595
+ if (!doFetch) return;
596
+ const headers = {};
597
+ if (etag) headers["If-None-Match"] = etag;
598
+ const response = await doFetch(options.cdnUrl, {
599
+ method: "GET",
600
+ headers
601
+ });
602
+ if (response.status === 304 || !response.ok) return;
603
+ adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
604
+ } catch {
605
+ }
606
+ }
607
+ rebuildIndex();
608
+ void revalidate();
609
+ return {
610
+ getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
611
+ getGoal: (key) => goalsByKey.get(key) ?? null,
612
+ listGoals: () => [...goalsByKey.values()],
613
+ current: () => current,
614
+ isReady: () => current !== null,
615
+ onResolve: (listener) => {
616
+ if (current !== null) {
617
+ listener();
618
+ return () => {
619
+ };
620
+ }
621
+ resolveListeners.add(listener);
622
+ return () => resolveListeners.delete(listener);
623
+ },
624
+ revalidate
625
+ };
626
+ }
627
+
628
+ // ../tracking-core/src/resources/sales/money.ts
629
+ var MINOR_UNIT_EXPONENT = {
630
+ USD: 2,
631
+ CAD: 2
632
+ };
633
+ function exponentFor(currency) {
634
+ return MINOR_UNIT_EXPONENT[currency] ?? 2;
635
+ }
636
+ function toMinor(amount, currency) {
637
+ return Math.round(amount * 10 ** exponentFor(currency));
638
+ }
639
+ function fromMinor(cents, currency) {
640
+ return cents / 10 ** exponentFor(currency);
641
+ }
642
+ function formatMoney(cents, currency, locale) {
643
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
644
+ fromMinor(cents, currency)
645
+ );
646
+ }
647
+ function formatDateInTz(iso, timeZone, opts, locale) {
648
+ const date = new Date(iso);
649
+ if (Number.isNaN(date.getTime())) return iso;
650
+ return new Intl.DateTimeFormat(locale, {
651
+ year: "numeric",
652
+ month: "short",
653
+ day: "2-digit",
654
+ hour: "2-digit",
655
+ minute: "2-digit",
656
+ ...opts,
657
+ timeZone
658
+ }).format(date);
659
+ }
660
+
661
+ // ../tracking-core/src/resources/conversion-autofire.ts
662
+ function thresholdMet(goal, eventType, metadata) {
663
+ const t = goal.trigger;
664
+ if (!t || t.event_type !== eventType) return false;
665
+ switch (eventType) {
666
+ case "scroll_depth":
667
+ return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
668
+ case "time_on_site":
669
+ return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
670
+ case "multi_page_session":
671
+ return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
672
+ case "specific_page_visit":
673
+ return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
674
+ case "page_view":
675
+ case "form_start":
676
+ return true;
677
+ // no threshold — fire whenever the detector emits
678
+ default:
679
+ return false;
680
+ }
681
+ }
682
+ function currentPath() {
683
+ return typeof window === "undefined" ? "" : window.location.pathname;
684
+ }
685
+ var MAX_BUFFERED_EVENTS = 50;
686
+ function createConversionAutoFire(store) {
687
+ const pending = [];
688
+ let subscribed = false;
689
+ function fireMatching(eventType, metadata) {
690
+ for (const goal of store.listGoals()) {
691
+ if (goal.kind !== "event" || !goal.firing) continue;
692
+ if (!thresholdMet(goal, eventType, metadata)) continue;
693
+ const firing = goal.firing;
694
+ const cents = firing.value_cents ?? null;
695
+ const currency = firing.currency ?? null;
696
+ fireConversionWithConsent({
697
+ sendTo: firing.send_to,
698
+ value: cents != null && currency ? fromMinor(cents, currency) : null,
699
+ currency,
700
+ // Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
701
+ // shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
702
+ transactionId: `auto:${goal.key}:${currentPath()}`
703
+ });
704
+ }
705
+ }
706
+ return {
707
+ onAutomaticEvent(eventType, metadata) {
708
+ if (store.isReady()) {
709
+ fireMatching(eventType, metadata);
710
+ return;
711
+ }
712
+ if (pending.length < MAX_BUFFERED_EVENTS) pending.push({ eventType, metadata });
713
+ if (!subscribed) {
714
+ subscribed = true;
715
+ store.onResolve(() => {
716
+ const buffered = pending.splice(0);
717
+ for (const event of buffered) fireMatching(event.eventType, event.metadata);
718
+ });
719
+ }
720
+ }
721
+ };
722
+ }
723
+ function withConversionAutoFire(client, autoFire) {
724
+ return {
725
+ ...client,
726
+ trackEvent: (input) => {
727
+ client.trackEvent(input);
728
+ try {
729
+ autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
730
+ } catch {
731
+ }
732
+ }
733
+ };
734
+ }
735
+
379
736
  // ../tracking-core/src/session.ts
380
737
  var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
381
738
  var SESSION_STORAGE_KEY = "aranova_tracking_session";
@@ -1195,7 +1552,7 @@ function attachScrollDepth(client, config) {
1195
1552
  }
1196
1553
  const thresholds = new Set(config.thresholds);
1197
1554
  let firedForPath = /* @__PURE__ */ new Set();
1198
- let currentPath = window.location.pathname;
1555
+ let currentPath2 = window.location.pathname;
1199
1556
  let rafId = null;
1200
1557
  function getScrollPercent() {
1201
1558
  const doc = document.documentElement;
@@ -1214,7 +1571,7 @@ function attachScrollDepth(client, config) {
1214
1571
  eventType: "scroll_depth",
1215
1572
  metadata: {
1216
1573
  depth_percent: threshold,
1217
- page: { path: currentPath }
1574
+ page: { path: currentPath2 }
1218
1575
  },
1219
1576
  pageUrl: window.location.href,
1220
1577
  occurredAt: null
@@ -1231,8 +1588,8 @@ function attachScrollDepth(client, config) {
1231
1588
  }
1232
1589
  function resetIfPathChanged() {
1233
1590
  const newPath = window.location.pathname;
1234
- if (newPath === currentPath) return;
1235
- currentPath = newPath;
1591
+ if (newPath === currentPath2) return;
1592
+ currentPath2 = newPath;
1236
1593
  firedForPath = /* @__PURE__ */ new Set();
1237
1594
  setTimeout(checkThresholds, 0);
1238
1595
  }
@@ -1308,13 +1665,13 @@ function attachMultiPageSession(client, config) {
1308
1665
  return storage.getItem(FIRED_KEY) === "1";
1309
1666
  }
1310
1667
  function check() {
1311
- const currentPath = window.location.pathname;
1312
- if (currentPath === lastCheckedPath) return;
1313
- lastCheckedPath = currentPath;
1668
+ const currentPath2 = window.location.pathname;
1669
+ if (currentPath2 === lastCheckedPath) return;
1670
+ lastCheckedPath = currentPath2;
1314
1671
  resetIfSessionChanged();
1315
1672
  if (hasFired()) return;
1316
1673
  const paths = getDistinctPaths();
1317
- paths.add(currentPath);
1674
+ paths.add(currentPath2);
1318
1675
  saveDistinctPaths(paths);
1319
1676
  if (paths.size >= pageThreshold) {
1320
1677
  storage.setItem(FIRED_KEY, "1");
@@ -1358,7 +1715,7 @@ function attachFormStart(client, config) {
1358
1715
  }
1359
1716
  const selector = config.selector ?? "form";
1360
1717
  let firedForms = /* @__PURE__ */ new Set();
1361
- let currentPath = window.location.pathname;
1718
+ let currentPath2 = window.location.pathname;
1362
1719
  function getFormKey(form) {
1363
1720
  if (form.id) return `id:${form.id}`;
1364
1721
  const explicitAction = form.getAttribute("action");
@@ -1389,8 +1746,8 @@ function attachFormStart(client, config) {
1389
1746
  }
1390
1747
  function resetIfPathChanged() {
1391
1748
  const newPath = window.location.pathname;
1392
- if (newPath === currentPath) return;
1393
- currentPath = newPath;
1749
+ if (newPath === currentPath2) return;
1750
+ currentPath2 = newPath;
1394
1751
  firedForms = /* @__PURE__ */ new Set();
1395
1752
  }
1396
1753
  const originalPushState = history.pushState.bind(history);
@@ -1469,21 +1826,64 @@ async function salesRequest(config, method, path, body) {
1469
1826
  }
1470
1827
 
1471
1828
  // ../tracking-core/src/resources/sales/client.ts
1829
+ function fireRecordedConversions(firing, input, recorded, sale, currency) {
1830
+ if (!firing) return;
1831
+ const txnBase = input.external_id ?? sale.id;
1832
+ for (const item of recorded) {
1833
+ if (!item.service) continue;
1834
+ const config = firing.getFiring(item.service);
1835
+ if (!config) continue;
1836
+ const cents = item.amount_cents ?? config.value_cents ?? null;
1837
+ fireConversionWithConsent({
1838
+ sendTo: config.send_to,
1839
+ value: cents != null ? fromMinor(cents, currency) : null,
1840
+ currency: config.currency ?? currency,
1841
+ transactionId: `${txnBase}:${item.service}`
1842
+ });
1843
+ }
1844
+ }
1472
1845
  function createSalesClient(config) {
1473
- return {
1474
- async record(input) {
1475
- const currency = input.currency ?? config.defaultCurrency;
1476
- if (!currency) {
1477
- throw new Error(
1478
- "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1479
- );
1846
+ async function record(input) {
1847
+ const currency = input.currency ?? config.defaultCurrency;
1848
+ if (!currency) {
1849
+ throw new Error(
1850
+ "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1851
+ );
1852
+ }
1853
+ const body = {
1854
+ ...input,
1855
+ currency,
1856
+ occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1857
+ };
1858
+ const sale = await salesRequest(config, "POST", "/sales", body);
1859
+ const recorded = input.services?.length ? input.services.map((s) => ({
1860
+ service: s.service,
1861
+ amount_cents: s.amount_cents
1862
+ })) : [
1863
+ {
1864
+ service: input.service,
1865
+ amount_cents: input.amount_total_cents ?? null
1480
1866
  }
1481
- const body = {
1482
- ...input,
1867
+ ];
1868
+ fireRecordedConversions(config.firing, input, recorded, sale, currency);
1869
+ return sale;
1870
+ }
1871
+ return {
1872
+ record,
1873
+ // recordSale is the intent-revealing alias — same behavior, clearer call site.
1874
+ recordSale: record,
1875
+ trackConversion(key, options) {
1876
+ const firing = config.firing?.getFiring(key);
1877
+ if (!firing) return;
1878
+ const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
1879
+ const cents = firing.value_cents ?? null;
1880
+ const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
1881
+ fireConversionWithConsent({
1882
+ sendTo: firing.send_to,
1883
+ value,
1483
1884
  currency,
1484
- occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1485
- };
1486
- return salesRequest(config, "POST", "/sales", body);
1885
+ transactionId: options?.transactionId ?? null
1886
+ });
1487
1887
  },
1488
1888
  async list(query) {
1489
1889
  const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
@@ -1577,39 +1977,6 @@ function createSalesClient(config) {
1577
1977
  };
1578
1978
  }
1579
1979
 
1580
- // ../tracking-core/src/resources/sales/money.ts
1581
- var MINOR_UNIT_EXPONENT = {
1582
- USD: 2,
1583
- CAD: 2
1584
- };
1585
- function exponentFor(currency) {
1586
- return MINOR_UNIT_EXPONENT[currency] ?? 2;
1587
- }
1588
- function toMinor(amount, currency) {
1589
- return Math.round(amount * 10 ** exponentFor(currency));
1590
- }
1591
- function fromMinor(cents, currency) {
1592
- return cents / 10 ** exponentFor(currency);
1593
- }
1594
- function formatMoney(cents, currency, locale) {
1595
- return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
1596
- fromMinor(cents, currency)
1597
- );
1598
- }
1599
- function formatDateInTz(iso, timeZone, opts, locale) {
1600
- const date = new Date(iso);
1601
- if (Number.isNaN(date.getTime())) return iso;
1602
- return new Intl.DateTimeFormat(locale, {
1603
- year: "numeric",
1604
- month: "short",
1605
- day: "2-digit",
1606
- hour: "2-digit",
1607
- minute: "2-digit",
1608
- ...opts,
1609
- timeZone
1610
- }).format(date);
1611
- }
1612
-
1613
1980
  // ../tracking-core/src/resources/sales/schema.ts
1614
1981
  import { z as z11 } from "zod";
1615
1982
  var SUPPORTED_CURRENCIES = ["USD", "CAD"];
@@ -2057,7 +2424,7 @@ function GoogleAdsTracking(props) {
2057
2424
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
2058
2425
 
2059
2426
  // package.json
2060
- var version = "0.13.0";
2427
+ var version = "0.14.1";
2061
2428
 
2062
2429
  // ../tracking-core/src/phone-react.tsx
2063
2430
  import {
@@ -2163,7 +2530,7 @@ var NOOP_CLIENT = {
2163
2530
  getVisitorId: () => ""
2164
2531
  };
2165
2532
  function createTracking(options) {
2166
- const { apiKey, endpoint, triggers, environment, debug, phone } = options;
2533
+ const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
2167
2534
  if (!apiKey || !endpoint) {
2168
2535
  if (apiKey || endpoint) {
2169
2536
  console.warn(
@@ -2238,27 +2605,32 @@ function createTracking(options) {
2238
2605
  activeGtagIds: resolvedGtagIds,
2239
2606
  debug
2240
2607
  });
2241
- detachers.push(attachAutoPageView(rawClient));
2242
- detachers.push(attachBfcacheRestore(rawClient));
2608
+ const conversionStore = conversionConfig ? resolveConversionConfig({
2609
+ cdnUrl: conversionConfig.cdnUrl,
2610
+ baked: conversionConfig.baked
2611
+ }) : null;
2612
+ const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
2613
+ detachers.push(attachAutoPageView(detectorClient));
2614
+ detachers.push(attachBfcacheRestore(detectorClient));
2243
2615
  const timeOnSite = triggers.automatic.time_on_site;
2244
2616
  if (timeOnSite) {
2245
- detachers.push(attachTimeOnSite(rawClient, timeOnSite));
2617
+ detachers.push(attachTimeOnSite(detectorClient, timeOnSite));
2246
2618
  }
2247
2619
  const specificPageVisit = triggers.automatic.specific_page_visit;
2248
2620
  if (specificPageVisit) {
2249
- detachers.push(attachSpecificPageVisit(rawClient, specificPageVisit));
2621
+ detachers.push(attachSpecificPageVisit(detectorClient, specificPageVisit));
2250
2622
  }
2251
2623
  const scrollDepth = triggers.automatic.scroll_depth;
2252
2624
  if (scrollDepth) {
2253
- detachers.push(attachScrollDepth(rawClient, scrollDepth));
2625
+ detachers.push(attachScrollDepth(detectorClient, scrollDepth));
2254
2626
  }
2255
2627
  const multiPageSession = triggers.automatic.multi_page_session;
2256
2628
  if (multiPageSession) {
2257
- detachers.push(attachMultiPageSession(rawClient, multiPageSession));
2629
+ detachers.push(attachMultiPageSession(detectorClient, multiPageSession));
2258
2630
  }
2259
2631
  const formStart = triggers.automatic.form_start;
2260
2632
  if (formStart) {
2261
- detachers.push(attachFormStart(rawClient, formStart));
2633
+ detachers.push(attachFormStart(detectorClient, formStart));
2262
2634
  }
2263
2635
  return () => {
2264
2636
  for (let i = detachers.length - 1; i >= 0; i--) {
@@ -2306,6 +2678,7 @@ export {
2306
2678
  parsePhone,
2307
2679
  phoneField,
2308
2680
  resetConsent,
2681
+ resolveConversionConfig,
2309
2682
  saleCreateSchema,
2310
2683
  saleItemSchema,
2311
2684
  saleServiceSchema,