@aranova/tracking-react 1.0.0 → 1.2.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/client.d.mts +9 -3
- package/dist/client.d.ts +9 -3
- package/dist/client.js +549 -197
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +549 -197
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +217 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +217 -141
- package/dist/index.mjs.map +1 -1
- package/dist/{ingest-typed-BdKmlouW.d.ts → ingest-typed-MBuMe9Pn.d.ts} +94 -2
- package/dist/{ingest-typed-Bo7WPmpU.d.mts → ingest-typed-UA13xTfI.d.mts} +94 -2
- package/dist/{phone-utils-CubQif9Z.d.mts → phone-utils-C0ds6cqZ.d.mts} +6 -0
- package/dist/{phone-utils-CubQif9Z.d.ts → phone-utils-C0ds6cqZ.d.ts} +6 -0
- package/dist/phone.d.mts +1 -1
- package/dist/phone.d.ts +1 -1
- package/dist/{sales-C7Xjsq-a.d.mts → sales-BuKD_bdo.d.mts} +1 -1
- package/dist/{sales-Bhh9mLBA.d.ts → sales-C3O_xxZ_.d.ts} +1 -1
- package/dist/sales.d.mts +2 -2
- package/dist/sales.d.ts +2 -2
- package/dist/sales.js +17 -1
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +17 -1
- package/dist/sales.mjs.map +1 -1
- package/dist/{tracking-config-runtime-D7prdTE1.d.mts → tracking-config-runtime-C6H7ofmo.d.mts} +6 -0
- package/dist/{tracking-config-runtime-D7prdTE1.d.ts → tracking-config-runtime-C6H7ofmo.d.ts} +6 -0
- package/package.json +1 -1
package/dist/client.mjs
CHANGED
|
@@ -248,6 +248,7 @@ var TRACKING_CAPABILITIES = [
|
|
|
248
248
|
"consent_controls",
|
|
249
249
|
"conversion_goals_auto",
|
|
250
250
|
"conversion_goals_manual",
|
|
251
|
+
"cross_site_linker",
|
|
251
252
|
"cta_click_capture",
|
|
252
253
|
"form_capture",
|
|
253
254
|
"phone_click_capture",
|
|
@@ -274,6 +275,9 @@ function readDomMarkers() {
|
|
|
274
275
|
return found;
|
|
275
276
|
}
|
|
276
277
|
|
|
278
|
+
// ../tracking-core/src/cross-site-link.ts
|
|
279
|
+
import * as z from "zod/mini";
|
|
280
|
+
|
|
277
281
|
// ../tracking-core/src/tracking.ts
|
|
278
282
|
var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
|
|
279
283
|
var TRACKING_PARAM_KEYS = [
|
|
@@ -641,6 +645,244 @@ function buildLandingPayloadFields(sessionId, override) {
|
|
|
641
645
|
};
|
|
642
646
|
}
|
|
643
647
|
|
|
648
|
+
// ../tracking-core/src/session.ts
|
|
649
|
+
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
650
|
+
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
651
|
+
var SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
652
|
+
function safeUuid() {
|
|
653
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function")
|
|
654
|
+
return crypto.randomUUID();
|
|
655
|
+
return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
|
|
656
|
+
}
|
|
657
|
+
function readLocalStorage(key) {
|
|
658
|
+
try {
|
|
659
|
+
return window.localStorage.getItem(key);
|
|
660
|
+
} catch {
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
function writeLocalStorage(key, value) {
|
|
665
|
+
try {
|
|
666
|
+
window.localStorage.setItem(key, value);
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function getVisitorId() {
|
|
671
|
+
if (typeof window === "undefined") return safeUuid();
|
|
672
|
+
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
673
|
+
if (existing && existing.length > 0) return existing;
|
|
674
|
+
const fresh = safeUuid();
|
|
675
|
+
writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
|
|
676
|
+
return fresh;
|
|
677
|
+
}
|
|
678
|
+
function adoptVisitorId(visitorId) {
|
|
679
|
+
if (typeof window === "undefined" || visitorId.length === 0) return false;
|
|
680
|
+
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
681
|
+
if (existing && existing.length > 0) return false;
|
|
682
|
+
writeLocalStorage(VISITOR_STORAGE_KEY, visitorId);
|
|
683
|
+
return readLocalStorage(VISITOR_STORAGE_KEY) === visitorId;
|
|
684
|
+
}
|
|
685
|
+
function getOrRotateSessionId(now = Date.now()) {
|
|
686
|
+
if (typeof window === "undefined") return { id: safeUuid(), isNew: true };
|
|
687
|
+
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
688
|
+
if (raw) {
|
|
689
|
+
try {
|
|
690
|
+
const parsed = JSON.parse(raw);
|
|
691
|
+
if (typeof parsed.id === "string" && typeof parsed.last_event_at === "number") {
|
|
692
|
+
if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
|
|
693
|
+
const refreshed = { id: parsed.id, last_event_at: now };
|
|
694
|
+
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
|
|
695
|
+
return { id: parsed.id, isNew: false };
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
} catch {
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const fresh = { id: safeUuid(), last_event_at: now };
|
|
702
|
+
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
|
|
703
|
+
return { id: fresh.id, isNew: true };
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ../tracking-core/src/cross-site-link.ts
|
|
707
|
+
var LINK_PARAM = "_arv";
|
|
708
|
+
var LINK_TOKEN_VERSION = "1";
|
|
709
|
+
var LINK_TOKEN_TTL_MS = 5 * 60 * 1e3;
|
|
710
|
+
var FUTURE_SKEW_MS = 60 * 1e3;
|
|
711
|
+
var CARRIED_KEYS = {
|
|
712
|
+
g: "gclid",
|
|
713
|
+
w: "wbraid",
|
|
714
|
+
gb: "gbraid",
|
|
715
|
+
f: "fbclid",
|
|
716
|
+
y: "ylpcid"
|
|
717
|
+
};
|
|
718
|
+
var CARRIED_ENTRIES = Object.entries(CARRIED_KEYS);
|
|
719
|
+
var identifier = z.string().check(z.minLength(1), z.maxLength(128));
|
|
720
|
+
var optionalIdentifier = z.optional(identifier);
|
|
721
|
+
var linkTokenSchema = z.object({
|
|
722
|
+
v: identifier,
|
|
723
|
+
s: identifier,
|
|
724
|
+
// Epoch ms in base36.
|
|
725
|
+
t: z.string().check(z.regex(/^[0-9a-z]{1,12}$/)),
|
|
726
|
+
g: optionalIdentifier,
|
|
727
|
+
w: optionalIdentifier,
|
|
728
|
+
gb: optionalIdentifier,
|
|
729
|
+
f: optionalIdentifier,
|
|
730
|
+
fc: optionalIdentifier,
|
|
731
|
+
y: optionalIdentifier
|
|
732
|
+
});
|
|
733
|
+
function toBase64Url(input) {
|
|
734
|
+
const bytes = new TextEncoder().encode(input);
|
|
735
|
+
let binary = "";
|
|
736
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
737
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
738
|
+
}
|
|
739
|
+
function fromBase64Url(input) {
|
|
740
|
+
try {
|
|
741
|
+
const padded = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
742
|
+
const binary = atob(padded + "=".repeat((4 - padded.length % 4) % 4));
|
|
743
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
744
|
+
return new TextDecoder().decode(bytes);
|
|
745
|
+
} catch {
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function encodeLinkToken(payload) {
|
|
750
|
+
const params = new URLSearchParams();
|
|
751
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
752
|
+
if (typeof value === "string" && value.length > 0) params.set(key, value);
|
|
753
|
+
}
|
|
754
|
+
return `${LINK_TOKEN_VERSION}.${toBase64Url(params.toString())}`;
|
|
755
|
+
}
|
|
756
|
+
function decodeLinkToken(raw) {
|
|
757
|
+
const dot = raw.indexOf(".");
|
|
758
|
+
if (dot <= 0 || raw.slice(0, dot) !== LINK_TOKEN_VERSION) return null;
|
|
759
|
+
const decoded = fromBase64Url(raw.slice(dot + 1));
|
|
760
|
+
if (decoded === null) return null;
|
|
761
|
+
const params = new URLSearchParams(decoded);
|
|
762
|
+
const candidate = {};
|
|
763
|
+
params.forEach((value, key) => {
|
|
764
|
+
candidate[key] = value;
|
|
765
|
+
});
|
|
766
|
+
const result = linkTokenSchema.safeParse(candidate);
|
|
767
|
+
return result.success ? result.data : null;
|
|
768
|
+
}
|
|
769
|
+
function payloadToLink(payload) {
|
|
770
|
+
const carried = {};
|
|
771
|
+
for (const [wire, param] of CARRIED_ENTRIES) {
|
|
772
|
+
const value = payload[wire];
|
|
773
|
+
if (value) carried[param] = value;
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
visitorId: payload.v,
|
|
777
|
+
sessionId: payload.s,
|
|
778
|
+
linkedAt: Number.parseInt(payload.t, 36),
|
|
779
|
+
carried,
|
|
780
|
+
fbc: payload.fc ?? null
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
function stripWww(hostname) {
|
|
784
|
+
return hostname.toLowerCase().replace(/^www\./, "");
|
|
785
|
+
}
|
|
786
|
+
function isSiblingHost(hostname, sibling) {
|
|
787
|
+
const host = stripWww(hostname);
|
|
788
|
+
const target = stripWww(sibling);
|
|
789
|
+
return host === target || host.endsWith(`.${target}`);
|
|
790
|
+
}
|
|
791
|
+
function resolveCrossSiteLink(url, linkedHostnames, now = Date.now()) {
|
|
792
|
+
if (typeof window === "undefined" || linkedHostnames.length === 0) return null;
|
|
793
|
+
let target;
|
|
794
|
+
try {
|
|
795
|
+
target = new URL(url, window.location.href);
|
|
796
|
+
} catch {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") return null;
|
|
800
|
+
const here = window.location.hostname;
|
|
801
|
+
if (here && isSiblingHost(target.hostname, here)) return null;
|
|
802
|
+
const hostname = linkedHostnames.find((sibling) => isSiblingHost(target.hostname, sibling));
|
|
803
|
+
if (hostname === void 0) return null;
|
|
804
|
+
const consent = getConsentChoice();
|
|
805
|
+
if (consent.state === "denied" && consent.source === "explicit") {
|
|
806
|
+
return { hostname, decorated: url };
|
|
807
|
+
}
|
|
808
|
+
target.searchParams.set(LINK_PARAM, buildOutboundLinkToken(now));
|
|
809
|
+
return { hostname, decorated: target.href };
|
|
810
|
+
}
|
|
811
|
+
function stripLinkParam(url) {
|
|
812
|
+
try {
|
|
813
|
+
const parsed = new URL(url, typeof window === "undefined" ? void 0 : window.location.href);
|
|
814
|
+
if (!parsed.searchParams.has(LINK_PARAM)) return url;
|
|
815
|
+
parsed.searchParams.delete(LINK_PARAM);
|
|
816
|
+
return parsed.href;
|
|
817
|
+
} catch {
|
|
818
|
+
return url;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
function stripLinkParamFromSearch(search) {
|
|
822
|
+
if (!search.includes(LINK_PARAM)) return search;
|
|
823
|
+
const params = new URLSearchParams(search);
|
|
824
|
+
if (!params.has(LINK_PARAM)) return search;
|
|
825
|
+
params.delete(LINK_PARAM);
|
|
826
|
+
const rest = params.toString();
|
|
827
|
+
return rest.length > 0 ? `?${rest}` : "";
|
|
828
|
+
}
|
|
829
|
+
function readCarried() {
|
|
830
|
+
const out = {};
|
|
831
|
+
for (const [wire, param] of CARRIED_ENTRIES) {
|
|
832
|
+
const value = readCookieValue(param);
|
|
833
|
+
if (value) out[wire] = value;
|
|
834
|
+
}
|
|
835
|
+
return out;
|
|
836
|
+
}
|
|
837
|
+
function buildOutboundLinkToken(now = Date.now()) {
|
|
838
|
+
const fbc = getFbcCookie();
|
|
839
|
+
return encodeLinkToken({
|
|
840
|
+
v: getVisitorId(),
|
|
841
|
+
s: getOrRotateSessionId(now).id,
|
|
842
|
+
t: now.toString(36),
|
|
843
|
+
...readCarried(),
|
|
844
|
+
...fbc ? { fc: fbc } : {}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
function decorateCrossSiteUrl(url, linkedHostnames, now = Date.now()) {
|
|
848
|
+
return resolveCrossSiteLink(url, linkedHostnames, now)?.decorated ?? url;
|
|
849
|
+
}
|
|
850
|
+
function consumeInboundLink(href = typeof window === "undefined" ? "" : window.location.href, now = Date.now()) {
|
|
851
|
+
if (typeof window === "undefined" || !href) return null;
|
|
852
|
+
let raw;
|
|
853
|
+
try {
|
|
854
|
+
raw = new URL(href, window.location.href).searchParams.get(LINK_PARAM);
|
|
855
|
+
} catch {
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
if (!raw) return null;
|
|
859
|
+
const payload = decodeLinkToken(raw);
|
|
860
|
+
if (payload === null) return { outcome: "invalid", link: null, adoptedVisitor: false };
|
|
861
|
+
const link = payloadToLink(payload);
|
|
862
|
+
const age = now - link.linkedAt;
|
|
863
|
+
if (!Number.isFinite(age) || age < -FUTURE_SKEW_MS) {
|
|
864
|
+
return { outcome: "invalid", link: null, adoptedVisitor: false };
|
|
865
|
+
}
|
|
866
|
+
if (age > LINK_TOKEN_TTL_MS) {
|
|
867
|
+
return { outcome: "stale", link: null, adoptedVisitor: false };
|
|
868
|
+
}
|
|
869
|
+
const adoptedVisitor = adoptVisitorId(link.visitorId);
|
|
870
|
+
for (const [param, value] of Object.entries(link.carried)) {
|
|
871
|
+
if (!readCookieValue(param)) setTrackingCookie(param, value);
|
|
872
|
+
}
|
|
873
|
+
if (link.fbc && !getFbcCookie()) persistCookieValue(FBC_COOKIE, link.fbc);
|
|
874
|
+
return { outcome: "linked", link, adoptedVisitor };
|
|
875
|
+
}
|
|
876
|
+
function stripLinkParamFromLocation() {
|
|
877
|
+
if (typeof window === "undefined" || typeof history === "undefined") return;
|
|
878
|
+
const clean = stripLinkParam(window.location.href);
|
|
879
|
+
if (clean === window.location.href) return;
|
|
880
|
+
try {
|
|
881
|
+
history.replaceState(null, "", clean);
|
|
882
|
+
} catch {
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
644
886
|
// ../tracking-core/src/resources/conversion-firing.ts
|
|
645
887
|
var DEDUP_PREFIX = "_aranova_conv_";
|
|
646
888
|
function dedupKey(input) {
|
|
@@ -747,7 +989,8 @@ function parseConversionConfig(raw) {
|
|
|
747
989
|
gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
|
|
748
990
|
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
749
991
|
services,
|
|
750
|
-
goals
|
|
992
|
+
goals,
|
|
993
|
+
linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : []
|
|
751
994
|
};
|
|
752
995
|
}
|
|
753
996
|
var CACHE_PREFIX = "_aranova_cfg_";
|
|
@@ -831,6 +1074,7 @@ function resolveConversionConfig(options) {
|
|
|
831
1074
|
getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
|
|
832
1075
|
getGoal: (key) => goalsByKey.get(key) ?? null,
|
|
833
1076
|
listGoals: () => [...goalsByKey.values()],
|
|
1077
|
+
linkedHostnames: () => current?.linked_hostnames ?? [],
|
|
834
1078
|
current: () => current,
|
|
835
1079
|
isReady: () => current !== null,
|
|
836
1080
|
onResolve: (listener) => {
|
|
@@ -1015,7 +1259,7 @@ function validateConfig(config, ref) {
|
|
|
1015
1259
|
function pageViewSnapshot() {
|
|
1016
1260
|
if (typeof window === "undefined" || typeof document === "undefined") return null;
|
|
1017
1261
|
return {
|
|
1018
|
-
href: window.location.href,
|
|
1262
|
+
href: stripLinkParam(window.location.href),
|
|
1019
1263
|
title: document.title || null,
|
|
1020
1264
|
referrer: document.referrer || null
|
|
1021
1265
|
};
|
|
@@ -1166,6 +1410,10 @@ var TrackingConfigRuntime = class {
|
|
|
1166
1410
|
listGoals() {
|
|
1167
1411
|
return this.current?.goals ?? [];
|
|
1168
1412
|
}
|
|
1413
|
+
/** Sibling hostnames for the linker — read from the cached object even while unconfirmed. */
|
|
1414
|
+
linkedHostnames() {
|
|
1415
|
+
return this.current?.linked_hostnames ?? [];
|
|
1416
|
+
}
|
|
1169
1417
|
async revalidateNow() {
|
|
1170
1418
|
try {
|
|
1171
1419
|
const headers = {};
|
|
@@ -1403,83 +1651,32 @@ function withConversionAutoFire(client, autoFire) {
|
|
|
1403
1651
|
};
|
|
1404
1652
|
}
|
|
1405
1653
|
|
|
1406
|
-
// ../tracking-core/src/session.ts
|
|
1407
|
-
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
1408
|
-
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
1409
|
-
var SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
1410
|
-
function safeUuid() {
|
|
1411
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function")
|
|
1412
|
-
return crypto.randomUUID();
|
|
1413
|
-
return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
|
|
1414
|
-
}
|
|
1415
|
-
function readLocalStorage(key) {
|
|
1416
|
-
try {
|
|
1417
|
-
return window.localStorage.getItem(key);
|
|
1418
|
-
} catch {
|
|
1419
|
-
return null;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
function writeLocalStorage(key, value) {
|
|
1423
|
-
try {
|
|
1424
|
-
window.localStorage.setItem(key, value);
|
|
1425
|
-
} catch {
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
function getVisitorId() {
|
|
1429
|
-
if (typeof window === "undefined") return safeUuid();
|
|
1430
|
-
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
1431
|
-
if (existing && existing.length > 0) return existing;
|
|
1432
|
-
const fresh = safeUuid();
|
|
1433
|
-
writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
|
|
1434
|
-
return fresh;
|
|
1435
|
-
}
|
|
1436
|
-
function getOrRotateSessionId(now = Date.now()) {
|
|
1437
|
-
if (typeof window === "undefined") return { id: safeUuid(), isNew: true };
|
|
1438
|
-
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
1439
|
-
if (raw) {
|
|
1440
|
-
try {
|
|
1441
|
-
const parsed = JSON.parse(raw);
|
|
1442
|
-
if (typeof parsed.id === "string" && typeof parsed.last_event_at === "number") {
|
|
1443
|
-
if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
|
|
1444
|
-
const refreshed = { id: parsed.id, last_event_at: now };
|
|
1445
|
-
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
|
|
1446
|
-
return { id: parsed.id, isNew: false };
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
} catch {
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
const fresh = { id: safeUuid(), last_event_at: now };
|
|
1453
|
-
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
|
|
1454
|
-
return { id: fresh.id, isNew: true };
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
1654
|
// ../tracking-core/src/page-view.ts
|
|
1458
1655
|
import { parse } from "zod/mini";
|
|
1459
1656
|
|
|
1460
1657
|
// ../tracking-core/src/events/page-view.ts
|
|
1461
|
-
import * as
|
|
1462
|
-
var pageViewMetadataSchema =
|
|
1463
|
-
page:
|
|
1464
|
-
title:
|
|
1465
|
-
path:
|
|
1466
|
-
search:
|
|
1467
|
-
hash:
|
|
1658
|
+
import * as z2 from "zod/mini";
|
|
1659
|
+
var pageViewMetadataSchema = z2.strictObject({
|
|
1660
|
+
page: z2.strictObject({
|
|
1661
|
+
title: z2.nullable(z2.string()),
|
|
1662
|
+
path: z2.string(),
|
|
1663
|
+
search: z2.string(),
|
|
1664
|
+
hash: z2.string()
|
|
1468
1665
|
}),
|
|
1469
|
-
referrer:
|
|
1666
|
+
referrer: z2.nullable(z2.string()),
|
|
1470
1667
|
// Optional + nullable — absent (undefined) OR explicit null OR a
|
|
1471
1668
|
// real viewport object. Mirrors Pydantic's `_Viewport | None = None`
|
|
1472
1669
|
// on the backend side so the drift test stays clean.
|
|
1473
|
-
viewport:
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
w:
|
|
1477
|
-
h:
|
|
1670
|
+
viewport: z2.optional(
|
|
1671
|
+
z2.nullable(
|
|
1672
|
+
z2.strictObject({
|
|
1673
|
+
w: z2.number(),
|
|
1674
|
+
h: z2.number()
|
|
1478
1675
|
})
|
|
1479
1676
|
)
|
|
1480
1677
|
)
|
|
1481
1678
|
});
|
|
1482
|
-
var pageViewConfigSchema =
|
|
1679
|
+
var pageViewConfigSchema = z2.strictObject({});
|
|
1483
1680
|
|
|
1484
1681
|
// ../tracking-core/src/page-view.ts
|
|
1485
1682
|
var LAST_FIRED_URL_STORAGE_KEY = "aranova_tracking_last_fired_url";
|
|
@@ -1519,7 +1716,7 @@ function buildPageViewMetadata(referrerOverride) {
|
|
|
1519
1716
|
page: {
|
|
1520
1717
|
title: document.title || null,
|
|
1521
1718
|
path: window.location.pathname,
|
|
1522
|
-
search: window.location.search,
|
|
1719
|
+
search: stripLinkParamFromSearch(window.location.search),
|
|
1523
1720
|
hash: window.location.hash
|
|
1524
1721
|
},
|
|
1525
1722
|
referrer: referrerOverride !== void 0 ? referrerOverride : document.referrer || null,
|
|
@@ -1818,11 +2015,19 @@ function createTrackingClient(config) {
|
|
|
1818
2015
|
let firstPage = null;
|
|
1819
2016
|
let initialParams = createEmptyTrackingParams();
|
|
1820
2017
|
let destroyed = false;
|
|
2018
|
+
let inboundLink = null;
|
|
2019
|
+
if (typeof window !== "undefined") {
|
|
2020
|
+
try {
|
|
2021
|
+
inboundLink = consumeInboundLink();
|
|
2022
|
+
} catch {
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
let originLink = inboundLink?.link ?? null;
|
|
1821
2026
|
const visitorId = getVisitorId();
|
|
1822
2027
|
const initialSession = getOrRotateSessionId();
|
|
1823
2028
|
let sessionId = initialSession.id;
|
|
1824
2029
|
if (typeof window !== "undefined") {
|
|
1825
|
-
firstPage = window.location.href;
|
|
2030
|
+
firstPage = stripLinkParam(window.location.href);
|
|
1826
2031
|
try {
|
|
1827
2032
|
initialParams = captureTrackingParamsFromLocation();
|
|
1828
2033
|
} catch {
|
|
@@ -1833,25 +2038,50 @@ function createTrackingClient(config) {
|
|
|
1833
2038
|
} catch {
|
|
1834
2039
|
}
|
|
1835
2040
|
}
|
|
1836
|
-
function
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
packageName,
|
|
1841
|
-
config.triggers ?? null,
|
|
1842
|
-
activeGtagIds,
|
|
1843
|
-
config.configSiteId ?? null
|
|
1844
|
-
);
|
|
2041
|
+
function currentPageUrl() {
|
|
2042
|
+
return typeof window === "undefined" ? null : stripLinkParam(window.location.href);
|
|
2043
|
+
}
|
|
2044
|
+
function enqueueInternal(eventType, metadata, pageUrl) {
|
|
1845
2045
|
queue.push({
|
|
1846
|
-
event_type:
|
|
1847
|
-
page_url:
|
|
2046
|
+
event_type: eventType,
|
|
2047
|
+
page_url: pageUrl,
|
|
1848
2048
|
metadata,
|
|
1849
2049
|
occurred_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1850
2050
|
});
|
|
1851
2051
|
}
|
|
2052
|
+
function enqueueHeartbeat() {
|
|
2053
|
+
enqueueInternal(
|
|
2054
|
+
"sdk_heartbeat",
|
|
2055
|
+
buildHeartbeatMetadata(
|
|
2056
|
+
config.surface,
|
|
2057
|
+
sdkVersion,
|
|
2058
|
+
packageName,
|
|
2059
|
+
config.triggers ?? null,
|
|
2060
|
+
activeGtagIds,
|
|
2061
|
+
config.configSiteId ?? null
|
|
2062
|
+
),
|
|
2063
|
+
currentPageUrl()
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
1852
2066
|
if (initialSession.isNew) {
|
|
1853
2067
|
enqueueHeartbeat();
|
|
1854
2068
|
}
|
|
2069
|
+
if (inboundLink !== null && typeof window !== "undefined") {
|
|
2070
|
+
const link = inboundLink.link;
|
|
2071
|
+
enqueueInternal(
|
|
2072
|
+
"site_link_arrival",
|
|
2073
|
+
{
|
|
2074
|
+
outcome: inboundLink.outcome,
|
|
2075
|
+
origin_session_id: link?.sessionId ?? null,
|
|
2076
|
+
origin_visitor_id: link?.visitorId ?? null,
|
|
2077
|
+
transit_ms: link ? Math.max(0, Date.now() - link.linkedAt) : null,
|
|
2078
|
+
adopted_visitor: inboundLink.adoptedVisitor,
|
|
2079
|
+
page: { path: window.location.pathname }
|
|
2080
|
+
},
|
|
2081
|
+
firstPage
|
|
2082
|
+
);
|
|
2083
|
+
scheduleFlush();
|
|
2084
|
+
}
|
|
1855
2085
|
if (pending.length > 0) {
|
|
1856
2086
|
scheduleFlush();
|
|
1857
2087
|
}
|
|
@@ -1859,6 +2089,7 @@ function createTrackingClient(config) {
|
|
|
1859
2089
|
const rotated = getOrRotateSessionId();
|
|
1860
2090
|
if (rotated.isNew && rotated.id !== sessionId) {
|
|
1861
2091
|
enqueueHeartbeat();
|
|
2092
|
+
originLink = null;
|
|
1862
2093
|
}
|
|
1863
2094
|
sessionId = rotated.id;
|
|
1864
2095
|
const params = mergeTrackingParams(readTrackingParams(), initialParams);
|
|
@@ -1889,6 +2120,11 @@ function createTrackingClient(config) {
|
|
|
1889
2120
|
// landing), reused from the stored record otherwise. Keys are omitted
|
|
1890
2121
|
// entirely when the landing isn't observable (SSR).
|
|
1891
2122
|
...buildLandingPayloadFields(sessionId),
|
|
2123
|
+
...originLink ? {
|
|
2124
|
+
origin_session_id: originLink.sessionId,
|
|
2125
|
+
origin_visitor_id: originLink.visitorId,
|
|
2126
|
+
origin_linked_at: new Date(originLink.linkedAt).toISOString()
|
|
2127
|
+
} : {},
|
|
1892
2128
|
first_page: firstPage,
|
|
1893
2129
|
consent_state: consentSnapshot(),
|
|
1894
2130
|
context
|
|
@@ -1965,7 +2201,8 @@ function createTrackingClient(config) {
|
|
|
1965
2201
|
const occurredAt = input.occurredAt instanceof Date ? input.occurredAt.toISOString() : typeof input.occurredAt === "string" ? input.occurredAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
1966
2202
|
queue.push({
|
|
1967
2203
|
event_type: input.eventType,
|
|
1968
|
-
|
|
2204
|
+
// A caller's href still carries `_arv` until the surface strips it after hydration.
|
|
2205
|
+
page_url: input.pageUrl != null ? stripLinkParam(input.pageUrl) : currentPageUrl(),
|
|
1969
2206
|
metadata: input.metadata ?? null,
|
|
1970
2207
|
occurred_at: occurredAt
|
|
1971
2208
|
});
|
|
@@ -2015,112 +2252,112 @@ function createTrackingClient(config) {
|
|
|
2015
2252
|
import { parse as parse2 } from "zod/mini";
|
|
2016
2253
|
|
|
2017
2254
|
// ../tracking-core/src/events/cta-click.ts
|
|
2018
|
-
import * as
|
|
2019
|
-
var ctaClickMetadataSchema =
|
|
2020
|
-
cta_name:
|
|
2021
|
-
page:
|
|
2022
|
-
path:
|
|
2255
|
+
import * as z3 from "zod/mini";
|
|
2256
|
+
var ctaClickMetadataSchema = z3.strictObject({
|
|
2257
|
+
cta_name: z3.string(),
|
|
2258
|
+
page: z3.strictObject({
|
|
2259
|
+
path: z3.string()
|
|
2023
2260
|
}),
|
|
2024
|
-
section:
|
|
2025
|
-
destination_url:
|
|
2261
|
+
section: z3.optional(z3.nullable(z3.string())),
|
|
2262
|
+
destination_url: z3.optional(z3.nullable(z3.string())),
|
|
2026
2263
|
// Set by auto-capture (and available to manual callers): the link target
|
|
2027
2264
|
// and a short element descriptor (tag#id) for tying clicks to specific UI.
|
|
2028
|
-
href:
|
|
2029
|
-
element:
|
|
2265
|
+
href: z3.optional(z3.nullable(z3.string())),
|
|
2266
|
+
element: z3.optional(z3.nullable(z3.string()))
|
|
2030
2267
|
});
|
|
2031
|
-
var ctaClickConfigSchema =
|
|
2032
|
-
autoCapture:
|
|
2033
|
-
|
|
2034
|
-
selector:
|
|
2268
|
+
var ctaClickConfigSchema = z3.strictObject({
|
|
2269
|
+
autoCapture: z3.optional(
|
|
2270
|
+
z3.strictObject({
|
|
2271
|
+
selector: z3.optional(z3.string())
|
|
2035
2272
|
})
|
|
2036
2273
|
)
|
|
2037
2274
|
});
|
|
2038
2275
|
|
|
2039
2276
|
// ../tracking-core/src/events/sdk-heartbeat.ts
|
|
2040
|
-
import * as
|
|
2041
|
-
var sdkHeartbeatTriggersSchema =
|
|
2042
|
-
automatic:
|
|
2043
|
-
manual:
|
|
2277
|
+
import * as z4 from "zod/mini";
|
|
2278
|
+
var sdkHeartbeatTriggersSchema = z4.strictObject({
|
|
2279
|
+
automatic: z4.array(z4.string()),
|
|
2280
|
+
manual: z4.array(z4.string())
|
|
2044
2281
|
});
|
|
2045
|
-
var sdkHeartbeatMetadataSchema =
|
|
2046
|
-
sdk_version:
|
|
2047
|
-
package_name:
|
|
2048
|
-
surface:
|
|
2282
|
+
var sdkHeartbeatMetadataSchema = z4.strictObject({
|
|
2283
|
+
sdk_version: z4.string(),
|
|
2284
|
+
package_name: z4.nullable(z4.string()),
|
|
2285
|
+
surface: z4.enum(["next", "react", "script"]),
|
|
2049
2286
|
triggers: sdkHeartbeatTriggersSchema,
|
|
2050
|
-
trigger_config:
|
|
2051
|
-
configured_gtag_ids:
|
|
2287
|
+
trigger_config: z4.optional(z4.nullable(z4.record(z4.string(), z4.record(z4.string(), z4.unknown())))),
|
|
2288
|
+
configured_gtag_ids: z4.optional(z4.nullable(z4.record(z4.string(), z4.string()))),
|
|
2052
2289
|
// Site whose config object the SDK resolves; null on a legacy business ref.
|
|
2053
|
-
config_site_id:
|
|
2290
|
+
config_site_id: z4.optional(z4.nullable(z4.uuid()))
|
|
2054
2291
|
});
|
|
2055
|
-
var sdkHeartbeatConfigSchema =
|
|
2292
|
+
var sdkHeartbeatConfigSchema = z4.strictObject({});
|
|
2056
2293
|
|
|
2057
2294
|
// ../tracking-core/src/events/form-start.ts
|
|
2058
|
-
import * as
|
|
2059
|
-
var formStartMetadataSchema =
|
|
2060
|
-
form:
|
|
2061
|
-
id:
|
|
2062
|
-
action:
|
|
2295
|
+
import * as z5 from "zod/mini";
|
|
2296
|
+
var formStartMetadataSchema = z5.strictObject({
|
|
2297
|
+
form: z5.strictObject({
|
|
2298
|
+
id: z5.string(),
|
|
2299
|
+
action: z5.nullable(z5.string())
|
|
2063
2300
|
}),
|
|
2064
|
-
page:
|
|
2065
|
-
path:
|
|
2301
|
+
page: z5.strictObject({
|
|
2302
|
+
path: z5.string()
|
|
2066
2303
|
})
|
|
2067
2304
|
});
|
|
2068
|
-
var formStartConfigSchema =
|
|
2069
|
-
selector:
|
|
2305
|
+
var formStartConfigSchema = z5.strictObject({
|
|
2306
|
+
selector: z5.optional(z5.string())
|
|
2070
2307
|
});
|
|
2071
2308
|
|
|
2072
2309
|
// ../tracking-core/src/events/form-submit.ts
|
|
2073
|
-
import * as
|
|
2074
|
-
var jsonValueSchema =
|
|
2075
|
-
() =>
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2310
|
+
import * as z6 from "zod/mini";
|
|
2311
|
+
var jsonValueSchema = z6.lazy(
|
|
2312
|
+
() => z6.union([
|
|
2313
|
+
z6.string(),
|
|
2314
|
+
z6.number(),
|
|
2315
|
+
z6.boolean(),
|
|
2316
|
+
z6.null(),
|
|
2317
|
+
z6.array(jsonValueSchema),
|
|
2318
|
+
z6.record(z6.string(), jsonValueSchema)
|
|
2082
2319
|
])
|
|
2083
|
-
).register(
|
|
2084
|
-
var formSubmitMetadataSchema =
|
|
2085
|
-
form:
|
|
2086
|
-
id:
|
|
2087
|
-
action:
|
|
2088
|
-
fields:
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
name:
|
|
2092
|
-
type:
|
|
2093
|
-
label:
|
|
2320
|
+
).register(z6.globalRegistry, { id: "JsonSerializableValue" });
|
|
2321
|
+
var formSubmitMetadataSchema = z6.strictObject({
|
|
2322
|
+
form: z6.strictObject({
|
|
2323
|
+
id: z6.string(),
|
|
2324
|
+
action: z6.nullable(z6.string()),
|
|
2325
|
+
fields: z6.optional(
|
|
2326
|
+
z6.array(
|
|
2327
|
+
z6.strictObject({
|
|
2328
|
+
name: z6.string(),
|
|
2329
|
+
type: z6.string(),
|
|
2330
|
+
label: z6.nullable(z6.string()),
|
|
2094
2331
|
value: jsonValueSchema
|
|
2095
2332
|
})
|
|
2096
2333
|
)
|
|
2097
2334
|
)
|
|
2098
2335
|
}),
|
|
2099
|
-
page:
|
|
2100
|
-
path:
|
|
2336
|
+
page: z6.strictObject({
|
|
2337
|
+
path: z6.string()
|
|
2101
2338
|
})
|
|
2102
2339
|
});
|
|
2103
|
-
var formSubmitConfigSchema =
|
|
2340
|
+
var formSubmitConfigSchema = z6.strictObject({});
|
|
2104
2341
|
|
|
2105
2342
|
// ../tracking-core/src/events/multi-page-session.ts
|
|
2106
|
-
import * as
|
|
2107
|
-
var multiPageSessionMetadataSchema =
|
|
2108
|
-
page_count:
|
|
2109
|
-
page:
|
|
2110
|
-
path:
|
|
2343
|
+
import * as z7 from "zod/mini";
|
|
2344
|
+
var multiPageSessionMetadataSchema = z7.strictObject({
|
|
2345
|
+
page_count: z7.int().check(z7.gte(2)),
|
|
2346
|
+
page: z7.strictObject({
|
|
2347
|
+
path: z7.string()
|
|
2111
2348
|
})
|
|
2112
2349
|
});
|
|
2113
|
-
var multiPageSessionConfigSchema =
|
|
2114
|
-
pageThreshold:
|
|
2350
|
+
var multiPageSessionConfigSchema = z7.strictObject({
|
|
2351
|
+
pageThreshold: z7.int().check(z7.gte(2))
|
|
2115
2352
|
});
|
|
2116
2353
|
|
|
2117
2354
|
// ../tracking-core/src/events/page-exit.ts
|
|
2118
|
-
import * as
|
|
2119
|
-
var pageExitMetadataSchema =
|
|
2120
|
-
dwell_ms:
|
|
2355
|
+
import * as z8 from "zod/mini";
|
|
2356
|
+
var pageExitMetadataSchema = z8.strictObject({
|
|
2357
|
+
dwell_ms: z8.int().check(z8.gte(0)),
|
|
2121
2358
|
// null = left without any scroll signal; floor is 0 so a valid 0% is never
|
|
2122
2359
|
// rejected (a single bad field 422s the whole keepalive beacon batch).
|
|
2123
|
-
max_scroll_percent:
|
|
2360
|
+
max_scroll_percent: z8.nullable(z8.int().check(z8.gte(0), z8.lte(100))),
|
|
2124
2361
|
// The gating baseline: the fraction of the page visible at load with
|
|
2125
2362
|
// zero scrolling — or, for pages that grew after the post-paint snapshot
|
|
2126
2363
|
// (skeleton/streaming renders), the first-scroll position that
|
|
@@ -2128,80 +2365,104 @@ var pageExitMetadataSchema = z7.strictObject({
|
|
|
2128
2365
|
// ended before the snapshot. Optionality is load-bearing: SDK builds
|
|
2129
2366
|
// predating this field keep POSTing page_exit without the key —
|
|
2130
2367
|
// requiring it would 422 whole keepalive beacon batches.
|
|
2131
|
-
scroll_baseline_percent:
|
|
2132
|
-
page:
|
|
2133
|
-
path:
|
|
2368
|
+
scroll_baseline_percent: z8.optional(z8.nullable(z8.int().check(z8.gte(0), z8.lte(100)))),
|
|
2369
|
+
page: z8.strictObject({
|
|
2370
|
+
path: z8.string()
|
|
2134
2371
|
})
|
|
2135
2372
|
});
|
|
2136
|
-
var pageExitConfigSchema =
|
|
2373
|
+
var pageExitConfigSchema = z8.strictObject({});
|
|
2137
2374
|
|
|
2138
2375
|
// ../tracking-core/src/events/phone-click.ts
|
|
2139
|
-
import * as
|
|
2140
|
-
var phoneClickMetadataSchema =
|
|
2141
|
-
phone_number:
|
|
2142
|
-
page:
|
|
2143
|
-
path:
|
|
2376
|
+
import * as z9 from "zod/mini";
|
|
2377
|
+
var phoneClickMetadataSchema = z9.strictObject({
|
|
2378
|
+
phone_number: z9.string(),
|
|
2379
|
+
page: z9.strictObject({
|
|
2380
|
+
path: z9.string()
|
|
2144
2381
|
}),
|
|
2145
|
-
section:
|
|
2382
|
+
section: z9.optional(z9.nullable(z9.string()))
|
|
2146
2383
|
});
|
|
2147
|
-
var phoneClickConfigSchema =
|
|
2148
|
-
autoCapture:
|
|
2149
|
-
|
|
2150
|
-
selector:
|
|
2384
|
+
var phoneClickConfigSchema = z9.strictObject({
|
|
2385
|
+
autoCapture: z9.optional(
|
|
2386
|
+
z9.strictObject({
|
|
2387
|
+
selector: z9.optional(z9.string())
|
|
2151
2388
|
})
|
|
2152
2389
|
)
|
|
2153
2390
|
});
|
|
2154
2391
|
|
|
2155
2392
|
// ../tracking-core/src/events/scroll-depth.ts
|
|
2156
|
-
import * as
|
|
2157
|
-
var scrollDepthMetadataSchema =
|
|
2158
|
-
depth_percent:
|
|
2159
|
-
page:
|
|
2160
|
-
path:
|
|
2393
|
+
import * as z10 from "zod/mini";
|
|
2394
|
+
var scrollDepthMetadataSchema = z10.strictObject({
|
|
2395
|
+
depth_percent: z10.int().check(z10.gte(1), z10.lte(100)),
|
|
2396
|
+
page: z10.strictObject({
|
|
2397
|
+
path: z10.string()
|
|
2161
2398
|
})
|
|
2162
2399
|
});
|
|
2163
|
-
var scrollDepthConfigSchema =
|
|
2164
|
-
thresholds:
|
|
2400
|
+
var scrollDepthConfigSchema = z10.strictObject({
|
|
2401
|
+
thresholds: z10.array(z10.int().check(z10.gte(1), z10.lte(100))).check(z10.minLength(1))
|
|
2165
2402
|
});
|
|
2166
2403
|
|
|
2167
2404
|
// ../tracking-core/src/events/specific-page-visit.ts
|
|
2168
|
-
import * as
|
|
2405
|
+
import * as z11 from "zod/mini";
|
|
2169
2406
|
var PAGE_IDENTITY_MAX_LENGTH = 64;
|
|
2170
2407
|
var PAGE_IDENTITY_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
|
|
2171
|
-
var pageIdentitySchema =
|
|
2172
|
-
|
|
2173
|
-
|
|
2408
|
+
var pageIdentitySchema = z11.string().check(
|
|
2409
|
+
z11.maxLength(PAGE_IDENTITY_MAX_LENGTH),
|
|
2410
|
+
z11.regex(PAGE_IDENTITY_PATTERN, {
|
|
2174
2411
|
message: "page identity must be lowercase snake_case, start with a letter, and contain at most 64 characters"
|
|
2175
2412
|
})
|
|
2176
2413
|
);
|
|
2177
2414
|
var specificPageNameSchema = pageIdentitySchema;
|
|
2178
|
-
var specificPageVisitMetadataSchema =
|
|
2415
|
+
var specificPageVisitMetadataSchema = z11.strictObject({
|
|
2179
2416
|
page_name: specificPageNameSchema,
|
|
2180
|
-
page:
|
|
2181
|
-
path:
|
|
2417
|
+
page: z11.strictObject({
|
|
2418
|
+
path: z11.string()
|
|
2182
2419
|
})
|
|
2183
2420
|
});
|
|
2184
|
-
var specificPageVisitConfigSchema =
|
|
2185
|
-
pages:
|
|
2186
|
-
|
|
2421
|
+
var specificPageVisitConfigSchema = z11.strictObject({
|
|
2422
|
+
pages: z11.array(
|
|
2423
|
+
z11.strictObject({
|
|
2187
2424
|
name: specificPageNameSchema,
|
|
2188
|
-
pathPattern:
|
|
2425
|
+
pathPattern: z11.custom((value) => value instanceof RegExp, {
|
|
2189
2426
|
message: "pathPattern must be a RegExp"
|
|
2190
2427
|
})
|
|
2191
2428
|
})
|
|
2192
|
-
).check(
|
|
2429
|
+
).check(z11.minLength(1))
|
|
2193
2430
|
});
|
|
2194
2431
|
|
|
2432
|
+
// ../tracking-core/src/events/site-link.ts
|
|
2433
|
+
import * as z12 from "zod/mini";
|
|
2434
|
+
var siteLinkClickMetadataSchema = z12.strictObject({
|
|
2435
|
+
destination_host: z12.string(),
|
|
2436
|
+
destination_url: z12.string(),
|
|
2437
|
+
page: z12.strictObject({
|
|
2438
|
+
path: z12.string()
|
|
2439
|
+
})
|
|
2440
|
+
});
|
|
2441
|
+
var siteLinkClickConfigSchema = z12.strictObject({});
|
|
2442
|
+
var siteLinkArrivalMetadataSchema = z12.strictObject({
|
|
2443
|
+
outcome: z12.enum(["linked", "stale", "invalid"]),
|
|
2444
|
+
origin_session_id: z12.optional(z12.nullable(z12.string())),
|
|
2445
|
+
origin_visitor_id: z12.optional(z12.nullable(z12.string())),
|
|
2446
|
+
// Milliseconds between the origin click and this page load.
|
|
2447
|
+
transit_ms: z12.optional(z12.nullable(z12.number())),
|
|
2448
|
+
// True when this browser had no visitor id and took the origin's.
|
|
2449
|
+
adopted_visitor: z12.boolean(),
|
|
2450
|
+
page: z12.strictObject({
|
|
2451
|
+
path: z12.string()
|
|
2452
|
+
})
|
|
2453
|
+
});
|
|
2454
|
+
var siteLinkArrivalConfigSchema = z12.strictObject({});
|
|
2455
|
+
|
|
2195
2456
|
// ../tracking-core/src/events/time-on-site.ts
|
|
2196
|
-
import * as
|
|
2197
|
-
var timeOnSiteMetadataSchema =
|
|
2198
|
-
duration_ms:
|
|
2199
|
-
page:
|
|
2200
|
-
path:
|
|
2457
|
+
import * as z13 from "zod/mini";
|
|
2458
|
+
var timeOnSiteMetadataSchema = z13.strictObject({
|
|
2459
|
+
duration_ms: z13.int().check(z13.nonnegative()),
|
|
2460
|
+
page: z13.strictObject({
|
|
2461
|
+
path: z13.string()
|
|
2201
2462
|
})
|
|
2202
2463
|
});
|
|
2203
|
-
var timeOnSiteConfigSchema =
|
|
2204
|
-
thresholdSeconds:
|
|
2464
|
+
var timeOnSiteConfigSchema = z13.strictObject({
|
|
2465
|
+
thresholdSeconds: z13.int().check(z13.positive())
|
|
2205
2466
|
});
|
|
2206
2467
|
|
|
2207
2468
|
// ../tracking-core/src/events/semantics.ts
|
|
@@ -2271,6 +2532,18 @@ var EVENT_SEMANTICS = {
|
|
|
2271
2532
|
category: "engagement",
|
|
2272
2533
|
outcomeRole: "engagement",
|
|
2273
2534
|
clientVisibility: "simple"
|
|
2535
|
+
},
|
|
2536
|
+
site_link_click: {
|
|
2537
|
+
label: "Left for sibling site",
|
|
2538
|
+
category: "page",
|
|
2539
|
+
outcomeRole: "navigation",
|
|
2540
|
+
clientVisibility: "detailed"
|
|
2541
|
+
},
|
|
2542
|
+
site_link_arrival: {
|
|
2543
|
+
label: "Arrived from sibling site",
|
|
2544
|
+
category: "page",
|
|
2545
|
+
outcomeRole: "navigation",
|
|
2546
|
+
clientVisibility: "simple"
|
|
2274
2547
|
}
|
|
2275
2548
|
};
|
|
2276
2549
|
|
|
@@ -2326,6 +2599,20 @@ var EVENT_REGISTRY = {
|
|
|
2326
2599
|
metadataSchema: pageExitMetadataSchema,
|
|
2327
2600
|
configSchema: pageExitConfigSchema
|
|
2328
2601
|
},
|
|
2602
|
+
// Cross-site linkage: emitted by the linker (roster comes from the site
|
|
2603
|
+
// config, not the trigger registry), so neither is consumer-configurable.
|
|
2604
|
+
site_link_click: {
|
|
2605
|
+
kind: "automatic",
|
|
2606
|
+
semantics: EVENT_SEMANTICS.site_link_click,
|
|
2607
|
+
metadataSchema: siteLinkClickMetadataSchema,
|
|
2608
|
+
configSchema: siteLinkClickConfigSchema
|
|
2609
|
+
},
|
|
2610
|
+
site_link_arrival: {
|
|
2611
|
+
kind: "automatic",
|
|
2612
|
+
semantics: EVENT_SEMANTICS.site_link_arrival,
|
|
2613
|
+
metadataSchema: siteLinkArrivalMetadataSchema,
|
|
2614
|
+
configSchema: siteLinkArrivalConfigSchema
|
|
2615
|
+
},
|
|
2329
2616
|
// --- manual triggers ---
|
|
2330
2617
|
form_submit: {
|
|
2331
2618
|
kind: "manual",
|
|
@@ -2931,6 +3218,57 @@ function attachCtaClickCapture(client, config) {
|
|
|
2931
3218
|
};
|
|
2932
3219
|
}
|
|
2933
3220
|
|
|
3221
|
+
// ../tracking-core/src/triggers/site-link-capture.ts
|
|
3222
|
+
function anchorFrom(target) {
|
|
3223
|
+
if (!(target instanceof Element)) return null;
|
|
3224
|
+
const anchor = target.closest("a[href]");
|
|
3225
|
+
return anchor instanceof HTMLAnchorElement ? anchor : null;
|
|
3226
|
+
}
|
|
3227
|
+
function opensTheLink(event) {
|
|
3228
|
+
return event.button === 0 || event.button === 1;
|
|
3229
|
+
}
|
|
3230
|
+
function attachSiteLinkCapture(client, options) {
|
|
3231
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
3232
|
+
return () => {
|
|
3233
|
+
};
|
|
3234
|
+
}
|
|
3235
|
+
registerCapability("cross_site_linker");
|
|
3236
|
+
function hopFrom(event) {
|
|
3237
|
+
const anchor = anchorFrom(event.target);
|
|
3238
|
+
if (anchor === null) return null;
|
|
3239
|
+
const link = resolveCrossSiteLink(anchor.href, options.linkedHostnames());
|
|
3240
|
+
return link === null ? null : { anchor, link };
|
|
3241
|
+
}
|
|
3242
|
+
function onPointerDown(event) {
|
|
3243
|
+
if (!opensTheLink(event)) return;
|
|
3244
|
+
const hop = hopFrom(event);
|
|
3245
|
+
if (hop !== null) hop.anchor.href = hop.link.decorated;
|
|
3246
|
+
}
|
|
3247
|
+
function onClick(event) {
|
|
3248
|
+
if (!opensTheLink(event)) return;
|
|
3249
|
+
const hop = hopFrom(event);
|
|
3250
|
+
if (hop === null) return;
|
|
3251
|
+
hop.anchor.href = hop.link.decorated;
|
|
3252
|
+
client.trackEvent({
|
|
3253
|
+
eventType: "site_link_click",
|
|
3254
|
+
metadata: {
|
|
3255
|
+
destination_host: hop.anchor.hostname,
|
|
3256
|
+
destination_url: stripLinkParam(hop.anchor.href),
|
|
3257
|
+
page: { path: window.location.pathname }
|
|
3258
|
+
},
|
|
3259
|
+
pageUrl: window.location.href,
|
|
3260
|
+
occurredAt: null
|
|
3261
|
+
});
|
|
3262
|
+
client.flushBeacon();
|
|
3263
|
+
}
|
|
3264
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
3265
|
+
document.addEventListener("click", onClick, true);
|
|
3266
|
+
return () => {
|
|
3267
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
3268
|
+
document.removeEventListener("click", onClick, true);
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
|
|
2934
3272
|
// ../tracking-core/src/triggers/phone-click-capture.ts
|
|
2935
3273
|
var DEFAULT_TEL_SELECTOR = 'a[href^="tel:"]';
|
|
2936
3274
|
function safeDecodeURIComponent(value) {
|
|
@@ -3316,7 +3654,7 @@ function GoogleAdsTracking(props) {
|
|
|
3316
3654
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
|
|
3317
3655
|
|
|
3318
3656
|
// package.json
|
|
3319
|
-
var version = "1.
|
|
3657
|
+
var version = "1.2.0";
|
|
3320
3658
|
|
|
3321
3659
|
// ../tracking-core/src/phone-react.tsx
|
|
3322
3660
|
import {
|
|
@@ -3446,7 +3784,8 @@ function createTracking(options) {
|
|
|
3446
3784
|
// Still publish phone config so usePhoneField/<PhoneField> work even when
|
|
3447
3785
|
// tracking is disabled (missing apiKey/endpoint).
|
|
3448
3786
|
TrackingProvider: ({ children }) => /* @__PURE__ */ jsx3(PhoneConfigProvider, { value: phone ?? null, children }),
|
|
3449
|
-
useTracking: () => noopTyped
|
|
3787
|
+
useTracking: () => noopTyped,
|
|
3788
|
+
decorateUrl: (url) => url
|
|
3450
3789
|
};
|
|
3451
3790
|
}
|
|
3452
3791
|
const TrackingContext = createContext2(null);
|
|
@@ -3465,8 +3804,8 @@ function createTracking(options) {
|
|
|
3465
3804
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- gtagIdsKey is stable proxy
|
|
3466
3805
|
[gtagId, gtagIdsKey]
|
|
3467
3806
|
);
|
|
3468
|
-
const rawClient = useMemo4(
|
|
3469
|
-
|
|
3807
|
+
const rawClient = useMemo4(() => {
|
|
3808
|
+
const created = getOrCreateTrackingClient({
|
|
3470
3809
|
apiKey,
|
|
3471
3810
|
endpoint,
|
|
3472
3811
|
surface: "react",
|
|
@@ -3477,9 +3816,10 @@ function createTracking(options) {
|
|
|
3477
3816
|
activeGtagIds: resolvedGtagIds,
|
|
3478
3817
|
configSiteId: trackingConfig?.siteId ?? null,
|
|
3479
3818
|
debug
|
|
3480
|
-
})
|
|
3481
|
-
|
|
3482
|
-
|
|
3819
|
+
});
|
|
3820
|
+
stripLinkParamFromLocation();
|
|
3821
|
+
return created;
|
|
3822
|
+
}, [resolvedGtagIds]);
|
|
3483
3823
|
const conversionStore = useMemo4(
|
|
3484
3824
|
() => trackingConfig ? getTrackingConfigRuntime(trackingConfig) : conversionConfig ? resolveConversionConfig({
|
|
3485
3825
|
cdnUrl: conversionConfig.cdnUrl,
|
|
@@ -3533,6 +3873,11 @@ function createTracking(options) {
|
|
|
3533
3873
|
if (timeOnSite) {
|
|
3534
3874
|
detachers.push(attachTimeOnSite(detectorClient, timeOnSite));
|
|
3535
3875
|
}
|
|
3876
|
+
detachers.push(
|
|
3877
|
+
attachSiteLinkCapture(detectorClient, {
|
|
3878
|
+
linkedHostnames: () => conversionStore?.linkedHostnames() ?? []
|
|
3879
|
+
})
|
|
3880
|
+
);
|
|
3536
3881
|
const specificPageVisit = triggers.automatic.specific_page_visit;
|
|
3537
3882
|
if (specificPageVisit) {
|
|
3538
3883
|
detachers.push(attachSpecificPageVisit(detectorClient, specificPageVisit));
|
|
@@ -3575,7 +3920,14 @@ function createTracking(options) {
|
|
|
3575
3920
|
}
|
|
3576
3921
|
return client;
|
|
3577
3922
|
}
|
|
3578
|
-
return {
|
|
3923
|
+
return {
|
|
3924
|
+
TrackingProvider,
|
|
3925
|
+
useTracking,
|
|
3926
|
+
decorateUrl: (url) => decorateCrossSiteUrl(
|
|
3927
|
+
url,
|
|
3928
|
+
trackingConfig ? getTrackingConfigRuntime(trackingConfig).linkedHostnames() : []
|
|
3929
|
+
)
|
|
3930
|
+
};
|
|
3579
3931
|
}
|
|
3580
3932
|
export {
|
|
3581
3933
|
AdPlatformTracking,
|