diff --git a/CHANGELOG.md b/CHANGELOG.md index e58069e..98c690f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.5.3](https://github.com/adobe/aem-lib/compare/v1.5.2...v1.5.3) (2024-04-17) + + +### Bug Fixes + +* **package): Revert "fix(deps:** update dependency @adobe/helix-rum-js to v2" ([a0a54a9](https://github.com/adobe/aem-lib/commit/a0a54a93e6c4fb2ba9e2405e51f9535967121dc5)) + ## [1.5.2](https://github.com/adobe/aem-lib/compare/v1.5.1...v1.5.2) (2024-04-17) diff --git a/dist/aem.js b/dist/aem.js index 2bff8f0..3aef990 100644 --- a/dist/aem.js +++ b/dist/aem.js @@ -11,63 +11,135 @@ */ /* eslint-env browser */ -function sampleRUM(checkpoint, data) { - // eslint-disable-next-line max-len - const timeShift = () => (window.performance ? window.performance.now() : Date.now() - window.hlx.rum.firstReadTime); + +/** + * log RUM if part of the sample. + * @param {string} checkpoint identifies the checkpoint in funnel + * @param {Object} data additional data for RUM sample + * @param {string} data.source DOM node that is the source of a checkpoint event, + * identified by #id or .classname + * @param {string} data.target subject of the checkpoint event, + * for instance the href of a link, or a search term + */ +function sampleRUM(checkpoint, data = {}) { const SESSION_STORAGE_KEY = 'aem-rum'; + sampleRUM.baseURL = sampleRUM.baseURL + || new URL(window.RUM_BASE == null ? 'https://rum.hlx.page' : window.RUM_BASE, window.location); + sampleRUM.defer = sampleRUM.defer || []; + const defer = (fnname) => { + sampleRUM[fnname] = sampleRUM[fnname] || ((...args) => sampleRUM.defer.push({ fnname, args })); + }; + sampleRUM.drain = sampleRUM.drain + || ((dfnname, fn) => { + sampleRUM[dfnname] = fn; + sampleRUM.defer + .filter(({ fnname }) => dfnname === fnname) + .forEach(({ fnname, args }) => sampleRUM[fnname](...args)); + }); + sampleRUM.always = sampleRUM.always || []; + sampleRUM.always.on = (chkpnt, fn) => { + sampleRUM.always[chkpnt] = fn; + }; + sampleRUM.on = (chkpnt, fn) => { + sampleRUM.cases[chkpnt] = fn; + }; + defer('observe'); + defer('cwv'); try { window.hlx = window.hlx || {}; if (!window.hlx.rum) { - // eslint-disable-next-line max-len - const rumStorage = sessionStorage.getItem(SESSION_STORAGE_KEY) - ? JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEY)) - : {}; - rumStorage.pages = (rumStorage.pages ?? 0) + (Math.floor(Math.random() * 20) - 10) + 1; - sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(rumStorage)); - sampleRUM.baseURL = sampleRUM.baseURL - || new URL( - window.RUM_BASE == null ? 'https://rum.hlx.page' : window.RUM_BASE, - window.location, - ); - const weight = new URLSearchParams(window.location.search).get('rum') === 'on' ? 1 : 100; + const usp = new URLSearchParams(window.location.search); + const weight = usp.get('rum') === 'on' ? 1 : 100; // with parameter, weight is 1. Defaults to 100. const id = Array.from({ length: 75 }, (_, i) => String.fromCharCode(48 + i)) .filter((a) => /\d|[A-Z]/i.test(a)) .filter(() => Math.random() * 75 > 70) .join(''); - const isSelected = Math.random() * weight < 1; + const random = Math.random(); + const isSelected = random * weight < 1; + const firstReadTime = window.performance ? window.performance.timeOrigin : Date.now(); + const urlSanitizers = { + full: () => window.location.href, + origin: () => window.location.origin, + path: () => window.location.href.replace(/\?.*$/, ''), + }; + // eslint-disable-next-line max-len + const rumSessionStorage = sessionStorage.getItem(SESSION_STORAGE_KEY) + ? JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEY)) + : {}; + // eslint-disable-next-line max-len + rumSessionStorage.pages = (rumSessionStorage.pages ? rumSessionStorage.pages : 0) + + 1 + /* noise */ + (Math.floor(Math.random() * 20) - 10); + sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(rumSessionStorage)); // eslint-disable-next-line object-curly-newline, max-len window.hlx.rum = { weight, id, + random, isSelected, - firstReadTime: window.performance ? window.performance.timeOrigin : Date.now(), + firstReadTime, sampleRUM, - queue: [], - collector: (...args) => window.hlx.rum.queue.push(args), + sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'], + rumSessionStorage, }; - if (isSelected) { - // eslint-disable-next-line object-curly-newline, max-len - const body = JSON.stringify({ - weight, - id, - referer: window.location.href, - checkpoint: 'top', - t: timeShift(), - target: document.visibilityState, - }); + } + + const { weight, id, firstReadTime } = window.hlx.rum; + if (window.hlx && window.hlx.rum && window.hlx.rum.isSelected) { + const knownProperties = [ + 'weight', + 'id', + 'referer', + 'checkpoint', + 't', + 'source', + 'target', + 'cwv', + 'CLS', + 'FID', + 'LCP', + 'INP', + 'TTFB', + ]; + const sendPing = (pdata = data) => { + // eslint-disable-next-line max-len + const t = Math.round( + window.performance ? window.performance.now() : Date.now() - firstReadTime, + ); + // eslint-disable-next-line object-curly-newline, max-len, no-use-before-define + const body = JSON.stringify( + { + weight, id, referer: window.hlx.rum.sanitizeURL(), checkpoint, t, ...data, + }, + knownProperties, + ); const url = new URL(`.rum/${weight}`, sampleRUM.baseURL).href; navigator.sendBeacon(url, body); - // eslint-disable-next-line max-statements-per-line, brace-style - window.addEventListener('load', () => { - sampleRUM('load'); - import(new URL('.rum/@adobe/helix-rum-enhancer@^2/src/index.js', sampleRUM.baseURL)); - }); + // eslint-disable-next-line no-console + console.debug(`ping:${checkpoint}`, pdata); + }; + sampleRUM.cases = sampleRUM.cases || { + load: () => sampleRUM('pagesviewed', { source: window.hlx.rum.rumSessionStorage.pages }) || true, + cwv: () => sampleRUM.cwv(data) || true, + lazy: () => { + // use classic script to avoid CORS issues + const script = document.createElement('script'); + script.src = new URL( + '.rum/@adobe/helix-rum-enhancer@^1/src/index.js', + sampleRUM.baseURL, + ).href; + document.head.appendChild(script); + return true; + }, + }; + sendPing(data); + if (sampleRUM.cases[checkpoint]) { + sampleRUM.cases[checkpoint](); } } - if (window.hlx.rum && window.hlx.rum.isSelected && checkpoint) { - window.hlx.rum.collector(checkpoint, data, timeShift()); + if (sampleRUM.always[checkpoint]) { + sampleRUM.always[checkpoint](data); } - document.dispatchEvent(new CustomEvent('rum', { detail: { checkpoint, data } })); } catch (error) { // something went wrong } diff --git a/package-lock.json b/package-lock.json index e493ea4..6e1a62e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/aem-lib", - "version": "1.5.2", + "version": "1.5.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/aem-lib", - "version": "1.5.2", + "version": "1.5.3", "license": "Apache License 2.0", "dependencies": { "@adobe/helix-rum-js": "1.8.0" diff --git a/package.json b/package.json index 71801fc..3721da7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/aem-lib", - "version": "1.5.2", + "version": "1.5.3", "description": "AEM Library", "type": "module", "scripts": {