diff --git a/browser/dist/esm/chunk-5LBAMSSV.js b/browser/dist/esm/chunk-OBW4BMTC.js similarity index 100% rename from browser/dist/esm/chunk-5LBAMSSV.js rename to browser/dist/esm/chunk-OBW4BMTC.js diff --git a/browser/dist/esm/feedbackReplay-6PAAGWVV.js b/browser/dist/esm/feedbackReplay-4NH5EQNJ.js similarity index 95% rename from browser/dist/esm/feedbackReplay-6PAAGWVV.js rename to browser/dist/esm/feedbackReplay-4NH5EQNJ.js index c0238f2..1057058 100644 --- a/browser/dist/esm/feedbackReplay-6PAAGWVV.js +++ b/browser/dist/esm/feedbackReplay-4NH5EQNJ.js @@ -1 +1 @@ -import{a as m,b,e as k}from"./chunk-5LBAMSSV.js";import{a as p,c as y,d as v,e as R,f as w,g}from"./chunk-UVRZCAHX.js";import{b as l,e as u}from"./chunk-QBI2JL2F.js";var t,i=!1,o=!1,r=0,d=Promise.resolve(),a;function c(){r++;let e=d,s=t?.stop({flush:!1}).catch(()=>{})??Promise.resolve();d=Promise.all([e,s]).then(()=>{})}async function f(){let e=r;await d,await Promise.resolve(),e===r&&o&&!i&&u(window.location)&&(w(document.documentElement),t?.startBuffering())}function x(){o=!0,!(t||!m())&&(g(),t=k({stickySession:!1,minReplayDuration:0,maskAllText:!l(),maskAllInputs:!l(),blockAllMedia:!l(),mask:[p],maskFn:y,maskAttributes:R,block:["script","iframe","canvas","video, audio, object, embed",p,v,'[style*="url("]',"[data-feedback-ui]"],networkCaptureBodies:!1,networkDetailAllowUrls:[],beforeAddRecordingEvent:()=>null}),b(t),window.addEventListener("popstate",c,{capture:!0}),window.addEventListener("hashchange",()=>{c(),f()}),f())}function I(){if(a)return a;i=!0;let e=t,s=e?.getReplayId(),h=r;if(!o||!e||!s||!u(window.location))return Promise.resolve(void 0);let n=(async()=>{try{return await e.flush({continueRecording:!1}),h===r&&o?s:void 0}catch{return}finally{await e.stop({flush:!1})}})();return a=n,d=n.then(()=>{}),n.finally(()=>{a===n&&(a=void 0)}),n}function E(){i=!1,c(),f()}function z(e){o=e,e?(i=!1,t?f():x()):(i=!0,c())}export{I as freezeFeedbackReplay,x as initializeFeedbackReplay,E as restartFeedbackReplay,f as resumeFeedbackReplay,z as setFeedbackReplayEnabled,c as stopFeedbackReplay}; +import{a as m,b,e as k}from"./chunk-OBW4BMTC.js";import{a as p,c as y,d as v,e as R,f as w,g}from"./chunk-UVRZCAHX.js";import{b as l,e as u}from"./chunk-QBI2JL2F.js";var t,i=!1,o=!1,r=0,d=Promise.resolve(),a;function c(){r++;let e=d,s=t?.stop({flush:!1}).catch(()=>{})??Promise.resolve();d=Promise.all([e,s]).then(()=>{})}async function f(){let e=r;await d,await Promise.resolve(),e===r&&o&&!i&&u(window.location)&&(w(document.documentElement),t?.startBuffering())}function x(){o=!0,!(t||!m())&&(g(),t=k({stickySession:!1,minReplayDuration:0,maskAllText:!l(),maskAllInputs:!l(),blockAllMedia:!l(),mask:[p],maskFn:y,maskAttributes:R,block:["script","iframe","canvas","video, audio, object, embed",p,v,'[style*="url("]',"[data-feedback-ui]"],networkCaptureBodies:!1,networkDetailAllowUrls:[],beforeAddRecordingEvent:()=>null}),b(t),window.addEventListener("popstate",c,{capture:!0}),window.addEventListener("hashchange",()=>{c(),f()}),f())}function I(){if(a)return a;i=!0;let e=t,s=e?.getReplayId(),h=r;if(!o||!e||!s||!u(window.location))return Promise.resolve(void 0);let n=(async()=>{try{return await e.flush({continueRecording:!1}),h===r&&o?s:void 0}catch{return}finally{await e.stop({flush:!1})}})();return a=n,d=n.then(()=>{}),n.finally(()=>{a===n&&(a=void 0)}),n}function E(){i=!1,c(),f()}function z(e){o=e,e?(i=!1,t?f():x()):(i=!0,c())}export{I as freezeFeedbackReplay,x as initializeFeedbackReplay,E as restartFeedbackReplay,f as resumeFeedbackReplay,z as setFeedbackReplayEnabled,c as stopFeedbackReplay}; diff --git a/browser/dist/esm/feedbackScreenshot-XN3R2P73.js b/browser/dist/esm/feedbackScreenshot-ZYNYCEWM.js similarity index 97% rename from browser/dist/esm/feedbackScreenshot-XN3R2P73.js rename to browser/dist/esm/feedbackScreenshot-ZYNYCEWM.js index fb41179..7e8a30c 100644 --- a/browser/dist/esm/feedbackScreenshot-XN3R2P73.js +++ b/browser/dist/esm/feedbackScreenshot-ZYNYCEWM.js @@ -1,2 +1,2 @@ import{a as u,b as y,d}from"./chunk-UVRZCAHX.js";import{b as f,c as b,d as m}from"./chunk-QBI2JL2F.js";function g(t){return Array.from(t.styleSheets).flatMap(n=>{if(!n.href)return[];let r=new URL(n.href,t.baseURI);if(r.origin!==new URL(t.baseURI).origin||!b(r)||r.search||r.hash)return[];try{return[Array.from(n.cssRules,o=>o.cssText).join(` -`)]}catch{return[]}})}function w(t,n){if(t.querySelectorAll(`script, iframe, canvas, video, audio, object, embed, ${u}, ${d}, [data-feedback-ui]`).forEach(e=>{e.style.visibility="hidden"}),n){t.body.style.visibility="hidden";return}let r=new Set(Array.from(t.querySelectorAll(u)).flatMap(e=>[e,...e.querySelectorAll("*")]));t.querySelectorAll(d).forEach(e=>e.removeAttribute("src"));let o=t.createTreeWalker(t.body,NodeFilter.SHOW_TEXT);for(;o.nextNode();)o.currentNode.textContent=y(o.currentNode.textContent??"",o.currentNode.parentElement);t.querySelectorAll("body, body *").forEach(e=>{let a=!f()||r.has(e),c=e,l=c.value,h=c.checked,p=e.selectedIndex;e.style.setProperty("background-image","none","important");for(let i of[...e.attributes])/^data-v-[0-9a-f]{8}$/.test(i.name)&&!i.value||(/^(?:data-|href$|srcset$|action$|formaction$|value$)/i.test(i.name)?e.removeAttribute(i.name):/^(?:title|alt|aria-label|aria-description|placeholder)$/.test(i.name)&&e.setAttribute(i.name,a?i.value.replace(/\S/g,"*"):i.value));(e.tagName==="INPUT"||e.tagName==="TEXTAREA")&&(e.value=a?"":l),e.tagName==="INPUT"&&(e.checked=a?!1:h),e.tagName==="SELECT"&&(e.selectedIndex=a?-1:p)});let s=t.createElement("style");s.textContent="*::before, *::after { content: none !important; background-image: none !important; }",t.head.append(s)}async function T(){if(m(window.location))return;let{default:t}=await import("./html2canvas-pro.esm-REK7NNFK.js"),n=window.innerWidth,r=window.innerHeight,o=g(document),s=await t(document.body,{width:n,height:r,x:window.scrollX,y:window.scrollY,scale:Math.min(1,Math.sqrt(15e5/(n*r))),backgroundColor:"#f4f8fb",logging:!1,allowTaint:!1,useCORS:!1,imageTimeout:3e3,ignoreElements:a=>a.hasAttribute("data-feedback-ui"),onclone:async a=>{for(let c of o){let l=a.createElement("style");l.textContent=c,a.head.append(l)}w(a,!1),a.body.getBoundingClientRect(),await a.fonts?.ready}}),e=await new Promise(a=>s.toBlob(a,"image/png"));if(!(!e||e.size>2e6))return{data:new Uint8Array(await e.arrayBuffer()),previewUrl:URL.createObjectURL(e)}}export{T as captureFeedbackScreenshot,g as compiledScreenshotStyles,w as sanitizeScreenshotDocument}; +`)]}catch{return[]}})}function w(t,n){if(t.querySelectorAll(`script, iframe, canvas, video, audio, object, embed, ${u}, ${d}, [data-feedback-ui]`).forEach(e=>{e.style.visibility="hidden"}),n){t.body.style.visibility="hidden";return}let r=new Set(Array.from(t.querySelectorAll(u)).flatMap(e=>[e,...e.querySelectorAll("*")]));t.querySelectorAll(d).forEach(e=>e.removeAttribute("src"));let o=t.createTreeWalker(t.body,NodeFilter.SHOW_TEXT);for(;o.nextNode();)o.currentNode.textContent=y(o.currentNode.textContent??"",o.currentNode.parentElement);t.querySelectorAll("body, body *").forEach(e=>{let a=!f()||r.has(e),c=e,l=c.value,h=c.checked,p=e.selectedIndex;e.style.setProperty("background-image","none","important");for(let i of[...e.attributes])/^data-v-[0-9a-f]{8}$/.test(i.name)&&!i.value||(/^(?:data-|href$|srcset$|action$|formaction$|value$)/i.test(i.name)?e.removeAttribute(i.name):/^(?:title|alt|aria-label|aria-description|placeholder)$/.test(i.name)&&e.setAttribute(i.name,a?i.value.replace(/\S/g,"*"):i.value));(e.tagName==="INPUT"||e.tagName==="TEXTAREA")&&(e.value=a?"":l),e.tagName==="INPUT"&&(e.checked=a?!1:h),e.tagName==="SELECT"&&(e.selectedIndex=a?-1:p)});let s=t.createElement("style");s.textContent="*::before, *::after { content: none !important; background-image: none !important; }",t.head.append(s)}async function T(){if(m(window.location))return;let{default:t}=await import("./html2canvas-pro.esm-BIHLXW6X.js"),n=window.innerWidth,r=window.innerHeight,o=g(document),s=await t(document.body,{width:n,height:r,x:window.scrollX,y:window.scrollY,scale:Math.min(1,Math.sqrt(15e5/(n*r))),backgroundColor:"#f4f8fb",logging:!1,allowTaint:!1,useCORS:!1,imageTimeout:3e3,ignoreElements:a=>a.hasAttribute("data-feedback-ui"),onclone:async a=>{for(let c of o){let l=a.createElement("style");l.textContent=c,a.head.append(l)}w(a,!1),a.body.getBoundingClientRect(),await a.fonts?.ready}}),e=await new Promise(a=>s.toBlob(a,"image/png"));if(!(!e||e.size>2e6))return{data:new Uint8Array(await e.arrayBuffer()),previewUrl:URL.createObjectURL(e)}}export{T as captureFeedbackScreenshot,g as compiledScreenshotStyles,w as sanitizeScreenshotDocument}; diff --git a/browser/dist/esm/html2canvas-pro.esm-REK7NNFK.js b/browser/dist/esm/html2canvas-pro.esm-BIHLXW6X.js similarity index 100% rename from browser/dist/esm/html2canvas-pro.esm-REK7NNFK.js rename to browser/dist/esm/html2canvas-pro.esm-BIHLXW6X.js diff --git a/browser/dist/esm/index.js b/browser/dist/esm/index.js index f39ec15..a53ebfd 100644 --- a/browser/dist/esm/index.js +++ b/browser/dist/esm/index.js @@ -1,3 +1,3 @@ -import{a as v,c as D,d as q,f as V,g as Y}from"./chunk-5LBAMSSV.js";import{a as I,d as j,f as J}from"./chunk-QBI2JL2F.js";var K=new WeakSet;function C(t){K.has(t)||(K.add(t),t.addEventProcessor((e,r)=>{if(e.type==="feedback"||e.type==="replay_event"){delete e.user,delete e.request,delete e.breadcrumbs,delete e.extra,delete e.transaction,e.type==="replay_event"&&Object.assign(e,{urls:[]});let i=r.data?.feedbackReplayId;e.type==="feedback"&&typeof i=="string"&&/^[a-f0-9]{32}$/i.test(i)&&e.contexts?.feedback&&(e.contexts.feedback.replay_id=i)}return e}))}function k(t){return t.split(/[?#]/)[0].replace(/\/(?:login|password|tokens?|invites?|kiosk|reset)(?:\/[^\s]*)?/gi,"/[private-page]").replace(/\/[A-Za-z0-9_-]{24,}(?=\/|$)/g,"/:id").replace(/\b[0-9a-f]{8}-[0-9a-f-]{27,}\b/gi,":id").replace(/\/\d+(?=\/|$)/g,"/:id").slice(0,256)}var X=new WeakSet,ie=/^(?:http\.request\.method|http\.response\.status_code|server\.address|sentry\.(?:origin|source|sample_rate|op|exclusive_time)|type|op)$/;function ae(t){try{return new URL(t).origin}catch{return"[resource]"}}function T(t){t.op?.startsWith("ui.")?t.description="interaction":t.description&&(["pageload","navigation"].includes(t.op??"")?t.description=k(t.description):/https?:\/\//i.test(t.description)?t.description=t.description.replace(/https?:\/\/\S+/gi,ae):["pageload","navigation"].includes(t.op??"")||(t.description=t.op??"operation"),t.description=t.description.split(/[?#]/)[0].replace(/\b[^\s/]+@[^\s/]+\b/g,"[private]").slice(0,256));let e={};for(let[r,i]of Object.entries(t.data??{})){if(/^browser\.web_vital\.(?:lcp|cls|inp|fcp|ttfb)\.(?:value|load_time|render_time|size)$/.test(r)&&typeof i=="number"&&Number.isFinite(i)){e[r]=i;continue}if(r==="sentry.pageload.span_id"&&typeof i=="string"&&/^[a-f0-9]{16}$/i.test(i)){e[r]=i;continue}if(["sentry.segment.name","sentry.transaction"].includes(r)&&typeof i=="string"){e[r]=k(i);continue}if(r==="user_agent.original"&&typeof i=="string"&&typeof navigator<"u"&&i===navigator.userAgent){e[r]=i.slice(0,512);continue}!ie.test(r)||!["string","number","boolean"].includes(typeof i)||(typeof i=="string"?r==="server.address"?e[r]=/^[a-z0-9.:-]+$/i.test(i)?i:"[destination]":/^[a-z0-9_. /:-]{1,128}$/i.test(i)&&(e[r]=i):e[r]=i)}return t.data=e,t}function _(t){if(X.has(t))return;X.add(t);let e=t.getOptions(),r=e.beforeSendSpan;e.beforeSendSpan=i=>T(r?r(i):i)}function Z(){return!!v()}async function G(t){let e=v();if(!e||!t.message.trim())throw new Error("Feedback is unavailable");typeof e.addEventProcessor=="function"&&C(e),await new Promise((r,i)=>{let s,o=e.on("afterSendEvent",(f,m)=>{f.event_id===s&&(clearTimeout(c),o(),m?.statusCode&&m.statusCode>=200&&m.statusCode<300?r():i(new Error("Feedback was not accepted")))}),c=setTimeout(()=>{o(),i(new Error("Feedback timed out"))},15e3);try{s=D({message:t.message.trim(),url:t.pageUrl,source:"api",tags:{page_component:t.component}},{includeReplay:!1,data:{feedbackReplayId:t.replayId},attachments:t.screenshot?[{filename:"feedback-screenshot.png",contentType:"image/png",data:t.screenshot.data}]:[]})}catch(f){clearTimeout(c),o(),i(f)}})}function Q(t,e){return new Promise(r=>{let i=!1,s=setTimeout(()=>{i=!0,r(void 0)},8e3);t.then(o=>{clearTimeout(s),i?o&&e?.(o):r(o)}).catch(()=>{clearTimeout(s),r(void 0)})})}function z(t={}){let e={message:"",busy:!1,capturing:!1,captureState:"pending",error:"",success:!1},r=0,i=!1,s={pageUrl:"",component:""},o=()=>t.changed?.({...e});function c(){e.screenshot&&(URL.revokeObjectURL(e.screenshot.previewUrl),e.captureState="removed"),e.screenshot=void 0,o()}async function f(){if(i||t.eligible?.()===!1)return;i=!0;let p=++r;e.error="",e.success=!1,e.capturing=!0,e.captureState=j(window.location)?"private":"pending",s={pageUrl:J(window.location),component:t.component?.()??"document"},o();let l=Q(import("./feedbackScreenshot-XN3R2P73.js").then(b=>b.captureFeedbackScreenshot()),b=>URL.revokeObjectURL(b.previewUrl)),R=Q(import("./feedbackReplay-6PAAGWVV.js").then(b=>b.freezeFeedbackReplay())),[g,y]=await Promise.all([l,R]);if(p!==r){g&&URL.revokeObjectURL(g.previewUrl);return}e.screenshot=g,s.replayId=y,e.capturing=!1,e.captureState!=="private"&&(e.captureState=g?"ready":"unavailable"),o()}function m(){e.busy||(w(),import("./feedbackReplay-6PAAGWVV.js").then(p=>p.restartFeedbackReplay()))}function w(){r++,i=!1,c(),e.message="",e.capturing=!1,o()}async function S(){if(e.busy||e.capturing||t.eligible?.()===!1)return;if(e.error="",!e.message.trim()){e.error="messageRequired",o();return}if(!Z()){e.error="unavailable",o();return}let p=r;e.busy=!0,o();try{await G({...s,message:e.message,screenshot:e.screenshot}),p===r&&(e.success=!0,e.message="",c())}catch{p===r&&(e.error="sendFailed")}finally{e.busy=!1,o()}}return{state:e,open:f,close:m,cancel:w,submit:S,removeScreenshot:c,setMessage(p){e.message=p,o()}}}var ee="sentry.feedback.corner";function te(){try{let t=localStorage.getItem(ee);if(["topLeft","topRight","bottomLeft","bottomRight"].includes(t??""))return t}catch{}return"bottomRight"}function re(t){try{localStorage.setItem(ee,t)}catch{}}function H(t,e){return{x:t.endsWith("Left")?e.left:e.right,y:t.startsWith("top")?e.top:e.bottom}}function ne(t,e){return(t.y<(e.top+e.bottom)/2?"top":"bottom")+(t.x<(e.left+e.right)/2?"Left":"Right")}function oe(t,e){if(e==="ArrowLeft")return t.startsWith("top")?"topLeft":"bottomLeft";if(e==="ArrowRight")return t.startsWith("top")?"topRight":"bottomRight";if(e==="ArrowUp")return t.endsWith("Left")?"topLeft":"topRight";if(e==="ArrowDown")return t.endsWith("Left")?"bottomLeft":"bottomRight"}function $(t,e){return{x:Math.max(e.left,Math.min(e.right,t.x)),y:Math.max(e.top,Math.min(e.bottom,t.y))}}var se={title:"Feedback",open:"Send feedback",close:"Close",message:"What happened?",submit:"Send",done:"Done",remove:"Remove screenshot",success:"Thank you. Your feedback was accepted.",sendFailed:"Feedback could not be sent. Please try again.",messageRequired:"Enter a message.",unavailable:"Feedback is unavailable.",disclosure:"Opening feedback uploads the recent replay buffer. Your message and screenshot are sent only when you submit.",pending:"Preparing capture\u2026",ready:"Review your screenshot",removed:"Screenshot removed",private:"Text feedback only on this page",captureUnavailable:"Capture unavailable; you can still send text feedback.",moved:"Feedback button moved"};function ce(t={}){let e=t.eligible?.()??!0;I(t.policy??{});let r={...se,...t.labels},i=new AbortController,s=document.createElement("div");s.dataset.feedbackUi="",s.dataset.sentryBlock="",s.className=t.className??"",s.innerHTML=`
`,s.hidden=!e,document.body.append(s);let o=n=>s.querySelector(n),c=o(".sentry-feedback-trigger"),f=o("dialog"),m=o("textarea"),w=o("img"),S=o("h2");S.id=`sentry-feedback-${crypto.randomUUID()}`,S.textContent=r.title,f.setAttribute("aria-labelledby",S.id),c.setAttribute("aria-label",r.open),c.title=r.open,o(".disclosure").textContent=r.disclosure,o("label span").textContent=r.message,o(".submit").textContent=r.submit,o(".remove").textContent=r.remove,o(".close").textContent=r.close,o(".success").textContent=r.success;let p=z({eligible:()=>e&&(t.eligible?.()??!0),component:t.component,changed(n){m.value=n.message,m.disabled=n.busy,o(".submit").disabled=n.busy||n.capturing,o(".close").disabled=n.busy,o(".error").textContent=n.error?r[n.error]:"",o(".capture").textContent=n.captureState==="unavailable"?r.captureUnavailable:r[n.captureState],w.hidden=!n.screenshot,n.screenshot?w.src=n.screenshot.previewUrl:w.removeAttribute("src"),o(".remove").hidden=!n.screenshot,o("form").hidden=n.success,o(".success").hidden=!n.success,n.success&&(o(".close").textContent=r.done,o(".close").focus())}}),l=(n,a,d)=>n.addEventListener(a,d,{signal:i.signal});l(c,"click",()=>{if(P){P=!1;return}f.open||(p.open(),f.showModal(),m.focus())});let R=()=>{p.state.busy||(p.close(),f.close(),c.focus())};l(o(".close"),"click",R),l(f,"cancel",n=>{n.preventDefault(),R()}),l(o("form"),"submit",n=>{n.preventDefault(),p.submit()}),l(m,"input",()=>p.setMessage(m.value)),l(o(".remove"),"click",p.removeScreenshot);let g=()=>{p.cancel(),f.close()};l(window,"popstate",g),l(window,"hashchange",g);let y=te(),b,F=0,P=!1,u,N=window.matchMedia("(prefers-reduced-motion: reduce)");function L(){let n=getComputedStyle(o(".sentry-feedback-probe")),a=U=>parseFloat(U)||0,d=window.visualViewport,x=(d?.offsetLeft??0)+16+a(n.paddingLeft),E=(d?.offsetTop??0)+16+a(n.paddingTop);return{left:x,top:E,right:Math.max(x,(d?.offsetLeft??0)+(d?.width??innerWidth)-64-a(n.paddingRight)),bottom:Math.max(E,(d?.offsetTop??0)+(d?.height??innerHeight)-64-a(n.paddingBottom))}}function B(n){b=n,c.style.transform=`translate3d(${n.x}px,${n.y}px,0)`}function h(n=!0){cancelAnimationFrame(F);let a=H(y,L()),d=b??a;if(!n||N.matches){B(a);return}let x=performance.now(),E=U=>{let A=(U-x)/700,O=1-Math.exp(-6*A)*Math.cos(7.5*A);B($({x:d.x+(a.x-d.x)*O,y:d.y+(a.y-d.y)*O},L())),A<1?F=requestAnimationFrame(E):B(a)};F=requestAnimationFrame(E)}function W(n){y=n,re(y),o('[role="status"]').textContent=r.moved,h()}l(c,"pointerdown",n=>{let a=n;!a.isPrimary||a.button!==0||u||(cancelAnimationFrame(F),u={id:a.pointerId,start:{x:a.clientX,y:a.clientY},origin:b??H(y,L()),moved:!1},P=!1,c.setPointerCapture(a.pointerId))}),l(c,"pointermove",n=>{let a=n;if(!u||u.id!==a.pointerId)return;let d=a.clientX-u.start.x,x=a.clientY-u.start.y;!u.moved&&Math.hypot(d,x)<8||(u.moved=!0,B($({x:u.origin.x+d,y:u.origin.y+x},L())))});let M=n=>{let a=n;!u||u.id!==a.pointerId||(P=u.moved||a.type==="pointercancel",u=void 0,c.hasPointerCapture(a.pointerId)&&c.releasePointerCapture(a.pointerId),P?W(ne(b,L())):h())};return l(c,"pointerup",M),l(c,"pointercancel",M),l(c,"lostpointercapture",M),l(c,"keydown",n=>{let a=n,d=oe(y,a.key);d&&(a.preventDefault(),W(d))}),l(window,"resize",()=>h(!1)),window.visualViewport&&(l(window.visualViewport,"resize",()=>h(!1)),l(window.visualViewport,"scroll",()=>h(!1))),l(N,"change",()=>h(!1)),h(!1),e&&import("./feedbackReplay-6PAAGWVV.js").then(n=>{e&&n.setFeedbackReplayEnabled(!0)}),{controller:p,setEnabled(n){e=n,n?s.hidden=!1:(g(),s.hidden=!0),import("./feedbackReplay-6PAAGWVV.js").then(a=>a.setFeedbackReplayEnabled(n))},dispose(){e=!1,i.abort(),cancelAnimationFrame(F),p.cancel(),s.remove(),import("./feedbackReplay-6PAAGWVV.js").then(n=>n.setFeedbackReplayEnabled(!1))}}}async function Pe(t,e,r){if(!e||r<=0)return!1;if(r>=100)return!0;let i=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(`${t}:${e.toLowerCase()}`)));return new DataView(i.buffer).getUint32(0)%100+1<=r}function le(t){t.transaction=k(t.transaction??"document"),delete t.request,delete t.extra,delete t.breadcrumbs,t.user&&(t.user=t.user.id?{id:t.user.id}:void 0);for(let e of t.spans??[])T(e);return t}function Le(t,e){if(e)return C(e),_(e),e;let r=v();if(r)return C(r),_(r),r;let i=/^(?:localhost|127\.|0\.0\.0\.0|\[?::1\]?$)|\.(?:localhost|test)$/.test(window.location.hostname);if(!t.enabled||i&&!t.localVerification)return;q({...t,sendDefaultPii:!1,replaysSessionSampleRate:0,replaysOnErrorSampleRate:0,integrations:[V({instrumentNavigation:!t.inertia,beforeStartSpan:o=>({...o,name:k(o.name)})})],beforeSendSpan:T,beforeSendTransaction:le});let s=v();return s&&C(s),s}function Ee(t){let e=v();if(e)return Y(e,{name:k(t),op:"navigation",attributes:{"sentry.source":"component"}})}export{I as configureCapturePolicy,z as createFeedbackController,Le as initializeBrowser,ce as mountFeedbackWidget,Pe as percentageEligible,T as sanitizeSpan,le as sanitizeTransaction,k as stablePageName,Ee as startInertiaNavigation}; +`,s.hidden=!e,document.body.append(s);let o=n=>s.querySelector(n),c=o(".sentry-feedback-trigger"),f=o("dialog"),m=o("textarea"),w=o("img"),S=o("h2");S.id=`sentry-feedback-${crypto.randomUUID()}`,S.textContent=r.title,f.setAttribute("aria-labelledby",S.id),c.setAttribute("aria-label",r.open),c.title=r.open,o(".disclosure").textContent=r.disclosure,o("label span").textContent=r.message,o(".submit").textContent=r.submit,o(".remove").textContent=r.remove,o(".close").textContent=r.close,o(".success").textContent=r.success;let p=H({eligible:()=>e&&(t.eligible?.()??!0),component:t.component,changed(n){m.value=n.message,m.disabled=n.busy,o(".submit").disabled=n.busy||n.capturing,o(".close").disabled=n.busy,o(".error").textContent=n.error?r[n.error]:"",o(".capture").textContent=n.captureState==="unavailable"?r.captureUnavailable:r[n.captureState],w.hidden=!n.screenshot,n.screenshot?w.src=n.screenshot.previewUrl:w.removeAttribute("src"),o(".remove").hidden=!n.screenshot,o("form").hidden=n.success,o(".success").hidden=!n.success,n.success&&(o(".close").textContent=r.done,o(".close").focus())}}),l=(n,a,d)=>n.addEventListener(a,d,{signal:i.signal});l(c,"click",()=>{if(P){P=!1;return}f.open||(p.open(),f.showModal(),m.focus())});let R=()=>{p.state.busy||(p.close(),f.close(),c.focus())};l(o(".close"),"click",R),l(f,"cancel",n=>{n.preventDefault(),R()}),l(o("form"),"submit",n=>{n.preventDefault(),p.submit()}),l(m,"input",()=>p.setMessage(m.value)),l(o(".remove"),"click",p.removeScreenshot);let g=()=>{p.cancel(),f.close()};l(window,"popstate",g),l(window,"hashchange",g);let y=re(),b,F=0,P=!1,u,W=window.matchMedia("(prefers-reduced-motion: reduce)");function L(){let n=getComputedStyle(o(".sentry-feedback-probe")),a=U=>parseFloat(U)||0,d=window.visualViewport,x=(d?.offsetLeft??0)+16+a(n.paddingLeft),E=(d?.offsetTop??0)+16+a(n.paddingTop);return{left:x,top:E,right:Math.max(x,(d?.offsetLeft??0)+(d?.width??innerWidth)-64-a(n.paddingRight)),bottom:Math.max(E,(d?.offsetTop??0)+(d?.height??innerHeight)-64-a(n.paddingBottom))}}function B(n){b=n,c.style.transform=`translate3d(${n.x}px,${n.y}px,0)`}function h(n=!0){cancelAnimationFrame(F);let a=$(y,L()),d=b??a;if(!n||W.matches){B(a);return}let x=performance.now(),E=U=>{let A=(U-x)/700,D=1-Math.exp(-6*A)*Math.cos(7.5*A);B(N({x:d.x+(a.x-d.x)*D,y:d.y+(a.y-d.y)*D},L())),A<1?F=requestAnimationFrame(E):B(a)};F=requestAnimationFrame(E)}function O(n){y=n,ne(y),o('[role="status"]').textContent=r.moved,h()}l(c,"pointerdown",n=>{let a=n;!a.isPrimary||a.button!==0||u||(cancelAnimationFrame(F),u={id:a.pointerId,start:{x:a.clientX,y:a.clientY},origin:b??$(y,L()),moved:!1},P=!1,c.setPointerCapture(a.pointerId))}),l(c,"pointermove",n=>{let a=n;if(!u||u.id!==a.pointerId)return;let d=a.clientX-u.start.x,x=a.clientY-u.start.y;!u.moved&&Math.hypot(d,x)<8||(u.moved=!0,B(N({x:u.origin.x+d,y:u.origin.y+x},L())))});let M=n=>{let a=n;!u||u.id!==a.pointerId||(P=u.moved||a.type==="pointercancel",u=void 0,c.hasPointerCapture(a.pointerId)&&c.releasePointerCapture(a.pointerId),P?O(oe(b,L())):h())};return l(c,"pointerup",M),l(c,"pointercancel",M),l(c,"lostpointercapture",M),l(c,"keydown",n=>{let a=n,d=ie(y,a.key);d&&(a.preventDefault(),O(d))}),l(window,"resize",()=>h(!1)),window.visualViewport&&(l(window.visualViewport,"resize",()=>h(!1)),l(window.visualViewport,"scroll",()=>h(!1))),l(W,"change",()=>h(!1)),h(!1),e&&import("./feedbackReplay-4NH5EQNJ.js").then(n=>{e&&n.setFeedbackReplayEnabled(!0)}),{controller:p,setEnabled(n){e=n,n?s.hidden=!1:(g(),s.hidden=!0),import("./feedbackReplay-4NH5EQNJ.js").then(a=>a.setFeedbackReplayEnabled(n))},dispose(){e=!1,i.abort(),cancelAnimationFrame(F),p.cancel(),s.remove(),import("./feedbackReplay-4NH5EQNJ.js").then(n=>n.setFeedbackReplayEnabled(!1))}}}async function Le(t,e,r){if(!e||r<=0)return!1;if(r>=100)return!0;let i=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(`${t}:${e.toLowerCase()}`)));return new DataView(i.buffer).getUint32(0)%100+1<=r}function de(t){t.transaction=k(t.transaction??"document"),delete t.request,delete t.extra,delete t.breadcrumbs,t.user&&(t.user=t.user.id?{id:t.user.id}:void 0);for(let e of t.spans??[])T(e);return t}function Ee(t,e){if(e)return C(e),z(e),e;let r=v();if(r)return C(r),z(r),r;let i=/^(?:localhost|127\.|0\.0\.0\.0|\[?::1\]?$)|\.(?:localhost|test)$/.test(window.location.hostname);if(!t.enabled||i&&!t.localVerification)return;V({...t,sendDefaultPii:!1,replaysSessionSampleRate:0,replaysOnErrorSampleRate:0,integrations:[Y({instrumentNavigation:!t.inertia,beforeStartSpan:o=>({...o,name:k(o.name)})})],beforeSendSpan:T,beforeSendTransaction:de});let s=v();return s&&C(s),s}function Te(t){let e=v();if(e)return j(e,{name:k(t),op:"navigation",attributes:{"sentry.source":"component"}})}export{I as configureCapturePolicy,H as createFeedbackController,Ee as initializeBrowser,le as mountFeedbackWidget,Le as percentageEligible,T as sanitizeSpan,de as sanitizeTransaction,k as stablePageName,Te as startInertiaNavigation}; diff --git a/browser/src/controller.ts b/browser/src/controller.ts index 79ca4f9..89dac6e 100644 --- a/browser/src/controller.ts +++ b/browser/src/controller.ts @@ -1,5 +1,5 @@ import { feedbackAvailable, sendFeedback } from './feedback'; -import { feedbackPageUrl, isPrivateFeedbackPage } from './feedbackPrivacy'; +import { canRecordFeedbackPage, feedbackPageUrl, isPrivateFeedbackPage } from './feedbackPrivacy'; import type { FeedbackScreenshot } from './feedbackScreenshot'; export type CaptureState = 'pending' | 'ready' | 'removed' | 'unavailable' | 'private'; export interface FeedbackState { message: string; busy: boolean; capturing: boolean; screenshot?: FeedbackScreenshot; captureState: CaptureState; error: '' | 'messageRequired' | 'unavailable' | 'sendFailed'; success: boolean; } @@ -18,14 +18,15 @@ export function createFeedbackController(options: { component?: () => string; ch opened = true; const current = ++generation; state.error = ''; state.success = false; state.capturing = true; state.captureState = isPrivateFeedbackPage(window.location) ? 'private' : 'pending'; context = { pageUrl: feedbackPageUrl(window.location), component: options.component?.() ?? 'document' }; notify(); + if (state.captureState === 'private') { state.capturing = false; notify(); return; } const capture = captureWithDeadline(import('./feedbackScreenshot').then(m => m.captureFeedbackScreenshot()), image => URL.revokeObjectURL(image.previewUrl)); - const replay = captureWithDeadline(import('./feedbackReplay').then(m => m.freezeFeedbackReplay())); + const replay = canRecordFeedbackPage(window.location) ? captureWithDeadline(import('./feedbackReplay').then(m => m.freezeFeedbackReplay())) : Promise.resolve(undefined); const [image, replayId] = await Promise.all([capture, replay]); if (current !== generation) { if (image) URL.revokeObjectURL(image.previewUrl); return; } state.screenshot = image; context.replayId = replayId; state.capturing = false; if (state.captureState !== 'private') state.captureState = image ? 'ready' : 'unavailable'; notify(); } - function close() { if (state.busy) return; cancel(); void import('./feedbackReplay').then(m => m.restartFeedbackReplay()); } + function close() { if (state.busy) return; cancel(); if (canRecordFeedbackPage(window.location)) void import('./feedbackReplay').then(m => m.restartFeedbackReplay()); } function cancel() { generation++; opened = false; removeScreenshot(); state.message = ''; state.capturing = false; notify(); } async function submit() { if (state.busy || state.capturing || options.eligible?.() === false) return; diff --git a/browser/tests/controller.test.ts b/browser/tests/controller.test.ts index 33b9cb3..016c8d3 100644 --- a/browser/tests/controller.test.ts +++ b/browser/tests/controller.test.ts @@ -12,3 +12,31 @@ it('discards stale screenshot results and revokes their object URLs after naviga it('allows text feedback after screenshot capture fails', async () => { mock.capture.mockRejectedValue(Error('renderer failed')); const controller = createFeedbackController(); await controller.open(); expect(controller.state.captureState).toBe('unavailable'); controller.setMessage('Text works'); mock.send.mockResolvedValue(undefined); await controller.submit(); expect(controller.state.success).toBe(true); }); it('keeps the eight second deadline and discards a late result', async () => { vi.useFakeTimers(); let resolve!: (value: string) => void; const discard = vi.fn(); const result = captureWithDeadline(new Promise