@adobe/helix-rum-enhancer 2.47.3 → 2.49.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/CHANGELOG.md +15 -0
- package/modules/defaults.js +1 -1
- package/modules/dom.js +21 -13
- package/modules/index.js +46 -44
- package/package.json +10 -10
- package/plugins/cwv.js +11 -0
- package/plugins/webcomponent.js +3 -1
- package/src/index.js +66 -55
- package/src/index.md5 +1 -1
- package/src/index.sri +1 -1
- package/src/plugins/cwv.js +21 -13
- package/src/plugins/cwv.map.js +22 -14
- package/src/plugins/cwv.md5 +1 -1
- package/src/plugins/form.md5 +1 -1
- package/src/plugins/onetrust.md5 +1 -1
- package/src/plugins/usercentrics.md5 +1 -1
- package/src/plugins/video.md5 +1 -1
- package/src/plugins/webcomponent.js +3 -1
- package/src/plugins/webcomponent.map.js +4 -2
- package/src/plugins/webcomponent.md5 +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# [2.49.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.48.0...v2.49.0) (2026-07-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* flag untrusted (synthetic) clicks as bots ([94b2893](https://github.com/adobe/helix-rum-enhancer/commit/94b289333d0c8a33435752c8f48f080b5dfa203d))
|
|
7
|
+
|
|
8
|
+
# [2.48.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.47.3...v2.48.0) (2026-07-08)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* report source for the largest CLS layout shift ([53a0432](https://github.com/adobe/helix-rum-enhancer/commit/53a04321044b444b8f883b63f71dd4394814877b))
|
|
14
|
+
* report source for the largest CLS layout shift ([a74c6f4](https://github.com/adobe/helix-rum-enhancer/commit/a74c6f453b639504b82874750d247b27c5a78f21))
|
|
15
|
+
|
|
1
16
|
## [2.47.3](https://github.com/adobe/helix-rum-enhancer/compare/v2.47.2...v2.47.3) (2026-05-13)
|
|
2
17
|
|
|
3
18
|
|
package/modules/defaults.js
CHANGED
|
@@ -11,6 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { fflags } from './fflags.js';
|
|
13
13
|
|
|
14
|
-
export const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
|
|
14
|
+
export const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB', 'ua'];
|
|
15
15
|
export const DEFAULT_TRACKING_EVENTS = ['click', 'cwv', 'form', 'viewblock', 'viewmedia', 'loadresource', 'utm', 'paid', 'email', 'consent'];
|
|
16
16
|
fflags.enabled('example', () => DEFAULT_TRACKING_EVENTS.push('example'));
|
package/modules/dom.js
CHANGED
|
@@ -32,12 +32,20 @@ export const targetSelector = (el) => {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
export const untrustedClickPayload = (event) => {
|
|
36
|
+
if (event && event.isTrusted === false) {
|
|
37
|
+
const ua = navigator.userAgent;
|
|
38
|
+
return { ua: ua.includes('+http') ? ua : `${ua} +http://event.untrusted` };
|
|
39
|
+
}
|
|
40
|
+
return {};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function walk(el, check) {
|
|
36
44
|
if (!el || el === document.body || el === document.documentElement) {
|
|
37
45
|
return undefined;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
|
-
return
|
|
48
|
+
return check(el) || walk(el.parentElement || (el.parentNode && el.parentNode.host), check);
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
function isDialog(el) {
|
|
@@ -53,19 +61,19 @@ function isButton(el) {
|
|
|
53
61
|
return true;
|
|
54
62
|
}
|
|
55
63
|
if (el.tagName === 'A') {
|
|
56
|
-
return Array.from(el.classList).some((
|
|
64
|
+
return Array.from(el.classList).some((cls) => cls.match(/button|cta/));
|
|
57
65
|
}
|
|
58
66
|
return el.getAttribute('role') === 'button';
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
function
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
const id =
|
|
69
|
+
function srcContext(el) {
|
|
70
|
+
const form = el.closest('form');
|
|
71
|
+
if (form) {
|
|
72
|
+
const id = form.getAttribute('id');
|
|
65
73
|
if (id) {
|
|
66
74
|
return `form#${CSS.escape(id)}`;
|
|
67
75
|
}
|
|
68
|
-
return `form${
|
|
76
|
+
return `form${form.classList.length > 0 ? `.${CSS.escape(form.classList[0])}` : ''}`;
|
|
69
77
|
}
|
|
70
78
|
const block = el.closest('.block[data-block-name]');
|
|
71
79
|
return ((block && `.${block.getAttribute('data-block-name')}`)
|
|
@@ -75,7 +83,7 @@ function getSourceContext(el) {
|
|
|
75
83
|
|| walk(el, (e) => e.id && `#${CSS.escape(e.id)}`));
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
function
|
|
86
|
+
function srcElement(el) {
|
|
79
87
|
const f = el.closest('form');
|
|
80
88
|
if (f && Array.from(f.elements).includes(el)) {
|
|
81
89
|
return (el.tagName.toLowerCase()
|
|
@@ -87,7 +95,7 @@ function getSourceElement(el) {
|
|
|
87
95
|
|| (el.tagName.toLowerCase().match(/^(a|img|video|form)$/) && el.tagName.toLowerCase());
|
|
88
96
|
}
|
|
89
97
|
|
|
90
|
-
function
|
|
98
|
+
function srcId(el) {
|
|
91
99
|
return (el.id && `#${CSS.escape(el.id)}`)
|
|
92
100
|
|| (el.getAttribute('data-block-name') && `.${el.getAttribute('data-block-name')}`)
|
|
93
101
|
|| (el.classList.length > 0 && `.${CSS.escape(el.classList[0])}`);
|
|
@@ -101,9 +109,9 @@ export const sourceSelector = (el) => {
|
|
|
101
109
|
if (el.getAttribute('data-rum-source')) {
|
|
102
110
|
return el.getAttribute('data-rum-source');
|
|
103
111
|
}
|
|
104
|
-
const ctx =
|
|
105
|
-
const name =
|
|
106
|
-
const id =
|
|
112
|
+
const ctx = srcContext(el.parentElement) || '';
|
|
113
|
+
const name = srcElement(el) || '';
|
|
114
|
+
const id = srcId(el) || '';
|
|
107
115
|
return `${ctx} ${name}${id}`.trim() || `"${el.textContent.substring(0, 10)}"`;
|
|
108
116
|
/* c8 ignore next 3 */
|
|
109
117
|
} catch (error) {
|
package/modules/index.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { KNOWN_PROPERTIES, DEFAULT_TRACKING_EVENTS } from './defaults.js';
|
|
15
15
|
import { urlSanitizers } from './utils.js';
|
|
16
|
-
import { targetSelector, sourceSelector } from './dom.js';
|
|
16
|
+
import { targetSelector, sourceSelector, untrustedClickPayload } from './dom.js';
|
|
17
17
|
import { fflags } from './fflags.js';
|
|
18
18
|
|
|
19
19
|
const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum
|
|
@@ -27,19 +27,19 @@ const createMO = (cb) => (window.MutationObserver ? new MutationObserver(cb)
|
|
|
27
27
|
const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO);
|
|
28
28
|
|
|
29
29
|
// Check for the presence of a given cookie
|
|
30
|
-
const
|
|
30
|
+
const hasCookie = (key) => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`));
|
|
31
31
|
|
|
32
32
|
// Set the base path for the plugins
|
|
33
|
-
const
|
|
33
|
+
const pluginBase = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins');
|
|
34
34
|
|
|
35
35
|
const CONSENT_PROVIDERS = [
|
|
36
36
|
{
|
|
37
37
|
name: 'onetrust',
|
|
38
|
-
detect: () =>
|
|
38
|
+
detect: () => hasCookie('OptanonAlertBoxClosed') || document.querySelector('#onetrust-banner-sdk, #onetrust-pc-sdk'),
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
name: 'trustarc',
|
|
42
|
-
detect: () => ['notice_gdpr_prefs', 'notice_preferences'].some(
|
|
42
|
+
detect: () => ['notice_gdpr_prefs', 'notice_preferences'].some(hasCookie) || document.querySelector('#truste-consent-track'),
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
name: 'usercentrics',
|
|
@@ -47,40 +47,40 @@ const CONSENT_PROVIDERS = [
|
|
|
47
47
|
},
|
|
48
48
|
];
|
|
49
49
|
|
|
50
|
-
const
|
|
50
|
+
const getConsent = () => CONSENT_PROVIDERS.find(({ detect }) => detect());
|
|
51
51
|
const bodyChildMO = {
|
|
52
52
|
target: document.body,
|
|
53
53
|
options: { attributes: false, childList: true, subtree: false },
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
const PLUGINS = {
|
|
57
|
-
cwv: `${
|
|
58
|
-
a11y: `${
|
|
57
|
+
cwv: `${pluginBase}/cwv.js`,
|
|
58
|
+
a11y: `${pluginBase}/a11y.js`,
|
|
59
59
|
// Interactive elements
|
|
60
60
|
form: {
|
|
61
|
-
url: `${
|
|
61
|
+
url: `${pluginBase}/form.js`,
|
|
62
62
|
when: () => document.querySelector('form'),
|
|
63
63
|
isBlockDependent: true,
|
|
64
|
-
|
|
64
|
+
moParams: bodyChildMO,
|
|
65
65
|
},
|
|
66
66
|
redirect: {
|
|
67
|
-
url: `${
|
|
67
|
+
url: `${pluginBase}/redirect.js`,
|
|
68
68
|
when: ({ perfEntry: pe, urlParameters: usp }) => (
|
|
69
69
|
pe && (usp.get('redirect_from') || pe.redirectCount > 0 || pe.fetchStart > 50)
|
|
70
70
|
),
|
|
71
71
|
},
|
|
72
|
-
video: { url: `${
|
|
72
|
+
video: { url: `${pluginBase}/video.js`, when: () => document.querySelector('video'), isBlockDependent: true },
|
|
73
73
|
webcomponent: {
|
|
74
|
-
url: `${
|
|
74
|
+
url: `${pluginBase}/webcomponent.js`,
|
|
75
75
|
when: () => [...document.querySelectorAll('*')].some((el) => el.tagName && el.tagName.includes('-')),
|
|
76
76
|
isBlockDependent: true,
|
|
77
77
|
},
|
|
78
78
|
// Martech
|
|
79
|
-
martech: { url: `${
|
|
79
|
+
martech: { url: `${pluginBase}/martech.js`, when: ({ urlParameters }) => urlParameters.size > 0 },
|
|
80
80
|
consent: {
|
|
81
|
-
when: () =>
|
|
81
|
+
when: () => getConsent(),
|
|
82
82
|
isBlockDependent: true,
|
|
83
|
-
|
|
83
|
+
moParams: bodyChildMO,
|
|
84
84
|
},
|
|
85
85
|
// test: broken-plugin
|
|
86
86
|
};
|
|
@@ -94,12 +94,12 @@ function getIntersectionObserver(checkpoint) {
|
|
|
94
94
|
if (!window.IntersectionObserver) {
|
|
95
95
|
return null;
|
|
96
96
|
}
|
|
97
|
-
const
|
|
97
|
+
const obs = new IntersectionObserver((entries) => {
|
|
98
98
|
try {
|
|
99
99
|
entries
|
|
100
100
|
.filter((e) => e.isIntersecting)
|
|
101
101
|
.forEach((e) => {
|
|
102
|
-
|
|
102
|
+
obs.unobserve(e.target); // observe only once
|
|
103
103
|
const target = targetSelector(e.target);
|
|
104
104
|
const source = sourceSelector(e.target);
|
|
105
105
|
if (checkpoint === 'viewmedia') {
|
|
@@ -118,15 +118,16 @@ function getIntersectionObserver(checkpoint) {
|
|
|
118
118
|
// something went wrong
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
|
-
return
|
|
121
|
+
return obs;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
const
|
|
124
|
+
const PLUGIN_PARAMS = {
|
|
125
125
|
context: document.body,
|
|
126
126
|
fflags,
|
|
127
127
|
sampleRUM,
|
|
128
128
|
sourceSelector,
|
|
129
129
|
targetSelector,
|
|
130
|
+
untrustedClickPayload,
|
|
130
131
|
getIntersectionObserver,
|
|
131
132
|
createMO,
|
|
132
133
|
};
|
|
@@ -137,14 +138,14 @@ function loadPlugin(key, params) {
|
|
|
137
138
|
const plugin = PLUGINS[key];
|
|
138
139
|
const usp = new URLSearchParams(window.location.search);
|
|
139
140
|
if (!pluginCache.has(key) && plugin.when && !plugin.when({ ...params, urlParameters: usp })) {
|
|
140
|
-
if (plugin.
|
|
141
|
+
if (plugin.moParams && !plugin.isBeingObserved) {
|
|
141
142
|
// eslint-disable-next-line no-use-before-define
|
|
142
143
|
createPluginMO(key, params, usp);
|
|
143
144
|
}
|
|
144
145
|
return null;
|
|
145
146
|
}
|
|
146
147
|
if (key === 'consent') {
|
|
147
|
-
plugin.url = `${
|
|
148
|
+
plugin.url = `${pluginBase}/${getConsent().name}.js`;
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
if (!pluginCache.has(key)) {
|
|
@@ -156,7 +157,7 @@ function loadPlugin(key, params) {
|
|
|
156
157
|
.catch(() => { /* silent plugin error catching */ });
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
function loadPlugins(filter = () => true, params =
|
|
160
|
+
function loadPlugins(filter = () => true, params = PLUGIN_PARAMS) {
|
|
160
161
|
Object.entries(PLUGINS)
|
|
161
162
|
.filter(([, plugin]) => filter(plugin))
|
|
162
163
|
.map(([key]) => loadPlugin(key, params));
|
|
@@ -164,19 +165,19 @@ function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) {
|
|
|
164
165
|
|
|
165
166
|
function createPluginMO(key, params, usp) {
|
|
166
167
|
const plugin = PLUGINS[key];
|
|
167
|
-
const
|
|
168
|
+
const obs = createMO(() => {
|
|
168
169
|
if (plugin.when({ urlParameters: usp })) {
|
|
169
170
|
plugin.isBeingObserved = false;
|
|
170
|
-
|
|
171
|
+
obs.disconnect();
|
|
171
172
|
loadPlugin(key, params);
|
|
172
173
|
}
|
|
173
174
|
});
|
|
174
175
|
|
|
175
|
-
if (
|
|
176
|
+
if (obs instanceof MutationObserver) {
|
|
176
177
|
plugin.isBeingObserved = true;
|
|
177
|
-
|
|
178
|
-
plugin.
|
|
179
|
-
plugin.
|
|
178
|
+
obs.observe(
|
|
179
|
+
plugin.moParams.target,
|
|
180
|
+
plugin.moParams.options,
|
|
180
181
|
);
|
|
181
182
|
}
|
|
182
183
|
}
|
|
@@ -242,7 +243,7 @@ function addNavigationTracking() {
|
|
|
242
243
|
} else {
|
|
243
244
|
sampleRUM('enter', payload); // enter site
|
|
244
245
|
}
|
|
245
|
-
loadPlugin('redirect', { ...
|
|
246
|
+
loadPlugin('redirect', { ...PLUGIN_PARAMS, perfEntry });
|
|
246
247
|
};
|
|
247
248
|
const processed = new Set(); // avoid processing duplicate types
|
|
248
249
|
new PerformanceObserver((list) => list
|
|
@@ -257,7 +258,7 @@ function addNavigationTracking() {
|
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
function addLoadResourceTracking() {
|
|
260
|
-
const
|
|
261
|
+
const obs = new PerformanceObserver((list) => {
|
|
261
262
|
try {
|
|
262
263
|
const entries = list.getEntries();
|
|
263
264
|
entries
|
|
@@ -265,14 +266,14 @@ function addLoadResourceTracking() {
|
|
|
265
266
|
.filter((e) => window.location.hostname === new URL(e.name).hostname || fflags.has('allresources'))
|
|
266
267
|
.filter((e) => {
|
|
267
268
|
const { pathname, hostname } = new URL(e.name);
|
|
268
|
-
const
|
|
269
|
+
const extMatch = pathname.match(
|
|
269
270
|
hostname !== window.location.hostname
|
|
270
271
|
? '.*(\\.html$|\\.json|\\.js|graphql|api)'
|
|
271
272
|
: '.*(\\.plain\\.html$|\\.json|graphql|api)',
|
|
272
273
|
);
|
|
273
274
|
const isDropIn = fflags.has('allresources') && (pathname.includes('__dropins__/storefront-') || pathname.includes('scripts/dropins/storefront-'));
|
|
274
275
|
const isImage = fflags.has('allresources') && pathname.match(/\.(png|jpe?g|svg)$/i);
|
|
275
|
-
return
|
|
276
|
+
return extMatch || isDropIn || isImage;
|
|
276
277
|
})
|
|
277
278
|
.forEach((e) => {
|
|
278
279
|
sampleRUM('loadresource', { source: e.name, target: Math.round(e.duration) });
|
|
@@ -288,7 +289,7 @@ function addLoadResourceTracking() {
|
|
|
288
289
|
// something went wrong
|
|
289
290
|
}
|
|
290
291
|
});
|
|
291
|
-
|
|
292
|
+
obs.observe({ type: 'resource', buffered: true });
|
|
292
293
|
}
|
|
293
294
|
|
|
294
295
|
// activate blocks mutation observer
|
|
@@ -317,22 +318,22 @@ function activateMediaMO() {
|
|
|
317
318
|
);
|
|
318
319
|
}
|
|
319
320
|
|
|
320
|
-
function addViewBlockTracking(
|
|
321
|
-
const
|
|
322
|
-
if (
|
|
323
|
-
const blocks =
|
|
324
|
-
blocks.forEach((b) =>
|
|
321
|
+
function addViewBlockTracking(el) {
|
|
322
|
+
const blockObs = getIntersectionObserver('viewblock');
|
|
323
|
+
if (blockObs) {
|
|
324
|
+
const blocks = el.getAttribute('data-block-status') ? [el] : el.querySelectorAll('div[data-block-status="loaded"]');
|
|
325
|
+
blocks.forEach((b) => blockObs.observe(b));
|
|
325
326
|
}
|
|
326
327
|
}
|
|
327
328
|
|
|
328
329
|
const observedMedia = new Set();
|
|
329
330
|
function addViewMediaTracking(parent) {
|
|
330
|
-
const
|
|
331
|
-
if (
|
|
331
|
+
const mediaObs = getIntersectionObserver('viewmedia');
|
|
332
|
+
if (mediaObs) {
|
|
332
333
|
parent.querySelectorAll('img, video, audio, iframe').forEach((m) => {
|
|
333
334
|
if (!observedMedia.has(m)) {
|
|
334
335
|
observedMedia.add(m);
|
|
335
|
-
|
|
336
|
+
mediaObs.observe(m);
|
|
336
337
|
}
|
|
337
338
|
});
|
|
338
339
|
}
|
|
@@ -349,7 +350,7 @@ function blocksMCB(mutations) {
|
|
|
349
350
|
.filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
|
|
350
351
|
.filter((m) => m.target.dataset.blockStatus === 'loaded')
|
|
351
352
|
.forEach((m) => {
|
|
352
|
-
addObserver('form', (el) => loadPlugins((p) => p.isBlockDependent, { ...
|
|
353
|
+
addObserver('form', (el) => loadPlugins((p) => p.isBlockDependent, { ...PLUGIN_PARAMS, context: el }), m.target);
|
|
353
354
|
addObserver('viewblock', addViewBlockTracking, m.target);
|
|
354
355
|
});
|
|
355
356
|
}
|
|
@@ -371,7 +372,8 @@ function addTrackingFromConfig() {
|
|
|
371
372
|
if (event.optelHandled) {
|
|
372
373
|
return;
|
|
373
374
|
}
|
|
374
|
-
|
|
375
|
+
// eslint-disable-next-line max-len
|
|
376
|
+
sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target), ...untrustedClickPayload(event) });
|
|
375
377
|
});
|
|
376
378
|
|
|
377
379
|
// Core tracking
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-rum-enhancer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.49.0",
|
|
4
4
|
"description": "Helix RUM Enhancer",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"reporter-options": "configFile=.mocha-multi.json"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@adobe/eslint-config-helix": "3.0.
|
|
37
|
-
"@adobe/helix-rum-js": "2.
|
|
36
|
+
"@adobe/eslint-config-helix": "3.0.28",
|
|
37
|
+
"@adobe/helix-rum-js": "2.15.3",
|
|
38
38
|
"@adobe/rollup-plugin-checksum": "1.2.0",
|
|
39
|
-
"@eslint/config-helpers": "0.
|
|
39
|
+
"@eslint/config-helpers": "0.6.0",
|
|
40
40
|
"@esm-bundle/chai": "4.3.4-fix.0",
|
|
41
|
-
"@rollup/plugin-babel": "7.
|
|
41
|
+
"@rollup/plugin-babel": "7.1.0",
|
|
42
42
|
"@semantic-release/changelog": "6.0.3",
|
|
43
43
|
"@semantic-release/exec": "7.1.0",
|
|
44
44
|
"@semantic-release/git": "10.0.1",
|
|
@@ -53,18 +53,18 @@
|
|
|
53
53
|
"eslint": "9.30.1",
|
|
54
54
|
"eslint-plugin-header": "3.1.1",
|
|
55
55
|
"eslint-plugin-import": "2.32.0",
|
|
56
|
-
"globals": "17.
|
|
56
|
+
"globals": "17.6.0",
|
|
57
57
|
"husky": "9.1.7",
|
|
58
58
|
"jsdoc-to-markdown": "9.1.3",
|
|
59
59
|
"junit-report-builder": "5.1.2",
|
|
60
60
|
"lint-staged": "16.4.0",
|
|
61
|
-
"mocha": "11.7.
|
|
61
|
+
"mocha": "11.7.6",
|
|
62
62
|
"mocha-multi-reporters": "1.5.1",
|
|
63
|
-
"rollup": "4.
|
|
63
|
+
"rollup": "4.62.2",
|
|
64
64
|
"rollup-plugin-eslint-bundle": "9.0.0",
|
|
65
|
-
"semantic-release": "25.0.
|
|
65
|
+
"semantic-release": "25.0.5",
|
|
66
66
|
"semantic-release-slack-bot": "^4.0.2",
|
|
67
|
-
"web-vitals": "5.
|
|
67
|
+
"web-vitals": "5.3.0"
|
|
68
68
|
},
|
|
69
69
|
"lint-staged": {
|
|
70
70
|
"*.js": "eslint",
|
package/plugins/cwv.js
CHANGED
|
@@ -35,6 +35,17 @@ export default function addCWVTracking({
|
|
|
35
35
|
data.target = targetSelector(element);
|
|
36
36
|
data.source = sourceSelector(element) || (element && element.outerHTML.slice(0, 30));
|
|
37
37
|
}
|
|
38
|
+
if (measurement.name === 'CLS' && measurement.entries.length > 0) {
|
|
39
|
+
// Attribute CLS to the element of the single largest layout shift
|
|
40
|
+
// (mirrors web-vitals' `largestShiftTarget`, derived from the standard entries).
|
|
41
|
+
const largest = measurement.entries
|
|
42
|
+
.reduce((a, b) => (b.value > (a ? a.value : 0) ? b : a), undefined);
|
|
43
|
+
const node = largest && largest.sources
|
|
44
|
+
&& largest.sources.map((s) => s.node).find((n) => n && n.nodeType === 1);
|
|
45
|
+
if (node) {
|
|
46
|
+
data.source = sourceSelector(node) || node.outerHTML.slice(0, 30);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
38
49
|
sampleRUM('cwv', data);
|
|
39
50
|
};
|
|
40
51
|
|
package/plugins/webcomponent.js
CHANGED
|
@@ -23,6 +23,7 @@ export default function addWebComponentTracking({
|
|
|
23
23
|
sampleRUM,
|
|
24
24
|
sourceSelector,
|
|
25
25
|
targetSelector,
|
|
26
|
+
untrustedClickPayload,
|
|
26
27
|
createMO,
|
|
27
28
|
}) {
|
|
28
29
|
/**
|
|
@@ -90,7 +91,8 @@ export default function addWebComponentTracking({
|
|
|
90
91
|
}
|
|
91
92
|
// eslint-disable-next-line no-param-reassign
|
|
92
93
|
event.optelHandled = true;
|
|
93
|
-
|
|
94
|
+
// eslint-disable-next-line max-len
|
|
95
|
+
sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target), ...untrustedClickPayload(event) });
|
|
94
96
|
});
|
|
95
97
|
}
|
|
96
98
|
// look for web components below this element
|