@sprig-technologies/sprig-browser 2.31.2 → 2.31.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core-DlBGQngD.js +12 -0
- package/dist/core-uZksLjLE.cjs +12 -0
- package/dist/core.cjs +1 -1
- package/dist/core.d.ts +13 -19
- package/dist/core.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +13 -19
- package/dist/index.js +1 -1
- package/dist/{metricsReporter-D-m62w_D.js → metricsReporter-5CQW74cF.js} +1 -1
- package/dist/{metricsReporter-DaSVYNOK.cjs → metricsReporter-D-24kpOB.cjs} +1 -1
- package/dist/replay.cjs +1 -1
- package/dist/replay.js +1 -1
- package/dist/{view-D4GRlCAk.cjs → view-BDFXZqzu.cjs} +6 -6
- package/dist/{view-B4bFr3nV.js → view-Bn47QoHP.js} +3 -3
- package/package.json +1 -1
- package/dist/core-CZcCXjci.js +0 -12
- package/dist/core-D0ATZnzx.cjs +0 -12
package/dist/replay.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var xe=Object.defineProperty;var Te=(e,t,n)=>t in e?xe(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var U=(e,t,n)=>(Te(e,typeof t!="symbol"?t+"":t,n),n);const o=require("./metricsReporter-DaSVYNOK.cjs");var P=(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))(P||{});class Ae{constructor(t){U(this,"awaitingResolvers",[]);U(this,"activeCount",0);this.capacity=t}async acquire(){if(this.activeCount<this.capacity){this.activeCount++;return}return new Promise(t=>{this.awaitingResolvers.push(t)})}release(){const t=this.awaitingResolvers.shift();t&&this.activeCount<=this.capacity?t():this.activeCount--}async execute(t){try{return await this.acquire(),await t()}finally{this.release()}}setLimit(t){this.capacity=t}}const ie=new Ae(2),Be=e=>ie.setLimit(e),Ue=async e=>ie.execute(async()=>{var a;o.info(`Beginning upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const t=await o.sprigFetch(e.uploadUrl,{body:e.data,method:"PUT"});o.info(`Completed upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const n=(a=t.headers)==null?void 0:a.get("ETag");if(!n)throw new Error(`Upload response did not include etag for upload ${e.uploadId}, part ${e.chunkIndex}`);return n}),ce=async({apiUrl:e,surveyId:t,uploadId:n,etags:a,headers:r,responseGroupUuid:s,replayDuration:i,eventDigest:c},l=!1)=>{var p;if(!l&&!n&&!a){o.info(`Cannot mark upload complete: isMobile: ${l} / uploadId: ${n} / etags: ${a}`);return}o.info(`Marking upload complete for survey: ${t}`);const d=await o.sprigFetch(`${e}/sdk/1/completeSessionReplay`,{method:"POST",body:JSON.stringify({etags:a,uploadId:n,responseGroupUuid:s,surveyId:t,replayDuration:i,eventDigest:c,userAgent:(p=window==null?void 0:window.navigator)==null?void 0:p.userAgent}),headers:r,shouldRetryRequest:!0});return o.info(`Done marking upload complete for survey: ${t}`),d},_=(e,t)=>t.some(n=>e instanceof n);let J,q;function $e(){return J||(J=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function Ne(){return q||(q=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const L=new WeakMap,$=new WeakMap,A=new WeakMap;function _e(e){const t=new Promise((n,a)=>{const r=()=>{n(S(e.result))},s=()=>{a(e.error)};e.onsuccess=r,e.onerror=s});return A.set(t,e),t}function Le(e){if(L.has(e))return;const t=new Promise((n,a)=>{const r=()=>{n()},s=()=>{a(e.error||new DOMException("AbortError","AbortError"))};e.oncomplete=r,e.onerror=s,e.onabort=s});L.set(e,t)}let M={get(e,t,n){if(e instanceof IDBTransaction){if(t==="done")return L.get(e);if(t==="store")return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return S(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function le(e){M=e(M)}function Me(e){return Ne().includes(e)?function(...t){return e.apply(H(this),t),S(this.request)}:function(...t){return S(e.apply(H(this),t))}}function He(e){return typeof e=="function"?Me(e):(e instanceof IDBTransaction&&Le(e),_(e,$e())?new Proxy(e,M):e)}function S(e){if(e instanceof IDBRequest)return _e(e);if($.has(e))return $.get(e);const t=He(e);return t!==e&&($.set(e,t),A.set(t,e)),t}const H=e=>A.get(e);function Oe(e,t,{blocked:n,upgrade:a,blocking:r,terminated:s}={}){const i=indexedDB.open(e,t),c=S(i);return a&&(i.onupgradeneeded=l=>{a(S(i.result),l.oldVersion,l.newVersion,S(i.transaction),l)}),n&&(i.onblocked=l=>n(l.oldVersion,l.newVersion,l)),c.then(l=>{s&&(l.onclose=()=>s()),r&&(l.onversionchange=d=>r(d.oldVersion,d.newVersion,d))}).catch(()=>{}),c}function K(e,{blocked:t}={}){const n=indexedDB.deleteDatabase(e);return t&&(n.onblocked=a=>t(a.oldVersion,a)),S(n).then(()=>{})}const Fe=["get","getKey","getAll","getAllKeys","count"],je=["put","add","delete","clear"],N=new Map;function Q(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(N.get(t))return N.get(t);const n=t.replace(/FromIndex$/,""),a=t!==n,r=je.includes(n);if(!(n in(a?IDBIndex:IDBObjectStore).prototype)||!(r||Fe.includes(n)))return;const s=async function(i,...c){const l=this.transaction(i,r?"readwrite":"readonly");let d=l.store;return a&&(d=d.index(c.shift())),(await Promise.all([d[n](...c),r&&l.done]))[0]};return N.set(t,s),s}le(e=>({...e,get:(t,n,a)=>Q(t,n)||e.get(t,n,a),has:(t,n)=>!!Q(t,n)||e.has(t,n)}));const Ve=["continue","continuePrimaryKey","advance"],X={},O=new WeakMap,de=new WeakMap,Ke={get(e,t){if(!Ve.includes(t))return e[t];let n=X[t];return n||(n=X[t]=function(...a){O.set(this,de.get(this)[t](...a))}),n}};async function*Ge(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;const n=new Proxy(t,Ke);for(de.set(n,t),A.set(n,H(t));t;)yield n,t=await(O.get(n)||t.continue()),O.delete(n)}function Y(e,t){return t===Symbol.asyncIterator&&_(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&_(e,[IDBIndex,IDBObjectStore])}le(e=>({...e,get(t,n,a){return Y(t,n)?Ge:e.get(t,n,a)},has(t,n){return Y(t,n)||e.has(t,n)}}));const We=e=>{if(e instanceof Attr)return null;let t=1;for(let n=e.previousSibling;n;n=n.previousSibling)n.nodeName===e.nodeName&&++t;return t},ue=e=>{if(e===null)return"";const t=[];if(e instanceof Document)return"/";for(let n=e;n&&!(n instanceof Document)&&n!==null;n=n instanceof Attr?n.ownerElement:n.parentElement){const a=t[t.length]={name:void 0,position:null};switch(n.nodeType){case Node.TEXT_NODE:a.name="text()";break;case Node.ATTRIBUTE_NODE:a.name="@"+n.nodeName;break;case Node.PROCESSING_INSTRUCTION_NODE:a.name="processing-instruction()";break;case Node.COMMENT_NODE:a.name="comment()";break;case Node.ELEMENT_NODE:a.name=n.nodeName;break}a.position=We(n)}return"/"+t.reverse().map(n=>n.position!==null?`/${n.name}[${n.position}]`:`/${n.name}`).join("")},v={capture:!0,passive:!0},ze=["a","button","input","option","li","link"],Je=["Escape","Enter","Backspace","F5","Tab"];let x=!1;const qe=["label","type","role","title","placeholder","errormessage","valuetext","href"],Z="aria-",Qe=e=>{if(!e.tagName)return"No tagName";const t=e.getAttribute("type");return t?`${t} ${e.tagName.toLowerCase()}`:e.tagName.toLowerCase()},ee=e=>{var a;if(((a=e.tagName)==null?void 0:a.toLowerCase())==="html")return{element:"html"};const t=e.textContent,n=t?{text:t}:{};n.element=Qe(e);for(const r of e.attributes){let s=r.name;const i=r.value;s.startsWith(Z)&&(s=s.substring(Z.length)),qe.includes(s)&&(n[s]=i)}return n},Xe=e=>{var r;if(!e)return{};const n={...ee(e)},a=e.parentElement;if(a&&ze.includes((r=a.tagName)==null?void 0:r.toLowerCase())){const s=ee(a);Object.assign(n,s)}return n},pe=(e,t)=>{var n;ut({x:t.x,y:t.y,type:e,elementAttributes:Xe(t.target),windowHeight:window.innerHeight,windowWidth:window.innerWidth,...t.target instanceof HTMLElement?{rect:(n=t.target)==null?void 0:n.getBoundingClientRect(),xPath:ue(t.target)}:{}})},Ye=e=>t=>pe(e,t),me=e=>{Je.includes(e.key)&&yt({key:e.key})},Ze=()=>{window.performance.getEntriesByType("navigation").map(t=>t.type).includes("reload")&&ft({url:window.location.href,currentPageTitle:document.title})},et=()=>{window.performance.getEntriesByType("navigation").map(t=>t.type).includes("back_forward")&&wt({curUrl:window.location.href,fromUrl:document.referrer,currentPageTitle:document.title})},tt=(e,t)=>{let n;return a=>{clearTimeout(n),n=window.setTimeout(()=>e(a),t)}},nt=e=>{if(!(e.target instanceof HTMLElement||e.target instanceof Document))return;let t=e.target;"scrollTop"in t||(t=t.documentElement),ht({xPath:ue(t),x:t.scrollLeft,y:t.scrollTop,elementAttributes:{targetScrollWidth:t.scrollWidth,targetClientWidth:t.clientWidth,targetScrollHeight:t.scrollHeight,targetClientHeight:t.clientHeight}})},ge=tt(nt,750),fe=Ye("left_click"),we=e=>{e.button===2&&pe("right_click",e)},rt=()=>{x||(window.addEventListener("click",fe,v),window.addEventListener("mousedown",we,v),window.addEventListener("keydown",me,v),window.addEventListener("scroll",ge,v),x=!0,Ze(),et())},at=()=>{x&&(window.removeEventListener("click",fe,v),window.removeEventListener("mousedown",we,v),window.removeEventListener("keydown",me,v),window.removeEventListener("scroll",ge,v),x=!1)},st=3e4;let E=0;const m={isRecording:!1,scrollEventUuids:{},stopRecording:()=>{}},ot=()=>{const e=o.sessionStorageHelper.getItem("sprig.sessionId");if(e)return o.info(`Found saved session id: ${e}`),o.sessionStorageHelper.removeItem("sprig.sessionId"),e;const t=o.v4();return o.info(`Generating new uuid: ${t}`),t},w=ot(),it=async e=>{var t;if((t=window.navigator.storage)!=null&&t.estimate){const{quota:n=0,usage:a=0}=await window.navigator.storage.estimate();return(n-a)/1024**3>=e}return!0},ye=()=>{o.sessionStorageHelper.setItem("sprig.disableReplayRecording","disabled")},D=()=>!!o.sessionStorageHelper.getItem("sprig.disableReplayRecording");window.addEventListener("beforeunload",()=>{o.info(`Before page unload saving session id: ${w}`),o.sessionStorageHelper.setItem("sprig.sessionId",w)});const ct=async()=>{const t=(await u.getPendingCaptures({isHeatmap:!0})).map(a=>({eventId:a.captureParams.eventId,uuid:a.uuid})),n=[];t.forEach(({eventId:a,uuid:r})=>{o.checkUrlStillMatching(a)||n.push(r)}),n.length&&h(()=>u.markPendingHeatmapsReady(n),"Error marking pending heatmaps ready")},lt=e=>{if(e>1){E=0;return}const t=Date.now();if(!E){E=t;return}t-E>=st&&(E=0,h(()=>u.markPendingHeatmapsReady(),"Error marking pending heatmaps ready"))},G=e=>e&&e.trim().substring(0,500).replace(/\s\s+/g," ").replace(/\r?\n|\r/g," ").substring(0,250),I=(e,t)=>{var n,a;if(m.isRecording)try{(a=(n=window.rrwebRecord)==null?void 0:n.addCustomEvent)==null||a.call(n,e,t)}catch(r){B("Error recording custom event",r)}},dt=e=>{e.description&&(e.description=G(e.description)),I("Sprig_PageView",e)},ut=e=>{var t;(t=e==null?void 0:e.elementAttributes)!=null&&t.text&&(e.elementAttributes.text=G(e.elementAttributes.text)),I("Sprig_Click",e)},pt=e=>{I("Sprig_TrackEvent",e)},mt=e=>{I("Sprig_ShowSurvey",e)},gt=e=>{I("Sprig_SubmitSurvey",e)},ft=e=>{I("Sprig_Refresh",e)},wt=e=>{e.currentPageTitle&&(e.currentPageTitle=G(e.currentPageTitle)),I("Sprig_BackForward",e)},yt=e=>{I("Sprig_Keystroke",e)},ht=async e=>{const{x:t,xPath:n,y:a}=e,r=m.scrollEventUuids[n];if(r)return h(async()=>{var c,l,d,p;const s=await u.openDB(),i=await s.get("events",r);if(i!=null&&i.event){const g=JSON.parse(i.event),y=t>((l=(c=g.data)==null?void 0:c.payload)==null?void 0:l.x),f=a>((p=(d=g.data)==null?void 0:d.payload)==null?void 0:p.y);if(!(y||f))return null;y&&(g.data.payload.x=t),f&&(g.data.payload.y=a),g.data.payload.elementAttributes=e.elementAttributes,i.event=JSON.stringify(g),await s.put("events",i)}else I("Sprig_Scroll",e)},"Error updating scroll event");I("Sprig_Scroll",e)},It=()=>m.isRecording,he=()=>{m.stopRecording&&(m.stopRecording(),m.stopRecording=void 0),m.isRecording=!1,["cleanupInterval","noopInterval","pendingCheckInterval"].forEach(e=>{m[e]&&(clearInterval(m[e]),m[e]=void 0)}),at()},bt=["did not allow mutations","called in an invalid security context"],vt=e=>{if(!e)return!0;for(const t of bt)if(e.toLowerCase().includes(t))return!1;return!0},St=(e,t,{reportError:n=!0,extraInfo:a})=>{D()||t instanceof Error&&(ye(),vt(t==null?void 0:t.message)&&(n&&window.UserLeap.reportError(e,t,a),u.clearAll()))},Ct=async(e,t,{reportError:n}={reportError:!0})=>{var r;let a;try{if(n&&((r=window.navigator.storage)!=null&&r.estimate)){const{quota:s=0,usage:i=0}=await window.navigator.storage.estimate();a={availableSpaceInMB:(s-i)/2**20,quota:s,usage:i}}}catch(s){window.UserLeap.reportError("Error getting storage estimate",s,{originalMessage:e,originalError:t})}St(e,t,{reportError:n,extraInfo:a})},B=(e,t,{reportError:n}={reportError:!0})=>(he(),o.error(`${e} - ${JSON.stringify(t)}`),Ct(e,t,{reportError:n})),h=async(e,t)=>{try{await e()}catch(n){B(t,n)}},Dt=()=>{m.isRecording&&h(()=>{var e,t;return(t=(e=window.rrwebRecord)==null?void 0:e.takeFullSnapshot)==null?void 0:t.call(e,!0)},"Error recording full snapshot")},Et=async({surveyId:e,responseGroupUuid:t,eventDigest:n,headers:a})=>{if(!e||!t)return!1;const r=window.UserLeap._API_URL,s=await ce({surveyId:e,responseGroupUuid:t,eventDigest:n,apiUrl:r,headers:a},!0);return!(s!=null&&s.error)},te=30,kt=1;K("replayStorage").catch(console.error);K("sprig.replay").catch(console.error);class Pt{openDB(){return Oe("sprigReplay",kt,{upgrade:(t,n,a)=>{if(a===0&&o.sessionStorageHelper.setItem("sprig.pendingCount","0"),!t.objectStoreNames.contains("events")){const r=t.createObjectStore("events",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+timestamp]",["sessionId","timestamp"])}if(!t.objectStoreNames.contains("chunkUploads")){const r=t.createObjectStore("chunkUploads",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+status]",["sessionId","status"]),r.createIndex("[uploadId+status]",["uploadId","status"]),r.createIndex("[sessionId+status+uploadId]",["sessionId","status","uploadId"])}if(!t.objectStoreNames.contains("pendingCaptures")){const r=t.createObjectStore("pendingCaptures",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+targetTimestamp]",["sessionId","targetTimestamp"])}}})}constructor(){this.openDB().catch(t=>{o.error(`Error opening replay storage: ${t.message}`),ye(),t.name==="VersionError"&&K("sprigReplay").catch(console.error)})}async bulkAdd(t,n){const a=(await this.openDB()).transaction(t,"readwrite");return Promise.all([...n.map(r=>a.store.add(r)),a.done])}async clearAll(){const t=(await this.openDB()).transaction(["events","chunkUploads","pendingCaptures"],"readwrite");return Promise.all([t.objectStore("events").clear(),t.objectStore("chunkUploads").clear(),t.objectStore("pendingCaptures").clear()])}async deleteBySessionId(t,n){const a=IDBKeyRange.only(n),r=(await this.openDB()).transaction(t,"readwrite");let i=await r.store.index("sessionId").openCursor(a);for(;i;)i.delete(),i=await i.continue();await r.done}async updatePartial(t,n,a){const s=(await this.openDB()).transaction(t,"readwrite"),i=await s.store.get(n);i&&await s.store.put({...i,...a}),await s.done}async deleteRowsBefore(t,n,a=()=>!0){const r=IDBKeyRange.upperBound(n,!0),s=(await this.openDB()).transaction(t,"readwrite");let c=await s.store.index("timestamp").openCursor(r);for(;c;)a(c.value)&&c.delete(),c=await c.continue();await s.done}async getEventsBetween(t,n=Date.now()){if(t>=n)return Promise.resolve([]);const a=IDBKeyRange.bound([w,t],[w,n],!1,!0);return(await this.openDB()).getAllFromIndex("events","[sessionId+timestamp]",a)}async updateEventsExpiredAt(t,n,a=te){const r=new Date,s=r.setMinutes(r.getMinutes()+(a??te)),i=(await this.openDB()).transaction("events","readwrite"),c=i.store.index("[sessionId+timestamp]"),l=IDBKeyRange.bound([w,t],[w,n],!1,!0);let d=await c.openCursor(l);for(;d;)d.update({...d.value,expiredAt:s}),d=await d.continue();await i.done}async deleteChunkUploads(t,n){const a=IDBKeyRange.only([n,t]),r=(await this.openDB()).transaction("chunkUploads","readwrite");let i=await r.store.index("[uploadId+status]").openCursor(a);for(;i;)i.delete(),i=await i.continue();await r.done}async getChunkUploadsByStatus({sessionId:t,status:n,uploadId:a}){const s=(await this.openDB()).transaction("chunkUploads","readonly"),i=a?s.store.index("[uploadId+status]"):s.store.index("[sessionId+status]"),c=a?IDBKeyRange.only([a,n]):IDBKeyRange.only([t,n]);return i.getAll(c)}async getPendingCaptures(t={}){return(await(await this.openDB()).getAllFromIndex("pendingCaptures","sessionId",w)).filter(r=>!t.beforePresent||r.targetTimestamp<Date.now()).filter(r=>!t.isHeatmap||(r.captureParams.isHeatmap??!1))}async markPendingCaptureToCanUpload(t){const n=(await this.openDB()).transaction("pendingCaptures","readwrite");let r=await n.store.index("sessionId").openCursor(w);for(;r;){const s=r.value;s.captureParams.responseGroupId===t&&r.update({...s,canUpload:!0}),r=await r.continue()}await n.done}async markPendingHeatmapsReady(t){if(parseInt(o.sessionStorageHelper.getItem("sprig.pendingCount")??"0")===0)return null;const a=Date.now(),r=(await this.openDB()).transaction("pendingCaptures","readwrite");let i=await r.store.index("sessionId").openCursor(w);for(;i;){const c=i.value;c.captureParams.isHeatmap&&(!t||t.includes(c.uuid))&&i.update({...c,targetTimestamp:a,captureParams:{...c.captureParams,triggerTimestamp:a,replayParams:{...c.captureParams.replayParams,replayDurationSeconds:Math.floor((a-c.timestamp)/1e3)}}}),i=await i.continue()}await r.done}}const u=new Pt,Rt=async(e,t,n)=>new Promise((a,r)=>{const s=e.createElement("script");s.src=t,s.onload=a,s.onerror=r,n&&(s.nonce=n),e.head.appendChild(s)}),Ie=async(e,t)=>{const n=performance.now();let a;try{a=await e()}finally{const r=performance.now()-n;let s=o.PerformanceMetrics[t];s||(s=o.registerMetric(t)),s.report(r/1e3)}return a},be=(e,t)=>{const n=performance.now();try{e()}finally{const a=performance.now()-n;let r=o.PerformanceMetrics[t];r||(r=o.registerMetric(t)),r.report(a/1e3)}};let ne=1,F=5e3,R=6e4;const re=1e3,xt=5,ve=30,T=ve+xt;let ae=Date.now(),C,W=!!o.sessionStorageHelper.getItem("sprig.isCapturingHeatmap"),j=!1,V=[];const Tt=async({viewDocument:e,maxReplayDurationSeconds:t,replayNonce:n,maxInflightRequests:a=2,replaySettings:r,teardownAfter:s=!1})=>{C=o.sessionStorageHelper.getItem("sprig.pendingCount"),!m.isRecording&&(s&&o.sessionStorageHelper.setItem("sprig.teardownAfterCapture","true"),await h(async()=>{if(D()){o.info("Not initializing replay because recording is disabled");return}if(!t){o.info("Not initializing replay because config didn't specify maxReplayDurationSeconds");return}if(r!=null&&r.minAvailableGb&&(ne=r.minAvailableGb),!await it(ne)){o.warn("Minimum storage not available");return}if(o.info("Initializing replay"),r!=null&&r.minDuration&&(F=r.minDuration),r!=null&&r.batchDuration&&(R=r.batchDuration),Be(a),Mt(),$t(t+T,30*60,t+T),Nt(),!window.rrwebRecord){o.info("Loading recording script");const d=window.UserLeap.replayLibraryURL??"https://cdn.sprig.com/dependencies/record-2.0.0-alpha.6.min.js";await Rt(e,d,n),o.info("Recording script finished loading")}const i=window.rrwebRecord;if(!i){o.warn("Record script failed to set global function");return}let c=!0,l=0;m.stopRecording=i({checkoutEveryNms:ve*1e3,sampling:{input:"last",scroll:250,media:800},emit:(d,p)=>{if(D())return;if(ae=Date.now(),p&&d.type===P.Meta)l=performance.now();else if(p&&l&&d.type===P.FullSnapshot){const y=performance.now()-l;o.reportAndRegister("sdk_replay_snapshot_seconds",y/1e3)}const g=c||!!p&&d.type===P.Meta;c=!1,At({uuid:o.v4(),event:JSON.stringify(d),isValidStart:g,timestamp:Date.now()})},...r}),m.isRecording=!!m.stopRecording,m.isRecording&&(m.noopInterval||(m.noopInterval=window.setInterval(()=>{Date.now()-ae>re&&I("Sprig_Noop",{})},re)),o.eventEmitter.on("survey.complete",d=>{gt({id:d,userAgent:window.navigator.userAgent})}),rt())},"Error initializing replay"))},At=e=>{var t,n,a,r;if((t=e.event)!=null&&t.includes("Sprig_Scroll")){const s=(r=(a=(n=JSON.parse(e.event))==null?void 0:n.data)==null?void 0:a.payload)==null?void 0:r.xPath;if(!s)return;m.scrollEventUuids[s]=e.uuid}V.push(e),j||Ut()},Bt=async e=>{const t=e.map(n=>({...n,sessionId:n.sessionId??w}));if(W&<(t.length),t.length!==0)return h(()=>u.bulkAdd("events",t),"Error storing replay events")},Ut=()=>{j=!0,setTimeout(async()=>{if(D())return;const e=V;V=[],j=!1,be(async()=>{await Bt(e)},"sdk_replay_add_event_batch_seconds")},500)},$t=(e,t,n)=>{m.cleanupInterval=window.setInterval(()=>{const a=Date.now();D()||(o.debug(`Performing periodic replay data cleanup / Event Seconds ${e} / Chunk Seconds ${t} / Pending Capture Seconds ${n}`),Ie(()=>h(async()=>{await Promise.all([u.deleteRowsBefore("events",a-e*1e3,r=>r.expiredAt===void 0||r.expiredAt<a-e*1e3),u.deleteRowsBefore("chunkUploads",a-t*1e3),u.deleteRowsBefore("pendingCaptures",a-n*1e3,r=>!r.canUpload)])},"Error deleting table rows"),"sdk_replay_cleanup_seconds"),o.info("Cleanup complete"))},3e4)},Nt=()=>{m.pendingCheckInterval=window.setInterval(async()=>{h(async()=>{const e=parseInt(C??"0");if(e===0)return;const t=await u.getPendingCaptures({beforePresent:!0}),n=await u.openDB();await Promise.all(t.map(async a=>(await n.delete("pendingCaptures",a.uuid),De(a.captureParams,a.canUpload)))),C=(e-t.length).toString(),o.sessionStorageHelper.setItem("sprig.pendingCount",C)},"Error initiating pending captures")},5e3)},_t=async(e,t,n,a,r)=>{const s=Math.min(e+r,n),i=`from: ${new Date(e).toLocaleTimeString()} to ${new Date(s).toLocaleTimeString()}`;o.info(`Getting event batch ${i}`);const c=await Ie(()=>u.getEventsBetween(e,s),"sdk_replay_get_events_between_seconds");if(!(c!=null&&c.length))return o.info(`No events found ${i}`),{validStartFound:a,events:[]};if(!a){o.info(`Searching for valid start in ${c.length} events ${i}`);let l=-1;if(c==null||c.forEach((p,g)=>{if(!p.isValidStart)return;const y=p.timestamp<=t;(l<0||y)&&(l=g)}),l<0)return o.info(`No valid start found in ${c.length} events ${i}`),{validStartFound:a,events:[]};const d=c[l].timestamp;return o.info(`Found valid start at: ${new Date(d).toLocaleTimeString()} in events ${i}`),{validStartFound:!0,events:c==null?void 0:c.slice(l)}}return{validStartFound:a,events:c}},Lt=(e,t,n)=>{const a=e.length,r=t*1024*1024,s=Math.ceil(a/n),i=Math.max(r,s);o.info(`Total file bytes: ${a} / target chunk size: ${i}`);const c=[];let l=0;for(;l<a;)c.push(e.slice(l,l+i)),l+=i;return c},Se=e=>Promise.all(e.map(async t=>{const n=await Ue(t);return await u.updatePartial("chunkUploads",t.uuid,{data:null,etag:n,status:"UploadComplete"}),t.uploadId})),Ce=async e=>{o.info(`Marking upload complete if finished: ${e}`);const t=await u.getChunkUploadsByStatus({status:"UploadComplete",uploadId:e});if(!(t!=null&&t.length)){o.info(`No finished chunks found for upload: ${e}`);return}const n=t.reduce((s,i)=>(s.find(c=>c.chunkIndex===i.chunkIndex)||s.push(i),s),[]);n.sort((s,i)=>s.chunkIndex-i.chunkIndex);const a=n.map(s=>({ETag:s.etag,PartNumber:s.chunkIndex})).filter(s=>s.ETag!==null),r=n[0];await ce({apiUrl:r.apiUrl,surveyId:r.surveyId,uploadId:e,responseGroupUuid:r.responseGroupId,etags:a,headers:r.completeUploadHeaders,replayDuration:r.replayDuration}),o.info(`Cleaning up chunks for ${e}`),await u.deleteChunkUploads("UploadComplete",e),o.info(`Done cleaning up chunks for ${e}`)},Mt=async()=>{h(async()=>{const e=await u.getChunkUploadsByStatus({sessionId:w,status:"ReadyForUpload"});if(!(e!=null&&e.length))return;const t=await Se(e);o.info(`Finished uploading unfinished chunks for ${t}`),t!=null&&t.length&&await Promise.all(t.map(n=>{if(n)return Ce(n)}))},"Error uploading unfinished chunks")},Ht=async(e,t)=>{await Se(t),o.info(`Done uploading chunks for uploads: ${e.join(",")}`),await Promise.all(e.map(n=>Ce(n)))},Ot=e=>{let t=0;e.forEach(r=>{t+=r.length});const n=new Uint8Array(t);let a=0;return e.forEach(r=>{n.set(r,a),a+=r.length}),n},se=async(e,t,n)=>{const a=new TextEncoder;let r=null,s=null,i=null,c=!1,l=!1,[d,p]=[0,0];const g=e-T*1e3,y=[];let f=[];o.info(`Getting events between ${new Date(e).toLocaleTimeString()} and ${new Date(t).toLocaleTimeString()}`),o.info(`Using batch duration: ${R}ms`);for(let k=g;k<t;k+=R){if({validStartFound:l,events:f}=await _t(k,e,t,l,R),!(f!=null&&f.length)){o.info("No events found");continue}d===0&&(d=f[0].timestamp),p=f[f.length-1].timestamp,o.info(`Last event time in batch: ${new Date(p).toLocaleTimeString()}`);const Pe=`${c?",":"["}${f.map(Re=>Re.event).join(",")}`,z=a.encode(Pe);n&&s===null&&(o.debug("Attempting compression"),i=new window.CompressionStream("gzip"),s=i.writable.getWriter()),be(()=>{n&&s?s.write(z):y.push(z)},"sdk_replay_compression_seconds"),c=!0}if(p-d<F)return o.info(`Replay duration is shorter than minimum of ${F}ms / Start:${d} / End:${p}`),null;const b=a.encode("]");return o.debug("Writing final close brace"),s&&i?(s.write(b),s.close(),r=new Uint8Array(await new Response(i.readable).arrayBuffer())):(y.push(b),r=Ot(y)),o.info("Finished generating file data"),r},Ft=async(e,t)=>{const n=window.CompressionStream!==void 0;let a=null;const r=t??Date.now(),s=r-e;try{a=await se(s,r,n)}catch(i){i instanceof Error&&window.UserLeap.reportError("Error compressing replay",i),n&&h(async()=>{await se(s,r,!1)},"fileData fallback failed")}return a},oe=async e=>{const{surveyId:t,responseGroupId:n,visitorId:a,apiUrl:r,completeUploadHeaders:s,replayParams:i,triggerTimestamp:c}=e,l=await Ft(i.replayDurationSeconds*1e3,c);if(l!=null&&l.length)o.info(`Found file data for survey: ${t}`);else{o.info(`File data is empty for survey: ${t}`);return}const d=Lt(l,i.minimumChunkSizeMb,i.signedUrls.length);o.info(`Got ${d.length} chunks for survey: ${t}`);const p=await Promise.all(d.map(async(g,y)=>{const f=o.v4(),b={apiUrl:r,chunkIndex:y+1,completeUploadHeaders:s,etag:null,responseGroupId:n,status:"ReadyForUpload",surveyId:t,timestamp:c,totalChunks:d.length,data:g,uploadId:i.uploadId,uploadUrl:i.signedUrls[y].url,uuid:f,visitorId:a};return o.info(`Recording chunk upload: ${JSON.stringify({index:b.chunkIndex,surveyId:b.surveyId,uploadId:b.uploadId,size:g.length,id:f},null,2)}`),await(await u.openDB()).add("chunkUploads",{...b,sessionId:b.sessionId??w}),o.info(`Done creating chunk upload: ${f}`),b}));o.info(`All chunk records created. Beginning upload for survey: ${t}`),await Ht([i.uploadId],p)},De=async(e,t)=>{if(o.info(`Attempting replay capture: ${JSON.stringify({isStandalone:e.isStandalone,duration:e.replayParams.replayDurationSeconds,type:e.replayParams.replayDurationType,responseGroupId:e.responseGroupId,surveyId:e.surveyId,triggerTimestamp:e.triggerTimestamp,visitorId:e.visitorId},null,2)}`),D())return o.info(`Replay recording is disabled: ${e.surveyId}`);o.info(`Replay recording enabled: ${e.surveyId}`);const{isHeatmap:n,isStandalone:a,replayParams:r,triggerTimestamp:s,responseGroupId:i}=e,c=async()=>{setTimeout(()=>o.eventEmitter.removeListener(o.SprigEvent.QuestionAnswered,c),0),h(async()=>{r.replayDurationType==="before"?await oe(e):await u.markPendingCaptureToCanUpload(i)},"Error in schedule/capture callback")};h(async()=>{if(r.replayDurationType==="after"||r.replayDurationType==="beforeAndAfter"){!a&&!n&&(o.info("Attaching QuestionAnswered listener for non-standalone replay"),o.eventEmitter.on(o.SprigEvent.QuestionAnswered,c)),o.info(`Scheduling capture for replay of type: ${r.replayDurationType}`),await ke(e);return}if(a||n||t)o.info(`Proceeding to capture replay for survey: ${e.surveyId} / standalone? ${a} / canUpload? ${t}`),await oe(e),n&&jt();else{const d=T+r.replayDurationSeconds,p=s-d*1e3,g=s;o.info(`Setting expiry minutes to ${r.expirationTimeLimitMinutes} for events from ${new Date(p).toLocaleTimeString()} to ${new Date(g).toLocaleTimeString()}`),await u.updateEventsExpiredAt(p,g,r.expirationTimeLimitMinutes),o.info("Attaching QuestionAnswered listener"),o.eventEmitter.on(o.SprigEvent.QuestionAnswered,c)}},"Error in scheduling/capturing replay")},jt=async()=>{parseInt(C??"0")||(o.sessionStorageHelper.removeItem("sprig.isCapturingHeatmap"),W=!1),o.sessionStorageHelper.getItem("sprig.teardownAfterCapture")&&(he(),Ee(),o.sessionStorageHelper.removeItem("sprig.teardownAfterCapture"))},Ee=()=>{if(D()){o.debug("Not clearing user data, replay is disabled");return}return Promise.all([u.deleteBySessionId("events",w),u.deleteBySessionId("pendingCaptures",w)]).catch(e=>{B("Error clearing user replay data",e)})},ke=async e=>{o.info(`Scheduling replay capture: ${JSON.stringify(e)}`);const{isHeatmap:t,surveyId:n}=e,a=await u.getPendingCaptures(),r=a==null?void 0:a.filter(l=>l.captureParams.surveyId===n);if(r!=null&&r.length){o.info(`Pending capture exists for survey: ${n}`);return}t&&(Dt(),W=!0,o.sessionStorageHelper.setItem("sprig.isCapturingHeatmap","true"));const s={...e,replayParams:{...e.replayParams}};e.replayParams.replayDurationType==="beforeAndAfter"&&(s.replayParams.replayDurationSeconds*=2),s.replayParams.replayDurationType="before";const i=e.triggerTimestamp+e.replayParams.replayDurationSeconds*1e3;s.triggerTimestamp=i,C=(parseInt(C??"0")+1).toString(),o.sessionStorageHelper.setItem("sprig.pendingCount",C),await(await u.openDB()).add("pendingCaptures",{canUpload:!1,captureParams:s,sessionId:w,targetTimestamp:i,timestamp:Date.now(),uuid:o.v4()})},Vt=Object.freeze(Object.defineProperty({__proto__:null,RecordEvent:pt,RecordPageView:dt,RecordSurveyShown:mt,_completeSessionReplay:Et,checkPendingHeatmapsUrl:ct,clearUserReplayData:Ee,disableRecording:B,initializeReplay:Tt,isReplayRecording:It,scheduleCapture:ke,scheduleOrCaptureReplay:De,tryReplayAction:h},Symbol.toStringTag,{value:"Module"}));o.registerReplay(Vt);
|
|
1
|
+
"use strict";var Ee=Object.defineProperty;var Re=(e,t,n)=>t in e?Ee(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var A=(e,t,n)=>(Re(e,typeof t!="symbol"?t+"":t,n),n);const o=require("./metricsReporter-D-24kpOB.cjs");var k=(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))(k||{});class Pe{constructor(t){A(this,"awaitingResolvers",[]);A(this,"activeCount",0);this.capacity=t}async acquire(){if(this.activeCount<this.capacity){this.activeCount++;return}return new Promise(t=>{this.awaitingResolvers.push(t)})}release(){const t=this.awaitingResolvers.shift();t&&this.activeCount<=this.capacity?t():this.activeCount--}async execute(t){try{return await this.acquire(),await t()}finally{this.release()}}setLimit(t){this.capacity=t}}const se=new Pe(2),xe=e=>se.setLimit(e),Be=async e=>se.execute(async()=>{var r;o.info(`Beginning upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const t=await o.sprigFetch(e.uploadUrl,{body:e.data,method:"PUT"});o.info(`Completed upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const n=(r=t.headers)==null?void 0:r.get("ETag");if(!n)throw new Error(`Upload response did not include etag for upload ${e.uploadId}, part ${e.chunkIndex}`);return n}),oe=async({apiUrl:e,surveyId:t,uploadId:n,etags:r,headers:a,responseGroupUuid:s,replayDuration:i,eventDigest:c},l=!1)=>{var p;if(!l&&!n&&!r){o.info(`Cannot mark upload complete: isMobile: ${l} / uploadId: ${n} / etags: ${r}`);return}o.info(`Marking upload complete for survey: ${t}`);const d=await o.sprigFetch(`${e}/sdk/1/completeSessionReplay`,{method:"POST",body:JSON.stringify({etags:r,uploadId:n,responseGroupUuid:s,surveyId:t,replayDuration:i,eventDigest:c,userAgent:(p=window==null?void 0:window.navigator)==null?void 0:p.userAgent}),headers:a,shouldRetryRequest:!0});return o.info(`Done marking upload complete for survey: ${t}`),d},N=(e,t)=>t.some(n=>e instanceof n);let q,Q;function Te(){return q||(q=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function Ae(){return Q||(Q=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const _=new WeakMap,$=new WeakMap,B=new WeakMap;function $e(e){const t=new Promise((n,r)=>{const a=()=>{n(D(e.result))},s=()=>{r(e.error)};e.onsuccess=a,e.onerror=s});return B.set(t,e),t}function Ue(e){if(_.has(e))return;const t=new Promise((n,r)=>{const a=()=>{n()},s=()=>{r(e.error||new DOMException("AbortError","AbortError"))};e.oncomplete=a,e.onerror=s,e.onabort=s});_.set(e,t)}let L={get(e,t,n){if(e instanceof IDBTransaction){if(t==="done")return _.get(e);if(t==="store")return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return D(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function ie(e){L=e(L)}function Ne(e){return Ae().includes(e)?function(...t){return e.apply(M(this),t),D(this.request)}:function(...t){return D(e.apply(M(this),t))}}function _e(e){return typeof e=="function"?Ne(e):(e instanceof IDBTransaction&&Ue(e),N(e,Te())?new Proxy(e,L):e)}function D(e){if(e instanceof IDBRequest)return $e(e);if($.has(e))return $.get(e);const t=_e(e);return t!==e&&($.set(e,t),B.set(t,e)),t}const M=e=>B.get(e);function Le(e,t,{blocked:n,upgrade:r,blocking:a,terminated:s}={}){const i=indexedDB.open(e,t),c=D(i);return r&&(i.onupgradeneeded=l=>{r(D(i.result),l.oldVersion,l.newVersion,D(i.transaction),l)}),n&&(i.onblocked=l=>n(l.oldVersion,l.newVersion,l)),c.then(l=>{s&&(l.onclose=()=>s()),a&&(l.onversionchange=d=>a(d.oldVersion,d.newVersion,d))}).catch(()=>{}),c}function G(e,{blocked:t}={}){const n=indexedDB.deleteDatabase(e);return t&&(n.onblocked=r=>t(r.oldVersion,r)),D(n).then(()=>{})}const Me=["get","getKey","getAll","getAllKeys","count"],Oe=["put","add","delete","clear"],U=new Map;function X(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(U.get(t))return U.get(t);const n=t.replace(/FromIndex$/,""),r=t!==n,a=Oe.includes(n);if(!(n in(r?IDBIndex:IDBObjectStore).prototype)||!(a||Me.includes(n)))return;const s=async function(i,...c){const l=this.transaction(i,a?"readwrite":"readonly");let d=l.store;return r&&(d=d.index(c.shift())),(await Promise.all([d[n](...c),a&&l.done]))[0]};return U.set(t,s),s}ie(e=>({...e,get:(t,n,r)=>X(t,n)||e.get(t,n,r),has:(t,n)=>!!X(t,n)||e.has(t,n)}));const He=["continue","continuePrimaryKey","advance"],Y={},O=new WeakMap,ce=new WeakMap,Fe={get(e,t){if(!He.includes(t))return e[t];let n=Y[t];return n||(n=Y[t]=function(...r){O.set(this,ce.get(this)[t](...r))}),n}};async function*je(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;const n=new Proxy(t,Fe);for(ce.set(n,t),B.set(n,M(t));t;)yield n,t=await(O.get(n)||t.continue()),O.delete(n)}function Z(e,t){return t===Symbol.asyncIterator&&N(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&N(e,[IDBIndex,IDBObjectStore])}ie(e=>({...e,get(t,n,r){return Z(t,n)?je:e.get(t,n,r)},has(t,n){return Z(t,n)||e.has(t,n)}}));const Ke=e=>{if(e instanceof Attr)return null;let t=1;for(let n=e.previousSibling;n;n=n.previousSibling)n.nodeName===e.nodeName&&++t;return t},le=e=>{if(e===null)return"";const t=[];if(e instanceof Document)return"/";for(let n=e;n&&!(n instanceof Document)&&n!==null;n=n instanceof Attr?n.ownerElement:n.parentElement){const r=t[t.length]={name:void 0,position:null};switch(n.nodeType){case Node.TEXT_NODE:r.name="text()";break;case Node.ATTRIBUTE_NODE:r.name="@"+n.nodeName;break;case Node.PROCESSING_INSTRUCTION_NODE:r.name="processing-instruction()";break;case Node.COMMENT_NODE:r.name="comment()";break;case Node.ELEMENT_NODE:r.name=n.nodeName;break}r.position=Ke(n)}return"/"+t.reverse().map(n=>n.position!==null?`/${n.name}[${n.position}]`:`/${n.name}`).join("")},S={capture:!0,passive:!0},Ve=["a","button","input","option","li","link"],Ge=["Escape","Enter","Backspace","F5","Tab"];let P=!1;const We=["label","type","role","title","placeholder","errormessage","valuetext","href"],ee="aria-",ze=e=>{if(!e.tagName)return"No tagName";const t=e.getAttribute("type");return t?`${t} ${e.tagName.toLowerCase()}`:e.tagName.toLowerCase()},te=e=>{var r;if(((r=e.tagName)==null?void 0:r.toLowerCase())==="html")return{element:"html"};const t=e.textContent,n=t?{text:t}:{};n.element=ze(e);for(const a of e.attributes){let s=a.name;const i=a.value;s.startsWith(ee)&&(s=s.substring(ee.length)),We.includes(s)&&(n[s]=i)}return n},Je=e=>{var a;if(!e)return{};const n={...te(e)},r=e.parentElement;if(r&&Ve.includes((a=r.tagName)==null?void 0:a.toLowerCase())){const s=te(r);Object.assign(n,s)}return n},de=(e,t)=>{var n;lt({x:t.x,y:t.y,type:e,elementAttributes:Je(t.target),windowHeight:window.innerHeight,windowWidth:window.innerWidth,...t.target instanceof HTMLElement?{rect:(n=t.target)==null?void 0:n.getBoundingClientRect(),xPath:le(t.target)}:{}})},qe=e=>t=>de(e,t),ue=e=>{Ge.includes(e.key)&>({key:e.key})},Qe=()=>{window.performance.getEntriesByType("navigation").map(t=>t.type).includes("reload")&&mt({url:window.location.href,currentPageTitle:document.title})},Xe=()=>{window.performance.getEntriesByType("navigation").map(t=>t.type).includes("back_forward")&&ft({curUrl:window.location.href,fromUrl:document.referrer,currentPageTitle:document.title})},Ye=(e,t)=>{let n;return r=>{clearTimeout(n),n=window.setTimeout(()=>e(r),t)}},Ze=e=>{if(!(e.target instanceof HTMLElement||e.target instanceof Document))return;let t=e.target;"scrollTop"in t||(t=t.documentElement),wt({xPath:le(t),x:t.scrollLeft,y:t.scrollTop,elementAttributes:{targetScrollWidth:t.scrollWidth,targetClientWidth:t.clientWidth,targetScrollHeight:t.scrollHeight,targetClientHeight:t.clientHeight}})},pe=Ye(Ze,750),me=qe("left_click"),fe=e=>{e.button===2&&de("right_click",e)},et=()=>{P||(window.addEventListener("click",me,S),window.addEventListener("mousedown",fe,S),window.addEventListener("keydown",ue,S),window.addEventListener("scroll",pe,S),P=!0,Qe(),Xe())},tt=()=>{P&&(window.removeEventListener("click",me,S),window.removeEventListener("mousedown",fe,S),window.removeEventListener("keydown",ue,S),window.removeEventListener("scroll",pe,S),P=!1)},nt=3e4,m={isRecording:!1,scrollEventUuids:{},stopRecording:()=>{}},rt=.5,at=async()=>{var e;if(!window.indexedDB||!window.IDBKeyRange)return!0;if((e=window.navigator.storage)!=null&&e.estimate)try{const{quota:t=0,usage:n=0}=await window.navigator.storage.estimate(),r=(t-n)/1024**3;return o.warn(`Storage: ${r}GB`),r<rt}catch{return!0}return!1},st=()=>{const e=o.sessionStorageHelper.getItem("sprig.sessionId");if(e)return o.info(`Found saved session id: ${e}`),o.sessionStorageHelper.removeItem("sprig.sessionId"),e;const t=o.v4();return o.info(`Generating new uuid: ${t}`),t},w=st(),H=()=>{o.sessionStorageHelper.setItem("sprig.disableReplayRecording","disabled")},b=()=>!!o.sessionStorageHelper.getItem("sprig.disableReplayRecording");window.addEventListener("beforeunload",()=>{o.info(`Before page unload saving session id: ${w}`),o.sessionStorageHelper.setItem("sprig.sessionId",w)});const ot=()=>b()?o.info("ReolayDisabledPendingHeatmap"):h(async()=>{const e=(await u.getPendingCaptures({isHeatmap:!0})).map(n=>({eventId:n.captureParams.eventId,uuid:n.uuid})),t=[];e.forEach(({eventId:n,uuid:r})=>{o.checkUrlStillMatching(n)||t.push(r)}),t.length&&await u.markPendingHeatmapsReady(t)},"Error marking pending heatmaps ready"),it=e=>{Date.now()-e>=nt&&h(()=>u.markPendingHeatmapsReady(),"Error in heatmap inactivity")},W=e=>e&&e.trim().substring(0,500).replace(/\s\s+/g," ").replace(/\r?\n|\r/g," ").substring(0,250),I=(e,t)=>{var n,r;if(m.isRecording)try{(r=(n=window.rrwebRecord)==null?void 0:n.addCustomEvent)==null||r.call(n,e,t)}catch(a){T("Error recording custom event",a)}},ct=e=>{e.description&&(e.description=W(e.description)),I("Sprig_PageView",e)},lt=e=>{var t;(t=e==null?void 0:e.elementAttributes)!=null&&t.text&&(e.elementAttributes.text=W(e.elementAttributes.text)),I("Sprig_Click",e)},dt=e=>{I("Sprig_TrackEvent",e)},ut=e=>{I("Sprig_ShowSurvey",e)},pt=e=>{I("Sprig_SubmitSurvey",e)},mt=e=>{I("Sprig_Refresh",e)},ft=e=>{e.currentPageTitle&&(e.currentPageTitle=W(e.currentPageTitle)),I("Sprig_BackForward",e)},gt=e=>{I("Sprig_Keystroke",e)},wt=async e=>{const{x:t,xPath:n,y:r}=e,a=m.scrollEventUuids[n];if(a)return h(async()=>{var c,l,d,p;const s=await u.openDB(),i=await s.get("events",a);if(i!=null&&i.event){const f=JSON.parse(i.event),y=t>((l=(c=f.data)==null?void 0:c.payload)==null?void 0:l.x),g=r>((p=(d=f.data)==null?void 0:d.payload)==null?void 0:p.y);if(!(y||g))return null;y&&(f.data.payload.x=t),g&&(f.data.payload.y=r),f.data.payload.elementAttributes=e.elementAttributes,i.event=JSON.stringify(f),await s.put("events",i)}else I("Sprig_Scroll",e)},"Error updating scroll event");I("Sprig_Scroll",e)},yt=()=>m.isRecording,ge=()=>{m.stopRecording&&(m.stopRecording(),m.stopRecording=void 0),m.isRecording=!1,["cleanupInterval","inactivityInterval","pendingCheckInterval"].forEach(e=>{m[e]&&(clearInterval(m[e]),m[e]=void 0)}),tt()},ht=["did not allow mutations","called in an invalid security context"],It=e=>{if(!e)return!0;for(const t of ht)if(e.toLowerCase().includes(t))return!1;return!0},vt=(e,t,{reportError:n=!0,extraInfo:r})=>{b()||t instanceof Error&&(H(),It(t==null?void 0:t.message)&&(n&&window.UserLeap.reportError(e,t,r),u.clearAll()))},bt=async(e,t,{reportError:n}={reportError:!0})=>{let r={};try{const{quota:a=0,usage:s=0}=await window.navigator.storage.estimate();r={availableSpaceInMB:(a-s)/2**20,quota:a,usage:s}}catch{r.availableSpaceInMB=null}vt(e,t,{reportError:n,extraInfo:r})},T=(e,t,{reportError:n}={reportError:!0})=>(ge(),o.error(`${e} - ${t.message} - ${t.name}`),bt(e,t,{reportError:n})),h=async(e,t)=>{try{await e()}catch(n){T(t,n)}},St=()=>{m.isRecording&&h(()=>{var e,t;return(t=(e=window.rrwebRecord)==null?void 0:e.takeFullSnapshot)==null?void 0:t.call(e,!0)},"Error recording full snapshot")},Dt=async({surveyId:e,responseGroupUuid:t,eventDigest:n,headers:r})=>{if(!e||!t)return!1;const a=window.UserLeap._API_URL,s=await oe({surveyId:e,responseGroupUuid:t,eventDigest:n,apiUrl:a,headers:r},!0);return!(s!=null&&s.error)},ne=30,Ct=1;G("replayStorage").catch(console.error);G("sprig.replay").catch(console.error);class kt{openDB(){return Le("sprigReplay",Ct,{upgrade:(t,n,r)=>{if(r===0&&o.sessionStorageHelper.setItem("sprig.pendingCount","0"),!t.objectStoreNames.contains("events")){const a=t.createObjectStore("events",{keyPath:"uuid"});a.createIndex("sessionId","sessionId"),a.createIndex("timestamp","timestamp"),a.createIndex("[sessionId+timestamp]",["sessionId","timestamp"])}if(!t.objectStoreNames.contains("chunkUploads")){const a=t.createObjectStore("chunkUploads",{keyPath:"uuid"});a.createIndex("sessionId","sessionId"),a.createIndex("timestamp","timestamp"),a.createIndex("[sessionId+status]",["sessionId","status"]),a.createIndex("[uploadId+status]",["uploadId","status"]),a.createIndex("[sessionId+status+uploadId]",["sessionId","status","uploadId"])}if(!t.objectStoreNames.contains("pendingCaptures")){const a=t.createObjectStore("pendingCaptures",{keyPath:"uuid"});a.createIndex("sessionId","sessionId"),a.createIndex("timestamp","timestamp"),a.createIndex("[sessionId+targetTimestamp]",["sessionId","targetTimestamp"])}}})}deleteDB(){return G("sprigReplay").catch(console.error)}async bulkAdd(t,n){const r=(await this.openDB()).transaction(t,"readwrite");return Promise.all([...n.map(a=>r.store.add(a)),r.done])}async clearAll(){const t=(await this.openDB()).transaction(["events","chunkUploads","pendingCaptures"],"readwrite");return Promise.all([t.objectStore("events").clear(),t.objectStore("chunkUploads").clear(),t.objectStore("pendingCaptures").clear()])}async deleteBySessionId(t,n){const r=IDBKeyRange.only(n),a=(await this.openDB()).transaction(t,"readwrite");let i=await a.store.index("sessionId").openCursor(r);for(;i;)i.delete(),i=await i.continue();await a.done}async updatePartial(t,n,r){const s=(await this.openDB()).transaction(t,"readwrite"),i=await s.store.get(n);i&&await s.store.put({...i,...r}),await s.done}async deleteRowsBefore(t,n,r=()=>!0){const a=IDBKeyRange.upperBound(n,!0),s=(await this.openDB()).transaction(t,"readwrite");let c=await s.store.index("timestamp").openCursor(a);for(;c;)r(c.value)&&c.delete(),c=await c.continue();await s.done}async getEventsBetween(t,n=Date.now()){if(t>=n)return Promise.resolve([]);const r=IDBKeyRange.bound([w,t],[w,n],!1,!0);return(await this.openDB()).getAllFromIndex("events","[sessionId+timestamp]",r)}async updateEventsExpiredAt(t,n,r=ne){const a=new Date,s=a.setMinutes(a.getMinutes()+(r??ne)),i=(await this.openDB()).transaction("events","readwrite"),c=i.store.index("[sessionId+timestamp]"),l=IDBKeyRange.bound([w,t],[w,n],!1,!0);let d=await c.openCursor(l);for(;d;)d.update({...d.value,expiredAt:s}),d=await d.continue();await i.done}async deleteChunkUploads(t,n){const r=IDBKeyRange.only([n,t]),a=(await this.openDB()).transaction("chunkUploads","readwrite");let i=await a.store.index("[uploadId+status]").openCursor(r);for(;i;)i.delete(),i=await i.continue();await a.done}async getChunkUploadsByStatus({sessionId:t,status:n,uploadId:r}){const s=(await this.openDB()).transaction("chunkUploads","readonly"),i=r?s.store.index("[uploadId+status]"):s.store.index("[sessionId+status]"),c=r?IDBKeyRange.only([r,n]):IDBKeyRange.only([t,n]);return i.getAll(c)}async getPendingCaptures(t={}){return(await(await this.openDB()).getAllFromIndex("pendingCaptures","sessionId",w)).filter(a=>!t.beforePresent||a.targetTimestamp<Date.now()).filter(a=>!t.isHeatmap||(a.captureParams.isHeatmap??!1))}async markPendingCaptureToCanUpload(t){const n=(await this.openDB()).transaction("pendingCaptures","readwrite");let a=await n.store.index("sessionId").openCursor(w);for(;a;){const s=a.value;s.captureParams.responseGroupId===t&&a.update({...s,canUpload:!0}),a=await a.continue()}await n.done}async markPendingHeatmapsReady(t){if(parseInt(o.sessionStorageHelper.getItem("sprig.pendingCount")??"0")===0)return null;const r=Date.now(),a=(await this.openDB()).transaction("pendingCaptures","readwrite");let i=await a.store.index("sessionId").openCursor(w);for(;i;){const c=i.value;c.captureParams.isHeatmap&&(!t||t.includes(c.uuid))&&i.update({...c,targetTimestamp:r,captureParams:{...c.captureParams,triggerTimestamp:r,replayParams:{...c.captureParams.replayParams,replayDurationSeconds:Math.floor((r-c.timestamp)/1e3)}}}),i=await i.continue()}await a.done}}const u=new kt,Et=async(e,t,n)=>new Promise((r,a)=>{const s=e.createElement("script");s.src=t,s.onload=r,s.onerror=a,n&&(s.nonce=n),e.head.appendChild(s)}),we=async(e,t)=>{const n=performance.now();let r;try{r=await e()}finally{const a=performance.now()-n;let s=o.PerformanceMetrics[t];s||(s=o.registerMetric(t)),s.report(a/1e3)}return r},ye=(e,t)=>{const n=performance.now();try{e()}finally{const r=performance.now()-n;let a=o.PerformanceMetrics[t];a||(a=o.registerMetric(t)),a.report(r/1e3)}};let F=5e3,R=6e4,j=0;const Rt=5,he=30,x=he+Rt;let C,K=!1,V=[];const Pt=async({viewDocument:e,maxReplayDurationSeconds:t,replayNonce:n,maxInflightRequests:r=2,replaySettings:a,teardownAfter:s=!1})=>{if(C=o.sessionStorageHelper.getItem("sprig.pendingCount"),!m.isRecording){if(s&&o.sessionStorageHelper.setItem("sprig.teardownAfterCapture","true"),b())return o.info("ReplayDisabled");if(await at())return o.error("IDBNotSupported"),H();try{await u.openDB()}catch(i){return o.error(`ReplayError-${i.message}-${i.name}`),i.name==="VersionError"&&u.deleteDB(),H()}if(!t)return o.info("MissingReplaySeconds");o.info("ReplayInit"),await h(async()=>{if(a!=null&&a.minDuration&&(F=a.minDuration),a!=null&&a.batchDuration&&(R=a.batchDuration),xe(r),_t(),At(t+x,30*60,t+x),$t(),!window.rrwebRecord){const d=window.UserLeap.replayLibraryURL??"https://cdn.sprig.com/dependencies/record-2.0.0-alpha.6.min.js";await Et(e,d,n)}const i=window.rrwebRecord;if(!i)return o.warn("RecordScriptFailed");let c=!0,l=0;m.stopRecording=i({checkoutEveryNms:he*1e3,sampling:{input:"last",scroll:250,media:800},emit:(d,p)=>{if(d.type===k.Custom&&(j=Date.now()),b())return;if(p&&d.type===k.Meta)l=performance.now();else if(p&&l&&d.type===k.FullSnapshot){const y=performance.now()-l;o.reportAndRegister("sdk_replay_snapshot_seconds",y/1e3)}const f=c||!!p&&d.type===k.Meta;c=!1,xt({uuid:o.v4(),event:JSON.stringify(d),isValidStart:f,timestamp:Date.now()})},...a}),m.isRecording=!!m.stopRecording,m.isRecording&&(o.eventEmitter.on("survey.complete",d=>{pt({id:d,userAgent:window.navigator.userAgent})}),et())},"Error initializing replay")}},xt=e=>{var t,n,r,a;if((t=e.event)!=null&&t.includes("Sprig_Scroll")){const s=(a=(r=(n=JSON.parse(e.event))==null?void 0:n.data)==null?void 0:r.payload)==null?void 0:a.xPath;if(!s)return;m.scrollEventUuids[s]=e.uuid}V.push(e),K||Tt()},Bt=async e=>{const t=e.map(n=>({...n,sessionId:n.sessionId??w}));if(t.length!==0)return h(()=>u.bulkAdd("events",t),"Error storing replay events")},Tt=()=>{K=!0,setTimeout(async()=>{if(b())return;const e=V;V=[],K=!1,ye(async()=>{await Bt(e)},"sdk_replay_add_event_batch_seconds")},500)},At=(e,t,n)=>{m.cleanupInterval=window.setInterval(()=>{const r=Date.now();b()||(o.debug(`CleanUp Secs - Events: ${e}, Chunks: ${t}, Captures: ${n}`),we(()=>h(async()=>{await Promise.all([u.deleteRowsBefore("events",r-e*1e3,a=>a.expiredAt===void 0||a.expiredAt<r-e*1e3),u.deleteRowsBefore("chunkUploads",r-t*1e3),u.deleteRowsBefore("pendingCaptures",r-n*1e3,a=>!a.canUpload)])},"Error deleting table rows"),"sdk_replay_cleanup_seconds"),o.info("Cleanup complete"))},3e4)},$t=()=>{m.pendingCheckInterval=window.setInterval(async()=>{h(async()=>{const e=parseInt(C??"0");if(e===0)return;const t=await u.getPendingCaptures({beforePresent:!0}),n=await u.openDB();await Promise.all(t.map(async r=>(await n.delete("pendingCaptures",r.uuid),be(r.captureParams,r.canUpload)))),C=(e-t.length).toString(),o.sessionStorageHelper.setItem("sprig.pendingCount",C)},"Error initiating pending captures")},5e3)},Ut=async(e,t,n,r,a)=>{const s=Math.min(e+a,n),i=`from: ${new Date(e).toLocaleTimeString()} to ${new Date(s).toLocaleTimeString()}`;o.info(`Getting event batch ${i}`);const c=await we(()=>u.getEventsBetween(e,s),"sdk_replay_get_events_between_seconds");if(!(c!=null&&c.length))return o.info(`No events found ${i}`),{validStartFound:r,events:[]};if(!r){o.info(`Searching for valid start in ${c.length} events ${i}`);let l=-1;if(c==null||c.forEach((p,f)=>{if(!p.isValidStart)return;const y=p.timestamp<=t;(l<0||y)&&(l=f)}),l<0)return o.info(`No valid start found in ${c.length} events ${i}`),{validStartFound:r,events:[]};const d=c[l].timestamp;return o.info(`Found valid start at: ${new Date(d).toLocaleTimeString()} in events ${i}`),{validStartFound:!0,events:c==null?void 0:c.slice(l)}}return{validStartFound:r,events:c}},Nt=(e,t,n)=>{const r=e.length,a=t*1024*1024,s=Math.ceil(r/n),i=Math.max(a,s);o.info(`Total file bytes: ${r} / target chunk size: ${i}`);const c=[];let l=0;for(;l<r;)c.push(e.slice(l,l+i)),l+=i;return c},Ie=e=>Promise.all(e.map(async t=>{const n=await Be(t);return await u.updatePartial("chunkUploads",t.uuid,{data:null,etag:n,status:"UploadComplete"}),t.uploadId})),ve=async e=>{o.info(`Marking upload complete if finished: ${e}`);const t=await u.getChunkUploadsByStatus({status:"UploadComplete",uploadId:e});if(!(t!=null&&t.length)){o.info(`No finished chunks found for upload: ${e}`);return}const n=t.reduce((s,i)=>(s.find(c=>c.chunkIndex===i.chunkIndex)||s.push(i),s),[]);n.sort((s,i)=>s.chunkIndex-i.chunkIndex);const r=n.map(s=>({ETag:s.etag,PartNumber:s.chunkIndex})).filter(s=>s.ETag!==null),a=n[0];await oe({apiUrl:a.apiUrl,surveyId:a.surveyId,uploadId:e,responseGroupUuid:a.responseGroupId,etags:r,headers:a.completeUploadHeaders,replayDuration:a.replayDuration}),o.info(`Cleaning up chunks for ${e}`),await u.deleteChunkUploads("UploadComplete",e),o.info(`Done cleaning up chunks for ${e}`)},_t=()=>{h(async()=>{const e=await u.getChunkUploadsByStatus({sessionId:w,status:"ReadyForUpload"});if(!(e!=null&&e.length))return;const t=await Ie(e);o.info(`Finished uploading unfinished chunks for ${t}`),t!=null&&t.length&&await Promise.all(t.map(n=>{if(n)return ve(n)}))},"Error uploading unfinished chunks")},Lt=async(e,t)=>{await Ie(t),o.info(`Done uploading chunks for uploads: ${e.join(",")}`),await Promise.all(e.map(n=>ve(n)))},Mt=e=>{let t=0;e.forEach(a=>{t+=a.length});const n=new Uint8Array(t);let r=0;return e.forEach(a=>{n.set(a,r),r+=a.length}),n},re=async(e,t,n)=>{const r=new TextEncoder;let a=null,s=null,i=null,c=!1,l=!1,[d,p]=[0,0];const f=e-x*1e3,y=[];let g=[];o.info(`Getting events between ${new Date(e).toLocaleTimeString()} and ${new Date(t).toLocaleTimeString()}`),o.info(`Using batch duration: ${R}ms`);for(let E=f;E<t;E+=R){if({validStartFound:l,events:g}=await Ut(E,e,t,l,R),!(g!=null&&g.length)){o.info("No events found");continue}d===0&&(d=g[0].timestamp),p=g[g.length-1].timestamp,o.info(`Last event time in batch: ${new Date(p).toLocaleTimeString()}`);const z=g.map(ke=>ke.event);z.push(`{"timestamp":${t}}`);const Ce=`${c?",":"["}${z}`,J=r.encode(Ce);n&&s===null&&(o.debug("Attempting compression"),i=new window.CompressionStream("gzip"),s=i.writable.getWriter()),ye(()=>{n&&s?s.write(J):y.push(J)},"sdk_replay_compression_seconds"),c=!0}if(p-d<F)return o.info(`Replay duration is shorter than minimum of ${F}ms / Start:${d} / End:${p}`),null;const v=r.encode("]");return o.debug("Writing final close brace"),s&&i?(s.write(v),s.close(),a=new Uint8Array(await new Response(i.readable).arrayBuffer())):(y.push(v),a=Mt(y)),o.info("Finished generating file data"),a},Ot=async(e,t)=>{const n=window.CompressionStream!==void 0;let r=null;const a=t??Date.now(),s=a-e;try{r=await re(s,a,n)}catch(i){i instanceof Error&&window.UserLeap.reportError("Error compressing replay",i),n&&h(async()=>{await re(s,a,!1)},"fileData fallback failed")}return r},ae=async e=>{const{surveyId:t,responseGroupId:n,visitorId:r,apiUrl:a,completeUploadHeaders:s,replayParams:i,triggerTimestamp:c}=e,l=await Ot(i.replayDurationSeconds*1e3,c);if(l!=null&&l.length)o.info(`Found file data for survey: ${t}`);else{o.info(`File data is empty for survey: ${t}`);return}const d=Nt(l,i.minimumChunkSizeMb,i.signedUrls.length);o.info(`Got ${d.length} chunks for survey: ${t}`);const p=await Promise.all(d.map(async(f,y)=>{const g=o.v4(),v={apiUrl:a,chunkIndex:y+1,completeUploadHeaders:s,etag:null,responseGroupId:n,status:"ReadyForUpload",surveyId:t,timestamp:c,totalChunks:d.length,data:f,uploadId:i.uploadId,uploadUrl:i.signedUrls[y].url,uuid:g,visitorId:r};return o.info(`Recording chunk upload: ${JSON.stringify({index:v.chunkIndex,surveyId:v.surveyId,uploadId:v.uploadId,size:f.length,id:g},null,2)}`),await(await u.openDB()).add("chunkUploads",{...v,sessionId:v.sessionId??w}),o.info(`Done creating chunk upload: ${g}`),v}));o.info(`All chunk records created. Beginning upload for survey: ${t}`),await Lt([i.uploadId],p)},be=async(e,t)=>{if(o.info(`Attempting replay capture: ${JSON.stringify({isStandalone:e.isStandalone,duration:e.replayParams.replayDurationSeconds,type:e.replayParams.replayDurationType,responseGroupId:e.responseGroupId,surveyId:e.surveyId,triggerTimestamp:e.triggerTimestamp,visitorId:e.visitorId},null,2)}`),b())return o.info(`Replay recording is disabled: ${e.surveyId}`);o.info(`Replay recording enabled: ${e.surveyId}`);const{isHeatmap:n,isStandalone:r,replayParams:a,triggerTimestamp:s,responseGroupId:i}=e,c=async()=>{setTimeout(()=>o.eventEmitter.removeListener(o.SprigEvent.QuestionAnswered,c),0),h(async()=>{a.replayDurationType==="before"?await ae(e):await u.markPendingCaptureToCanUpload(i)},"Error in schedule/capture callback")};h(async()=>{if(a.replayDurationType==="after"||a.replayDurationType==="beforeAndAfter"){!r&&!n&&(o.info("Attaching QuestionAnswered listener for non-standalone replay"),o.eventEmitter.on(o.SprigEvent.QuestionAnswered,c)),o.info(`Scheduling capture for replay of type: ${a.replayDurationType}`),await De(e);return}if(r||n||t)o.info(`Proceeding to capture replay for survey: ${e.surveyId} / standalone? ${r} / canUpload? ${t}`),await ae(e),n&&Ht();else{const d=x+a.replayDurationSeconds,p=s-d*1e3,f=s;o.info(`Setting expiry minutes to ${a.expirationTimeLimitMinutes} for events from ${new Date(p).toLocaleTimeString()} to ${new Date(f).toLocaleTimeString()}`),await u.updateEventsExpiredAt(p,f,a.expirationTimeLimitMinutes),o.info("Attaching QuestionAnswered listener"),o.eventEmitter.on(o.SprigEvent.QuestionAnswered,c)}},"Error in scheduling/capturing replay")},Ht=async()=>{parseInt(C??"0")||o.sessionStorageHelper.removeItem("sprig.isCapturingHeatmap"),o.sessionStorageHelper.getItem("sprig.teardownAfterCapture")&&(ge(),Se(),o.sessionStorageHelper.removeItem("sprig.teardownAfterCapture"))},Se=async()=>b()?o.debug("Not clearing user data, replay is disabled"):Promise.all([u.deleteBySessionId("events",w),u.deleteBySessionId("pendingCaptures",w)]).catch(e=>{T("Error clearing user replay data",e)}),De=async e=>{if(b())return;o.info(`Scheduling replay capture: ${JSON.stringify(e)}`);const{isHeatmap:t,surveyId:n}=e,r=await u.getPendingCaptures(),a=r==null?void 0:r.filter(l=>l.captureParams.surveyId===n);if(a!=null&&a.length){o.info(`Pending capture exists for survey: ${n}`);return}t&&(St(),o.sessionStorageHelper.setItem("sprig.isCapturingHeatmap","true"),j=Date.now(),m.inactivityInterval||(m.inactivityInterval=window.setInterval(()=>{it(j)},1e3)));const s={...e,replayParams:{...e.replayParams}};e.replayParams.replayDurationType==="beforeAndAfter"&&(s.replayParams.replayDurationSeconds*=2),s.replayParams.replayDurationType="before";const i=e.triggerTimestamp+e.replayParams.replayDurationSeconds*1e3;s.triggerTimestamp=i,C=(parseInt(C??"0")+1).toString(),o.sessionStorageHelper.setItem("sprig.pendingCount",C),await(await u.openDB()).add("pendingCaptures",{canUpload:!1,captureParams:s,sessionId:w,targetTimestamp:i,timestamp:Date.now(),uuid:o.v4()})},Ft=Object.freeze(Object.defineProperty({__proto__:null,RecordEvent:dt,RecordPageView:ct,RecordSurveyShown:ut,_completeSessionReplay:Dt,checkPendingHeatmapsUrl:ot,clearUserReplayData:Se,disableRecording:T,initializeReplay:Pt,isReplayRecording:yt,scheduleCapture:De,scheduleOrCaptureReplay:be,tryReplayAction:h},Symbol.toStringTag,{value:"Module"}));o.registerReplay(Ft);
|
package/dist/replay.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var Oe=Object.defineProperty,je=(e,t,n)=>t in e?Oe(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,Y=(e,t,n)=>(je(e,typeof t!="symbol"?t+"":t,n),n);import{i,s as Z,a as m,v as P,c as He,e as ee,P as te,r as ne,w as ae,b as Fe,d as x,f as R,S as L,g as Ge}from"./metricsReporter-D-m62w_D.js";var $=(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))($||{});class We{constructor(t){Y(this,"awaitingResolvers",[]),Y(this,"activeCount",0),this.capacity=t}async acquire(){if(this.activeCount<this.capacity){this.activeCount++;return}return new Promise(t=>{this.awaitingResolvers.push(t)})}release(){const t=this.awaitingResolvers.shift();t&&this.activeCount<=this.capacity?t():this.activeCount--}async execute(t){try{return await this.acquire(),await t()}finally{this.release()}}setLimit(t){this.capacity=t}}const re=new We(2),Ke=e=>re.setLimit(e),Ve=async e=>re.execute(async()=>{var t;i(`Beginning upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const n=await Z(e.uploadUrl,{body:e.data,method:"PUT"});i(`Completed upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const a=(t=n.headers)==null?void 0:t.get("ETag");if(!a)throw new Error(`Upload response did not include etag for upload ${e.uploadId}, part ${e.chunkIndex}`);return a}),oe=async({apiUrl:e,surveyId:t,uploadId:n,etags:a,headers:r,responseGroupUuid:o,replayDuration:s,eventDigest:d},l=!1)=>{var u;if(!l&&!n&&!a){i(`Cannot mark upload complete: isMobile: ${l} / uploadId: ${n} / etags: ${a}`);return}i(`Marking upload complete for survey: ${t}`);const c=await Z(`${e}/sdk/1/completeSessionReplay`,{method:"POST",body:JSON.stringify({etags:a,uploadId:n,responseGroupUuid:o,surveyId:t,replayDuration:s,eventDigest:d,userAgent:(u=window?.navigator)==null?void 0:u.userAgent}),headers:r,shouldRetryRequest:!0});return i(`Done marking upload complete for survey: ${t}`),c},M=(e,t)=>t.some(n=>e instanceof n);let se,ie;function ze(){return se||(se=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function qe(){return ie||(ie=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const O=new WeakMap,j=new WeakMap,B=new WeakMap;function Je(e){const t=new Promise((n,a)=>{const r=()=>{n(D(e.result))},o=()=>{a(e.error)};e.onsuccess=r,e.onerror=o});return B.set(t,e),t}function Qe(e){if(O.has(e))return;const t=new Promise((n,a)=>{const r=()=>{n()},o=()=>{a(e.error||new DOMException("AbortError","AbortError"))};e.oncomplete=r,e.onerror=o,e.onabort=o});O.set(e,t)}let H={get(e,t,n){if(e instanceof IDBTransaction){if(t==="done")return O.get(e);if(t==="store")return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return D(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function le(e){H=e(H)}function Xe(e){return qe().includes(e)?function(...t){return e.apply(F(this),t),D(this.request)}:function(...t){return D(e.apply(F(this),t))}}function Ye(e){return typeof e=="function"?Xe(e):(e instanceof IDBTransaction&&Qe(e),M(e,ze())?new Proxy(e,H):e)}function D(e){if(e instanceof IDBRequest)return Je(e);if(j.has(e))return j.get(e);const t=Ye(e);return t!==e&&(j.set(e,t),B.set(t,e)),t}const F=e=>B.get(e);function Ze(e,t,{blocked:n,upgrade:a,blocking:r,terminated:o}={}){const s=indexedDB.open(e,t),d=D(s);return a&&(s.onupgradeneeded=l=>{a(D(s.result),l.oldVersion,l.newVersion,D(s.transaction),l)}),n&&(s.onblocked=l=>n(l.oldVersion,l.newVersion,l)),d.then(l=>{o&&(l.onclose=()=>o()),r&&(l.onversionchange=u=>r(u.oldVersion,u.newVersion,u))}).catch(()=>{}),d}function G(e,{blocked:t}={}){const n=indexedDB.deleteDatabase(e);return t&&(n.onblocked=a=>t(a.oldVersion,a)),D(n).then(()=>{})}const et=["get","getKey","getAll","getAllKeys","count"],tt=["put","add","delete","clear"],W=new Map;function de(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(W.get(t))return W.get(t);const n=t.replace(/FromIndex$/,""),a=t!==n,r=tt.includes(n);if(!(n in(a?IDBIndex:IDBObjectStore).prototype)||!(r||et.includes(n)))return;const o=async function(s,...d){const l=this.transaction(s,r?"readwrite":"readonly");let u=l.store;return a&&(u=u.index(d.shift())),(await Promise.all([u[n](...d),r&&l.done]))[0]};return W.set(t,o),o}le(e=>({...e,get:(t,n,a)=>de(t,n)||e.get(t,n,a),has:(t,n)=>!!de(t,n)||e.has(t,n)}));const nt=["continue","continuePrimaryKey","advance"],ue={},K=new WeakMap,ce=new WeakMap,at={get(e,t){if(!nt.includes(t))return e[t];let n=ue[t];return n||(n=ue[t]=function(...a){K.set(this,ce.get(this)[t](...a))}),n}};async function*rt(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;const n=new Proxy(t,at);for(ce.set(n,t),B.set(n,F(t));t;)yield n,t=await(K.get(n)||t.continue()),K.delete(n)}function pe(e,t){return t===Symbol.asyncIterator&&M(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&M(e,[IDBIndex,IDBObjectStore])}le(e=>({...e,get(t,n,a){return pe(t,n)?rt:e.get(t,n,a)},has(t,n){return pe(t,n)||e.has(t,n)}}));const ot=e=>{if(e instanceof Attr)return null;let t=1;for(let n=e.previousSibling;n;n=n.previousSibling)n.nodeName===e.nodeName&&++t;return t},ge=e=>{if(e===null)return"";const t=[];if(e instanceof Document)return"/";for(let n=e;n&&!(n instanceof Document)&&n!==null;n=n instanceof Attr?n.ownerElement:n.parentElement){const a=t[t.length]={name:void 0,position:null};switch(n.nodeType){case Node.TEXT_NODE:a.name="text()";break;case Node.ATTRIBUTE_NODE:a.name="@"+n.nodeName;break;case Node.PROCESSING_INSTRUCTION_NODE:a.name="processing-instruction()";break;case Node.COMMENT_NODE:a.name="comment()";break;case Node.ELEMENT_NODE:a.name=n.nodeName;break}a.position=ot(n)}return"/"+t.reverse().map(n=>n.position!==null?`/${n.name}[${n.position}]`:`/${n.name}`).join("")},S={capture:!0,passive:!0},st=["a","button","input","option","li","link"],it=["Escape","Enter","Backspace","F5","Tab"];let T=!1;const lt=["label","type","role","title","placeholder","errormessage","valuetext","href"],me="aria-",dt=e=>{if(!e.tagName)return"No tagName";const t=e.getAttribute("type");return t?`${t} ${e.tagName.toLowerCase()}`:e.tagName.toLowerCase()},ye=e=>{var t;if(((t=e.tagName)==null?void 0:t.toLowerCase())==="html")return{element:"html"};const n=e.textContent,a=n?{text:n}:{};a.element=dt(e);for(const r of e.attributes){let o=r.name;const s=r.value;o.startsWith(me)&&(o=o.substring(me.length)),lt.includes(o)&&(a[o]=s)}return a},ut=e=>{var t;if(!e)return{};const n={...ye(e)},a=e.parentElement;if(a&&st.includes((t=a.tagName)==null?void 0:t.toLowerCase())){const r=ye(a);Object.assign(n,r)}return n},we=(e,t)=>{var n;kt({x:t.x,y:t.y,type:e,elementAttributes:ut(t.target),windowHeight:window.innerHeight,windowWidth:window.innerWidth,...t.target instanceof HTMLElement?{rect:(n=t.target)==null?void 0:n.getBoundingClientRect(),xPath:ge(t.target)}:{}})},ct=e=>t=>we(e,t),fe=e=>{it.includes(e.key)&&$t({key:e.key})},pt=()=>{window.performance.getEntriesByType("navigation").map(e=>e.type).includes("reload")&&xt({url:window.location.href,currentPageTitle:document.title})},gt=()=>{window.performance.getEntriesByType("navigation").map(e=>e.type).includes("back_forward")&&Rt({curUrl:window.location.href,fromUrl:document.referrer,currentPageTitle:document.title})},mt=(e,t)=>{let n;return a=>{clearTimeout(n),n=window.setTimeout(()=>e(a),t)}},yt=e=>{if(!(e.target instanceof HTMLElement||e.target instanceof Document))return;let t=e.target;"scrollTop"in t||(t=t.documentElement),Bt({xPath:ge(t),x:t.scrollLeft,y:t.scrollTop,elementAttributes:{targetScrollWidth:t.scrollWidth,targetClientWidth:t.clientWidth,targetScrollHeight:t.scrollHeight,targetClientHeight:t.clientHeight}})},he=mt(yt,750),ve=ct("left_click"),Ie=e=>{e.button===2&&we("right_click",e)},wt=()=>{T||(window.addEventListener("click",ve,S),window.addEventListener("mousedown",Ie,S),window.addEventListener("keydown",fe,S),window.addEventListener("scroll",he,S),T=!0,pt(),gt())},ft=()=>{T&&(window.removeEventListener("click",ve,S),window.removeEventListener("mousedown",Ie,S),window.removeEventListener("keydown",fe,S),window.removeEventListener("scroll",he,S),T=!1)},ht=3e4;let C=0;const g={isRecording:!1,scrollEventUuids:{},stopRecording:()=>{}},vt=()=>{const e=m.getItem("sprig.sessionId");if(e)return i(`Found saved session id: ${e}`),m.removeItem("sprig.sessionId"),e;const t=P();return i(`Generating new uuid: ${t}`),t},w=vt(),It=async e=>{var t;if((t=window.navigator.storage)!=null&&t.estimate){const{quota:n=0,usage:a=0}=await window.navigator.storage.estimate();return(n-a)/1024**3>=e}return!0},be=()=>{m.setItem("sprig.disableReplayRecording","disabled")},E=()=>!!m.getItem("sprig.disableReplayRecording");window.addEventListener("beforeunload",()=>{i(`Before page unload saving session id: ${w}`),m.setItem("sprig.sessionId",w)});const bt=async()=>{const e=(await p.getPendingCaptures({isHeatmap:!0})).map(n=>({eventId:n.captureParams.eventId,uuid:n.uuid})),t=[];e.forEach(({eventId:n,uuid:a})=>{He(n)||t.push(a)}),t.length&&v(()=>p.markPendingHeatmapsReady(t),"Error marking pending heatmaps ready")},Dt=e=>{if(e>1){C=0;return}const t=Date.now();if(!C){C=t;return}t-C>=ht&&(C=0,v(()=>p.markPendingHeatmapsReady(),"Error marking pending heatmaps ready"))},V=e=>e&&e.trim().substring(0,500).replace(/\s\s+/g," ").replace(/\r?\n|\r/g," ").substring(0,250),I=(e,t)=>{var n,a;if(g.isRecording)try{(a=(n=window.rrwebRecord)==null?void 0:n.addCustomEvent)==null||a.call(n,e,t)}catch(r){U("Error recording custom event",r)}},St=e=>{e.description&&(e.description=V(e.description)),I("Sprig_PageView",e)},kt=e=>{var t;(t=e?.elementAttributes)!=null&&t.text&&(e.elementAttributes.text=V(e.elementAttributes.text)),I("Sprig_Click",e)},Et=e=>{I("Sprig_TrackEvent",e)},Ct=e=>{I("Sprig_ShowSurvey",e)},Pt=e=>{I("Sprig_SubmitSurvey",e)},xt=e=>{I("Sprig_Refresh",e)},Rt=e=>{e.currentPageTitle&&(e.currentPageTitle=V(e.currentPageTitle)),I("Sprig_BackForward",e)},$t=e=>{I("Sprig_Keystroke",e)},Bt=async e=>{const{x:t,xPath:n,y:a}=e,r=g.scrollEventUuids[n];if(r)return v(async()=>{var o,s,d,l;const u=await p.openDB(),c=await u.get("events",r);if(c!=null&&c.event){const y=JSON.parse(c.event),h=t>((s=(o=y.data)==null?void 0:o.payload)==null?void 0:s.x),f=a>((l=(d=y.data)==null?void 0:d.payload)==null?void 0:l.y);if(!(h||f))return null;h&&(y.data.payload.x=t),f&&(y.data.payload.y=a),y.data.payload.elementAttributes=e.elementAttributes,c.event=JSON.stringify(y),await u.put("events",c)}else I("Sprig_Scroll",e)},"Error updating scroll event");I("Sprig_Scroll",e)},Tt=()=>g.isRecording,De=()=>{g.stopRecording&&(g.stopRecording(),g.stopRecording=void 0),g.isRecording=!1,["cleanupInterval","noopInterval","pendingCheckInterval"].forEach(e=>{g[e]&&(clearInterval(g[e]),g[e]=void 0)}),ft()},Ut=["did not allow mutations","called in an invalid security context"],At=e=>{if(!e)return!0;for(const t of Ut)if(e.toLowerCase().includes(t))return!1;return!0},Nt=(e,t,{reportError:n=!0,extraInfo:a})=>{E()||t instanceof Error&&(be(),At(t?.message)&&(n&&window.UserLeap.reportError(e,t,a),p.clearAll()))},_t=async(e,t,{reportError:n}={reportError:!0})=>{var a;let r;try{if(n&&(a=window.navigator.storage)!=null&&a.estimate){const{quota:o=0,usage:s=0}=await window.navigator.storage.estimate();r={availableSpaceInMB:(o-s)/2**20,quota:o,usage:s}}}catch(o){window.UserLeap.reportError("Error getting storage estimate",o,{originalMessage:e,originalError:t})}Nt(e,t,{reportError:n,extraInfo:r})},U=(e,t,{reportError:n}={reportError:!0})=>(De(),ee(`${e} - ${JSON.stringify(t)}`),_t(e,t,{reportError:n})),v=async(e,t)=>{try{await e()}catch(n){U(t,n)}},Lt=()=>{g.isRecording&&v(()=>{var e,t;return(t=(e=window.rrwebRecord)==null?void 0:e.takeFullSnapshot)==null?void 0:t.call(e,!0)},"Error recording full snapshot")},Mt=async({surveyId:e,responseGroupUuid:t,eventDigest:n,headers:a})=>{if(!e||!t)return!1;const r=window.UserLeap._API_URL,o=await oe({surveyId:e,responseGroupUuid:t,eventDigest:n,apiUrl:r,headers:a},!0);return!(o!=null&&o.error)},Se=30,Ot=1;G("replayStorage").catch(console.error),G("sprig.replay").catch(console.error);class jt{openDB(){return Ze("sprigReplay",Ot,{upgrade:(t,n,a)=>{if(a===0&&m.setItem("sprig.pendingCount","0"),!t.objectStoreNames.contains("events")){const r=t.createObjectStore("events",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+timestamp]",["sessionId","timestamp"])}if(!t.objectStoreNames.contains("chunkUploads")){const r=t.createObjectStore("chunkUploads",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+status]",["sessionId","status"]),r.createIndex("[uploadId+status]",["uploadId","status"]),r.createIndex("[sessionId+status+uploadId]",["sessionId","status","uploadId"])}if(!t.objectStoreNames.contains("pendingCaptures")){const r=t.createObjectStore("pendingCaptures",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+targetTimestamp]",["sessionId","targetTimestamp"])}}})}constructor(){this.openDB().catch(t=>{ee(`Error opening replay storage: ${t.message}`),be(),t.name==="VersionError"&&G("sprigReplay").catch(console.error)})}async bulkAdd(t,n){const a=(await this.openDB()).transaction(t,"readwrite");return Promise.all([...n.map(r=>a.store.add(r)),a.done])}async clearAll(){const t=(await this.openDB()).transaction(["events","chunkUploads","pendingCaptures"],"readwrite");return Promise.all([t.objectStore("events").clear(),t.objectStore("chunkUploads").clear(),t.objectStore("pendingCaptures").clear()])}async deleteBySessionId(t,n){const a=IDBKeyRange.only(n),r=(await this.openDB()).transaction(t,"readwrite");let o=await r.store.index("sessionId").openCursor(a);for(;o;)o.delete(),o=await o.continue();await r.done}async updatePartial(t,n,a){const r=(await this.openDB()).transaction(t,"readwrite"),o=await r.store.get(n);o&&await r.store.put({...o,...a}),await r.done}async deleteRowsBefore(t,n,a=()=>!0){const r=IDBKeyRange.upperBound(n,!0),o=(await this.openDB()).transaction(t,"readwrite");let s=await o.store.index("timestamp").openCursor(r);for(;s;)a(s.value)&&s.delete(),s=await s.continue();await o.done}async getEventsBetween(t,n=Date.now()){if(t>=n)return Promise.resolve([]);const a=IDBKeyRange.bound([w,t],[w,n],!1,!0);return(await this.openDB()).getAllFromIndex("events","[sessionId+timestamp]",a)}async updateEventsExpiredAt(t,n,a=Se){const r=new Date,o=r.setMinutes(r.getMinutes()+(a??Se)),s=(await this.openDB()).transaction("events","readwrite"),d=s.store.index("[sessionId+timestamp]"),l=IDBKeyRange.bound([w,t],[w,n],!1,!0);let u=await d.openCursor(l);for(;u;)u.update({...u.value,expiredAt:o}),u=await u.continue();await s.done}async deleteChunkUploads(t,n){const a=IDBKeyRange.only([n,t]),r=(await this.openDB()).transaction("chunkUploads","readwrite");let o=await r.store.index("[uploadId+status]").openCursor(a);for(;o;)o.delete(),o=await o.continue();await r.done}async getChunkUploadsByStatus({sessionId:t,status:n,uploadId:a}){const r=(await this.openDB()).transaction("chunkUploads","readonly"),o=a?r.store.index("[uploadId+status]"):r.store.index("[sessionId+status]"),s=a?IDBKeyRange.only([a,n]):IDBKeyRange.only([t,n]);return o.getAll(s)}async getPendingCaptures(t={}){return(await(await this.openDB()).getAllFromIndex("pendingCaptures","sessionId",w)).filter(n=>!t.beforePresent||n.targetTimestamp<Date.now()).filter(n=>!t.isHeatmap||(n.captureParams.isHeatmap??!1))}async markPendingCaptureToCanUpload(t){const n=(await this.openDB()).transaction("pendingCaptures","readwrite");let a=await n.store.index("sessionId").openCursor(w);for(;a;){const r=a.value;r.captureParams.responseGroupId===t&&a.update({...r,canUpload:!0}),a=await a.continue()}await n.done}async markPendingHeatmapsReady(t){if(parseInt(m.getItem("sprig.pendingCount")??"0")===0)return null;const n=Date.now(),a=(await this.openDB()).transaction("pendingCaptures","readwrite");let r=await a.store.index("sessionId").openCursor(w);for(;r;){const o=r.value;o.captureParams.isHeatmap&&(!t||t.includes(o.uuid))&&r.update({...o,targetTimestamp:n,captureParams:{...o.captureParams,triggerTimestamp:n,replayParams:{...o.captureParams.replayParams,replayDurationSeconds:Math.floor((n-o.timestamp)/1e3)}}}),r=await r.continue()}await a.done}}const p=new jt,Ht=async(e,t,n)=>new Promise((a,r)=>{const o=e.createElement("script");o.src=t,o.onload=a,o.onerror=r,n&&(o.nonce=n),e.head.appendChild(o)}),ke=async(e,t)=>{const n=performance.now();let a;try{a=await e()}finally{const r=performance.now()-n;let o=te[t];o||(o=ne(t)),o.report(r/1e3)}return a},Ee=(e,t)=>{const n=performance.now();try{e()}finally{const a=performance.now()-n;let r=te[t];r||(r=ne(t)),r.report(a/1e3)}};let Ce=1,z=5e3,A=6e4;const Pe=1e3,Ft=5,xe=30,N=xe+Ft;let Re=Date.now(),k,q=!!m.getItem("sprig.isCapturingHeatmap"),J=!1,Q=[];const Gt=async({viewDocument:e,maxReplayDurationSeconds:t,replayNonce:n,maxInflightRequests:a=2,replaySettings:r,teardownAfter:o=!1})=>{k=m.getItem("sprig.pendingCount"),!g.isRecording&&(o&&m.setItem("sprig.teardownAfterCapture","true"),await v(async()=>{if(E()){i("Not initializing replay because recording is disabled");return}if(!t){i("Not initializing replay because config didn't specify maxReplayDurationSeconds");return}if(r!=null&&r.minAvailableGb&&(Ce=r.minAvailableGb),!await It(Ce)){ae("Minimum storage not available");return}if(i("Initializing replay"),r!=null&&r.minDuration&&(z=r.minDuration),r!=null&&r.batchDuration&&(A=r.batchDuration),Ke(a),Xt(),zt(t+N,30*60,t+N),qt(),!window.rrwebRecord){i("Loading recording script");const u=window.UserLeap.replayLibraryURL??"https://cdn.sprig.com/dependencies/record-2.0.0-alpha.6.min.js";await Ht(e,u,n),i("Recording script finished loading")}const s=window.rrwebRecord;if(!s){ae("Record script failed to set global function");return}let d=!0,l=0;g.stopRecording=s({checkoutEveryNms:xe*1e3,sampling:{input:"last",scroll:250,media:800},emit:(u,c)=>{if(E())return;if(Re=Date.now(),c&&u.type===$.Meta)l=performance.now();else if(c&&l&&u.type===$.FullSnapshot){const h=performance.now()-l;Fe("sdk_replay_snapshot_seconds",h/1e3)}const y=d||!!c&&u.type===$.Meta;d=!1,Wt({uuid:P(),event:JSON.stringify(u),isValidStart:y,timestamp:Date.now()})},...r}),g.isRecording=!!g.stopRecording,g.isRecording&&(g.noopInterval||(g.noopInterval=window.setInterval(()=>{Date.now()-Re>Pe&&I("Sprig_Noop",{})},Pe)),x.on("survey.complete",u=>{Pt({id:u,userAgent:window.navigator.userAgent})}),wt())},"Error initializing replay"))},Wt=e=>{var t,n,a,r;if((t=e.event)!=null&&t.includes("Sprig_Scroll")){const o=(r=(a=(n=JSON.parse(e.event))==null?void 0:n.data)==null?void 0:a.payload)==null?void 0:r.xPath;if(!o)return;g.scrollEventUuids[o]=e.uuid}Q.push(e),J||Vt()},Kt=async e=>{const t=e.map(n=>({...n,sessionId:n.sessionId??w}));if(q&&Dt(t.length),t.length!==0)return v(()=>p.bulkAdd("events",t),"Error storing replay events")},Vt=()=>{J=!0,setTimeout(async()=>{if(E())return;const e=Q;Q=[],J=!1,Ee(async()=>{await Kt(e)},"sdk_replay_add_event_batch_seconds")},500)},zt=(e,t,n)=>{g.cleanupInterval=window.setInterval(()=>{const a=Date.now();E()||(R(`Performing periodic replay data cleanup / Event Seconds ${e} / Chunk Seconds ${t} / Pending Capture Seconds ${n}`),ke(()=>v(async()=>{await Promise.all([p.deleteRowsBefore("events",a-e*1e3,r=>r.expiredAt===void 0||r.expiredAt<a-e*1e3),p.deleteRowsBefore("chunkUploads",a-t*1e3),p.deleteRowsBefore("pendingCaptures",a-n*1e3,r=>!r.canUpload)])},"Error deleting table rows"),"sdk_replay_cleanup_seconds"),i("Cleanup complete"))},3e4)},qt=()=>{g.pendingCheckInterval=window.setInterval(async()=>{v(async()=>{const e=parseInt(k??"0");if(e===0)return;const t=await p.getPendingCaptures({beforePresent:!0}),n=await p.openDB();await Promise.all(t.map(async a=>(await n.delete("pendingCaptures",a.uuid),Ae(a.captureParams,a.canUpload)))),k=(e-t.length).toString(),m.setItem("sprig.pendingCount",k)},"Error initiating pending captures")},5e3)},Jt=async(e,t,n,a,r)=>{const o=Math.min(e+r,n),s=`from: ${new Date(e).toLocaleTimeString()} to ${new Date(o).toLocaleTimeString()}`;i(`Getting event batch ${s}`);const d=await ke(()=>p.getEventsBetween(e,o),"sdk_replay_get_events_between_seconds");if(!(d!=null&&d.length))return i(`No events found ${s}`),{validStartFound:a,events:[]};if(!a){i(`Searching for valid start in ${d.length} events ${s}`);let l=-1;if(d?.forEach((c,y)=>{if(!c.isValidStart)return;const h=c.timestamp<=t;(l<0||h)&&(l=y)}),l<0)return i(`No valid start found in ${d.length} events ${s}`),{validStartFound:a,events:[]};const u=d[l].timestamp;return i(`Found valid start at: ${new Date(u).toLocaleTimeString()} in events ${s}`),{validStartFound:!0,events:d?.slice(l)}}return{validStartFound:a,events:d}},Qt=(e,t,n)=>{const a=e.length,r=t*1024*1024,o=Math.ceil(a/n),s=Math.max(r,o);i(`Total file bytes: ${a} / target chunk size: ${s}`);const d=[];let l=0;for(;l<a;)d.push(e.slice(l,l+s)),l+=s;return d},$e=e=>Promise.all(e.map(async t=>{const n=await Ve(t);return await p.updatePartial("chunkUploads",t.uuid,{data:null,etag:n,status:"UploadComplete"}),t.uploadId})),Be=async e=>{i(`Marking upload complete if finished: ${e}`);const t=await p.getChunkUploadsByStatus({status:"UploadComplete",uploadId:e});if(!(t!=null&&t.length)){i(`No finished chunks found for upload: ${e}`);return}const n=t.reduce((o,s)=>(o.find(d=>d.chunkIndex===s.chunkIndex)||o.push(s),o),[]);n.sort((o,s)=>o.chunkIndex-s.chunkIndex);const a=n.map(o=>({ETag:o.etag,PartNumber:o.chunkIndex})).filter(o=>o.ETag!==null),r=n[0];await oe({apiUrl:r.apiUrl,surveyId:r.surveyId,uploadId:e,responseGroupUuid:r.responseGroupId,etags:a,headers:r.completeUploadHeaders,replayDuration:r.replayDuration}),i(`Cleaning up chunks for ${e}`),await p.deleteChunkUploads("UploadComplete",e),i(`Done cleaning up chunks for ${e}`)},Xt=async()=>{v(async()=>{const e=await p.getChunkUploadsByStatus({sessionId:w,status:"ReadyForUpload"});if(!(e!=null&&e.length))return;const t=await $e(e);i(`Finished uploading unfinished chunks for ${t}`),t!=null&&t.length&&await Promise.all(t.map(n=>{if(n)return Be(n)}))},"Error uploading unfinished chunks")},Yt=async(e,t)=>{await $e(t),i(`Done uploading chunks for uploads: ${e.join(",")}`),await Promise.all(e.map(n=>Be(n)))},Zt=e=>{let t=0;e.forEach(r=>{t+=r.length});const n=new Uint8Array(t);let a=0;return e.forEach(r=>{n.set(r,a),a+=r.length}),n},Te=async(e,t,n)=>{const a=new TextEncoder;let r=null,o=null,s=null,d=!1,l=!1,[u,c]=[0,0];const y=e-N*1e3,h=[];let f=[];i(`Getting events between ${new Date(e).toLocaleTimeString()} and ${new Date(t).toLocaleTimeString()}`),i(`Using batch duration: ${A}ms`);for(let _=y;_<t;_+=A){if({validStartFound:l,events:f}=await Jt(_,e,t,l,A),!(f!=null&&f.length)){i("No events found");continue}u===0&&(u=f[0].timestamp),c=f[f.length-1].timestamp,i(`Last event time in batch: ${new Date(c).toLocaleTimeString()}`);const Le=`${d?",":"["}${f.map(Me=>Me.event).join(",")}`,X=a.encode(Le);n&&o===null&&(R("Attempting compression"),s=new window.CompressionStream("gzip"),o=s.writable.getWriter()),Ee(()=>{n&&o?o.write(X):h.push(X)},"sdk_replay_compression_seconds"),d=!0}if(c-u<z)return i(`Replay duration is shorter than minimum of ${z}ms / Start:${u} / End:${c}`),null;const b=a.encode("]");return R("Writing final close brace"),o&&s?(o.write(b),o.close(),r=new Uint8Array(await new Response(s.readable).arrayBuffer())):(h.push(b),r=Zt(h)),i("Finished generating file data"),r},en=async(e,t)=>{const n=window.CompressionStream!==void 0;let a=null;const r=t??Date.now(),o=r-e;try{a=await Te(o,r,n)}catch(s){s instanceof Error&&window.UserLeap.reportError("Error compressing replay",s),n&&v(async()=>{await Te(o,r,!1)},"fileData fallback failed")}return a},Ue=async e=>{const{surveyId:t,responseGroupId:n,visitorId:a,apiUrl:r,completeUploadHeaders:o,replayParams:s,triggerTimestamp:d}=e,l=await en(s.replayDurationSeconds*1e3,d);if(l!=null&&l.length)i(`Found file data for survey: ${t}`);else{i(`File data is empty for survey: ${t}`);return}const u=Qt(l,s.minimumChunkSizeMb,s.signedUrls.length);i(`Got ${u.length} chunks for survey: ${t}`);const c=await Promise.all(u.map(async(y,h)=>{const f=P(),b={apiUrl:r,chunkIndex:h+1,completeUploadHeaders:o,etag:null,responseGroupId:n,status:"ReadyForUpload",surveyId:t,timestamp:d,totalChunks:u.length,data:y,uploadId:s.uploadId,uploadUrl:s.signedUrls[h].url,uuid:f,visitorId:a};return i(`Recording chunk upload: ${JSON.stringify({index:b.chunkIndex,surveyId:b.surveyId,uploadId:b.uploadId,size:y.length,id:f},null,2)}`),await(await p.openDB()).add("chunkUploads",{...b,sessionId:b.sessionId??w}),i(`Done creating chunk upload: ${f}`),b}));i(`All chunk records created. Beginning upload for survey: ${t}`),await Yt([s.uploadId],c)},Ae=async(e,t)=>{if(i(`Attempting replay capture: ${JSON.stringify({isStandalone:e.isStandalone,duration:e.replayParams.replayDurationSeconds,type:e.replayParams.replayDurationType,responseGroupId:e.responseGroupId,surveyId:e.surveyId,triggerTimestamp:e.triggerTimestamp,visitorId:e.visitorId},null,2)}`),E())return i(`Replay recording is disabled: ${e.surveyId}`);i(`Replay recording enabled: ${e.surveyId}`);const{isHeatmap:n,isStandalone:a,replayParams:r,triggerTimestamp:o,responseGroupId:s}=e,d=async()=>{setTimeout(()=>x.removeListener(L.QuestionAnswered,d),0),v(async()=>{r.replayDurationType==="before"?await Ue(e):await p.markPendingCaptureToCanUpload(s)},"Error in schedule/capture callback")};v(async()=>{if(r.replayDurationType==="after"||r.replayDurationType==="beforeAndAfter"){!a&&!n&&(i("Attaching QuestionAnswered listener for non-standalone replay"),x.on(L.QuestionAnswered,d)),i(`Scheduling capture for replay of type: ${r.replayDurationType}`),await _e(e);return}if(a||n||t)i(`Proceeding to capture replay for survey: ${e.surveyId} / standalone? ${a} / canUpload? ${t}`),await Ue(e),n&&tn();else{const l=N+r.replayDurationSeconds,u=o-l*1e3,c=o;i(`Setting expiry minutes to ${r.expirationTimeLimitMinutes} for events from ${new Date(u).toLocaleTimeString()} to ${new Date(c).toLocaleTimeString()}`),await p.updateEventsExpiredAt(u,c,r.expirationTimeLimitMinutes),i("Attaching QuestionAnswered listener"),x.on(L.QuestionAnswered,d)}},"Error in scheduling/capturing replay")},tn=async()=>{parseInt(k??"0")||(m.removeItem("sprig.isCapturingHeatmap"),q=!1),m.getItem("sprig.teardownAfterCapture")&&(De(),Ne(),m.removeItem("sprig.teardownAfterCapture"))},Ne=()=>{if(E()){R("Not clearing user data, replay is disabled");return}return Promise.all([p.deleteBySessionId("events",w),p.deleteBySessionId("pendingCaptures",w)]).catch(e=>{U("Error clearing user replay data",e)})},_e=async e=>{i(`Scheduling replay capture: ${JSON.stringify(e)}`);const{isHeatmap:t,surveyId:n}=e,a=await p.getPendingCaptures(),r=a?.filter(d=>d.captureParams.surveyId===n);if(r!=null&&r.length){i(`Pending capture exists for survey: ${n}`);return}t&&(Lt(),q=!0,m.setItem("sprig.isCapturingHeatmap","true"));const o={...e,replayParams:{...e.replayParams}};e.replayParams.replayDurationType==="beforeAndAfter"&&(o.replayParams.replayDurationSeconds*=2),o.replayParams.replayDurationType="before";const s=e.triggerTimestamp+e.replayParams.replayDurationSeconds*1e3;o.triggerTimestamp=s,k=(parseInt(k??"0")+1).toString(),m.setItem("sprig.pendingCount",k),await(await p.openDB()).add("pendingCaptures",{canUpload:!1,captureParams:o,sessionId:w,targetTimestamp:s,timestamp:Date.now(),uuid:P()})},nn=Object.freeze(Object.defineProperty({__proto__:null,RecordEvent:Et,RecordPageView:St,RecordSurveyShown:Ct,_completeSessionReplay:Mt,checkPendingHeatmapsUrl:bt,clearUserReplayData:Ne,disableRecording:U,initializeReplay:Gt,isReplayRecording:Tt,scheduleCapture:_e,scheduleOrCaptureReplay:Ae,tryReplayAction:v},Symbol.toStringTag,{value:"Module"}));Ge(nn);
|
|
1
|
+
var _e=Object.defineProperty,Le=(e,t,n)=>t in e?_e(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,ee=(e,t,n)=>(Le(e,typeof t!="symbol"?t+"":t,n),n);import{i,s as te,a as y,v as P,e as _,w as ne,c as Me,P as ae,r as re,b as Oe,d as x,f as B,S as L,g as He}from"./metricsReporter-5CQW74cF.js";var E=(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))(E||{});class je{constructor(t){ee(this,"awaitingResolvers",[]),ee(this,"activeCount",0),this.capacity=t}async acquire(){if(this.activeCount<this.capacity){this.activeCount++;return}return new Promise(t=>{this.awaitingResolvers.push(t)})}release(){const t=this.awaitingResolvers.shift();t&&this.activeCount<=this.capacity?t():this.activeCount--}async execute(t){try{return await this.acquire(),await t()}finally{this.release()}}setLimit(t){this.capacity=t}}const oe=new je(2),Fe=e=>oe.setLimit(e),Ge=async e=>oe.execute(async()=>{var t;i(`Beginning upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const n=await te(e.uploadUrl,{body:e.data,method:"PUT"});i(`Completed upload of chunk ${e.chunkIndex} for survey: ${e.surveyId}`);const a=(t=n.headers)==null?void 0:t.get("ETag");if(!a)throw new Error(`Upload response did not include etag for upload ${e.uploadId}, part ${e.chunkIndex}`);return a}),se=async({apiUrl:e,surveyId:t,uploadId:n,etags:a,headers:r,responseGroupUuid:o,replayDuration:s,eventDigest:d},l=!1)=>{var u;if(!l&&!n&&!a){i(`Cannot mark upload complete: isMobile: ${l} / uploadId: ${n} / etags: ${a}`);return}i(`Marking upload complete for survey: ${t}`);const p=await te(`${e}/sdk/1/completeSessionReplay`,{method:"POST",body:JSON.stringify({etags:a,uploadId:n,responseGroupUuid:o,surveyId:t,replayDuration:s,eventDigest:d,userAgent:(u=window?.navigator)==null?void 0:u.userAgent}),headers:r,shouldRetryRequest:!0});return i(`Done marking upload complete for survey: ${t}`),p},M=(e,t)=>t.some(n=>e instanceof n);let ie,le;function We(){return ie||(ie=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function Ke(){return le||(le=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const O=new WeakMap,H=new WeakMap,R=new WeakMap;function Ve(e){const t=new Promise((n,a)=>{const r=()=>{n(b(e.result))},o=()=>{a(e.error)};e.onsuccess=r,e.onerror=o});return R.set(t,e),t}function qe(e){if(O.has(e))return;const t=new Promise((n,a)=>{const r=()=>{n()},o=()=>{a(e.error||new DOMException("AbortError","AbortError"))};e.oncomplete=r,e.onerror=o,e.onabort=o});O.set(e,t)}let j={get(e,t,n){if(e instanceof IDBTransaction){if(t==="done")return O.get(e);if(t==="store")return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return b(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function de(e){j=e(j)}function Je(e){return Ke().includes(e)?function(...t){return e.apply(F(this),t),b(this.request)}:function(...t){return b(e.apply(F(this),t))}}function ze(e){return typeof e=="function"?Je(e):(e instanceof IDBTransaction&&qe(e),M(e,We())?new Proxy(e,j):e)}function b(e){if(e instanceof IDBRequest)return Ve(e);if(H.has(e))return H.get(e);const t=ze(e);return t!==e&&(H.set(e,t),R.set(t,e)),t}const F=e=>R.get(e);function Qe(e,t,{blocked:n,upgrade:a,blocking:r,terminated:o}={}){const s=indexedDB.open(e,t),d=b(s);return a&&(s.onupgradeneeded=l=>{a(b(s.result),l.oldVersion,l.newVersion,b(s.transaction),l)}),n&&(s.onblocked=l=>n(l.oldVersion,l.newVersion,l)),d.then(l=>{o&&(l.onclose=()=>o()),r&&(l.onversionchange=u=>r(u.oldVersion,u.newVersion,u))}).catch(()=>{}),d}function G(e,{blocked:t}={}){const n=indexedDB.deleteDatabase(e);return t&&(n.onblocked=a=>t(a.oldVersion,a)),b(n).then(()=>{})}const Xe=["get","getKey","getAll","getAllKeys","count"],Ye=["put","add","delete","clear"],W=new Map;function ue(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(W.get(t))return W.get(t);const n=t.replace(/FromIndex$/,""),a=t!==n,r=Ye.includes(n);if(!(n in(a?IDBIndex:IDBObjectStore).prototype)||!(r||Xe.includes(n)))return;const o=async function(s,...d){const l=this.transaction(s,r?"readwrite":"readonly");let u=l.store;return a&&(u=u.index(d.shift())),(await Promise.all([u[n](...d),r&&l.done]))[0]};return W.set(t,o),o}de(e=>({...e,get:(t,n,a)=>ue(t,n)||e.get(t,n,a),has:(t,n)=>!!ue(t,n)||e.has(t,n)}));const Ze=["continue","continuePrimaryKey","advance"],ce={},K=new WeakMap,pe=new WeakMap,et={get(e,t){if(!Ze.includes(t))return e[t];let n=ce[t];return n||(n=ce[t]=function(...a){K.set(this,pe.get(this)[t](...a))}),n}};async function*tt(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;const n=new Proxy(t,et);for(pe.set(n,t),R.set(n,F(t));t;)yield n,t=await(K.get(n)||t.continue()),K.delete(n)}function ge(e,t){return t===Symbol.asyncIterator&&M(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&M(e,[IDBIndex,IDBObjectStore])}de(e=>({...e,get(t,n,a){return ge(t,n)?tt:e.get(t,n,a)},has(t,n){return ge(t,n)||e.has(t,n)}}));const nt=e=>{if(e instanceof Attr)return null;let t=1;for(let n=e.previousSibling;n;n=n.previousSibling)n.nodeName===e.nodeName&&++t;return t},me=e=>{if(e===null)return"";const t=[];if(e instanceof Document)return"/";for(let n=e;n&&!(n instanceof Document)&&n!==null;n=n instanceof Attr?n.ownerElement:n.parentElement){const a=t[t.length]={name:void 0,position:null};switch(n.nodeType){case Node.TEXT_NODE:a.name="text()";break;case Node.ATTRIBUTE_NODE:a.name="@"+n.nodeName;break;case Node.PROCESSING_INSTRUCTION_NODE:a.name="processing-instruction()";break;case Node.COMMENT_NODE:a.name="comment()";break;case Node.ELEMENT_NODE:a.name=n.nodeName;break}a.position=nt(n)}return"/"+t.reverse().map(n=>n.position!==null?`/${n.name}[${n.position}]`:`/${n.name}`).join("")},k={capture:!0,passive:!0},at=["a","button","input","option","li","link"],rt=["Escape","Enter","Backspace","F5","Tab"];let $=!1;const ot=["label","type","role","title","placeholder","errormessage","valuetext","href"],ye="aria-",st=e=>{if(!e.tagName)return"No tagName";const t=e.getAttribute("type");return t?`${t} ${e.tagName.toLowerCase()}`:e.tagName.toLowerCase()},we=e=>{var t;if(((t=e.tagName)==null?void 0:t.toLowerCase())==="html")return{element:"html"};const n=e.textContent,a=n?{text:n}:{};a.element=st(e);for(const r of e.attributes){let o=r.name;const s=r.value;o.startsWith(ye)&&(o=o.substring(ye.length)),ot.includes(o)&&(a[o]=s)}return a},it=e=>{var t;if(!e)return{};const n={...we(e)},a=e.parentElement;if(a&&at.includes((t=a.tagName)==null?void 0:t.toLowerCase())){const r=we(a);Object.assign(n,r)}return n},fe=(e,t)=>{var n;St({x:t.x,y:t.y,type:e,elementAttributes:it(t.target),windowHeight:window.innerHeight,windowWidth:window.innerWidth,...t.target instanceof HTMLElement?{rect:(n=t.target)==null?void 0:n.getBoundingClientRect(),xPath:me(t.target)}:{}})},lt=e=>t=>fe(e,t),he=e=>{rt.includes(e.key)&&xt({key:e.key})},dt=()=>{window.performance.getEntriesByType("navigation").map(e=>e.type).includes("reload")&&Et({url:window.location.href,currentPageTitle:document.title})},ut=()=>{window.performance.getEntriesByType("navigation").map(e=>e.type).includes("back_forward")&&Pt({curUrl:window.location.href,fromUrl:document.referrer,currentPageTitle:document.title})},ct=(e,t)=>{let n;return a=>{clearTimeout(n),n=window.setTimeout(()=>e(a),t)}},pt=e=>{if(!(e.target instanceof HTMLElement||e.target instanceof Document))return;let t=e.target;"scrollTop"in t||(t=t.documentElement),Bt({xPath:me(t),x:t.scrollLeft,y:t.scrollTop,elementAttributes:{targetScrollWidth:t.scrollWidth,targetClientWidth:t.clientWidth,targetScrollHeight:t.scrollHeight,targetClientHeight:t.clientHeight}})},ve=ct(pt,750),Ie=lt("left_click"),De=e=>{e.button===2&&fe("right_click",e)},gt=()=>{$||(window.addEventListener("click",Ie,k),window.addEventListener("mousedown",De,k),window.addEventListener("keydown",he,k),window.addEventListener("scroll",ve,k),$=!0,dt(),ut())},mt=()=>{$&&(window.removeEventListener("click",Ie,k),window.removeEventListener("mousedown",De,k),window.removeEventListener("keydown",he,k),window.removeEventListener("scroll",ve,k),$=!1)},yt=3e4,g={isRecording:!1,scrollEventUuids:{},stopRecording:()=>{}},wt=.5,ft=async()=>{var e;if(!window.indexedDB||!window.IDBKeyRange)return!0;if((e=window.navigator.storage)!=null&&e.estimate)try{const{quota:t=0,usage:n=0}=await window.navigator.storage.estimate(),a=(t-n)/1024**3;return ne(`Storage: ${a}GB`),a<wt}catch{return!0}return!1},ht=()=>{const e=y.getItem("sprig.sessionId");if(e)return i(`Found saved session id: ${e}`),y.removeItem("sprig.sessionId"),e;const t=P();return i(`Generating new uuid: ${t}`),t},w=ht(),V=()=>{y.setItem("sprig.disableReplayRecording","disabled")},S=()=>!!y.getItem("sprig.disableReplayRecording");window.addEventListener("beforeunload",()=>{i(`Before page unload saving session id: ${w}`),y.setItem("sprig.sessionId",w)});const vt=()=>S()?i("ReolayDisabledPendingHeatmap"):v(async()=>{const e=(await c.getPendingCaptures({isHeatmap:!0})).map(n=>({eventId:n.captureParams.eventId,uuid:n.uuid})),t=[];e.forEach(({eventId:n,uuid:a})=>{Me(n)||t.push(a)}),t.length&&await c.markPendingHeatmapsReady(t)},"Error marking pending heatmaps ready"),It=e=>{Date.now()-e>=yt&&v(()=>c.markPendingHeatmapsReady(),"Error in heatmap inactivity")},q=e=>e&&e.trim().substring(0,500).replace(/\s\s+/g," ").replace(/\r?\n|\r/g," ").substring(0,250),I=(e,t)=>{var n,a;if(g.isRecording)try{(a=(n=window.rrwebRecord)==null?void 0:n.addCustomEvent)==null||a.call(n,e,t)}catch(r){T("Error recording custom event",r)}},Dt=e=>{e.description&&(e.description=q(e.description)),I("Sprig_PageView",e)},St=e=>{var t;(t=e?.elementAttributes)!=null&&t.text&&(e.elementAttributes.text=q(e.elementAttributes.text)),I("Sprig_Click",e)},bt=e=>{I("Sprig_TrackEvent",e)},kt=e=>{I("Sprig_ShowSurvey",e)},Ct=e=>{I("Sprig_SubmitSurvey",e)},Et=e=>{I("Sprig_Refresh",e)},Pt=e=>{e.currentPageTitle&&(e.currentPageTitle=q(e.currentPageTitle)),I("Sprig_BackForward",e)},xt=e=>{I("Sprig_Keystroke",e)},Bt=async e=>{const{x:t,xPath:n,y:a}=e,r=g.scrollEventUuids[n];if(r)return v(async()=>{var o,s,d,l;const u=await c.openDB(),p=await u.get("events",r);if(p!=null&&p.event){const m=JSON.parse(p.event),h=t>((s=(o=m.data)==null?void 0:o.payload)==null?void 0:s.x),f=a>((l=(d=m.data)==null?void 0:d.payload)==null?void 0:l.y);if(!(h||f))return null;h&&(m.data.payload.x=t),f&&(m.data.payload.y=a),m.data.payload.elementAttributes=e.elementAttributes,p.event=JSON.stringify(m),await u.put("events",p)}else I("Sprig_Scroll",e)},"Error updating scroll event");I("Sprig_Scroll",e)},Rt=()=>g.isRecording,Se=()=>{g.stopRecording&&(g.stopRecording(),g.stopRecording=void 0),g.isRecording=!1,["cleanupInterval","inactivityInterval","pendingCheckInterval"].forEach(e=>{g[e]&&(clearInterval(g[e]),g[e]=void 0)}),mt()},$t=["did not allow mutations","called in an invalid security context"],Tt=e=>{if(!e)return!0;for(const t of $t)if(e.toLowerCase().includes(t))return!1;return!0},Ut=(e,t,{reportError:n=!0,extraInfo:a})=>{S()||t instanceof Error&&(V(),Tt(t?.message)&&(n&&window.UserLeap.reportError(e,t,a),c.clearAll()))},At=async(e,t,{reportError:n}={reportError:!0})=>{let a={};try{const{quota:r=0,usage:o=0}=await window.navigator.storage.estimate();a={availableSpaceInMB:(r-o)/2**20,quota:r,usage:o}}catch{a.availableSpaceInMB=null}Ut(e,t,{reportError:n,extraInfo:a})},T=(e,t,{reportError:n}={reportError:!0})=>(Se(),_(`${e} - ${t.message} - ${t.name}`),At(e,t,{reportError:n})),v=async(e,t)=>{try{await e()}catch(n){T(t,n)}},Nt=()=>{g.isRecording&&v(()=>{var e,t;return(t=(e=window.rrwebRecord)==null?void 0:e.takeFullSnapshot)==null?void 0:t.call(e,!0)},"Error recording full snapshot")},_t=async({surveyId:e,responseGroupUuid:t,eventDigest:n,headers:a})=>{if(!e||!t)return!1;const r=window.UserLeap._API_URL,o=await se({surveyId:e,responseGroupUuid:t,eventDigest:n,apiUrl:r,headers:a},!0);return!(o!=null&&o.error)},be=30,Lt=1;G("replayStorage").catch(console.error),G("sprig.replay").catch(console.error);class Mt{openDB(){return Qe("sprigReplay",Lt,{upgrade:(t,n,a)=>{if(a===0&&y.setItem("sprig.pendingCount","0"),!t.objectStoreNames.contains("events")){const r=t.createObjectStore("events",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+timestamp]",["sessionId","timestamp"])}if(!t.objectStoreNames.contains("chunkUploads")){const r=t.createObjectStore("chunkUploads",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+status]",["sessionId","status"]),r.createIndex("[uploadId+status]",["uploadId","status"]),r.createIndex("[sessionId+status+uploadId]",["sessionId","status","uploadId"])}if(!t.objectStoreNames.contains("pendingCaptures")){const r=t.createObjectStore("pendingCaptures",{keyPath:"uuid"});r.createIndex("sessionId","sessionId"),r.createIndex("timestamp","timestamp"),r.createIndex("[sessionId+targetTimestamp]",["sessionId","targetTimestamp"])}}})}deleteDB(){return G("sprigReplay").catch(console.error)}async bulkAdd(t,n){const a=(await this.openDB()).transaction(t,"readwrite");return Promise.all([...n.map(r=>a.store.add(r)),a.done])}async clearAll(){const t=(await this.openDB()).transaction(["events","chunkUploads","pendingCaptures"],"readwrite");return Promise.all([t.objectStore("events").clear(),t.objectStore("chunkUploads").clear(),t.objectStore("pendingCaptures").clear()])}async deleteBySessionId(t,n){const a=IDBKeyRange.only(n),r=(await this.openDB()).transaction(t,"readwrite");let o=await r.store.index("sessionId").openCursor(a);for(;o;)o.delete(),o=await o.continue();await r.done}async updatePartial(t,n,a){const r=(await this.openDB()).transaction(t,"readwrite"),o=await r.store.get(n);o&&await r.store.put({...o,...a}),await r.done}async deleteRowsBefore(t,n,a=()=>!0){const r=IDBKeyRange.upperBound(n,!0),o=(await this.openDB()).transaction(t,"readwrite");let s=await o.store.index("timestamp").openCursor(r);for(;s;)a(s.value)&&s.delete(),s=await s.continue();await o.done}async getEventsBetween(t,n=Date.now()){if(t>=n)return Promise.resolve([]);const a=IDBKeyRange.bound([w,t],[w,n],!1,!0);return(await this.openDB()).getAllFromIndex("events","[sessionId+timestamp]",a)}async updateEventsExpiredAt(t,n,a=be){const r=new Date,o=r.setMinutes(r.getMinutes()+(a??be)),s=(await this.openDB()).transaction("events","readwrite"),d=s.store.index("[sessionId+timestamp]"),l=IDBKeyRange.bound([w,t],[w,n],!1,!0);let u=await d.openCursor(l);for(;u;)u.update({...u.value,expiredAt:o}),u=await u.continue();await s.done}async deleteChunkUploads(t,n){const a=IDBKeyRange.only([n,t]),r=(await this.openDB()).transaction("chunkUploads","readwrite");let o=await r.store.index("[uploadId+status]").openCursor(a);for(;o;)o.delete(),o=await o.continue();await r.done}async getChunkUploadsByStatus({sessionId:t,status:n,uploadId:a}){const r=(await this.openDB()).transaction("chunkUploads","readonly"),o=a?r.store.index("[uploadId+status]"):r.store.index("[sessionId+status]"),s=a?IDBKeyRange.only([a,n]):IDBKeyRange.only([t,n]);return o.getAll(s)}async getPendingCaptures(t={}){return(await(await this.openDB()).getAllFromIndex("pendingCaptures","sessionId",w)).filter(n=>!t.beforePresent||n.targetTimestamp<Date.now()).filter(n=>!t.isHeatmap||(n.captureParams.isHeatmap??!1))}async markPendingCaptureToCanUpload(t){const n=(await this.openDB()).transaction("pendingCaptures","readwrite");let a=await n.store.index("sessionId").openCursor(w);for(;a;){const r=a.value;r.captureParams.responseGroupId===t&&a.update({...r,canUpload:!0}),a=await a.continue()}await n.done}async markPendingHeatmapsReady(t){if(parseInt(y.getItem("sprig.pendingCount")??"0")===0)return null;const n=Date.now(),a=(await this.openDB()).transaction("pendingCaptures","readwrite");let r=await a.store.index("sessionId").openCursor(w);for(;r;){const o=r.value;o.captureParams.isHeatmap&&(!t||t.includes(o.uuid))&&r.update({...o,targetTimestamp:n,captureParams:{...o.captureParams,triggerTimestamp:n,replayParams:{...o.captureParams.replayParams,replayDurationSeconds:Math.floor((n-o.timestamp)/1e3)}}}),r=await r.continue()}await a.done}}const c=new Mt,Ot=async(e,t,n)=>new Promise((a,r)=>{const o=e.createElement("script");o.src=t,o.onload=a,o.onerror=r,n&&(o.nonce=n),e.head.appendChild(o)}),ke=async(e,t)=>{const n=performance.now();let a;try{a=await e()}finally{const r=performance.now()-n;let o=ae[t];o||(o=re(t)),o.report(r/1e3)}return a},Ce=(e,t)=>{const n=performance.now();try{e()}finally{const a=performance.now()-n;let r=ae[t];r||(r=re(t)),r.report(a/1e3)}};let J=5e3,U=6e4,z=0;const Ht=5,Ee=30,A=Ee+Ht;let C,Q=!1,X=[];const jt=async({viewDocument:e,maxReplayDurationSeconds:t,replayNonce:n,maxInflightRequests:a=2,replaySettings:r,teardownAfter:o=!1})=>{if(C=y.getItem("sprig.pendingCount"),!g.isRecording){if(o&&y.setItem("sprig.teardownAfterCapture","true"),S())return i("ReplayDisabled");if(await ft())return _("IDBNotSupported"),V();try{await c.openDB()}catch(s){return _(`ReplayError-${s.message}-${s.name}`),s.name==="VersionError"&&c.deleteDB(),V()}if(!t)return i("MissingReplaySeconds");i("ReplayInit"),await v(async()=>{if(r!=null&&r.minDuration&&(J=r.minDuration),r!=null&&r.batchDuration&&(U=r.batchDuration),Fe(a),zt(),Kt(t+A,30*60,t+A),Vt(),!window.rrwebRecord){const u=window.UserLeap.replayLibraryURL??"https://cdn.sprig.com/dependencies/record-2.0.0-alpha.6.min.js";await Ot(e,u,n)}const s=window.rrwebRecord;if(!s)return ne("RecordScriptFailed");let d=!0,l=0;g.stopRecording=s({checkoutEveryNms:Ee*1e3,sampling:{input:"last",scroll:250,media:800},emit:(u,p)=>{if(u.type===E.Custom&&(z=Date.now()),S())return;if(p&&u.type===E.Meta)l=performance.now();else if(p&&l&&u.type===E.FullSnapshot){const h=performance.now()-l;Oe("sdk_replay_snapshot_seconds",h/1e3)}const m=d||!!p&&u.type===E.Meta;d=!1,Ft({uuid:P(),event:JSON.stringify(u),isValidStart:m,timestamp:Date.now()})},...r}),g.isRecording=!!g.stopRecording,g.isRecording&&(x.on("survey.complete",u=>{Ct({id:u,userAgent:window.navigator.userAgent})}),gt())},"Error initializing replay")}},Ft=e=>{var t,n,a,r;if((t=e.event)!=null&&t.includes("Sprig_Scroll")){const o=(r=(a=(n=JSON.parse(e.event))==null?void 0:n.data)==null?void 0:a.payload)==null?void 0:r.xPath;if(!o)return;g.scrollEventUuids[o]=e.uuid}X.push(e),Q||Wt()},Gt=async e=>{const t=e.map(n=>({...n,sessionId:n.sessionId??w}));if(t.length!==0)return v(()=>c.bulkAdd("events",t),"Error storing replay events")},Wt=()=>{Q=!0,setTimeout(async()=>{if(S())return;const e=X;X=[],Q=!1,Ce(async()=>{await Gt(e)},"sdk_replay_add_event_batch_seconds")},500)},Kt=(e,t,n)=>{g.cleanupInterval=window.setInterval(()=>{const a=Date.now();S()||(B(`CleanUp Secs - Events: ${e}, Chunks: ${t}, Captures: ${n}`),ke(()=>v(async()=>{await Promise.all([c.deleteRowsBefore("events",a-e*1e3,r=>r.expiredAt===void 0||r.expiredAt<a-e*1e3),c.deleteRowsBefore("chunkUploads",a-t*1e3),c.deleteRowsBefore("pendingCaptures",a-n*1e3,r=>!r.canUpload)])},"Error deleting table rows"),"sdk_replay_cleanup_seconds"),i("Cleanup complete"))},3e4)},Vt=()=>{g.pendingCheckInterval=window.setInterval(async()=>{v(async()=>{const e=parseInt(C??"0");if(e===0)return;const t=await c.getPendingCaptures({beforePresent:!0}),n=await c.openDB();await Promise.all(t.map(async a=>(await n.delete("pendingCaptures",a.uuid),$e(a.captureParams,a.canUpload)))),C=(e-t.length).toString(),y.setItem("sprig.pendingCount",C)},"Error initiating pending captures")},5e3)},qt=async(e,t,n,a,r)=>{const o=Math.min(e+r,n),s=`from: ${new Date(e).toLocaleTimeString()} to ${new Date(o).toLocaleTimeString()}`;i(`Getting event batch ${s}`);const d=await ke(()=>c.getEventsBetween(e,o),"sdk_replay_get_events_between_seconds");if(!(d!=null&&d.length))return i(`No events found ${s}`),{validStartFound:a,events:[]};if(!a){i(`Searching for valid start in ${d.length} events ${s}`);let l=-1;if(d?.forEach((p,m)=>{if(!p.isValidStart)return;const h=p.timestamp<=t;(l<0||h)&&(l=m)}),l<0)return i(`No valid start found in ${d.length} events ${s}`),{validStartFound:a,events:[]};const u=d[l].timestamp;return i(`Found valid start at: ${new Date(u).toLocaleTimeString()} in events ${s}`),{validStartFound:!0,events:d?.slice(l)}}return{validStartFound:a,events:d}},Jt=(e,t,n)=>{const a=e.length,r=t*1024*1024,o=Math.ceil(a/n),s=Math.max(r,o);i(`Total file bytes: ${a} / target chunk size: ${s}`);const d=[];let l=0;for(;l<a;)d.push(e.slice(l,l+s)),l+=s;return d},Pe=e=>Promise.all(e.map(async t=>{const n=await Ge(t);return await c.updatePartial("chunkUploads",t.uuid,{data:null,etag:n,status:"UploadComplete"}),t.uploadId})),xe=async e=>{i(`Marking upload complete if finished: ${e}`);const t=await c.getChunkUploadsByStatus({status:"UploadComplete",uploadId:e});if(!(t!=null&&t.length)){i(`No finished chunks found for upload: ${e}`);return}const n=t.reduce((o,s)=>(o.find(d=>d.chunkIndex===s.chunkIndex)||o.push(s),o),[]);n.sort((o,s)=>o.chunkIndex-s.chunkIndex);const a=n.map(o=>({ETag:o.etag,PartNumber:o.chunkIndex})).filter(o=>o.ETag!==null),r=n[0];await se({apiUrl:r.apiUrl,surveyId:r.surveyId,uploadId:e,responseGroupUuid:r.responseGroupId,etags:a,headers:r.completeUploadHeaders,replayDuration:r.replayDuration}),i(`Cleaning up chunks for ${e}`),await c.deleteChunkUploads("UploadComplete",e),i(`Done cleaning up chunks for ${e}`)},zt=()=>{v(async()=>{const e=await c.getChunkUploadsByStatus({sessionId:w,status:"ReadyForUpload"});if(!(e!=null&&e.length))return;const t=await Pe(e);i(`Finished uploading unfinished chunks for ${t}`),t!=null&&t.length&&await Promise.all(t.map(n=>{if(n)return xe(n)}))},"Error uploading unfinished chunks")},Qt=async(e,t)=>{await Pe(t),i(`Done uploading chunks for uploads: ${e.join(",")}`),await Promise.all(e.map(n=>xe(n)))},Xt=e=>{let t=0;e.forEach(r=>{t+=r.length});const n=new Uint8Array(t);let a=0;return e.forEach(r=>{n.set(r,a),a+=r.length}),n},Be=async(e,t,n)=>{const a=new TextEncoder;let r=null,o=null,s=null,d=!1,l=!1,[u,p]=[0,0];const m=e-A*1e3,h=[];let f=[];i(`Getting events between ${new Date(e).toLocaleTimeString()} and ${new Date(t).toLocaleTimeString()}`),i(`Using batch duration: ${U}ms`);for(let N=m;N<t;N+=U){if({validStartFound:l,events:f}=await qt(N,e,t,l,U),!(f!=null&&f.length)){i("No events found");continue}u===0&&(u=f[0].timestamp),p=f[f.length-1].timestamp,i(`Last event time in batch: ${new Date(p).toLocaleTimeString()}`);const Y=f.map(Ne=>Ne.event);Y.push(`{"timestamp":${t}}`);const Ae=`${d?",":"["}${Y}`,Z=a.encode(Ae);n&&o===null&&(B("Attempting compression"),s=new window.CompressionStream("gzip"),o=s.writable.getWriter()),Ce(()=>{n&&o?o.write(Z):h.push(Z)},"sdk_replay_compression_seconds"),d=!0}if(p-u<J)return i(`Replay duration is shorter than minimum of ${J}ms / Start:${u} / End:${p}`),null;const D=a.encode("]");return B("Writing final close brace"),o&&s?(o.write(D),o.close(),r=new Uint8Array(await new Response(s.readable).arrayBuffer())):(h.push(D),r=Xt(h)),i("Finished generating file data"),r},Yt=async(e,t)=>{const n=window.CompressionStream!==void 0;let a=null;const r=t??Date.now(),o=r-e;try{a=await Be(o,r,n)}catch(s){s instanceof Error&&window.UserLeap.reportError("Error compressing replay",s),n&&v(async()=>{await Be(o,r,!1)},"fileData fallback failed")}return a},Re=async e=>{const{surveyId:t,responseGroupId:n,visitorId:a,apiUrl:r,completeUploadHeaders:o,replayParams:s,triggerTimestamp:d}=e,l=await Yt(s.replayDurationSeconds*1e3,d);if(l!=null&&l.length)i(`Found file data for survey: ${t}`);else{i(`File data is empty for survey: ${t}`);return}const u=Jt(l,s.minimumChunkSizeMb,s.signedUrls.length);i(`Got ${u.length} chunks for survey: ${t}`);const p=await Promise.all(u.map(async(m,h)=>{const f=P(),D={apiUrl:r,chunkIndex:h+1,completeUploadHeaders:o,etag:null,responseGroupId:n,status:"ReadyForUpload",surveyId:t,timestamp:d,totalChunks:u.length,data:m,uploadId:s.uploadId,uploadUrl:s.signedUrls[h].url,uuid:f,visitorId:a};return i(`Recording chunk upload: ${JSON.stringify({index:D.chunkIndex,surveyId:D.surveyId,uploadId:D.uploadId,size:m.length,id:f},null,2)}`),await(await c.openDB()).add("chunkUploads",{...D,sessionId:D.sessionId??w}),i(`Done creating chunk upload: ${f}`),D}));i(`All chunk records created. Beginning upload for survey: ${t}`),await Qt([s.uploadId],p)},$e=async(e,t)=>{if(i(`Attempting replay capture: ${JSON.stringify({isStandalone:e.isStandalone,duration:e.replayParams.replayDurationSeconds,type:e.replayParams.replayDurationType,responseGroupId:e.responseGroupId,surveyId:e.surveyId,triggerTimestamp:e.triggerTimestamp,visitorId:e.visitorId},null,2)}`),S())return i(`Replay recording is disabled: ${e.surveyId}`);i(`Replay recording enabled: ${e.surveyId}`);const{isHeatmap:n,isStandalone:a,replayParams:r,triggerTimestamp:o,responseGroupId:s}=e,d=async()=>{setTimeout(()=>x.removeListener(L.QuestionAnswered,d),0),v(async()=>{r.replayDurationType==="before"?await Re(e):await c.markPendingCaptureToCanUpload(s)},"Error in schedule/capture callback")};v(async()=>{if(r.replayDurationType==="after"||r.replayDurationType==="beforeAndAfter"){!a&&!n&&(i("Attaching QuestionAnswered listener for non-standalone replay"),x.on(L.QuestionAnswered,d)),i(`Scheduling capture for replay of type: ${r.replayDurationType}`),await Ue(e);return}if(a||n||t)i(`Proceeding to capture replay for survey: ${e.surveyId} / standalone? ${a} / canUpload? ${t}`),await Re(e),n&&Zt();else{const l=A+r.replayDurationSeconds,u=o-l*1e3,p=o;i(`Setting expiry minutes to ${r.expirationTimeLimitMinutes} for events from ${new Date(u).toLocaleTimeString()} to ${new Date(p).toLocaleTimeString()}`),await c.updateEventsExpiredAt(u,p,r.expirationTimeLimitMinutes),i("Attaching QuestionAnswered listener"),x.on(L.QuestionAnswered,d)}},"Error in scheduling/capturing replay")},Zt=async()=>{parseInt(C??"0")||y.removeItem("sprig.isCapturingHeatmap"),y.getItem("sprig.teardownAfterCapture")&&(Se(),Te(),y.removeItem("sprig.teardownAfterCapture"))},Te=async()=>S()?B("Not clearing user data, replay is disabled"):Promise.all([c.deleteBySessionId("events",w),c.deleteBySessionId("pendingCaptures",w)]).catch(e=>{T("Error clearing user replay data",e)}),Ue=async e=>{if(S())return;i(`Scheduling replay capture: ${JSON.stringify(e)}`);const{isHeatmap:t,surveyId:n}=e,a=await c.getPendingCaptures(),r=a?.filter(d=>d.captureParams.surveyId===n);if(r!=null&&r.length){i(`Pending capture exists for survey: ${n}`);return}t&&(Nt(),y.setItem("sprig.isCapturingHeatmap","true"),z=Date.now(),g.inactivityInterval||(g.inactivityInterval=window.setInterval(()=>{It(z)},1e3)));const o={...e,replayParams:{...e.replayParams}};e.replayParams.replayDurationType==="beforeAndAfter"&&(o.replayParams.replayDurationSeconds*=2),o.replayParams.replayDurationType="before";const s=e.triggerTimestamp+e.replayParams.replayDurationSeconds*1e3;o.triggerTimestamp=s,C=(parseInt(C??"0")+1).toString(),y.setItem("sprig.pendingCount",C),await(await c.openDB()).add("pendingCaptures",{canUpload:!1,captureParams:o,sessionId:w,targetTimestamp:s,timestamp:Date.now(),uuid:P()})},en=Object.freeze(Object.defineProperty({__proto__:null,RecordEvent:bt,RecordPageView:Dt,RecordSurveyShown:kt,_completeSessionReplay:_t,checkPendingHeatmapsUrl:vt,clearUserReplayData:Te,disableRecording:T,initializeReplay:jt,isReplayRecording:Rt,scheduleCapture:Ue,scheduleOrCaptureReplay:$e,tryReplayAction:v},Symbol.toStringTag,{value:"Module"}));He(en);
|