@sphoro/bugcatch-web-sdk 0.20.0 → 0.21.0

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/README.md CHANGED
@@ -55,7 +55,7 @@ BugCatch.init({
55
55
  ```html
56
56
  <!-- Pin the version. Without one the CDN serves whatever is latest, so a
57
57
  future release changes behaviour on a site nobody redeployed. -->
58
- <script src="https://unpkg.com/@sphoro/bugcatch-web-sdk@0.20.0/dist/bugcatch.umd.js"></script>
58
+ <script src="https://unpkg.com/@sphoro/bugcatch-web-sdk@0.21.0/dist/bugcatch.umd.js"></script>
59
59
  <script>
60
60
  BugCatch.init({ apiBase: '…', apiKey: 'bc_live_…', projectId: '…' });
61
61
  </script>
@@ -381,6 +381,7 @@ On top of that:
381
381
  | `drafts` | `true` | Recover an unfinished report on this device for seven days. |
382
382
  | `agentIssues` | `true` | Show the one-tap questions the assistant answers by itself. Draws nothing until the project turns the agent on. |
383
383
  | `knownIssues` | `true` | Show what this project already knows is broken, with "me too". Draws nothing until the project turns it on. |
384
+ | `feedback` | `true` | Offer **Give feedback** beside **Report a bug** in the panel, where the project has it on (Settings → Project → General, on by default). `false` hides it on this site; `feedback()` still sends. |
384
385
  | `announcements` | `true` | Show what your team publishes under Settings → Project → Widget announcements, in the panel and beside the button. Draws nothing until one is published. `false` to show them your own way with `announcements()`. |
385
386
  | `beforeSend` | — | Mutate the payload, or return `false` to cancel. |
386
387
  | `updates` | `true` | Tell the reporter live when a report they filed moves. |
@@ -426,6 +427,8 @@ await BugCatch.agentIssues(); // one-tap questions the assistant ans
426
427
 
427
428
  await BugCatch.knownIssues(); await BugCatch.matchKnownIssues(q, { signal }); await BugCatch.meToo(bugId);
428
429
  await BugCatch.announcements(); BugCatch.dismissAnnouncement(a); // what your team is telling visitors
430
+ await BugCatch.feedbackEnabled(); await BugCatch.feedback({ message, kind, score }); // not a bug
431
+ BugCatch.open({ mode: 'feedback' }); // the panel, on the feedback form
429
432
 
430
433
  await BugCatch.canCallNow(); await BugCatch.startCall(bugId?); BugCatch.endCall();
431
434
 
@@ -917,6 +920,41 @@ BugCatch.dismissAnnouncement(notices[0]);
917
920
  `announcements()` is already narrowed to the visitor's day and to what this
918
921
  browser has not closed, and resolves to an empty list on every failure.
919
922
 
923
+ ### Feedback that is not a bug
924
+
925
+ The panel has two forms: **Report a bug** and **Give feedback**, switched at
926
+ the top. Feedback is for everything that is not "this is broken" — an idea,
927
+ praise, something that confused them — and is deliberately short: one box, an
928
+ optional kind (idea, praise, confusing, other), an optional 1–5 face for how
929
+ the product feels so far, and an address only when the page does not already
930
+ know one. Nobody is asked to sign in, even on a project that requires it for
931
+ reports.
932
+
933
+ It is not filed as a bug. Nothing analyses it, assigns it, holds it to an SLA
934
+ or emails anyone about it; it lands on the dashboard's **Feedback** page, where
935
+ the team reads it, writes back if there is an address, and archives it. It is
936
+ sent with the page and browser details, identify()'s user and your
937
+ setContext() context — never the console or network logs — and goes through
938
+ `beforeSend`, whose second argument is `{ type: 'feedback' }`.
939
+
940
+ On by default; a project switches it off under **Settings → Project →
941
+ General**, and the widget then stops drawing the switch.
942
+
943
+ ```js
944
+ // Your own "Send feedback" menu item
945
+ BugCatch.open({ mode: 'feedback' });
946
+
947
+ // Or your own form (works with widget: false)
948
+ if (await BugCatch.feedbackEnabled()) {
949
+ await BugCatch.feedback({
950
+ message: 'Export to CSV would save me an hour a week',
951
+ kind: 'idea', // 'idea' | 'praise' | 'confusing' | 'other' — optional
952
+ score: 4, // 1–5, optional
953
+ });
954
+ }
955
+ BugCatch.on('feedback', ({ id, kind, score }) => analytics.track('feedback', { kind, score }));
956
+ ```
957
+
920
958
  ### Talking a report through
921
959
 
922
960
  Where the workspace has sphoro.voice configured, a reporter can talk to the team
@@ -1,2 +1,2 @@
1
- (function(){"use strict";function it(e=8e3){const r=window.AudioContext||window.webkitAudioContext;try{return new r({sampleRate:e})}catch{return new r}}async function st(e){if(e.state==="suspended")try{await e.resume()}catch{}}function lt(e,r,o){const a=r/o,s=new Float32Array(Math.floor(e.length/a));for(let f=0;f<s.length;f++){const l=Math.floor(f*a),m=Math.min(Math.floor((f+1)*a),e.length);let g=0;for(let i=l;i<m;i++)g+=e[i];s[f]=m>l?g/(m-l):0}return s}const ut=132,j=32635;function ft(e){const r=new Uint8Array(e.length);for(let o=0;o<e.length;o++){const a=Math.max(-1,Math.min(1,e[o]));let s=Math.round(a*32767);const f=s<0?128:0;f&&(s=-s),s>j&&(s=j),s+=ut;let l=7;for(let g=16384;!(s&g)&&l>0;l--,g>>=1);const m=s>>l+3&15;r[o]=~(f|l<<4|m)&255}return r}const dt=512;function pt(e,r,o,a=8e3){const s=e.createMediaStreamSource(r),f=e.createScriptProcessor(dt,1,1);f.onaudioprocess=m=>{const g=m.inputBuffer.getChannelData(0),i=e.sampleRate===a?g:lt(g,e.sampleRate,a);o(ft(i))},s.connect(f);const l=e.createGain();return l.gain.value=0,f.connect(l),l.connect(e.destination),{stop(){f.onaudioprocess=null;try{s.disconnect()}catch{}try{f.disconnect()}catch{}try{l.disconnect()}catch{}}}}const mt="voiceai.realtime.v1",yt=[{urls:"stun:stun.l.google.com:19302"}];function z(){return navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,channelCount:1}})}function F(){var e;return typeof window<"u"&&typeof window.RTCPeerConnection=="function"&&!!((e=navigator.mediaDevices)!=null&&e.getUserMedia)}async function gt({realtimeUrl:e,stream:r,ringsUntil:o,onState:a,onAudioBlocked:s,onMicrophone:f}){const l=(t,n)=>{try{a==null||a(t,n)}catch{}},m=t=>{try{s==null||s(t)}catch{}},g=t=>{try{f==null||f(t)}catch{}};if(!F()){const t=new Error("[BugCatch] this browser cannot make live calls.");throw l("failed",{reason:"unsupported"}),t}let i=r;if(!i)try{i=await z()}catch(t){throw l("failed",{reason:"microphone",error:String((t==null?void 0:t.name)||t)}),t}let y;try{y=await ht(e)}catch(t){throw W(i),l("failed",{reason:"connect"}),t}let c=null,u=null,p=!1,w=null,h=null,E=null,S=!1,b=null,C=null,O=!1;const x=[];let M=!1,D=!1,P=!1,R=null,I=null,B=0;const Ot=2e3,K=5e3,_t=3e4,At=4,k=(t,n)=>{if(!p){p=!0,w&&(clearTimeout(w),w=null),et(),C==null||C(),C=null,Mt(),b==null||b(),b=null;try{c==null||c.close()}catch{}W(i),u&&(u.srcObject=null,u.remove(),u=null);try{y.readyState===WebSocket.OPEN&&y.close(1e3,"call over")}catch{}l(t,n)}},_=t=>{y.readyState===WebSocket.OPEN&&y.send(JSON.stringify(t))},q=async()=>{if(O||E||p||!h||!h.audio&&!h.transcript)return;O=!0;const t=h.encoding||"mulaw";if(t!=="mulaw"){V(`this call is kept as ${t}, which this SDK cannot produce.`);return}const n=Number(h.sample_rate)||8e3;try{const d=it(n);if(await st(d),p){try{d.close()}catch{}return}const v=pt(d,i,T=>{y.readyState===WebSocket.OPEN&&y.send(T)},n);E={context:d,tap:v}}catch(d){V(`could not send the copy this call is keeping: ${String((d==null?void 0:d.message)||d)}`)}};function Mt(){if(O=!1,!E)return;const{context:t,tap:n}=E;E=null;try{n.stop()}catch{}try{t.close()}catch{}}function X(){var n;if(!u||p)return;let t;try{t=(n=u.play)==null?void 0:n.call(u)}catch{Q();return}if(!t||typeof t.then!="function"){H();return}t.then(H,Q)}function H(){b==null||b(),b=null,S&&(S=!1,m(!1))}function Q(){p||(S||(S=!0,m(!0)),It())}function It(){if(b||typeof window>"u"||typeof window.addEventListener!="function")return;const t=()=>X(),n=["pointerdown","keydown","touchstart"];for(const d of n)window.addEventListener(d,t,{capture:!0,passive:!0});b=()=>{for(const d of n)try{window.removeEventListener(d,t,{capture:!0})}catch{}}}const $t=t=>{c=new RTCPeerConnection({iceServers:t!=null&&t.length?t:yt});for(const n of i.getAudioTracks())c.addTrack(n,i);C=Nt(),c.onicecandidate=n=>{n.candidate&&_({type:"signal",signal:{kind:"candidate",payload:n.candidate.toJSON()}})},c.ontrack=n=>{var v;const[d]=n.streams;d&&(u||(u=document.createElement("audio"),u.autoplay=!0,u.playsInline=!0,(v=u.setAttribute)==null||v.call(u,"playsinline",""),u.style.cssText="position:fixed;width:0;height:0;opacity:0;pointer-events:none",document.body.appendChild(u)),u.srcObject=d,X())},c.onconnectionstatechange=Z,c.oniceconnectionstatechange=Z};function Z(){if(!c||p)return;const t=c.connectionState||c.iceConnectionState;if(t==="connected"||t==="completed"){D=!0,B=0,et(),P=!1,l("connected");return}if(t==="disconnected"){if(!D)return;tt(Ot);return}if(t==="failed"){if(!D){k("failed",{reason:"ice"});return}tt(0)}}function tt(t){p||(P||(P=!0,l("reconnecting"),I=setTimeout(()=>k("failed",{reason:"network"}),_t)),!R&&(R=setTimeout(U,t)))}function et(){R&&(clearTimeout(R),R=null),I&&(clearTimeout(I),I=null)}async function U(){if(R=null,p||!c)return;const t=c.connectionState||c.iceConnectionState;if(!(t==="connected"||t==="completed")){if(!M){_({type:"signal",signal:{kind:"restart",payload:{}}}),R=setTimeout(U,K);return}B>=At||(B+=1,await nt(),R=setTimeout(U,K))}}async function nt(){if(!(p||!c))try{const t=await c.createOffer({iceRestart:!0});await c.setLocalDescription(t),_({type:"signal",signal:{kind:"offer",payload:c.localDescription.toJSON()}})}catch{}}function Nt(){let n=null,d=!1;const v=T=>{if(n&&(clearTimeout(n),n=null),T){if(!d)return;d=!1,g(!0);return}d||(n=setTimeout(()=>{n=null,!p&&(d=!0,g(!1))},600))};for(const T of i.getAudioTracks())T.onmute=()=>v(!1),T.onunmute=()=>v(!0),T.onended=()=>{n&&(clearTimeout(n),n=null),!d&&(d=!0,g(!1))};return()=>{n&&(clearTimeout(n),n=null);for(const T of i.getAudioTracks())T.onmute=null,T.onunmute=null,T.onended=null}}const Lt=async()=>{try{const t=await c.createOffer();await c.setLocalDescription(t),_({type:"signal",signal:{kind:"offer",payload:c.localDescription.toJSON()}})}catch{k("failed",{reason:"negotiation"})}},Dt=async t=>{try{await c.setRemoteDescription(new RTCSessionDescription(t));const n=await c.createAnswer();await c.setLocalDescription(n),_({type:"signal",signal:{kind:"answer",payload:c.localDescription.toJSON()}}),await ot()}catch{k("failed",{reason:"negotiation"})}},ot=async()=>{for(;x.length;){const t=x.shift();try{await c.addIceCandidate(new RTCIceCandidate(t))}catch{}}};let rt=Promise.resolve();y.onmessage=t=>{rt=rt.then(()=>Pt(t)).catch(()=>{})};const Pt=async t=>{var d,v,T,at,ct;if(typeof t.data!="string")return;let n;try{n=JSON.parse(t.data)}catch{return}switch(n.type){case"session.created":{if($t((d=n.data)==null?void 0:d.ice_servers),h=((v=n.data)==null?void 0:v.capture)||null,(T=n.data)!=null&&T.peer_present){l("connecting"),q();break}l("ringing"),Bt();break}case"peer.joined":{w&&(clearTimeout(w),w=null),l("connecting"),M=!!((at=n.data)!=null&&at.should_offer),M&&await Lt(),q();break}case"signal":{if(!c)break;const{kind:$,payload:N}=n.data||{};if($==="offer")await Dt(N);else if($==="answer")try{await c.setRemoteDescription(new RTCSessionDescription(N)),await ot()}catch{k("failed",{reason:"negotiation"})}else if($==="candidate")if(c.remoteDescription)try{await c.addIceCandidate(new RTCIceCandidate(N))}catch{}else x.push(N);else $==="restart"&&M&&await nt();break}case"peer.left":k("ended",{reason:"peer_left"});break;case"error":k("failed",{reason:"server",detail:(ct=n.error)==null?void 0:ct.detail});break;case"session.ended":k("ended",{reason:"server"});break}};y.onclose=()=>k("ended",{reason:"disconnected"}),y.onerror=()=>k("failed",{reason:"socket"});function Bt(){if(!o)return;const t=new Date(o).getTime()-Date.now();Number.isFinite(t)&&(w=setTimeout(()=>k("missed"),Math.max(0,t)))}return{hangUp(){_({type:"session.end"}),k("ended",{reason:"hung_up"})},setMuted(t){for(const n of i.getAudioTracks())n.enabled=!t;return t},isMuted(){return i.getAudioTracks().every(t=>!t.enabled)}}}function ht(e){return new Promise((r,o)=>{let a;try{a=new WebSocket(e,mt)}catch(s){o(s);return}a.onopen=()=>{a.onopen=null,a.onerror=null,r(a)},a.onerror=()=>{a.onopen=null,a.onerror=null,o(new Error("[BugCatch] could not connect the call."))}})}function V(e){try{console.warn(`[BugCatch] ${e}`)}catch{}}function W(e){var r;for(const o of((r=e==null?void 0:e.getTracks)==null?void 0:r.call(e))??[])try{o.stop()}catch{}}const J="#0e0e10",L="#ffffff";function wt(e){const r=bt(e);if(!r)return L;const[o,a,s]=r.map(l=>{const m=l/255;return m<=.03928?m/12.92:((m+.055)/1.055)**2.4});return .2126*o+.7152*a+.0722*s>.179?J:L}function bt(e){const r=String(e||"").trim();let o=/^#([0-9a-f]{3})$/i.exec(r);return o?[...o[1]].map(a=>parseInt(a+a,16)):(o=/^#([0-9a-f]{6})$/i.exec(r),o?[0,2,4].map(a=>parseInt(o[1].slice(a,a+2),16)):(o=/^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/i.exec(r),o?[o[1],o[2],o[3]].map(Number):null))}const A={cycleMs:3e3,peak:.045,bursts:[{at:0,seconds:.4,hz:[440,660]},{at:.55,seconds:.4,hz:[440,660]}]};function Tt(){var e;try{return!!((e=navigator.userActivation)!=null&&e.hasBeenActive)}catch{return!1}}function kt(e){if(!e()&&!Tt())return()=>{};const r=typeof window<"u"&&(window.AudioContext||window.webkitAudioContext);if(!r)return()=>{};let o;try{o=new r}catch{return()=>{}}let a=!1,s=null;const f=[],l=({at:i,seconds:y,hz:c})=>{const u=o.currentTime+i,p=o.createGain();p.connect(o.destination),p.gain.setValueAtTime(0,u),p.gain.linearRampToValueAtTime(A.peak,u+.02),p.gain.setValueAtTime(A.peak,u+y-.06),p.gain.linearRampToValueAtTime(0,u+y);for(const w of c){const h=o.createOscillator();h.type="sine",h.frequency.value=w,h.connect(p),h.start(u),h.stop(u+y+.02),f.push(h)}},m=()=>{if(!a)try{A.bursts.forEach(l)}catch{}},g=()=>{a||(m(),s=setInterval(m,A.cycleMs))};return o.state==="running"?g():o.resume().then(g).catch(()=>{}),()=>{a=!0,s&&clearInterval(s);for(const i of f)try{i.stop()}catch{}try{o.close()}catch{}}}function xt(e){const r=Date.parse(e||"");return Number.isNaN(r)?0:Math.max(0,Math.round((r-Date.now())/1e3))}const Y=["flex:1","padding:9px 12px","border:0","border-radius:999px","font:560 13px/1.4 inherit","cursor:pointer"].join(";");function Ct({call:e,accent:r=null,position:o="bottom-right",onAnswer:a,onDecline:s,onExpire:f,touched:l=()=>!1}){if(typeof document>"u"||!document.body)return()=>{};const[m,g]=String(o).split("-"),i=document.createElement("div");i.setAttribute("role","alertdialog"),i.setAttribute("aria-live","assertive"),i.setAttribute("aria-label",`${e.from||"Support"} is calling about ${e.reference}`),i.style.cssText=["position:fixed",`${m==="top"?"top":"bottom"}:20px`,`${g==="left"?"left":"right"}:20px`,"z-index:2147483647","width:300px","max-width:calc(100vw - 40px)","padding:16px","border-radius:16px","background:#111113","color:#f3f2ef",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',`box-shadow:0 0 0 1px ${r?`color-mix(in srgb, ${r} 55%, transparent)`:"rgba(255,255,255,.12)"},0 24px 50px -12px rgba(0,0,0,.6)`,"opacity:0","transform:translateY(8px)","transition:opacity .2s ease,transform .2s ease"].join(";");const y=document.createElement("div");y.style.cssText="font-weight:600;font-size:14px;margin-bottom:2px",y.textContent=`${e.from||"Support"} is calling`;const c=document.createElement("div");c.style.cssText="color:#b3b0aa;margin-bottom:10px",c.textContent=e.project?`About your report ${e.reference} · ${e.project}`:`About your report ${e.reference}`;const u=document.createElement("div");u.style.cssText="color:#8f8c86;font-size:12px;margin-bottom:10px";const p=document.createElement("button");p.type="button",p.textContent="Answer",p.style.cssText=`${Y};background:${r||L};color:${r?wt(r):J}`;const w=document.createElement("button");w.type="button",w.textContent="Not now",w.style.cssText=`${Y};background:rgba(255,255,255,.08);color:#f3f2ef`;const h=document.createElement("div");if(h.style.cssText="display:flex;gap:8px",h.append(p,w),i.append(y,c,u),e.recorded){const x=document.createElement("div");x.style.cssText="color:#8f8c86;font-size:12px;margin-bottom:10px",x.textContent="This call will be recorded.",i.append(x)}i.append(h),document.body.appendChild(i);const E=kt(l);let S=!1,b=null;const C=()=>{S||(S=!0,b&&clearInterval(b),E(),i.style.opacity="0",i.style.transform="translateY(8px)",setTimeout(()=>i.remove(),250))},O=()=>{const x=xt(e.ringsUntil);if(u.textContent=x?`Ringing — ${x}s`:"The call has stopped ringing.",!x){C();try{f==null||f()}catch{}}};return O(),b=setInterval(O,1e3),p.addEventListener("click",()=>{C();try{a==null||a()}catch{}}),w.addEventListener("click",()=>{C();try{s==null||s()}catch{}}),requestAnimationFrame(()=>{i.style.opacity="1",i.style.transform="translateY(0)"}),C}const vt=Object.freeze(Object.defineProperty({__proto__:null,joinLiveCall:gt,liveCallSupported:F,openMicrophone:z,showIncomingCall:Ct},Symbol.toStringTag,{value:"Module"})),Rt="0.20.0",G="__bugcatchChunks",Et=e=>`${e}@${Rt}`;function St(e,r){const o=window[G]||(window[G]={});o[Et(e)]=r}St("call",vt)})();
1
+ (function(){"use strict";function it(e=8e3){const r=window.AudioContext||window.webkitAudioContext;try{return new r({sampleRate:e})}catch{return new r}}async function st(e){if(e.state==="suspended")try{await e.resume()}catch{}}function lt(e,r,o){const a=r/o,s=new Float32Array(Math.floor(e.length/a));for(let f=0;f<s.length;f++){const l=Math.floor(f*a),m=Math.min(Math.floor((f+1)*a),e.length);let g=0;for(let i=l;i<m;i++)g+=e[i];s[f]=m>l?g/(m-l):0}return s}const ut=132,j=32635;function ft(e){const r=new Uint8Array(e.length);for(let o=0;o<e.length;o++){const a=Math.max(-1,Math.min(1,e[o]));let s=Math.round(a*32767);const f=s<0?128:0;f&&(s=-s),s>j&&(s=j),s+=ut;let l=7;for(let g=16384;!(s&g)&&l>0;l--,g>>=1);const m=s>>l+3&15;r[o]=~(f|l<<4|m)&255}return r}const dt=512;function pt(e,r,o,a=8e3){const s=e.createMediaStreamSource(r),f=e.createScriptProcessor(dt,1,1);f.onaudioprocess=m=>{const g=m.inputBuffer.getChannelData(0),i=e.sampleRate===a?g:lt(g,e.sampleRate,a);o(ft(i))},s.connect(f);const l=e.createGain();return l.gain.value=0,f.connect(l),l.connect(e.destination),{stop(){f.onaudioprocess=null;try{s.disconnect()}catch{}try{f.disconnect()}catch{}try{l.disconnect()}catch{}}}}const mt="voiceai.realtime.v1",yt=[{urls:"stun:stun.l.google.com:19302"}];function z(){return navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,channelCount:1}})}function F(){var e;return typeof window<"u"&&typeof window.RTCPeerConnection=="function"&&!!((e=navigator.mediaDevices)!=null&&e.getUserMedia)}async function gt({realtimeUrl:e,stream:r,ringsUntil:o,onState:a,onAudioBlocked:s,onMicrophone:f}){const l=(t,n)=>{try{a==null||a(t,n)}catch{}},m=t=>{try{s==null||s(t)}catch{}},g=t=>{try{f==null||f(t)}catch{}};if(!F()){const t=new Error("[BugCatch] this browser cannot make live calls.");throw l("failed",{reason:"unsupported"}),t}let i=r;if(!i)try{i=await z()}catch(t){throw l("failed",{reason:"microphone",error:String((t==null?void 0:t.name)||t)}),t}let y;try{y=await ht(e)}catch(t){throw W(i),l("failed",{reason:"connect"}),t}let c=null,u=null,p=!1,w=null,h=null,E=null,S=!1,b=null,C=null,O=!1;const x=[];let M=!1,D=!1,P=!1,R=null,I=null,B=0;const Ot=2e3,K=5e3,_t=3e4,At=4,k=(t,n)=>{if(!p){p=!0,w&&(clearTimeout(w),w=null),et(),C==null||C(),C=null,Mt(),b==null||b(),b=null;try{c==null||c.close()}catch{}W(i),u&&(u.srcObject=null,u.remove(),u=null);try{y.readyState===WebSocket.OPEN&&y.close(1e3,"call over")}catch{}l(t,n)}},_=t=>{y.readyState===WebSocket.OPEN&&y.send(JSON.stringify(t))},q=async()=>{if(O||E||p||!h||!h.audio&&!h.transcript)return;O=!0;const t=h.encoding||"mulaw";if(t!=="mulaw"){V(`this call is kept as ${t}, which this SDK cannot produce.`);return}const n=Number(h.sample_rate)||8e3;try{const d=it(n);if(await st(d),p){try{d.close()}catch{}return}const v=pt(d,i,T=>{y.readyState===WebSocket.OPEN&&y.send(T)},n);E={context:d,tap:v}}catch(d){V(`could not send the copy this call is keeping: ${String((d==null?void 0:d.message)||d)}`)}};function Mt(){if(O=!1,!E)return;const{context:t,tap:n}=E;E=null;try{n.stop()}catch{}try{t.close()}catch{}}function X(){var n;if(!u||p)return;let t;try{t=(n=u.play)==null?void 0:n.call(u)}catch{Q();return}if(!t||typeof t.then!="function"){H();return}t.then(H,Q)}function H(){b==null||b(),b=null,S&&(S=!1,m(!1))}function Q(){p||(S||(S=!0,m(!0)),It())}function It(){if(b||typeof window>"u"||typeof window.addEventListener!="function")return;const t=()=>X(),n=["pointerdown","keydown","touchstart"];for(const d of n)window.addEventListener(d,t,{capture:!0,passive:!0});b=()=>{for(const d of n)try{window.removeEventListener(d,t,{capture:!0})}catch{}}}const $t=t=>{c=new RTCPeerConnection({iceServers:t!=null&&t.length?t:yt});for(const n of i.getAudioTracks())c.addTrack(n,i);C=Nt(),c.onicecandidate=n=>{n.candidate&&_({type:"signal",signal:{kind:"candidate",payload:n.candidate.toJSON()}})},c.ontrack=n=>{var v;const[d]=n.streams;d&&(u||(u=document.createElement("audio"),u.autoplay=!0,u.playsInline=!0,(v=u.setAttribute)==null||v.call(u,"playsinline",""),u.style.cssText="position:fixed;width:0;height:0;opacity:0;pointer-events:none",document.body.appendChild(u)),u.srcObject=d,X())},c.onconnectionstatechange=Z,c.oniceconnectionstatechange=Z};function Z(){if(!c||p)return;const t=c.connectionState||c.iceConnectionState;if(t==="connected"||t==="completed"){D=!0,B=0,et(),P=!1,l("connected");return}if(t==="disconnected"){if(!D)return;tt(Ot);return}if(t==="failed"){if(!D){k("failed",{reason:"ice"});return}tt(0)}}function tt(t){p||(P||(P=!0,l("reconnecting"),I=setTimeout(()=>k("failed",{reason:"network"}),_t)),!R&&(R=setTimeout(U,t)))}function et(){R&&(clearTimeout(R),R=null),I&&(clearTimeout(I),I=null)}async function U(){if(R=null,p||!c)return;const t=c.connectionState||c.iceConnectionState;if(!(t==="connected"||t==="completed")){if(!M){_({type:"signal",signal:{kind:"restart",payload:{}}}),R=setTimeout(U,K);return}B>=At||(B+=1,await nt(),R=setTimeout(U,K))}}async function nt(){if(!(p||!c))try{const t=await c.createOffer({iceRestart:!0});await c.setLocalDescription(t),_({type:"signal",signal:{kind:"offer",payload:c.localDescription.toJSON()}})}catch{}}function Nt(){let n=null,d=!1;const v=T=>{if(n&&(clearTimeout(n),n=null),T){if(!d)return;d=!1,g(!0);return}d||(n=setTimeout(()=>{n=null,!p&&(d=!0,g(!1))},600))};for(const T of i.getAudioTracks())T.onmute=()=>v(!1),T.onunmute=()=>v(!0),T.onended=()=>{n&&(clearTimeout(n),n=null),!d&&(d=!0,g(!1))};return()=>{n&&(clearTimeout(n),n=null);for(const T of i.getAudioTracks())T.onmute=null,T.onunmute=null,T.onended=null}}const Lt=async()=>{try{const t=await c.createOffer();await c.setLocalDescription(t),_({type:"signal",signal:{kind:"offer",payload:c.localDescription.toJSON()}})}catch{k("failed",{reason:"negotiation"})}},Dt=async t=>{try{await c.setRemoteDescription(new RTCSessionDescription(t));const n=await c.createAnswer();await c.setLocalDescription(n),_({type:"signal",signal:{kind:"answer",payload:c.localDescription.toJSON()}}),await ot()}catch{k("failed",{reason:"negotiation"})}},ot=async()=>{for(;x.length;){const t=x.shift();try{await c.addIceCandidate(new RTCIceCandidate(t))}catch{}}};let rt=Promise.resolve();y.onmessage=t=>{rt=rt.then(()=>Pt(t)).catch(()=>{})};const Pt=async t=>{var d,v,T,at,ct;if(typeof t.data!="string")return;let n;try{n=JSON.parse(t.data)}catch{return}switch(n.type){case"session.created":{if($t((d=n.data)==null?void 0:d.ice_servers),h=((v=n.data)==null?void 0:v.capture)||null,(T=n.data)!=null&&T.peer_present){l("connecting"),q();break}l("ringing"),Bt();break}case"peer.joined":{w&&(clearTimeout(w),w=null),l("connecting"),M=!!((at=n.data)!=null&&at.should_offer),M&&await Lt(),q();break}case"signal":{if(!c)break;const{kind:$,payload:N}=n.data||{};if($==="offer")await Dt(N);else if($==="answer")try{await c.setRemoteDescription(new RTCSessionDescription(N)),await ot()}catch{k("failed",{reason:"negotiation"})}else if($==="candidate")if(c.remoteDescription)try{await c.addIceCandidate(new RTCIceCandidate(N))}catch{}else x.push(N);else $==="restart"&&M&&await nt();break}case"peer.left":k("ended",{reason:"peer_left"});break;case"error":k("failed",{reason:"server",detail:(ct=n.error)==null?void 0:ct.detail});break;case"session.ended":k("ended",{reason:"server"});break}};y.onclose=()=>k("ended",{reason:"disconnected"}),y.onerror=()=>k("failed",{reason:"socket"});function Bt(){if(!o)return;const t=new Date(o).getTime()-Date.now();Number.isFinite(t)&&(w=setTimeout(()=>k("missed"),Math.max(0,t)))}return{hangUp(){_({type:"session.end"}),k("ended",{reason:"hung_up"})},setMuted(t){for(const n of i.getAudioTracks())n.enabled=!t;return t},isMuted(){return i.getAudioTracks().every(t=>!t.enabled)}}}function ht(e){return new Promise((r,o)=>{let a;try{a=new WebSocket(e,mt)}catch(s){o(s);return}a.onopen=()=>{a.onopen=null,a.onerror=null,r(a)},a.onerror=()=>{a.onopen=null,a.onerror=null,o(new Error("[BugCatch] could not connect the call."))}})}function V(e){try{console.warn(`[BugCatch] ${e}`)}catch{}}function W(e){var r;for(const o of((r=e==null?void 0:e.getTracks)==null?void 0:r.call(e))??[])try{o.stop()}catch{}}const J="#0e0e10",L="#ffffff";function wt(e){const r=bt(e);if(!r)return L;const[o,a,s]=r.map(l=>{const m=l/255;return m<=.03928?m/12.92:((m+.055)/1.055)**2.4});return .2126*o+.7152*a+.0722*s>.179?J:L}function bt(e){const r=String(e||"").trim();let o=/^#([0-9a-f]{3})$/i.exec(r);return o?[...o[1]].map(a=>parseInt(a+a,16)):(o=/^#([0-9a-f]{6})$/i.exec(r),o?[0,2,4].map(a=>parseInt(o[1].slice(a,a+2),16)):(o=/^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/i.exec(r),o?[o[1],o[2],o[3]].map(Number):null))}const A={cycleMs:3e3,peak:.045,bursts:[{at:0,seconds:.4,hz:[440,660]},{at:.55,seconds:.4,hz:[440,660]}]};function Tt(){var e;try{return!!((e=navigator.userActivation)!=null&&e.hasBeenActive)}catch{return!1}}function kt(e){if(!e()&&!Tt())return()=>{};const r=typeof window<"u"&&(window.AudioContext||window.webkitAudioContext);if(!r)return()=>{};let o;try{o=new r}catch{return()=>{}}let a=!1,s=null;const f=[],l=({at:i,seconds:y,hz:c})=>{const u=o.currentTime+i,p=o.createGain();p.connect(o.destination),p.gain.setValueAtTime(0,u),p.gain.linearRampToValueAtTime(A.peak,u+.02),p.gain.setValueAtTime(A.peak,u+y-.06),p.gain.linearRampToValueAtTime(0,u+y);for(const w of c){const h=o.createOscillator();h.type="sine",h.frequency.value=w,h.connect(p),h.start(u),h.stop(u+y+.02),f.push(h)}},m=()=>{if(!a)try{A.bursts.forEach(l)}catch{}},g=()=>{a||(m(),s=setInterval(m,A.cycleMs))};return o.state==="running"?g():o.resume().then(g).catch(()=>{}),()=>{a=!0,s&&clearInterval(s);for(const i of f)try{i.stop()}catch{}try{o.close()}catch{}}}function xt(e){const r=Date.parse(e||"");return Number.isNaN(r)?0:Math.max(0,Math.round((r-Date.now())/1e3))}const Y=["flex:1","padding:9px 12px","border:0","border-radius:999px","font:560 13px/1.4 inherit","cursor:pointer"].join(";");function Ct({call:e,accent:r=null,position:o="bottom-right",onAnswer:a,onDecline:s,onExpire:f,touched:l=()=>!1}){if(typeof document>"u"||!document.body)return()=>{};const[m,g]=String(o).split("-"),i=document.createElement("div");i.setAttribute("role","alertdialog"),i.setAttribute("aria-live","assertive"),i.setAttribute("aria-label",`${e.from||"Support"} is calling about ${e.reference}`),i.style.cssText=["position:fixed",`${m==="top"?"top":"bottom"}:20px`,`${g==="left"?"left":"right"}:20px`,"z-index:2147483647","width:300px","max-width:calc(100vw - 40px)","padding:16px","border-radius:16px","background:#111113","color:#f3f2ef",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',`box-shadow:0 0 0 1px ${r?`color-mix(in srgb, ${r} 55%, transparent)`:"rgba(255,255,255,.12)"},0 24px 50px -12px rgba(0,0,0,.6)`,"opacity:0","transform:translateY(8px)","transition:opacity .2s ease,transform .2s ease"].join(";");const y=document.createElement("div");y.style.cssText="font-weight:600;font-size:14px;margin-bottom:2px",y.textContent=`${e.from||"Support"} is calling`;const c=document.createElement("div");c.style.cssText="color:#b3b0aa;margin-bottom:10px",c.textContent=e.project?`About your report ${e.reference} · ${e.project}`:`About your report ${e.reference}`;const u=document.createElement("div");u.style.cssText="color:#8f8c86;font-size:12px;margin-bottom:10px";const p=document.createElement("button");p.type="button",p.textContent="Answer",p.style.cssText=`${Y};background:${r||L};color:${r?wt(r):J}`;const w=document.createElement("button");w.type="button",w.textContent="Not now",w.style.cssText=`${Y};background:rgba(255,255,255,.08);color:#f3f2ef`;const h=document.createElement("div");if(h.style.cssText="display:flex;gap:8px",h.append(p,w),i.append(y,c,u),e.recorded){const x=document.createElement("div");x.style.cssText="color:#8f8c86;font-size:12px;margin-bottom:10px",x.textContent="This call will be recorded.",i.append(x)}i.append(h),document.body.appendChild(i);const E=kt(l);let S=!1,b=null;const C=()=>{S||(S=!0,b&&clearInterval(b),E(),i.style.opacity="0",i.style.transform="translateY(8px)",setTimeout(()=>i.remove(),250))},O=()=>{const x=xt(e.ringsUntil);if(u.textContent=x?`Ringing — ${x}s`:"The call has stopped ringing.",!x){C();try{f==null||f()}catch{}}};return O(),b=setInterval(O,1e3),p.addEventListener("click",()=>{C();try{a==null||a()}catch{}}),w.addEventListener("click",()=>{C();try{s==null||s()}catch{}}),requestAnimationFrame(()=>{i.style.opacity="1",i.style.transform="translateY(0)"}),C}const vt=Object.freeze(Object.defineProperty({__proto__:null,joinLiveCall:gt,liveCallSupported:F,openMicrophone:z,showIncomingCall:Ct},Symbol.toStringTag,{value:"Module"})),Rt="0.21.0",G="__bugcatchChunks",Et=e=>`${e}@${Rt}`;function St(e,r){const o=window[G]||(window[G]={});o[Et(e)]=r}St("call",vt)})();
2
2
  //# sourceMappingURL=bugcatch-call.umd.js.map