1/* 2 * Copyright 2024 Adobe. All rights reserved. 3 * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. You may obtain a copy 5 * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 * 7 * Unless required by applicable law or agreed to in writing, software distributed under 8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 * OF ANY KIND, either express or implied. See the License for the specific language 10 * governing permissions and limitations under the License. 11 */ 12 13// /* eslint-disable max-classes-per-file */ 14(function () { 15 'use strict'; 16 17 /* eslint-env browser */ 18 function sampleRUM(checkpoint, data) { 19 // eslint-disable-next-line max-len 20 const timeShift = () => (window.performance ? window.performance.now() : Date.now() - window.hlx.rum.firstReadTime); 21 try { 22 window.hlx = window.hlx || {}; 23 if (!window.hlx.rum || !window.hlx.rum.collector) { 24 sampleRUM.enhance = () => {}; 25 const params = new URLSearchParams(window.location.search); 26 const { currentScript } = document; 27 const rate = params.get('rum') || window.SAMPLE_PAGEVIEWS_AT_RATE 28 || params.get('optel') || (currentScript && currentScript.dataset.rate); 29 const rateValue = { 30 on: 1, 31 off: 0, 32 high: 10, 33 low: 1000, 34 }[rate]; 35 const weight = rateValue !== undefined ? rateValue : 100; 36 const id = (window.hlx.rum && window.hlx.rum.id) 37 || crypto.randomUUID().slice(-9); 38 const isSelected = (window.hlx.rum && window.hlx.rum.isSelected) 39 || (weight > 0 && Math.random() * weight < 1); 40 // eslint-disable-next-line object-curly-newline, max-len 41 window.hlx.rum = { weight, id, isSelected, firstReadTime: window.performance ? window.performance.timeOrigin : Date.now(), sampleRUM, queue: [], collector: (...args) => window.hlx.rum.queue.push(args) }; 42 if (isSelected) { 43 const dataFromErrorObj = (error) => { 44 const errData = { source: 'undefined error' }; 45 try { 46 errData.target = error.toString(); 47 if (error.stack) { 48 errData.source = error.stack.split('\n') 49 .filter((line) => line.match(/https?:\/\//)).shift() 50 .replace(/at ([^ ]+) \((.+)\)/, '$1@$2') 51 .replace(/ at /, '@') 52 .trim(); 53 } 54 } catch (err) { /* error structure was not as expected */ } 55 return errData; 56 }; 57 58 window.addEventListener('error', ({ error }) => { 59 const errData = dataFromErrorObj(error); 60 sampleRUM('error', errData); 61 }); 62 63 window.addEventListener('unhandledrejection', ({ reason }) => { 64 let errData = { 65 source: 'Unhandled Rejection', 66 target: reason || 'Unknown', 67 }; 68 if (reason instanceof Error) { 69 errData = dataFromErrorObj(reason); 70 } 71 sampleRUM('error', errData); 72 }); 73 74 window.addEventListener('securitypolicyviolation', (e) => { 75 if (e.blockedURI.includes('helix-rum-enhancer') && e.disposition === 'enforce') { 76 const errData = { 77 source: 'csp', 78 target: e.blockedURI, 79 }; 80 sampleRUM.sendPing('error', timeShift(), errData); 81 } 82 }); 83 84 sampleRUM.baseURL = sampleRUM.baseURL || new URL(window.RUM_BASE || '/', new URL('https://rum.hlx.page')); 85 sampleRUM.collectBaseURL = sampleRUM.collectBaseURL || sampleRUM.baseURL; 86 sampleRUM.sendPing = (ck, time, pingData = {}) => { 87 // eslint-disable-next-line max-len, object-curly-newline 88 const rumData = JSON.stringify({ weight, id, referer: window.location.href, checkpoint: ck, t: time, ...pingData }); 89 const urlParams = window.RUM_PARAMS ? (new URLSearchParams(window.RUM_PARAMS).toString() || '') : ''; 90 const { href: url, origin } = new URL(`.rum/${weight}
90${urlParams ? `?${urlParams}` : ''}`, sampleRUM.collectBaseURL); 91 const body = origin === window.location.origin ? new Blob([rumData], { type: 'application/json' }) : rumData; 92 navigator.sendBeacon(url, body); 93 // eslint-disable-next-line no-console 94 console.debug(`ping:${ck}`, pingData); 95 }; 96 sampleRUM.sendPing('top', timeShift()); 97 98 sampleRUM.enhance = () => { 99 // only enhance once 100 if (document.querySelector('script[src*="rum-enhancer"]')) return; 101 const { enhancerVersion, enhancerHash } = sampleRUM.enhancerContext || {}; 102 const script = document.createElement('script'); 103 if (enhancerHash) { 104 script.integrity = enhancerHash; 105 script.setAttribute('crossorigin', 'anonymous'); 106 } 107 script.src = new URL(`.rum/@adobe/helix-rum-enhancer@${enhancerVersion || '^2'}/src/index.js`, sampleRUM.baseURL).href; 108 document.head.appendChild(script); 109 }; 110 if (!window.hlx.RUM_MANUAL_ENHANCE) { 111 sampleRUM.enhance(); 112 } 113 } 114 } 115 if (window.hlx.rum && window.hlx.rum.isSelected && checkpoint) { 116 window.hlx.rum.collector(checkpoint, data, timeShift()); 117 } 118 document.dispatchEvent(new CustomEvent('rum', { detail: { checkpoint, data } })); 119 } catch (error) { 120 // something went awry 121 } 122 } 123 124 try { 125 const scriptSrc = (document.currentScript && document.currentScript.src) 126 ? new URL(document.currentScript.src, window.location.origin).origin : null; 127 // eslint-disable-next-line max-len 128 const dataAttrs = (document.currentScript && document.currentScript.dataset) ? document.currentScript.dataset : {}; 129 const { 130 postPath, status, enhancerVersion, enhancerHash, ...scriptParams 131 } = dataAttrs; 132 const base = scriptSrc && postPath ? new URL(postPath, scriptSrc) : scriptSrc; 133 sampleRUM.enhancerContext = { enhancerVersion, enhancerHash }; 134 window.RUM_BASE = window.RUM_BASE || base; 135 window.RUM_PARAMS = window.RUM_PARAMS || scriptParams; 136 137 const [navigation] = (window.performance && window.performance.getEntriesByType('navigation')) || []; 138 const is404 = status === '404' || (navigation && navigation.name === window.location.href 139 && navigation.responseStatus === 404); 140 141 if (is404) { 142 sampleRUM('404', { source: document.referrer }); 143 } else { 144 sampleRUM(); 145 } 146 } catch (error) { 147 // something went wrong 148 } 149}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.