@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/README.md +38 -0
- package/dist/index.d.mts +26 -14
- package/dist/index.d.ts +26 -14
- package/dist/index.js +442 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +441 -68
- package/dist/index.mjs.map +1 -1
- package/dist/phone.js +73 -0
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +73 -0
- package/dist/phone.mjs.map +1 -1
- package/dist/sales-7w7-Ud60.d.mts +895 -0
- package/dist/sales-7w7-Ud60.d.ts +895 -0
- package/dist/sales.d.mts +2 -784
- package/dist/sales.d.ts +2 -784
- package/dist/sales.js +172 -45
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +172 -45
- package/dist/sales.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(src_exports, {
|
|
|
46
46
|
parsePhone: () => parsePhone,
|
|
47
47
|
phoneField: () => phoneField,
|
|
48
48
|
resetConsent: () => resetConsent,
|
|
49
|
+
resolveConversionConfig: () => resolveConversionConfig,
|
|
49
50
|
saleCreateSchema: () => saleCreateSchema,
|
|
50
51
|
saleItemSchema: () => saleItemSchema,
|
|
51
52
|
saleServiceSchema: () => saleServiceSchema,
|
|
@@ -72,6 +73,13 @@ var import_react = require("react");
|
|
|
72
73
|
// ../tracking-core/src/consent.ts
|
|
73
74
|
var CONSENT_STATE_KEY = "consent_state";
|
|
74
75
|
var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
|
|
76
|
+
var grantedListeners = /* @__PURE__ */ new Set();
|
|
77
|
+
function onConsentGranted(listener) {
|
|
78
|
+
grantedListeners.add(listener);
|
|
79
|
+
return () => {
|
|
80
|
+
grantedListeners.delete(listener);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
75
83
|
function buildConsentPayload(state) {
|
|
76
84
|
return {
|
|
77
85
|
ad_storage: state,
|
|
@@ -100,6 +108,14 @@ function setConsentState(state) {
|
|
|
100
108
|
window.gtag("consent", "update", buildConsentPayload(state));
|
|
101
109
|
if (typeof window.fbq === "function")
|
|
102
110
|
window.fbq("consent", state === "granted" ? "grant" : "revoke");
|
|
111
|
+
if (state === "granted") {
|
|
112
|
+
for (const listener of grantedListeners) {
|
|
113
|
+
try {
|
|
114
|
+
listener();
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
103
119
|
}
|
|
104
120
|
function resetConsent() {
|
|
105
121
|
if (typeof window === "undefined") return;
|
|
@@ -230,11 +246,30 @@ function isValidGtagId(id) {
|
|
|
230
246
|
function ensureGtagFunction() {
|
|
231
247
|
window.dataLayer = window.dataLayer || [];
|
|
232
248
|
if (typeof window.gtag === "function") return window.gtag;
|
|
233
|
-
|
|
234
|
-
window.dataLayer?.push(
|
|
235
|
-
}
|
|
249
|
+
function gtag() {
|
|
250
|
+
window.dataLayer?.push(arguments);
|
|
251
|
+
}
|
|
252
|
+
window.gtag = gtag;
|
|
236
253
|
return window.gtag;
|
|
237
254
|
}
|
|
255
|
+
var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
|
|
256
|
+
function isValidSendTo(sendTo) {
|
|
257
|
+
return SEND_TO_RE.test(sendTo);
|
|
258
|
+
}
|
|
259
|
+
function fireGtagConversion(input) {
|
|
260
|
+
if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
|
|
261
|
+
if (!isValidSendTo(input.sendTo)) return false;
|
|
262
|
+
const params = { send_to: input.sendTo };
|
|
263
|
+
if (input.value != null) params.value = input.value;
|
|
264
|
+
if (input.currency) params.currency = input.currency;
|
|
265
|
+
if (input.transactionId) params.transaction_id = input.transactionId;
|
|
266
|
+
try {
|
|
267
|
+
window.gtag("event", "conversion", params);
|
|
268
|
+
return true;
|
|
269
|
+
} catch {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
238
273
|
function applyDefaultConsentState() {
|
|
239
274
|
const gtag = ensureGtagFunction();
|
|
240
275
|
gtag("consent", "default", {
|
|
@@ -441,6 +476,329 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
|
|
|
441
476
|
};
|
|
442
477
|
}
|
|
443
478
|
|
|
479
|
+
// ../tracking-core/src/resources/conversion-firing.ts
|
|
480
|
+
var DEDUP_PREFIX = "_aranova_conv_";
|
|
481
|
+
var MAX_PENDING = 100;
|
|
482
|
+
var pendingQueue = [];
|
|
483
|
+
function dedupKey(input) {
|
|
484
|
+
return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
|
|
485
|
+
}
|
|
486
|
+
function alreadyFired(input) {
|
|
487
|
+
if (!input.transactionId || typeof window === "undefined") return false;
|
|
488
|
+
try {
|
|
489
|
+
return window.sessionStorage.getItem(dedupKey(input)) !== null;
|
|
490
|
+
} catch {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function markFired(input) {
|
|
495
|
+
if (!input.transactionId || typeof window === "undefined") return;
|
|
496
|
+
try {
|
|
497
|
+
window.sessionStorage.setItem(dedupKey(input), "1");
|
|
498
|
+
} catch {
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function fireOnce(input) {
|
|
502
|
+
if (alreadyFired(input)) return;
|
|
503
|
+
if (fireGtagConversion(input)) markFired(input);
|
|
504
|
+
}
|
|
505
|
+
function fireConversionWithConsent(input) {
|
|
506
|
+
const state = getConsentState();
|
|
507
|
+
if (state === "denied") return;
|
|
508
|
+
if (state === "pending") {
|
|
509
|
+
if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
|
|
510
|
+
pendingQueue.push(input);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
fireOnce(input);
|
|
514
|
+
}
|
|
515
|
+
function flushPendingConversions() {
|
|
516
|
+
if (getConsentState() !== "granted") return;
|
|
517
|
+
while (pendingQueue.length > 0) {
|
|
518
|
+
const input = pendingQueue.shift();
|
|
519
|
+
if (input) fireOnce(input);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
|
|
523
|
+
|
|
524
|
+
// ../tracking-core/src/resources/conversion-config.ts
|
|
525
|
+
function isStringMap(value) {
|
|
526
|
+
return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
|
|
527
|
+
}
|
|
528
|
+
function parseFiring(value) {
|
|
529
|
+
if (!value || typeof value !== "object") return null;
|
|
530
|
+
const f = value;
|
|
531
|
+
if (typeof f.send_to !== "string") return null;
|
|
532
|
+
return {
|
|
533
|
+
send_to: f.send_to,
|
|
534
|
+
value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
|
|
535
|
+
currency: typeof f.currency === "string" ? f.currency : null
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function parseTrigger(value) {
|
|
539
|
+
if (!value || typeof value !== "object") return null;
|
|
540
|
+
const t = value;
|
|
541
|
+
if (typeof t.event_type !== "string") return null;
|
|
542
|
+
const spec = { event_type: t.event_type };
|
|
543
|
+
if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
|
|
544
|
+
if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
|
|
545
|
+
if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
|
|
546
|
+
if (typeof t.page_name === "string") spec.page_name = t.page_name;
|
|
547
|
+
return spec;
|
|
548
|
+
}
|
|
549
|
+
function parseConversionConfig(raw) {
|
|
550
|
+
if (!raw || typeof raw !== "object") return null;
|
|
551
|
+
const obj = raw;
|
|
552
|
+
const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
|
|
553
|
+
const services = servicesRaw.flatMap((entry) => {
|
|
554
|
+
if (!entry || typeof entry !== "object") return [];
|
|
555
|
+
const s = entry;
|
|
556
|
+
if (typeof s.key !== "string") return [];
|
|
557
|
+
return [
|
|
558
|
+
{
|
|
559
|
+
key: s.key,
|
|
560
|
+
label: typeof s.label === "string" ? s.label : void 0,
|
|
561
|
+
firing: parseFiring(s.firing)
|
|
562
|
+
}
|
|
563
|
+
];
|
|
564
|
+
});
|
|
565
|
+
const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
|
|
566
|
+
const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
|
|
567
|
+
if (!entry || typeof entry !== "object") return [];
|
|
568
|
+
const g = entry;
|
|
569
|
+
if (typeof g.key !== "string") return [];
|
|
570
|
+
return [
|
|
571
|
+
{
|
|
572
|
+
key: g.key,
|
|
573
|
+
label: typeof g.label === "string" ? g.label : void 0,
|
|
574
|
+
kind: g.kind === "event" ? "event" : "sale",
|
|
575
|
+
trigger: parseTrigger(g.trigger),
|
|
576
|
+
firing: parseFiring(g.firing)
|
|
577
|
+
}
|
|
578
|
+
];
|
|
579
|
+
}) : services.map((s) => ({
|
|
580
|
+
key: s.key,
|
|
581
|
+
label: s.label,
|
|
582
|
+
kind: "sale",
|
|
583
|
+
trigger: null,
|
|
584
|
+
firing: s.firing
|
|
585
|
+
}));
|
|
586
|
+
return {
|
|
587
|
+
schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
|
|
588
|
+
config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
|
|
589
|
+
business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
|
|
590
|
+
customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
|
|
591
|
+
environment: typeof obj.environment === "string" ? obj.environment : void 0,
|
|
592
|
+
gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
|
|
593
|
+
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
594
|
+
services,
|
|
595
|
+
goals
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
var CACHE_PREFIX = "_aranova_cfg_";
|
|
599
|
+
function cacheKey(url) {
|
|
600
|
+
return `${CACHE_PREFIX}${url}`;
|
|
601
|
+
}
|
|
602
|
+
function readCache(url) {
|
|
603
|
+
if (typeof window === "undefined") return null;
|
|
604
|
+
try {
|
|
605
|
+
const raw = window.sessionStorage.getItem(cacheKey(url));
|
|
606
|
+
if (!raw) return null;
|
|
607
|
+
const parsed = JSON.parse(raw);
|
|
608
|
+
const config = parseConversionConfig(parsed.config);
|
|
609
|
+
if (!config) return null;
|
|
610
|
+
return {
|
|
611
|
+
etag: typeof parsed.etag === "string" ? parsed.etag : null,
|
|
612
|
+
config
|
|
613
|
+
};
|
|
614
|
+
} catch {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function writeCache(url, entry) {
|
|
619
|
+
if (typeof window === "undefined") return;
|
|
620
|
+
try {
|
|
621
|
+
window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
|
|
622
|
+
} catch {
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function resolveConversionConfig(options) {
|
|
626
|
+
const cached = readCache(options.cdnUrl);
|
|
627
|
+
let current = cached?.config ?? options.baked ?? null;
|
|
628
|
+
let etag = cached?.etag ?? null;
|
|
629
|
+
const goalsByKey = /* @__PURE__ */ new Map();
|
|
630
|
+
const resolveListeners = /* @__PURE__ */ new Set();
|
|
631
|
+
function rebuildIndex() {
|
|
632
|
+
goalsByKey.clear();
|
|
633
|
+
for (const goal of current?.goals ?? []) {
|
|
634
|
+
goalsByKey.set(goal.key, goal);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
function notifyResolved() {
|
|
638
|
+
const listeners = [...resolveListeners];
|
|
639
|
+
resolveListeners.clear();
|
|
640
|
+
for (const listener of listeners) {
|
|
641
|
+
try {
|
|
642
|
+
listener();
|
|
643
|
+
} catch {
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function adopt(next, nextEtag) {
|
|
648
|
+
if (!next) return;
|
|
649
|
+
if (current && next.config_version <= current.config_version) return;
|
|
650
|
+
const wasEmpty = current === null;
|
|
651
|
+
current = next;
|
|
652
|
+
etag = nextEtag;
|
|
653
|
+
rebuildIndex();
|
|
654
|
+
writeCache(options.cdnUrl, { etag, config: next });
|
|
655
|
+
if (wasEmpty) notifyResolved();
|
|
656
|
+
}
|
|
657
|
+
async function revalidate() {
|
|
658
|
+
if (typeof window === "undefined") return;
|
|
659
|
+
try {
|
|
660
|
+
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
661
|
+
if (!doFetch) return;
|
|
662
|
+
const headers = {};
|
|
663
|
+
if (etag) headers["If-None-Match"] = etag;
|
|
664
|
+
const response = await doFetch(options.cdnUrl, {
|
|
665
|
+
method: "GET",
|
|
666
|
+
headers
|
|
667
|
+
});
|
|
668
|
+
if (response.status === 304 || !response.ok) return;
|
|
669
|
+
adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
|
|
670
|
+
} catch {
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
rebuildIndex();
|
|
674
|
+
void revalidate();
|
|
675
|
+
return {
|
|
676
|
+
getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
|
|
677
|
+
getGoal: (key) => goalsByKey.get(key) ?? null,
|
|
678
|
+
listGoals: () => [...goalsByKey.values()],
|
|
679
|
+
current: () => current,
|
|
680
|
+
isReady: () => current !== null,
|
|
681
|
+
onResolve: (listener) => {
|
|
682
|
+
if (current !== null) {
|
|
683
|
+
listener();
|
|
684
|
+
return () => {
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
resolveListeners.add(listener);
|
|
688
|
+
return () => resolveListeners.delete(listener);
|
|
689
|
+
},
|
|
690
|
+
revalidate
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// ../tracking-core/src/resources/sales/money.ts
|
|
695
|
+
var MINOR_UNIT_EXPONENT = {
|
|
696
|
+
USD: 2,
|
|
697
|
+
CAD: 2
|
|
698
|
+
};
|
|
699
|
+
function exponentFor(currency) {
|
|
700
|
+
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
701
|
+
}
|
|
702
|
+
function toMinor(amount, currency) {
|
|
703
|
+
return Math.round(amount * 10 ** exponentFor(currency));
|
|
704
|
+
}
|
|
705
|
+
function fromMinor(cents, currency) {
|
|
706
|
+
return cents / 10 ** exponentFor(currency);
|
|
707
|
+
}
|
|
708
|
+
function formatMoney(cents, currency, locale) {
|
|
709
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
710
|
+
fromMinor(cents, currency)
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
714
|
+
const date = new Date(iso);
|
|
715
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
716
|
+
return new Intl.DateTimeFormat(locale, {
|
|
717
|
+
year: "numeric",
|
|
718
|
+
month: "short",
|
|
719
|
+
day: "2-digit",
|
|
720
|
+
hour: "2-digit",
|
|
721
|
+
minute: "2-digit",
|
|
722
|
+
...opts,
|
|
723
|
+
timeZone
|
|
724
|
+
}).format(date);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// ../tracking-core/src/resources/conversion-autofire.ts
|
|
728
|
+
function thresholdMet(goal, eventType, metadata) {
|
|
729
|
+
const t = goal.trigger;
|
|
730
|
+
if (!t || t.event_type !== eventType) return false;
|
|
731
|
+
switch (eventType) {
|
|
732
|
+
case "scroll_depth":
|
|
733
|
+
return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
|
|
734
|
+
case "time_on_site":
|
|
735
|
+
return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
|
|
736
|
+
case "multi_page_session":
|
|
737
|
+
return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
|
|
738
|
+
case "specific_page_visit":
|
|
739
|
+
return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
|
|
740
|
+
case "page_view":
|
|
741
|
+
case "form_start":
|
|
742
|
+
return true;
|
|
743
|
+
// no threshold — fire whenever the detector emits
|
|
744
|
+
default:
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
function currentPath() {
|
|
749
|
+
return typeof window === "undefined" ? "" : window.location.pathname;
|
|
750
|
+
}
|
|
751
|
+
var MAX_BUFFERED_EVENTS = 50;
|
|
752
|
+
function createConversionAutoFire(store) {
|
|
753
|
+
const pending = [];
|
|
754
|
+
let subscribed = false;
|
|
755
|
+
function fireMatching(eventType, metadata) {
|
|
756
|
+
for (const goal of store.listGoals()) {
|
|
757
|
+
if (goal.kind !== "event" || !goal.firing) continue;
|
|
758
|
+
if (!thresholdMet(goal, eventType, metadata)) continue;
|
|
759
|
+
const firing = goal.firing;
|
|
760
|
+
const cents = firing.value_cents ?? null;
|
|
761
|
+
const currency = firing.currency ?? null;
|
|
762
|
+
fireConversionWithConsent({
|
|
763
|
+
sendTo: firing.send_to,
|
|
764
|
+
value: cents != null && currency ? fromMinor(cents, currency) : null,
|
|
765
|
+
currency,
|
|
766
|
+
// Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
|
|
767
|
+
// shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
|
|
768
|
+
transactionId: `auto:${goal.key}:${currentPath()}`
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
onAutomaticEvent(eventType, metadata) {
|
|
774
|
+
if (store.isReady()) {
|
|
775
|
+
fireMatching(eventType, metadata);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (pending.length < MAX_BUFFERED_EVENTS) pending.push({ eventType, metadata });
|
|
779
|
+
if (!subscribed) {
|
|
780
|
+
subscribed = true;
|
|
781
|
+
store.onResolve(() => {
|
|
782
|
+
const buffered = pending.splice(0);
|
|
783
|
+
for (const event of buffered) fireMatching(event.eventType, event.metadata);
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
function withConversionAutoFire(client, autoFire) {
|
|
790
|
+
return {
|
|
791
|
+
...client,
|
|
792
|
+
trackEvent: (input) => {
|
|
793
|
+
client.trackEvent(input);
|
|
794
|
+
try {
|
|
795
|
+
autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
|
|
796
|
+
} catch {
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
|
|
444
802
|
// ../tracking-core/src/session.ts
|
|
445
803
|
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
446
804
|
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
@@ -1260,7 +1618,7 @@ function attachScrollDepth(client, config) {
|
|
|
1260
1618
|
}
|
|
1261
1619
|
const thresholds = new Set(config.thresholds);
|
|
1262
1620
|
let firedForPath = /* @__PURE__ */ new Set();
|
|
1263
|
-
let
|
|
1621
|
+
let currentPath2 = window.location.pathname;
|
|
1264
1622
|
let rafId = null;
|
|
1265
1623
|
function getScrollPercent() {
|
|
1266
1624
|
const doc = document.documentElement;
|
|
@@ -1279,7 +1637,7 @@ function attachScrollDepth(client, config) {
|
|
|
1279
1637
|
eventType: "scroll_depth",
|
|
1280
1638
|
metadata: {
|
|
1281
1639
|
depth_percent: threshold,
|
|
1282
|
-
page: { path:
|
|
1640
|
+
page: { path: currentPath2 }
|
|
1283
1641
|
},
|
|
1284
1642
|
pageUrl: window.location.href,
|
|
1285
1643
|
occurredAt: null
|
|
@@ -1296,8 +1654,8 @@ function attachScrollDepth(client, config) {
|
|
|
1296
1654
|
}
|
|
1297
1655
|
function resetIfPathChanged() {
|
|
1298
1656
|
const newPath = window.location.pathname;
|
|
1299
|
-
if (newPath ===
|
|
1300
|
-
|
|
1657
|
+
if (newPath === currentPath2) return;
|
|
1658
|
+
currentPath2 = newPath;
|
|
1301
1659
|
firedForPath = /* @__PURE__ */ new Set();
|
|
1302
1660
|
setTimeout(checkThresholds, 0);
|
|
1303
1661
|
}
|
|
@@ -1373,13 +1731,13 @@ function attachMultiPageSession(client, config) {
|
|
|
1373
1731
|
return storage.getItem(FIRED_KEY) === "1";
|
|
1374
1732
|
}
|
|
1375
1733
|
function check() {
|
|
1376
|
-
const
|
|
1377
|
-
if (
|
|
1378
|
-
lastCheckedPath =
|
|
1734
|
+
const currentPath2 = window.location.pathname;
|
|
1735
|
+
if (currentPath2 === lastCheckedPath) return;
|
|
1736
|
+
lastCheckedPath = currentPath2;
|
|
1379
1737
|
resetIfSessionChanged();
|
|
1380
1738
|
if (hasFired()) return;
|
|
1381
1739
|
const paths = getDistinctPaths();
|
|
1382
|
-
paths.add(
|
|
1740
|
+
paths.add(currentPath2);
|
|
1383
1741
|
saveDistinctPaths(paths);
|
|
1384
1742
|
if (paths.size >= pageThreshold) {
|
|
1385
1743
|
storage.setItem(FIRED_KEY, "1");
|
|
@@ -1423,7 +1781,7 @@ function attachFormStart(client, config) {
|
|
|
1423
1781
|
}
|
|
1424
1782
|
const selector = config.selector ?? "form";
|
|
1425
1783
|
let firedForms = /* @__PURE__ */ new Set();
|
|
1426
|
-
let
|
|
1784
|
+
let currentPath2 = window.location.pathname;
|
|
1427
1785
|
function getFormKey(form) {
|
|
1428
1786
|
if (form.id) return `id:${form.id}`;
|
|
1429
1787
|
const explicitAction = form.getAttribute("action");
|
|
@@ -1454,8 +1812,8 @@ function attachFormStart(client, config) {
|
|
|
1454
1812
|
}
|
|
1455
1813
|
function resetIfPathChanged() {
|
|
1456
1814
|
const newPath = window.location.pathname;
|
|
1457
|
-
if (newPath ===
|
|
1458
|
-
|
|
1815
|
+
if (newPath === currentPath2) return;
|
|
1816
|
+
currentPath2 = newPath;
|
|
1459
1817
|
firedForms = /* @__PURE__ */ new Set();
|
|
1460
1818
|
}
|
|
1461
1819
|
const originalPushState = history.pushState.bind(history);
|
|
@@ -1534,21 +1892,64 @@ async function salesRequest(config, method, path, body) {
|
|
|
1534
1892
|
}
|
|
1535
1893
|
|
|
1536
1894
|
// ../tracking-core/src/resources/sales/client.ts
|
|
1895
|
+
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
1896
|
+
if (!firing) return;
|
|
1897
|
+
const txnBase = input.external_id ?? sale.id;
|
|
1898
|
+
for (const item of recorded) {
|
|
1899
|
+
if (!item.service) continue;
|
|
1900
|
+
const config = firing.getFiring(item.service);
|
|
1901
|
+
if (!config) continue;
|
|
1902
|
+
const cents = item.amount_cents ?? config.value_cents ?? null;
|
|
1903
|
+
fireConversionWithConsent({
|
|
1904
|
+
sendTo: config.send_to,
|
|
1905
|
+
value: cents != null ? fromMinor(cents, currency) : null,
|
|
1906
|
+
currency: config.currency ?? currency,
|
|
1907
|
+
transactionId: `${txnBase}:${item.service}`
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1537
1911
|
function createSalesClient(config) {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1912
|
+
async function record(input) {
|
|
1913
|
+
const currency = input.currency ?? config.defaultCurrency;
|
|
1914
|
+
if (!currency) {
|
|
1915
|
+
throw new Error(
|
|
1916
|
+
"record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
const body = {
|
|
1920
|
+
...input,
|
|
1921
|
+
currency,
|
|
1922
|
+
occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1923
|
+
};
|
|
1924
|
+
const sale = await salesRequest(config, "POST", "/sales", body);
|
|
1925
|
+
const recorded = input.services?.length ? input.services.map((s) => ({
|
|
1926
|
+
service: s.service,
|
|
1927
|
+
amount_cents: s.amount_cents
|
|
1928
|
+
})) : [
|
|
1929
|
+
{
|
|
1930
|
+
service: input.service,
|
|
1931
|
+
amount_cents: input.amount_total_cents ?? null
|
|
1545
1932
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1933
|
+
];
|
|
1934
|
+
fireRecordedConversions(config.firing, input, recorded, sale, currency);
|
|
1935
|
+
return sale;
|
|
1936
|
+
}
|
|
1937
|
+
return {
|
|
1938
|
+
record,
|
|
1939
|
+
// recordSale is the intent-revealing alias — same behavior, clearer call site.
|
|
1940
|
+
recordSale: record,
|
|
1941
|
+
trackConversion(key, options) {
|
|
1942
|
+
const firing = config.firing?.getFiring(key);
|
|
1943
|
+
if (!firing) return;
|
|
1944
|
+
const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
|
|
1945
|
+
const cents = firing.value_cents ?? null;
|
|
1946
|
+
const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
|
|
1947
|
+
fireConversionWithConsent({
|
|
1948
|
+
sendTo: firing.send_to,
|
|
1949
|
+
value,
|
|
1548
1950
|
currency,
|
|
1549
|
-
|
|
1550
|
-
};
|
|
1551
|
-
return salesRequest(config, "POST", "/sales", body);
|
|
1951
|
+
transactionId: options?.transactionId ?? null
|
|
1952
|
+
});
|
|
1552
1953
|
},
|
|
1553
1954
|
async list(query) {
|
|
1554
1955
|
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
@@ -1642,39 +2043,6 @@ function createSalesClient(config) {
|
|
|
1642
2043
|
};
|
|
1643
2044
|
}
|
|
1644
2045
|
|
|
1645
|
-
// ../tracking-core/src/resources/sales/money.ts
|
|
1646
|
-
var MINOR_UNIT_EXPONENT = {
|
|
1647
|
-
USD: 2,
|
|
1648
|
-
CAD: 2
|
|
1649
|
-
};
|
|
1650
|
-
function exponentFor(currency) {
|
|
1651
|
-
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
1652
|
-
}
|
|
1653
|
-
function toMinor(amount, currency) {
|
|
1654
|
-
return Math.round(amount * 10 ** exponentFor(currency));
|
|
1655
|
-
}
|
|
1656
|
-
function fromMinor(cents, currency) {
|
|
1657
|
-
return cents / 10 ** exponentFor(currency);
|
|
1658
|
-
}
|
|
1659
|
-
function formatMoney(cents, currency, locale) {
|
|
1660
|
-
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
1661
|
-
fromMinor(cents, currency)
|
|
1662
|
-
);
|
|
1663
|
-
}
|
|
1664
|
-
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1665
|
-
const date = new Date(iso);
|
|
1666
|
-
if (Number.isNaN(date.getTime())) return iso;
|
|
1667
|
-
return new Intl.DateTimeFormat(locale, {
|
|
1668
|
-
year: "numeric",
|
|
1669
|
-
month: "short",
|
|
1670
|
-
day: "2-digit",
|
|
1671
|
-
hour: "2-digit",
|
|
1672
|
-
minute: "2-digit",
|
|
1673
|
-
...opts,
|
|
1674
|
-
timeZone
|
|
1675
|
-
}).format(date);
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
2046
|
// ../tracking-core/src/resources/sales/schema.ts
|
|
1679
2047
|
var import_zod11 = require("zod");
|
|
1680
2048
|
var SUPPORTED_CURRENCIES = ["USD", "CAD"];
|
|
@@ -2122,7 +2490,7 @@ function GoogleAdsTracking(props) {
|
|
|
2122
2490
|
var import_react6 = require("react");
|
|
2123
2491
|
|
|
2124
2492
|
// package.json
|
|
2125
|
-
var version = "0.
|
|
2493
|
+
var version = "0.14.1";
|
|
2126
2494
|
|
|
2127
2495
|
// ../tracking-core/src/phone-react.tsx
|
|
2128
2496
|
var import_react5 = require("react");
|
|
@@ -2221,7 +2589,7 @@ var NOOP_CLIENT = {
|
|
|
2221
2589
|
getVisitorId: () => ""
|
|
2222
2590
|
};
|
|
2223
2591
|
function createTracking(options) {
|
|
2224
|
-
const { apiKey, endpoint, triggers, environment, debug, phone } = options;
|
|
2592
|
+
const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
|
|
2225
2593
|
if (!apiKey || !endpoint) {
|
|
2226
2594
|
if (apiKey || endpoint) {
|
|
2227
2595
|
console.warn(
|
|
@@ -2296,27 +2664,32 @@ function createTracking(options) {
|
|
|
2296
2664
|
activeGtagIds: resolvedGtagIds,
|
|
2297
2665
|
debug
|
|
2298
2666
|
});
|
|
2299
|
-
|
|
2300
|
-
|
|
2667
|
+
const conversionStore = conversionConfig ? resolveConversionConfig({
|
|
2668
|
+
cdnUrl: conversionConfig.cdnUrl,
|
|
2669
|
+
baked: conversionConfig.baked
|
|
2670
|
+
}) : null;
|
|
2671
|
+
const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
|
|
2672
|
+
detachers.push(attachAutoPageView(detectorClient));
|
|
2673
|
+
detachers.push(attachBfcacheRestore(detectorClient));
|
|
2301
2674
|
const timeOnSite = triggers.automatic.time_on_site;
|
|
2302
2675
|
if (timeOnSite) {
|
|
2303
|
-
detachers.push(attachTimeOnSite(
|
|
2676
|
+
detachers.push(attachTimeOnSite(detectorClient, timeOnSite));
|
|
2304
2677
|
}
|
|
2305
2678
|
const specificPageVisit = triggers.automatic.specific_page_visit;
|
|
2306
2679
|
if (specificPageVisit) {
|
|
2307
|
-
detachers.push(attachSpecificPageVisit(
|
|
2680
|
+
detachers.push(attachSpecificPageVisit(detectorClient, specificPageVisit));
|
|
2308
2681
|
}
|
|
2309
2682
|
const scrollDepth = triggers.automatic.scroll_depth;
|
|
2310
2683
|
if (scrollDepth) {
|
|
2311
|
-
detachers.push(attachScrollDepth(
|
|
2684
|
+
detachers.push(attachScrollDepth(detectorClient, scrollDepth));
|
|
2312
2685
|
}
|
|
2313
2686
|
const multiPageSession = triggers.automatic.multi_page_session;
|
|
2314
2687
|
if (multiPageSession) {
|
|
2315
|
-
detachers.push(attachMultiPageSession(
|
|
2688
|
+
detachers.push(attachMultiPageSession(detectorClient, multiPageSession));
|
|
2316
2689
|
}
|
|
2317
2690
|
const formStart = triggers.automatic.form_start;
|
|
2318
2691
|
if (formStart) {
|
|
2319
|
-
detachers.push(attachFormStart(
|
|
2692
|
+
detachers.push(attachFormStart(detectorClient, formStart));
|
|
2320
2693
|
}
|
|
2321
2694
|
return () => {
|
|
2322
2695
|
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
@@ -2365,6 +2738,7 @@ function createTracking(options) {
|
|
|
2365
2738
|
parsePhone,
|
|
2366
2739
|
phoneField,
|
|
2367
2740
|
resetConsent,
|
|
2741
|
+
resolveConversionConfig,
|
|
2368
2742
|
saleCreateSchema,
|
|
2369
2743
|
saleItemSchema,
|
|
2370
2744
|
saleServiceSchema,
|