diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e9150a..7482ac57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +**2.55.1** (27 Aug 2024) +- Adds a minimum recording length option for session recording +- Fixes and improvements for session recording batcher to support offline queueing and retry + **2.55.0** (2 Aug 2024) - Added new build to support native JavaScript modules diff --git a/dist/mixpanel-core.cjs.js b/dist/mixpanel-core.cjs.js index 48dd54d1..e0d99c30 100644 --- a/dist/mixpanel-core.cjs.js +++ b/dist/mixpanel-core.cjs.js @@ -2,7 +2,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -14,7 +14,7 @@ if (typeof(window) === 'undefined') { hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -968,7 +968,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) { _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -1425,8 +1425,8 @@ _.dom_query = (function() { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -1708,6 +1708,15 @@ var extract_domain = function(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -2523,7 +2532,12 @@ RequestBatcher.prototype.flush = function(options) { this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -4247,6 +4261,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/dist/mixpanel-recorder.js b/dist/mixpanel-recorder.js index f3e1a48c..6c34bf47 100644 --- a/dist/mixpanel-recorder.js +++ b/dist/mixpanel-recorder.js @@ -4510,7 +4510,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4522,7 +4522,7 @@ hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4536,6 +4536,8 @@ // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours + // Maximum allowed value for minimum session recording length + var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5447,7 +5449,7 @@ _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5904,8 +5906,8 @@ }; })(); - var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; - var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; + var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; + var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6187,6 +6189,15 @@ return matches ? matches[0] : ''; }; + /** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ + var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; + }; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7018,7 +7029,12 @@ this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7169,6 +7185,7 @@ this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7200,16 +7217,24 @@ logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7223,11 +7248,16 @@ }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7235,7 +7265,7 @@ } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7289,14 +7319,14 @@ } }; - MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { + MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7319,7 +7349,7 @@ callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7327,9 +7357,15 @@ const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7338,7 +7374,7 @@ 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7361,11 +7397,11 @@ .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); diff --git a/dist/mixpanel-recorder.min.js b/dist/mixpanel-recorder.min.js index ea2c33e1..0197d859 100644 --- a/dist/mixpanel-recorder.min.js +++ b/dist/mixpanel-recorder.min.js @@ -1,6 +1,6 @@ -(function(){"use strict";var A;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(A||(A={}));function Sr(e){return e.nodeType===e.ELEMENT_NODE}function be(e){const t=e?.host;return t?.shadowRoot===e}function we(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function br(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function wr(e){const{cssText:t}=e;if(t.split('"').length<3)return t;const r=["@import",`url(${JSON.stringify(e.href)})`];return e.layerName===""?r.push("layer"):e.layerName&&r.push(`layer(${e.layerName})`),e.supportsText&&r.push(`supports(${e.supportsText})`),e.media.length&&r.push(e.media.mediaText),r.join(" ")+";"}function Te(e){try{const t=e.rules||e.cssRules;return t?br(Array.from(t,St).join("")):null}catch{return null}}function St(e){let t;if(Mr(e))try{t=Te(e.styleSheet)||wr(e)}catch{}else if(Cr(e)&&e.selectorText.includes(":"))return Ir(e.cssText);return t||e.cssText}function Ir(e){const t=/(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;return e.replace(t,"$1\\$2")}function Mr(e){return"styleSheet"in e}function Cr(e){return"selectorText"in e}class bt{constructor(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}getId(t){var r;if(!t)return-1;const n=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return n??-1}getNode(t){return this.idNodeMap.get(t)||null}getIds(){return Array.from(this.idNodeMap.keys())}getMeta(t){return this.nodeMetaMap.get(t)||null}removeNodeFromMap(t){const r=this.getId(t);this.idNodeMap.delete(r),t.childNodes&&t.childNodes.forEach(n=>this.removeNodeFromMap(n))}has(t){return this.idNodeMap.has(t)}hasNode(t){return this.nodeMetaMap.has(t)}add(t,r){const n=r.id;this.idNodeMap.set(n,t),this.nodeMetaMap.set(t,r)}replace(t,r){const n=this.getNode(t);if(n){const i=this.nodeMetaMap.get(n);i&&this.nodeMetaMap.set(r,i)}this.idNodeMap.set(t,r)}reset(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}}function _r(){return new bt}function tt({element:e,maskInputOptions:t,tagName:r,type:n,value:i,maskInputFn:o}){let a=i||"";const l=n&&ie(n);return(t[r.toLowerCase()]||l&&t[l])&&(o?a=o(a,e):a="*".repeat(a.length)),a}function ie(e){return e.toLowerCase()}const wt="__rrweb_original__";function Or(e){const t=e.getContext("2d");if(!t)return!0;const r=50;for(let n=0;ns!==0))return!1}return!0}function rt(e){const t=e.type;return e.hasAttribute("data-rr-is-password")?"password":t?ie(t):null}function It(e,t){var r;let n;try{n=new URL(e,t??window.location.href)}catch{return null}const i=/\.([0-9a-z]+)(?:$)/i,o=n.pathname.match(i);return(r=o?.[1])!==null&&r!==void 0?r:null}let Er=1;const kr=new RegExp("[^a-z0-9-_:]"),Ie=-2;function Mt(){return Er++}function xr(e){if(e instanceof HTMLFormElement)return"form";const t=ie(e.tagName);return kr.test(t)?"div":t}function Rr(e){let t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}let fe,Ct;const Tr=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Dr=/^(?:[a-z+]+:)?\/\//i,Nr=/^www\..*/i,Ar=/^(data:)([^,]*),(.*)/i;function De(e,t){return(e||"").replace(Tr,(r,n,i,o,a,l)=>{const s=i||a||l,c=n||o||"";if(!s)return r;if(Dr.test(s)||Nr.test(s))return`url(${c}${s}${c})`;if(Ar.test(s))return`url(${c}${s}${c})`;if(s[0]==="/")return`url(${c}${Rr(t)+s}${c})`;const u=t.split("/"),f=s.split("/");u.pop();for(const m of f)m!=="."&&(m===".."?u.pop():u.push(m));return`url(${c}${u.join("/")}${c})`})}const Lr=/^[^ \t\n\r\u000c]+/,Fr=/^[, \t\n\r\u000c]+/;function Pr(e,t){if(t.trim()==="")return t;let r=0;function n(o){let a;const l=o.exec(t.substring(r));return l?(a=l[0],r+=a.length,a):""}const i=[];for(;n(Fr),!(r>=t.length);){let o=n(Lr);if(o.slice(-1)===",")o=he(e,o.substring(0,o.length-1)),i.push(o);else{let a="";o=he(e,o);let l=!1;for(;;){const s=t.charAt(r);if(s===""){i.push((o+a).trim());break}else if(l)s===")"&&(l=!1);else if(s===","){r+=1,i.push((o+a).trim());break}else s==="("&&(l=!0);a+=s,r+=1}}}return i.join(", ")}function he(e,t){if(!t||t.trim()==="")return t;const r=e.createElement("a");return r.href=t,r.href}function Br(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function nt(){const e=document.createElement("a");return e.href="",e.href}function _t(e,t,r,n){return n&&(r==="src"||r==="href"&&!(t==="use"&&n[0]==="#")||r==="xlink:href"&&n[0]!=="#"||r==="background"&&(t==="table"||t==="td"||t==="th")?he(e,n):r==="srcset"?Pr(e,n):r==="style"?De(n,nt()):t==="object"&&r==="data"?he(e,n):n)}function Ot(e,t,r){return(e==="video"||e==="audio")&&t==="autoplay"}function Wr(e,t,r){try{if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(let n=e.classList.length;n--;){const i=e.classList[n];if(t.test(i))return!0}if(r)return e.matches(r)}catch{}return!1}function Ne(e,t,r){if(!e)return!1;if(e.nodeType!==e.ELEMENT_NODE)return r?Ne(e.parentNode,t,r):!1;for(let n=e.classList.length;n--;){const i=e.classList[n];if(t.test(i))return!0}return r?Ne(e.parentNode,t,r):!1}function Et(e,t,r,n){try{const i=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(i===null)return!1;if(typeof t=="string"){if(n){if(i.closest(`.${t}`))return!0}else if(i.classList.contains(t))return!0}else if(Ne(i,t,n))return!0;if(r){if(n){if(i.closest(r))return!0}else if(i.matches(r))return!0}}catch{}return!1}function Ur(e,t,r){const n=e.contentWindow;if(!n)return;let i=!1,o;try{o=n.document.readyState}catch{return}if(o!=="complete"){const l=setTimeout(()=>{i||(t(),i=!0)},r);e.addEventListener("load",()=>{clearTimeout(l),i=!0,t()});return}const a="about:blank";if(n.location.href!==a||e.src===a||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}function zr(e,t,r){let n=!1,i;try{i=e.sheet}catch{return}if(i)return;const o=setTimeout(()=>{n||(t(),n=!0)},r);e.addEventListener("load",()=>{clearTimeout(o),n=!0,t()})}function Hr(e,t){const{doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:a,inlineStylesheet:l,maskInputOptions:s={},maskTextFn:c,maskInputFn:u,dataURLOptions:f={},inlineImages:m,recordCanvas:h,keepIframeSrcFn:g,newlyAddedElement:p=!1}=t,y=$r(r,n);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:A.Document,childNodes:[],compatMode:e.compatMode}:{type:A.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:A.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return jr(e,{doc:r,blockClass:i,blockSelector:o,inlineStylesheet:l,maskInputOptions:s,maskInputFn:u,dataURLOptions:f,inlineImages:m,recordCanvas:h,keepIframeSrcFn:g,newlyAddedElement:p,rootId:y});case e.TEXT_NODE:return qr(e,{needsMask:a,maskTextFn:c,rootId:y});case e.CDATA_SECTION_NODE:return{type:A.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:A.Comment,textContent:e.textContent||"",rootId:y};default:return!1}}function $r(e,t){if(!t.hasNode(e))return;const r=t.getId(e);return r===1?void 0:r}function qr(e,t){var r;const{needsMask:n,maskTextFn:i,rootId:o}=t,a=e.parentNode&&e.parentNode.tagName;let l=e.textContent;const s=a==="STYLE"?!0:void 0,c=a==="SCRIPT"?!0:void 0;if(s&&l){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(l=Te(e.parentNode.sheet))}catch(u){console.warn(`Cannot get CSS styles from text's parentNode. Error: ${u}`,e)}l=De(l,nt())}return c&&(l="SCRIPT_PLACEHOLDER"),!s&&!c&&l&&n&&(l=i?i(l,e.parentElement):l.replace(/[\S]/g,"*")),{type:A.Text,textContent:l||"",isStyle:s,rootId:o}}function jr(e,t){const{doc:r,blockClass:n,blockSelector:i,inlineStylesheet:o,maskInputOptions:a={},maskInputFn:l,dataURLOptions:s={},inlineImages:c,recordCanvas:u,keepIframeSrcFn:f,newlyAddedElement:m=!1,rootId:h}=t,g=Wr(e,n,i),p=xr(e);let y={};const w=e.attributes.length;for(let v=0;vI.href===e.href);let b=null;v&&(b=Te(v)),b&&(delete y.rel,delete y.href,y._cssText=De(b,v.href))}if(p==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){const v=Te(e.sheet);v&&(y._cssText=De(v,nt()))}if(p==="input"||p==="textarea"||p==="select"){const v=e.value,b=e.checked;y.type!=="radio"&&y.type!=="checkbox"&&y.type!=="submit"&&y.type!=="button"&&v?y.value=tt({element:e,type:rt(e),tagName:p,value:v,maskInputOptions:a,maskInputFn:l}):b&&(y.checked=b)}if(p==="option"&&(e.selected&&!a.select?y.selected=!0:delete y.selected),p==="canvas"&&u){if(e.__context==="2d")Or(e)||(y.rr_dataURL=e.toDataURL(s.type,s.quality));else if(!("__context"in e)){const v=e.toDataURL(s.type,s.quality),b=document.createElement("canvas");b.width=e.width,b.height=e.height;const I=b.toDataURL(s.type,s.quality);v!==I&&(y.rr_dataURL=v)}}if(p==="img"&&c){fe||(fe=r.createElement("canvas"),Ct=fe.getContext("2d"));const v=e,b=v.crossOrigin;v.crossOrigin="anonymous";const I=()=>{v.removeEventListener("load",I);try{fe.width=v.naturalWidth,fe.height=v.naturalHeight,Ct.drawImage(v,0,0),y.rr_dataURL=fe.toDataURL(s.type,s.quality)}catch(B){console.warn(`Cannot inline img src=${v.currentSrc}! Error: ${B}`)}b?y.crossOrigin=b:v.removeAttribute("crossorigin")};v.complete&&v.naturalWidth!==0?I():v.addEventListener("load",I)}if(p==="audio"||p==="video"){const v=y;v.rr_mediaState=e.paused?"paused":"played",v.rr_mediaCurrentTime=e.currentTime,v.rr_mediaPlaybackRate=e.playbackRate,v.rr_mediaMuted=e.muted,v.rr_mediaLoop=e.loop,v.rr_mediaVolume=e.volume}if(m||(e.scrollLeft&&(y.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(y.rr_scrollTop=e.scrollTop)),g){const{width:v,height:b}=e.getBoundingClientRect();y={class:y.class,rr_width:`${v}px`,rr_height:`${b}px`}}p==="iframe"&&!f(y.src)&&(e.contentDocument||(y.rr_src=y.src),delete y.src);let S;try{customElements.get(p)&&(S=!0)}catch{}return{type:A.Element,tagName:p,attributes:y,childNodes:[],isSVG:Br(e)||void 0,needBlock:g,rootId:h,isCustom:S}}function k(e){return e==null?"":e.toLowerCase()}function Gr(e,t){if(t.comment&&e.type===A.Comment)return!0;if(e.type===A.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&(e.attributes.rel==="preload"||e.attributes.rel==="modulepreload")&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&It(e.attributes.href)==="js"))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(k(e.attributes.name).match(/^msapplication-tile(image|color)$/)||k(e.attributes.name)==="application-name"||k(e.attributes.rel)==="icon"||k(e.attributes.rel)==="apple-touch-icon"||k(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&k(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(k(e.attributes.property).match(/^(og|twitter|fb):/)||k(e.attributes.name).match(/^(og|twitter):/)||k(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(k(e.attributes.name)==="robots"||k(e.attributes.name)==="googlebot"||k(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(k(e.attributes.name)==="author"||k(e.attributes.name)==="generator"||k(e.attributes.name)==="framework"||k(e.attributes.name)==="publisher"||k(e.attributes.name)==="progid"||k(e.attributes.property).match(/^article:/)||k(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(k(e.attributes.name)==="google-site-verification"||k(e.attributes.name)==="yandex-verification"||k(e.attributes.name)==="csrf-token"||k(e.attributes.name)==="p:domain_verify"||k(e.attributes.name)==="verify-v1"||k(e.attributes.name)==="verification"||k(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function pe(e,t){const{doc:r,mirror:n,blockClass:i,blockSelector:o,maskTextClass:a,maskTextSelector:l,skipChild:s=!1,inlineStylesheet:c=!0,maskInputOptions:u={},maskTextFn:f,maskInputFn:m,slimDOMOptions:h,dataURLOptions:g={},inlineImages:p=!1,recordCanvas:y=!1,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v=5e3,onStylesheetLoad:b,stylesheetLoadTimeout:I=5e3,keepIframeSrcFn:B=()=>!1,newlyAddedElement:F=!1}=t;let{needsMask:x}=t,{preserveWhiteSpace:R=!0}=t;!x&&e.childNodes&&(x=Et(e,a,l,x===void 0));const j=Hr(e,{doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:x,inlineStylesheet:c,maskInputOptions:u,maskTextFn:f,maskInputFn:m,dataURLOptions:g,inlineImages:p,recordCanvas:y,keepIframeSrcFn:B,newlyAddedElement:F});if(!j)return console.warn(e,"not serialized"),null;let G;n.hasNode(e)?G=n.getId(e):Gr(j,h)||!R&&j.type===A.Text&&!j.isStyle&&!j.textContent.replace(/^\s+|\s+$/gm,"").length?G=Ie:G=Mt();const E=Object.assign(j,{id:G});if(n.add(e,E),G===Ie)return null;w&&w(e);let le=!s;if(E.type===A.Element){le=le&&!E.needBlock,delete E.needBlock;const z=e.shadowRoot;z&&we(z)&&(E.isShadowHost=!0)}if((E.type===A.Document||E.type===A.Element)&&le){h.headWhitespace&&E.type===A.Element&&E.tagName==="head"&&(R=!1);const z={doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:x,maskTextClass:a,maskTextSelector:l,skipChild:s,inlineStylesheet:c,maskInputOptions:u,maskTextFn:f,maskInputFn:m,slimDOMOptions:h,dataURLOptions:g,inlineImages:p,recordCanvas:y,preserveWhiteSpace:R,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v,onStylesheetLoad:b,stylesheetLoadTimeout:I,keepIframeSrcFn:B};if(!(E.type===A.Element&&E.tagName==="textarea"&&E.attributes.value!==void 0))for(const ne of Array.from(e.childNodes)){const Z=pe(ne,z);Z&&E.childNodes.push(Z)}if(Sr(e)&&e.shadowRoot)for(const ne of Array.from(e.shadowRoot.childNodes)){const Z=pe(ne,z);Z&&(we(e.shadowRoot)&&(Z.isShadow=!0),E.childNodes.push(Z))}}return e.parentNode&&be(e.parentNode)&&we(e.parentNode)&&(E.isShadow=!0),E.type===A.Element&&E.tagName==="iframe"&&Ur(e,()=>{const z=e.contentDocument;if(z&&S){const ne=pe(z,{doc:z,mirror:n,blockClass:i,blockSelector:o,needsMask:x,maskTextClass:a,maskTextSelector:l,skipChild:!1,inlineStylesheet:c,maskInputOptions:u,maskTextFn:f,maskInputFn:m,slimDOMOptions:h,dataURLOptions:g,inlineImages:p,recordCanvas:y,preserveWhiteSpace:R,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v,onStylesheetLoad:b,stylesheetLoadTimeout:I,keepIframeSrcFn:B});ne&&S(e,ne)}},v),E.type===A.Element&&E.tagName==="link"&&typeof E.attributes.rel=="string"&&(E.attributes.rel==="stylesheet"||E.attributes.rel==="preload"&&typeof E.attributes.href=="string"&&It(E.attributes.href)==="css")&&zr(e,()=>{if(b){const z=pe(e,{doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:x,maskTextClass:a,maskTextSelector:l,skipChild:!1,inlineStylesheet:c,maskInputOptions:u,maskTextFn:f,maskInputFn:m,slimDOMOptions:h,dataURLOptions:g,inlineImages:p,recordCanvas:y,preserveWhiteSpace:R,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v,onStylesheetLoad:b,stylesheetLoadTimeout:I,keepIframeSrcFn:B});z&&b(e,z)}},I),E}function Vr(e,t){const{mirror:r=new bt,blockClass:n="rr-block",blockSelector:i=null,maskTextClass:o="rr-mask",maskTextSelector:a=null,inlineStylesheet:l=!0,inlineImages:s=!1,recordCanvas:c=!1,maskAllInputs:u=!1,maskTextFn:f,maskInputFn:m,slimDOM:h=!1,dataURLOptions:g,preserveWhiteSpace:p,onSerialize:y,onIframeLoad:w,iframeLoadTimeout:S,onStylesheetLoad:v,stylesheetLoadTimeout:b,keepIframeSrcFn:I=()=>!1}=t||{};return pe(e,{doc:e,mirror:r,blockClass:n,blockSelector:i,maskTextClass:o,maskTextSelector:a,skipChild:!1,inlineStylesheet:l,maskInputOptions:u===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:u===!1?{password:!0}:u,maskTextFn:f,maskInputFn:m,slimDOMOptions:h===!0||h==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:h==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:h===!1?{}:h,dataURLOptions:g,inlineImages:s,recordCanvas:c,preserveWhiteSpace:p,onSerialize:y,onIframeLoad:w,iframeLoadTimeout:S,onStylesheetLoad:v,stylesheetLoadTimeout:b,keepIframeSrcFn:I,newlyAddedElement:!1})}function W(e,t,r=document){const n={capture:!0,passive:!0};return r.addEventListener(e,t,n),()=>r.removeEventListener(e,t,n)}const me=`Please stop import mirror directly. Instead of that,\r +(function(){"use strict";var A;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(A||(A={}));function br(e){return e.nodeType===e.ELEMENT_NODE}function be(e){const t=e?.host;return t?.shadowRoot===e}function we(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function wr(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function Mr(e){const{cssText:t}=e;if(t.split('"').length<3)return t;const r=["@import",`url(${JSON.stringify(e.href)})`];return e.layerName===""?r.push("layer"):e.layerName&&r.push(`layer(${e.layerName})`),e.supportsText&&r.push(`supports(${e.supportsText})`),e.media.length&&r.push(e.media.mediaText),r.join(" ")+";"}function Te(e){try{const t=e.rules||e.cssRules;return t?wr(Array.from(t,bt).join("")):null}catch{return null}}function bt(e){let t;if(Cr(e))try{t=Te(e.styleSheet)||Mr(e)}catch{}else if(_r(e)&&e.selectorText.includes(":"))return Ir(e.cssText);return t||e.cssText}function Ir(e){const t=/(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;return e.replace(t,"$1\\$2")}function Cr(e){return"styleSheet"in e}function _r(e){return"selectorText"in e}class wt{constructor(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}getId(t){var r;if(!t)return-1;const n=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return n??-1}getNode(t){return this.idNodeMap.get(t)||null}getIds(){return Array.from(this.idNodeMap.keys())}getMeta(t){return this.nodeMetaMap.get(t)||null}removeNodeFromMap(t){const r=this.getId(t);this.idNodeMap.delete(r),t.childNodes&&t.childNodes.forEach(n=>this.removeNodeFromMap(n))}has(t){return this.idNodeMap.has(t)}hasNode(t){return this.nodeMetaMap.has(t)}add(t,r){const n=r.id;this.idNodeMap.set(n,t),this.nodeMetaMap.set(t,r)}replace(t,r){const n=this.getNode(t);if(n){const i=this.nodeMetaMap.get(n);i&&this.nodeMetaMap.set(r,i)}this.idNodeMap.set(t,r)}reset(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}}function Or(){return new wt}function tt({element:e,maskInputOptions:t,tagName:r,type:n,value:i,maskInputFn:o}){let a=i||"";const l=n&&ie(n);return(t[r.toLowerCase()]||l&&t[l])&&(o?a=o(a,e):a="*".repeat(a.length)),a}function ie(e){return e.toLowerCase()}const Mt="__rrweb_original__";function Er(e){const t=e.getContext("2d");if(!t)return!0;const r=50;for(let n=0;ns!==0))return!1}return!0}function rt(e){const t=e.type;return e.hasAttribute("data-rr-is-password")?"password":t?ie(t):null}function It(e,t){var r;let n;try{n=new URL(e,t??window.location.href)}catch{return null}const i=/\.([0-9a-z]+)(?:$)/i,o=n.pathname.match(i);return(r=o?.[1])!==null&&r!==void 0?r:null}let kr=1;const xr=new RegExp("[^a-z0-9-_:]"),Me=-2;function Ct(){return kr++}function Rr(e){if(e instanceof HTMLFormElement)return"form";const t=ie(e.tagName);return xr.test(t)?"div":t}function Tr(e){let t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}let he,_t;const Dr=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Nr=/^(?:[a-z+]+:)?\/\//i,Ar=/^www\..*/i,Lr=/^(data:)([^,]*),(.*)/i;function De(e,t){return(e||"").replace(Dr,(r,n,i,o,a,l)=>{const s=i||a||l,c=n||o||"";if(!s)return r;if(Nr.test(s)||Ar.test(s))return`url(${c}${s}${c})`;if(Lr.test(s))return`url(${c}${s}${c})`;if(s[0]==="/")return`url(${c}${Tr(t)+s}${c})`;const u=t.split("/"),h=s.split("/");u.pop();for(const m of h)m!=="."&&(m===".."?u.pop():u.push(m));return`url(${c}${u.join("/")}${c})`})}const Fr=/^[^ \t\n\r\u000c]+/,Pr=/^[, \t\n\r\u000c]+/;function Br(e,t){if(t.trim()==="")return t;let r=0;function n(o){let a;const l=o.exec(t.substring(r));return l?(a=l[0],r+=a.length,a):""}const i=[];for(;n(Pr),!(r>=t.length);){let o=n(Fr);if(o.slice(-1)===",")o=pe(e,o.substring(0,o.length-1)),i.push(o);else{let a="";o=pe(e,o);let l=!1;for(;;){const s=t.charAt(r);if(s===""){i.push((o+a).trim());break}else if(l)s===")"&&(l=!1);else if(s===","){r+=1,i.push((o+a).trim());break}else s==="("&&(l=!0);a+=s,r+=1}}}return i.join(", ")}function pe(e,t){if(!t||t.trim()==="")return t;const r=e.createElement("a");return r.href=t,r.href}function Wr(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function nt(){const e=document.createElement("a");return e.href="",e.href}function Ot(e,t,r,n){return n&&(r==="src"||r==="href"&&!(t==="use"&&n[0]==="#")||r==="xlink:href"&&n[0]!=="#"||r==="background"&&(t==="table"||t==="td"||t==="th")?pe(e,n):r==="srcset"?Br(e,n):r==="style"?De(n,nt()):t==="object"&&r==="data"?pe(e,n):n)}function Et(e,t,r){return(e==="video"||e==="audio")&&t==="autoplay"}function Ur(e,t,r){try{if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(let n=e.classList.length;n--;){const i=e.classList[n];if(t.test(i))return!0}if(r)return e.matches(r)}catch{}return!1}function Ne(e,t,r){if(!e)return!1;if(e.nodeType!==e.ELEMENT_NODE)return r?Ne(e.parentNode,t,r):!1;for(let n=e.classList.length;n--;){const i=e.classList[n];if(t.test(i))return!0}return r?Ne(e.parentNode,t,r):!1}function kt(e,t,r,n){try{const i=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(i===null)return!1;if(typeof t=="string"){if(n){if(i.closest(`.${t}`))return!0}else if(i.classList.contains(t))return!0}else if(Ne(i,t,n))return!0;if(r){if(n){if(i.closest(r))return!0}else if(i.matches(r))return!0}}catch{}return!1}function zr(e,t,r){const n=e.contentWindow;if(!n)return;let i=!1,o;try{o=n.document.readyState}catch{return}if(o!=="complete"){const l=setTimeout(()=>{i||(t(),i=!0)},r);e.addEventListener("load",()=>{clearTimeout(l),i=!0,t()});return}const a="about:blank";if(n.location.href!==a||e.src===a||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}function Hr(e,t,r){let n=!1,i;try{i=e.sheet}catch{return}if(i)return;const o=setTimeout(()=>{n||(t(),n=!0)},r);e.addEventListener("load",()=>{clearTimeout(o),n=!0,t()})}function $r(e,t){const{doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:a,inlineStylesheet:l,maskInputOptions:s={},maskTextFn:c,maskInputFn:u,dataURLOptions:h={},inlineImages:m,recordCanvas:f,keepIframeSrcFn:g,newlyAddedElement:p=!1}=t,y=qr(r,n);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:A.Document,childNodes:[],compatMode:e.compatMode}:{type:A.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:A.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return Gr(e,{doc:r,blockClass:i,blockSelector:o,inlineStylesheet:l,maskInputOptions:s,maskInputFn:u,dataURLOptions:h,inlineImages:m,recordCanvas:f,keepIframeSrcFn:g,newlyAddedElement:p,rootId:y});case e.TEXT_NODE:return jr(e,{needsMask:a,maskTextFn:c,rootId:y});case e.CDATA_SECTION_NODE:return{type:A.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:A.Comment,textContent:e.textContent||"",rootId:y};default:return!1}}function qr(e,t){if(!t.hasNode(e))return;const r=t.getId(e);return r===1?void 0:r}function jr(e,t){var r;const{needsMask:n,maskTextFn:i,rootId:o}=t,a=e.parentNode&&e.parentNode.tagName;let l=e.textContent;const s=a==="STYLE"?!0:void 0,c=a==="SCRIPT"?!0:void 0;if(s&&l){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(l=Te(e.parentNode.sheet))}catch(u){console.warn(`Cannot get CSS styles from text's parentNode. Error: ${u}`,e)}l=De(l,nt())}return c&&(l="SCRIPT_PLACEHOLDER"),!s&&!c&&l&&n&&(l=i?i(l,e.parentElement):l.replace(/[\S]/g,"*")),{type:A.Text,textContent:l||"",isStyle:s,rootId:o}}function Gr(e,t){const{doc:r,blockClass:n,blockSelector:i,inlineStylesheet:o,maskInputOptions:a={},maskInputFn:l,dataURLOptions:s={},inlineImages:c,recordCanvas:u,keepIframeSrcFn:h,newlyAddedElement:m=!1,rootId:f}=t,g=Ur(e,n,i),p=Rr(e);let y={};const w=e.attributes.length;for(let v=0;vM.href===e.href);let b=null;v&&(b=Te(v)),b&&(delete y.rel,delete y.href,y._cssText=De(b,v.href))}if(p==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){const v=Te(e.sheet);v&&(y._cssText=De(v,nt()))}if(p==="input"||p==="textarea"||p==="select"){const v=e.value,b=e.checked;y.type!=="radio"&&y.type!=="checkbox"&&y.type!=="submit"&&y.type!=="button"&&v?y.value=tt({element:e,type:rt(e),tagName:p,value:v,maskInputOptions:a,maskInputFn:l}):b&&(y.checked=b)}if(p==="option"&&(e.selected&&!a.select?y.selected=!0:delete y.selected),p==="canvas"&&u){if(e.__context==="2d")Er(e)||(y.rr_dataURL=e.toDataURL(s.type,s.quality));else if(!("__context"in e)){const v=e.toDataURL(s.type,s.quality),b=document.createElement("canvas");b.width=e.width,b.height=e.height;const M=b.toDataURL(s.type,s.quality);v!==M&&(y.rr_dataURL=v)}}if(p==="img"&&c){he||(he=r.createElement("canvas"),_t=he.getContext("2d"));const v=e,b=v.crossOrigin;v.crossOrigin="anonymous";const M=()=>{v.removeEventListener("load",M);try{he.width=v.naturalWidth,he.height=v.naturalHeight,_t.drawImage(v,0,0),y.rr_dataURL=he.toDataURL(s.type,s.quality)}catch(B){console.warn(`Cannot inline img src=${v.currentSrc}! Error: ${B}`)}b?y.crossOrigin=b:v.removeAttribute("crossorigin")};v.complete&&v.naturalWidth!==0?M():v.addEventListener("load",M)}if(p==="audio"||p==="video"){const v=y;v.rr_mediaState=e.paused?"paused":"played",v.rr_mediaCurrentTime=e.currentTime,v.rr_mediaPlaybackRate=e.playbackRate,v.rr_mediaMuted=e.muted,v.rr_mediaLoop=e.loop,v.rr_mediaVolume=e.volume}if(m||(e.scrollLeft&&(y.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(y.rr_scrollTop=e.scrollTop)),g){const{width:v,height:b}=e.getBoundingClientRect();y={class:y.class,rr_width:`${v}px`,rr_height:`${b}px`}}p==="iframe"&&!h(y.src)&&(e.contentDocument||(y.rr_src=y.src),delete y.src);let S;try{customElements.get(p)&&(S=!0)}catch{}return{type:A.Element,tagName:p,attributes:y,childNodes:[],isSVG:Wr(e)||void 0,needBlock:g,rootId:f,isCustom:S}}function k(e){return e==null?"":e.toLowerCase()}function Vr(e,t){if(t.comment&&e.type===A.Comment)return!0;if(e.type===A.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&(e.attributes.rel==="preload"||e.attributes.rel==="modulepreload")&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&It(e.attributes.href)==="js"))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(k(e.attributes.name).match(/^msapplication-tile(image|color)$/)||k(e.attributes.name)==="application-name"||k(e.attributes.rel)==="icon"||k(e.attributes.rel)==="apple-touch-icon"||k(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&k(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(k(e.attributes.property).match(/^(og|twitter|fb):/)||k(e.attributes.name).match(/^(og|twitter):/)||k(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(k(e.attributes.name)==="robots"||k(e.attributes.name)==="googlebot"||k(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(k(e.attributes.name)==="author"||k(e.attributes.name)==="generator"||k(e.attributes.name)==="framework"||k(e.attributes.name)==="publisher"||k(e.attributes.name)==="progid"||k(e.attributes.property).match(/^article:/)||k(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(k(e.attributes.name)==="google-site-verification"||k(e.attributes.name)==="yandex-verification"||k(e.attributes.name)==="csrf-token"||k(e.attributes.name)==="p:domain_verify"||k(e.attributes.name)==="verify-v1"||k(e.attributes.name)==="verification"||k(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function me(e,t){const{doc:r,mirror:n,blockClass:i,blockSelector:o,maskTextClass:a,maskTextSelector:l,skipChild:s=!1,inlineStylesheet:c=!0,maskInputOptions:u={},maskTextFn:h,maskInputFn:m,slimDOMOptions:f,dataURLOptions:g={},inlineImages:p=!1,recordCanvas:y=!1,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v=5e3,onStylesheetLoad:b,stylesheetLoadTimeout:M=5e3,keepIframeSrcFn:B=()=>!1,newlyAddedElement:P=!1}=t;let{needsMask:x}=t,{preserveWhiteSpace:R=!0}=t;!x&&e.childNodes&&(x=kt(e,a,l,x===void 0));const j=$r(e,{doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:x,inlineStylesheet:c,maskInputOptions:u,maskTextFn:h,maskInputFn:m,dataURLOptions:g,inlineImages:p,recordCanvas:y,keepIframeSrcFn:B,newlyAddedElement:P});if(!j)return console.warn(e,"not serialized"),null;let G;n.hasNode(e)?G=n.getId(e):Vr(j,f)||!R&&j.type===A.Text&&!j.isStyle&&!j.textContent.replace(/^\s+|\s+$/gm,"").length?G=Me:G=Ct();const E=Object.assign(j,{id:G});if(n.add(e,E),G===Me)return null;w&&w(e);let ue=!s;if(E.type===A.Element){ue=ue&&!E.needBlock,delete E.needBlock;const z=e.shadowRoot;z&&we(z)&&(E.isShadowHost=!0)}if((E.type===A.Document||E.type===A.Element)&&ue){f.headWhitespace&&E.type===A.Element&&E.tagName==="head"&&(R=!1);const z={doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:x,maskTextClass:a,maskTextSelector:l,skipChild:s,inlineStylesheet:c,maskInputOptions:u,maskTextFn:h,maskInputFn:m,slimDOMOptions:f,dataURLOptions:g,inlineImages:p,recordCanvas:y,preserveWhiteSpace:R,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v,onStylesheetLoad:b,stylesheetLoadTimeout:M,keepIframeSrcFn:B};if(!(E.type===A.Element&&E.tagName==="textarea"&&E.attributes.value!==void 0))for(const ne of Array.from(e.childNodes)){const Z=me(ne,z);Z&&E.childNodes.push(Z)}if(br(e)&&e.shadowRoot)for(const ne of Array.from(e.shadowRoot.childNodes)){const Z=me(ne,z);Z&&(we(e.shadowRoot)&&(Z.isShadow=!0),E.childNodes.push(Z))}}return e.parentNode&&be(e.parentNode)&&we(e.parentNode)&&(E.isShadow=!0),E.type===A.Element&&E.tagName==="iframe"&&zr(e,()=>{const z=e.contentDocument;if(z&&S){const ne=me(z,{doc:z,mirror:n,blockClass:i,blockSelector:o,needsMask:x,maskTextClass:a,maskTextSelector:l,skipChild:!1,inlineStylesheet:c,maskInputOptions:u,maskTextFn:h,maskInputFn:m,slimDOMOptions:f,dataURLOptions:g,inlineImages:p,recordCanvas:y,preserveWhiteSpace:R,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v,onStylesheetLoad:b,stylesheetLoadTimeout:M,keepIframeSrcFn:B});ne&&S(e,ne)}},v),E.type===A.Element&&E.tagName==="link"&&typeof E.attributes.rel=="string"&&(E.attributes.rel==="stylesheet"||E.attributes.rel==="preload"&&typeof E.attributes.href=="string"&&It(E.attributes.href)==="css")&&Hr(e,()=>{if(b){const z=me(e,{doc:r,mirror:n,blockClass:i,blockSelector:o,needsMask:x,maskTextClass:a,maskTextSelector:l,skipChild:!1,inlineStylesheet:c,maskInputOptions:u,maskTextFn:h,maskInputFn:m,slimDOMOptions:f,dataURLOptions:g,inlineImages:p,recordCanvas:y,preserveWhiteSpace:R,onSerialize:w,onIframeLoad:S,iframeLoadTimeout:v,onStylesheetLoad:b,stylesheetLoadTimeout:M,keepIframeSrcFn:B});z&&b(e,z)}},M),E}function Jr(e,t){const{mirror:r=new wt,blockClass:n="rr-block",blockSelector:i=null,maskTextClass:o="rr-mask",maskTextSelector:a=null,inlineStylesheet:l=!0,inlineImages:s=!1,recordCanvas:c=!1,maskAllInputs:u=!1,maskTextFn:h,maskInputFn:m,slimDOM:f=!1,dataURLOptions:g,preserveWhiteSpace:p,onSerialize:y,onIframeLoad:w,iframeLoadTimeout:S,onStylesheetLoad:v,stylesheetLoadTimeout:b,keepIframeSrcFn:M=()=>!1}=t||{};return me(e,{doc:e,mirror:r,blockClass:n,blockSelector:i,maskTextClass:o,maskTextSelector:a,skipChild:!1,inlineStylesheet:l,maskInputOptions:u===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:u===!1?{password:!0}:u,maskTextFn:h,maskInputFn:m,slimDOMOptions:f===!0||f==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:f==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:f===!1?{}:f,dataURLOptions:g,inlineImages:s,recordCanvas:c,preserveWhiteSpace:p,onSerialize:y,onIframeLoad:w,iframeLoadTimeout:S,onStylesheetLoad:v,stylesheetLoadTimeout:b,keepIframeSrcFn:M,newlyAddedElement:!1})}function W(e,t,r=document){const n={capture:!0,passive:!0};return r.addEventListener(e,t,n),()=>r.removeEventListener(e,t,n)}const ge=`Please stop import mirror directly. Instead of that,\r now you can use replayer.getMirror() to access the mirror instance of a replayer,\r -or you can use record.mirror to access the mirror instance during recording.`;let kt={map:{},getId(){return console.error(me),-1},getNode(){return console.error(me),null},removeNodeFromMap(){console.error(me)},has(){return console.error(me),!1},reset(){console.error(me)}};typeof window<"u"&&window.Proxy&&window.Reflect&&(kt=new Proxy(kt,{get(e,t,r){return t==="map"&&console.error(me),Reflect.get(e,t,r)}}));function Me(e,t,r={}){let n=null,i=0;return function(...o){const a=Date.now();!i&&r.leading===!1&&(i=a);const l=t-(a-i),s=this;l<=0||l>t?(n&&(clearTimeout(n),n=null),i=a,e.apply(s,o)):!n&&r.trailing!==!1&&(n=setTimeout(()=>{i=r.leading===!1?0:Date.now(),n=null,e.apply(s,o)},l))}}function Ae(e,t,r,n,i=window){const o=i.Object.getOwnPropertyDescriptor(e,t);return i.Object.defineProperty(e,t,n?r:{set(a){setTimeout(()=>{r.set.call(this,a)},0),o&&o.set&&o.set.call(this,a)}}),()=>Ae(e,t,o||{},!0)}function ge(e,t,r){try{if(!(t in e))return()=>{};const n=e[t],i=r(n);return typeof i=="function"&&(i.prototype=i.prototype||{},Object.defineProperties(i,{__rrweb_original__:{enumerable:!1,value:n}})),e[t]=i,()=>{e[t]=n}}catch{return()=>{}}}let Le=Date.now;/[1-9][0-9]{12}/.test(Date.now().toString())||(Le=()=>new Date().getTime());function xt(e){var t,r,n,i,o,a;const l=e.document;return{left:l.scrollingElement?l.scrollingElement.scrollLeft:e.pageXOffset!==void 0?e.pageXOffset:l?.documentElement.scrollLeft||((r=(t=l?.body)===null||t===void 0?void 0:t.parentElement)===null||r===void 0?void 0:r.scrollLeft)||((n=l?.body)===null||n===void 0?void 0:n.scrollLeft)||0,top:l.scrollingElement?l.scrollingElement.scrollTop:e.pageYOffset!==void 0?e.pageYOffset:l?.documentElement.scrollTop||((o=(i=l?.body)===null||i===void 0?void 0:i.parentElement)===null||o===void 0?void 0:o.scrollTop)||((a=l?.body)===null||a===void 0?void 0:a.scrollTop)||0}}function Rt(){return window.innerHeight||document.documentElement&&document.documentElement.clientHeight||document.body&&document.body.clientHeight}function Tt(){return window.innerWidth||document.documentElement&&document.documentElement.clientWidth||document.body&&document.body.clientWidth}function Dt(e){return e?e.nodeType===e.ELEMENT_NODE?e:e.parentElement:null}function U(e,t,r,n){if(!e)return!1;const i=Dt(e);if(!i)return!1;try{if(typeof t=="string"){if(i.classList.contains(t)||n&&i.closest("."+t)!==null)return!0}else if(Ne(i,t,n))return!0}catch{}return!!(r&&(i.matches(r)||n&&i.closest(r)!==null))}function Jr(e,t){return t.getId(e)!==-1}function it(e,t){return t.getId(e)===Ie}function Nt(e,t){if(be(e))return!1;const r=t.getId(e);return t.has(r)?e.parentNode&&e.parentNode.nodeType===e.DOCUMENT_NODE?!1:e.parentNode?Nt(e.parentNode,t):!0:!0}function ot(e){return!!e.changedTouches}function Xr(e=window){"NodeList"in e&&!e.NodeList.prototype.forEach&&(e.NodeList.prototype.forEach=Array.prototype.forEach),"DOMTokenList"in e&&!e.DOMTokenList.prototype.forEach&&(e.DOMTokenList.prototype.forEach=Array.prototype.forEach),Node.prototype.contains||(Node.prototype.contains=(...t)=>{let r=t[0];if(!(0 in t))throw new TypeError("1 argument is required");do if(this===r)return!0;while(r=r&&r.parentNode);return!1})}function At(e,t){return!!(e.nodeName==="IFRAME"&&t.getMeta(e))}function Lt(e,t){return!!(e.nodeName==="LINK"&&e.nodeType===e.ELEMENT_NODE&&e.getAttribute&&e.getAttribute("rel")==="stylesheet"&&t.getMeta(e))}function st(e){return!!e?.shadowRoot}class Kr{constructor(){this.id=1,this.styleIDMap=new WeakMap,this.idStyleMap=new Map}getId(t){var r;return(r=this.styleIDMap.get(t))!==null&&r!==void 0?r:-1}has(t){return this.styleIDMap.has(t)}add(t,r){if(this.has(t))return this.getId(t);let n;return r===void 0?n=this.id++:n=r,this.styleIDMap.set(t,n),this.idStyleMap.set(n,t),n}getStyle(t){return this.idStyleMap.get(t)||null}reset(){this.styleIDMap=new WeakMap,this.idStyleMap=new Map,this.id=1}generateId(){return this.id++}}function Ft(e){var t,r;let n=null;return((r=(t=e.getRootNode)===null||t===void 0?void 0:t.call(e))===null||r===void 0?void 0:r.nodeType)===Node.DOCUMENT_FRAGMENT_NODE&&e.getRootNode().host&&(n=e.getRootNode().host),n}function Yr(e){let t=e,r;for(;r=Ft(t);)t=r;return t}function Qr(e){const t=e.ownerDocument;if(!t)return!1;const r=Yr(e);return t.contains(r)}function Pt(e){const t=e.ownerDocument;return t?t.contains(e)||Qr(e):!1}var O=(e=>(e[e.DomContentLoaded=0]="DomContentLoaded",e[e.Load=1]="Load",e[e.FullSnapshot=2]="FullSnapshot",e[e.IncrementalSnapshot=3]="IncrementalSnapshot",e[e.Meta=4]="Meta",e[e.Custom=5]="Custom",e[e.Plugin=6]="Plugin",e))(O||{}),C=(e=>(e[e.Mutation=0]="Mutation",e[e.MouseMove=1]="MouseMove",e[e.MouseInteraction=2]="MouseInteraction",e[e.Scroll=3]="Scroll",e[e.ViewportResize=4]="ViewportResize",e[e.Input=5]="Input",e[e.TouchMove=6]="TouchMove",e[e.MediaInteraction=7]="MediaInteraction",e[e.StyleSheetRule=8]="StyleSheetRule",e[e.CanvasMutation=9]="CanvasMutation",e[e.Font=10]="Font",e[e.Log=11]="Log",e[e.Drag=12]="Drag",e[e.StyleDeclaration=13]="StyleDeclaration",e[e.Selection=14]="Selection",e[e.AdoptedStyleSheet=15]="AdoptedStyleSheet",e[e.CustomElement=16]="CustomElement",e))(C||{}),$=(e=>(e[e.MouseUp=0]="MouseUp",e[e.MouseDown=1]="MouseDown",e[e.Click=2]="Click",e[e.ContextMenu=3]="ContextMenu",e[e.DblClick=4]="DblClick",e[e.Focus=5]="Focus",e[e.Blur=6]="Blur",e[e.TouchStart=7]="TouchStart",e[e.TouchMove_Departed=8]="TouchMove_Departed",e[e.TouchEnd=9]="TouchEnd",e[e.TouchCancel=10]="TouchCancel",e))($||{}),ee=(e=>(e[e.Mouse=0]="Mouse",e[e.Pen=1]="Pen",e[e.Touch=2]="Touch",e))(ee||{}),ye=(e=>(e[e["2D"]=0]="2D",e[e.WebGL=1]="WebGL",e[e.WebGL2=2]="WebGL2",e))(ye||{});function Bt(e){return"__ln"in e}class Zr{constructor(){this.length=0,this.head=null,this.tail=null}get(t){if(t>=this.length)throw new Error("Position outside of list range");let r=this.head;for(let n=0;n`${e}@${t}`;class en{constructor(){this.frozen=!1,this.locked=!1,this.texts=[],this.attributes=[],this.attributeMap=new WeakMap,this.removes=[],this.mapRemoves=[],this.movedMap={},this.addedSet=new Set,this.movedSet=new Set,this.droppedSet=new Set,this.processMutations=t=>{t.forEach(this.processMutation),this.emit()},this.emit=()=>{if(this.frozen||this.locked)return;const t=[],r=new Set,n=new Zr,i=s=>{let c=s,u=Ie;for(;u===Ie;)c=c&&c.nextSibling,u=c&&this.mirror.getId(c);return u},o=s=>{if(!s.parentNode||!Pt(s)||s.parentNode.tagName==="TEXTAREA")return;const c=be(s.parentNode)?this.mirror.getId(Ft(s)):this.mirror.getId(s.parentNode),u=i(s);if(c===-1||u===-1)return n.addNode(s);const f=pe(s,{doc:this.doc,mirror:this.mirror,blockClass:this.blockClass,blockSelector:this.blockSelector,maskTextClass:this.maskTextClass,maskTextSelector:this.maskTextSelector,skipChild:!0,newlyAddedElement:!0,inlineStylesheet:this.inlineStylesheet,maskInputOptions:this.maskInputOptions,maskTextFn:this.maskTextFn,maskInputFn:this.maskInputFn,slimDOMOptions:this.slimDOMOptions,dataURLOptions:this.dataURLOptions,recordCanvas:this.recordCanvas,inlineImages:this.inlineImages,onSerialize:m=>{At(m,this.mirror)&&this.iframeManager.addIframe(m),Lt(m,this.mirror)&&this.stylesheetManager.trackLinkElement(m),st(s)&&this.shadowDomManager.addShadowRoot(s.shadowRoot,this.doc)},onIframeLoad:(m,h)=>{this.iframeManager.attachIframe(m,h),this.shadowDomManager.observeAttachShadow(m)},onStylesheetLoad:(m,h)=>{this.stylesheetManager.attachLinkElement(m,h)}});f&&(t.push({parentId:c,nextId:u,node:f}),r.add(f.id))};for(;this.mapRemoves.length;)this.mirror.removeNodeFromMap(this.mapRemoves.shift());for(const s of this.movedSet)Ut(this.removes,s,this.mirror)&&!this.movedSet.has(s.parentNode)||o(s);for(const s of this.addedSet)!Ht(this.droppedSet,s)&&!Ut(this.removes,s,this.mirror)||Ht(this.movedSet,s)?o(s):this.droppedSet.add(s);let a=null;for(;n.length;){let s=null;if(a){const c=this.mirror.getId(a.value.parentNode),u=i(a.value);c!==-1&&u!==-1&&(s=a)}if(!s){let c=n.tail;for(;c;){const u=c;if(c=c.previous,u){const f=this.mirror.getId(u.value.parentNode);if(i(u.value)===-1)continue;if(f!==-1){s=u;break}else{const h=u.value;if(h.parentNode&&h.parentNode.nodeType===Node.DOCUMENT_FRAGMENT_NODE){const g=h.parentNode.host;if(this.mirror.getId(g)!==-1){s=u;break}}}}}}if(!s){for(;n.head;)n.removeNode(n.head.value);break}a=s.previous,n.removeNode(s.value),o(s.value)}const l={texts:this.texts.map(s=>{const c=s.node;return c.parentNode&&c.parentNode.tagName==="TEXTAREA"&&this.genTextAreaValueMutation(c.parentNode),{id:this.mirror.getId(c),value:s.value}}).filter(s=>!r.has(s.id)).filter(s=>this.mirror.has(s.id)),attributes:this.attributes.map(s=>{const{attributes:c}=s;if(typeof c.style=="string"){const u=JSON.stringify(s.styleDiff),f=JSON.stringify(s._unchangedStyles);u.length!r.has(s.id)).filter(s=>this.mirror.has(s.id)),removes:this.removes,adds:t};!l.texts.length&&!l.attributes.length&&!l.removes.length&&!l.adds.length||(this.texts=[],this.attributes=[],this.attributeMap=new WeakMap,this.removes=[],this.addedSet=new Set,this.movedSet=new Set,this.droppedSet=new Set,this.movedMap={},this.mutationCb(l))},this.genTextAreaValueMutation=t=>{let r=this.attributeMap.get(t);r||(r={node:t,attributes:{},styleDiff:{},_unchangedStyles:{}},this.attributes.push(r),this.attributeMap.set(t,r)),r.attributes.value=Array.from(t.childNodes,n=>n.textContent||"").join("")},this.processMutation=t=>{if(!it(t.target,this.mirror))switch(t.type){case"characterData":{const r=t.target.textContent;!U(t.target,this.blockClass,this.blockSelector,!1)&&r!==t.oldValue&&this.texts.push({value:Et(t.target,this.maskTextClass,this.maskTextSelector,!0)&&r?this.maskTextFn?this.maskTextFn(r,Dt(t.target)):r.replace(/[\S]/g,"*"):r,node:t.target});break}case"attributes":{const r=t.target;let n=t.attributeName,i=t.target.getAttribute(n);if(n==="value"){const a=rt(r);i=tt({element:r,maskInputOptions:this.maskInputOptions,tagName:r.tagName,type:a,value:i,maskInputFn:this.maskInputFn})}if(U(t.target,this.blockClass,this.blockSelector,!1)||i===t.oldValue)return;let o=this.attributeMap.get(t.target);if(r.tagName==="IFRAME"&&n==="src"&&!this.keepIframeSrcFn(i))if(!r.contentDocument)n="rr_src";else return;if(o||(o={node:t.target,attributes:{},styleDiff:{},_unchangedStyles:{}},this.attributes.push(o),this.attributeMap.set(t.target,o)),n==="type"&&r.tagName==="INPUT"&&(t.oldValue||"").toLowerCase()==="password"&&r.setAttribute("data-rr-is-password","true"),!Ot(r.tagName,n)&&(o.attributes[n]=_t(this.doc,ie(r.tagName),ie(n),i),n==="style")){if(!this.unattachedDoc)try{this.unattachedDoc=document.implementation.createHTMLDocument()}catch{this.unattachedDoc=this.doc}const a=this.unattachedDoc.createElement("span");t.oldValue&&a.setAttribute("style",t.oldValue);for(const l of Array.from(r.style)){const s=r.style.getPropertyValue(l),c=r.style.getPropertyPriority(l);s!==a.style.getPropertyValue(l)||c!==a.style.getPropertyPriority(l)?c===""?o.styleDiff[l]=s:o.styleDiff[l]=[s,c]:o._unchangedStyles[l]=[s,c]}for(const l of Array.from(a.style))r.style.getPropertyValue(l)===""&&(o.styleDiff[l]=!1)}break}case"childList":{if(U(t.target,this.blockClass,this.blockSelector,!0))return;if(t.target.tagName==="TEXTAREA"){this.genTextAreaValueMutation(t.target);return}t.addedNodes.forEach(r=>this.genAdds(r,t.target)),t.removedNodes.forEach(r=>{const n=this.mirror.getId(r),i=be(t.target)?this.mirror.getId(t.target.host):this.mirror.getId(t.target);U(t.target,this.blockClass,this.blockSelector,!1)||it(r,this.mirror)||!Jr(r,this.mirror)||(this.addedSet.has(r)?(at(this.addedSet,r),this.droppedSet.add(r)):this.addedSet.has(t.target)&&n===-1||Nt(t.target,this.mirror)||(this.movedSet.has(r)&&this.movedMap[Wt(n,i)]?at(this.movedSet,r):this.removes.push({parentId:i,id:n,isShadow:be(t.target)&&we(t.target)?!0:void 0})),this.mapRemoves.push(r))});break}}},this.genAdds=(t,r)=>{if(!this.processedNodeManager.inOtherBuffer(t,this)&&!(this.addedSet.has(t)||this.movedSet.has(t))){if(this.mirror.hasNode(t)){if(it(t,this.mirror))return;this.movedSet.add(t);let n=null;r&&this.mirror.hasNode(r)&&(n=this.mirror.getId(r)),n&&n!==-1&&(this.movedMap[Wt(this.mirror.getId(t),n)]=!0)}else this.addedSet.add(t),this.droppedSet.delete(t);U(t,this.blockClass,this.blockSelector,!1)||(t.childNodes.forEach(n=>this.genAdds(n)),st(t)&&t.shadowRoot.childNodes.forEach(n=>{this.processedNodeManager.add(n,this),this.genAdds(n,t)}))}}}init(t){["mutationCb","blockClass","blockSelector","maskTextClass","maskTextSelector","inlineStylesheet","maskInputOptions","maskTextFn","maskInputFn","keepIframeSrcFn","recordCanvas","inlineImages","slimDOMOptions","dataURLOptions","doc","mirror","iframeManager","stylesheetManager","shadowDomManager","canvasManager","processedNodeManager"].forEach(r=>{this[r]=t[r]})}freeze(){this.frozen=!0,this.canvasManager.freeze()}unfreeze(){this.frozen=!1,this.canvasManager.unfreeze(),this.emit()}isFrozen(){return this.frozen}lock(){this.locked=!0,this.canvasManager.lock()}unlock(){this.locked=!1,this.canvasManager.unlock(),this.emit()}reset(){this.shadowDomManager.reset(),this.canvasManager.reset()}}function at(e,t){e.delete(t),t.childNodes.forEach(r=>at(e,r))}function Ut(e,t,r){return e.length===0?!1:zt(e,t,r)}function zt(e,t,r){const{parentNode:n}=t;if(!n)return!1;const i=r.getId(n);return e.some(o=>o.id===i)?!0:zt(e,n,r)}function Ht(e,t){return e.size===0?!1:$t(e,t)}function $t(e,t){const{parentNode:r}=t;return r?e.has(r)?!0:$t(e,r):!1}let Ce;function tn(e){Ce=e}function rn(){Ce=void 0}const _=e=>Ce?(...r)=>{try{return e(...r)}catch(n){if(Ce&&Ce(n)===!0)return;throw n}}:e,oe=[];function _e(e){try{if("composedPath"in e){const t=e.composedPath();if(t.length)return t[0]}else if("path"in e&&e.path.length)return e.path[0]}catch{}return e&&e.target}function qt(e,t){var r,n;const i=new en;oe.push(i),i.init(e);let o=window.MutationObserver||window.__rrMutationObserver;const a=(n=(r=window?.Zone)===null||r===void 0?void 0:r.__symbol__)===null||n===void 0?void 0:n.call(r,"MutationObserver");a&&window[a]&&(o=window[a]);const l=new o(_(i.processMutations.bind(i)));return l.observe(t,{attributes:!0,attributeOldValue:!0,characterData:!0,characterDataOldValue:!0,childList:!0,subtree:!0}),l}function nn({mousemoveCb:e,sampling:t,doc:r,mirror:n}){if(t.mousemove===!1)return()=>{};const i=typeof t.mousemove=="number"?t.mousemove:50,o=typeof t.mousemoveCallback=="number"?t.mousemoveCallback:500;let a=[],l;const s=Me(_(f=>{const m=Date.now()-l;e(a.map(h=>(h.timeOffset-=m,h)),f),a=[],l=null}),o),c=_(Me(_(f=>{const m=_e(f),{clientX:h,clientY:g}=ot(f)?f.changedTouches[0]:f;l||(l=Le()),a.push({x:h,y:g,id:n.getId(m),timeOffset:Le()-l}),s(typeof DragEvent<"u"&&f instanceof DragEvent?C.Drag:f instanceof MouseEvent?C.MouseMove:C.TouchMove)}),i,{trailing:!1})),u=[W("mousemove",c,r),W("touchmove",c,r),W("drag",c,r)];return _(()=>{u.forEach(f=>f())})}function on({mouseInteractionCb:e,doc:t,mirror:r,blockClass:n,blockSelector:i,sampling:o}){if(o.mouseInteraction===!1)return()=>{};const a=o.mouseInteraction===!0||o.mouseInteraction===void 0?{}:o.mouseInteraction,l=[];let s=null;const c=u=>f=>{const m=_e(f);if(U(m,n,i,!0))return;let h=null,g=u;if("pointerType"in f){switch(f.pointerType){case"mouse":h=ee.Mouse;break;case"touch":h=ee.Touch;break;case"pen":h=ee.Pen;break}h===ee.Touch?$[u]===$.MouseDown?g="TouchStart":$[u]===$.MouseUp&&(g="TouchEnd"):ee.Pen}else ot(f)&&(h=ee.Touch);h!==null?(s=h,(g.startsWith("Touch")&&h===ee.Touch||g.startsWith("Mouse")&&h===ee.Mouse)&&(h=null)):$[u]===$.Click&&(h=s,s=null);const p=ot(f)?f.changedTouches[0]:f;if(!p)return;const y=r.getId(m),{clientX:w,clientY:S}=p;_(e)(Object.assign({type:$[g],id:y,x:w,y:S},h!==null&&{pointerType:h}))};return Object.keys($).filter(u=>Number.isNaN(Number(u))&&!u.endsWith("_Departed")&&a[u]!==!1).forEach(u=>{let f=ie(u);const m=c(u);if(window.PointerEvent)switch($[u]){case $.MouseDown:case $.MouseUp:f=f.replace("mouse","pointer");break;case $.TouchStart:case $.TouchEnd:return}l.push(W(f,m,t))}),_(()=>{l.forEach(u=>u())})}function jt({scrollCb:e,doc:t,mirror:r,blockClass:n,blockSelector:i,sampling:o}){const a=_(Me(_(l=>{const s=_e(l);if(!s||U(s,n,i,!0))return;const c=r.getId(s);if(s===t&&t.defaultView){const u=xt(t.defaultView);e({id:c,x:u.left,y:u.top})}else e({id:c,x:s.scrollLeft,y:s.scrollTop})}),o.scroll||100));return W("scroll",a,t)}function sn({viewportResizeCb:e},{win:t}){let r=-1,n=-1;const i=_(Me(_(()=>{const o=Rt(),a=Tt();(r!==o||n!==a)&&(e({width:Number(a),height:Number(o)}),r=o,n=a)}),200));return W("resize",i,t)}const an=["INPUT","TEXTAREA","SELECT"],Gt=new WeakMap;function ln({inputCb:e,doc:t,mirror:r,blockClass:n,blockSelector:i,ignoreClass:o,ignoreSelector:a,maskInputOptions:l,maskInputFn:s,sampling:c,userTriggeredOnInput:u}){function f(S){let v=_e(S);const b=S.isTrusted,I=v&&v.tagName;if(v&&I==="OPTION"&&(v=v.parentElement),!v||!I||an.indexOf(I)<0||U(v,n,i,!0)||v.classList.contains(o)||a&&v.matches(a))return;let B=v.value,F=!1;const x=rt(v)||"";x==="radio"||x==="checkbox"?F=v.checked:(l[I.toLowerCase()]||l[x])&&(B=tt({element:v,maskInputOptions:l,tagName:I,type:x,value:B,maskInputFn:s})),m(v,u?{text:B,isChecked:F,userTriggered:b}:{text:B,isChecked:F});const R=v.name;x==="radio"&&R&&F&&t.querySelectorAll(`input[type="radio"][name="${R}"]`).forEach(j=>{if(j!==v){const G=j.value;m(j,u?{text:G,isChecked:!F,userTriggered:!1}:{text:G,isChecked:!F})}})}function m(S,v){const b=Gt.get(S);if(!b||b.text!==v.text||b.isChecked!==v.isChecked){Gt.set(S,v);const I=r.getId(S);_(e)(Object.assign(Object.assign({},v),{id:I}))}}const g=(c.input==="last"?["change"]:["input","change"]).map(S=>W(S,_(f),t)),p=t.defaultView;if(!p)return()=>{g.forEach(S=>S())};const y=p.Object.getOwnPropertyDescriptor(p.HTMLInputElement.prototype,"value"),w=[[p.HTMLInputElement.prototype,"value"],[p.HTMLInputElement.prototype,"checked"],[p.HTMLSelectElement.prototype,"value"],[p.HTMLTextAreaElement.prototype,"value"],[p.HTMLSelectElement.prototype,"selectedIndex"],[p.HTMLOptionElement.prototype,"selected"]];return y&&y.set&&g.push(...w.map(S=>Ae(S[0],S[1],{set(){_(f)({target:this,isTrusted:!1})}},!1,p))),_(()=>{g.forEach(S=>S())})}function Fe(e){const t=[];function r(n,i){if(Pe("CSSGroupingRule")&&n.parentRule instanceof CSSGroupingRule||Pe("CSSMediaRule")&&n.parentRule instanceof CSSMediaRule||Pe("CSSSupportsRule")&&n.parentRule instanceof CSSSupportsRule||Pe("CSSConditionRule")&&n.parentRule instanceof CSSConditionRule){const a=Array.from(n.parentRule.cssRules).indexOf(n);i.unshift(a)}else if(n.parentStyleSheet){const a=Array.from(n.parentStyleSheet.cssRules).indexOf(n);i.unshift(a)}return i}return r(e,t)}function te(e,t,r){let n,i;return e?(e.ownerNode?n=t.getId(e.ownerNode):i=r.getId(e),{styleId:i,id:n}):{}}function un({styleSheetRuleCb:e,mirror:t,stylesheetManager:r},{win:n}){if(!n.CSSStyleSheet||!n.CSSStyleSheet.prototype)return()=>{};const i=n.CSSStyleSheet.prototype.insertRule;n.CSSStyleSheet.prototype.insertRule=new Proxy(i,{apply:_((u,f,m)=>{const[h,g]=m,{id:p,styleId:y}=te(f,t,r.styleMirror);return(p&&p!==-1||y&&y!==-1)&&e({id:p,styleId:y,adds:[{rule:h,index:g}]}),u.apply(f,m)})});const o=n.CSSStyleSheet.prototype.deleteRule;n.CSSStyleSheet.prototype.deleteRule=new Proxy(o,{apply:_((u,f,m)=>{const[h]=m,{id:g,styleId:p}=te(f,t,r.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,removes:[{index:h}]}),u.apply(f,m)})});let a;n.CSSStyleSheet.prototype.replace&&(a=n.CSSStyleSheet.prototype.replace,n.CSSStyleSheet.prototype.replace=new Proxy(a,{apply:_((u,f,m)=>{const[h]=m,{id:g,styleId:p}=te(f,t,r.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,replace:h}),u.apply(f,m)})}));let l;n.CSSStyleSheet.prototype.replaceSync&&(l=n.CSSStyleSheet.prototype.replaceSync,n.CSSStyleSheet.prototype.replaceSync=new Proxy(l,{apply:_((u,f,m)=>{const[h]=m,{id:g,styleId:p}=te(f,t,r.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,replaceSync:h}),u.apply(f,m)})}));const s={};Be("CSSGroupingRule")?s.CSSGroupingRule=n.CSSGroupingRule:(Be("CSSMediaRule")&&(s.CSSMediaRule=n.CSSMediaRule),Be("CSSConditionRule")&&(s.CSSConditionRule=n.CSSConditionRule),Be("CSSSupportsRule")&&(s.CSSSupportsRule=n.CSSSupportsRule));const c={};return Object.entries(s).forEach(([u,f])=>{c[u]={insertRule:f.prototype.insertRule,deleteRule:f.prototype.deleteRule},f.prototype.insertRule=new Proxy(c[u].insertRule,{apply:_((m,h,g)=>{const[p,y]=g,{id:w,styleId:S}=te(h.parentStyleSheet,t,r.styleMirror);return(w&&w!==-1||S&&S!==-1)&&e({id:w,styleId:S,adds:[{rule:p,index:[...Fe(h),y||0]}]}),m.apply(h,g)})}),f.prototype.deleteRule=new Proxy(c[u].deleteRule,{apply:_((m,h,g)=>{const[p]=g,{id:y,styleId:w}=te(h.parentStyleSheet,t,r.styleMirror);return(y&&y!==-1||w&&w!==-1)&&e({id:y,styleId:w,removes:[{index:[...Fe(h),p]}]}),m.apply(h,g)})})}),_(()=>{n.CSSStyleSheet.prototype.insertRule=i,n.CSSStyleSheet.prototype.deleteRule=o,a&&(n.CSSStyleSheet.prototype.replace=a),l&&(n.CSSStyleSheet.prototype.replaceSync=l),Object.entries(s).forEach(([u,f])=>{f.prototype.insertRule=c[u].insertRule,f.prototype.deleteRule=c[u].deleteRule})})}function Vt({mirror:e,stylesheetManager:t},r){var n,i,o;let a=null;r.nodeName==="#document"?a=e.getId(r):a=e.getId(r.host);const l=r.nodeName==="#document"?(n=r.defaultView)===null||n===void 0?void 0:n.Document:(o=(i=r.ownerDocument)===null||i===void 0?void 0:i.defaultView)===null||o===void 0?void 0:o.ShadowRoot,s=l?.prototype?Object.getOwnPropertyDescriptor(l?.prototype,"adoptedStyleSheets"):void 0;return a===null||a===-1||!l||!s?()=>{}:(Object.defineProperty(r,"adoptedStyleSheets",{configurable:s.configurable,enumerable:s.enumerable,get(){var c;return(c=s.get)===null||c===void 0?void 0:c.call(this)},set(c){var u;const f=(u=s.set)===null||u===void 0?void 0:u.call(this,c);if(a!==null&&a!==-1)try{t.adoptStyleSheets(c,a)}catch{}return f}}),_(()=>{Object.defineProperty(r,"adoptedStyleSheets",{configurable:s.configurable,enumerable:s.enumerable,get:s.get,set:s.set})}))}function cn({styleDeclarationCb:e,mirror:t,ignoreCSSAttributes:r,stylesheetManager:n},{win:i}){const o=i.CSSStyleDeclaration.prototype.setProperty;i.CSSStyleDeclaration.prototype.setProperty=new Proxy(o,{apply:_((l,s,c)=>{var u;const[f,m,h]=c;if(r.has(f))return o.apply(s,[f,m,h]);const{id:g,styleId:p}=te((u=s.parentRule)===null||u===void 0?void 0:u.parentStyleSheet,t,n.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,set:{property:f,value:m,priority:h},index:Fe(s.parentRule)}),l.apply(s,c)})});const a=i.CSSStyleDeclaration.prototype.removeProperty;return i.CSSStyleDeclaration.prototype.removeProperty=new Proxy(a,{apply:_((l,s,c)=>{var u;const[f]=c;if(r.has(f))return a.apply(s,[f]);const{id:m,styleId:h}=te((u=s.parentRule)===null||u===void 0?void 0:u.parentStyleSheet,t,n.styleMirror);return(m&&m!==-1||h&&h!==-1)&&e({id:m,styleId:h,remove:{property:f},index:Fe(s.parentRule)}),l.apply(s,c)})}),_(()=>{i.CSSStyleDeclaration.prototype.setProperty=o,i.CSSStyleDeclaration.prototype.removeProperty=a})}function dn({mediaInteractionCb:e,blockClass:t,blockSelector:r,mirror:n,sampling:i,doc:o}){const a=_(s=>Me(_(c=>{const u=_e(c);if(!u||U(u,t,r,!0))return;const{currentTime:f,volume:m,muted:h,playbackRate:g,loop:p}=u;e({type:s,id:n.getId(u),currentTime:f,volume:m,muted:h,playbackRate:g,loop:p})}),i.media||500)),l=[W("play",a(0),o),W("pause",a(1),o),W("seeked",a(2),o),W("volumechange",a(3),o),W("ratechange",a(4),o)];return _(()=>{l.forEach(s=>s())})}function fn({fontCb:e,doc:t}){const r=t.defaultView;if(!r)return()=>{};const n=[],i=new WeakMap,o=r.FontFace;r.FontFace=function(s,c,u){const f=new o(s,c,u);return i.set(f,{family:s,buffer:typeof c!="string",descriptors:u,fontSource:typeof c=="string"?c:JSON.stringify(Array.from(new Uint8Array(c)))}),f};const a=ge(t.fonts,"add",function(l){return function(s){return setTimeout(_(()=>{const c=i.get(s);c&&(e(c),i.delete(s))}),0),l.apply(this,[s])}});return n.push(()=>{r.FontFace=o}),n.push(a),_(()=>{n.forEach(l=>l())})}function hn(e){const{doc:t,mirror:r,blockClass:n,blockSelector:i,selectionCb:o}=e;let a=!0;const l=_(()=>{const s=t.getSelection();if(!s||a&&s?.isCollapsed)return;a=s.isCollapsed||!1;const c=[],u=s.rangeCount||0;for(let f=0;f{}:ge(r.customElements,"define",function(i){return function(o,a,l){try{t({define:{name:o}})}catch{console.warn(`Custom element callback failed for ${o}`)}return i.apply(this,[o,a,l])}})}function mn(e,t){const{mutationCb:r,mousemoveCb:n,mouseInteractionCb:i,scrollCb:o,viewportResizeCb:a,inputCb:l,mediaInteractionCb:s,styleSheetRuleCb:c,styleDeclarationCb:u,canvasMutationCb:f,fontCb:m,selectionCb:h,customElementCb:g}=e;e.mutationCb=(...p)=>{t.mutation&&t.mutation(...p),r(...p)},e.mousemoveCb=(...p)=>{t.mousemove&&t.mousemove(...p),n(...p)},e.mouseInteractionCb=(...p)=>{t.mouseInteraction&&t.mouseInteraction(...p),i(...p)},e.scrollCb=(...p)=>{t.scroll&&t.scroll(...p),o(...p)},e.viewportResizeCb=(...p)=>{t.viewportResize&&t.viewportResize(...p),a(...p)},e.inputCb=(...p)=>{t.input&&t.input(...p),l(...p)},e.mediaInteractionCb=(...p)=>{t.mediaInteaction&&t.mediaInteaction(...p),s(...p)},e.styleSheetRuleCb=(...p)=>{t.styleSheetRule&&t.styleSheetRule(...p),c(...p)},e.styleDeclarationCb=(...p)=>{t.styleDeclaration&&t.styleDeclaration(...p),u(...p)},e.canvasMutationCb=(...p)=>{t.canvasMutation&&t.canvasMutation(...p),f(...p)},e.fontCb=(...p)=>{t.font&&t.font(...p),m(...p)},e.selectionCb=(...p)=>{t.selection&&t.selection(...p),h(...p)},e.customElementCb=(...p)=>{t.customElement&&t.customElement(...p),g(...p)}}function gn(e,t={}){const r=e.doc.defaultView;if(!r)return()=>{};mn(e,t);let n;e.recordDOM&&(n=qt(e,e.doc));const i=nn(e),o=on(e),a=jt(e),l=sn(e,{win:r}),s=ln(e),c=dn(e);let u=()=>{},f=()=>{},m=()=>{},h=()=>{};e.recordDOM&&(u=un(e,{win:r}),f=Vt(e,e.doc),m=cn(e,{win:r}),e.collectFonts&&(h=fn(e)));const g=hn(e),p=pn(e),y=[];for(const w of e.plugins)y.push(w.observer(w.callback,r,w.options));return _(()=>{oe.forEach(w=>w.reset()),n?.disconnect(),i(),o(),a(),l(),s(),c(),u(),f(),m(),h(),g(),p(),y.forEach(w=>w())})}function Pe(e){return typeof window[e]<"u"}function Be(e){return!!(typeof window[e]<"u"&&window[e].prototype&&"insertRule"in window[e].prototype&&"deleteRule"in window[e].prototype)}class Jt{constructor(t){this.generateIdFn=t,this.iframeIdToRemoteIdMap=new WeakMap,this.iframeRemoteIdToIdMap=new WeakMap}getId(t,r,n,i){const o=n||this.getIdToRemoteIdMap(t),a=i||this.getRemoteIdToIdMap(t);let l=o.get(r);return l||(l=this.generateIdFn(),o.set(r,l),a.set(l,r)),l}getIds(t,r){const n=this.getIdToRemoteIdMap(t),i=this.getRemoteIdToIdMap(t);return r.map(o=>this.getId(t,o,n,i))}getRemoteId(t,r,n){const i=n||this.getRemoteIdToIdMap(t);if(typeof r!="number")return r;const o=i.get(r);return o||-1}getRemoteIds(t,r){const n=this.getRemoteIdToIdMap(t);return r.map(i=>this.getRemoteId(t,i,n))}reset(t){if(!t){this.iframeIdToRemoteIdMap=new WeakMap,this.iframeRemoteIdToIdMap=new WeakMap;return}this.iframeIdToRemoteIdMap.delete(t),this.iframeRemoteIdToIdMap.delete(t)}getIdToRemoteIdMap(t){let r=this.iframeIdToRemoteIdMap.get(t);return r||(r=new Map,this.iframeIdToRemoteIdMap.set(t,r)),r}getRemoteIdToIdMap(t){let r=this.iframeRemoteIdToIdMap.get(t);return r||(r=new Map,this.iframeRemoteIdToIdMap.set(t,r)),r}}class yn{constructor(t){this.iframes=new WeakMap,this.crossOriginIframeMap=new WeakMap,this.crossOriginIframeMirror=new Jt(Mt),this.crossOriginIframeRootIdMap=new WeakMap,this.mutationCb=t.mutationCb,this.wrappedEmit=t.wrappedEmit,this.stylesheetManager=t.stylesheetManager,this.recordCrossOriginIframes=t.recordCrossOriginIframes,this.crossOriginIframeStyleMirror=new Jt(this.stylesheetManager.styleMirror.generateId.bind(this.stylesheetManager.styleMirror)),this.mirror=t.mirror,this.recordCrossOriginIframes&&window.addEventListener("message",this.handleMessage.bind(this))}addIframe(t){this.iframes.set(t,!0),t.contentWindow&&this.crossOriginIframeMap.set(t.contentWindow,t)}addLoadListener(t){this.loadListener=t}attachIframe(t,r){var n;this.mutationCb({adds:[{parentId:this.mirror.getId(t),nextId:null,node:r}],removes:[],texts:[],attributes:[],isAttachIframe:!0}),(n=this.loadListener)===null||n===void 0||n.call(this,t),t.contentDocument&&t.contentDocument.adoptedStyleSheets&&t.contentDocument.adoptedStyleSheets.length>0&&this.stylesheetManager.adoptStyleSheets(t.contentDocument.adoptedStyleSheets,this.mirror.getId(t.contentDocument))}handleMessage(t){const r=t;if(r.data.type!=="rrweb"||r.origin!==r.data.origin||!t.source)return;const i=this.crossOriginIframeMap.get(t.source);if(!i)return;const o=this.transformCrossOriginEvent(i,r.data.event);o&&this.wrappedEmit(o,r.data.isCheckout)}transformCrossOriginEvent(t,r){var n;switch(r.type){case O.FullSnapshot:{this.crossOriginIframeMirror.reset(t),this.crossOriginIframeStyleMirror.reset(t),this.replaceIdOnNode(r.data.node,t);const i=r.data.node.id;return this.crossOriginIframeRootIdMap.set(t,i),this.patchRootIdOnNode(r.data.node,i),{timestamp:r.timestamp,type:O.IncrementalSnapshot,data:{source:C.Mutation,adds:[{parentId:this.mirror.getId(t),nextId:null,node:r.data.node}],removes:[],texts:[],attributes:[],isAttachIframe:!0}}}case O.Meta:case O.Load:case O.DomContentLoaded:return!1;case O.Plugin:return r;case O.Custom:return this.replaceIds(r.data.payload,t,["id","parentId","previousId","nextId"]),r;case O.IncrementalSnapshot:switch(r.data.source){case C.Mutation:return r.data.adds.forEach(i=>{this.replaceIds(i,t,["parentId","nextId","previousId"]),this.replaceIdOnNode(i.node,t);const o=this.crossOriginIframeRootIdMap.get(t);o&&this.patchRootIdOnNode(i.node,o)}),r.data.removes.forEach(i=>{this.replaceIds(i,t,["parentId","id"])}),r.data.attributes.forEach(i=>{this.replaceIds(i,t,["id"])}),r.data.texts.forEach(i=>{this.replaceIds(i,t,["id"])}),r;case C.Drag:case C.TouchMove:case C.MouseMove:return r.data.positions.forEach(i=>{this.replaceIds(i,t,["id"])}),r;case C.ViewportResize:return!1;case C.MediaInteraction:case C.MouseInteraction:case C.Scroll:case C.CanvasMutation:case C.Input:return this.replaceIds(r.data,t,["id"]),r;case C.StyleSheetRule:case C.StyleDeclaration:return this.replaceIds(r.data,t,["id"]),this.replaceStyleIds(r.data,t,["styleId"]),r;case C.Font:return r;case C.Selection:return r.data.ranges.forEach(i=>{this.replaceIds(i,t,["start","end"])}),r;case C.AdoptedStyleSheet:return this.replaceIds(r.data,t,["id"]),this.replaceStyleIds(r.data,t,["styleIds"]),(n=r.data.styles)===null||n===void 0||n.forEach(i=>{this.replaceStyleIds(i,t,["styleId"])}),r}}return!1}replace(t,r,n,i){for(const o of i)!Array.isArray(r[o])&&typeof r[o]!="number"||(Array.isArray(r[o])?r[o]=t.getIds(n,r[o]):r[o]=t.getId(n,r[o]));return r}replaceIds(t,r,n){return this.replace(this.crossOriginIframeMirror,t,r,n)}replaceStyleIds(t,r,n){return this.replace(this.crossOriginIframeStyleMirror,t,r,n)}replaceIdOnNode(t,r){this.replaceIds(t,r,["id","rootId"]),"childNodes"in t&&t.childNodes.forEach(n=>{this.replaceIdOnNode(n,r)})}patchRootIdOnNode(t,r){t.type!==A.Document&&!t.rootId&&(t.rootId=r),"childNodes"in t&&t.childNodes.forEach(n=>{this.patchRootIdOnNode(n,r)})}}class vn{constructor(t){this.shadowDoms=new WeakSet,this.restoreHandlers=[],this.mutationCb=t.mutationCb,this.scrollCb=t.scrollCb,this.bypassOptions=t.bypassOptions,this.mirror=t.mirror,this.init()}init(){this.reset(),this.patchAttachShadow(Element,document)}addShadowRoot(t,r){if(!we(t)||this.shadowDoms.has(t))return;this.shadowDoms.add(t);const n=qt(Object.assign(Object.assign({},this.bypassOptions),{doc:r,mutationCb:this.mutationCb,mirror:this.mirror,shadowDomManager:this}),t);this.restoreHandlers.push(()=>n.disconnect()),this.restoreHandlers.push(jt(Object.assign(Object.assign({},this.bypassOptions),{scrollCb:this.scrollCb,doc:t,mirror:this.mirror}))),setTimeout(()=>{t.adoptedStyleSheets&&t.adoptedStyleSheets.length>0&&this.bypassOptions.stylesheetManager.adoptStyleSheets(t.adoptedStyleSheets,this.mirror.getId(t.host)),this.restoreHandlers.push(Vt({mirror:this.mirror,stylesheetManager:this.bypassOptions.stylesheetManager},t))},0)}observeAttachShadow(t){!t.contentWindow||!t.contentDocument||this.patchAttachShadow(t.contentWindow.Element,t.contentDocument)}patchAttachShadow(t,r){const n=this;this.restoreHandlers.push(ge(t.prototype,"attachShadow",function(i){return function(o){const a=i.call(this,o);return this.shadowRoot&&Pt(this)&&n.addShadowRoot(this.shadowRoot,r),a}}))}reset(){this.restoreHandlers.forEach(t=>{try{t()}catch{}}),this.restoreHandlers=[],this.shadowDoms=new WeakSet}}/*! ***************************************************************************** +or you can use record.mirror to access the mirror instance during recording.`;let xt={map:{},getId(){return console.error(ge),-1},getNode(){return console.error(ge),null},removeNodeFromMap(){console.error(ge)},has(){return console.error(ge),!1},reset(){console.error(ge)}};typeof window<"u"&&window.Proxy&&window.Reflect&&(xt=new Proxy(xt,{get(e,t,r){return t==="map"&&console.error(ge),Reflect.get(e,t,r)}}));function Ie(e,t,r={}){let n=null,i=0;return function(...o){const a=Date.now();!i&&r.leading===!1&&(i=a);const l=t-(a-i),s=this;l<=0||l>t?(n&&(clearTimeout(n),n=null),i=a,e.apply(s,o)):!n&&r.trailing!==!1&&(n=setTimeout(()=>{i=r.leading===!1?0:Date.now(),n=null,e.apply(s,o)},l))}}function Ae(e,t,r,n,i=window){const o=i.Object.getOwnPropertyDescriptor(e,t);return i.Object.defineProperty(e,t,n?r:{set(a){setTimeout(()=>{r.set.call(this,a)},0),o&&o.set&&o.set.call(this,a)}}),()=>Ae(e,t,o||{},!0)}function ye(e,t,r){try{if(!(t in e))return()=>{};const n=e[t],i=r(n);return typeof i=="function"&&(i.prototype=i.prototype||{},Object.defineProperties(i,{__rrweb_original__:{enumerable:!1,value:n}})),e[t]=i,()=>{e[t]=n}}catch{return()=>{}}}let Le=Date.now;/[1-9][0-9]{12}/.test(Date.now().toString())||(Le=()=>new Date().getTime());function Rt(e){var t,r,n,i,o,a;const l=e.document;return{left:l.scrollingElement?l.scrollingElement.scrollLeft:e.pageXOffset!==void 0?e.pageXOffset:l?.documentElement.scrollLeft||((r=(t=l?.body)===null||t===void 0?void 0:t.parentElement)===null||r===void 0?void 0:r.scrollLeft)||((n=l?.body)===null||n===void 0?void 0:n.scrollLeft)||0,top:l.scrollingElement?l.scrollingElement.scrollTop:e.pageYOffset!==void 0?e.pageYOffset:l?.documentElement.scrollTop||((o=(i=l?.body)===null||i===void 0?void 0:i.parentElement)===null||o===void 0?void 0:o.scrollTop)||((a=l?.body)===null||a===void 0?void 0:a.scrollTop)||0}}function Tt(){return window.innerHeight||document.documentElement&&document.documentElement.clientHeight||document.body&&document.body.clientHeight}function Dt(){return window.innerWidth||document.documentElement&&document.documentElement.clientWidth||document.body&&document.body.clientWidth}function Nt(e){return e?e.nodeType===e.ELEMENT_NODE?e:e.parentElement:null}function U(e,t,r,n){if(!e)return!1;const i=Nt(e);if(!i)return!1;try{if(typeof t=="string"){if(i.classList.contains(t)||n&&i.closest("."+t)!==null)return!0}else if(Ne(i,t,n))return!0}catch{}return!!(r&&(i.matches(r)||n&&i.closest(r)!==null))}function Xr(e,t){return t.getId(e)!==-1}function it(e,t){return t.getId(e)===Me}function At(e,t){if(be(e))return!1;const r=t.getId(e);return t.has(r)?e.parentNode&&e.parentNode.nodeType===e.DOCUMENT_NODE?!1:e.parentNode?At(e.parentNode,t):!0:!0}function ot(e){return!!e.changedTouches}function Kr(e=window){"NodeList"in e&&!e.NodeList.prototype.forEach&&(e.NodeList.prototype.forEach=Array.prototype.forEach),"DOMTokenList"in e&&!e.DOMTokenList.prototype.forEach&&(e.DOMTokenList.prototype.forEach=Array.prototype.forEach),Node.prototype.contains||(Node.prototype.contains=(...t)=>{let r=t[0];if(!(0 in t))throw new TypeError("1 argument is required");do if(this===r)return!0;while(r=r&&r.parentNode);return!1})}function Lt(e,t){return!!(e.nodeName==="IFRAME"&&t.getMeta(e))}function Ft(e,t){return!!(e.nodeName==="LINK"&&e.nodeType===e.ELEMENT_NODE&&e.getAttribute&&e.getAttribute("rel")==="stylesheet"&&t.getMeta(e))}function st(e){return!!e?.shadowRoot}class Yr{constructor(){this.id=1,this.styleIDMap=new WeakMap,this.idStyleMap=new Map}getId(t){var r;return(r=this.styleIDMap.get(t))!==null&&r!==void 0?r:-1}has(t){return this.styleIDMap.has(t)}add(t,r){if(this.has(t))return this.getId(t);let n;return r===void 0?n=this.id++:n=r,this.styleIDMap.set(t,n),this.idStyleMap.set(n,t),n}getStyle(t){return this.idStyleMap.get(t)||null}reset(){this.styleIDMap=new WeakMap,this.idStyleMap=new Map,this.id=1}generateId(){return this.id++}}function Pt(e){var t,r;let n=null;return((r=(t=e.getRootNode)===null||t===void 0?void 0:t.call(e))===null||r===void 0?void 0:r.nodeType)===Node.DOCUMENT_FRAGMENT_NODE&&e.getRootNode().host&&(n=e.getRootNode().host),n}function Qr(e){let t=e,r;for(;r=Pt(t);)t=r;return t}function Zr(e){const t=e.ownerDocument;if(!t)return!1;const r=Qr(e);return t.contains(r)}function Bt(e){const t=e.ownerDocument;return t?t.contains(e)||Zr(e):!1}var O=(e=>(e[e.DomContentLoaded=0]="DomContentLoaded",e[e.Load=1]="Load",e[e.FullSnapshot=2]="FullSnapshot",e[e.IncrementalSnapshot=3]="IncrementalSnapshot",e[e.Meta=4]="Meta",e[e.Custom=5]="Custom",e[e.Plugin=6]="Plugin",e))(O||{}),C=(e=>(e[e.Mutation=0]="Mutation",e[e.MouseMove=1]="MouseMove",e[e.MouseInteraction=2]="MouseInteraction",e[e.Scroll=3]="Scroll",e[e.ViewportResize=4]="ViewportResize",e[e.Input=5]="Input",e[e.TouchMove=6]="TouchMove",e[e.MediaInteraction=7]="MediaInteraction",e[e.StyleSheetRule=8]="StyleSheetRule",e[e.CanvasMutation=9]="CanvasMutation",e[e.Font=10]="Font",e[e.Log=11]="Log",e[e.Drag=12]="Drag",e[e.StyleDeclaration=13]="StyleDeclaration",e[e.Selection=14]="Selection",e[e.AdoptedStyleSheet=15]="AdoptedStyleSheet",e[e.CustomElement=16]="CustomElement",e))(C||{}),$=(e=>(e[e.MouseUp=0]="MouseUp",e[e.MouseDown=1]="MouseDown",e[e.Click=2]="Click",e[e.ContextMenu=3]="ContextMenu",e[e.DblClick=4]="DblClick",e[e.Focus=5]="Focus",e[e.Blur=6]="Blur",e[e.TouchStart=7]="TouchStart",e[e.TouchMove_Departed=8]="TouchMove_Departed",e[e.TouchEnd=9]="TouchEnd",e[e.TouchCancel=10]="TouchCancel",e))($||{}),ee=(e=>(e[e.Mouse=0]="Mouse",e[e.Pen=1]="Pen",e[e.Touch=2]="Touch",e))(ee||{}),ve=(e=>(e[e["2D"]=0]="2D",e[e.WebGL=1]="WebGL",e[e.WebGL2=2]="WebGL2",e))(ve||{});function Wt(e){return"__ln"in e}class en{constructor(){this.length=0,this.head=null,this.tail=null}get(t){if(t>=this.length)throw new Error("Position outside of list range");let r=this.head;for(let n=0;n`${e}@${t}`;class tn{constructor(){this.frozen=!1,this.locked=!1,this.texts=[],this.attributes=[],this.attributeMap=new WeakMap,this.removes=[],this.mapRemoves=[],this.movedMap={},this.addedSet=new Set,this.movedSet=new Set,this.droppedSet=new Set,this.processMutations=t=>{t.forEach(this.processMutation),this.emit()},this.emit=()=>{if(this.frozen||this.locked)return;const t=[],r=new Set,n=new en,i=s=>{let c=s,u=Me;for(;u===Me;)c=c&&c.nextSibling,u=c&&this.mirror.getId(c);return u},o=s=>{if(!s.parentNode||!Bt(s)||s.parentNode.tagName==="TEXTAREA")return;const c=be(s.parentNode)?this.mirror.getId(Pt(s)):this.mirror.getId(s.parentNode),u=i(s);if(c===-1||u===-1)return n.addNode(s);const h=me(s,{doc:this.doc,mirror:this.mirror,blockClass:this.blockClass,blockSelector:this.blockSelector,maskTextClass:this.maskTextClass,maskTextSelector:this.maskTextSelector,skipChild:!0,newlyAddedElement:!0,inlineStylesheet:this.inlineStylesheet,maskInputOptions:this.maskInputOptions,maskTextFn:this.maskTextFn,maskInputFn:this.maskInputFn,slimDOMOptions:this.slimDOMOptions,dataURLOptions:this.dataURLOptions,recordCanvas:this.recordCanvas,inlineImages:this.inlineImages,onSerialize:m=>{Lt(m,this.mirror)&&this.iframeManager.addIframe(m),Ft(m,this.mirror)&&this.stylesheetManager.trackLinkElement(m),st(s)&&this.shadowDomManager.addShadowRoot(s.shadowRoot,this.doc)},onIframeLoad:(m,f)=>{this.iframeManager.attachIframe(m,f),this.shadowDomManager.observeAttachShadow(m)},onStylesheetLoad:(m,f)=>{this.stylesheetManager.attachLinkElement(m,f)}});h&&(t.push({parentId:c,nextId:u,node:h}),r.add(h.id))};for(;this.mapRemoves.length;)this.mirror.removeNodeFromMap(this.mapRemoves.shift());for(const s of this.movedSet)zt(this.removes,s,this.mirror)&&!this.movedSet.has(s.parentNode)||o(s);for(const s of this.addedSet)!$t(this.droppedSet,s)&&!zt(this.removes,s,this.mirror)||$t(this.movedSet,s)?o(s):this.droppedSet.add(s);let a=null;for(;n.length;){let s=null;if(a){const c=this.mirror.getId(a.value.parentNode),u=i(a.value);c!==-1&&u!==-1&&(s=a)}if(!s){let c=n.tail;for(;c;){const u=c;if(c=c.previous,u){const h=this.mirror.getId(u.value.parentNode);if(i(u.value)===-1)continue;if(h!==-1){s=u;break}else{const f=u.value;if(f.parentNode&&f.parentNode.nodeType===Node.DOCUMENT_FRAGMENT_NODE){const g=f.parentNode.host;if(this.mirror.getId(g)!==-1){s=u;break}}}}}}if(!s){for(;n.head;)n.removeNode(n.head.value);break}a=s.previous,n.removeNode(s.value),o(s.value)}const l={texts:this.texts.map(s=>{const c=s.node;return c.parentNode&&c.parentNode.tagName==="TEXTAREA"&&this.genTextAreaValueMutation(c.parentNode),{id:this.mirror.getId(c),value:s.value}}).filter(s=>!r.has(s.id)).filter(s=>this.mirror.has(s.id)),attributes:this.attributes.map(s=>{const{attributes:c}=s;if(typeof c.style=="string"){const u=JSON.stringify(s.styleDiff),h=JSON.stringify(s._unchangedStyles);u.length!r.has(s.id)).filter(s=>this.mirror.has(s.id)),removes:this.removes,adds:t};!l.texts.length&&!l.attributes.length&&!l.removes.length&&!l.adds.length||(this.texts=[],this.attributes=[],this.attributeMap=new WeakMap,this.removes=[],this.addedSet=new Set,this.movedSet=new Set,this.droppedSet=new Set,this.movedMap={},this.mutationCb(l))},this.genTextAreaValueMutation=t=>{let r=this.attributeMap.get(t);r||(r={node:t,attributes:{},styleDiff:{},_unchangedStyles:{}},this.attributes.push(r),this.attributeMap.set(t,r)),r.attributes.value=Array.from(t.childNodes,n=>n.textContent||"").join("")},this.processMutation=t=>{if(!it(t.target,this.mirror))switch(t.type){case"characterData":{const r=t.target.textContent;!U(t.target,this.blockClass,this.blockSelector,!1)&&r!==t.oldValue&&this.texts.push({value:kt(t.target,this.maskTextClass,this.maskTextSelector,!0)&&r?this.maskTextFn?this.maskTextFn(r,Nt(t.target)):r.replace(/[\S]/g,"*"):r,node:t.target});break}case"attributes":{const r=t.target;let n=t.attributeName,i=t.target.getAttribute(n);if(n==="value"){const a=rt(r);i=tt({element:r,maskInputOptions:this.maskInputOptions,tagName:r.tagName,type:a,value:i,maskInputFn:this.maskInputFn})}if(U(t.target,this.blockClass,this.blockSelector,!1)||i===t.oldValue)return;let o=this.attributeMap.get(t.target);if(r.tagName==="IFRAME"&&n==="src"&&!this.keepIframeSrcFn(i))if(!r.contentDocument)n="rr_src";else return;if(o||(o={node:t.target,attributes:{},styleDiff:{},_unchangedStyles:{}},this.attributes.push(o),this.attributeMap.set(t.target,o)),n==="type"&&r.tagName==="INPUT"&&(t.oldValue||"").toLowerCase()==="password"&&r.setAttribute("data-rr-is-password","true"),!Et(r.tagName,n)&&(o.attributes[n]=Ot(this.doc,ie(r.tagName),ie(n),i),n==="style")){if(!this.unattachedDoc)try{this.unattachedDoc=document.implementation.createHTMLDocument()}catch{this.unattachedDoc=this.doc}const a=this.unattachedDoc.createElement("span");t.oldValue&&a.setAttribute("style",t.oldValue);for(const l of Array.from(r.style)){const s=r.style.getPropertyValue(l),c=r.style.getPropertyPriority(l);s!==a.style.getPropertyValue(l)||c!==a.style.getPropertyPriority(l)?c===""?o.styleDiff[l]=s:o.styleDiff[l]=[s,c]:o._unchangedStyles[l]=[s,c]}for(const l of Array.from(a.style))r.style.getPropertyValue(l)===""&&(o.styleDiff[l]=!1)}break}case"childList":{if(U(t.target,this.blockClass,this.blockSelector,!0))return;if(t.target.tagName==="TEXTAREA"){this.genTextAreaValueMutation(t.target);return}t.addedNodes.forEach(r=>this.genAdds(r,t.target)),t.removedNodes.forEach(r=>{const n=this.mirror.getId(r),i=be(t.target)?this.mirror.getId(t.target.host):this.mirror.getId(t.target);U(t.target,this.blockClass,this.blockSelector,!1)||it(r,this.mirror)||!Xr(r,this.mirror)||(this.addedSet.has(r)?(at(this.addedSet,r),this.droppedSet.add(r)):this.addedSet.has(t.target)&&n===-1||At(t.target,this.mirror)||(this.movedSet.has(r)&&this.movedMap[Ut(n,i)]?at(this.movedSet,r):this.removes.push({parentId:i,id:n,isShadow:be(t.target)&&we(t.target)?!0:void 0})),this.mapRemoves.push(r))});break}}},this.genAdds=(t,r)=>{if(!this.processedNodeManager.inOtherBuffer(t,this)&&!(this.addedSet.has(t)||this.movedSet.has(t))){if(this.mirror.hasNode(t)){if(it(t,this.mirror))return;this.movedSet.add(t);let n=null;r&&this.mirror.hasNode(r)&&(n=this.mirror.getId(r)),n&&n!==-1&&(this.movedMap[Ut(this.mirror.getId(t),n)]=!0)}else this.addedSet.add(t),this.droppedSet.delete(t);U(t,this.blockClass,this.blockSelector,!1)||(t.childNodes.forEach(n=>this.genAdds(n)),st(t)&&t.shadowRoot.childNodes.forEach(n=>{this.processedNodeManager.add(n,this),this.genAdds(n,t)}))}}}init(t){["mutationCb","blockClass","blockSelector","maskTextClass","maskTextSelector","inlineStylesheet","maskInputOptions","maskTextFn","maskInputFn","keepIframeSrcFn","recordCanvas","inlineImages","slimDOMOptions","dataURLOptions","doc","mirror","iframeManager","stylesheetManager","shadowDomManager","canvasManager","processedNodeManager"].forEach(r=>{this[r]=t[r]})}freeze(){this.frozen=!0,this.canvasManager.freeze()}unfreeze(){this.frozen=!1,this.canvasManager.unfreeze(),this.emit()}isFrozen(){return this.frozen}lock(){this.locked=!0,this.canvasManager.lock()}unlock(){this.locked=!1,this.canvasManager.unlock(),this.emit()}reset(){this.shadowDomManager.reset(),this.canvasManager.reset()}}function at(e,t){e.delete(t),t.childNodes.forEach(r=>at(e,r))}function zt(e,t,r){return e.length===0?!1:Ht(e,t,r)}function Ht(e,t,r){const{parentNode:n}=t;if(!n)return!1;const i=r.getId(n);return e.some(o=>o.id===i)?!0:Ht(e,n,r)}function $t(e,t){return e.size===0?!1:qt(e,t)}function qt(e,t){const{parentNode:r}=t;return r?e.has(r)?!0:qt(e,r):!1}let Ce;function rn(e){Ce=e}function nn(){Ce=void 0}const _=e=>Ce?(...r)=>{try{return e(...r)}catch(n){if(Ce&&Ce(n)===!0)return;throw n}}:e,oe=[];function _e(e){try{if("composedPath"in e){const t=e.composedPath();if(t.length)return t[0]}else if("path"in e&&e.path.length)return e.path[0]}catch{}return e&&e.target}function jt(e,t){var r,n;const i=new tn;oe.push(i),i.init(e);let o=window.MutationObserver||window.__rrMutationObserver;const a=(n=(r=window?.Zone)===null||r===void 0?void 0:r.__symbol__)===null||n===void 0?void 0:n.call(r,"MutationObserver");a&&window[a]&&(o=window[a]);const l=new o(_(i.processMutations.bind(i)));return l.observe(t,{attributes:!0,attributeOldValue:!0,characterData:!0,characterDataOldValue:!0,childList:!0,subtree:!0}),l}function on({mousemoveCb:e,sampling:t,doc:r,mirror:n}){if(t.mousemove===!1)return()=>{};const i=typeof t.mousemove=="number"?t.mousemove:50,o=typeof t.mousemoveCallback=="number"?t.mousemoveCallback:500;let a=[],l;const s=Ie(_(h=>{const m=Date.now()-l;e(a.map(f=>(f.timeOffset-=m,f)),h),a=[],l=null}),o),c=_(Ie(_(h=>{const m=_e(h),{clientX:f,clientY:g}=ot(h)?h.changedTouches[0]:h;l||(l=Le()),a.push({x:f,y:g,id:n.getId(m),timeOffset:Le()-l}),s(typeof DragEvent<"u"&&h instanceof DragEvent?C.Drag:h instanceof MouseEvent?C.MouseMove:C.TouchMove)}),i,{trailing:!1})),u=[W("mousemove",c,r),W("touchmove",c,r),W("drag",c,r)];return _(()=>{u.forEach(h=>h())})}function sn({mouseInteractionCb:e,doc:t,mirror:r,blockClass:n,blockSelector:i,sampling:o}){if(o.mouseInteraction===!1)return()=>{};const a=o.mouseInteraction===!0||o.mouseInteraction===void 0?{}:o.mouseInteraction,l=[];let s=null;const c=u=>h=>{const m=_e(h);if(U(m,n,i,!0))return;let f=null,g=u;if("pointerType"in h){switch(h.pointerType){case"mouse":f=ee.Mouse;break;case"touch":f=ee.Touch;break;case"pen":f=ee.Pen;break}f===ee.Touch?$[u]===$.MouseDown?g="TouchStart":$[u]===$.MouseUp&&(g="TouchEnd"):ee.Pen}else ot(h)&&(f=ee.Touch);f!==null?(s=f,(g.startsWith("Touch")&&f===ee.Touch||g.startsWith("Mouse")&&f===ee.Mouse)&&(f=null)):$[u]===$.Click&&(f=s,s=null);const p=ot(h)?h.changedTouches[0]:h;if(!p)return;const y=r.getId(m),{clientX:w,clientY:S}=p;_(e)(Object.assign({type:$[g],id:y,x:w,y:S},f!==null&&{pointerType:f}))};return Object.keys($).filter(u=>Number.isNaN(Number(u))&&!u.endsWith("_Departed")&&a[u]!==!1).forEach(u=>{let h=ie(u);const m=c(u);if(window.PointerEvent)switch($[u]){case $.MouseDown:case $.MouseUp:h=h.replace("mouse","pointer");break;case $.TouchStart:case $.TouchEnd:return}l.push(W(h,m,t))}),_(()=>{l.forEach(u=>u())})}function Gt({scrollCb:e,doc:t,mirror:r,blockClass:n,blockSelector:i,sampling:o}){const a=_(Ie(_(l=>{const s=_e(l);if(!s||U(s,n,i,!0))return;const c=r.getId(s);if(s===t&&t.defaultView){const u=Rt(t.defaultView);e({id:c,x:u.left,y:u.top})}else e({id:c,x:s.scrollLeft,y:s.scrollTop})}),o.scroll||100));return W("scroll",a,t)}function an({viewportResizeCb:e},{win:t}){let r=-1,n=-1;const i=_(Ie(_(()=>{const o=Tt(),a=Dt();(r!==o||n!==a)&&(e({width:Number(a),height:Number(o)}),r=o,n=a)}),200));return W("resize",i,t)}const ln=["INPUT","TEXTAREA","SELECT"],Vt=new WeakMap;function un({inputCb:e,doc:t,mirror:r,blockClass:n,blockSelector:i,ignoreClass:o,ignoreSelector:a,maskInputOptions:l,maskInputFn:s,sampling:c,userTriggeredOnInput:u}){function h(S){let v=_e(S);const b=S.isTrusted,M=v&&v.tagName;if(v&&M==="OPTION"&&(v=v.parentElement),!v||!M||ln.indexOf(M)<0||U(v,n,i,!0)||v.classList.contains(o)||a&&v.matches(a))return;let B=v.value,P=!1;const x=rt(v)||"";x==="radio"||x==="checkbox"?P=v.checked:(l[M.toLowerCase()]||l[x])&&(B=tt({element:v,maskInputOptions:l,tagName:M,type:x,value:B,maskInputFn:s})),m(v,u?{text:B,isChecked:P,userTriggered:b}:{text:B,isChecked:P});const R=v.name;x==="radio"&&R&&P&&t.querySelectorAll(`input[type="radio"][name="${R}"]`).forEach(j=>{if(j!==v){const G=j.value;m(j,u?{text:G,isChecked:!P,userTriggered:!1}:{text:G,isChecked:!P})}})}function m(S,v){const b=Vt.get(S);if(!b||b.text!==v.text||b.isChecked!==v.isChecked){Vt.set(S,v);const M=r.getId(S);_(e)(Object.assign(Object.assign({},v),{id:M}))}}const g=(c.input==="last"?["change"]:["input","change"]).map(S=>W(S,_(h),t)),p=t.defaultView;if(!p)return()=>{g.forEach(S=>S())};const y=p.Object.getOwnPropertyDescriptor(p.HTMLInputElement.prototype,"value"),w=[[p.HTMLInputElement.prototype,"value"],[p.HTMLInputElement.prototype,"checked"],[p.HTMLSelectElement.prototype,"value"],[p.HTMLTextAreaElement.prototype,"value"],[p.HTMLSelectElement.prototype,"selectedIndex"],[p.HTMLOptionElement.prototype,"selected"]];return y&&y.set&&g.push(...w.map(S=>Ae(S[0],S[1],{set(){_(h)({target:this,isTrusted:!1})}},!1,p))),_(()=>{g.forEach(S=>S())})}function Fe(e){const t=[];function r(n,i){if(Pe("CSSGroupingRule")&&n.parentRule instanceof CSSGroupingRule||Pe("CSSMediaRule")&&n.parentRule instanceof CSSMediaRule||Pe("CSSSupportsRule")&&n.parentRule instanceof CSSSupportsRule||Pe("CSSConditionRule")&&n.parentRule instanceof CSSConditionRule){const a=Array.from(n.parentRule.cssRules).indexOf(n);i.unshift(a)}else if(n.parentStyleSheet){const a=Array.from(n.parentStyleSheet.cssRules).indexOf(n);i.unshift(a)}return i}return r(e,t)}function te(e,t,r){let n,i;return e?(e.ownerNode?n=t.getId(e.ownerNode):i=r.getId(e),{styleId:i,id:n}):{}}function cn({styleSheetRuleCb:e,mirror:t,stylesheetManager:r},{win:n}){if(!n.CSSStyleSheet||!n.CSSStyleSheet.prototype)return()=>{};const i=n.CSSStyleSheet.prototype.insertRule;n.CSSStyleSheet.prototype.insertRule=new Proxy(i,{apply:_((u,h,m)=>{const[f,g]=m,{id:p,styleId:y}=te(h,t,r.styleMirror);return(p&&p!==-1||y&&y!==-1)&&e({id:p,styleId:y,adds:[{rule:f,index:g}]}),u.apply(h,m)})});const o=n.CSSStyleSheet.prototype.deleteRule;n.CSSStyleSheet.prototype.deleteRule=new Proxy(o,{apply:_((u,h,m)=>{const[f]=m,{id:g,styleId:p}=te(h,t,r.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,removes:[{index:f}]}),u.apply(h,m)})});let a;n.CSSStyleSheet.prototype.replace&&(a=n.CSSStyleSheet.prototype.replace,n.CSSStyleSheet.prototype.replace=new Proxy(a,{apply:_((u,h,m)=>{const[f]=m,{id:g,styleId:p}=te(h,t,r.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,replace:f}),u.apply(h,m)})}));let l;n.CSSStyleSheet.prototype.replaceSync&&(l=n.CSSStyleSheet.prototype.replaceSync,n.CSSStyleSheet.prototype.replaceSync=new Proxy(l,{apply:_((u,h,m)=>{const[f]=m,{id:g,styleId:p}=te(h,t,r.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,replaceSync:f}),u.apply(h,m)})}));const s={};Be("CSSGroupingRule")?s.CSSGroupingRule=n.CSSGroupingRule:(Be("CSSMediaRule")&&(s.CSSMediaRule=n.CSSMediaRule),Be("CSSConditionRule")&&(s.CSSConditionRule=n.CSSConditionRule),Be("CSSSupportsRule")&&(s.CSSSupportsRule=n.CSSSupportsRule));const c={};return Object.entries(s).forEach(([u,h])=>{c[u]={insertRule:h.prototype.insertRule,deleteRule:h.prototype.deleteRule},h.prototype.insertRule=new Proxy(c[u].insertRule,{apply:_((m,f,g)=>{const[p,y]=g,{id:w,styleId:S}=te(f.parentStyleSheet,t,r.styleMirror);return(w&&w!==-1||S&&S!==-1)&&e({id:w,styleId:S,adds:[{rule:p,index:[...Fe(f),y||0]}]}),m.apply(f,g)})}),h.prototype.deleteRule=new Proxy(c[u].deleteRule,{apply:_((m,f,g)=>{const[p]=g,{id:y,styleId:w}=te(f.parentStyleSheet,t,r.styleMirror);return(y&&y!==-1||w&&w!==-1)&&e({id:y,styleId:w,removes:[{index:[...Fe(f),p]}]}),m.apply(f,g)})})}),_(()=>{n.CSSStyleSheet.prototype.insertRule=i,n.CSSStyleSheet.prototype.deleteRule=o,a&&(n.CSSStyleSheet.prototype.replace=a),l&&(n.CSSStyleSheet.prototype.replaceSync=l),Object.entries(s).forEach(([u,h])=>{h.prototype.insertRule=c[u].insertRule,h.prototype.deleteRule=c[u].deleteRule})})}function Jt({mirror:e,stylesheetManager:t},r){var n,i,o;let a=null;r.nodeName==="#document"?a=e.getId(r):a=e.getId(r.host);const l=r.nodeName==="#document"?(n=r.defaultView)===null||n===void 0?void 0:n.Document:(o=(i=r.ownerDocument)===null||i===void 0?void 0:i.defaultView)===null||o===void 0?void 0:o.ShadowRoot,s=l?.prototype?Object.getOwnPropertyDescriptor(l?.prototype,"adoptedStyleSheets"):void 0;return a===null||a===-1||!l||!s?()=>{}:(Object.defineProperty(r,"adoptedStyleSheets",{configurable:s.configurable,enumerable:s.enumerable,get(){var c;return(c=s.get)===null||c===void 0?void 0:c.call(this)},set(c){var u;const h=(u=s.set)===null||u===void 0?void 0:u.call(this,c);if(a!==null&&a!==-1)try{t.adoptStyleSheets(c,a)}catch{}return h}}),_(()=>{Object.defineProperty(r,"adoptedStyleSheets",{configurable:s.configurable,enumerable:s.enumerable,get:s.get,set:s.set})}))}function dn({styleDeclarationCb:e,mirror:t,ignoreCSSAttributes:r,stylesheetManager:n},{win:i}){const o=i.CSSStyleDeclaration.prototype.setProperty;i.CSSStyleDeclaration.prototype.setProperty=new Proxy(o,{apply:_((l,s,c)=>{var u;const[h,m,f]=c;if(r.has(h))return o.apply(s,[h,m,f]);const{id:g,styleId:p}=te((u=s.parentRule)===null||u===void 0?void 0:u.parentStyleSheet,t,n.styleMirror);return(g&&g!==-1||p&&p!==-1)&&e({id:g,styleId:p,set:{property:h,value:m,priority:f},index:Fe(s.parentRule)}),l.apply(s,c)})});const a=i.CSSStyleDeclaration.prototype.removeProperty;return i.CSSStyleDeclaration.prototype.removeProperty=new Proxy(a,{apply:_((l,s,c)=>{var u;const[h]=c;if(r.has(h))return a.apply(s,[h]);const{id:m,styleId:f}=te((u=s.parentRule)===null||u===void 0?void 0:u.parentStyleSheet,t,n.styleMirror);return(m&&m!==-1||f&&f!==-1)&&e({id:m,styleId:f,remove:{property:h},index:Fe(s.parentRule)}),l.apply(s,c)})}),_(()=>{i.CSSStyleDeclaration.prototype.setProperty=o,i.CSSStyleDeclaration.prototype.removeProperty=a})}function fn({mediaInteractionCb:e,blockClass:t,blockSelector:r,mirror:n,sampling:i,doc:o}){const a=_(s=>Ie(_(c=>{const u=_e(c);if(!u||U(u,t,r,!0))return;const{currentTime:h,volume:m,muted:f,playbackRate:g,loop:p}=u;e({type:s,id:n.getId(u),currentTime:h,volume:m,muted:f,playbackRate:g,loop:p})}),i.media||500)),l=[W("play",a(0),o),W("pause",a(1),o),W("seeked",a(2),o),W("volumechange",a(3),o),W("ratechange",a(4),o)];return _(()=>{l.forEach(s=>s())})}function hn({fontCb:e,doc:t}){const r=t.defaultView;if(!r)return()=>{};const n=[],i=new WeakMap,o=r.FontFace;r.FontFace=function(s,c,u){const h=new o(s,c,u);return i.set(h,{family:s,buffer:typeof c!="string",descriptors:u,fontSource:typeof c=="string"?c:JSON.stringify(Array.from(new Uint8Array(c)))}),h};const a=ye(t.fonts,"add",function(l){return function(s){return setTimeout(_(()=>{const c=i.get(s);c&&(e(c),i.delete(s))}),0),l.apply(this,[s])}});return n.push(()=>{r.FontFace=o}),n.push(a),_(()=>{n.forEach(l=>l())})}function pn(e){const{doc:t,mirror:r,blockClass:n,blockSelector:i,selectionCb:o}=e;let a=!0;const l=_(()=>{const s=t.getSelection();if(!s||a&&s?.isCollapsed)return;a=s.isCollapsed||!1;const c=[],u=s.rangeCount||0;for(let h=0;h{}:ye(r.customElements,"define",function(i){return function(o,a,l){try{t({define:{name:o}})}catch{console.warn(`Custom element callback failed for ${o}`)}return i.apply(this,[o,a,l])}})}function gn(e,t){const{mutationCb:r,mousemoveCb:n,mouseInteractionCb:i,scrollCb:o,viewportResizeCb:a,inputCb:l,mediaInteractionCb:s,styleSheetRuleCb:c,styleDeclarationCb:u,canvasMutationCb:h,fontCb:m,selectionCb:f,customElementCb:g}=e;e.mutationCb=(...p)=>{t.mutation&&t.mutation(...p),r(...p)},e.mousemoveCb=(...p)=>{t.mousemove&&t.mousemove(...p),n(...p)},e.mouseInteractionCb=(...p)=>{t.mouseInteraction&&t.mouseInteraction(...p),i(...p)},e.scrollCb=(...p)=>{t.scroll&&t.scroll(...p),o(...p)},e.viewportResizeCb=(...p)=>{t.viewportResize&&t.viewportResize(...p),a(...p)},e.inputCb=(...p)=>{t.input&&t.input(...p),l(...p)},e.mediaInteractionCb=(...p)=>{t.mediaInteaction&&t.mediaInteaction(...p),s(...p)},e.styleSheetRuleCb=(...p)=>{t.styleSheetRule&&t.styleSheetRule(...p),c(...p)},e.styleDeclarationCb=(...p)=>{t.styleDeclaration&&t.styleDeclaration(...p),u(...p)},e.canvasMutationCb=(...p)=>{t.canvasMutation&&t.canvasMutation(...p),h(...p)},e.fontCb=(...p)=>{t.font&&t.font(...p),m(...p)},e.selectionCb=(...p)=>{t.selection&&t.selection(...p),f(...p)},e.customElementCb=(...p)=>{t.customElement&&t.customElement(...p),g(...p)}}function yn(e,t={}){const r=e.doc.defaultView;if(!r)return()=>{};gn(e,t);let n;e.recordDOM&&(n=jt(e,e.doc));const i=on(e),o=sn(e),a=Gt(e),l=an(e,{win:r}),s=un(e),c=fn(e);let u=()=>{},h=()=>{},m=()=>{},f=()=>{};e.recordDOM&&(u=cn(e,{win:r}),h=Jt(e,e.doc),m=dn(e,{win:r}),e.collectFonts&&(f=hn(e)));const g=pn(e),p=mn(e),y=[];for(const w of e.plugins)y.push(w.observer(w.callback,r,w.options));return _(()=>{oe.forEach(w=>w.reset()),n?.disconnect(),i(),o(),a(),l(),s(),c(),u(),h(),m(),f(),g(),p(),y.forEach(w=>w())})}function Pe(e){return typeof window[e]<"u"}function Be(e){return!!(typeof window[e]<"u"&&window[e].prototype&&"insertRule"in window[e].prototype&&"deleteRule"in window[e].prototype)}class Xt{constructor(t){this.generateIdFn=t,this.iframeIdToRemoteIdMap=new WeakMap,this.iframeRemoteIdToIdMap=new WeakMap}getId(t,r,n,i){const o=n||this.getIdToRemoteIdMap(t),a=i||this.getRemoteIdToIdMap(t);let l=o.get(r);return l||(l=this.generateIdFn(),o.set(r,l),a.set(l,r)),l}getIds(t,r){const n=this.getIdToRemoteIdMap(t),i=this.getRemoteIdToIdMap(t);return r.map(o=>this.getId(t,o,n,i))}getRemoteId(t,r,n){const i=n||this.getRemoteIdToIdMap(t);if(typeof r!="number")return r;const o=i.get(r);return o||-1}getRemoteIds(t,r){const n=this.getRemoteIdToIdMap(t);return r.map(i=>this.getRemoteId(t,i,n))}reset(t){if(!t){this.iframeIdToRemoteIdMap=new WeakMap,this.iframeRemoteIdToIdMap=new WeakMap;return}this.iframeIdToRemoteIdMap.delete(t),this.iframeRemoteIdToIdMap.delete(t)}getIdToRemoteIdMap(t){let r=this.iframeIdToRemoteIdMap.get(t);return r||(r=new Map,this.iframeIdToRemoteIdMap.set(t,r)),r}getRemoteIdToIdMap(t){let r=this.iframeRemoteIdToIdMap.get(t);return r||(r=new Map,this.iframeRemoteIdToIdMap.set(t,r)),r}}class vn{constructor(t){this.iframes=new WeakMap,this.crossOriginIframeMap=new WeakMap,this.crossOriginIframeMirror=new Xt(Ct),this.crossOriginIframeRootIdMap=new WeakMap,this.mutationCb=t.mutationCb,this.wrappedEmit=t.wrappedEmit,this.stylesheetManager=t.stylesheetManager,this.recordCrossOriginIframes=t.recordCrossOriginIframes,this.crossOriginIframeStyleMirror=new Xt(this.stylesheetManager.styleMirror.generateId.bind(this.stylesheetManager.styleMirror)),this.mirror=t.mirror,this.recordCrossOriginIframes&&window.addEventListener("message",this.handleMessage.bind(this))}addIframe(t){this.iframes.set(t,!0),t.contentWindow&&this.crossOriginIframeMap.set(t.contentWindow,t)}addLoadListener(t){this.loadListener=t}attachIframe(t,r){var n;this.mutationCb({adds:[{parentId:this.mirror.getId(t),nextId:null,node:r}],removes:[],texts:[],attributes:[],isAttachIframe:!0}),(n=this.loadListener)===null||n===void 0||n.call(this,t),t.contentDocument&&t.contentDocument.adoptedStyleSheets&&t.contentDocument.adoptedStyleSheets.length>0&&this.stylesheetManager.adoptStyleSheets(t.contentDocument.adoptedStyleSheets,this.mirror.getId(t.contentDocument))}handleMessage(t){const r=t;if(r.data.type!=="rrweb"||r.origin!==r.data.origin||!t.source)return;const i=this.crossOriginIframeMap.get(t.source);if(!i)return;const o=this.transformCrossOriginEvent(i,r.data.event);o&&this.wrappedEmit(o,r.data.isCheckout)}transformCrossOriginEvent(t,r){var n;switch(r.type){case O.FullSnapshot:{this.crossOriginIframeMirror.reset(t),this.crossOriginIframeStyleMirror.reset(t),this.replaceIdOnNode(r.data.node,t);const i=r.data.node.id;return this.crossOriginIframeRootIdMap.set(t,i),this.patchRootIdOnNode(r.data.node,i),{timestamp:r.timestamp,type:O.IncrementalSnapshot,data:{source:C.Mutation,adds:[{parentId:this.mirror.getId(t),nextId:null,node:r.data.node}],removes:[],texts:[],attributes:[],isAttachIframe:!0}}}case O.Meta:case O.Load:case O.DomContentLoaded:return!1;case O.Plugin:return r;case O.Custom:return this.replaceIds(r.data.payload,t,["id","parentId","previousId","nextId"]),r;case O.IncrementalSnapshot:switch(r.data.source){case C.Mutation:return r.data.adds.forEach(i=>{this.replaceIds(i,t,["parentId","nextId","previousId"]),this.replaceIdOnNode(i.node,t);const o=this.crossOriginIframeRootIdMap.get(t);o&&this.patchRootIdOnNode(i.node,o)}),r.data.removes.forEach(i=>{this.replaceIds(i,t,["parentId","id"])}),r.data.attributes.forEach(i=>{this.replaceIds(i,t,["id"])}),r.data.texts.forEach(i=>{this.replaceIds(i,t,["id"])}),r;case C.Drag:case C.TouchMove:case C.MouseMove:return r.data.positions.forEach(i=>{this.replaceIds(i,t,["id"])}),r;case C.ViewportResize:return!1;case C.MediaInteraction:case C.MouseInteraction:case C.Scroll:case C.CanvasMutation:case C.Input:return this.replaceIds(r.data,t,["id"]),r;case C.StyleSheetRule:case C.StyleDeclaration:return this.replaceIds(r.data,t,["id"]),this.replaceStyleIds(r.data,t,["styleId"]),r;case C.Font:return r;case C.Selection:return r.data.ranges.forEach(i=>{this.replaceIds(i,t,["start","end"])}),r;case C.AdoptedStyleSheet:return this.replaceIds(r.data,t,["id"]),this.replaceStyleIds(r.data,t,["styleIds"]),(n=r.data.styles)===null||n===void 0||n.forEach(i=>{this.replaceStyleIds(i,t,["styleId"])}),r}}return!1}replace(t,r,n,i){for(const o of i)!Array.isArray(r[o])&&typeof r[o]!="number"||(Array.isArray(r[o])?r[o]=t.getIds(n,r[o]):r[o]=t.getId(n,r[o]));return r}replaceIds(t,r,n){return this.replace(this.crossOriginIframeMirror,t,r,n)}replaceStyleIds(t,r,n){return this.replace(this.crossOriginIframeStyleMirror,t,r,n)}replaceIdOnNode(t,r){this.replaceIds(t,r,["id","rootId"]),"childNodes"in t&&t.childNodes.forEach(n=>{this.replaceIdOnNode(n,r)})}patchRootIdOnNode(t,r){t.type!==A.Document&&!t.rootId&&(t.rootId=r),"childNodes"in t&&t.childNodes.forEach(n=>{this.patchRootIdOnNode(n,r)})}}class Sn{constructor(t){this.shadowDoms=new WeakSet,this.restoreHandlers=[],this.mutationCb=t.mutationCb,this.scrollCb=t.scrollCb,this.bypassOptions=t.bypassOptions,this.mirror=t.mirror,this.init()}init(){this.reset(),this.patchAttachShadow(Element,document)}addShadowRoot(t,r){if(!we(t)||this.shadowDoms.has(t))return;this.shadowDoms.add(t);const n=jt(Object.assign(Object.assign({},this.bypassOptions),{doc:r,mutationCb:this.mutationCb,mirror:this.mirror,shadowDomManager:this}),t);this.restoreHandlers.push(()=>n.disconnect()),this.restoreHandlers.push(Gt(Object.assign(Object.assign({},this.bypassOptions),{scrollCb:this.scrollCb,doc:t,mirror:this.mirror}))),setTimeout(()=>{t.adoptedStyleSheets&&t.adoptedStyleSheets.length>0&&this.bypassOptions.stylesheetManager.adoptStyleSheets(t.adoptedStyleSheets,this.mirror.getId(t.host)),this.restoreHandlers.push(Jt({mirror:this.mirror,stylesheetManager:this.bypassOptions.stylesheetManager},t))},0)}observeAttachShadow(t){!t.contentWindow||!t.contentDocument||this.patchAttachShadow(t.contentWindow.Element,t.contentDocument)}patchAttachShadow(t,r){const n=this;this.restoreHandlers.push(ye(t.prototype,"attachShadow",function(i){return function(o){const a=i.call(this,o);return this.shadowRoot&&Bt(this)&&n.addShadowRoot(this.shadowRoot,r),a}}))}reset(){this.restoreHandlers.forEach(t=>{try{t()}catch{}}),this.restoreHandlers=[],this.shadowDoms=new WeakSet}}/*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any @@ -13,10 +13,10 @@ or you can use record.mirror to access the mirror instance during recording.`;le LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */function Sn(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var i=0,n=Object.getOwnPropertySymbols(e);i"u"?[]:new Uint8Array(256),We=0;We>2],i+=ve[(t[r]&3)<<4|t[r+1]>>4],i+=ve[(t[r+1]&15)<<2|t[r+2]>>6],i+=ve[t[r+2]&63];return n%3===2?i=i.substring(0,i.length-1)+"=":n%3===1&&(i=i.substring(0,i.length-2)+"=="),i};const Xt=new Map;function Mn(e,t){let r=Xt.get(e);return r||(r=new Map,Xt.set(e,r)),r.has(t)||r.set(t,[]),r.get(t)}const Kt=(e,t,r)=>{if(!e||!(Qt(e,t)||typeof e=="object"))return;const n=e.constructor.name,i=Mn(r,n);let o=i.indexOf(e);return o===-1&&(o=i.length,i.push(e)),o};function Ue(e,t,r){if(e instanceof Array)return e.map(n=>Ue(n,t,r));if(e===null)return e;if(e instanceof Float32Array||e instanceof Float64Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Uint8Array||e instanceof Uint16Array||e instanceof Int16Array||e instanceof Int8Array||e instanceof Uint8ClampedArray)return{rr_type:e.constructor.name,args:[Object.values(e)]};if(e instanceof ArrayBuffer){const n=e.constructor.name,i=In(e);return{rr_type:n,base64:i}}else{if(e instanceof DataView)return{rr_type:e.constructor.name,args:[Ue(e.buffer,t,r),e.byteOffset,e.byteLength]};if(e instanceof HTMLImageElement){const n=e.constructor.name,{src:i}=e;return{rr_type:n,src:i}}else if(e instanceof HTMLCanvasElement){const n="HTMLImageElement",i=e.toDataURL();return{rr_type:n,src:i}}else{if(e instanceof ImageData)return{rr_type:e.constructor.name,args:[Ue(e.data,t,r),e.width,e.height]};if(Qt(e,t)||typeof e=="object"){const n=e.constructor.name,i=Kt(e,t,r);return{rr_type:n,index:i}}}}return e}const Yt=(e,t,r)=>e.map(n=>Ue(n,t,r)),Qt=(e,t)=>!!["WebGLActiveInfo","WebGLBuffer","WebGLFramebuffer","WebGLProgram","WebGLRenderbuffer","WebGLShader","WebGLShaderPrecisionFormat","WebGLTexture","WebGLUniformLocation","WebGLVertexArrayObject","WebGLVertexArrayObjectOES"].filter(i=>typeof t[i]=="function").find(i=>e instanceof t[i]);function Cn(e,t,r,n){const i=[],o=Object.getOwnPropertyNames(t.CanvasRenderingContext2D.prototype);for(const a of o)try{if(typeof t.CanvasRenderingContext2D.prototype[a]!="function")continue;const l=ge(t.CanvasRenderingContext2D.prototype,a,function(s){return function(...c){return U(this.canvas,r,n,!0)||setTimeout(()=>{const u=Yt(c,t,this);e(this.canvas,{type:ye["2D"],property:a,args:u})},0),s.apply(this,c)}});i.push(l)}catch{const s=Ae(t.CanvasRenderingContext2D.prototype,a,{set(c){e(this.canvas,{type:ye["2D"],property:a,args:[c],setter:!0})}});i.push(s)}return()=>{i.forEach(a=>a())}}function _n(e){return e==="experimental-webgl"?"webgl":e}function Zt(e,t,r,n){const i=[];try{const o=ge(e.HTMLCanvasElement.prototype,"getContext",function(a){return function(l,...s){if(!U(this,t,r,!0)){const c=_n(l);if("__context"in this||(this.__context=c),n&&["webgl","webgl2"].includes(c))if(s[0]&&typeof s[0]=="object"){const u=s[0];u.preserveDrawingBuffer||(u.preserveDrawingBuffer=!0)}else s.splice(0,1,{preserveDrawingBuffer:!0})}return a.apply(this,[l,...s])}});i.push(o)}catch{console.error("failed to patch HTMLCanvasElement.prototype.getContext")}return()=>{i.forEach(o=>o())}}function er(e,t,r,n,i,o,a){const l=[],s=Object.getOwnPropertyNames(e);for(const c of s)if(!["isContextLost","canvas","drawingBufferWidth","drawingBufferHeight"].includes(c))try{if(typeof e[c]!="function")continue;const u=ge(e,c,function(f){return function(...m){const h=f.apply(this,m);if(Kt(h,a,this),"tagName"in this.canvas&&!U(this.canvas,n,i,!0)){const g=Yt(m,a,this),p={type:t,property:c,args:g};r(this.canvas,p)}return h}});l.push(u)}catch{const f=Ae(e,c,{set(m){r(this.canvas,{type:t,property:c,args:[m],setter:!0})}});l.push(f)}return l}function On(e,t,r,n,i){const o=[];return o.push(...er(t.WebGLRenderingContext.prototype,ye.WebGL,e,r,n,i,t)),typeof t.WebGL2RenderingContext<"u"&&o.push(...er(t.WebGL2RenderingContext.prototype,ye.WebGL2,e,r,n,i,t)),()=>{o.forEach(a=>a())}}function En(e,t){var r=t===void 0?null:t,n=e.toString(),i=n.split(` + ***************************************************************************** */function bn(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var i=0,n=Object.getOwnPropertySymbols(e);i"u"?[]:new Uint8Array(256),We=0;We>2],i+=Se[(t[r]&3)<<4|t[r+1]>>4],i+=Se[(t[r+1]&15)<<2|t[r+2]>>6],i+=Se[t[r+2]&63];return n%3===2?i=i.substring(0,i.length-1)+"=":n%3===1&&(i=i.substring(0,i.length-2)+"=="),i};const Kt=new Map;function Cn(e,t){let r=Kt.get(e);return r||(r=new Map,Kt.set(e,r)),r.has(t)||r.set(t,[]),r.get(t)}const Yt=(e,t,r)=>{if(!e||!(Zt(e,t)||typeof e=="object"))return;const n=e.constructor.name,i=Cn(r,n);let o=i.indexOf(e);return o===-1&&(o=i.length,i.push(e)),o};function Ue(e,t,r){if(e instanceof Array)return e.map(n=>Ue(n,t,r));if(e===null)return e;if(e instanceof Float32Array||e instanceof Float64Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Uint8Array||e instanceof Uint16Array||e instanceof Int16Array||e instanceof Int8Array||e instanceof Uint8ClampedArray)return{rr_type:e.constructor.name,args:[Object.values(e)]};if(e instanceof ArrayBuffer){const n=e.constructor.name,i=In(e);return{rr_type:n,base64:i}}else{if(e instanceof DataView)return{rr_type:e.constructor.name,args:[Ue(e.buffer,t,r),e.byteOffset,e.byteLength]};if(e instanceof HTMLImageElement){const n=e.constructor.name,{src:i}=e;return{rr_type:n,src:i}}else if(e instanceof HTMLCanvasElement){const n="HTMLImageElement",i=e.toDataURL();return{rr_type:n,src:i}}else{if(e instanceof ImageData)return{rr_type:e.constructor.name,args:[Ue(e.data,t,r),e.width,e.height]};if(Zt(e,t)||typeof e=="object"){const n=e.constructor.name,i=Yt(e,t,r);return{rr_type:n,index:i}}}}return e}const Qt=(e,t,r)=>e.map(n=>Ue(n,t,r)),Zt=(e,t)=>!!["WebGLActiveInfo","WebGLBuffer","WebGLFramebuffer","WebGLProgram","WebGLRenderbuffer","WebGLShader","WebGLShaderPrecisionFormat","WebGLTexture","WebGLUniformLocation","WebGLVertexArrayObject","WebGLVertexArrayObjectOES"].filter(i=>typeof t[i]=="function").find(i=>e instanceof t[i]);function _n(e,t,r,n){const i=[],o=Object.getOwnPropertyNames(t.CanvasRenderingContext2D.prototype);for(const a of o)try{if(typeof t.CanvasRenderingContext2D.prototype[a]!="function")continue;const l=ye(t.CanvasRenderingContext2D.prototype,a,function(s){return function(...c){return U(this.canvas,r,n,!0)||setTimeout(()=>{const u=Qt(c,t,this);e(this.canvas,{type:ve["2D"],property:a,args:u})},0),s.apply(this,c)}});i.push(l)}catch{const s=Ae(t.CanvasRenderingContext2D.prototype,a,{set(c){e(this.canvas,{type:ve["2D"],property:a,args:[c],setter:!0})}});i.push(s)}return()=>{i.forEach(a=>a())}}function On(e){return e==="experimental-webgl"?"webgl":e}function er(e,t,r,n){const i=[];try{const o=ye(e.HTMLCanvasElement.prototype,"getContext",function(a){return function(l,...s){if(!U(this,t,r,!0)){const c=On(l);if("__context"in this||(this.__context=c),n&&["webgl","webgl2"].includes(c))if(s[0]&&typeof s[0]=="object"){const u=s[0];u.preserveDrawingBuffer||(u.preserveDrawingBuffer=!0)}else s.splice(0,1,{preserveDrawingBuffer:!0})}return a.apply(this,[l,...s])}});i.push(o)}catch{console.error("failed to patch HTMLCanvasElement.prototype.getContext")}return()=>{i.forEach(o=>o())}}function tr(e,t,r,n,i,o,a){const l=[],s=Object.getOwnPropertyNames(e);for(const c of s)if(!["isContextLost","canvas","drawingBufferWidth","drawingBufferHeight"].includes(c))try{if(typeof e[c]!="function")continue;const u=ye(e,c,function(h){return function(...m){const f=h.apply(this,m);if(Yt(f,a,this),"tagName"in this.canvas&&!U(this.canvas,n,i,!0)){const g=Qt(m,a,this),p={type:t,property:c,args:g};r(this.canvas,p)}return f}});l.push(u)}catch{const h=Ae(e,c,{set(m){r(this.canvas,{type:t,property:c,args:[m],setter:!0})}});l.push(h)}return l}function En(e,t,r,n,i){const o=[];return o.push(...tr(t.WebGLRenderingContext.prototype,ve.WebGL,e,r,n,i,t)),typeof t.WebGL2RenderingContext<"u"&&o.push(...tr(t.WebGL2RenderingContext.prototype,ve.WebGL2,e,r,n,i,t)),()=>{o.forEach(a=>a())}}function kn(e,t){var r=t===void 0?null:t,n=e.toString(),i=n.split(` `);i.pop(),i.shift();for(var o=i[0].search(/\S/),a=/(['"])__worker_loader_strict__(['"])/g,l=0,s=i.length;l"u"?[]:new Uint8Array(256),n=0;n>2],h+=t[(u[f]&3)<<4|u[f+1]>>4],h+=t[(u[f+1]&15)<<2|u[f+2]>>6],h+=t[u[f+2]&63];return m%3===2?h=h.substring(0,h.length-1)+"=":m%3===1&&(h=h.substring(0,h.length-2)+"=="),h};const o=new Map,a=new Map;function l(c,u,f){return e(this,void 0,void 0,function*(){const m=`${c}-${u}`;if("OffscreenCanvas"in globalThis){if(a.has(m))return a.get(m);const h=new OffscreenCanvas(c,u);h.getContext("2d");const p=yield(yield h.convertToBlob(f)).arrayBuffer(),y=i(p);return a.set(m,y),y}else return""})}const s=self;s.onmessage=function(c){return e(this,void 0,void 0,function*(){if("OffscreenCanvas"in globalThis){const{id:u,bitmap:f,width:m,height:h,dataURLOptions:g}=c.data,p=l(m,h,g),y=new OffscreenCanvas(m,h);y.getContext("2d").drawImage(f,0,0),f.close();const S=yield y.convertToBlob(g),v=S.type,b=yield S.arrayBuffer(),I=i(b);if(!o.has(u)&&(yield p)===I)return o.set(u,I),s.postMessage({id:u});if(o.get(u)===I)return s.postMessage({id:u});s.postMessage({id:u,type:v,base64:I,width:m,height:h}),o.set(u,I)}else return s.postMessage({id:c.data.id})})}})()},null);class Tn{reset(){this.pendingCanvasMutations.clear(),this.resetObservers&&this.resetObservers()}freeze(){this.frozen=!0}unfreeze(){this.frozen=!1}lock(){this.locked=!0}unlock(){this.locked=!1}constructor(t){this.pendingCanvasMutations=new Map,this.rafStamps={latestId:0,invokeId:null},this.frozen=!1,this.locked=!1,this.processMutation=(s,c)=>{(this.rafStamps.invokeId&&this.rafStamps.latestId!==this.rafStamps.invokeId||!this.rafStamps.invokeId)&&(this.rafStamps.invokeId=this.rafStamps.latestId),this.pendingCanvasMutations.has(s)||this.pendingCanvasMutations.set(s,[]),this.pendingCanvasMutations.get(s).push(c)};const{sampling:r="all",win:n,blockClass:i,blockSelector:o,recordCanvas:a,dataURLOptions:l}=t;this.mutationCb=t.mutationCb,this.mirror=t.mirror,a&&r==="all"&&this.initCanvasMutationObserver(n,i,o),a&&typeof r=="number"&&this.initCanvasFPSObserver(r,n,i,o,{dataURLOptions:l})}initCanvasFPSObserver(t,r,n,i,o){const a=Zt(r,n,i,!0),l=new Map,s=new Rn;s.onmessage=g=>{const{id:p}=g.data;if(l.set(p,!1),!("base64"in g.data))return;const{base64:y,type:w,width:S,height:v}=g.data;this.mutationCb({id:p,type:ye["2D"],commands:[{property:"clearRect",args:[0,0,S,v]},{property:"drawImage",args:[{rr_type:"ImageBitmap",args:[{rr_type:"Blob",data:[{rr_type:"ArrayBuffer",base64:y}],type:w}]},0,0]}]})};const c=1e3/t;let u=0,f;const m=()=>{const g=[];return r.document.querySelectorAll("canvas").forEach(p=>{U(p,n,i,!0)||g.push(p)}),g},h=g=>{if(u&&g-ubn(this,void 0,void 0,function*(){var y;const w=this.mirror.getId(p);if(l.get(w)||p.width===0||p.height===0)return;if(l.set(w,!0),["webgl","webgl2"].includes(p.__context)){const v=p.getContext(p.__context);((y=v?.getContextAttributes())===null||y===void 0?void 0:y.preserveDrawingBuffer)===!1&&v.clear(v.COLOR_BUFFER_BIT)}const S=yield createImageBitmap(p);s.postMessage({id:w,bitmap:S,width:p.width,height:p.height,dataURLOptions:o.dataURLOptions},[S])})),f=requestAnimationFrame(h)};f=requestAnimationFrame(h),this.resetObservers=()=>{a(),cancelAnimationFrame(f)}}initCanvasMutationObserver(t,r,n){this.startRAFTimestamping(),this.startPendingCanvasMutationFlusher();const i=Zt(t,r,n,!1),o=Cn(this.processMutation.bind(this),t,r,n),a=On(this.processMutation.bind(this),t,r,n,this.mirror);this.resetObservers=()=>{i(),o(),a()}}startPendingCanvasMutationFlusher(){requestAnimationFrame(()=>this.flushPendingCanvasMutations())}startRAFTimestamping(){const t=r=>{this.rafStamps.latestId=r,requestAnimationFrame(t)};requestAnimationFrame(t)}flushPendingCanvasMutations(){this.pendingCanvasMutations.forEach((t,r)=>{const n=this.mirror.getId(r);this.flushPendingCanvasMutationFor(r,n)}),requestAnimationFrame(()=>this.flushPendingCanvasMutations())}flushPendingCanvasMutationFor(t,r){if(this.frozen||this.locked)return;const n=this.pendingCanvasMutations.get(t);if(!n||r===-1)return;const i=n.map(a=>Sn(a,["type"])),{type:o}=n[0];this.mutationCb({id:r,type:o,commands:i}),this.pendingCanvasMutations.delete(t)}}class Dn{constructor(t){this.trackedLinkElements=new WeakSet,this.styleMirror=new Kr,this.mutationCb=t.mutationCb,this.adoptedStyleSheetCb=t.adoptedStyleSheetCb}attachLinkElement(t,r){"_cssText"in r.attributes&&this.mutationCb({adds:[],removes:[],texts:[],attributes:[{id:r.id,attributes:r.attributes}]}),this.trackLinkElement(t)}trackLinkElement(t){this.trackedLinkElements.has(t)||(this.trackedLinkElements.add(t),this.trackStylesheetInLinkElement(t))}adoptStyleSheets(t,r){if(t.length===0)return;const n={id:r,styleIds:[]},i=[];for(const o of t){let a;this.styleMirror.has(o)?a=this.styleMirror.getId(o):(a=this.styleMirror.add(o),i.push({styleId:a,rules:Array.from(o.rules||CSSRule,(l,s)=>({rule:St(l),index:s}))})),n.styleIds.push(a)}i.length>0&&(n.styles=i),this.adoptedStyleSheetCb(n)}reset(){this.styleMirror.reset(),this.trackedLinkElements=new WeakSet}trackStylesheetInLinkElement(t){}}class Nn{constructor(){this.nodeMap=new WeakMap,this.loop=!0,this.periodicallyClear()}periodicallyClear(){requestAnimationFrame(()=>{this.clear(),this.loop&&this.periodicallyClear()})}inOtherBuffer(t,r){const n=this.nodeMap.get(t);return n&&Array.from(n).some(i=>i!==r)}add(t,r){this.nodeMap.set(t,(this.nodeMap.get(t)||new Set).add(r))}clear(){this.nodeMap=new WeakMap}destroy(){this.loop=!1}}function L(e){return Object.assign(Object.assign({},e),{timestamp:Le()})}let N,ze,lt,He=!1;const V=_r();function Oe(e={}){const{emit:t,checkoutEveryNms:r,checkoutEveryNth:n,blockClass:i="rr-block",blockSelector:o=null,ignoreClass:a="rr-ignore",ignoreSelector:l=null,maskTextClass:s="rr-mask",maskTextSelector:c=null,inlineStylesheet:u=!0,maskAllInputs:f,maskInputOptions:m,slimDOMOptions:h,maskInputFn:g,maskTextFn:p,hooks:y,packFn:w,sampling:S={},dataURLOptions:v={},mousemoveWait:b,recordDOM:I=!0,recordCanvas:B=!1,recordCrossOriginIframes:F=!1,recordAfter:x=e.recordAfter==="DOMContentLoaded"?e.recordAfter:"load",userTriggeredOnInput:R=!1,collectFonts:j=!1,inlineImages:G=!1,plugins:E,keepIframeSrcFn:le=()=>!1,ignoreCSSAttributes:z=new Set([]),errorHandler:ne}=e;tn(ne);const Z=F?window.parent===window:!0;let Qe=!1;if(!Z)try{window.parent.document&&(Qe=!1)}catch{Qe=!0}if(Z&&!t)throw new Error("emit function is required");b!==void 0&&S.mousemove===void 0&&(S.mousemove=b),V.reset();const pt=f===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:m!==void 0?m:{password:!0},mt=h===!0||h==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaVerification:!0,headMetaAuthorship:h==="all",headMetaDescKeywords:h==="all"}:h||{};Xr();let mr,gt=0;const gr=M=>{for(const K of E||[])K.eventProcessor&&(M=K.eventProcessor(M));return w&&!Qe&&(M=w(M)),M};N=(M,K)=>{var D;if(!((D=oe[0])===null||D===void 0)&&D.isFrozen()&&M.type!==O.FullSnapshot&&!(M.type===O.IncrementalSnapshot&&M.data.source===C.Mutation)&&oe.forEach(H=>H.unfreeze()),Z)t?.(gr(M),K);else if(Qe){const H={type:"rrweb",event:gr(M),origin:window.location.origin,isCheckout:K};window.parent.postMessage(H,"*")}if(M.type===O.FullSnapshot)mr=M,gt=0;else if(M.type===O.IncrementalSnapshot){if(M.data.source===C.Mutation&&M.data.isAttachIframe)return;gt++;const H=n&>>=n,de=r&&M.timestamp-mr.timestamp>r;(H||de)&&ze(!0)}};const Ze=M=>{N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Mutation},M)}))},yr=M=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Scroll},M)})),vr=M=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.CanvasMutation},M)})),ei=M=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.AdoptedStyleSheet},M)})),ue=new Dn({mutationCb:Ze,adoptedStyleSheetCb:ei}),ce=new yn({mirror:V,mutationCb:Ze,stylesheetManager:ue,recordCrossOriginIframes:F,wrappedEmit:N});for(const M of E||[])M.getMirror&&M.getMirror({nodeMirror:V,crossOriginIframeMirror:ce.crossOriginIframeMirror,crossOriginIframeStyleMirror:ce.crossOriginIframeStyleMirror});const yt=new Nn;lt=new Tn({recordCanvas:B,mutationCb:vr,win:window,blockClass:i,blockSelector:o,mirror:V,sampling:S.canvas,dataURLOptions:v});const et=new vn({mutationCb:Ze,scrollCb:yr,bypassOptions:{blockClass:i,blockSelector:o,maskTextClass:s,maskTextSelector:c,inlineStylesheet:u,maskInputOptions:pt,dataURLOptions:v,maskTextFn:p,maskInputFn:g,recordCanvas:B,inlineImages:G,sampling:S,slimDOMOptions:mt,iframeManager:ce,stylesheetManager:ue,canvasManager:lt,keepIframeSrcFn:le,processedNodeManager:yt},mirror:V});ze=(M=!1)=>{if(!I)return;N(L({type:O.Meta,data:{href:window.location.href,width:Tt(),height:Rt()}}),M),ue.reset(),et.init(),oe.forEach(D=>D.lock());const K=Vr(document,{mirror:V,blockClass:i,blockSelector:o,maskTextClass:s,maskTextSelector:c,inlineStylesheet:u,maskAllInputs:pt,maskTextFn:p,slimDOM:mt,dataURLOptions:v,recordCanvas:B,inlineImages:G,onSerialize:D=>{At(D,V)&&ce.addIframe(D),Lt(D,V)&&ue.trackLinkElement(D),st(D)&&et.addShadowRoot(D.shadowRoot,document)},onIframeLoad:(D,H)=>{ce.attachIframe(D,H),et.observeAttachShadow(D)},onStylesheetLoad:(D,H)=>{ue.attachLinkElement(D,H)},keepIframeSrcFn:le});if(!K)return console.warn("Failed to snapshot the document");N(L({type:O.FullSnapshot,data:{node:K,initialOffset:xt(window)}}),M),oe.forEach(D=>D.unlock()),document.adoptedStyleSheets&&document.adoptedStyleSheets.length>0&&ue.adoptStyleSheets(document.adoptedStyleSheets,V.getId(document))};try{const M=[],K=H=>{var de;return _(gn)({mutationCb:Ze,mousemoveCb:(T,vt)=>N(L({type:O.IncrementalSnapshot,data:{source:vt,positions:T}})),mouseInteractionCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.MouseInteraction},T)})),scrollCb:yr,viewportResizeCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.ViewportResize},T)})),inputCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Input},T)})),mediaInteractionCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.MediaInteraction},T)})),styleSheetRuleCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.StyleSheetRule},T)})),styleDeclarationCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.StyleDeclaration},T)})),canvasMutationCb:vr,fontCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Font},T)})),selectionCb:T=>{N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Selection},T)}))},customElementCb:T=>{N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.CustomElement},T)}))},blockClass:i,ignoreClass:a,ignoreSelector:l,maskTextClass:s,maskTextSelector:c,maskInputOptions:pt,inlineStylesheet:u,sampling:S,recordDOM:I,recordCanvas:B,inlineImages:G,userTriggeredOnInput:R,collectFonts:j,doc:H,maskInputFn:g,maskTextFn:p,keepIframeSrcFn:le,blockSelector:o,slimDOMOptions:mt,dataURLOptions:v,mirror:V,iframeManager:ce,stylesheetManager:ue,shadowDomManager:et,processedNodeManager:yt,canvasManager:lt,ignoreCSSAttributes:z,plugins:((de=E?.filter(T=>T.observer))===null||de===void 0?void 0:de.map(T=>({observer:T.observer,options:T.options,callback:vt=>N(L({type:O.Plugin,data:{plugin:T.name,payload:vt}}))})))||[]},y)};ce.addLoadListener(H=>{try{M.push(K(H.contentDocument))}catch(de){console.warn(de)}});const D=()=>{ze(),M.push(K(document)),He=!0};return document.readyState==="interactive"||document.readyState==="complete"?D():(M.push(W("DOMContentLoaded",()=>{N(L({type:O.DomContentLoaded,data:{}})),x==="DOMContentLoaded"&&D()})),M.push(W("load",()=>{N(L({type:O.Load,data:{}})),x==="load"&&D()},window))),()=>{M.forEach(H=>H()),yt.destroy(),He=!1,rn()}}catch(M){console.warn(M)}}Oe.addCustomEvent=(e,t)=>{if(!He)throw new Error("please add custom event after start recording");N(L({type:O.Custom,data:{tag:e,payload:t}}))},Oe.freezePage=()=>{oe.forEach(e=>e.freeze())},Oe.takeFullSnapshot=e=>{if(!He)throw new Error("please take full snapshot after start recording");ze(e)},Oe.mirror=V;var tr=(e=>(e[e.DomContentLoaded=0]="DomContentLoaded",e[e.Load=1]="Load",e[e.FullSnapshot=2]="FullSnapshot",e[e.IncrementalSnapshot=3]="IncrementalSnapshot",e[e.Meta=4]="Meta",e[e.Custom=5]="Custom",e[e.Plugin=6]="Plugin",e))(tr||{}),Y=(e=>(e[e.Mutation=0]="Mutation",e[e.MouseMove=1]="MouseMove",e[e.MouseInteraction=2]="MouseInteraction",e[e.Scroll=3]="Scroll",e[e.ViewportResize=4]="ViewportResize",e[e.Input=5]="Input",e[e.TouchMove=6]="TouchMove",e[e.MediaInteraction=7]="MediaInteraction",e[e.StyleSheetRule=8]="StyleSheetRule",e[e.CanvasMutation=9]="CanvasMutation",e[e.Font=10]="Font",e[e.Log=11]="Log",e[e.Drag=12]="Drag",e[e.StyleDeclaration=13]="StyleDeclaration",e[e.Selection=14]="Selection",e[e.AdoptedStyleSheet=15]="AdoptedStyleSheet",e[e.CustomElement=16]="CustomElement",e))(Y||{}),rr={DEBUG:!1,LIB_VERSION:"2.55.0"},P;if(typeof window>"u"){var nr={hostname:""};P={navigator:{userAgent:""},document:{location:nr,referrer:""},screen:{width:0,height:0},location:nr}}else P=window;var $e=24*60*60*1e3,qe=Array.prototype,An=Function.prototype,ir=Object.prototype,se=qe.slice,Ee=ir.toString,je=ir.hasOwnProperty,ke=P.console,xe=P.navigator,q=P.document,Ge=P.opera,Ve=P.screen,ae=xe.userAgent,ut=An.bind,or=qe.forEach,sr=qe.indexOf,ar=qe.map,Ln=Array.isArray,ct={},d={trim:function(e){return e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}},J={log:function(){},warn:function(){},error:function(){},critical:function(){if(!d.isUndefined(ke)&&ke){var e=["Mixpanel error:"].concat(d.toArray(arguments));try{ke.error.apply(ke,e)}catch{d.each(e,function(r){ke.error(r)})}}}},dt=function(e,t){return function(){return arguments[0]="["+t+"] "+arguments[0],e.apply(J,arguments)}},Je=function(e){return{log:dt(J.log,e),error:dt(J.error,e),critical:dt(J.critical,e)}};d.bind=function(e,t){var r,n;if(ut&&e.bind===ut)return ut.apply(e,se.call(arguments,1));if(!d.isFunction(e))throw new TypeError;return r=se.call(arguments,2),n=function(){if(!(this instanceof n))return e.apply(t,r.concat(se.call(arguments)));var i={};i.prototype=e.prototype;var o=new i;i.prototype=null;var a=e.apply(o,r.concat(se.call(arguments)));return Object(a)===a?a:o},n},d.each=function(e,t,r){if(e!=null){if(or&&e.forEach===or)e.forEach(t,r);else if(e.length===+e.length){for(var n=0,i=e.length;n0&&(t[n]=r)}),t},d.truncate=function(e,t){var r;return typeof e=="string"?r=e.slice(0,t):d.isArray(e)?(r=[],d.each(e,function(n){r.push(d.truncate(n,t))})):d.isObject(e)?(r={},d.each(e,function(n,i){r[i]=d.truncate(n,t)})):r=e,r},d.JSONEncode=function(){return function(e){var t=e,r=function(i){var o=/[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,a={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return o.lastIndex=0,o.test(i)?'"'+i.replace(o,function(l){var s=a[l];return typeof s=="string"?s:"\\u"+("0000"+l.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+i+'"'},n=function(i,o){var a="",l=" ",s=0,c="",u="",f=0,m=a,h=[],g=o[i];switch(g&&typeof g=="object"&&typeof g.toJSON=="function"&&(g=g.toJSON(i)),typeof g){case"string":return r(g);case"number":return isFinite(g)?String(g):"null";case"boolean":case"null":return String(g);case"object":if(!g)return"null";if(a+=l,h=[],Ee.apply(g)==="[object Array]"){for(f=g.length,s=0;s"u"?[]:new Uint8Array(256),n=0;n>2],f+=t[(u[h]&3)<<4|u[h+1]>>4],f+=t[(u[h+1]&15)<<2|u[h+2]>>6],f+=t[u[h+2]&63];return m%3===2?f=f.substring(0,f.length-1)+"=":m%3===1&&(f=f.substring(0,f.length-2)+"=="),f};const o=new Map,a=new Map;function l(c,u,h){return e(this,void 0,void 0,function*(){const m=`${c}-${u}`;if("OffscreenCanvas"in globalThis){if(a.has(m))return a.get(m);const f=new OffscreenCanvas(c,u);f.getContext("2d");const p=yield(yield f.convertToBlob(h)).arrayBuffer(),y=i(p);return a.set(m,y),y}else return""})}const s=self;s.onmessage=function(c){return e(this,void 0,void 0,function*(){if("OffscreenCanvas"in globalThis){const{id:u,bitmap:h,width:m,height:f,dataURLOptions:g}=c.data,p=l(m,f,g),y=new OffscreenCanvas(m,f);y.getContext("2d").drawImage(h,0,0),h.close();const S=yield y.convertToBlob(g),v=S.type,b=yield S.arrayBuffer(),M=i(b);if(!o.has(u)&&(yield p)===M)return o.set(u,M),s.postMessage({id:u});if(o.get(u)===M)return s.postMessage({id:u});s.postMessage({id:u,type:v,base64:M,width:m,height:f}),o.set(u,M)}else return s.postMessage({id:c.data.id})})}})()},null);class Dn{reset(){this.pendingCanvasMutations.clear(),this.resetObservers&&this.resetObservers()}freeze(){this.frozen=!0}unfreeze(){this.frozen=!1}lock(){this.locked=!0}unlock(){this.locked=!1}constructor(t){this.pendingCanvasMutations=new Map,this.rafStamps={latestId:0,invokeId:null},this.frozen=!1,this.locked=!1,this.processMutation=(s,c)=>{(this.rafStamps.invokeId&&this.rafStamps.latestId!==this.rafStamps.invokeId||!this.rafStamps.invokeId)&&(this.rafStamps.invokeId=this.rafStamps.latestId),this.pendingCanvasMutations.has(s)||this.pendingCanvasMutations.set(s,[]),this.pendingCanvasMutations.get(s).push(c)};const{sampling:r="all",win:n,blockClass:i,blockSelector:o,recordCanvas:a,dataURLOptions:l}=t;this.mutationCb=t.mutationCb,this.mirror=t.mirror,a&&r==="all"&&this.initCanvasMutationObserver(n,i,o),a&&typeof r=="number"&&this.initCanvasFPSObserver(r,n,i,o,{dataURLOptions:l})}initCanvasFPSObserver(t,r,n,i,o){const a=er(r,n,i,!0),l=new Map,s=new Tn;s.onmessage=g=>{const{id:p}=g.data;if(l.set(p,!1),!("base64"in g.data))return;const{base64:y,type:w,width:S,height:v}=g.data;this.mutationCb({id:p,type:ve["2D"],commands:[{property:"clearRect",args:[0,0,S,v]},{property:"drawImage",args:[{rr_type:"ImageBitmap",args:[{rr_type:"Blob",data:[{rr_type:"ArrayBuffer",base64:y}],type:w}]},0,0]}]})};const c=1e3/t;let u=0,h;const m=()=>{const g=[];return r.document.querySelectorAll("canvas").forEach(p=>{U(p,n,i,!0)||g.push(p)}),g},f=g=>{if(u&&g-uwn(this,void 0,void 0,function*(){var y;const w=this.mirror.getId(p);if(l.get(w)||p.width===0||p.height===0)return;if(l.set(w,!0),["webgl","webgl2"].includes(p.__context)){const v=p.getContext(p.__context);((y=v?.getContextAttributes())===null||y===void 0?void 0:y.preserveDrawingBuffer)===!1&&v.clear(v.COLOR_BUFFER_BIT)}const S=yield createImageBitmap(p);s.postMessage({id:w,bitmap:S,width:p.width,height:p.height,dataURLOptions:o.dataURLOptions},[S])})),h=requestAnimationFrame(f)};h=requestAnimationFrame(f),this.resetObservers=()=>{a(),cancelAnimationFrame(h)}}initCanvasMutationObserver(t,r,n){this.startRAFTimestamping(),this.startPendingCanvasMutationFlusher();const i=er(t,r,n,!1),o=_n(this.processMutation.bind(this),t,r,n),a=En(this.processMutation.bind(this),t,r,n,this.mirror);this.resetObservers=()=>{i(),o(),a()}}startPendingCanvasMutationFlusher(){requestAnimationFrame(()=>this.flushPendingCanvasMutations())}startRAFTimestamping(){const t=r=>{this.rafStamps.latestId=r,requestAnimationFrame(t)};requestAnimationFrame(t)}flushPendingCanvasMutations(){this.pendingCanvasMutations.forEach((t,r)=>{const n=this.mirror.getId(r);this.flushPendingCanvasMutationFor(r,n)}),requestAnimationFrame(()=>this.flushPendingCanvasMutations())}flushPendingCanvasMutationFor(t,r){if(this.frozen||this.locked)return;const n=this.pendingCanvasMutations.get(t);if(!n||r===-1)return;const i=n.map(a=>bn(a,["type"])),{type:o}=n[0];this.mutationCb({id:r,type:o,commands:i}),this.pendingCanvasMutations.delete(t)}}class Nn{constructor(t){this.trackedLinkElements=new WeakSet,this.styleMirror=new Yr,this.mutationCb=t.mutationCb,this.adoptedStyleSheetCb=t.adoptedStyleSheetCb}attachLinkElement(t,r){"_cssText"in r.attributes&&this.mutationCb({adds:[],removes:[],texts:[],attributes:[{id:r.id,attributes:r.attributes}]}),this.trackLinkElement(t)}trackLinkElement(t){this.trackedLinkElements.has(t)||(this.trackedLinkElements.add(t),this.trackStylesheetInLinkElement(t))}adoptStyleSheets(t,r){if(t.length===0)return;const n={id:r,styleIds:[]},i=[];for(const o of t){let a;this.styleMirror.has(o)?a=this.styleMirror.getId(o):(a=this.styleMirror.add(o),i.push({styleId:a,rules:Array.from(o.rules||CSSRule,(l,s)=>({rule:bt(l),index:s}))})),n.styleIds.push(a)}i.length>0&&(n.styles=i),this.adoptedStyleSheetCb(n)}reset(){this.styleMirror.reset(),this.trackedLinkElements=new WeakSet}trackStylesheetInLinkElement(t){}}class An{constructor(){this.nodeMap=new WeakMap,this.loop=!0,this.periodicallyClear()}periodicallyClear(){requestAnimationFrame(()=>{this.clear(),this.loop&&this.periodicallyClear()})}inOtherBuffer(t,r){const n=this.nodeMap.get(t);return n&&Array.from(n).some(i=>i!==r)}add(t,r){this.nodeMap.set(t,(this.nodeMap.get(t)||new Set).add(r))}clear(){this.nodeMap=new WeakMap}destroy(){this.loop=!1}}function L(e){return Object.assign(Object.assign({},e),{timestamp:Le()})}let N,ze,lt,He=!1;const V=Or();function Oe(e={}){const{emit:t,checkoutEveryNms:r,checkoutEveryNth:n,blockClass:i="rr-block",blockSelector:o=null,ignoreClass:a="rr-ignore",ignoreSelector:l=null,maskTextClass:s="rr-mask",maskTextSelector:c=null,inlineStylesheet:u=!0,maskAllInputs:h,maskInputOptions:m,slimDOMOptions:f,maskInputFn:g,maskTextFn:p,hooks:y,packFn:w,sampling:S={},dataURLOptions:v={},mousemoveWait:b,recordDOM:M=!0,recordCanvas:B=!1,recordCrossOriginIframes:P=!1,recordAfter:x=e.recordAfter==="DOMContentLoaded"?e.recordAfter:"load",userTriggeredOnInput:R=!1,collectFonts:j=!1,inlineImages:G=!1,plugins:E,keepIframeSrcFn:ue=()=>!1,ignoreCSSAttributes:z=new Set([]),errorHandler:ne}=e;rn(ne);const Z=P?window.parent===window:!0;let Qe=!1;if(!Z)try{window.parent.document&&(Qe=!1)}catch{Qe=!0}if(Z&&!t)throw new Error("emit function is required");b!==void 0&&S.mousemove===void 0&&(S.mousemove=b),V.reset();const mt=h===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:m!==void 0?m:{password:!0},gt=f===!0||f==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaVerification:!0,headMetaAuthorship:f==="all",headMetaDescKeywords:f==="all"}:f||{};Kr();let gr,yt=0;const yr=I=>{for(const K of E||[])K.eventProcessor&&(I=K.eventProcessor(I));return w&&!Qe&&(I=w(I)),I};N=(I,K)=>{var D;if(!((D=oe[0])===null||D===void 0)&&D.isFrozen()&&I.type!==O.FullSnapshot&&!(I.type===O.IncrementalSnapshot&&I.data.source===C.Mutation)&&oe.forEach(H=>H.unfreeze()),Z)t?.(yr(I),K);else if(Qe){const H={type:"rrweb",event:yr(I),origin:window.location.origin,isCheckout:K};window.parent.postMessage(H,"*")}if(I.type===O.FullSnapshot)gr=I,yt=0;else if(I.type===O.IncrementalSnapshot){if(I.data.source===C.Mutation&&I.data.isAttachIframe)return;yt++;const H=n&&yt>=n,fe=r&&I.timestamp-gr.timestamp>r;(H||fe)&&ze(!0)}};const Ze=I=>{N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Mutation},I)}))},vr=I=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Scroll},I)})),Sr=I=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.CanvasMutation},I)})),ri=I=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.AdoptedStyleSheet},I)})),ce=new Nn({mutationCb:Ze,adoptedStyleSheetCb:ri}),de=new vn({mirror:V,mutationCb:Ze,stylesheetManager:ce,recordCrossOriginIframes:P,wrappedEmit:N});for(const I of E||[])I.getMirror&&I.getMirror({nodeMirror:V,crossOriginIframeMirror:de.crossOriginIframeMirror,crossOriginIframeStyleMirror:de.crossOriginIframeStyleMirror});const vt=new An;lt=new Dn({recordCanvas:B,mutationCb:Sr,win:window,blockClass:i,blockSelector:o,mirror:V,sampling:S.canvas,dataURLOptions:v});const et=new Sn({mutationCb:Ze,scrollCb:vr,bypassOptions:{blockClass:i,blockSelector:o,maskTextClass:s,maskTextSelector:c,inlineStylesheet:u,maskInputOptions:mt,dataURLOptions:v,maskTextFn:p,maskInputFn:g,recordCanvas:B,inlineImages:G,sampling:S,slimDOMOptions:gt,iframeManager:de,stylesheetManager:ce,canvasManager:lt,keepIframeSrcFn:ue,processedNodeManager:vt},mirror:V});ze=(I=!1)=>{if(!M)return;N(L({type:O.Meta,data:{href:window.location.href,width:Dt(),height:Tt()}}),I),ce.reset(),et.init(),oe.forEach(D=>D.lock());const K=Jr(document,{mirror:V,blockClass:i,blockSelector:o,maskTextClass:s,maskTextSelector:c,inlineStylesheet:u,maskAllInputs:mt,maskTextFn:p,slimDOM:gt,dataURLOptions:v,recordCanvas:B,inlineImages:G,onSerialize:D=>{Lt(D,V)&&de.addIframe(D),Ft(D,V)&&ce.trackLinkElement(D),st(D)&&et.addShadowRoot(D.shadowRoot,document)},onIframeLoad:(D,H)=>{de.attachIframe(D,H),et.observeAttachShadow(D)},onStylesheetLoad:(D,H)=>{ce.attachLinkElement(D,H)},keepIframeSrcFn:ue});if(!K)return console.warn("Failed to snapshot the document");N(L({type:O.FullSnapshot,data:{node:K,initialOffset:Rt(window)}}),I),oe.forEach(D=>D.unlock()),document.adoptedStyleSheets&&document.adoptedStyleSheets.length>0&&ce.adoptStyleSheets(document.adoptedStyleSheets,V.getId(document))};try{const I=[],K=H=>{var fe;return _(yn)({mutationCb:Ze,mousemoveCb:(T,St)=>N(L({type:O.IncrementalSnapshot,data:{source:St,positions:T}})),mouseInteractionCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.MouseInteraction},T)})),scrollCb:vr,viewportResizeCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.ViewportResize},T)})),inputCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Input},T)})),mediaInteractionCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.MediaInteraction},T)})),styleSheetRuleCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.StyleSheetRule},T)})),styleDeclarationCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.StyleDeclaration},T)})),canvasMutationCb:Sr,fontCb:T=>N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Font},T)})),selectionCb:T=>{N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.Selection},T)}))},customElementCb:T=>{N(L({type:O.IncrementalSnapshot,data:Object.assign({source:C.CustomElement},T)}))},blockClass:i,ignoreClass:a,ignoreSelector:l,maskTextClass:s,maskTextSelector:c,maskInputOptions:mt,inlineStylesheet:u,sampling:S,recordDOM:M,recordCanvas:B,inlineImages:G,userTriggeredOnInput:R,collectFonts:j,doc:H,maskInputFn:g,maskTextFn:p,keepIframeSrcFn:ue,blockSelector:o,slimDOMOptions:gt,dataURLOptions:v,mirror:V,iframeManager:de,stylesheetManager:ce,shadowDomManager:et,processedNodeManager:vt,canvasManager:lt,ignoreCSSAttributes:z,plugins:((fe=E?.filter(T=>T.observer))===null||fe===void 0?void 0:fe.map(T=>({observer:T.observer,options:T.options,callback:St=>N(L({type:O.Plugin,data:{plugin:T.name,payload:St}}))})))||[]},y)};de.addLoadListener(H=>{try{I.push(K(H.contentDocument))}catch(fe){console.warn(fe)}});const D=()=>{ze(),I.push(K(document)),He=!0};return document.readyState==="interactive"||document.readyState==="complete"?D():(I.push(W("DOMContentLoaded",()=>{N(L({type:O.DomContentLoaded,data:{}})),x==="DOMContentLoaded"&&D()})),I.push(W("load",()=>{N(L({type:O.Load,data:{}})),x==="load"&&D()},window))),()=>{I.forEach(H=>H()),vt.destroy(),He=!1,nn()}}catch(I){console.warn(I)}}Oe.addCustomEvent=(e,t)=>{if(!He)throw new Error("please add custom event after start recording");N(L({type:O.Custom,data:{tag:e,payload:t}}))},Oe.freezePage=()=>{oe.forEach(e=>e.freeze())},Oe.takeFullSnapshot=e=>{if(!He)throw new Error("please take full snapshot after start recording");ze(e)},Oe.mirror=V;var rr=(e=>(e[e.DomContentLoaded=0]="DomContentLoaded",e[e.Load=1]="Load",e[e.FullSnapshot=2]="FullSnapshot",e[e.IncrementalSnapshot=3]="IncrementalSnapshot",e[e.Meta=4]="Meta",e[e.Custom=5]="Custom",e[e.Plugin=6]="Plugin",e))(rr||{}),Y=(e=>(e[e.Mutation=0]="Mutation",e[e.MouseMove=1]="MouseMove",e[e.MouseInteraction=2]="MouseInteraction",e[e.Scroll=3]="Scroll",e[e.ViewportResize=4]="ViewportResize",e[e.Input=5]="Input",e[e.TouchMove=6]="TouchMove",e[e.MediaInteraction=7]="MediaInteraction",e[e.StyleSheetRule=8]="StyleSheetRule",e[e.CanvasMutation=9]="CanvasMutation",e[e.Font=10]="Font",e[e.Log=11]="Log",e[e.Drag=12]="Drag",e[e.StyleDeclaration=13]="StyleDeclaration",e[e.Selection=14]="Selection",e[e.AdoptedStyleSheet=15]="AdoptedStyleSheet",e[e.CustomElement=16]="CustomElement",e))(Y||{}),nr={DEBUG:!1,LIB_VERSION:"2.55.1"},F;if(typeof window>"u"){var ir={hostname:""};F={navigator:{userAgent:"",onLine:!0},document:{location:ir,referrer:""},screen:{width:0,height:0},location:ir}}else F=window;var $e=24*60*60*1e3,ut=8*1e3,qe=Array.prototype,Ln=Function.prototype,or=Object.prototype,se=qe.slice,Ee=or.toString,je=or.hasOwnProperty,ke=F.console,xe=F.navigator,q=F.document,Ge=F.opera,Ve=F.screen,ae=xe.userAgent,ct=Ln.bind,sr=qe.forEach,ar=qe.indexOf,lr=qe.map,Fn=Array.isArray,dt={},d={trim:function(e){return e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}},J={log:function(){},warn:function(){},error:function(){},critical:function(){if(!d.isUndefined(ke)&&ke){var e=["Mixpanel error:"].concat(d.toArray(arguments));try{ke.error.apply(ke,e)}catch{d.each(e,function(r){ke.error(r)})}}}},ft=function(e,t){return function(){return arguments[0]="["+t+"] "+arguments[0],e.apply(J,arguments)}},Je=function(e){return{log:ft(J.log,e),error:ft(J.error,e),critical:ft(J.critical,e)}};d.bind=function(e,t){var r,n;if(ct&&e.bind===ct)return ct.apply(e,se.call(arguments,1));if(!d.isFunction(e))throw new TypeError;return r=se.call(arguments,2),n=function(){if(!(this instanceof n))return e.apply(t,r.concat(se.call(arguments)));var i={};i.prototype=e.prototype;var o=new i;i.prototype=null;var a=e.apply(o,r.concat(se.call(arguments)));return Object(a)===a?a:o},n},d.each=function(e,t,r){if(e!=null){if(sr&&e.forEach===sr)e.forEach(t,r);else if(e.length===+e.length){for(var n=0,i=e.length;n0&&(t[n]=r)}),t},d.truncate=function(e,t){var r;return typeof e=="string"?r=e.slice(0,t):d.isArray(e)?(r=[],d.each(e,function(n){r.push(d.truncate(n,t))})):d.isObject(e)?(r={},d.each(e,function(n,i){r[i]=d.truncate(n,t)})):r=e,r},d.JSONEncode=function(){return function(e){var t=e,r=function(i){var o=/[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,a={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return o.lastIndex=0,o.test(i)?'"'+i.replace(o,function(l){var s=a[l];return typeof s=="string"?s:"\\u"+("0000"+l.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+i+'"'},n=function(i,o){var a="",l=" ",s=0,c="",u="",h=0,m=a,f=[],g=o[i];switch(g&&typeof g=="object"&&typeof g.toJSON=="function"&&(g=g.toJSON(i)),typeof g){case"string":return r(g);case"number":return isFinite(g)?String(g):"null";case"boolean":case"null":return String(g);case"object":if(!g)return"null";if(a+=l,f=[],Ee.apply(g)==="[object Array]"){for(h=g.length,s=0;s="0"&&t<="9";)g+=t,o();if(t===".")for(g+=".";o()&&t>="0"&&t<="9";)g+=t;if(t==="e"||t==="E")for(g+=t,o(),(t==="-"||t==="+")&&(g+=t,o());t>="0"&&t<="9";)g+=t,o();if(h=+g,!isFinite(h))i("Bad number");else return h},l=function(){var h,g,p="",y;if(t==='"')for(;o();){if(t==='"')return o(),p;if(t==="\\")if(o(),t==="u"){for(y=0,g=0;g<4&&(h=parseInt(o(),16),!!isFinite(h));g+=1)y=y*16+h;p+=String.fromCharCode(y)}else if(typeof r[t]=="string")p+=r[t];else break;else p+=t}i("Bad string")},s=function(){for(;t&&t<=" ";)o()},c=function(){switch(t){case"t":return o("t"),o("r"),o("u"),o("e"),!0;case"f":return o("f"),o("a"),o("l"),o("s"),o("e"),!1;case"n":return o("n"),o("u"),o("l"),o("l"),null}i('Unexpected "'+t+'"')},u,f=function(){var h=[];if(t==="["){if(o("["),s(),t==="]")return o("]"),h;for(;t;){if(h.push(u()),s(),t==="]")return o("]"),h;o(","),s()}}i("Bad array")},m=function(){var h,g={};if(t==="{"){if(o("{"),s(),t==="}")return o("}"),g;for(;t;){if(h=l(),s(),o(":"),Object.hasOwnProperty.call(g,h)&&i('Duplicate key "'+h+'"'),g[h]=u(),s(),t==="}")return o("}"),g;o(","),s()}}i("Bad object")};return u=function(){switch(s(),t){case"{":return m();case"[":return f();case'"':return l();case"-":return a();default:return t>="0"&&t<="9"?a():c()}},function(h){var g;return n=h,e=0,t=" ",g=u(),s(),t&&i("Syntax error"),g}}(),d.base64Encode=function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r,n,i,o,a,l,s,c,u=0,f=0,m="",h=[];if(!e)return e;e=d.utf8Encode(e);do r=e.charCodeAt(u++),n=e.charCodeAt(u++),i=e.charCodeAt(u++),c=r<<16|n<<8|i,o=c>>18&63,a=c>>12&63,l=c>>6&63,s=c&63,h[f++]=t.charAt(o)+t.charAt(a)+t.charAt(l)+t.charAt(s);while(u="0"&&t<="9";)g+=t,o();if(t===".")for(g+=".";o()&&t>="0"&&t<="9";)g+=t;if(t==="e"||t==="E")for(g+=t,o(),(t==="-"||t==="+")&&(g+=t,o());t>="0"&&t<="9";)g+=t,o();if(f=+g,!isFinite(f))i("Bad number");else return f},l=function(){var f,g,p="",y;if(t==='"')for(;o();){if(t==='"')return o(),p;if(t==="\\")if(o(),t==="u"){for(y=0,g=0;g<4&&(f=parseInt(o(),16),!!isFinite(f));g+=1)y=y*16+f;p+=String.fromCharCode(y)}else if(typeof r[t]=="string")p+=r[t];else break;else p+=t}i("Bad string")},s=function(){for(;t&&t<=" ";)o()},c=function(){switch(t){case"t":return o("t"),o("r"),o("u"),o("e"),!0;case"f":return o("f"),o("a"),o("l"),o("s"),o("e"),!1;case"n":return o("n"),o("u"),o("l"),o("l"),null}i('Unexpected "'+t+'"')},u,h=function(){var f=[];if(t==="["){if(o("["),s(),t==="]")return o("]"),f;for(;t;){if(f.push(u()),s(),t==="]")return o("]"),f;o(","),s()}}i("Bad array")},m=function(){var f,g={};if(t==="{"){if(o("{"),s(),t==="}")return o("}"),g;for(;t;){if(f=l(),s(),o(":"),Object.hasOwnProperty.call(g,f)&&i('Duplicate key "'+f+'"'),g[f]=u(),s(),t==="}")return o("}"),g;o(","),s()}}i("Bad object")};return u=function(){switch(s(),t){case"{":return m();case"[":return h();case'"':return l();case"-":return a();default:return t>="0"&&t<="9"?a():c()}},function(f){var g;return n=f,e=0,t=" ",g=u(),s(),t&&i("Syntax error"),g}}(),d.base64Encode=function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r,n,i,o,a,l,s,c,u=0,h=0,m="",f=[];if(!e)return e;e=d.utf8Encode(e);do r=e.charCodeAt(u++),n=e.charCodeAt(u++),i=e.charCodeAt(u++),c=r<<16|n<<8|i,o=c>>18&63,a=c>>12&63,l=c>>6&63,s=c&63,f[h++]=t.charAt(o)+t.charAt(a)+t.charAt(l)+t.charAt(s);while(u127&&a<2048?l=String.fromCharCode(a>>6|192,a&63|128):l=String.fromCharCode(a>>12|224,a>>6&63|128,a&63|128),l!==null&&(n>r&&(t+=e.substring(r,n)),t+=l,r=n=o+1)}return n>r&&(t+=e.substring(r,e.length)),t},d.UUID=function(){var e=function(){var n=1*new Date,i;if(P.performance&&P.performance.now)i=P.performance.now();else for(i=0;n==1*new Date;)i++;return n.toString(16)+Math.floor(i).toString(16)},t=function(){return Math.random().toString(16).replace(".","")},r=function(){var n=ae,i,o,a=[],l=0;function s(c,u){var f,m=0;for(f=0;f=4&&(l=s(l,a),a=[]);return a.length>0&&(l=s(l,a)),l.toString(16)};return function(){var n=(Ve.height*Ve.width).toString(16);return e()+"-"+t()+"-"+r()+"-"+n+"-"+e()}}();var lr=["ahrefsbot","ahrefssiteaudit","baiduspider","bingbot","bingpreview","chrome-lighthouse","facebookexternal","petalbot","pinterest","screaming frog","yahoo! slurp","yandexbot","adsbot-google","apis-google","duplexweb-google","feedfetcher-google","google favicon","google web preview","google-read-aloud","googlebot","googleweblight","mediapartners-google","storebot-google"];d.isBlockedUA=function(e){var t;for(e=e.toLowerCase(),t=0;t=0}function n(i){if(!q.getElementsByTagName)return[];var o=i.split(" "),a,l,s,c,u,f,m,h,g,p,y=[q];for(f=0;f-1){l=a.split("#"),s=l[0];var w=l[1],S=q.getElementById(w);if(!S||s&&S.nodeName.toLowerCase()!=s)return[];y=[S];continue}if(a.indexOf(".")>-1){l=a.split("."),s=l[0];var v=l[1];for(s||(s="*"),c=[],u=0,m=0;m-1};break;default:x=function(R){return R.getAttribute(I)}}for(y=[],p=0,m=0;m=3?t[2]:""},currentUrl:function(){return P.location.href},properties:function(e){return typeof e!="object"&&(e={}),d.extend(d.strip_empty_properties({$os:d.info.os(),$browser:d.info.browser(ae,xe.vendor,Ge),$referrer:q.referrer,$referring_domain:d.info.referringDomain(q.referrer),$device:d.info.device(ae)}),{$current_url:d.info.currentUrl(),$browser_version:d.info.browserVersion(ae,xe.vendor,Ge),$screen_height:Ve.height,$screen_width:Ve.width,mp_lib:"web",$lib_version:rr.LIB_VERSION,$insert_id:ht(),time:d.timestamp()/1e3},d.strip_empty_properties(e))},people_properties:function(){return d.extend(d.strip_empty_properties({$os:d.info.os(),$browser:d.info.browser(ae,xe.vendor,Ge)}),{$browser_version:d.info.browserVersion(ae,xe.vendor,Ge)})},mpPageViewProperties:function(){return d.strip_empty_properties({current_page_title:q.title,current_domain:P.location.hostname,current_url_path:P.location.pathname,current_url_protocol:P.location.protocol,current_url_search:P.location.search})}};var ht=function(e){var t=Math.random().toString(36).substring(2,10)+Math.random().toString(36).substring(2,10);return e?t.substring(0,e):t},Wn=/[a-z0-9][a-z0-9-]*\.[a-z]+$/i,Un=/[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i,ur=function(e){var t=Un,r=e.split("."),n=r[r.length-1];(n.length>4||n==="com"||n==="org")&&(t=Wn);var i=e.match(t);return i?i[0]:""},Ke=null,Ye=null;typeof JSON<"u"&&(Ke=JSON.stringify,Ye=JSON.parse),Ke=Ke||d.JSONEncode,Ye=Ye||d.JSONDecode,d.toArray=d.toArray,d.isObject=d.isObject,d.JSONEncode=d.JSONEncode,d.JSONDecode=d.JSONDecode,d.isBlockedUA=d.isBlockedUA,d.isEmptyObject=d.isEmptyObject,d.info=d.info,d.info.device=d.info.device,d.info.browser=d.info.browser,d.info.browserVersion=d.info.browserVersion,d.info.properties=d.info.properties;var zn="__mp_opt_in_out_";function Hn(e,t){if(Vn(t))return J.warn('This browser has "Do Not Track" enabled. This will prevent the Mixpanel SDK from sending any data. To ignore the "Do Not Track" browser setting, initialize the Mixpanel instance with the config "ignore_dnt: true"'),!0;var r=Gn(e,t)==="0";return r&&J.warn("You are opted out of Mixpanel tracking. This will prevent the Mixpanel SDK from sending any data."),r}function $n(e){return Jn(e,function(t){return this.get_config(t)})}function qn(e){return e=e||{},e.persistenceType==="localStorage"?d.localStorage:d.cookie}function jn(e,t){return t=t||{},(t.persistencePrefix||zn)+e}function Gn(e,t){return qn(t).get(jn(e,t))}function Vn(e){if(e&&e.ignoreDnt)return!1;var t=e&&e.window||P,r=t.navigator||{},n=!1;return d.each([r.doNotTrack,r.msDoNotTrack,t.doNotTrack],function(i){d.includes([!0,1,"1","yes"],i)&&(n=!0)}),n}function Jn(e,t){return function(){var r=!1;try{var n=t.call(this,"token"),i=t.call(this,"ignore_dnt"),o=t.call(this,"opt_out_tracking_persistence_type"),a=t.call(this,"opt_out_tracking_cookie_prefix"),l=t.call(this,"window");n&&(r=Hn(n,{ignoreDnt:i,persistenceType:o,persistencePrefix:a,window:l}))}catch(c){J.error("Unexpected error when checking tracking opt-out status: "+c)}if(!r)return e.apply(this,arguments);var s=arguments[arguments.length-1];typeof s=="function"&&s(0)}}var Xn=Je("lock"),cr=function(e,t){t=t||{},this.storageKey=e,this.storage=t.storage||window.localStorage,this.pollIntervalMS=t.pollIntervalMS||100,this.timeoutMS=t.timeoutMS||2e3};cr.prototype.withLock=function(e,t,r){!r&&typeof t!="function"&&(r=t,t=null);var n=r||new Date().getTime()+"|"+Math.random(),i=new Date().getTime(),o=this.storageKey,a=this.pollIntervalMS,l=this.timeoutMS,s=this.storage,c=o+":X",u=o+":Y",f=o+":Z",m=function(S){t&&t(S)},h=function(S){if(new Date().getTime()-i>l){Xn.error("Timeout waiting for mutex on "+o+"; clearing lock. ["+n+"]"),s.removeItem(f),s.removeItem(u),y();return}setTimeout(function(){try{S()}catch(v){m(v)}},a*(Math.random()+.1))},g=function(S,v){S()?v():h(function(){g(S,v)})},p=function(){var S=s.getItem(u);if(S&&S!==n)return!1;if(s.setItem(u,n),s.getItem(u)===n)return!0;if(!Xe(s,!0))throw new Error("localStorage support dropped while acquiring lock");return!1},y=function(){s.setItem(c,n),g(p,function(){if(s.getItem(c)===n){w();return}h(function(){if(s.getItem(u)!==n){y();return}g(function(){return!s.getItem(f)},w)})})},w=function(){s.setItem(f,"1");try{e()}finally{s.removeItem(f),s.getItem(u)===n&&s.removeItem(u),s.getItem(c)===n&&s.removeItem(c)}};try{if(Xe(s,!0))y();else throw new Error("localStorage support check failed")}catch(S){m(S)}};var dr=Je("batch"),re=function(e,t){t=t||{},this.storageKey=e,this.storage=t.storage||window.localStorage,this.reportError=t.errorReporter||d.bind(dr.error,dr),this.lock=new cr(e,{storage:this.storage}),this.usePersistence=t.usePersistence,this.pid=t.pid||null,this.memQueue=[]};re.prototype.enqueue=function(e,t,r){var n={id:ht(),flushAfter:new Date().getTime()+t*2,payload:e};this.usePersistence?this.lock.withLock(d.bind(function(){var o;try{var a=this.readFromStorage();a.push(n),o=this.saveToStorage(a),o&&this.memQueue.push(n)}catch{this.reportError("Error enqueueing item",e),o=!1}r&&r(o)},this),d.bind(function(o){this.reportError("Error acquiring storage lock",o),r&&r(!1)},this),this.pid):(this.memQueue.push(n),r&&r(!0))},re.prototype.fillBatch=function(e){var t=this.memQueue.slice(0,e);if(this.usePersistence&&t.lengtho.flushAfter&&!n[o.id]&&(o.orphaned=!0,t.push(o),t.length>=e))break}}}return t};var fr=function(e,t){var r=[];return d.each(e,function(n){n.id&&!t[n.id]&&r.push(n)}),r};re.prototype.removeItemsByID=function(e,t){var r={};if(d.each(e,function(i){r[i]=!0}),this.memQueue=fr(this.memQueue,r),!this.usePersistence)t&&t(!0);else{var n=d.bind(function(){var i;try{var o=this.readFromStorage();if(o=fr(o,r),i=this.saveToStorage(o),i){o=this.readFromStorage();for(var a=0;a5&&(this.reportError("[dupe] item ID sent too many times, not sending",{item:u,batchSize:i.length,timesSent:this.itemIdsSentSuccessfully[h]}),m=!1):this.reportError("[dupe] found item with no ID",{item:u}),m&&a.push(f)}l[u.id]=f},this),a.length<1){this.resetFlush();return}this.requestInProgress=!0;var s=d.bind(function(u){this.requestInProgress=!1;try{var f=!1;if(e.unloading)this.queue.updatePayloads(l);else if(d.isObject(u)&&u.error==="timeout"&&new Date().getTime()-r>=t)this.reportError("Network timeout; retrying"),this.flush();else if(d.isObject(u)&&(u.httpStatusCode>=500||u.httpStatusCode===429||u.error==="timeout")){var m=this.flushInterval*2;u.retryAfter&&(m=parseInt(u.retryAfter,10)*1e3||m),m=Math.min(Kn,m),this.reportError("Error; retry in "+m+" ms"),this.scheduleFlush(m)}else if(d.isObject(u)&&u.httpStatusCode===413)if(i.length>1){var h=Math.max(1,Math.floor(n/2));this.batchSize=Math.min(this.batchSize,h,i.length-1),this.reportError("413 response; reducing batch size to "+this.batchSize),this.resetFlush()}else this.reportError("Single-event request too large; dropping",i),this.resetBatchSize(),f=!0;else f=!0;f&&(this.queue.removeItemsByID(d.map(i,function(g){return g.id}),d.bind(function(g){g?(this.consecutiveRemovalFailures=0,this.flushOnlyOnInterval&&!o?this.resetFlush():this.flush()):(this.reportError("Failed to remove items from queue"),++this.consecutiveRemovalFailures>5?(this.reportError("Too many queue failures; disabling batching system."),this.stopAllBatching()):this.resetFlush())},this)),d.each(i,d.bind(function(g){var p=g.id;p?(this.itemIdsSentSuccessfully[p]=this.itemIdsSentSuccessfully[p]||0,this.itemIdsSentSuccessfully[p]++,this.itemIdsSentSuccessfully[p]>5&&this.reportError("[dupe] item ID sent too many times",{item:g,batchSize:i.length,timesSent:this.itemIdsSentSuccessfully[p]})):this.reportError("[dupe] found item with no ID while removing",{item:g})},this)))}catch(g){this.reportError("Error handling API response",g),this.resetFlush()}},this),c={method:"POST",verbose:!0,ignore_json_errors:!0,timeout_ms:t};e.unloading&&(c.transport="sendBeacon"),Re.log("MIXPANEL REQUEST:",a),this.sendRequest(a,c,s)}catch(u){this.reportError("Error flushing request queue",u),this.resetFlush()}},Q.prototype.reportError=function(e,t){if(Re.error.apply(Re.error,arguments),this.errorReporter)try{t instanceof Error||(t=new Error(e)),this.errorReporter(e,t)}catch(r){Re.error(r)}};var Se=Je("recorder"),pr=P.CompressionStream,Yn={batch_size:1e3,batch_flush_interval_ms:10*1e3,batch_request_timeout_ms:90*1e3,batch_autostart:!0},Qn=new Set([Y.MouseMove,Y.MouseInteraction,Y.Scroll,Y.ViewportResize,Y.Input,Y.TouchMove,Y.MediaInteraction,Y.Drag,Y.Selection]);function Zn(e){return e.type===tr.IncrementalSnapshot&&Qn.has(e.data.source)}var X=function(e){this._mixpanel=e,this._stopRecording=null,this.recEvents=[],this.seqNo=0,this.replayId=null,this.replayStartTime=null,this.sendBatchId=null,this.idleTimeoutId=null,this.maxTimeoutId=null,this.recordMaxMs=$e,this._initBatcher()};X.prototype._initBatcher=function(){this.batcher=new Q("__mprec",{libConfig:Yn,sendRequestFunc:d.bind(this.flushEventsWithOptOut,this),errorReporter:d.bind(this.reportError,this),flushOnlyOnInterval:!0,usePersistence:!1})},X.prototype.get_config=function(e){return this._mixpanel.get_config(e)},X.prototype.startRecording=function(e){if(this._stopRecording!==null){Se.log("Recording already in progress, skipping startRecording.");return}this.recordMaxMs=this.get_config("record_max_ms"),this.recordMaxMs>$e&&(this.recordMaxMs=$e,Se.critical("record_max_ms cannot be greater than "+$e+"ms. Capping value.")),this.recEvents=[],this.seqNo=0,this.replayStartTime=null,this.replayId=d.UUID(),e?this.batcher.stop():this.batcher.start();var t=d.bind(function(){clearTimeout(this.idleTimeoutId),this.idleTimeoutId=setTimeout(d.bind(function(){Se.log("Idle timeout reached, restarting recording."),this.resetRecording()},this),this.get_config("record_idle_timeout_ms"))},this);this._stopRecording=Oe({emit:d.bind(function(r){this.batcher.enqueue(r),Zn(r)&&(this.batcher.stopped&&this.batcher.start(),t())},this),blockClass:this.get_config("record_block_class"),blockSelector:this.get_config("record_block_selector"),collectFonts:this.get_config("record_collect_fonts"),inlineImages:this.get_config("record_inline_images"),maskAllInputs:!0,maskTextClass:this.get_config("record_mask_text_class"),maskTextSelector:this.get_config("record_mask_text_selector")}),t(),this.maxTimeoutId=setTimeout(d.bind(this.resetRecording,this),this.recordMaxMs)},X.prototype.resetRecording=function(){this.stopRecording(),this.startRecording(!0)},X.prototype.stopRecording=function(){this._stopRecording!==null&&(this._stopRecording(),this._stopRecording=null),this.batcher.stopped?this.batcher.clear():(this.batcher.flush(),this.batcher.stop()),this.replayId=null,clearTimeout(this.idleTimeoutId),clearTimeout(this.maxTimeoutId)},X.prototype.flushEventsWithOptOut=function(e,t,r){this._flushEvents(e,t,r,d.bind(this._onOptOut,this))},X.prototype._onOptOut=function(e){e===0&&(this.recEvents=[],this.stopRecording())},X.prototype._sendRequest=function(e,t,r){var n=d.bind(function(i,o){i.status===200&&this.seqNo++,r({status:0,httpStatusCode:i.status,responseBody:o,retryAfter:i.headers.get("Retry-After")})},this);P.fetch(this.get_config("api_host")+"/"+this.get_config("api_routes").record+"?"+new URLSearchParams(e),{method:"POST",headers:{Authorization:"Basic "+btoa(this.get_config("token")+":"),"Content-Type":"application/octet-stream"},body:t}).then(function(i){i.json().then(function(o){n(i,o)}).catch(function(o){r({error:o})})}).catch(function(i){r({error:i})})},X.prototype._flushEvents=$n(function(e,t,r){const n=e.length;if(n>0){var i=e[0].timestamp;this.seqNo===0&&(this.replayStartTime=i);var o=e[n-1].timestamp-this.replayStartTime,a={distinct_id:String(this._mixpanel.get_distinct_id()),seq:this.seqNo,batch_start_time:i/1e3,replay_id:this.replayId,replay_length_ms:o,replay_start_time:this.replayStartTime/1e3},l=d.JSONEncode(e),s=this._mixpanel.get_property("$device_id");s&&(a.$device_id=s);var c=this._mixpanel.get_property("$user_id");if(c&&(a.$user_id=c),pr){var u=new Blob([l],{type:"application/json"}).stream(),f=u.pipeThrough(new pr("gzip"));new Response(f).blob().then(d.bind(function(m){a.format="gzip",this._sendRequest(a,m,r)},this))}else a.format="body",this._sendRequest(a,l,r)}}),X.prototype.reportError=function(e,t){Se.error.apply(Se.error,arguments);try{!t&&!(e instanceof Error)&&(e=new Error(e)),this.get_config("error_reporter")(e,t)}catch(r){Se.error(r)}},P.__mp_recorder=X})(); +`);var t="",r,n,i=0,o;for(r=n=0,i=e.length,o=0;o127&&a<2048?l=String.fromCharCode(a>>6|192,a&63|128):l=String.fromCharCode(a>>12|224,a>>6&63|128,a&63|128),l!==null&&(n>r&&(t+=e.substring(r,n)),t+=l,r=n=o+1)}return n>r&&(t+=e.substring(r,e.length)),t},d.UUID=function(){var e=function(){var n=1*new Date,i;if(F.performance&&F.performance.now)i=F.performance.now();else for(i=0;n==1*new Date;)i++;return n.toString(16)+Math.floor(i).toString(16)},t=function(){return Math.random().toString(16).replace(".","")},r=function(){var n=ae,i,o,a=[],l=0;function s(c,u){var h,m=0;for(h=0;h=4&&(l=s(l,a),a=[]);return a.length>0&&(l=s(l,a)),l.toString(16)};return function(){var n=(Ve.height*Ve.width).toString(16);return e()+"-"+t()+"-"+r()+"-"+n+"-"+e()}}();var ur=["ahrefsbot","ahrefssiteaudit","baiduspider","bingbot","bingpreview","chrome-lighthouse","facebookexternal","petalbot","pinterest","screaming frog","yahoo! slurp","yandexbot","adsbot-google","apis-google","duplexweb-google","feedfetcher-google","google favicon","google web preview","google-read-aloud","googlebot","googleweblight","mediapartners-google","storebot-google"];d.isBlockedUA=function(e){var t;for(e=e.toLowerCase(),t=0;t=0}function n(i){if(!q.getElementsByTagName)return[];var o=i.split(" "),a,l,s,c,u,h,m,f,g,p,y=[q];for(h=0;h-1){l=a.split("#"),s=l[0];var w=l[1],S=q.getElementById(w);if(!S||s&&S.nodeName.toLowerCase()!=s)return[];y=[S];continue}if(a.indexOf(".")>-1){l=a.split("."),s=l[0];var v=l[1];for(s||(s="*"),c=[],u=0,m=0;m-1};break;default:x=function(R){return R.getAttribute(M)}}for(y=[],p=0,m=0;m=3?t[2]:""},currentUrl:function(){return F.location.href},properties:function(e){return typeof e!="object"&&(e={}),d.extend(d.strip_empty_properties({$os:d.info.os(),$browser:d.info.browser(ae,xe.vendor,Ge),$referrer:q.referrer,$referring_domain:d.info.referringDomain(q.referrer),$device:d.info.device(ae)}),{$current_url:d.info.currentUrl(),$browser_version:d.info.browserVersion(ae,xe.vendor,Ge),$screen_height:Ve.height,$screen_width:Ve.width,mp_lib:"web",$lib_version:nr.LIB_VERSION,$insert_id:pt(),time:d.timestamp()/1e3},d.strip_empty_properties(e))},people_properties:function(){return d.extend(d.strip_empty_properties({$os:d.info.os(),$browser:d.info.browser(ae,xe.vendor,Ge)}),{$browser_version:d.info.browserVersion(ae,xe.vendor,Ge)})},mpPageViewProperties:function(){return d.strip_empty_properties({current_page_title:q.title,current_domain:F.location.hostname,current_url_path:F.location.pathname,current_url_protocol:F.location.protocol,current_url_search:F.location.search})}};var pt=function(e){var t=Math.random().toString(36).substring(2,10)+Math.random().toString(36).substring(2,10);return e?t.substring(0,e):t},Un=/[a-z0-9][a-z0-9-]*\.[a-z]+$/i,zn=/[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i,cr=function(e){var t=zn,r=e.split("."),n=r[r.length-1];(n.length>4||n==="com"||n==="org")&&(t=Un);var i=e.match(t);return i?i[0]:""},Hn=function(){var e=F.navigator.onLine;return d.isUndefined(e)||e},Ke=null,Ye=null;typeof JSON<"u"&&(Ke=JSON.stringify,Ye=JSON.parse),Ke=Ke||d.JSONEncode,Ye=Ye||d.JSONDecode,d.toArray=d.toArray,d.isObject=d.isObject,d.JSONEncode=d.JSONEncode,d.JSONDecode=d.JSONDecode,d.isBlockedUA=d.isBlockedUA,d.isEmptyObject=d.isEmptyObject,d.info=d.info,d.info.device=d.info.device,d.info.browser=d.info.browser,d.info.browserVersion=d.info.browserVersion,d.info.properties=d.info.properties;var $n="__mp_opt_in_out_";function qn(e,t){if(Xn(t))return J.warn('This browser has "Do Not Track" enabled. This will prevent the Mixpanel SDK from sending any data. To ignore the "Do Not Track" browser setting, initialize the Mixpanel instance with the config "ignore_dnt: true"'),!0;var r=Jn(e,t)==="0";return r&&J.warn("You are opted out of Mixpanel tracking. This will prevent the Mixpanel SDK from sending any data."),r}function jn(e){return Kn(e,function(t){return this.get_config(t)})}function Gn(e){return e=e||{},e.persistenceType==="localStorage"?d.localStorage:d.cookie}function Vn(e,t){return t=t||{},(t.persistencePrefix||$n)+e}function Jn(e,t){return Gn(t).get(Vn(e,t))}function Xn(e){if(e&&e.ignoreDnt)return!1;var t=e&&e.window||F,r=t.navigator||{},n=!1;return d.each([r.doNotTrack,r.msDoNotTrack,t.doNotTrack],function(i){d.includes([!0,1,"1","yes"],i)&&(n=!0)}),n}function Kn(e,t){return function(){var r=!1;try{var n=t.call(this,"token"),i=t.call(this,"ignore_dnt"),o=t.call(this,"opt_out_tracking_persistence_type"),a=t.call(this,"opt_out_tracking_cookie_prefix"),l=t.call(this,"window");n&&(r=qn(n,{ignoreDnt:i,persistenceType:o,persistencePrefix:a,window:l}))}catch(c){J.error("Unexpected error when checking tracking opt-out status: "+c)}if(!r)return e.apply(this,arguments);var s=arguments[arguments.length-1];typeof s=="function"&&s(0)}}var Yn=Je("lock"),dr=function(e,t){t=t||{},this.storageKey=e,this.storage=t.storage||window.localStorage,this.pollIntervalMS=t.pollIntervalMS||100,this.timeoutMS=t.timeoutMS||2e3};dr.prototype.withLock=function(e,t,r){!r&&typeof t!="function"&&(r=t,t=null);var n=r||new Date().getTime()+"|"+Math.random(),i=new Date().getTime(),o=this.storageKey,a=this.pollIntervalMS,l=this.timeoutMS,s=this.storage,c=o+":X",u=o+":Y",h=o+":Z",m=function(S){t&&t(S)},f=function(S){if(new Date().getTime()-i>l){Yn.error("Timeout waiting for mutex on "+o+"; clearing lock. ["+n+"]"),s.removeItem(h),s.removeItem(u),y();return}setTimeout(function(){try{S()}catch(v){m(v)}},a*(Math.random()+.1))},g=function(S,v){S()?v():f(function(){g(S,v)})},p=function(){var S=s.getItem(u);if(S&&S!==n)return!1;if(s.setItem(u,n),s.getItem(u)===n)return!0;if(!Xe(s,!0))throw new Error("localStorage support dropped while acquiring lock");return!1},y=function(){s.setItem(c,n),g(p,function(){if(s.getItem(c)===n){w();return}f(function(){if(s.getItem(u)!==n){y();return}g(function(){return!s.getItem(h)},w)})})},w=function(){s.setItem(h,"1");try{e()}finally{s.removeItem(h),s.getItem(u)===n&&s.removeItem(u),s.getItem(c)===n&&s.removeItem(c)}};try{if(Xe(s,!0))y();else throw new Error("localStorage support check failed")}catch(S){m(S)}};var fr=Je("batch"),re=function(e,t){t=t||{},this.storageKey=e,this.storage=t.storage||window.localStorage,this.reportError=t.errorReporter||d.bind(fr.error,fr),this.lock=new dr(e,{storage:this.storage}),this.usePersistence=t.usePersistence,this.pid=t.pid||null,this.memQueue=[]};re.prototype.enqueue=function(e,t,r){var n={id:pt(),flushAfter:new Date().getTime()+t*2,payload:e};this.usePersistence?this.lock.withLock(d.bind(function(){var o;try{var a=this.readFromStorage();a.push(n),o=this.saveToStorage(a),o&&this.memQueue.push(n)}catch{this.reportError("Error enqueueing item",e),o=!1}r&&r(o)},this),d.bind(function(o){this.reportError("Error acquiring storage lock",o),r&&r(!1)},this),this.pid):(this.memQueue.push(n),r&&r(!0))},re.prototype.fillBatch=function(e){var t=this.memQueue.slice(0,e);if(this.usePersistence&&t.lengtho.flushAfter&&!n[o.id]&&(o.orphaned=!0,t.push(o),t.length>=e))break}}}return t};var hr=function(e,t){var r=[];return d.each(e,function(n){n.id&&!t[n.id]&&r.push(n)}),r};re.prototype.removeItemsByID=function(e,t){var r={};if(d.each(e,function(i){r[i]=!0}),this.memQueue=hr(this.memQueue,r),!this.usePersistence)t&&t(!0);else{var n=d.bind(function(){var i;try{var o=this.readFromStorage();if(o=hr(o,r),i=this.saveToStorage(o),i){o=this.readFromStorage();for(var a=0;a5&&(this.reportError("[dupe] item ID sent too many times, not sending",{item:u,batchSize:i.length,timesSent:this.itemIdsSentSuccessfully[f]}),m=!1):this.reportError("[dupe] found item with no ID",{item:u}),m&&a.push(h)}l[u.id]=h},this),a.length<1){this.resetFlush();return}this.requestInProgress=!0;var s=d.bind(function(u){this.requestInProgress=!1;try{var h=!1;if(e.unloading)this.queue.updatePayloads(l);else if(d.isObject(u)&&u.error==="timeout"&&new Date().getTime()-r>=t)this.reportError("Network timeout; retrying"),this.flush();else if(d.isObject(u)&&(u.httpStatusCode>=500||u.httpStatusCode===429||u.httpStatusCode<=0&&!Hn()||u.error==="timeout")){var m=this.flushInterval*2;u.retryAfter&&(m=parseInt(u.retryAfter,10)*1e3||m),m=Math.min(Qn,m),this.reportError("Error; retry in "+m+" ms"),this.scheduleFlush(m)}else if(d.isObject(u)&&u.httpStatusCode===413)if(i.length>1){var f=Math.max(1,Math.floor(n/2));this.batchSize=Math.min(this.batchSize,f,i.length-1),this.reportError("413 response; reducing batch size to "+this.batchSize),this.resetFlush()}else this.reportError("Single-event request too large; dropping",i),this.resetBatchSize(),h=!0;else h=!0;h&&(this.queue.removeItemsByID(d.map(i,function(g){return g.id}),d.bind(function(g){g?(this.consecutiveRemovalFailures=0,this.flushOnlyOnInterval&&!o?this.resetFlush():this.flush()):(this.reportError("Failed to remove items from queue"),++this.consecutiveRemovalFailures>5?(this.reportError("Too many queue failures; disabling batching system."),this.stopAllBatching()):this.resetFlush())},this)),d.each(i,d.bind(function(g){var p=g.id;p?(this.itemIdsSentSuccessfully[p]=this.itemIdsSentSuccessfully[p]||0,this.itemIdsSentSuccessfully[p]++,this.itemIdsSentSuccessfully[p]>5&&this.reportError("[dupe] item ID sent too many times",{item:g,batchSize:i.length,timesSent:this.itemIdsSentSuccessfully[p]})):this.reportError("[dupe] found item with no ID while removing",{item:g})},this)))}catch(g){this.reportError("Error handling API response",g),this.resetFlush()}},this),c={method:"POST",verbose:!0,ignore_json_errors:!0,timeout_ms:t};e.unloading&&(c.transport="sendBeacon"),Re.log("MIXPANEL REQUEST:",a),this.sendRequest(a,c,s)}catch(u){this.reportError("Error flushing request queue",u),this.resetFlush()}},Q.prototype.reportError=function(e,t){if(Re.error.apply(Re.error,arguments),this.errorReporter)try{t instanceof Error||(t=new Error(e)),this.errorReporter(e,t)}catch(r){Re.error(r)}};var le=Je("recorder"),mr=F.CompressionStream,Zn={batch_size:1e3,batch_flush_interval_ms:10*1e3,batch_request_timeout_ms:90*1e3,batch_autostart:!0},ei=new Set([Y.MouseMove,Y.MouseInteraction,Y.Scroll,Y.ViewportResize,Y.Input,Y.TouchMove,Y.MediaInteraction,Y.Drag,Y.Selection]);function ti(e){return e.type===rr.IncrementalSnapshot&&ei.has(e.data.source)}var X=function(e){this._mixpanel=e,this._stopRecording=null,this.recEvents=[],this.seqNo=0,this.replayId=null,this.replayStartTime=null,this.sendBatchId=null,this.idleTimeoutId=null,this.maxTimeoutId=null,this.recordMaxMs=$e,this.recordMinMs=0,this._initBatcher()};X.prototype._initBatcher=function(){this.batcher=new Q("__mprec",{libConfig:Zn,sendRequestFunc:d.bind(this.flushEventsWithOptOut,this),errorReporter:d.bind(this.reportError,this),flushOnlyOnInterval:!0,usePersistence:!1})},X.prototype.get_config=function(e){return this._mixpanel.get_config(e)},X.prototype.startRecording=function(e){if(this._stopRecording!==null){le.log("Recording already in progress, skipping startRecording.");return}this.recordMaxMs=this.get_config("record_max_ms"),this.recordMaxMs>$e&&(this.recordMaxMs=$e,le.critical("record_max_ms cannot be greater than "+$e+"ms. Capping value.")),this.recordMinMs=this.get_config("record_min_ms"),this.recordMinMs>ut&&(this.recordMinMs=ut,le.critical("record_min_ms cannot be greater than "+ut+"ms. Capping value.")),this.recEvents=[],this.seqNo=0,this.replayStartTime=new Date().getTime(),this.replayId=d.UUID(),e||this.recordMinMs>0?this.batcher.stop():this.batcher.start();var t=d.bind(function(){clearTimeout(this.idleTimeoutId),this.idleTimeoutId=setTimeout(d.bind(function(){le.log("Idle timeout reached, restarting recording."),this.resetRecording()},this),this.get_config("record_idle_timeout_ms"))},this),r=this.get_config("record_block_selector");(r===""||r===null)&&(r=void 0),this._stopRecording=Oe({emit:d.bind(function(n){this.batcher.enqueue(n),ti(n)&&(this.batcher.stopped&&new Date().getTime()-this.replayStartTime>=this.recordMinMs&&this.batcher.start(),t())},this),blockClass:this.get_config("record_block_class"),blockSelector:r,collectFonts:this.get_config("record_collect_fonts"),inlineImages:this.get_config("record_inline_images"),maskAllInputs:!0,maskTextClass:this.get_config("record_mask_text_class"),maskTextSelector:this.get_config("record_mask_text_selector")}),t(),this.maxTimeoutId=setTimeout(d.bind(this.resetRecording,this),this.recordMaxMs)},X.prototype.resetRecording=function(){this.stopRecording(),this.startRecording(!0)},X.prototype.stopRecording=function(){this._stopRecording!==null&&(this._stopRecording(),this._stopRecording=null),this.batcher.stopped?this.batcher.clear():(this.batcher.flush(),this.batcher.stop()),this.replayId=null,clearTimeout(this.idleTimeoutId),clearTimeout(this.maxTimeoutId)},X.prototype.flushEventsWithOptOut=function(e,t,r){this._flushEvents(e,t,r,d.bind(this._onOptOut,this))},X.prototype._onOptOut=function(e){e===0&&(this.recEvents=[],this.stopRecording())},X.prototype._sendRequest=function(e,t,r,n){var i=d.bind(function(o,a){o.status===200&&this.replayId===e&&this.seqNo++,n({status:0,httpStatusCode:o.status,responseBody:a,retryAfter:o.headers.get("Retry-After")})},this);F.fetch(this.get_config("api_host")+"/"+this.get_config("api_routes").record+"?"+new URLSearchParams(t),{method:"POST",headers:{Authorization:"Basic "+btoa(this.get_config("token")+":"),"Content-Type":"application/octet-stream"},body:r}).then(function(o){o.json().then(function(a){i(o,a)}).catch(function(a){n({error:a})})}).catch(function(o){n({error:o,httpStatusCode:0})})},X.prototype._flushEvents=jn(function(e,t,r){const n=e.length;if(n>0){var i=this.replayId,o=e[0].timestamp;(this.seqNo===0||!this.replayStartTime)&&(this.seqNo!==0&&this.reportError("Replay start time not set but seqNo is not 0. Using current batch start time as a fallback."),this.replayStartTime=o);var a=e[n-1].timestamp-this.replayStartTime,l={distinct_id:String(this._mixpanel.get_distinct_id()),seq:this.seqNo,batch_start_time:o/1e3,replay_id:i,replay_length_ms:a,replay_start_time:this.replayStartTime/1e3},s=d.JSONEncode(e),c=this._mixpanel.get_property("$device_id");c&&(l.$device_id=c);var u=this._mixpanel.get_property("$user_id");if(u&&(l.$user_id=u),mr){var h=new Blob([s],{type:"application/json"}).stream(),m=h.pipeThrough(new mr("gzip"));new Response(m).blob().then(d.bind(function(f){l.format="gzip",this._sendRequest(i,l,f,r)},this))}else l.format="body",this._sendRequest(i,l,s,r)}}),X.prototype.reportError=function(e,t){le.error.apply(le.error,arguments);try{!t&&!(e instanceof Error)&&(e=new Error(e)),this.get_config("error_reporter")(e,t)}catch(r){le.error(r)}},F.__mp_recorder=X})(); diff --git a/dist/mixpanel-with-async-recorder.cjs.js b/dist/mixpanel-with-async-recorder.cjs.js index 18560421..3ceab20b 100644 --- a/dist/mixpanel-with-async-recorder.cjs.js +++ b/dist/mixpanel-with-async-recorder.cjs.js @@ -2,7 +2,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -14,7 +14,7 @@ if (typeof(window) === 'undefined') { hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -968,7 +968,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) { _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -1425,8 +1425,8 @@ _.dom_query = (function() { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -1708,6 +1708,15 @@ var extract_domain = function(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -2523,7 +2532,12 @@ RequestBatcher.prototype.flush = function(options) { this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -4247,6 +4261,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/dist/mixpanel.amd.js b/dist/mixpanel.amd.js index 4619c3ab..1af1ccdb 100644 --- a/dist/mixpanel.amd.js +++ b/dist/mixpanel.amd.js @@ -4509,7 +4509,7 @@ define((function () { 'use strict'; var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4521,7 +4521,7 @@ define((function () { 'use strict'; hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4535,6 +4535,8 @@ define((function () { 'use strict'; // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours + // Maximum allowed value for minimum session recording length + var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5475,7 +5477,7 @@ define((function () { 'use strict'; _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5932,8 +5934,8 @@ define((function () { 'use strict'; }; })(); - var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; - var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; + var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; + var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6215,6 +6217,15 @@ define((function () { 'use strict'; return matches ? matches[0] : ''; }; + /** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ + var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; + }; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7178,7 +7189,12 @@ define((function () { 'use strict'; this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7329,6 +7345,7 @@ define((function () { 'use strict'; this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7360,16 +7377,24 @@ define((function () { 'use strict'; logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7383,11 +7408,16 @@ define((function () { 'use strict'; }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7395,7 +7425,7 @@ define((function () { 'use strict'; } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7449,14 +7479,14 @@ define((function () { 'use strict'; } }; - MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { + MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7479,7 +7509,7 @@ define((function () { 'use strict'; callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7487,9 +7517,15 @@ define((function () { 'use strict'; const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7498,7 +7534,7 @@ define((function () { 'use strict'; 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7521,11 +7557,11 @@ define((function () { 'use strict'; .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -9013,6 +9049,7 @@ define((function () { 'use strict'; 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/dist/mixpanel.cjs.js b/dist/mixpanel.cjs.js index 1bfc0ca1..376a0bc7 100644 --- a/dist/mixpanel.cjs.js +++ b/dist/mixpanel.cjs.js @@ -4509,7 +4509,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => { var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4521,7 +4521,7 @@ if (typeof(window) === 'undefined') { hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4535,6 +4535,8 @@ if (typeof(window) === 'undefined') { // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours +// Maximum allowed value for minimum session recording length +var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5475,7 +5477,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) { _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5932,8 +5934,8 @@ _.dom_query = (function() { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6215,6 +6217,15 @@ var extract_domain = function(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7178,7 +7189,12 @@ RequestBatcher.prototype.flush = function(options) { this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7329,6 +7345,7 @@ var MixpanelRecorder = function(mixpanelInstance) { this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7360,16 +7377,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7383,11 +7408,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7395,7 +7425,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7449,14 +7479,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) { } }; -MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { +MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7479,7 +7509,7 @@ MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7487,9 +7517,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7498,7 +7534,7 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7521,11 +7557,11 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -9013,6 +9049,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/dist/mixpanel.globals.js b/dist/mixpanel.globals.js index 169818d4..6be0a895 100644 --- a/dist/mixpanel.globals.js +++ b/dist/mixpanel.globals.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -15,7 +15,7 @@ hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -969,7 +969,7 @@ _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -1426,8 +1426,8 @@ }; })(); - var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; - var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; + var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; + var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -1709,6 +1709,15 @@ return matches ? matches[0] : ''; }; + /** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ + var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; + }; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -2524,7 +2533,12 @@ this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -4248,6 +4262,7 @@ 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/dist/mixpanel.min.js b/dist/mixpanel.min.js index d49ab84e..9c5ad1ca 100644 --- a/dist/mixpanel.min.js +++ b/dist/mixpanel.min.js @@ -1,112 +1,113 @@ (function() { var l=void 0,m=!0,r=null,D=!1; -(function(){function Ba(){function a(){if(!a.Gc)la=a.Gc=m,ma=D,c.a(F,function(a){a.tc()})}function b(){try{v.documentElement.doScroll("left")}catch(d){setTimeout(b,1);return}a()}if(v.addEventListener)"complete"===v.readyState?a():v.addEventListener("DOMContentLoaded",a,D);else if(v.attachEvent){v.attachEvent("onreadystatechange",a);var d=D;try{d=o.frameElement===r}catch(f){}v.documentElement.doScroll&&d&&b()}c.Vb(o,"load",a,m)}function Ca(){x.init=function(a,b,d){if(d)return x[d]||(x[d]=F[d]=S(a, -b,d),x[d].la()),x[d];d=x;if(F.mixpanel)d=F.mixpanel;else if(a)d=S(a,b,"mixpanel"),d.la(),F.mixpanel=d;x=d;1===ca&&(o.mixpanel=x);Da()}}function Da(){c.a(F,function(a,b){"mixpanel"!==b&&(x[b]=a)});x._=c}function da(a){a=c.e(a)?a:c.g(a)?{}:{days:a};return c.extend({},Ea,a)}function S(a,b,d){var f,h="mixpanel"===d?x:x[d];if(h&&0===ca)f=h;else{if(h&&!c.isArray(h)){n.error("You have already initialized "+d);return}f=new e}f.lb={};f.Y(a,b,d);f.people=new j;f.people.Y(f);if(!f.c("skip_first_touch_marketing")){var a= -c.info.Z(r),g={},t=D;c.a(a,function(a,b){(g["initial_"+b]=a)&&(t=m)});t&&f.people.O(g)}J=J||f.c("debug");!c.g(h)&&c.isArray(h)&&(f.Aa.call(f.people,h.people),f.Aa(h));return f}function e(){}function P(){}function Fa(a){return a}function na(a){throw Error(a+" not available in this build.");}function q(a){this.props={};this.Dd=D;this.name=a.persistence_name?"mp_"+a.persistence_name:"mp_"+a.token+"_mixpanel";var b=a.persistence;if("cookie"!==b&&"localStorage"!==b)n.B("Unknown persistence type "+b+"; falling back to cookie"), -b=a.persistence="cookie";this.j="localStorage"===b&&c.localStorage.ta()?c.localStorage:c.cookie;this.load();this.nc(a);this.zd();this.save()}function j(){}function u(){}function C(a,b){this.K=b.K;this.ca=new G(a,{K:c.bind(this.h,this),j:b.j,z:b.z});this.C=b.C;this.bd=b.cd;this.ma=b.ma;this.md=b.nd;this.G=this.C.batch_size;this.qa=this.C.batch_flush_interval_ms;this.fa=!this.C.batch_autostart;this.Ja=0;this.I={};this.Db=b.Db||D}function oa(a,b){var d=[];c.a(a,function(a){var c=a.id;if(c in b){if(c= -b[c],c!==r)a.payload=c,d.push(a)}else d.push(a)});return d}function pa(a,b){var d=[];c.a(a,function(a){a.id&&!b[a.id]&&d.push(a)});return d}function G(a,b){b=b||{};this.P=a;this.j=b.j||window.localStorage;this.h=b.K||c.bind(qa.error,qa);this.Ya=new ra(a,{j:this.j});this.z=b.z;this.va=b.va||r;this.D=[]}function ra(a,b){b=b||{};this.P=a;this.j=b.j||window.localStorage;this.Tb=b.Tb||100;this.hc=b.hc||2E3}function T(){this.Qb="submit"}function M(){this.Qb="click"}function E(){}function sa(a){var b=Ga, -d=a.split("."),d=d[d.length-1];if(4a?"0"+a:a}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())};c.ga=function(a){var b= -{};c.a(a,function(a,f){c.Xa(a)&&0=i;)h()}function d(){var a,b,d="",c;if('"'===i)for(;h();){if('"'===i)return h(),d;if("\\"===i)if(h(),"u"===i){for(b=c=0;4>b;b+=1){a=parseInt(h(),16);if(!isFinite(a))break;c=16*c+a}d+=String.fromCharCode(c)}else if("string"===typeof k[i])d+=k[i];else break;else d+=i}g("Bad string")}function c(){var a;a="";"-"===i&&(a="-",h("-"));for(;"0"<=i&&"9">=i;)a+=i,h();if("."===i)for(a+=".";h()&&"0"<=i&&"9">=i;)a+=i;if("e"===i||"E"===i){a+=i;h();if("-"===i||"+"===i)a+=i,h();for(;"0"<=i&&"9">=i;)a+=i,h()}a= -+a;if(isFinite(a))return a;g("Bad number")}function h(a){a&&a!==i&&g("Expected '"+a+"' instead of '"+i+"'");i=p.charAt(e);e+=1;return i}function g(a){a=new SyntaxError(a);a.Cd=e;a.text=p;throw a;}var e,i,k={'"':'"',"\\":"\\","/":"/",b:"\u0008",f:"\u000c",n:"\n",r:"\r",t:"\t"},p,s;s=function(){b();switch(i){case "{":var e;a:{var t,k={};if("{"===i){h("{");b();if("}"===i){h("}");e=k;break a}for(;i;){t=d();b();h(":");Object.hasOwnProperty.call(k,t)&&g('Duplicate key "'+t+'"');k[t]=s();b();if("}"===i){h("}"); -e=k;break a}h(",");b()}}g("Bad object")}return e;case "[":a:{e=[];if("["===i){h("[");b();if("]"===i){h("]");t=e;break a}for(;i;){e.push(s());b();if("]"===i){h("]");t=e;break a}h(",");b()}}g("Bad array")}return t;case '"':return d();case "-":return c();default:return"0"<=i&&"9">=i?c():a()}};return function(a){p=a;e=0;i=" ";a=s();b();i&&g("Syntax error");return a}}();c.Bc=function(a){var b,d,f,h,g=0,e=0,i="",i=[];if(!a)return a;a=c.Ad(a);do b=a.charCodeAt(g++),d=a.charCodeAt(g++),f=a.charCodeAt(g++), -h=b<<16|d<<8|f,b=h>>18&63,d=h>>12&63,f=h>>6&63,h&=63,i[e++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h);while(ge?c++:i=127e?String.fromCharCode(e>>6|192,e&63|128):String.fromCharCode(e>>12|224,e>>6&63|128,e&63|128);i!==r&&(c>d&&(b+=a.substring(d,c)),b+=i,d=c=g+1)}c>d&&(b+=a.substring(d,a.length));return b};c.jb=function(){function a(){function a(b,c){var d,f=0;for(d=0;da?"0"+a:a}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+ +"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())};c.ga=function(a){var b={};c.a(a,function(a,f){c.Xa(a)&&0=i;)h()}function d(){var a,b,d="",c;if('"'===i)for(;h();){if('"'===i)return h(),d;if("\\"===i)if(h(),"u"===i){for(b=c=0;4>b;b+=1){a=parseInt(h(),16);if(!isFinite(a))break;c=16*c+a}d+=String.fromCharCode(c)}else if("string"===typeof k[i])d+=k[i];else break;else d+=i}g("Bad string")}function c(){var a;a="";"-"===i&&(a="-",h("-"));for(;"0"<=i&&"9">=i;)a+=i,h();if("."===i)for(a+= +".";h()&&"0"<=i&&"9">=i;)a+=i;if("e"===i||"E"===i){a+=i;h();if("-"===i||"+"===i)a+=i,h();for(;"0"<=i&&"9">=i;)a+=i,h()}a=+a;if(isFinite(a))return a;g("Bad number")}function h(a){a&&a!==i&&g("Expected '"+a+"' instead of '"+i+"'");i=p.charAt(e);e+=1;return i}function g(a){a=new SyntaxError(a);a.Cd=e;a.text=p;throw a;}var e,i,k={'"':'"',"\\":"\\","/":"/",b:"\u0008",f:"\u000c",n:"\n",r:"\r",t:"\t"},p,s;s=function(){b();switch(i){case "{":var e;a:{var t,k={};if("{"===i){h("{");b();if("}"===i){h("}");e= +k;break a}for(;i;){t=d();b();h(":");Object.hasOwnProperty.call(k,t)&&g('Duplicate key "'+t+'"');k[t]=s();b();if("}"===i){h("}");e=k;break a}h(",");b()}}g("Bad object")}return e;case "[":a:{e=[];if("["===i){h("[");b();if("]"===i){h("]");t=e;break a}for(;i;){e.push(s());b();if("]"===i){h("]");t=e;break a}h(",");b()}}g("Bad array")}return t;case '"':return d();case "-":return c();default:return"0"<=i&&"9">=i?c():a()}};return function(a){p=a;e=0;i=" ";a=s();b();i&&g("Syntax error");return a}}();c.Bc= +function(a){var b,d,f,h,g=0,e=0,i="",i=[];if(!a)return a;a=c.Ad(a);do b=a.charCodeAt(g++),d=a.charCodeAt(g++),f=a.charCodeAt(g++),h=b<<16|d<<8|f,b=h>>18&63,d=h>>12&63,f=h>>6&63,h&=63,i[e++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h); +while(ge?c++:i=127e?String.fromCharCode(e>>6|192,e&63|128):String.fromCharCode(e>>12|224,e>>6&63|128,e&63|128);i!==r&&(c>d&&(b+=a.substring(d,c)),b+=i,d=c=g+1)}c>d&&(b+=a.substring(d,a.length));return b};c.jb=function(){function a(){function a(b, +c){var d,f=0;for(d=0;dB?(Ra.error("Timeout waiting for mutex on "+s+"; clearing lock. ["+k+"]"),j.removeItem(n),j.removeItem(q),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},w*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=r);var k=c|| -(new Date).getTime()+"|"+Math.random(),p=(new Date).getTime(),s=this.P,w=this.Tb,B=this.hc,j=this.j,o=s+":X",q=s+":Y",n=s+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(v){b&&b(v)}};var qa=ga("batch");G.prototype.Na=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.z?this.Ya.ib(c.bind(function(){var b;try{var c=this.ea();c.push(f);(b=this.ab(c))&&this.D.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock", -a);d&&d(D)},this),this.va):(this.D.push(f),d&&d(m))};G.prototype.Hc=function(a){var b=this.D.slice(0,a);if(this.z&&b.lengthg.flushAfter&&!f[g.id]&&(g.Uc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Wc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.D=pa(this.D,d);if(this.z){var f=c.bind(function(){var b;try{var c=this.ea(),c=pa(c,d);if(b=this.ab(c))for(var c= -this.ea(),f=0;ft.length)this.N();else{this.Xb=m;var k=c.bind(function(k){this.Xb=D;try{var t=D;if(a.lc)this.ca.yd(i);else if(c.e(k)&&"timeout"===k.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(k)&&(500<=k.Sa||429===k.Sa||"timeout"===k.error)){var j=2*this.qa;k.Zb&&(j=1E3*parseInt(k.Zb,10)||j);j=Math.min(6E5,j);this.h("Error; retry in "+j+" ms"); -this.$b(j)}else if(c.e(k)&&413===k.Sa)if(1B?(Sa.error("Timeout waiting for mutex on "+s+"; clearing lock. ["+k+"]"),j.removeItem(o),j.removeItem(q),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},w*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=r);var k=c|| +(new Date).getTime()+"|"+Math.random(),p=(new Date).getTime(),s=this.P,w=this.Tb,B=this.hc,j=this.j,n=s+":X",q=s+":Y",o=s+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(v){b&&b(v)}};var qa=ga("batch");G.prototype.Oa=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.z?this.Ya.ib(c.bind(function(){var b;try{var c=this.ea();c.push(f);(b=this.ab(c))&&this.D.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock", +a);d&&d(D)},this),this.wa):(this.D.push(f),d&&d(m))};G.prototype.Hc=function(a){var b=this.D.slice(0,a);if(this.z&&b.lengthg.flushAfter&&!f[g.id]&&(g.Uc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Wc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.D=pa(this.D,d);if(this.z){var f=c.bind(function(){var b;try{var c=this.ea(),c=pa(c,d);if(b=this.ab(c))for(var c= +this.ea(),f=0;ft.length)this.N();else{this.Xb=m;var k=c.bind(function(k){this.Xb=D;try{var t=D;if(a.lc)this.ca.yd(i);else if(c.g(k)&&"timeout"===k.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.g(k)&&(500<=k.sa||429===k.sa||0>=k.sa&&!Ga()||"timeout"===k.error)){var j=2*this.qa;k.Zb&&(j=1E3*parseInt(k.Zb,10)||j);j=Math.min(6E5,j);this.h("Error; retry in "+ +j+" ms");this.$b(j)}else if(c.g(k)&&413===k.sa)if(1=n.timeout?"timeout":"Bad HTTP status: "+n.status+" "+n.statusText,p.l(a),f&&(k?f({status:0,Sa:n.status,error:a,Zb:(n.responseHeaders|| -{})["Retry-After"]}):f(0))};n.send(j)}catch(y){p.l(y),e=D}else j=v.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,u=v.getElementsByTagName("script")[0],u.parentNode.insertBefore(j,u);return e};e.prototype.Aa=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a,function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this): -c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.sb=function(){return!!this.u.L};e.prototype.Eb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.kb=this.kb||{L:{type:"events",H:"/"+b.track,da:a+"_ev"},$a:{type:"people",H:"/"+b.engage,da:a+"_pp"},Ra:{type:"groups",H:"/"+b.groups,da:a+"_gr"}}};e.prototype.Nc=function(){if(!this.sb()){var a=c.bind(function(a){return new C(a.da, -{C:this.config,K:this.c("error_reporter"),cd:c.bind(function(b,c,e){this.k(this.c("api_host")+a.H,this.mb(b),c,this.ob(e,b))},this),ma:c.bind(function(b){return this.qb("before_send_"+a.type,b)},this),nd:c.bind(this.cb,this),z:m})},this),b=this.Eb();this.u={L:a(b.L),$a:a(b.$a),Ra:a(b.Ra)}}this.c("batch_autostart")&&this.bb()};e.prototype.bb=function(){this.rc=m;if(this.sb())this.U=m,c.a(this.u,function(a){a.start()})};e.prototype.cb=function(){this.U=D;c.a(this.u,function(a){a.stop();a.clear()})}; -e.prototype.push=function(a){this.Aa([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.V.Ec=m:this.xa=this.xa.concat(a)};e.prototype.mb=function(a){a=c.ia(a);"base64"===this.c("api_payload_format")&&(a=c.Bc(a));return{data:a}};e.prototype.Fa=function(a,b){var d=c.truncate(a.data,255),e=a.H,h=a.Ha,g=a.ld,j=a.dd||{},b=b||P,i=m,k=c.bind(function(){j.fc||(d=this.qb("before_send_"+a.type,d));return d?(n.log("MIXPANEL REQUEST:"),n.log(d),this.k(e,this.mb(d),j,this.ob(b,d))):r},this);this.U&& -!g?h.Na(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=K(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=r);var d=d||{},h=d.transport;if(h)d.gb=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.g(a))this.l("No event name provided to mixpanel.track");else if(this.nb(a))e(0);else{b=c.extend({},b);b.token=this.c("token");var g=this.persistence.Xc(a);c.g(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3)));this.rb();g=this.c("track_marketing")?c.info.Rc(): -{};b=c.extend({},c.info.ba({mp_loader:this.c("mp_loader")}),g,this.persistence.ba(),this.R,this.Fb(),b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Fa({type:"events",data:{event:a,properties:b},H:this.c("api_host")+"/"+this.c("api_routes").track,Ha:this.u.L,ld:h,dd:d},e)}});e.prototype.jd=K(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.yc= +record_block_selector:"img, video",record_collect_fonts:D,record_idle_timeout_ms:18E5,record_inline_images:D,record_mask_text_class:/^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$/,record_mask_text_selector:"*",record_max_ms:864E5,record_min_ms:0,record_sessions_percent:0,recorder_src:"https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js"},la=D;e.prototype.Va=function(a,b,d){if(c.e(d))this.l("You must name your new library: init(token, config, name)");else if("mixpanel"===d)this.l("You must initialize the main mixpanel object right after you include the Mixpanel js snippet"); +else return a=S(a,b,d),x[d]=a,a.la(),a};e.prototype.Y=function(a,b,d){b=b||{};this.__loaded=m;this.config={};var f={};"api_payload_format"in b||(b.api_host||Aa.api_host).match(/\.mixpanel\.com/)&&(f.api_payload_format="json");this.cc(c.extend({},Aa,f,b,{name:d,token:a,callback_fn:("mixpanel"===d?d:"mixpanel."+d)+"._jsc"}));this._jsc=P;this.za=[];this.Aa=[];this.ya=[];this.V={disable_all_events:D,identify_called:D};this.u={};if(this.U=this.c("batch_requests"))if(!c.localStorage.ua(m)||!O)this.U=D, +o.log("Turning off Mixpanel request-queueing; needs XHR and localStorage support"),c.a(this.Eb(),function(a){o.log("Clearing batch queue "+a.da);c.localStorage.remove(a.da)});else if(this.Nc(),ba&&n.addEventListener){var e=c.bind(function(){this.u.L.fa||this.u.L.flush({lc:m})},this);n.addEventListener("pagehide",function(a){a.persisted&&e()});n.addEventListener("visibilitychange",function(){"hidden"===v.visibilityState&&e()})}this.persistence=this.cookie=new q(this.config);this.R={};this.wc();a=c.jb(); +this.M()||this.w({distinct_id:"$device:"+a,$device_id:a},"");(a=this.c("track_pageview"))&&this.xc(a);0=o.timeout?"timeout":"Bad HTTP status: "+o.status+" "+o.statusText,p.l(a),f&&(k?f({status:0,sa:o.status,error:a,Zb:(o.responseHeaders|| +{})["Retry-After"]}):f(0))};o.send(j)}catch(y){p.l(y),e=D}else j=v.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,u=v.getElementsByTagName("script")[0],u.parentNode.insertBefore(j,u);return e};e.prototype.Ba=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a,function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this): +c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.sb=function(){return!!this.u.L};e.prototype.Eb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.kb=this.kb||{L:{type:"events",H:"/"+b.track,da:a+"_ev"},$a:{type:"people",H:"/"+b.engage,da:a+"_pp"},Sa:{type:"groups",H:"/"+b.groups,da:a+"_gr"}}};e.prototype.Nc=function(){if(!this.sb()){var a=c.bind(function(a){return new C(a.da, +{C:this.config,K:this.c("error_reporter"),cd:c.bind(function(b,c,e){this.k(this.c("api_host")+a.H,this.mb(b),c,this.ob(e,b))},this),ma:c.bind(function(b){return this.qb("before_send_"+a.type,b)},this),nd:c.bind(this.cb,this),z:m})},this),b=this.Eb();this.u={L:a(b.L),$a:a(b.$a),Sa:a(b.Sa)}}this.c("batch_autostart")&&this.bb()};e.prototype.bb=function(){this.rc=m;if(this.sb())this.U=m,c.a(this.u,function(a){a.start()})};e.prototype.cb=function(){this.U=D;c.a(this.u,function(a){a.stop();a.clear()})}; +e.prototype.push=function(a){this.Ba([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.V.Ec=m:this.ya=this.ya.concat(a)};e.prototype.mb=function(a){a=c.ia(a);"base64"===this.c("api_payload_format")&&(a=c.Bc(a));return{data:a}};e.prototype.Ga=function(a,b){var d=c.truncate(a.data,255),e=a.H,h=a.Ia,g=a.ld,j=a.dd||{},b=b||P,i=m,k=c.bind(function(){j.fc||(d=this.qb("before_send_"+a.type,d));return d?(o.log("MIXPANEL REQUEST:"),o.log(d),this.k(e,this.mb(d),j,this.ob(b,d))):r},this);this.U&& +!g?h.Oa(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=K(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=r);var d=d||{},h=d.transport;if(h)d.gb=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.e(a))this.l("No event name provided to mixpanel.track");else if(this.nb(a))e(0);else{b=c.extend({},b);b.token=this.c("token");var g=this.persistence.Xc(a);c.e(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3)));this.rb();g=this.c("track_marketing")?c.info.Rc(): +{};b=c.extend({},c.info.ba({mp_loader:this.c("mp_loader")}),g,this.persistence.ba(),this.R,this.Fb(),b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Ga({type:"events",data:{event:a,properties:b},H:this.c("api_host")+"/"+this.c("api_routes").track,Ia:this.u.L,ld:h,dd:d},e)}});e.prototype.jd=K(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.yc= K(function(a,b,c){var e=this.s(a),h={};e===l?(h[a]=[b],this.m(h)):-1===e.indexOf(b)&&(e.push(b),h[a]=e,this.m(h));return this.people.ha(a,b,c)});e.prototype.Yc=K(function(a,b,c){var e=this.s(a);if(e!==l){var h=e.indexOf(b);-1(x.__SV||0)?n.B("Version mismatch; please ensure you're using the latest version of the Mixpanel code snippet."):(c.a(x._i,function(a){a&&c.isArray(a)&&(F[a[a.length-1]]=S.apply(this,a))}),Ca(),x.init(),c.a(F,function(a){a.la()}),Ba())})(function(a,b){var c=document.createElement("script");c.type="text/javascript";c.async=m;c.onload=b;c.src=a;document.head.appendChild(c)})})(); +q.prototype.get_cross_subdomain=q.prototype.Jc;q.prototype.clear=q.prototype.clear;var F={};(function(a){na=a;ca=1;x=n.mixpanel;c.e(x)?o.B('"mixpanel" object not initialized. Ensure you are using the latest version of the Mixpanel JS Library along with the snippet we provide.'):x.__loaded||x.config&&x.persistence?o.B("The Mixpanel library has already been downloaded at least once. Ensure that the Mixpanel code snippet only appears once on the page (and is not double-loaded by a tag manager) in order to avoid errors."): +1.1>(x.__SV||0)?o.B("Version mismatch; please ensure you're using the latest version of the Mixpanel code snippet."):(c.a(x._i,function(a){a&&c.isArray(a)&&(F[a[a.length-1]]=S.apply(this,a))}),Ca(),x.init(),c.a(F,function(a){a.la()}),Ba())})(function(a,b){var c=document.createElement("script");c.type="text/javascript";c.async=m;c.onload=b;c.src=a;document.head.appendChild(c)})})(); })(); diff --git a/dist/mixpanel.module.js b/dist/mixpanel.module.js index 7826bcdb..256533d9 100644 --- a/dist/mixpanel.module.js +++ b/dist/mixpanel.module.js @@ -4507,7 +4507,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => { var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4519,7 +4519,7 @@ if (typeof(window) === 'undefined') { hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4533,6 +4533,8 @@ if (typeof(window) === 'undefined') { // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours +// Maximum allowed value for minimum session recording length +var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5473,7 +5475,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) { _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5930,8 +5932,8 @@ _.dom_query = (function() { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6213,6 +6215,15 @@ var extract_domain = function(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7176,7 +7187,12 @@ RequestBatcher.prototype.flush = function(options) { this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7327,6 +7343,7 @@ var MixpanelRecorder = function(mixpanelInstance) { this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7358,16 +7375,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7381,11 +7406,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7393,7 +7423,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7447,14 +7477,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) { } }; -MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { +MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7477,7 +7507,7 @@ MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7485,9 +7515,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7496,7 +7532,7 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7519,11 +7555,11 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -9011,6 +9047,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/dist/mixpanel.umd.js b/dist/mixpanel.umd.js index de10f216..370bd479 100644 --- a/dist/mixpanel.umd.js +++ b/dist/mixpanel.umd.js @@ -4513,7 +4513,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4525,7 +4525,7 @@ hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4539,6 +4539,8 @@ // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours + // Maximum allowed value for minimum session recording length + var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5479,7 +5481,7 @@ _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5936,8 +5938,8 @@ }; })(); - var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; - var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; + var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; + var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6219,6 +6221,15 @@ return matches ? matches[0] : ''; }; + /** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ + var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; + }; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7182,7 +7193,12 @@ this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7333,6 +7349,7 @@ this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7364,16 +7381,24 @@ logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7387,11 +7412,16 @@ }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7399,7 +7429,7 @@ } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7453,14 +7483,14 @@ } }; - MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { + MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7483,7 +7513,7 @@ callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7491,9 +7521,15 @@ const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7502,7 +7538,7 @@ 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7525,11 +7561,11 @@ .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -9017,6 +9053,7 @@ 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/examples/commonjs-browserify/bundle.js b/examples/commonjs-browserify/bundle.js index 1ded6a34..01a47fbe 100644 --- a/examples/commonjs-browserify/bundle.js +++ b/examples/commonjs-browserify/bundle.js @@ -4510,7 +4510,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => { var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4522,7 +4522,7 @@ if (typeof(window) === 'undefined') { hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4536,6 +4536,8 @@ if (typeof(window) === 'undefined') { // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours +// Maximum allowed value for minimum session recording length +var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5476,7 +5478,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) { _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5933,8 +5935,8 @@ _.dom_query = (function() { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6216,6 +6218,15 @@ var extract_domain = function(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7179,7 +7190,12 @@ RequestBatcher.prototype.flush = function(options) { this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7330,6 +7346,7 @@ var MixpanelRecorder = function(mixpanelInstance) { this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7361,16 +7378,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7384,11 +7409,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7396,7 +7426,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7450,14 +7480,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) { } }; -MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { +MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7480,7 +7510,7 @@ MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7488,9 +7518,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7499,7 +7535,7 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7522,11 +7558,11 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -9014,6 +9050,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/examples/es2015-babelify/bundle.js b/examples/es2015-babelify/bundle.js index 49dc73bb..4341757d 100644 --- a/examples/es2015-babelify/bundle.js +++ b/examples/es2015-babelify/bundle.js @@ -10982,7 +10982,7 @@ Object.defineProperty(exports, '__esModule', { }); var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; exports['default'] = Config; @@ -11682,6 +11682,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': _utils.MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; @@ -14943,6 +14944,7 @@ var MixpanelRecorder = function MixpanelRecorder(mixpanelInstance) { this.maxTimeoutId = null; this.recordMaxMs = _utils.MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -14973,16 +14975,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { logger.critical('record_max_ms cannot be greater than ' + _utils.MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > _utils.MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = _utils.MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + _utils.MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _utils._.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -14996,11 +15006,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = (0, _rrweb.record)({ 'emit': _utils._.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -15008,7 +15023,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -15062,14 +15077,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) { } }; -MixpanelRecorder.prototype._sendRequest = function (reqParams, reqBody, callback) { +MixpanelRecorder.prototype._sendRequest = function (currentReplayId, reqParams, reqBody, callback) { var onSuccess = _utils._.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -15092,7 +15107,7 @@ MixpanelRecorder.prototype._sendRequest = function (reqParams, reqBody, callback callback({ error: error }); }); })['catch'](function (error) { - callback({ error: error }); + callback({ error: error, httpStatusCode: 0 }); }); }; @@ -15100,9 +15115,15 @@ MixpanelRecorder.prototype._flushEvents = (0, _gdprUtils.addOptOutCheckMixpanelL var numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -15111,7 +15132,7 @@ MixpanelRecorder.prototype._flushEvents = (0, _gdprUtils.addOptOutCheckMixpanelL 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -15132,11 +15153,11 @@ MixpanelRecorder.prototype._flushEvents = (0, _gdprUtils.addOptOutCheckMixpanelL var gzipStream = jsonStream.pipeThrough(new CompressionStream('gzip')); new Response(gzipStream).blob().then(_utils._.bind(function (compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -15361,7 +15382,7 @@ RequestBatcher.prototype.flush = function (options) { } else if (_utils._.isObject(res) && res.error === 'timeout' && new Date().getTime() - startTime >= timeoutMS) { this.reportError('Network timeout; retrying'); this.flush(); - } else if (_utils._.isObject(res) && (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout')) { + } else if (_utils._.isObject(res) && (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.httpStatusCode <= 0 && !(0, _utils.isOnline)() || res.error === 'timeout')) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; if (res.retryAfter) { @@ -15968,7 +15989,7 @@ if (typeof window === 'undefined') { hostname: '' }; exports.window = win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -15982,6 +16003,8 @@ if (typeof window === 'undefined') { // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours +// Maximum allowed value for minimum session recording length +var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -16900,7 +16923,7 @@ _.HTTPBuildQuery = function (formdata, arg_separator) { _.getQueryParam = function (url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -17356,8 +17379,8 @@ _.dom_query = (function () { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform', 'utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function campaignParams(default_value) { @@ -17639,6 +17662,15 @@ var extract_domain = function extract_domain(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function isOnline() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { @@ -17661,19 +17693,21 @@ _['info']['browser'] = _.info.browser; _['info']['browserVersion'] = _.info.browserVersion; _['info']['properties'] = _.info.properties; -exports.MAX_RECORDING_MS = MAX_RECORDING_MS; exports._ = _; -exports.userAgent = userAgent; -exports.console = console; -exports.window = win; -exports.document = document; -exports.navigator = navigator; exports.cheap_guid = cheap_guid; exports.console_with_prefix = console_with_prefix; +exports.console = console; +exports.document = document; exports.extract_domain = extract_domain; -exports.localStorageSupported = localStorageSupported; -exports.JSONStringify = JSONStringify; exports.JSONParse = JSONParse; +exports.JSONStringify = JSONStringify; +exports.isOnline = isOnline; +exports.localStorageSupported = localStorageSupported; +exports.MAX_RECORDING_MS = MAX_RECORDING_MS; +exports.MAX_VALUE_FOR_MIN_RECORDING_MS = MAX_VALUE_FOR_MIN_RECORDING_MS; +exports.navigator = navigator; exports.slice = slice; +exports.userAgent = userAgent; +exports.window = win; },{"./config":5}]},{},[1]); diff --git a/examples/umd-webpack/bundle.js b/examples/umd-webpack/bundle.js index 97556c5f..1dfc0d97 100644 --- a/examples/umd-webpack/bundle.js +++ b/examples/umd-webpack/bundle.js @@ -4576,7 +4576,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; /* eslint camelcase: "off", eqeqeq: "off" */ @@ -4588,7 +4588,7 @@ hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -4602,6 +4602,8 @@ // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours + // Maximum allowed value for minimum session recording length + var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -5542,7 +5544,7 @@ _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -5999,8 +6001,8 @@ }; })(); - var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; - var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; + var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; + var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -6282,6 +6284,15 @@ return matches ? matches[0] : ''; }; + /** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ + var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; + }; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -7245,7 +7256,12 @@ this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; @@ -7396,6 +7412,7 @@ this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -7427,16 +7444,24 @@ logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -7450,11 +7475,16 @@ }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -7462,7 +7492,7 @@ } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -7516,14 +7546,14 @@ } }; - MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { + MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -7546,7 +7576,7 @@ callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -7554,9 +7584,15 @@ const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -7565,7 +7601,7 @@ 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -7588,11 +7624,11 @@ .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); @@ -9080,6 +9116,7 @@ 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/src/config.js b/src/config.js index 4d9887ad..a98d7980 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,6 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.55.0' + LIB_VERSION: '2.55.1' }; export default Config; diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index c3575933..7f6c3cbd 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -152,6 +152,7 @@ var DEFAULT_CONFIG = { 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'), 'record_mask_text_selector': '*', 'record_max_ms': MAX_RECORDING_MS, + 'record_min_ms': 0, 'record_sessions_percent': 0, 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js' }; diff --git a/src/recorder/index.js b/src/recorder/index.js index 21125054..4f2f9a92 100644 --- a/src/recorder/index.js +++ b/src/recorder/index.js @@ -1,7 +1,7 @@ import { record } from 'rrweb'; import { IncrementalSource, EventType } from '@rrweb/types'; -import { MAX_RECORDING_MS, console_with_prefix, _, window} from '../utils'; // eslint-disable-line camelcase +import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, _, window} from '../utils'; // eslint-disable-line camelcase import { addOptOutCheckMixpanelLib } from '../gdpr-utils'; import { RequestBatcher } from '../request-batcher'; @@ -47,6 +47,7 @@ var MixpanelRecorder = function(mixpanelInstance) { this.maxTimeoutId = null; this.recordMaxMs = MAX_RECORDING_MS; + this.recordMinMs = 0; this._initBatcher(); }; @@ -78,16 +79,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.'); } + this.recordMinMs = this.get_config('record_min_ms'); + if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) { + this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS; + logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.'); + } + this.recEvents = []; this.seqNo = 0; - this.replayStartTime = null; + this.replayStartTime = new Date().getTime(); this.replayId = _.UUID(); - if (shouldStopBatcher) { - // this is the case when we're starting recording after a reset + if (shouldStopBatcher || this.recordMinMs > 0) { + // the primary case for shouldStopBatcher is when we're starting recording after a reset // and don't want to send anything over the network until there's // actual user activity + // this also applies if the minimum recording length has not been hit yet + // so that we don't send data until we know the recording will be long enough this.batcher.stop(); } else { this.batcher.start(); @@ -101,11 +110,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { }, this), this.get_config('record_idle_timeout_ms')); }, this); + var blockSelector = this.get_config('record_block_selector'); + if (blockSelector === '' || blockSelector === null) { + blockSelector = undefined; + } + this._stopRecording = record({ 'emit': _.bind(function (ev) { this.batcher.enqueue(ev); if (isUserEvent(ev)) { - if (this.batcher.stopped) { + if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) { // start flushing again after user activity this.batcher.start(); } @@ -113,7 +127,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) { } }, this), 'blockClass': this.get_config('record_block_class'), - 'blockSelector': this.get_config('record_block_selector'), + 'blockSelector': blockSelector, 'collectFonts': this.get_config('record_collect_fonts'), 'inlineImages': this.get_config('record_inline_images'), 'maskAllInputs': true, @@ -167,14 +181,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) { } }; -MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) { +MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) { var onSuccess = _.bind(function (response, responseBody) { // Increment sequence counter only if the request was successful to guarantee ordering. // RequestBatcher will always flush the next batch after the previous one succeeds. - if (response.status === 200) { + // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay + if (response.status === 200 && this.replayId === currentReplayId) { this.seqNo++; } - callback({ status: 0, httpStatusCode: response.status, @@ -197,7 +211,7 @@ MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) callback({error: error}); }); }).catch(function (error) { - callback({error: error}); + callback({error: error, httpStatusCode: 0}); }); }; @@ -205,9 +219,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da const numEvents = data.length; if (numEvents > 0) { + var replayId = this.replayId; // each rrweb event has a timestamp - leverage those to get time properties var batchStartTime = data[0].timestamp; - if (this.seqNo === 0) { + if (this.seqNo === 0 || !this.replayStartTime) { + // extra safety net so that we don't send a null replay start time + if (this.seqNo !== 0) { + this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.'); + } + this.replayStartTime = batchStartTime; } var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime; @@ -216,7 +236,7 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da 'distinct_id': String(this._mixpanel.get_distinct_id()), 'seq': this.seqNo, 'batch_start_time': batchStartTime / 1000, - 'replay_id': this.replayId, + 'replay_id': replayId, 'replay_length_ms': replayLengthMs, 'replay_start_time': this.replayStartTime / 1000 }; @@ -239,11 +259,11 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da .blob() .then(_.bind(function(compressedBlob) { reqParams['format'] = 'gzip'; - this._sendRequest(reqParams, compressedBlob, callback); + this._sendRequest(replayId, reqParams, compressedBlob, callback); }, this)); } else { reqParams['format'] = 'body'; - this._sendRequest(reqParams, eventsJson, callback); + this._sendRequest(replayId, reqParams, eventsJson, callback); } } }); diff --git a/src/request-batcher.js b/src/request-batcher.js index afe4a6b7..40cd88fb 100644 --- a/src/request-batcher.js +++ b/src/request-batcher.js @@ -1,6 +1,6 @@ import Config from './config'; import { RequestQueue } from './request-queue'; -import { console_with_prefix, _ } from './utils'; // eslint-disable-line camelcase +import { console_with_prefix, isOnline, _ } from './utils'; // eslint-disable-line camelcase // maximum interval between request retries after exponential backoff var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes @@ -198,7 +198,12 @@ RequestBatcher.prototype.flush = function(options) { this.flush(); } else if ( _.isObject(res) && - (res.httpStatusCode >= 500 || res.httpStatusCode === 429 || res.error === 'timeout') + ( + res.httpStatusCode >= 500 + || res.httpStatusCode === 429 + || (res.httpStatusCode <= 0 && !isOnline()) + || res.error === 'timeout' + ) ) { // network or API error, or 429 Too Many Requests, retry var retryMS = this.flushInterval * 2; diff --git a/src/utils.js b/src/utils.js index af6a76db..2c7fe178 100644 --- a/src/utils.js +++ b/src/utils.js @@ -8,7 +8,7 @@ if (typeof(window) === 'undefined') { hostname: '' }; win = { - navigator: { userAgent: '' }, + navigator: { userAgent: '', onLine: true }, document: { location: loc, referrer: '' @@ -22,6 +22,8 @@ if (typeof(window) === 'undefined') { // Maximum allowed session recording length var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours +// Maximum allowed value for minimum session recording length +var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds /* * Saved references to long variable names, so that closure compiler can @@ -962,7 +964,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) { _.getQueryParam = function(url, param) { // Expects a raw URL - param = param.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]'); var regexS = '[\\?&]' + param + '=([^&#]*)', regex = new RegExp(regexS), results = regex.exec(url); @@ -1419,8 +1421,8 @@ _.dom_query = (function() { }; })(); -var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; -var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid']; +var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic']; +var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid']; _.info = { campaignParams: function(default_value) { @@ -1702,6 +1704,15 @@ var extract_domain = function(hostname) { return matches ? matches[0] : ''; }; +/** + * Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE) + * @returns {boolean} + */ +var isOnline = function() { + var onLine = win.navigator['onLine']; + return _.isUndefined(onLine) || onLine; +}; + var JSONStringify = null, JSONParse = null; if (typeof JSON !== 'undefined') { JSONStringify = JSON.stringify; @@ -1724,18 +1735,20 @@ _['info']['browserVersion'] = _.info.browserVersion; _['info']['properties'] = _.info.properties; export { - MAX_RECORDING_MS, _, - userAgent, - console, - win as window, - document, - navigator, cheap_guid, console_with_prefix, + console, + document, extract_domain, - localStorageSupported, - JSONStringify, JSONParse, - slice + JSONStringify, + isOnline, + localStorageSupported, + MAX_RECORDING_MS, + MAX_VALUE_FOR_MIN_RECORDING_MS, + navigator, + slice, + userAgent, + win as window }; diff --git a/tests/test.js b/tests/test.js index 195b76c4..57c74b22 100644 --- a/tests/test.js +++ b/tests/test.js @@ -3941,6 +3941,24 @@ this.clock.tick(10000); same(stored_requests.length, 2, "both events should still be in localStorage"); }); + + test('requests are not cleared from localStorage when offline', 3, function() { + var onlineStub = sinon.stub(window.navigator, 'onLine').value(false); + + mixpanel.batchtest.track('storagetest 1'); + mixpanel.batchtest.track('storagetest 2'); + var stored_requests = JSON.parse(localStorage.getItem(LOCALSTORAGE_EVENTS_KEY)); + same(stored_requests.length, 2, "both events should be in localStorage"); + + this.clock.tick(5000); + this.requests[0].respond(0, {}, ''); + + stored_requests = JSON.parse(localStorage.getItem(LOCALSTORAGE_EVENTS_KEY)); + same(stored_requests.length, 2, "both events should still be in localStorage"); + this.clock.tick(10000); + same(stored_requests.length, 2, "both events should still be in localStorage"); + onlineStub.restore(); + }); test('orphaned data in localStorage gets sent on init', 6, function() { clearLibInstance(mixpanel.batchtest); @@ -5243,7 +5261,7 @@ } } - function makeFakeFetchResponse(status, body, cb) { + function makeFakeFetchResponse(status, body) { body = body || {} var response = new Response({}, { status: status, @@ -5262,11 +5280,19 @@ ); } + function makeDelayedFetchResponse(status, body, delay) { + return new Promise(function(resolve) { + setTimeout(function() { + resolve(makeFakeFetchResponse(status, body)); + }, delay); + }); + } + module('recorder', { setup: function () { this.token = rand_name(); - - this.clock = sinon.useFakeTimers(); + this.startTime = 1723733423402; + this.clock = sinon.useFakeTimers(this.startTime); this.randomStub = sinon.stub(Math, 'random'); this.fetchStub = sinon.stub(window, 'fetch'); @@ -5543,7 +5569,6 @@ }, this)); }); }); - asyncTest('retries record request after a 500', 17, function () { this.randomStub.returns(0.02); this.initMixpanelRecorder({record_sessions_percent: 10}); @@ -5580,6 +5605,53 @@ }); }); + asyncTest('retries record requests when offline', 7, function () { + var onlineStub = sinon.stub(window.navigator, 'onLine').value(false); + // pretend we can't compress so we can compare the events in the fetch request + var compressionStreamStub = sinon.stub(window, 'CompressionStream').value(undefined); + + this.randomStub.returns(0.02); + this.initMixpanelRecorder({record_sessions_percent: 10}); + this.assertRecorderScript(true); + + this.responseBlobStub = sinon.stub(window.Response.prototype, 'blob'); + this.responseBlobStub.returns(fakePromiseWrap(new Blob())); + this.fetchStub.onCall(0) + .returns(new Promise(function (_resolve, reject) { + // simulate offline + reject(new TypeError('Failed to fetch')); + })) + .onCall(1) + .returns(makeFakeFetchResponse(200)) + + this.afterRecorderLoaded.call(this, function () { + simulateMouseClick(document.body); + this.clock.tick(10 * 1000) + same(this.fetchStub.getCalls().length, 1, 'one batch fetch request made every ten seconds'); + + var urlParams = validateAndGetUrlParams(this.fetchStub.getCall(0)); + same(urlParams.get("seq"), "0", "first sequence fails because we're offline"); + var fetchBody = this.fetchStub.getCall(0).args[1].body; + + this.clock.tick(20 * 1000); + + stop(); + untilDone(_.bind(function (done) { + var fetchCall1 = this.fetchStub.getCall(1); + if (fetchCall1) { + urlParams = validateAndGetUrlParams(fetchCall1); + same(urlParams.get("seq"), "0", "first sequence is retried with exponential backoff"); + same(fetchBody, fetchCall1.args[1].body, 'fetch body should be the same as the first request'); + } + onlineStub.restore(); + compressionStreamStub.restore(); + mixpanel.recordertest.stop_session_recording(); + + done(); + }, this)) + }); + }); + asyncTest('halves batch size and retries record request after a 413', 25, function () { this.randomStub.returns(0.02); this.initMixpanelRecorder({record_sessions_percent: 10}); @@ -5640,6 +5712,31 @@ }); }); + asyncTest('respects minimum session length setting', function () { + this.randomStub.returns(0.02); + this.initMixpanelRecorder({record_sessions_percent: 10, record_min_ms: 8000}); + this.assertRecorderScript(true) + + this.afterRecorderLoaded.call(this, function () { + simulateMouseClick(document.body); + this.clock.tick(5 * 1000); + + mixpanel.recordertest.stop_session_recording(); + + stop(); + untilDone(_.bind(function(done) { + same(this.fetchStub.getCalls().length, 0, 'does not flush events if session is too short'); + + simulateMouseClick(document.body); + this.clock.tick(20 * 1000); + realSetTimeout(_.bind(function() { + same(this.fetchStub.getCalls().length, 0, 'no fetch requests after recording is stopped'); + done(); + }, this), 2); + }, this)); + }); + }); + asyncTest('resets after idle timeout', 14, function () { this.randomStub.returns(0.02); this.initMixpanelRecorder({record_sessions_percent: 10}); @@ -5661,7 +5758,11 @@ same(urlParams.get('seq'), '0', 'sends first sequence'); var replayId1 = urlParams.get('replay_id'); - this.clock.tick(33 * 60 * 1000); + this.clock.tick(16 * 60 * 1000); + // simulate a mutation event to ensure we don't try sending it until there's a user event + document.body.appendChild(document.createElement('div')); + this.clock.tick(16 * 60 * 1000); + same(this.fetchStub.getCalls().length, 1, 'no new record requests after idle timeout'); simulateMouseClick(document.body); @@ -5675,6 +5776,64 @@ mixpanel.recordertest.stop_session_recording(); }); }); + + + asyncTest('handles race condition where the recording resets while a request is in flight', 14, function () { + this.randomStub.returns(0.02); + + this.initMixpanelRecorder({record_sessions_percent: 10}); + this.assertRecorderScript(true); + this.randomStub.restore(); // restore the random stub after script is loaded for batcher uuid dedupe + + this.responseBlobStub = sinon.stub(window.Response.prototype, 'blob'); + this.responseBlobStub.returns(fakePromiseWrap(new Blob())); + this.fetchStub.onFirstCall() + .returns(makeDelayedFetchResponse(200, {}, 5 * 1000)) + + this.fetchStub.callThrough(); + + this.afterRecorderLoaded.call(this, function () { + // current replay stops, a new one starts a bit after + mixpanel.recordertest.stop_session_recording(); + + same(this.fetchStub.getCalls().length, 1, 'flushed events after stopping recording'); + var urlParams = validateAndGetUrlParams(this.fetchStub.getCall(0)); + same(urlParams.get('seq'), '0', 'sends first sequence'); + + if (!IS_RECORDER_BUNDLED) { + same(urlParams.get('replay_start_time'), (this.startTime / 1000).toString(), 'sends the right start time'); + } else { + ok(true, 'cannot test replay_start_time when recorder is bundled, rrweb stores a reference to Date.now at the global level so stubs / fake timers will not work.'); + } + + var replayId1 = urlParams.get('replay_id'); + + // start recording again while the first replay's request is in flight + mixpanel.recordertest.start_session_recording(); + simulateMouseClick(document.body); + stop(); + + untilDone(_.bind(function (done) { + this.clock.tick(10 * 1000); + var fetchCall1 = this.fetchStub.getCall(1); + if (fetchCall1) { + urlParams = validateAndGetUrlParams(this.fetchStub.getCall(1)); + same(urlParams.get('seq'), '0', 'new replay uses the first sequence'); + + if (!IS_RECORDER_BUNDLED) { + same(urlParams.get('replay_start_time'), (this.startTime / 1000).toString(), 'sends the right start time'); + } else { + ok(true, 'cannot test replay_start_time when recorder is bundled, rrweb stores a reference to Date.now at the global level so stubs / fake timers will not work.'); + } + + var replayId2 = urlParams.get('replay_id'); + ok(replayId1 !== replayId2, 'replay id is different after reset'); + mixpanel.recordertest.stop_session_recording(); + done(); + } + }, this)); + }); + }); } }, 10); }; diff --git a/tests/unit/request-batcher.js b/tests/unit/request-batcher.js index 77e02e64..50c90456 100644 --- a/tests/unit/request-batcher.js +++ b/tests/unit/request-batcher.js @@ -3,6 +3,8 @@ import localStorage from 'localStorage'; import sinon from 'sinon'; import sinonChai from 'sinon-chai'; +import { window } from '../../src/utils'; + chai.use(sinonChai); import { RequestBatcher } from '../../src/request-batcher'; @@ -332,6 +334,34 @@ describe(`RequestBatcher`, function() { ]); }); + it(`retries ERR_INTERNET_DISCONNECTED and continues queueing`, function() { + var isOnlineStub = sinon.stub(window.navigator, `onLine`).value(false); + batcher.flush(); + batcher.enqueue({ev: `queued event 1`}); + batcher.enqueue({ev: `queued event 2`}); + + // fail a couple times + clock.tick(DEFAULT_FLUSH_INTERVAL); + expect(batcher.sendRequest).to.have.been.calledOnce; + sendResponse(0); + clock.tick(DEFAULT_FLUSH_INTERVAL * 2); + expect(batcher.sendRequest).to.have.been.calledTwice; + sendResponse(0); + + batcher.enqueue({ev: `queued event 3`}); + + clock.tick(DEFAULT_FLUSH_INTERVAL * 4); + expect(batcher.sendRequest).to.have.callCount(3); + + // should include all events in current retry + expect(batcher.sendRequest.args[2][0]).to.deep.equal([ + {ev: `queued event 1`}, + {ev: `queued event 2`}, + {ev: `queued event 3`}, + ]); + isOnlineStub.restore(); + }); + it(`does not retry 400s / successful API rejections`, function() { batcher.enqueue({ev: `queued event 1`}); batcher.enqueue({ev: `queued event 2`});