@aranova/tracking-next 0.17.1 → 0.17.3
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.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +182 -111
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +178 -107
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +8 -0
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +8 -0
- package/dist/middleware.mjs.map +1 -1
- package/dist/phone.js +8 -0
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +8 -0
- package/dist/phone.mjs.map +1 -1
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs.map +1 -1
- package/dist/server.js +8 -0
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +8 -0
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -598,9 +598,9 @@ function resolveConversionConfig(options) {
|
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
600
|
function notifyResolved() {
|
|
601
|
-
const
|
|
601
|
+
const listeners2 = [...resolveListeners];
|
|
602
602
|
resolveListeners.clear();
|
|
603
|
-
for (const listener of
|
|
603
|
+
for (const listener of listeners2) {
|
|
604
604
|
try {
|
|
605
605
|
listener();
|
|
606
606
|
} catch {
|
|
@@ -1040,6 +1040,27 @@ function getOrCreateTrackingClient(config) {
|
|
|
1040
1040
|
globalClientKey = key;
|
|
1041
1041
|
return globalClient;
|
|
1042
1042
|
}
|
|
1043
|
+
var clientCaptureRegistry = /* @__PURE__ */ new WeakMap();
|
|
1044
|
+
function attachClientCapturesOnce(client, build) {
|
|
1045
|
+
let entry = clientCaptureRegistry.get(client);
|
|
1046
|
+
if (entry === void 0) {
|
|
1047
|
+
entry = { detach: build(), refCount: 0 };
|
|
1048
|
+
clientCaptureRegistry.set(client, entry);
|
|
1049
|
+
}
|
|
1050
|
+
entry.refCount += 1;
|
|
1051
|
+
let released = false;
|
|
1052
|
+
return () => {
|
|
1053
|
+
if (released) return;
|
|
1054
|
+
released = true;
|
|
1055
|
+
const current = clientCaptureRegistry.get(client);
|
|
1056
|
+
if (current === void 0) return;
|
|
1057
|
+
current.refCount -= 1;
|
|
1058
|
+
if (current.refCount <= 0) {
|
|
1059
|
+
current.detach();
|
|
1060
|
+
clientCaptureRegistry.delete(client);
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1043
1064
|
function createTrackingClient(config) {
|
|
1044
1065
|
const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
1045
1066
|
const maxQueueSize = Math.min(config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE, HARD_MAX_BATCH);
|
|
@@ -1309,6 +1330,14 @@ var pageExitMetadataSchema = z7.object({
|
|
|
1309
1330
|
// null = left without any scroll signal; floor is 0 so a valid 0% is never
|
|
1310
1331
|
// rejected (a single bad field 422s the whole keepalive beacon batch).
|
|
1311
1332
|
max_scroll_percent: z7.number().int().min(0).max(100).nullable(),
|
|
1333
|
+
// The gating baseline: the fraction of the page visible at load with
|
|
1334
|
+
// zero scrolling — or, for pages that grew after the post-paint snapshot
|
|
1335
|
+
// (skeleton/streaming renders), the first-scroll position that
|
|
1336
|
+
// established it. null = page had no scrollable range, or the segment
|
|
1337
|
+
// ended before the snapshot. `.optional()` is load-bearing: SDK builds
|
|
1338
|
+
// predating this field keep POSTing page_exit without the key —
|
|
1339
|
+
// requiring it would 422 whole keepalive beacon batches.
|
|
1340
|
+
scroll_baseline_percent: z7.number().int().min(0).max(100).nullable().optional(),
|
|
1312
1341
|
page: z7.object({
|
|
1313
1342
|
path: z7.string()
|
|
1314
1343
|
}).strict()
|
|
@@ -1533,6 +1562,97 @@ function attachTimeOnSite(client, config) {
|
|
|
1533
1562
|
};
|
|
1534
1563
|
}
|
|
1535
1564
|
|
|
1565
|
+
// ../tracking-core/src/triggers/navigation.ts
|
|
1566
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
1567
|
+
var restorePatch = null;
|
|
1568
|
+
function notify() {
|
|
1569
|
+
for (const listener of listeners) listener();
|
|
1570
|
+
}
|
|
1571
|
+
function notifyDeferred() {
|
|
1572
|
+
setTimeout(notify, 0);
|
|
1573
|
+
}
|
|
1574
|
+
function installPatch() {
|
|
1575
|
+
const originalPushState = history.pushState;
|
|
1576
|
+
const originalReplaceState = history.replaceState;
|
|
1577
|
+
function patchedPushState(...args) {
|
|
1578
|
+
originalPushState.apply(this, args);
|
|
1579
|
+
notifyDeferred();
|
|
1580
|
+
}
|
|
1581
|
+
function patchedReplaceState(...args) {
|
|
1582
|
+
originalReplaceState.apply(this, args);
|
|
1583
|
+
notifyDeferred();
|
|
1584
|
+
}
|
|
1585
|
+
history.pushState = patchedPushState;
|
|
1586
|
+
history.replaceState = patchedReplaceState;
|
|
1587
|
+
window.addEventListener("popstate", notify);
|
|
1588
|
+
restorePatch = () => {
|
|
1589
|
+
history.pushState = originalPushState;
|
|
1590
|
+
history.replaceState = originalReplaceState;
|
|
1591
|
+
window.removeEventListener("popstate", notify);
|
|
1592
|
+
restorePatch = null;
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
function onHistoryChange(listener) {
|
|
1596
|
+
if (listeners.size === 0) installPatch();
|
|
1597
|
+
listeners.add(listener);
|
|
1598
|
+
return () => {
|
|
1599
|
+
if (!listeners.delete(listener)) return;
|
|
1600
|
+
if (listeners.size === 0) restorePatch?.();
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// ../tracking-core/src/triggers/scroll-measurement.ts
|
|
1605
|
+
var BOTTOM_EPSILON_PX = 2;
|
|
1606
|
+
function measureScrollPercent() {
|
|
1607
|
+
const root = document.scrollingElement ?? document.documentElement;
|
|
1608
|
+
const scrollHeight = root.scrollHeight;
|
|
1609
|
+
const clientHeight = root.clientHeight;
|
|
1610
|
+
if (scrollHeight <= 0 || clientHeight <= 0) return null;
|
|
1611
|
+
if (scrollHeight <= clientHeight + BOTTOM_EPSILON_PX) return null;
|
|
1612
|
+
const maxTop = scrollHeight - clientHeight;
|
|
1613
|
+
const scrollTop = Math.min(Math.max(root.scrollTop, 0), maxTop);
|
|
1614
|
+
if (scrollTop + clientHeight >= scrollHeight - BOTTOM_EPSILON_PX) return 100;
|
|
1615
|
+
return Math.max(1, Math.min(100, Math.round((scrollTop + clientHeight) / scrollHeight * 100)));
|
|
1616
|
+
}
|
|
1617
|
+
function scheduleBaselineSnapshot(onSnapshot) {
|
|
1618
|
+
let rafId = requestAnimationFrame(() => {
|
|
1619
|
+
rafId = requestAnimationFrame(() => {
|
|
1620
|
+
onSnapshot(measureScrollPercent());
|
|
1621
|
+
});
|
|
1622
|
+
});
|
|
1623
|
+
return () => cancelAnimationFrame(rafId);
|
|
1624
|
+
}
|
|
1625
|
+
function createBaselineGate() {
|
|
1626
|
+
let baselinePercent = null;
|
|
1627
|
+
let ready = false;
|
|
1628
|
+
let cancelSnapshot = null;
|
|
1629
|
+
return {
|
|
1630
|
+
rebaseline() {
|
|
1631
|
+
cancelSnapshot?.();
|
|
1632
|
+
ready = false;
|
|
1633
|
+
baselinePercent = null;
|
|
1634
|
+
cancelSnapshot = scheduleBaselineSnapshot((b) => {
|
|
1635
|
+
baselinePercent = b;
|
|
1636
|
+
ready = true;
|
|
1637
|
+
});
|
|
1638
|
+
},
|
|
1639
|
+
cancel() {
|
|
1640
|
+
cancelSnapshot?.();
|
|
1641
|
+
},
|
|
1642
|
+
baseline() {
|
|
1643
|
+
return ready ? baselinePercent : null;
|
|
1644
|
+
},
|
|
1645
|
+
sample() {
|
|
1646
|
+
if (!ready) return null;
|
|
1647
|
+
if (baselinePercent === null) {
|
|
1648
|
+
baselinePercent = measureScrollPercent();
|
|
1649
|
+
return null;
|
|
1650
|
+
}
|
|
1651
|
+
return measureScrollPercent();
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1536
1656
|
// ../tracking-core/src/triggers/scroll-depth.ts
|
|
1537
1657
|
function attachScrollDepth(client, config) {
|
|
1538
1658
|
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
@@ -1543,17 +1663,14 @@ function attachScrollDepth(client, config) {
|
|
|
1543
1663
|
let firedForPath = /* @__PURE__ */ new Set();
|
|
1544
1664
|
let currentPath2 = window.location.pathname;
|
|
1545
1665
|
let rafId = null;
|
|
1546
|
-
|
|
1547
|
-
const doc = document.documentElement;
|
|
1548
|
-
const scrollTop = window.scrollY || doc.scrollTop;
|
|
1549
|
-
const scrollHeight = doc.scrollHeight;
|
|
1550
|
-
const clientHeight = doc.clientHeight;
|
|
1551
|
-
if (scrollHeight <= clientHeight) return 100;
|
|
1552
|
-
return Math.round((scrollTop + clientHeight) / scrollHeight * 100);
|
|
1553
|
-
}
|
|
1666
|
+
const gate = createBaselineGate();
|
|
1554
1667
|
function checkThresholds() {
|
|
1555
|
-
const percent =
|
|
1668
|
+
const percent = gate.sample();
|
|
1669
|
+
if (percent === null) return;
|
|
1670
|
+
const baseline = gate.baseline();
|
|
1671
|
+
if (baseline === null) return;
|
|
1556
1672
|
for (const threshold of thresholds) {
|
|
1673
|
+
if (threshold <= baseline) continue;
|
|
1557
1674
|
if (percent >= threshold && !firedForPath.has(threshold)) {
|
|
1558
1675
|
firedForPath.add(threshold);
|
|
1559
1676
|
client.trackEvent({
|
|
@@ -1580,28 +1697,15 @@ function attachScrollDepth(client, config) {
|
|
|
1580
1697
|
if (newPath === currentPath2) return;
|
|
1581
1698
|
currentPath2 = newPath;
|
|
1582
1699
|
firedForPath = /* @__PURE__ */ new Set();
|
|
1583
|
-
|
|
1700
|
+
gate.rebaseline();
|
|
1584
1701
|
}
|
|
1585
|
-
const
|
|
1586
|
-
const originalReplaceState = history.replaceState.bind(history);
|
|
1587
|
-
function patchedPushState(...args) {
|
|
1588
|
-
originalPushState(...args);
|
|
1589
|
-
setTimeout(resetIfPathChanged, 0);
|
|
1590
|
-
}
|
|
1591
|
-
function patchedReplaceState(...args) {
|
|
1592
|
-
originalReplaceState(...args);
|
|
1593
|
-
setTimeout(resetIfPathChanged, 0);
|
|
1594
|
-
}
|
|
1595
|
-
history.pushState = patchedPushState;
|
|
1596
|
-
history.replaceState = patchedReplaceState;
|
|
1597
|
-
window.addEventListener("popstate", resetIfPathChanged);
|
|
1702
|
+
const unsubscribeNav = onHistoryChange(resetIfPathChanged);
|
|
1598
1703
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
1599
|
-
|
|
1704
|
+
gate.rebaseline();
|
|
1600
1705
|
return () => {
|
|
1601
1706
|
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
window.removeEventListener("popstate", resetIfPathChanged);
|
|
1707
|
+
gate.cancel();
|
|
1708
|
+
unsubscribeNav();
|
|
1605
1709
|
window.removeEventListener("scroll", onScroll);
|
|
1606
1710
|
};
|
|
1607
1711
|
}
|
|
@@ -1683,21 +1787,14 @@ function attachPageExit(client) {
|
|
|
1683
1787
|
let accumulatedMs = 0;
|
|
1684
1788
|
let maxScrollPercent = null;
|
|
1685
1789
|
let rafId = null;
|
|
1686
|
-
|
|
1687
|
-
const doc = document.documentElement;
|
|
1688
|
-
const scrollTop = window.scrollY || doc.scrollTop;
|
|
1689
|
-
const scrollHeight = doc.scrollHeight;
|
|
1690
|
-
const clientHeight = doc.clientHeight;
|
|
1691
|
-
if (scrollHeight <= clientHeight) return 100;
|
|
1692
|
-
return Math.round((scrollTop + clientHeight) / scrollHeight * 100);
|
|
1693
|
-
}
|
|
1790
|
+
const gate = createBaselineGate();
|
|
1694
1791
|
function onScroll() {
|
|
1695
1792
|
if (rafId !== null) return;
|
|
1696
1793
|
rafId = requestAnimationFrame(() => {
|
|
1697
1794
|
rafId = null;
|
|
1698
|
-
const percent =
|
|
1699
|
-
if (percent
|
|
1700
|
-
maxScrollPercent =
|
|
1795
|
+
const percent = gate.sample();
|
|
1796
|
+
if (percent !== null && (maxScrollPercent === null || percent > maxScrollPercent)) {
|
|
1797
|
+
maxScrollPercent = percent;
|
|
1701
1798
|
}
|
|
1702
1799
|
});
|
|
1703
1800
|
}
|
|
@@ -1716,6 +1813,12 @@ function attachPageExit(client) {
|
|
|
1716
1813
|
metadata: {
|
|
1717
1814
|
dwell_ms: dwell,
|
|
1718
1815
|
max_scroll_percent: maxScrollPercent,
|
|
1816
|
+
// Lets the backend tell "scrolled to the bottom" apart from "the page
|
|
1817
|
+
// was barely scrollable". null = unscrollable page or the segment
|
|
1818
|
+
// ended before the post-paint snapshot landed. For pages that grew
|
|
1819
|
+
// after the snapshot this is the first-scroll position, not the
|
|
1820
|
+
// at-load fraction (see BaselineGate.baseline).
|
|
1821
|
+
scroll_baseline_percent: gate.baseline(),
|
|
1719
1822
|
page: { path }
|
|
1720
1823
|
},
|
|
1721
1824
|
pageUrl: window.location.href,
|
|
@@ -1733,6 +1836,7 @@ function attachPageExit(client) {
|
|
|
1733
1836
|
emitSegment(currentPath2, false);
|
|
1734
1837
|
currentPath2 = newPath;
|
|
1735
1838
|
maxScrollPercent = null;
|
|
1839
|
+
gate.rebaseline();
|
|
1736
1840
|
accumulatedMs = 0;
|
|
1737
1841
|
activeSince = document.visibilityState === "visible" ? Date.now() : null;
|
|
1738
1842
|
}
|
|
@@ -1746,27 +1850,15 @@ function attachPageExit(client) {
|
|
|
1746
1850
|
function onPageHide() {
|
|
1747
1851
|
emitSegment(currentPath2, true);
|
|
1748
1852
|
}
|
|
1749
|
-
const
|
|
1750
|
-
const originalReplaceState = history.replaceState.bind(history);
|
|
1751
|
-
function patchedPushState(...args) {
|
|
1752
|
-
originalPushState(...args);
|
|
1753
|
-
setTimeout(onNavigate, 0);
|
|
1754
|
-
}
|
|
1755
|
-
function patchedReplaceState(...args) {
|
|
1756
|
-
originalReplaceState(...args);
|
|
1757
|
-
setTimeout(onNavigate, 0);
|
|
1758
|
-
}
|
|
1759
|
-
history.pushState = patchedPushState;
|
|
1760
|
-
history.replaceState = patchedReplaceState;
|
|
1761
|
-
window.addEventListener("popstate", onNavigate);
|
|
1853
|
+
const unsubscribeNav = onHistoryChange(onNavigate);
|
|
1762
1854
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
1763
1855
|
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
1764
1856
|
window.addEventListener("pagehide", onPageHide);
|
|
1857
|
+
gate.rebaseline();
|
|
1765
1858
|
return () => {
|
|
1766
1859
|
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
window.removeEventListener("popstate", onNavigate);
|
|
1860
|
+
gate.cancel();
|
|
1861
|
+
unsubscribeNav();
|
|
1770
1862
|
window.removeEventListener("scroll", onScroll);
|
|
1771
1863
|
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1772
1864
|
window.removeEventListener("pagehide", onPageHide);
|
|
@@ -2585,7 +2677,7 @@ function GoogleAdsTracking(props) {
|
|
|
2585
2677
|
import { usePathname, useSearchParams } from "next/navigation";
|
|
2586
2678
|
|
|
2587
2679
|
// package.json
|
|
2588
|
-
var version = "0.17.
|
|
2680
|
+
var version = "0.17.3";
|
|
2589
2681
|
|
|
2590
2682
|
// src/factory.tsx
|
|
2591
2683
|
import {
|
|
@@ -2799,33 +2891,6 @@ function createTracking(options) {
|
|
|
2799
2891
|
});
|
|
2800
2892
|
}
|
|
2801
2893
|
}, [pathname]);
|
|
2802
|
-
useEffect3(() => {
|
|
2803
|
-
const rawClient = getOrCreateTrackingClient({
|
|
2804
|
-
apiKey,
|
|
2805
|
-
endpoint,
|
|
2806
|
-
surface: "next",
|
|
2807
|
-
packageName: "@aranova/tracking-next",
|
|
2808
|
-
triggers,
|
|
2809
|
-
environment,
|
|
2810
|
-
activeGtagIds: gtagIds,
|
|
2811
|
-
debug
|
|
2812
|
-
});
|
|
2813
|
-
return attachBfcacheRestore(wrapClient(rawClient));
|
|
2814
|
-
}, []);
|
|
2815
|
-
useEffect3(() => {
|
|
2816
|
-
if (!timeOnSiteConfig) return;
|
|
2817
|
-
const rawClient = getOrCreateTrackingClient({
|
|
2818
|
-
apiKey,
|
|
2819
|
-
endpoint,
|
|
2820
|
-
surface: "next",
|
|
2821
|
-
packageName: "@aranova/tracking-next",
|
|
2822
|
-
triggers,
|
|
2823
|
-
environment,
|
|
2824
|
-
activeGtagIds: gtagIds,
|
|
2825
|
-
debug
|
|
2826
|
-
});
|
|
2827
|
-
return attachTimeOnSite(wrapClient(rawClient), timeOnSiteConfig);
|
|
2828
|
-
}, []);
|
|
2829
2894
|
const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
|
|
2830
2895
|
const mpsLastPathRef = useRef(null);
|
|
2831
2896
|
useEffect3(() => {
|
|
@@ -2876,7 +2941,6 @@ function createTracking(options) {
|
|
|
2876
2941
|
}
|
|
2877
2942
|
}, [pathname]);
|
|
2878
2943
|
useEffect3(() => {
|
|
2879
|
-
const detachers = [];
|
|
2880
2944
|
const rawClient = getOrCreateTrackingClient({
|
|
2881
2945
|
apiKey,
|
|
2882
2946
|
endpoint,
|
|
@@ -2887,29 +2951,36 @@ function createTracking(options) {
|
|
|
2887
2951
|
activeGtagIds: gtagIds,
|
|
2888
2952
|
debug
|
|
2889
2953
|
});
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
detachers.push(
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
if (ctaClick) {
|
|
2902
|
-
detachers.push(attachCtaClickCapture(detectorClient, ctaClick));
|
|
2903
|
-
}
|
|
2904
|
-
const phoneClick = triggers.manual?.phone_click;
|
|
2905
|
-
if (phoneClick) {
|
|
2906
|
-
detachers.push(attachPhoneClickCapture(detectorClient, phoneClick));
|
|
2907
|
-
}
|
|
2908
|
-
return () => {
|
|
2909
|
-
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
2910
|
-
detachers[i]();
|
|
2954
|
+
return attachClientCapturesOnce(rawClient, () => {
|
|
2955
|
+
const detachers = [];
|
|
2956
|
+
const detectorClient = wrapClient(rawClient);
|
|
2957
|
+
detachers.push(attachPageExit(detectorClient));
|
|
2958
|
+
detachers.push(attachBfcacheRestore(detectorClient));
|
|
2959
|
+
if (timeOnSiteConfig) {
|
|
2960
|
+
detachers.push(attachTimeOnSite(detectorClient, timeOnSiteConfig));
|
|
2961
|
+
}
|
|
2962
|
+
const scrollDepth = triggers.automatic.scroll_depth;
|
|
2963
|
+
if (scrollDepth) {
|
|
2964
|
+
detachers.push(attachScrollDepth(detectorClient, scrollDepth));
|
|
2911
2965
|
}
|
|
2912
|
-
|
|
2966
|
+
const formStart = triggers.automatic.form_start;
|
|
2967
|
+
if (formStart) {
|
|
2968
|
+
detachers.push(attachFormStart(detectorClient, formStart));
|
|
2969
|
+
}
|
|
2970
|
+
const ctaClick = triggers.manual?.cta_click;
|
|
2971
|
+
if (ctaClick) {
|
|
2972
|
+
detachers.push(attachCtaClickCapture(detectorClient, ctaClick));
|
|
2973
|
+
}
|
|
2974
|
+
const phoneClick = triggers.manual?.phone_click;
|
|
2975
|
+
if (phoneClick) {
|
|
2976
|
+
detachers.push(attachPhoneClickCapture(detectorClient, phoneClick));
|
|
2977
|
+
}
|
|
2978
|
+
return () => {
|
|
2979
|
+
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
2980
|
+
detachers[i]();
|
|
2981
|
+
}
|
|
2982
|
+
};
|
|
2983
|
+
});
|
|
2913
2984
|
}, []);
|
|
2914
2985
|
return /* @__PURE__ */ jsxs4(TrackingContext.Provider, { value: client, children: [
|
|
2915
2986
|
/* @__PURE__ */ jsx5(Suspense, { fallback: null, children: /* @__PURE__ */ jsx5(PageViewTracker, { fire: firePageView }) }),
|