@sphoro/bugcatch-web-sdk 0.18.0 → 0.20.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 +51 -3
- package/dist/bugcatch-call.es.js +201 -200
- package/dist/bugcatch-call.es.js.map +1 -1
- package/dist/bugcatch-call.umd.js +1 -1
- package/dist/bugcatch-call.umd.js.map +1 -1
- package/dist/bugcatch-core.es.js +1085 -1007
- package/dist/bugcatch-core.es.js.map +1 -1
- package/dist/bugcatch-panel.es.js +1337 -1067
- package/dist/bugcatch-panel.es.js.map +1 -1
- package/dist/bugcatch-panel.umd.js +427 -315
- package/dist/bugcatch-panel.umd.js.map +1 -1
- package/dist/bugcatch.standalone.umd.js +553 -429
- package/dist/bugcatch.standalone.umd.js.map +1 -1
- package/dist/bugcatch.umd.js +132 -120
- package/dist/bugcatch.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/accent.js +38 -0
- package/src/incoming-call.js +17 -15
- package/src/index.d.ts +52 -2
- package/src/index.js +26 -7
- package/src/panel/call.js +3 -2
- package/src/panel/compose.js +7 -3
- package/src/panel/icons.js +2 -0
- package/src/panel/index.js +26 -3
- package/src/panel/messages.js +2 -2
- package/src/panel/picks.js +6 -2
- package/src/panel/rate-due.js +155 -0
- package/src/panel/rating.js +87 -0
- package/src/panel/refs.js +1 -1
- package/src/panel/render.js +11 -3
- package/src/panel/signin.js +1 -1
- package/src/panel/styles.js +270 -186
- package/src/panel/thread.js +48 -7
- package/src/updates.js +77 -27
- package/src/widget.js +160 -141
package/dist/bugcatch.umd.js
CHANGED
|
@@ -1,81 +1,106 @@
|
|
|
1
|
-
(function(C,B){typeof exports=="object"&&typeof module<"u"?module.exports=B():typeof define=="function"&&define.amd?define(B):(C=typeof globalThis<"u"?globalThis:C||self,C.BugCatch=B())})(this,function(){"use strict";var st=C=>{throw TypeError(C)};var to=(C,B,K)=>B.has(C)||st("Cannot "+K);var at=(C,B,K)=>B.has(C)?st("Cannot add the same private member more than once"):B instanceof WeakSet?B.add(C):B.set(C,K);var b=(C,B,K)=>(to(C,B,"access private method"),K);var d,Z,ct,R,lt,me,G,Q,we,ut,dt,ht,ee,ft;const C="[REDACTED]",B=new Set(["auth","bearer","session","sid","phpsessid","otp","pass","passwd","pwd","sig","codeverifier"]),K=["token","secret","password","passwd","apikey","signature","credential","sessionid","privatekey","accesskey","authorization"],pt=new Set(["key","code","state","nonce","salt","hash"]),be=[/eyJ[\w-]{8,}\.[\w-]{8,}\.[\w-]+/g,/(?:AKIA|ASIA|AROA|AIDA|AGPA|ANPA|ANVA|APKA)[0-9A-Z]{16}/g,/AIza[\w-]{35}/g,/gh[pousr]_[A-Za-z0-9]{36,}/g,/github_pat_\w{22,}/g,/[sprk]k_(?:live|test)_[0-9A-Za-z]{10,}/g,/xox[abposr]-[A-Za-z0-9-]{10,}/g,/sk-ant-[\w-]{20,}/g,/sk-[\w-]{20,}/g,/glpat-[\w-]{20,}/g,/shp(?:at|ss|ca|pa)_[A-Za-z0-9]{32}/g],gt=/\bBearer\s+[\w.~+/=-]{8,}/gi,mt=/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^/?#@]+)@/;function ye(t){try{return decodeURIComponent(t.replace(/\+/g," "))}catch{return t}}function wt(t){return ye(t).toLowerCase().replace(/[^a-z0-9]/g,"")}function bt(t){return t.length>=20?!0:be.some(e=>(e.lastIndex=0,e.test(t)))}function yt(t,e){const n=wt(t);if(!n)return!1;if(B.has(n))return!0;for(const o of K)if(n.includes(o))return!0;return pt.has(n)?bt(ye(e)):!1}function te(t){return t.split("&").map(e=>{const n=e.indexOf("=");if(n===-1)return e;const o=e.slice(0,n),s=e.slice(n+1);return s&&yt(o,s)?`${o}=${C}`:e}).join("&")}function xe(t){let e=t;for(const n of be)n.lastIndex=0,e=e.replace(n,C);return e}function ke(t){if(t==null)return t;let e=String(t);if(!e)return e;e=e.replace(mt,`$1${C}@`);const n=e.indexOf("#");let o=n===-1?e:e.slice(0,n),s=n===-1?"":e.slice(n);const i=o.indexOf("?");if(i!==-1&&(o=o.slice(0,i+1)+te(o.slice(i+1))),s.length>1){const r=s.slice(1),a=r.indexOf("?");a!==-1?s=`#${r.slice(0,a+1)}${te(r.slice(a+1))}`:r.includes("=")&&(s=`#${te(r)}`)}return xe(o+s)}function xt(t){if(t==null)return t;let e=String(t);return e&&(e=e.replace(/[A-Za-z][A-Za-z0-9+.-]{0,30}:\/\/[^\s"'<>)\]]+/g,n=>ke(n)),e=e.replace(gt,`Bearer ${C}`),xe(e))}function z(t){const e=[];return{push(n){e.push(n),e.length>t&&e.splice(0,e.length-t)},all:()=>e.slice(),clear:()=>{e.length=0},get size(){return e.length}}}const ve=["log","info","warn","error","debug"];function kt(t,{levels:e=["warn","error","log","info"]}={}){const n={};for(const o of ve)n[o]=console[o],e.includes(o)&&(console[o]=(...s)=>{try{t.push({level:o,text:s.map(Se).join(" ").slice(0,2e3),at:new Date().toISOString()})}catch{}n[o].apply(console,s)});return()=>{for(const o of ve)console[o]=n[o]}}function vt(t,{slowMs:e=2e3}={}){const n=window.fetch,o=XMLHttpRequest.prototype.open,s=XMLHttpRequest.prototype.send;return n&&(window.fetch=async function(...r){var h,u,E;const a=performance.now(),c=typeof r[0]=="string"?r[0]:(h=r[0])==null?void 0:h.url,l=((u=r[1])==null?void 0:u.method)||(typeof r[0]=="object"?(E=r[0])==null?void 0:E.method:"GET")||"GET";try{const x=await n.apply(this,r);return ne(t,{url:c,method:l,status:x.status,ms:Math.round(performance.now()-a),slowMs:e}),x}catch(x){throw ne(t,{url:c,method:l,status:0,error:String((x==null?void 0:x.message)||x),ms:Math.round(performance.now()-a),slowMs:e}),x}}),XMLHttpRequest.prototype.open=function(r,a,...c){return this.__bc={method:r,url:a,started:0},o.call(this,r,a,...c)},XMLHttpRequest.prototype.send=function(...r){return this.__bc&&(this.__bc.started=performance.now(),this.addEventListener("loadend",()=>{ne(t,{url:this.__bc.url,method:this.__bc.method,status:this.status,ms:Math.round(performance.now()-this.__bc.started),slowMs:e})})),s.apply(this,r)},()=>{n&&(window.fetch=n),XMLHttpRequest.prototype.open=o,XMLHttpRequest.prototype.send=s}}function ne(t,{url:e,method:n,status:o,ms:s,error:i,slowMs:r}){try{t.push({url:ke(String(e)).slice(0,500),method:n,status:o,ms:s,error:i===void 0?void 0:xt(i),failed:o===0||o>=400,slow:s>=r,at:new Date().toISOString()})}catch{}}function Ct(t){const e=o=>{const s=String(o.message||"Error"),i=o.filename?` (${o.filename}:${o.lineno}:${o.colno})`:"";t.push({level:"error",text:(/^uncaught/i.test(s)?s:`Uncaught ${s}`)+i,at:new Date().toISOString()})},n=o=>{t.push({level:"error",text:`Unhandled rejection: ${Se(o.reason)}`,at:new Date().toISOString()})};return window.addEventListener("error",e),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",e),window.removeEventListener("unhandledrejection",n)}}async function Ce(){const t=Ie();try{if(navigator.getBattery){const e=await navigator.getBattery();t.battery=Math.round(e.level*100),t.charging=e.charging}}catch{}return t}function Ie(){var e,n,o,s,i,r,a,c,l;const t=window.navigator||{};return{userAgent:t.userAgent,platform:t.platform,language:t.language,languages:t.languages?[...t.languages]:null,online:t.onLine,cookieEnabled:t.cookieEnabled,maxTouchPoints:t.maxTouchPoints??null,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:(e=window.screen)==null?void 0:e.width,height:(n=window.screen)==null?void 0:n.height,availWidth:(o=window.screen)==null?void 0:o.availWidth,availHeight:(s=window.screen)==null?void 0:s.availHeight,colorDepth:(i=window.screen)==null?void 0:i.colorDepth,orientation:((a=(r=window.screen)==null?void 0:r.orientation)==null?void 0:a.type)||null},devicePixelRatio:window.devicePixelRatio,referrer:document.referrer||null,title:document.title,capturedAt:new Date().toISOString(),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffsetMinutes:new Date().getTimezoneOffset(),browserMode:t.webdriver?"Automated":"Normal",doNotTrack:t.doNotTrack||null,hardwareConcurrency:t.hardwareConcurrency??null,deviceMemory:t.deviceMemory??null,connection:t.connection?{effectiveType:t.connection.effectiveType,downlink:t.connection.downlink,rtt:t.connection.rtt,saveData:t.connection.saveData}:null,prefersColorScheme:(c=window.matchMedia)!=null&&c.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light",prefersReducedMotion:((l=window.matchMedia)==null?void 0:l.call(window,"(prefers-reduced-motion: reduce)").matches)||!1}}function Se(t){if(typeof t=="string")return t;if(t instanceof Error)return`${t.name}: ${t.message}`;try{return JSON.stringify(t)}catch{return String(t)}}const It='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11.5a7.5 7 0 0 1 7.5-7h1a7.5 7 0 0 1 0 14H9l-4.2 2.6a.5.5 0 0 1-.76-.5l.5-3.1A7 7 0 0 1 4 11.5z"/><path d="M8.5 11.5h.01M12 11.5h.01M15.5 11.5h.01" stroke-width="2.6"/></svg>',St='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9.5l6 6 6-6"/></svg>',Bt='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.6v2.2M12 19.2v2.2M2.6 12h2.2M19.2 12h2.2M5.4 5.4l1.6 1.6M17 17l1.6 1.6M18.6 5.4L17 7M7 17l-1.6 1.6"/></svg>',$t='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13.4A8.2 8.2 0 1 1 10.6 4a6.6 6.6 0 0 0 9.4 9.4z"/></svg>',Et='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="2.8" y="4.4" width="18.4" height="12.6" rx="2.2"/><path d="M8.6 20.2h6.8"/><path d="M12 4.4v12.6"/><path d="M12 7.2a3.6 3.6 0 0 1 0 7.2z" fill="currentColor" stroke="none"/></svg>',Be='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7.5v5.2M12 16.3h.01"/></svg>',$e='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>',At='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.8l4.6 4.4L19 7"/></svg>',Ee='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.7h.01"/></svg>',Tt='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.3 4.2a2 2 0 0 1 3.4 0l7.6 13.1a2 2 0 0 1-1.7 3H4.4a2 2 0 0 1-1.7-3z"/><path d="M12 9.5v4.2M12 17h.01"/></svg>',oe="0.18.0",jt="__bugcatchChunks",Ot=t=>`${t}@${oe}`;function Ae(t){var e;return typeof window<"u"?(e=window[jt])==null?void 0:e[Ot(t)]:void 0}function ie(t,e){return console.warn(`[BugCatch] ${t}`),new Error("[BugCatch] part of the widget could not be loaded — check the connection and try again.")}function Te(t){let e=null;return(...n)=>(e||(e=t(...n).catch(o=>{throw e=null,o})),e)}const A=typeof document<"u"?document.currentScript:null,Lt=(A==null?void 0:A.src)||null,je=(A==null?void 0:A.nonce)||"",Oe=(A==null?void 0:A.getAttribute("crossorigin"))??null,Le=(A==null?void 0:A.referrerPolicy)||"";function Mt({chunkBase:t,loadedFrom:e,baseURI:n}){if(t)return new URL(String(t).replace(/\/*$/,"/"),n).href;if(!e)return null;const o=new URL(e);return/\.js$/i.test(o.pathname)?new URL(".",o).href:new URL(`${o.pathname.replace(/\/*$/,"/")}dist/`,o).href}function Me(t,e){const n=Ae(t);if(n)return Promise.resolve(n);const o=Mt({chunkBase:e,loadedFrom:Lt,baseURI:document.baseURI});if(!o)return Promise.reject(ie(`bugcatch-${t}.umd.js could not be loaded: this copy of the SDK was not loaded from an address, so there is nowhere to look for it. Set init({ chunkBase }) to the folder that holds it.`));const s=`${o}bugcatch-${t}.umd.js?v=${encodeURIComponent(oe)}`;return new Promise((i,r)=>{const a=document.createElement("script");a.src=s,a.async=!0,je&&(a.nonce=je),Oe!==null&&(a.crossOrigin=Oe),Le&&(a.referrerPolicy=Le);const c=()=>{a.onload=null,a.onerror=null,a.remove()};a.onload=()=>{c();const l=Ae(t);l?i(l):r(ie(`${s} loaded, but not as version ${oe} of the SDK — serve every file in dist/ from the same release.`))},a.onerror=()=>{c(),r(ie(`could not load ${s}. The files in dist/ are served together: a self-hosted copy needs all of them (or init({ chunkBase }) pointing at them), and a Content-Security-Policy has to allow them in script-src.`))},(document.head||document.documentElement).appendChild(a)})}const Re=Te(t=>Me("panel",t)),F=Te(t=>Me("call",t)),Rt={info:Ee,success:At,warning:Tt,critical:Be};function Kt(t,{where:e,onDismiss:n}){const o=document.createElement("div");o.className=`notice tone-${t.tone} at-${e}`,o.setAttribute("role","status");const s=document.createElement("span");s.className="notice-ico",s.setAttribute("aria-hidden","true"),s.innerHTML=Rt[t.tone]||Ee;const i=document.createElement("div");i.className="notice-text";const r=document.createElement("strong");if(r.textContent=t.title,i.append(r),t.body){const a=document.createElement("p");a.textContent=t.body,i.append(a)}if(t.ctaHref&&t.ctaLabel){const a=document.createElement("a");a.className="notice-cta",a.href=t.ctaHref,a.textContent=t.ctaLabel,/^https?:/i.test(t.ctaHref)&&(a.target="_blank",a.rel="noopener noreferrer"),i.append(a)}if(o.append(s,i),t.dismissible&&n){const a=document.createElement("button");a.type="button",a.className="notice-x",a.setAttribute("aria-label","Dismiss this notice"),a.innerHTML=$e,a.addEventListener("click",()=>n(t)),o.append(a)}return o}const Ke={"bottom-right":"bottom:20px;right:20px;","bottom-left":"bottom:20px;left:20px;","top-right":"top:20px;right:20px;","top-left":"top:20px;left:20px;"},Ue=[{value:"light",label:"Light",icon:Bt},{value:"dark",label:"Dark",icon:$t},{value:"auto",label:"System default",icon:Et}],Ne="bugcatch:theme";function Ut(){try{const t=localStorage.getItem(Ne);return Ue.some(e=>e.value===t)?t:null}catch{return null}}function Nt(t){try{localStorage.setItem(Ne,t)}catch{}}const Pt=t=>`
|
|
1
|
+
(function(v,$){typeof exports=="object"&&typeof module<"u"?module.exports=$():typeof define=="function"&&define.amd?define($):(v=typeof globalThis<"u"?globalThis:v||self,v.BugCatch=$())})(this,function(){"use strict";var pt=v=>{throw TypeError(v)};var uo=(v,$,U)=>$.has(v)||pt("Cannot "+U);var gt=(v,$,U)=>$.has(v)?pt("Cannot add the same private member more than once"):$ instanceof WeakSet?$.add(v):$.set(v,U);var m=(v,$,U)=>(uo(v,$,"access private method"),U);var d,ne,mt,K,wt,ke,oe,ie,ve,bt,yt,xt,re,kt;const v="[REDACTED]",$=new Set(["auth","bearer","session","sid","phpsessid","otp","pass","passwd","pwd","sig","codeverifier"]),U=["token","secret","password","passwd","apikey","signature","credential","sessionid","privatekey","accesskey","authorization"],vt=new Set(["key","code","state","nonce","salt","hash"]),Ce=[/eyJ[\w-]{8,}\.[\w-]{8,}\.[\w-]+/g,/(?:AKIA|ASIA|AROA|AIDA|AGPA|ANPA|ANVA|APKA)[0-9A-Z]{16}/g,/AIza[\w-]{35}/g,/gh[pousr]_[A-Za-z0-9]{36,}/g,/github_pat_\w{22,}/g,/[sprk]k_(?:live|test)_[0-9A-Za-z]{10,}/g,/xox[abposr]-[A-Za-z0-9-]{10,}/g,/sk-ant-[\w-]{20,}/g,/sk-[\w-]{20,}/g,/glpat-[\w-]{20,}/g,/shp(?:at|ss|ca|pa)_[A-Za-z0-9]{32}/g],Ct=/\bBearer\s+[\w.~+/=-]{8,}/gi,It=/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^/?#@]+)@/;function Ie(t){try{return decodeURIComponent(t.replace(/\+/g," "))}catch{return t}}function St(t){return Ie(t).toLowerCase().replace(/[^a-z0-9]/g,"")}function $t(t){return t.length>=20?!0:Ce.some(e=>(e.lastIndex=0,e.test(t)))}function Bt(t,e){const n=St(t);if(!n)return!1;if($.has(n))return!0;for(const o of U)if(n.includes(o))return!0;return vt.has(n)?$t(Ie(e)):!1}function se(t){return t.split("&").map(e=>{const n=e.indexOf("=");if(n===-1)return e;const o=e.slice(0,n),s=e.slice(n+1);return s&&Bt(o,s)?`${o}=${v}`:e}).join("&")}function Se(t){let e=t;for(const n of Ce)n.lastIndex=0,e=e.replace(n,v);return e}function $e(t){if(t==null)return t;let e=String(t);if(!e)return e;e=e.replace(It,`$1${v}@`);const n=e.indexOf("#");let o=n===-1?e:e.slice(0,n),s=n===-1?"":e.slice(n);const i=o.indexOf("?");if(i!==-1&&(o=o.slice(0,i+1)+se(o.slice(i+1))),s.length>1){const r=s.slice(1),a=r.indexOf("?");a!==-1?s=`#${r.slice(0,a+1)}${se(r.slice(a+1))}`:r.includes("=")&&(s=`#${se(r)}`)}return Se(o+s)}function Et(t){if(t==null)return t;let e=String(t);return e&&(e=e.replace(/[A-Za-z][A-Za-z0-9+.-]{0,30}:\/\/[^\s"'<>)\]]+/g,n=>$e(n)),e=e.replace(Ct,`Bearer ${v}`),Se(e))}function W(t){const e=[];return{push(n){e.push(n),e.length>t&&e.splice(0,e.length-t)},all:()=>e.slice(),clear:()=>{e.length=0},get size(){return e.length}}}const Be=["log","info","warn","error","debug"];function Tt(t,{levels:e=["warn","error","log","info"]}={}){const n={};for(const o of Be)n[o]=console[o],e.includes(o)&&(console[o]=(...s)=>{try{t.push({level:o,text:s.map(Ae).join(" ").slice(0,2e3),at:new Date().toISOString()})}catch{}n[o].apply(console,s)});return()=>{for(const o of Be)console[o]=n[o]}}function At(t,{slowMs:e=2e3}={}){const n=window.fetch,o=XMLHttpRequest.prototype.open,s=XMLHttpRequest.prototype.send;return n&&(window.fetch=async function(...r){var h,u,B;const a=performance.now(),c=typeof r[0]=="string"?r[0]:(h=r[0])==null?void 0:h.url,l=((u=r[1])==null?void 0:u.method)||(typeof r[0]=="object"?(B=r[0])==null?void 0:B.method:"GET")||"GET";try{const y=await n.apply(this,r);return ae(t,{url:c,method:l,status:y.status,ms:Math.round(performance.now()-a),slowMs:e}),y}catch(y){throw ae(t,{url:c,method:l,status:0,error:String((y==null?void 0:y.message)||y),ms:Math.round(performance.now()-a),slowMs:e}),y}}),XMLHttpRequest.prototype.open=function(r,a,...c){return this.__bc={method:r,url:a,started:0},o.call(this,r,a,...c)},XMLHttpRequest.prototype.send=function(...r){return this.__bc&&(this.__bc.started=performance.now(),this.addEventListener("loadend",()=>{ae(t,{url:this.__bc.url,method:this.__bc.method,status:this.status,ms:Math.round(performance.now()-this.__bc.started),slowMs:e})})),s.apply(this,r)},()=>{n&&(window.fetch=n),XMLHttpRequest.prototype.open=o,XMLHttpRequest.prototype.send=s}}function ae(t,{url:e,method:n,status:o,ms:s,error:i,slowMs:r}){try{t.push({url:$e(String(e)).slice(0,500),method:n,status:o,ms:s,error:i===void 0?void 0:Et(i),failed:o===0||o>=400,slow:s>=r,at:new Date().toISOString()})}catch{}}function jt(t){const e=o=>{const s=String(o.message||"Error"),i=o.filename?` (${o.filename}:${o.lineno}:${o.colno})`:"";t.push({level:"error",text:(/^uncaught/i.test(s)?s:`Uncaught ${s}`)+i,at:new Date().toISOString()})},n=o=>{t.push({level:"error",text:`Unhandled rejection: ${Ae(o.reason)}`,at:new Date().toISOString()})};return window.addEventListener("error",e),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",e),window.removeEventListener("unhandledrejection",n)}}async function Ee(){const t=Te();try{if(navigator.getBattery){const e=await navigator.getBattery();t.battery=Math.round(e.level*100),t.charging=e.charging}}catch{}return t}function Te(){var e,n,o,s,i,r,a,c,l;const t=window.navigator||{};return{userAgent:t.userAgent,platform:t.platform,language:t.language,languages:t.languages?[...t.languages]:null,online:t.onLine,cookieEnabled:t.cookieEnabled,maxTouchPoints:t.maxTouchPoints??null,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:(e=window.screen)==null?void 0:e.width,height:(n=window.screen)==null?void 0:n.height,availWidth:(o=window.screen)==null?void 0:o.availWidth,availHeight:(s=window.screen)==null?void 0:s.availHeight,colorDepth:(i=window.screen)==null?void 0:i.colorDepth,orientation:((a=(r=window.screen)==null?void 0:r.orientation)==null?void 0:a.type)||null},devicePixelRatio:window.devicePixelRatio,referrer:document.referrer||null,title:document.title,capturedAt:new Date().toISOString(),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffsetMinutes:new Date().getTimezoneOffset(),browserMode:t.webdriver?"Automated":"Normal",doNotTrack:t.doNotTrack||null,hardwareConcurrency:t.hardwareConcurrency??null,deviceMemory:t.deviceMemory??null,connection:t.connection?{effectiveType:t.connection.effectiveType,downlink:t.connection.downlink,rtt:t.connection.rtt,saveData:t.connection.saveData}:null,prefersColorScheme:(c=window.matchMedia)!=null&&c.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light",prefersReducedMotion:((l=window.matchMedia)==null?void 0:l.call(window,"(prefers-reduced-motion: reduce)").matches)||!1}}function Ae(t){if(typeof t=="string")return t;if(t instanceof Error)return`${t.name}: ${t.message}`;try{return JSON.stringify(t)}catch{return String(t)}}const Ot='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9.5l6 6 6-6"/></svg>',Lt='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.6v2.2M12 19.2v2.2M2.6 12h2.2M19.2 12h2.2M5.4 5.4l1.6 1.6M17 17l1.6 1.6M18.6 5.4L17 7M7 17l-1.6 1.6"/></svg>',Rt='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13.4A8.2 8.2 0 1 1 10.6 4a6.6 6.6 0 0 0 9.4 9.4z"/></svg>',Mt='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="2.8" y="4.4" width="18.4" height="12.6" rx="2.2"/><path d="M8.6 20.2h6.8"/><path d="M12 4.4v12.6"/><path d="M12 7.2a3.6 3.6 0 0 1 0 7.2z" fill="currentColor" stroke="none"/></svg>',je='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7.5v5.2M12 16.3h.01"/></svg>',Oe='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>',Kt='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.8l4.6 4.4L19 7"/></svg>',Le='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.7h.01"/></svg>',Ut='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.3 4.2a2 2 0 0 1 3.4 0l7.6 13.1a2 2 0 0 1-1.7 3H4.4a2 2 0 0 1-1.7-3z"/><path d="M12 9.5v4.2M12 17h.01"/></svg>',ce="0.20.0",Nt="__bugcatchChunks",Pt=t=>`${t}@${ce}`;function Re(t){var e;return typeof window<"u"?(e=window[Nt])==null?void 0:e[Pt(t)]:void 0}function le(t,e){return console.warn(`[BugCatch] ${t}`),new Error("[BugCatch] part of the widget could not be loaded — check the connection and try again.")}function Me(t){let e=null;return(...n)=>(e||(e=t(...n).catch(o=>{throw e=null,o})),e)}const E=typeof document<"u"?document.currentScript:null,_t=(E==null?void 0:E.src)||null,Ke=(E==null?void 0:E.nonce)||"",Ue=(E==null?void 0:E.getAttribute("crossorigin"))??null,Ne=(E==null?void 0:E.referrerPolicy)||"";function Dt({chunkBase:t,loadedFrom:e,baseURI:n}){if(t)return new URL(String(t).replace(/\/*$/,"/"),n).href;if(!e)return null;const o=new URL(e);return/\.js$/i.test(o.pathname)?new URL(".",o).href:new URL(`${o.pathname.replace(/\/*$/,"/")}dist/`,o).href}function Pe(t,e){const n=Re(t);if(n)return Promise.resolve(n);const o=Dt({chunkBase:e,loadedFrom:_t,baseURI:document.baseURI});if(!o)return Promise.reject(le(`bugcatch-${t}.umd.js could not be loaded: this copy of the SDK was not loaded from an address, so there is nowhere to look for it. Set init({ chunkBase }) to the folder that holds it.`));const s=`${o}bugcatch-${t}.umd.js?v=${encodeURIComponent(ce)}`;return new Promise((i,r)=>{const a=document.createElement("script");a.src=s,a.async=!0,Ke&&(a.nonce=Ke),Ue!==null&&(a.crossOrigin=Ue),Ne&&(a.referrerPolicy=Ne);const c=()=>{a.onload=null,a.onerror=null,a.remove()};a.onload=()=>{c();const l=Re(t);l?i(l):r(le(`${s} loaded, but not as version ${ce} of the SDK — serve every file in dist/ from the same release.`))},a.onerror=()=>{c(),r(le(`could not load ${s}. The files in dist/ are served together: a self-hosted copy needs all of them (or init({ chunkBase }) pointing at them), and a Content-Security-Policy has to allow them in script-src.`))},(document.head||document.documentElement).appendChild(a)})}const _e=Me(t=>Pe("panel",t)),J=Me(t=>Pe("call",t)),Ht={info:Le,success:Kt,warning:Ut,critical:je};function zt(t,{where:e,onDismiss:n}){const o=document.createElement("div");o.className=`notice tone-${t.tone} at-${e}`,o.setAttribute("role","status");const s=document.createElement("span");s.className="notice-ico",s.setAttribute("aria-hidden","true"),s.innerHTML=Ht[t.tone]||Le;const i=document.createElement("div");i.className="notice-text";const r=document.createElement("strong");if(r.textContent=t.title,i.append(r),t.body){const a=document.createElement("p");a.textContent=t.body,i.append(a)}if(t.ctaHref&&t.ctaLabel){const a=document.createElement("a");a.className="notice-cta",a.href=t.ctaHref,a.textContent=t.ctaLabel,/^https?:/i.test(t.ctaHref)&&(a.target="_blank",a.rel="noopener noreferrer"),i.append(a)}if(o.append(s,i),t.dismissible&&n){const a=document.createElement("button");a.type="button",a.className="notice-x",a.setAttribute("aria-label","Dismiss this notice"),a.innerHTML=Oe,a.addEventListener("click",()=>n(t)),o.append(a)}return o}const De="#0e0e10",ue="#ffffff";function He(t){const e=Ft(t);if(!e)return ue;const[n,o,s]=e.map(r=>{const a=r/255;return a<=.03928?a/12.92:((a+.055)/1.055)**2.4});return .2126*n+.7152*o+.0722*s>.179?De:ue}function Ft(t){const e=String(t||"").trim();let n=/^#([0-9a-f]{3})$/i.exec(e);return n?[...n[1]].map(o=>parseInt(o+o,16)):(n=/^#([0-9a-f]{6})$/i.exec(e),n?[0,2,4].map(o=>parseInt(n[1].slice(o,o+2),16)):(n=/^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/i.exec(e),n?[n[1],n[2],n[3]].map(Number):null))}const ze={"bottom-right":"bottom:20px;right:20px;","bottom-left":"bottom:20px;left:20px;","top-right":"top:20px;right:20px;","top-left":"top:20px;left:20px;"},H=[{value:"light",label:"Light",icon:Lt},{value:"dark",label:"Dark",icon:Rt},{value:"auto",label:"System default",icon:Mt}],Fe="bugcatch:theme";function Xt(){try{const t=localStorage.getItem(Fe);return H.some(e=>e.value===t)?t:null}catch{return null}}function qt(t){try{localStorage.setItem(Fe,t)}catch{}}const Xe=`
|
|
2
|
+
--bc-bg: #151517;
|
|
3
|
+
--bc-elevated: #1c1c1f;
|
|
4
|
+
--bc-fg: #f3f2ef;
|
|
5
|
+
--bc-muted: #b3b0aa;
|
|
6
|
+
--bc-faint: #8f8c86;
|
|
7
|
+
--bc-border: #2c2c30;
|
|
8
|
+
--bc-subtle: #1f1f22;
|
|
9
|
+
--bc-stone: #26262a;
|
|
10
|
+
--bc-raised: #303035;
|
|
11
|
+
--bc-danger: #ff6b81;
|
|
12
|
+
--bc-ok: #4fd19a;
|
|
13
|
+
--bc-warn: #f2a54a;
|
|
14
|
+
--bc-info: #79a8ff;
|
|
15
|
+
--bc-brand-ink: #b3b0aa;
|
|
16
|
+
--bc-brand-mark: #a59cff;
|
|
17
|
+
--bc-shadow: 0 0 0 1px rgba(255,255,255,.08), 0 30px 70px -20px rgba(0,0,0,.8), 0 8px 20px -8px rgba(0,0,0,.5);
|
|
18
|
+
--bc-shadow-sm: 0 0 0 1px rgba(255,255,255,.07), 0 1px 2px rgba(0,0,0,.4);
|
|
19
|
+
--bc-accent-soft: color-mix(in srgb, var(--bc-accent) 14%, var(--bc-bg));`,Wt=t=>`
|
|
2
20
|
:host { all: initial; }
|
|
3
21
|
:host {
|
|
4
|
-
--bc-accent: ${t};
|
|
5
|
-
--bc-on-accent:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
--bc-
|
|
9
|
-
--bc-
|
|
10
|
-
--bc-
|
|
11
|
-
--bc-
|
|
12
|
-
--bc-
|
|
13
|
-
--bc-
|
|
14
|
-
--bc-
|
|
15
|
-
--bc-
|
|
16
|
-
--bc-
|
|
22
|
+
--bc-accent: ${t||"var(--bc-fg)"};
|
|
23
|
+
--bc-on-accent: ${t?He(t):"var(--bc-bg)"};
|
|
24
|
+
/* The assistant's orb: BugCatch's own three colours, or the host's accent
|
|
25
|
+
with two lighter cuts of it, so the orb on their site is in their colour. */
|
|
26
|
+
--bc-o1: ${t?`color-mix(in srgb, ${t} 32%, #fff)`:"#ffb3c9"};
|
|
27
|
+
--bc-o2: ${t||"#6a5cff"};
|
|
28
|
+
--bc-o3: ${t?`color-mix(in srgb, ${t} 22%, #ffe7d1)`:"#ffd6a0"};
|
|
29
|
+
--bc-bg: #ffffff;
|
|
30
|
+
--bc-elevated: #ffffff;
|
|
31
|
+
--bc-fg: #0e0e10;
|
|
32
|
+
--bc-muted: #57544e;
|
|
33
|
+
--bc-faint: #75726c;
|
|
34
|
+
--bc-border: #e9e7e3;
|
|
35
|
+
--bc-subtle: #f6f5f3;
|
|
36
|
+
/* Warm stone: fields, chips and the selected track. */
|
|
37
|
+
--bc-stone: #f0efec;
|
|
38
|
+
--bc-raised: #ffffff;
|
|
39
|
+
--bc-danger: #c8233d;
|
|
40
|
+
--bc-ok: #0b7a55;
|
|
41
|
+
--bc-warn: #a4570a;
|
|
42
|
+
--bc-info: #2459d1;
|
|
17
43
|
/* The lockup's own two colours, kept off --bc-accent on purpose: that one is
|
|
18
44
|
the customer's brand, and this mark is ours. Values are the light cut of
|
|
19
45
|
brand/sphoro-bugcatch-primary.svg, pulled up from near-black so the mark
|
|
20
46
|
identifies itself without out-shouting the host's page. */
|
|
21
|
-
--bc-brand-ink: #
|
|
47
|
+
--bc-brand-ink: #57544e;
|
|
22
48
|
--bc-brand-mark: #5647ee;
|
|
23
|
-
--bc-shadow: 0
|
|
24
|
-
--bc-shadow-sm: 0 1px
|
|
25
|
-
--bc-dur:
|
|
49
|
+
--bc-shadow: 0 0 0 1px rgba(20,18,14,.06), 0 30px 70px -24px rgba(20,18,14,.30), 0 8px 20px -8px rgba(20,18,14,.10);
|
|
50
|
+
--bc-shadow-sm: 0 0 0 1px rgba(20,18,14,.06), 0 1px 2px rgba(20,18,14,.05);
|
|
51
|
+
--bc-dur: 220ms;
|
|
26
52
|
--bc-ease: cubic-bezier(.22,1,.36,1);
|
|
53
|
+
/* Film grain over the orb, so it reads as light rather than a gradient. */
|
|
54
|
+
--bc-grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
|
|
27
55
|
/* The system everything below is drawn from. Derived tokens are written in
|
|
28
56
|
terms of the ones above, so a host that overrides --bc-accent or the
|
|
29
57
|
palette gets a coherent result without touching these. */
|
|
30
|
-
--bc-accent-soft: color-mix(in srgb, var(--bc-accent)
|
|
31
|
-
--bc-accent-line: color-mix(in srgb, var(--bc-accent)
|
|
32
|
-
--bc-ring: 0 0 0 3px color-mix(in srgb, var(--bc-accent)
|
|
58
|
+
--bc-accent-soft: color-mix(in srgb, var(--bc-accent) 7%, var(--bc-bg));
|
|
59
|
+
--bc-accent-line: color-mix(in srgb, var(--bc-accent) 30%, var(--bc-border));
|
|
60
|
+
--bc-ring: 0 0 0 3px color-mix(in srgb, var(--bc-accent) 16%, transparent);
|
|
33
61
|
--bc-r-sm: 8px;
|
|
34
62
|
--bc-r-md: 12px;
|
|
35
|
-
--bc-r-lg:
|
|
36
|
-
--bc-r-xl:
|
|
63
|
+
--bc-r-lg: 16px;
|
|
64
|
+
--bc-r-xl: 20px;
|
|
37
65
|
--bc-fs-xs: 11.5px;
|
|
38
66
|
--bc-fs-sm: 12.5px;
|
|
39
67
|
--bc-fs-md: 14px;
|
|
40
|
-
--bc-fs-lg:
|
|
68
|
+
--bc-fs-lg: 15px;
|
|
41
69
|
--bc-pad: 18px;
|
|
42
70
|
}
|
|
43
|
-
:host(.bc-dark) {
|
|
44
|
-
--bc-bg: #14161c;
|
|
45
|
-
--bc-elevated: #1c1f27;
|
|
46
|
-
--bc-fg: #eef0f4;
|
|
47
|
-
--bc-muted: #a3aab6;
|
|
48
|
-
--bc-faint: #6f7682;
|
|
49
|
-
--bc-border: #2a2e38;
|
|
50
|
-
--bc-subtle: #1f222a;
|
|
51
|
-
--bc-raised: #363d4b;
|
|
52
|
-
--bc-warn: #f59e0b;
|
|
53
|
-
--bc-brand-ink: #9aa1ad;
|
|
54
|
-
--bc-brand-mark: #9b8fff;
|
|
55
|
-
--bc-shadow: 0 24px 64px rgba(0,0,0,.6), 0 4px 14px rgba(0,0,0,.4);
|
|
56
|
-
--bc-shadow-sm: 0 1px 2px rgba(0,0,0,.4);
|
|
57
|
-
--bc-accent-soft: color-mix(in srgb, var(--bc-accent) 18%, var(--bc-bg));
|
|
71
|
+
:host(.bc-dark) {${Xe}
|
|
58
72
|
}
|
|
59
73
|
@media (prefers-color-scheme: dark) {
|
|
60
|
-
:host(.bc-auto) {
|
|
61
|
-
--bc-bg: #14161c;
|
|
62
|
-
--bc-elevated: #1c1f27;
|
|
63
|
-
--bc-fg: #eef0f4;
|
|
64
|
-
--bc-muted: #a3aab6;
|
|
65
|
-
--bc-faint: #6f7682;
|
|
66
|
-
--bc-border: #2a2e38;
|
|
67
|
-
--bc-subtle: #1f222a;
|
|
68
|
-
--bc-raised: #363d4b;
|
|
69
|
-
--bc-warn: #f59e0b;
|
|
70
|
-
--bc-brand-ink: #9aa1ad;
|
|
71
|
-
--bc-brand-mark: #9b8fff;
|
|
72
|
-
--bc-shadow: 0 24px 64px rgba(0,0,0,.6), 0 4px 14px rgba(0,0,0,.4);
|
|
73
|
-
--bc-shadow-sm: 0 1px 2px rgba(0,0,0,.4);
|
|
74
|
-
--bc-accent-soft: color-mix(in srgb, var(--bc-accent) 18%, var(--bc-bg));
|
|
74
|
+
:host(.bc-auto) {${Xe}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
* { box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif; }
|
|
79
|
+
|
|
80
|
+
/* ---------- the orb ----------
|
|
81
|
+
The assistant's face, on the launcher and at the top of every screen: three
|
|
82
|
+
blurred colour blobs turning slowly under a highlight and grain. Hue from
|
|
83
|
+
--bc-o1..3. Sized by whoever places it. */
|
|
84
|
+
.orb {
|
|
85
|
+
position: relative; display: block; flex: none; aspect-ratio: 1; border-radius: 50%;
|
|
86
|
+
background: var(--bc-o2); overflow: hidden; isolation: isolate;
|
|
87
|
+
box-shadow: inset -3px -5px 10px rgba(0,0,0,.22), inset 2px 3px 7px rgba(255,255,255,.35);
|
|
88
|
+
}
|
|
89
|
+
.orb::before {
|
|
90
|
+
content: ''; position: absolute; inset: -20%; border-radius: 50%; z-index: -1;
|
|
91
|
+
background:
|
|
92
|
+
radial-gradient(circle at 70% 72%, var(--bc-o3) 0%, transparent 44%),
|
|
93
|
+
radial-gradient(circle at 26% 66%, var(--bc-o1) 0%, transparent 48%),
|
|
94
|
+
radial-gradient(circle at 58% 30%, var(--bc-o2) 0%, transparent 62%);
|
|
95
|
+
filter: blur(3px);
|
|
96
|
+
animation: bc-orb-turn 18s linear infinite;
|
|
97
|
+
}
|
|
98
|
+
.orb::after {
|
|
99
|
+
content: ''; position: absolute; inset: 0; border-radius: 50%;
|
|
100
|
+
background: radial-gradient(circle at 34% 26%, rgba(255,255,255,.85) 0 5%, rgba(255,255,255,0) 30%), var(--bc-grain);
|
|
101
|
+
mix-blend-mode: soft-light;
|
|
102
|
+
}
|
|
103
|
+
@keyframes bc-orb-turn { to { transform: rotate(360deg); } }
|
|
79
104
|
svg { width: 1em; height: 1em; display: block; }
|
|
80
105
|
/* The hidden attribute has to actually hide. Nearly every element in here is given a
|
|
81
106
|
display by a rule below, and any of them beats the attribute's own UA style
|
|
@@ -106,65 +131,50 @@ button:focus-visible, a:focus-visible, select:focus-visible, [tabindex]:focus-vi
|
|
|
106
131
|
@keyframes bc-launcher-in { from { opacity: 0; transform: translateY(12px) scale(.86) } to { opacity: 1; transform: none } }
|
|
107
132
|
@keyframes bc-item-in { from { opacity: 0; transform: translateY(8px) scale(.96) } to { opacity: 1; transform: none } }
|
|
108
133
|
|
|
109
|
-
/* ---------- dock:
|
|
134
|
+
/* ---------- dock: the launcher, and what is said beside it ---------- */
|
|
110
135
|
.dock {
|
|
111
136
|
position: fixed; z-index: 2147483000;
|
|
112
137
|
display: flex; flex-direction: column; gap: 10px;
|
|
113
138
|
}
|
|
114
139
|
.dock[hidden] { display: none; }
|
|
115
|
-
/* While the panel is open the
|
|
116
|
-
|
|
140
|
+
/* While the panel is open the launcher rises above the scrim, so the button
|
|
141
|
+
that opened it is the button that closes it. */
|
|
117
142
|
.dock.over { z-index: 2147483002; }
|
|
118
143
|
.dock.at-right { align-items: flex-end; }
|
|
119
144
|
.dock.at-left { align-items: flex-start; }
|
|
120
|
-
/* Anchored to the top, "above the launcher" would be off-screen, so
|
|
121
|
-
|
|
145
|
+
/* Anchored to the top, "above the launcher" would be off-screen, so cards go
|
|
146
|
+
under it and the launcher stays the outermost thing. */
|
|
122
147
|
.dock.at-top { flex-direction: column-reverse; }
|
|
123
148
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
box-shadow: 0 6px 18px rgba(10,12,16,.14), 0 1px 3px rgba(10,12,16,.08);
|
|
129
|
-
animation: bc-launcher-in 420ms var(--bc-ease) both;
|
|
130
|
-
}
|
|
131
|
-
.themer button {
|
|
132
|
-
display: grid; place-items: center;
|
|
133
|
-
width: 28px; height: 28px; padding: 0;
|
|
134
|
-
border: none; border-radius: 999px; background: transparent;
|
|
135
|
-
color: var(--bc-muted); cursor: pointer;
|
|
136
|
-
transition: background var(--bc-dur) var(--bc-ease), color var(--bc-dur) var(--bc-ease), transform 140ms var(--bc-ease);
|
|
137
|
-
}
|
|
138
|
-
.themer button svg { font-size: 15px; }
|
|
139
|
-
.themer button:hover { background: var(--bc-subtle); color: var(--bc-fg); }
|
|
140
|
-
.themer button:active { transform: scale(.92); }
|
|
141
|
-
.themer button[aria-pressed="true"] { background: var(--bc-accent); color: var(--bc-on-accent); }
|
|
142
|
-
.themer button[aria-pressed="true"]:hover { background: var(--bc-accent); filter: brightness(1.06); }
|
|
143
|
-
|
|
144
|
-
/* ---------- launcher ---------- */
|
|
149
|
+
/* ---------- launcher ----------
|
|
150
|
+
A pill with the assistant's orb in it: ink by default, the host's colour when
|
|
151
|
+
they set one. The shadow is neutral, never tinted, so a bright brand colour
|
|
152
|
+
does not glow on somebody's checkout. */
|
|
145
153
|
.launcher {
|
|
146
154
|
position: relative;
|
|
147
|
-
display: inline-flex; align-items: center; gap:
|
|
148
|
-
height:
|
|
155
|
+
display: inline-flex; align-items: center; gap: 10px;
|
|
156
|
+
height: 46px; padding: 0 18px 0 7px; border: none; border-radius: 999px;
|
|
149
157
|
background: var(--bc-accent); color: var(--bc-on-accent);
|
|
150
|
-
font-size: var(--bc-fs-md); font-weight:
|
|
158
|
+
font-size: var(--bc-fs-md); font-weight: 560; line-height: 1; letter-spacing: -.01em;
|
|
151
159
|
cursor: pointer;
|
|
152
|
-
box-shadow: 0
|
|
153
|
-
transition: transform var(--bc-dur) var(--bc-ease), box-shadow var(--bc-dur) var(--bc-ease), filter 160ms linear
|
|
160
|
+
box-shadow: 0 1px 2px rgba(0,0,0,.18), 0 10px 26px -8px rgba(0,0,0,.36);
|
|
161
|
+
transition: transform var(--bc-dur) var(--bc-ease), box-shadow var(--bc-dur) var(--bc-ease), filter 160ms linear;
|
|
154
162
|
animation: bc-launcher-in 420ms var(--bc-ease) both;
|
|
155
163
|
}
|
|
156
|
-
/* Two
|
|
164
|
+
/* Two faces in one circle: the orb when closed, a chevron when open, turned
|
|
157
165
|
into each other so the button reads as the panel's own handle. */
|
|
158
|
-
.launcher .ico { position: relative; width:
|
|
166
|
+
.launcher .ico { position: relative; width: 32px; height: 32px; flex: none; }
|
|
159
167
|
.launcher .ico > span {
|
|
160
|
-
position: absolute; inset: 0;
|
|
168
|
+
position: absolute; inset: 0; display: grid; place-items: center; border-radius: 50%;
|
|
161
169
|
transition: transform 320ms var(--bc-ease), opacity 200ms ease;
|
|
162
170
|
}
|
|
163
|
-
.launcher .ico
|
|
171
|
+
.launcher .ico .orb { width: 32px; }
|
|
172
|
+
.launcher .ico .when-open { background: color-mix(in srgb, var(--bc-on-accent) 14%, transparent); }
|
|
173
|
+
.launcher .ico svg { width: 18px; height: 18px; }
|
|
164
174
|
.launcher .ico .when-open { opacity: 0; transform: rotate(-90deg) scale(.6); }
|
|
165
175
|
.launcher[aria-expanded="true"] .ico .when-closed { opacity: 0; transform: rotate(90deg) scale(.6); }
|
|
166
176
|
.launcher[aria-expanded="true"] .ico .when-open { opacity: 1; transform: none; }
|
|
167
|
-
.launcher:hover { transform: translateY(-
|
|
177
|
+
.launcher:hover { transform: translateY(-1px); box-shadow: 0 1px 2px rgba(0,0,0,.18), 0 14px 30px -8px rgba(0,0,0,.42); }
|
|
168
178
|
.launcher:active { transform: translateY(0) scale(.97); transition-duration: 90ms; }
|
|
169
179
|
.launcher:focus-visible { outline-offset: 3px; }
|
|
170
180
|
.launcher[hidden] { display: none; }
|
|
@@ -187,11 +197,11 @@ button:focus-visible, a:focus-visible, select:focus-visible, [tabindex]:focus-vi
|
|
|
187
197
|
In this sheet because the card beside the button exists before the panel's
|
|
188
198
|
does. The tone is a colour and an icon; the site's accent is the info one. */
|
|
189
199
|
.notice {
|
|
190
|
-
--tone: var(--bc-
|
|
200
|
+
--tone: var(--bc-info);
|
|
191
201
|
display: flex; align-items: flex-start; gap: 10px;
|
|
192
|
-
padding:
|
|
193
|
-
background:
|
|
194
|
-
border: 1px solid
|
|
202
|
+
padding: 11px 10px 11px 12px; border-radius: var(--bc-r-md);
|
|
203
|
+
background: var(--bc-subtle);
|
|
204
|
+
border: 1px solid var(--bc-border);
|
|
195
205
|
color: var(--bc-fg);
|
|
196
206
|
font-size: var(--bc-fs-sm); line-height: 1.45; text-align: left;
|
|
197
207
|
animation: bc-item-in 240ms var(--bc-ease) both;
|
|
@@ -199,33 +209,48 @@ button:focus-visible, a:focus-visible, select:focus-visible, [tabindex]:focus-vi
|
|
|
199
209
|
.notice.tone-success { --tone: var(--bc-ok); }
|
|
200
210
|
.notice.tone-warning { --tone: var(--bc-warn); }
|
|
201
211
|
.notice.tone-critical { --tone: var(--bc-danger); }
|
|
202
|
-
|
|
212
|
+
/* The tone is the icon's colour and a wash behind it — enough to tell a delay
|
|
213
|
+
from a fix at a glance, without a coloured card shouting over the form. */
|
|
214
|
+
.notice-ico {
|
|
215
|
+
flex: none; display: grid; place-items: center; width: 22px; height: 22px; margin-top: -1px;
|
|
216
|
+
border-radius: 7px; font-size: 14px;
|
|
217
|
+
color: var(--tone); background: color-mix(in srgb, var(--tone) 13%, transparent);
|
|
218
|
+
}
|
|
203
219
|
.notice-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
204
|
-
.notice-text strong { display: block; font-weight:
|
|
220
|
+
.notice-text strong { display: block; font-weight: 600; letter-spacing: -.005em; }
|
|
205
221
|
.notice-text p { margin: 2px 0 0; color: var(--bc-muted); white-space: pre-line; }
|
|
206
222
|
.notice-cta {
|
|
207
|
-
display: inline-
|
|
208
|
-
color: var(--
|
|
223
|
+
display: inline-flex; align-items: center; gap: 4px; margin-top: 6px;
|
|
224
|
+
color: var(--bc-fg); font-weight: 600; text-decoration: underline;
|
|
225
|
+
text-decoration-color: color-mix(in srgb, var(--bc-fg) 30%, transparent); text-underline-offset: 3px;
|
|
209
226
|
}
|
|
210
|
-
.notice-cta:hover { text-decoration
|
|
227
|
+
.notice-cta:hover { text-decoration-color: currentColor; }
|
|
211
228
|
.notice-x {
|
|
212
229
|
flex: none; display: grid; place-items: center;
|
|
213
|
-
width:
|
|
230
|
+
width: 24px; height: 24px; margin: -2px -2px 0 0; padding: 0;
|
|
214
231
|
border: 0; border-radius: 999px; background: transparent;
|
|
215
|
-
color: var(--bc-
|
|
232
|
+
color: var(--bc-faint); cursor: pointer;
|
|
216
233
|
}
|
|
217
|
-
.notice-x:hover { background: color-mix(in srgb, var(--
|
|
218
|
-
.notice-x svg { font-size:
|
|
234
|
+
.notice-x:hover { background: color-mix(in srgb, var(--bc-fg) 7%, transparent); color: var(--bc-fg); }
|
|
235
|
+
.notice-x svg { font-size: 13px; }
|
|
219
236
|
/* Beside the button it floats over somebody else's page: opaque, lifted, and
|
|
220
237
|
never taller than a glance. The whole text is in the panel. */
|
|
221
238
|
.notice.at-launcher {
|
|
222
239
|
width: min(320px, calc(100vw - 40px));
|
|
223
|
-
|
|
240
|
+
background: var(--bc-elevated); border-color: transparent;
|
|
241
|
+
box-shadow: var(--bc-shadow);
|
|
242
|
+
padding: 13px 12px 13px 13px;
|
|
224
243
|
}
|
|
225
244
|
.notice.at-launcher .notice-text p {
|
|
226
245
|
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
|
|
227
246
|
}
|
|
228
|
-
|
|
247
|
+
/* In the panel they are a stack of short lines above the form, not a wall:
|
|
248
|
+
the body is held to two lines, and the whole of it was beside the button. */
|
|
249
|
+
.notice.at-panel { margin-bottom: 8px; padding: 9px 8px 9px 10px; }
|
|
250
|
+
.notice.at-panel .notice-text p {
|
|
251
|
+
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
|
|
252
|
+
}
|
|
253
|
+
.notice.at-panel .notice-cta { margin-top: 3px; }
|
|
229
254
|
|
|
230
255
|
/* The dock sits in a corner of a page the widget does not own. On a notched
|
|
231
256
|
phone that corner is under the home indicator, and in landscape it is under
|
|
@@ -245,25 +270,12 @@ button:focus-visible, a:focus-visible, select:focus-visible, [tabindex]:focus-vi
|
|
|
245
270
|
.dock.over { display: none; }
|
|
246
271
|
}
|
|
247
272
|
@media (pointer: coarse) {
|
|
248
|
-
/* The theme switch's buttons are small glyphs whose boxes cannot grow without
|
|
249
|
-
moving the launcher under them, so each keeps its size and gets an
|
|
250
|
-
invisible target drawn around it instead. */
|
|
251
|
-
.themer button { position: relative; }
|
|
252
|
-
.themer button::after {
|
|
253
|
-
content: '';
|
|
254
|
-
position: absolute;
|
|
255
|
-
inset: -8px;
|
|
256
|
-
}
|
|
257
|
-
/* The themer's three buttons sit side by side, so their expanders would
|
|
258
|
-
overlap each other without a gap to grow into. */
|
|
259
|
-
.themer { gap: 4px; }
|
|
260
273
|
.notice-x { width: 36px; height: 36px; margin: -9px -8px -6px 0; }
|
|
261
274
|
}
|
|
262
275
|
/* Hover is a lie on a touchscreen: it latches on tap and stays. The launcher's
|
|
263
276
|
lift in particular was left applied after the panel closed. */
|
|
264
277
|
@media (hover: none) {
|
|
265
278
|
.launcher:hover { transform: none; filter: none; }
|
|
266
|
-
.themer button:hover { transform: none; }
|
|
267
279
|
}
|
|
268
280
|
|
|
269
281
|
/* ---------- while the panel's code is on its way ----------
|
|
@@ -288,11 +300,11 @@ button:focus-visible, a:focus-visible, select:focus-visible, [tabindex]:focus-vi
|
|
|
288
300
|
}
|
|
289
301
|
.loadfail button[data-act="retry"] { text-decoration: underline; text-underline-offset: 2px; }
|
|
290
302
|
.loadfail button svg { font-size: 13px; margin: 0; }
|
|
291
|
-
`;function
|
|
303
|
+
`;function Jt(t){const e=document.createElement("div");e.setAttribute("data-bugcatch","widget");let n=Xt()||Yt(t.config.theme);e.className=qe(n);const o=e.attachShadow({mode:"open"}),s=document.createElement("style");s.textContent=Wt(t.config.accent||null),o.appendChild(s);const i=ze[t.config.widgetPosition]?t.config.widgetPosition:"bottom-right",r=document.createElement("div");r.className=`dock ${i.includes("right")?"at-right":"at-left"}`+(i.startsWith("top")?" at-top":""),r.style.cssText=ze[i];const a={current:()=>n,label:()=>H.find(p=>p.value===n).label,cycle(){const p=H[(H.findIndex(b=>b.value===n)+1)%H.length];return n=p.value,e.className=qe(n),qt(n),p}},c=document.createElement("button");c.className="launcher",c.type="button",c.innerHTML=`<span class="ico" aria-hidden="true"><span class="when-closed"><span class="orb"></span></span><span class="when-open">${Ot}</span></span><span>Report a bug</span>`,c.setAttribute("aria-haspopup","dialog"),c.setAttribute("aria-expanded","false");let l=null;c.addEventListener("click",()=>{if(l){l.close();return}l=h()});function h(){j(),f();let p=null,b=!1;const I=()=>{b=!0,c.removeAttribute("aria-busy"),l=null},g={close:()=>p?p.close():I(),destroy:()=>p?p.destroy():I()};return c.setAttribute("aria-busy","true"),_e(t.config.chunkBase).then(({openPanel:S})=>{b||(c.removeAttribute("aria-busy"),r.classList.add("over"),c.setAttribute("aria-expanded","true"),p=S({root:o,host:e,dock:r,client:t,preloadCall:y,themeControls:a,onClose:()=>{l=null,r.classList.remove("over"),c.setAttribute("aria-expanded","false")}}))},()=>{b||(I(),M())}),g}const u=()=>{_e(t.config.chunkBase).catch(()=>{})};for(const p of["pointerenter","touchstart","focus"])c.addEventListener(p,u,{once:!0,passive:!0});const B=We(u);function y(){J(t.config.chunkBase).catch(()=>{})}let w=null;function M(){j(),w=document.createElement("div"),w.className="msg err loadfail",w.setAttribute("role","alert"),w.innerHTML=`${je}<span>The report form didn't load. Check your connection and try again.</span><button type="button" data-act="retry">Try again</button><button type="button" data-act="dismiss" aria-label="Dismiss">${Oe}</button>`,w.querySelector('[data-act="retry"]').addEventListener("click",()=>{c.focus(),l||(l=h())}),w.querySelector('[data-act="dismiss"]').addEventListener("click",()=>{c.focus(),j()}),r.prepend(w)}function j(){w==null||w.remove(),w=null}let A=null;function D(p){f(),A=zt(p,{where:"launcher",onDismiss:b=>{t.dismissAnnouncement(b),c.focus(),f()}}),w?w.after(A):r.prepend(A)}function f(){A==null||A.remove(),A=null}const k=t.config.announcements===!1?()=>{}:We(()=>{t.announcements().then(p=>{const b=p.find(I=>I.placement==="launcher");b&&!l&&e.isConnected&&D(b)}).catch(()=>{})});return r.append(c),o.appendChild(r),document.body.appendChild(e),t.widgetControls={open:()=>{l||c.click()},close:()=>{l==null||l.close()},isOpen:()=>!!l},()=>{B(),k(),l==null||l.destroy(),e.remove(),t.widgetControls=null}}function Yt(t){return t==="dark"||t==="light"?t:"auto"}function qe(t){return t==="dark"?"bc-dark":t==="light"?"bc-light":"bc-auto"}function We(t){let e=()=>{};const n=()=>{if(typeof requestIdleCallback=="function"){const o=requestIdleCallback(t,{timeout:5e3});e=()=>cancelIdleCallback(o)}else{const o=setTimeout(t,1500);e=()=>clearTimeout(o)}};return document.readyState==="complete"?n():(window.addEventListener("load",n,{once:!0}),e=()=>window.removeEventListener("load",n)),()=>e()}const Vt="Too many requests are being sent from here at the moment. Please try again in a minute.";function _(t){return t||Vt}const Zt=typeof window<"u"&&window.fetch?window.fetch.bind(window):null,Gt=typeof XMLHttpRequest<"u"?XMLHttpRequest.prototype.open:null,Qt=typeof XMLHttpRequest<"u"?XMLHttpRequest.prototype.send:null,en=["image/png","image/jpeg","image/webp","image/gif","video/webm","video/mp4","audio/webm","audio/ogg","audio/mpeg","audio/mp4","audio/wav","application/pdf","text/plain","text/csv","application/json","application/zip","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],Je=["image/png","image/jpeg","image/webp","video/webm","video/mp4"];function de(t,e=en){const n=String(t||"").split(";")[0].trim().toLowerCase();return e.includes(n)?n:null}async function tn({apiBase:t,apiKey:e,blob:n,mime:o,onProgress:s}){var l;const i=de(o||n.type);if(!i)throw new Error(`[BugCatch] ${o||n.type||"that file"} can't be attached.`);const r=await Zt(`${t}/ingest/presign`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e},body:JSON.stringify({mime:i})});if(r.status===429){let h="";try{h=((l=await r.json())==null?void 0:l.message)||""}catch{}throw new Error(`[BugCatch] ${_(typeof h=="string"?h:"")}`)}if(!r.ok)throw new Error(`[BugCatch] could not start the upload (HTTP ${r.status}).`);const{key:a,uploadUrl:c}=await r.json();return await nn(c,n,i,s),{storageKey:a,mime:i}}function nn(t,e,n,o){return new Promise((s,i)=>{const r=new XMLHttpRequest;Gt.call(r,"PUT",t,!0),r.setRequestHeader("Content-Type",n),r.upload.onprogress=a=>{a.lengthComputable&&(o==null||o(a.loaded/a.total))},r.onload=()=>{r.status>=200&&r.status<300?s():i(new Error(`[BugCatch] upload failed (HTTP ${r.status}).`))},r.onerror=()=>i(new Error("[BugCatch] the browser blocked the upload to storage. If this is a new environment, the media bucket is probably missing its CORS policy.")),r.onabort=()=>i(new Error("[BugCatch] upload cancelled.")),Qt.call(r,e)})}const Y="bugcatch.watch",Ye=[2e3,5e3,15e3,3e4,6e4],on=5e3;let z=null;function rn(t){z=t||null}const he=()=>z?`${Y}:${z}`:Y;function V(){return z?`?projectId=${encodeURIComponent(z)}`:""}function C(){try{const t=window.localStorage;return(t==null?void 0:t.getItem(he()))||(t==null?void 0:t.getItem(Y))||null}catch{return null}}function fe(t){var e;if(t)try{(e=window.localStorage)==null||e.setItem(he(),t)}catch{}}function N(){var t,e;try{(t=window.localStorage)==null||t.removeItem(he()),(e=window.localStorage)==null||e.removeItem(Y)}catch{}Ve()}const Z="bugcatch.unread";function sn(t){return[(t==null?void 0:t.bugId)||"report",(t==null?void 0:t.kind)||"status",(t==null?void 0:t.at)||""].join("|")}function F(){var t;try{const e=(t=window.localStorage)==null?void 0:t.getItem(Z),n=e?JSON.parse(e):[];return Array.isArray(n)?n.filter(o=>o&&typeof o.id=="string"):[]}catch{return[]}}function G(t){var e,n;try{t.length?(e=window.localStorage)==null||e.setItem(Z,JSON.stringify(t)):(n=window.localStorage)==null||n.removeItem(Z)}catch{}}function an(t){const e={...t,id:sn(t)},n=F().filter(o=>o.id!==e.id);return n.push(e),G(n.slice(-20)),e}function cn(t){const e=F().filter(n=>n.id!==t);return G(e),e}function ln(t){const e=F().filter(n=>n.bugId!==t);return G(e),e}function Ve(){return G([]),[]}function un(t,e){let n=t,o=n.indexOf(`
|
|
292
304
|
|
|
293
305
|
`);for(;o!==-1;){const s=n.slice(0,o);n=n.slice(o+2);const i=s.split(`
|
|
294
306
|
`).filter(r=>r.startsWith("data:")).map(r=>r.slice(5).trim()).join(`
|
|
295
307
|
`);if(i)try{e(JSON.parse(i))}catch{}o=n.indexOf(`
|
|
296
308
|
|
|
297
|
-
`)}return n}async function nn({apiBase:t}){const e=S();if(!e)return{reporter:null,reports:[]};const n=await fetch(`${t}/ingest/watch/reports${ae()}`,{headers:{Authorization:`Bearer ${e}`}});if(n.status===401)return U(),{reporter:null,reports:[]};if(!n.ok)throw new Error(`[BugCatch] could not load your reports (HTTP ${n.status})`);return n.json()}async function on({apiBase:t,bugId:e}){const n=S();if(!n)return null;const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}${ae()}`,{headers:{Authorization:`Bearer ${n}`}});if(o.status===401)return U(),null;if(o.status===404)return null;if(!o.ok)throw new Error(`[BugCatch] could not load that report (HTTP ${o.status})`);return o.json()}async function rn({apiBase:t,bugId:e,body:n,attachments:o}){const s=S();if(!s)throw new Error("[BugCatch] nothing filed from this browser yet.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/messages`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({...n?{body:n}:{},...o!=null&&o.length?{attachments:o}:{}})});if(i.status===401)throw U(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!i.ok){let r="";try{const a=await i.json();r=Array.isArray(a.message)?a.message.join(", "):a.message||""}catch{}throw i.status===429?new Error(N(r)):new Error(r||`[BugCatch] could not send that (HTTP ${i.status}).`)}return i.json()}async function sn({apiBase:t,apiKey:e,projectId:n}){const o={agent:!1,live:!1};try{const s=await fetch(`${t}/ingest/calls?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!s.ok)return o;const i=await s.json();return i!=null&&i.available?i.kinds&&typeof i.kinds=="object"?{agent:!1,live:!!i.kinds.live}:{agent:!1,live:i.kind==="live"}:o}catch{return o}}async function an({apiBase:t,apiKey:e,token:n,payload:o,watchToken:s}){const i=await fetch(`${t}/ingest/calls`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e,...n?{"X-BugCatch-Session":n}:{}},body:JSON.stringify(s?{...o,watchToken:s}:o)});if(!i.ok){let r="";try{const c=await i.json();r=Array.isArray(c.message)?c.message.join(", "):c.message||""}catch{}const a=new Error(i.status===429?N(r):r||`[BugCatch] the call could not be started (HTTP ${i.status}).`);throw a.status=i.status,a}return i.json()}async function Fe({apiBase:t,bugId:e}){const n=S();if(!n)return!1;try{const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{headers:{Authorization:`Bearer ${n}`}});if(!o.ok)return!1;const s=await o.json();return!!(s!=null&&s.offered)}catch{return!1}}async function cn({apiBase:t,bugId:e}){const n=S();if(!n)throw new Error("[BugCatch] nothing filed from this browser yet.");const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(o.status===401)throw U(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!o.ok){let s="";try{const i=await o.json();s=Array.isArray(i.message)?i.message.join(", "):i.message||""}catch{}throw new Error(s||`[BugCatch] the call could not be started (HTTP ${o.status}).`)}return o.json()}async function ln({apiBase:t,bugId:e,callId:n}){const o=S();if(o)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/give-up`,{method:"POST",headers:{Authorization:`Bearer ${o}`}})}catch{}}async function un({apiBase:t,bugId:e,callId:n}){const o=S();if(!o)throw new Error("[BugCatch] nothing filed from this browser yet.");const s=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/answer`,{method:"POST",headers:{Authorization:`Bearer ${o}`}});if(s.status===401)throw U(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(s.status===409)throw new Error("[BugCatch] that call is no longer ringing.");if(!s.ok){let i="";try{const r=await s.json();i=Array.isArray(r.message)?r.message.join(", "):r.message||""}catch{}throw new Error(i||`[BugCatch] the call could not be answered (HTTP ${s.status}).`)}return s.json()}async function Xe({apiBase:t,bugId:e,callId:n}){const o=S();if(o)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/decline`,{method:"POST",headers:{Authorization:`Bearer ${o}`}})}catch{}}function dn({apiBase:t,onUpdate:e}){let n=!0,o=0,s=null;async function i(){const r=S();if(!r)throw new Error("nothing filed from this browser yet");s=new AbortController;const a=await fetch(`${t}/ingest/watch/stream${ae()}`,{headers:{Authorization:`Bearer ${r}`,Accept:"text/event-stream"},signal:s.signal});if(a.status===401)throw n=!1,U(),new Error("subscription no longer valid");if(!a.ok||!a.body)throw new Error(`stream failed (${a.status})`);const c=Date.now(),l=a.body.getReader(),h=new TextDecoder;let u="";try{for(;;){const{value:E,done:x}=await l.read();if(x)break;u+=h.decode(E,{stream:!0}),u=tn(u,m=>{if(m.type!=="ping")try{e(m)}catch{}})}}finally{Date.now()-c>=Yt&&(o=0)}}return(async()=>{for(;n;){try{await i()}catch(a){if((a==null?void 0:a.name)==="AbortError")return}if(!n)return;const r=He[Math.min(o,He.length-1)];o+=1,await new Promise(a=>setTimeout(a,r))}})(),()=>{n=!1,s==null||s.abort(),s=null}}const hn={OPEN:"is open",IN_PROGRESS:"is being worked on",RESOLVED:"has been fixed",CLOSED:"has been closed"},fn={status:null,severity:"#e8912a",assignment:"#4da3ff",reply:"#35b87f"};function qe(t){return t!=null&&t.summary?t.summary:`Your report ${hn[t==null?void 0:t.status]||"was updated"}`}function pn(t){var e;return(t==null?void 0:t.kind)==="reply"&&((e=t.reply)!=null&&e.body)?`${t.reply.author?`${t.reply.author}: `:""}${t.reply.body}`:(t==null?void 0:t.title)||""}function gn(t){const e=Date.parse(t||"");if(!Number.isFinite(e))return"";const n=Math.round((Date.now()-e)/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const o=Math.round(n/60);if(o<24)return`${o}h ago`;const s=Math.round(o/24);return s===1?"yesterday":`${s}d ago`}function mn(){var t;try{const e=document.querySelector('[data-bugcatch="widget"]'),n=(t=e==null?void 0:e.shadowRoot)==null?void 0:t.querySelector(".dock"),o=(n==null?void 0:n.getBoundingClientRect().height)||0;return o?Math.round(o)+12:0}catch{return 0}}function wn({accent:t="#4F46E5",position:e="bottom-right",onRead:n=null,onReadAll:o=null,onCall:s=null}={}){const[i,r]=String(e).split("-"),a=i==="top",c=r==="left",l=new Map;let h=null,u=null;function E(){return h!=null&&h.isConnected||(h=document.createElement("div"),h.setAttribute("data-bugcatch","updates"),h.style.cssText=["position:fixed",`${a?"top":"bottom"}:${20+mn()}px`,`${c?"left":"right"}:20px`,"z-index:2147482998","display:flex","flex-direction:column","gap:10px",`align-items:${c?"flex-start":"flex-end"}`,"width:min(320px,calc(100vw - 40px))","pointer-events:none"].join(";"),document.body.appendChild(h)),h}function x(f){if(!f._bcShown){f.remove();return}f.style.opacity="0",f.style.transform=`translateY(${a?-8:8}px)`,setTimeout(()=>f.remove(),250)}function m(f,v){const y=document.createElement("button");return y.type="button",y.textContent=f,y.style.cssText=["padding:5px 11px",`border:${v?"0":"1px solid rgba(236,238,242,.24)"}`,"border-radius:6px",`background:${v?t:"transparent"}`,`color:${v?"#fff":"#eceef2"}`,"font:600 12px/1.4 inherit","cursor:pointer","white-space:nowrap"].join(";"),y}function O(f){var p;const v=document.createElement("div");v.setAttribute("role","status"),v.style.cssText=["box-sizing:border-box","width:100%","padding:12px 14px","border-radius:10px","background:#1b1e26","color:#eceef2",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 12px 30px rgba(0,0,0,0.45)",`border-left:3px solid ${fn[f==null?void 0:f.kind]||t}`,"opacity:0",`transform:translateY(${a?-8:8}px)`,"transition:opacity .2s ease,transform .2s ease","pointer-events:auto"].join(";");const y=document.createElement("div");y.style.cssText="font-weight:600;margin-bottom:2px",y.textContent=qe(f);const $=document.createElement("div");$.style.cssText=(f==null?void 0:f.kind)==="reply"?"color:#a4abba;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden":"color:#a4abba",$.textContent=pn(f);const g=document.createElement("div");g.style.cssText="display:flex;align-items:center;gap:8px;margin-top:10px;flex-wrap:wrap";const k=document.createElement("span");k.style.cssText="color:#7b8394;font-size:11px;margin-right:auto",k.textContent=gn(f==null?void 0:f.at);const I=m("Mark as read",!1);if(I.setAttribute("aria-label",`Mark as read: ${qe(f)}`),I.addEventListener("click",()=>n==null?void 0:n(f.id)),g.append(k,I),(p=f==null?void 0:f.call)!=null&&p.offered&&typeof s=="function"){const w=m("Talk it through",!0);w.addEventListener("click",()=>s(f)),g.insertBefore(w,I)}return v.append(y,$,g),v}function L(f){const v=document.createElement("div");v.style.cssText=["box-sizing:border-box","width:100%","display:flex","align-items:center","gap:8px","padding:8px 12px","border-radius:10px","background:#1b1e26","color:#a4abba",'font:12px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 12px 30px rgba(0,0,0,0.45)","pointer-events:auto"].join(";");const y=document.createElement("span");y.style.cssText="margin-right:auto",y.textContent=`${f} more update${f===1?"":"s"}`;const $=m("Mark all as read",!1);return $.style.cssText+=";padding:4px 9px",$.addEventListener("click",()=>o==null?void 0:o()),v.append(y,$),v}return{render(f){const v=Array.isArray(f)?f:[];if(!v.length){for(const w of l.values())x(w);l.clear(),u==null||u.remove(),u=null,h==null||h.remove(),h=null;return}const y=v.slice(-3),$=new Set(y.map(w=>w.id)),g=E();for(const[w,M]of l)$.has(w)||(x(M),l.delete(w));const k=[];for(const w of y){if(l.has(w.id))continue;const M=O(w);l.set(w.id,M),k.push(M)}const I=a?[...y].reverse():y;for(const w of I)g.appendChild(l.get(w.id));const p=v.length-y.length;p>0?(u==null||u.remove(),u=L(p),a?g.appendChild(u):g.insertBefore(u,g.firstChild)):(u==null||u.remove(),u=null),requestAnimationFrame(()=>{for(const w of k)w.isConnected&&(w._bcShown=!0,w.style.opacity="1",w.style.transform="translateY(0)")})},destroy(){l.clear(),u=null,h==null||h.remove(),h=null}}}async function bn({apiBase:t,apiKey:e,projectId:n,sessionToken:o}){try{const s=await fetch(`${t}/ingest/known-issues?projectId=${encodeURIComponent(n)}`,{headers:le(e,o)});if(!s.ok)return[];const i=await s.json();return Array.isArray(i==null?void 0:i.issues)?i.issues:[]}catch{return[]}}async function yn({apiBase:t,apiKey:e,projectId:n,q:o,sessionToken:s,signal:i}){try{const r=`${t}/ingest/known-issues/match?projectId=${encodeURIComponent(n)}&q=${encodeURIComponent(o)}`,a=await fetch(r,{headers:le(e,s),signal:i});if(!a.ok)return[];const c=await a.json();return Array.isArray(c==null?void 0:c.issues)?c.issues:[]}catch{return[]}}async function xn({apiBase:t,apiKey:e,projectId:n,bugId:o,reporterEmail:s,reporterName:i,metadata:r,logs:a,sessionToken:c}){const l=S(),h=await fetch(`${t}/ingest/known-issues/${encodeURIComponent(o)}/join`,{method:"POST",headers:le(e,c),body:JSON.stringify({projectId:n,reporterEmail:s,reporterName:i,metadata:r,logs:a,...l?{watchToken:l}:{}})});if(!h.ok)throw new Error(await kn(h));const u=await h.json();return u!=null&&u.watchToken&&ce(u.watchToken),u}function le(t,e){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function kn(t){let e="";try{const n=await t.json();e=Array.isArray(n.message)?n.message.join(", "):n.message||""}catch{}return t.status===429?N(e):e||`Could not add you to this issue (HTTP ${t.status})`}async function vn({apiBase:t,bugId:e,...n}){const o=S();if(!o)throw new Error("This browser cannot access that report.");const s=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/verification`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(n)}),i=await s.json().catch(()=>({}));if(!s.ok)throw new Error(i.message||"Could not record feedback. Please refresh and try again.");return i}const Cn="bugcatch.session.",ue=t=>`${Cn}${t}`,de=new Map;function j(t){var e;if(!t)return null;try{const n=(e=window.localStorage)==null?void 0:e.getItem(ue(t));if(n){const o=JSON.parse(n);if(o!=null&&o.token)return o}}catch{}return de.get(t)||null}function In(t,e){var o;if(!t||!(e!=null&&e.token))return;const n={token:e.token,email:e.email||null,name:e.name||null};de.set(t,n);try{(o=window.localStorage)==null||o.setItem(ue(t),JSON.stringify(n))}catch{}}function he(t){var e;if(t){de.delete(t);try{(e=window.localStorage)==null||e.removeItem(ue(t))}catch{}}}function J({apiKey:t,token:e}){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function We(t){let e="";try{const n=await t.json();e=Array.isArray(n.message)?n.message.join(", "):n.message||""}catch{}return t.status===429?N(e):e||`Request failed (HTTP ${t.status})`}async function Sn({apiBase:t,apiKey:e,projectId:n,token:o}){const s={mode:"off",signedIn:null,signedOutReason:null};try{const i=await fetch(`${t}/ingest/login?projectId=${encodeURIComponent(n)}`,{headers:J({apiKey:e,token:o})});if(!i.ok)return s;const r=await i.json();return{mode:r.mode==="optional"||r.mode==="required"?r.mode:"off",signedIn:r.signedIn||null,signedOutReason:r.signedOutReason||null}}catch{return s}}async function Bn({apiBase:t,apiKey:e,projectId:n,email:o,name:s}){const i=await fetch(`${t}/ingest/login/start`,{method:"POST",headers:J({apiKey:e}),body:JSON.stringify({projectId:n,email:o,...s?{name:s}:{}})});if(!i.ok)throw new Error(await We(i));return i.json()}async function $n({apiBase:t,apiKey:e,projectId:n,email:o,code:s}){const i=await fetch(`${t}/ingest/login`,{method:"POST",headers:J({apiKey:e}),body:JSON.stringify({projectId:n,email:o,code:s})});if(!i.ok)throw new Error(await We(i));const r=await i.json(),a={token:r.sessionToken,email:r.email,name:r.name};return In(n,a),a}async function En({apiBase:t,apiKey:e,projectId:n,token:o}){if(he(n),!o)return{signedOut:!0};try{await fetch(`${t}/ingest/logout`,{method:"POST",headers:J({apiKey:e,token:o}),body:JSON.stringify({projectId:n})})}catch{}return{signedOut:!0}}let Je=!1;if(typeof window<"u"&&window.addEventListener)for(const t of["pointerdown","keydown","touchstart"])window.addEventListener(t,()=>{Je=!0},{once:!0,capture:!0,passive:!0});function An(){return Je}async function Tn({apiBase:t,apiKey:e,projectId:n}){const o={policy:"off",fields:[]};try{const s=await fetch(`${t}/ingest/reference-fields?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!s.ok)return o;const i=await s.json(),r=i.policy==="optional"||i.policy==="required"?i.policy:"off",a=Array.isArray(i.fields)?i.fields:[];return a.length?{policy:r,fields:a}:o}catch{return o}}async function jn({apiBase:t,apiKey:e,projectId:n}){try{const o=await fetch(`${t}/ingest/agent-issues?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!o.ok)return[];const s=await o.json();return(Array.isArray(s==null?void 0:s.issues)?s.issues:[]).filter(i=>i&&typeof i.key=="string"&&typeof i.title=="string").map(i=>({key:i.key,title:i.title,hint:typeof i.hint=="string"?i.hint:""}))}catch{return[]}}const On=5*6e4,Ye="bugcatch:announcements:seen",Ln=40,Mn=["info","success","warning","critical"],Ve=t=>`bugcatch:announcements:${t}`;async function Rn({apiBase:t,apiKey:e,projectId:n,fresh:o=!1}){var s;if(!o){const i=Hn(n);if(i)return i}try{const i=await fetch(`${t}/ingest/announcements?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}}),r=i.ok?Dn((s=await i.json())==null?void 0:s.announcements):[];return zn(n,r),r}catch{return[]}}function Kn(t,{on:e=Pn(),seen:n=Ge()}={}){return(t||[]).filter(o=>_n(o,e)&&!(o.dismissible&&n.includes(Ze(o))))}function Un(t){if(!(!(t!=null&&t.id)||!t.dismissible))try{const e=Ze(t),n=[...Ge().filter(o=>o!==e),e];localStorage.setItem(Ye,JSON.stringify(n.slice(-Ln)))}catch{}}function Nn(t){return typeof t!="string"||!t||t.startsWith("//")?null:t.startsWith("/")||/^(https?:\/\/|mailto:)./i.test(t)?t:null}function Pn(t=new Date){const e=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}`}function _n(t,e){return!(t.startsOn&&e<t.startsOn||t.endsOn&&e>t.endsOn)}function Ze(t){return`${t.id}#${t.revision||0}`}function Dn(t){return(Array.isArray(t)?t:[]).filter(e=>e&&typeof e.id=="string"&&typeof e.title=="string"&&e.title.trim()).map(e=>{const n=e.placement==="launcher"?"launcher":"panel",o=Nn(e.ctaHref);return{id:e.id,revision:Number.isInteger(e.revision)?e.revision:0,title:e.title,body:typeof e.body=="string"?e.body:"",tone:Mn.includes(e.tone)?e.tone:"info",ctaLabel:o&&typeof e.ctaLabel=="string"?e.ctaLabel:"",ctaHref:o&&typeof e.ctaLabel=="string"?o:"",placement:n,dismissible:n==="launcher"||e.dismissible!==!1,startsOn:typeof e.startsOn=="string"?e.startsOn:"",endsOn:typeof e.endsOn=="string"?e.endsOn:""}})}function Ge(){try{const t=JSON.parse(localStorage.getItem(Ye)||"[]");return Array.isArray(t)?t.filter(e=>typeof e=="string"):[]}catch{return[]}}function Hn(t){try{const e=JSON.parse(localStorage.getItem(Ve(t))||"null");if(!e||!Array.isArray(e.list)||typeof e.at!="number")return null;const n=Date.now()-e.at;return n>=0&&n<On?e.list:null}catch{return null}}function zn(t,e){try{localStorage.setItem(Ve(t),JSON.stringify({at:Date.now(),list:e}))}catch{}}const Y=120,Fn=500,V=30,Xn=1e3,fe={loanId:["loanId","loanNumber"],applicationId:["applicationId"],customerNumber:["customerNumber","customerId"]},qn=/[\u0000-\u001f\u007f]/;function Wn(t){if(typeof t=="number")return Number.isFinite(t)?String(t):null;if(typeof t!="string")return null;const e=t.trim();return!e||e.length>Y||qn.test(e)?null:e}function T(t){return t===null?"null":Array.isArray(t)?"an array":typeof t=="object"?"an object":`a ${typeof t}`}function pe(t,e,n,o,s){for(const i of n){if(!(i in t)||t[i]===void 0||t[i]===null||t[i]==="")continue;const r=Wn(t[i]);if(r)return r;const a=t[i];s(typeof a=="string"&&a.trim().length>Y?`${o}.${i} is longer than ${Y} characters and was dropped — pass the identifier itself, not a sentence or a URL.`:`${o}.${i} should be a string or number, got ${T(a)} — it was dropped.`)}return null}function Qe(t){if(t===null||typeof t=="boolean")return{ok:!0,value:t};if(typeof t=="number")return Number.isFinite(t)?{ok:!0,value:t}:{ok:!1};if(typeof t=="string")return{ok:!0,value:t.slice(0,Fn)};if(typeof t=="object")try{const e=JSON.stringify(t);if(e&&e.length<=Xn)return{ok:!0,value:JSON.parse(e)}}catch{}return{ok:!1}}const et=["email","name","phone"],Jn=new Set(["id","userId",...et,...Object.values(fe).flat()]);function tt(t,e=()=>{}){if(t==null)return null;if(typeof t!="object"||Array.isArray(t))return e(`identify() takes an object like { id, email, name } or null, got ${T(t)} — ignored.`),null;const n={};try{const o=pe(t,"id",["id","userId"],"identify()",e);o&&(n.id=o);for(const i of et){const r=t[i];if(r==null||r==="")continue;if(i==="phone"&&typeof r=="number"&&Number.isFinite(r)){n.phone=String(r);continue}if(typeof r!="string"){e(`identify().${i} should be a string, got ${T(r)} — it was dropped.`);continue}const a=r.trim().slice(0,i==="name"?200:Y);a&&(i==="email"&&!a.includes("@")&&e(`identify().email "${a}" does not look like an email address — reports cannot be threaded or followed up without one.`),n[i]=a)}for(const[i,r]of Object.entries(fe)){const a=pe(t,i,r,"identify()",e);a&&(n[i]=a)}let s=0;for(const[i,r]of Object.entries(t)){if(Jn.has(i)||r===void 0||typeof r=="function")continue;if(s>=V){e(`identify() was given more than ${V} extra fields; the rest were dropped.`);break}const a=Qe(r);if(!a.ok){e(`identify().${i} could not be sent (${T(r)} too large or not serialisable) — dropped.`);continue}n[i]=a.value,s+=1}}catch{}return!n.id&&!n.email&&e("identify() was called without an id or email — reports will not be attributed to anyone, and nothing can be looked up by user."),n}function nt(t,e,n=()=>{}){if(e===null)return{};const o={...t||{}};if(e===void 0)return o;if(typeof e!="object"||Array.isArray(e))return n(`setContext() takes an object like { loanId, screen } or null, got ${T(e)} — ignored.`),o;try{const s=new Map;for(const[i,r]of Object.entries(fe))for(const a of r)s.set(a,i);for(const[i,r]of Object.entries(e)){const a=s.get(i);if(r==null){delete o[a||i];continue}if(a){const l=pe({[i]:r},a,[i],"setContext()",n);l?o[a]=l:delete o[a];continue}if(typeof r=="function")continue;if(!(i in o)&&Object.keys(o).length>=V){n(`setContext() holds at most ${V} keys; "${i}" was dropped.`);continue}const c=Qe(r);if(!c.ok){n(`setContext().${i} could not be sent (${T(r)} too large or not serialisable) — dropped.`);continue}o[i]=c.value}}catch{}return o}const ot=["apiBase","apiKey","projectId","consoleLimit","networkLimit","captureConsole","captureNetwork","captureErrors","widget","widgetPosition","theme","accent","attachments","maxAttachments","maxAttachmentBytes","maxRecordingMs","beforeSend","user","context","updates","updateToast","onUpdate","voice","onCallState","onIncomingCall","onReportSubmitted","onAssistantPhase","onError","debug","drafts","knownIssues","agentIssues","release","environment","buildId","chunkBase","announcements"],Yn=["beforeSend","onUpdate","onCallState","onIncomingCall","onReportSubmitted","onAssistantPhase","onError"];function Vn(t){const e=t.toLowerCase().replace(/[-_]/g,"");return ot.find(n=>n.toLowerCase()===e)||null}const it=/^(your[_-]|<|xxx|todo|changeme)/i,Zn=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Gn(t,{pageHost:e=""}={}){const n=[],o=[];if(!t||typeof t!="object")return n.push("init() takes an options object: BugCatch.init({ apiBase, apiKey, projectId })."),{errors:n,warnings:o};const{apiKey:s,projectId:i,apiBase:r}=t;s?typeof s!="string"?n.push(`apiKey must be a string, got ${T(s)}.`):it.test(s)?n.push(`apiKey is still the placeholder "${s}" — paste the key you saved when you created it.`):Zn.test(s)?o.push("apiKey looks like a project id — did you swap apiKey and projectId?"):s.startsWith("bc_")||o.push('apiKey does not look like a BugCatch key (they start with "bc_live_") — reports will be refused with HTTP 401.'):n.push("apiKey is required — create one under Workspace Settings → API Keys."),i?typeof i!="string"?n.push(`projectId must be a string, got ${T(i)}.`):it.test(i)?n.push(`projectId is still the placeholder "${i}".`):i.startsWith("bc_")?o.push("projectId looks like an API key — did you swap apiKey and projectId?"):/\s/.test(i)&&o.push("projectId contains whitespace — check it was copied cleanly."):n.push("projectId is required — copy it from Project Settings → Web SDK."),r==null?!e||/^(localhost|127\.|0\.0\.0\.0|\[::1\])/.test(e)||o.push("apiBase is not set, so reports go to http://localhost:3000 — set apiBase to your BugCatch API URL."):(typeof r!="string"||!/^https?:\/\//.test(r))&&o.push(`apiBase should be an absolute http(s) URL, got ${JSON.stringify(r)}.`);for(const a of Object.keys(t)){if(ot.includes(a))continue;const c=Vn(a);o.push(c?`unknown option "${a}" — did you mean "${c}"?`:`unknown option "${a}" is ignored.`)}for(const a of Yn){const c=t[a];c!=null&&typeof c!="function"&&o.push(`${a} should be a function, got ${T(c)} — it will not be called.`)}return{errors:n,warnings:o}}function Qn(t){return typeof t=="string"?t.replace(/\/+$/,""):t}const D={name:"@sphoro/bugcatch-web-sdk",version:"0.18.0"},H={apiBase:"http://localhost:3000",apiKey:null,projectId:null,consoleLimit:100,networkLimit:50,captureConsole:!0,captureNetwork:!0,captureErrors:!0,widget:!0,widgetPosition:"bottom-right",theme:"auto",accent:"#4F46E5",announcements:!0,attachments:!0,maxAttachments:5,maxAttachmentBytes:25*1024*1024,maxRecordingMs:12e4,beforeSend:null,user:null,updates:!0,updateToast:!0,onUpdate:null,voice:!0,onCallState:null,onIncomingCall:null,onReportSubmitted:null,onAssistantPhase:null,onError:null,context:null,chunkBase:null,debug:!1};function eo(t){const e=S();return e?{...t,watchToken:e}:t}class rt{constructor(){at(this,d);this.config={...H},this.started=!1,this.teardown=[],this.consoleBuffer=z(H.consoleLimit),this.networkBuffer=z(H.networkLimit),this.stopWatching=null,this.notifier=null,this.call=null,this.callStarting=!1,this.ringing=null,this.listeners=new Map,this.context={},this.warned=new Set,this.phases=new Map}warn(e){this.warned.has(e)||(this.warned.add(e),console.warn(`[BugCatch] ${e}`))}debugLog(...e){this.config.debug&&console.info("[BugCatch]",...e)}init(e={}){if(this.started)return console.warn("[BugCatch] init() called twice — ignoring the second call."),this;const{errors:n,warnings:o}=Gn(e,{pageHost:typeof location<"u"?location.hostname:""});if(n.length)throw new Error(`[BugCatch] ${n[0]}`);for(const i of o)this.warn(i);const s=this.config.user;return this.config={...H,...e,apiBase:Qn(e.apiBase??H.apiBase)},this.config.user=e.user!==void 0?tt(e.user,i=>this.warn(i.replace("identify()","init({ user })"))):s||null,e.context&&this.setContext(e.context),this.consoleBuffer=z(this.config.consoleLimit),this.networkBuffer=z(this.config.networkLimit),this.config.captureConsole&&this.teardown.push(kt(this.consoleBuffer)),this.config.captureNetwork&&this.teardown.push(vt(this.networkBuffer)),this.config.captureErrors&&this.teardown.push(Ct(this.consoleBuffer)),Vt(this.config.projectId),this.config.widget&&this.teardown.push(_t(this)),this.config.updates&&S()&&(this.startWatching(),queueMicrotask(()=>b(this,d,R).call(this))),this.started=!0,b(this,d,ct).call(this),this.debugLog("initialised",{version:D.version,apiBase:this.config.apiBase,projectId:this.config.projectId,user:this.config.user,context:this.context}),this}startWatching(){if(this.stopWatching)return this;this.stopWatching=dn({apiBase:this.config.apiBase,onUpdate:n=>{if(n!=null&&n.incomingCall){b(this,d,ht).call(this,n);return}if(n!=null&&n.callWithdrawn){b(this,d,ee).call(this,n.callWithdrawn.callId);return}const o=Gt(n);typeof this.config.onUpdate=="function"&&this.config.onUpdate(o),this.emit("update",o),b(this,d,R).call(this)}}),this.teardown.push(()=>{var n;return(n=this.stopWatching)==null?void 0:n.call(this)}),this.teardown.push(()=>b(this,d,ee).call(this));const e=n=>{(n.key===q||n.key===null)&&b(this,d,R).call(this)};return window.addEventListener("storage",e),this.teardown.push(()=>window.removeEventListener("storage",e)),this}on(e,n){if(typeof n!="function")return()=>{};const o=this.listeners.get(e)||new Set;return o.add(n),this.listeners.set(e,o),()=>this.off(e,n)}off(e,n){var o;return(o=this.listeners.get(e))==null||o.delete(n),this}emit(e,n){for(const o of this.listeners.get(e)||[])try{o(n)}catch(s){console.error(`[BugCatch] a '${e}' listener threw:`,s)}}unreadUpdates(){return _()}markUpdateRead(e){return Qt(e),b(this,d,R).call(this),this}markReportRead(e){return en(e),b(this,d,R).call(this),this}markUpdatesRead(){return ze(),b(this,d,R).call(this),this}async verifyFix(e,{result:n,resolvedAt:o,note:s}){const i=n==="STILL_HAPPENING"?await b(this,d,Q).call(this,{}):{};return vn({apiBase:this.config.apiBase,bugId:e,result:n,resolvedAt:o,note:s,metadata:i.metadata,logs:i.logs})}async myReport(e){const n=await on({apiBase:this.config.apiBase,bugId:e});return b(this,d,lt).call(this,e,n==null?void 0:n.assistant),n}replyToReport(e,{body:n,attachments:o}={}){return rn({apiBase:this.config.apiBase,bugId:e,body:n,attachments:o})}async canCallNow(){return!!await this.callKind()}async callKind(){return(await this.callKinds()).live?"live":null}async callKinds(){var n;const e={agent:!1,live:!1};return!this.config.voice||!((n=this.config.user)!=null&&n.email)?e:this.kinds!==void 0?this.kinds:(this.kinds=await sn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.kinds)}canCall(e){return this.config.voice?Fe({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}async startCall(e){var n;if(!this.config.voice)throw new Error("[BugCatch] calling is switched off.");if(this.call||this.callStarting)throw new Error("[BugCatch] a call is already running.");this.callStarting=!0;try{if(!await this.callKind())throw new Error((n=this.config.user)!=null&&n.email?"[BugCatch] calling is not available on this project.":"[BugCatch] a call needs to know who is calling — call identify() with an email first.");return await b(this,d,dt).call(this,e)}finally{this.callStarting=!1}}startLiveCall(e){return this.startCall(e)}canCallTeam(e){return this.config.voice?Fe({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}endCall(){var e;return(e=this.call)==null||e.hangUp(),this.call=null,this}myReports(){return nn({apiBase:this.config.apiBase})}hasReports(){return!!S()}forgetReports(){var e;return(e=this.stopWatching)==null||e.call(this),this.stopWatching=null,this.endCall(),U(),b(this,d,R).call(this),this}identify(e){const n=tt(e,o=>this.warn(o));return e!=null&&!n?this:(this.config.user=n,this.debugLog("identify",n),this)}setContext(e){return this.context=nt(this.context,e,n=>this.warn(n)),this.debugLog("context",this.context),this}getContext(){return{...this.context}}open(){return this.started?this.widgetControls?(this.widgetControls.open(),this):(this.warn("open() needs the built-in widget; it was turned off with widget: false."),this):(this.warn("open() was called before init() — nothing to open yet."),this)}close(){var e;return(e=this.widgetControls)==null||e.close(),this}isOpen(){var e;return!!((e=this.widgetControls)!=null&&e.isOpen())}async uploadAttachment(e,n,o){if(!this.started)throw new Error("[BugCatch] call init() first.");return Wt({apiBase:this.config.apiBase,apiKey:this.config.apiKey,blob:e,mime:n||(e==null?void 0:e.type),onProgress:o})}async report({title:e,description:n="",priority:o="MEDIUM",metadata:s={},attachments:i=[],references:r=[],context:a=null,issue:c=null}={}){var L,f,v,y,$,g,k,I;if(!this.started)throw new Error("[BugCatch] call init() first.");if(typeof e!="string"||!e.trim())throw new Error("[BugCatch] a title is required.");["LOW","MEDIUM","HIGH","CRITICAL"].includes(String(o).toUpperCase())||(this.warn(`priority "${o}" is not one of LOW, MEDIUM, HIGH, CRITICAL — sent as MEDIUM.`),o="MEDIUM");const l=(i||[]).filter(p=>(p==null?void 0:p.storageKey)&&re(p.mime,De)).map(p=>({type:p.type==="VIDEO"?"VIDEO":"SCREENSHOT",storageKey:p.storageKey,mime:re(p.mime,De)})),h=(Array.isArray(r)?r:[]).filter(p=>p&&typeof p.key=="string"&&p.key&&(typeof p.value=="string"||typeof p.value=="number")).map(p=>({key:p.key.slice(0,64),value:String(p.value).trim().slice(0,120)})).filter(p=>p.value);Array.isArray(r)&&h.length<r.length&&this.warn("report({ references }) takes [{ key, value }] with string values; malformed entries were dropped.");let u=await b(this,d,Q).call(this,{title:e.trim(),description:typeof n=="string"?n:String(n??""),priority:String(o).toUpperCase(),metadata:s,media:l,references:h,context:a,issue:typeof c=="string"&&c?c.slice(0,32):null});const E=b(this,d,we).call(this,u);if(E===!1)return{cancelled:!0};u=E,this.debugLog("sending report",{title:u.title,user:(L=u.metadata)==null?void 0:L.user,context:(f=u.metadata)==null?void 0:f.context,references:u.references,console:($=(y=(v=u.logs)==null?void 0:v.console)==null?void 0:y.entries)==null?void 0:$.length,network:(I=(k=(g=u.logs)==null?void 0:g.network)==null?void 0:k.entries)==null?void 0:I.length});const x=j(this.config.projectId);let m;try{m=await fetch(`${this.config.apiBase}/ingest/bugs`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":this.config.apiKey,...x!=null&&x.token?{"X-BugCatch-Session":x.token}:{}},body:JSON.stringify(eo(u))})}catch(p){const w=new Error(`[BugCatch] could not reach ${this.config.apiBase} — check apiBase, and that this site's origin is allowed by the API.`);throw w.cause=p,b(this,d,G).call(this,"report",w),w}if(m.status===401&&x&&he(this.config.projectId),!m.ok){let p="";try{const M=await m.json();p=Array.isArray(M.message)?M.message.join(", "):M.message||""}catch{}m.status===401&&!x&&(p||(p="the apiKey was not accepted")),m.status===403&&(p||(p="the apiKey is not allowed to report to this projectId"));const w=m.status===429?new Error(`[BugCatch] ${N(p)}`):new Error(`[BugCatch] report failed (HTTP ${m.status})${p?": "+p:""}`);throw w.status=m.status,b(this,d,G).call(this,"report",w),w}const O=await m.json();return b(this,d,me).call(this,O,{title:u.title??e.trim(),via:"form"}),O.watchToken&&(ce(O.watchToken),this.config.updates&&this.startWatching()),O}loginState(){var e;return Sn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:(e=j(this.config.projectId))==null?void 0:e.token})}referenceFields(){return this.refFields?this.refFields:(this.refFields=Tn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.refFields)}agentIssues(){return this.agentIssueList?this.agentIssueList:(this.agentIssueList=jn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.agentIssueList)}async announcements(){const e=await Rn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId});return Kn(e)}dismissAnnouncement(e){Un(e)}signedInAs(){const e=j(this.config.projectId);return e?{email:e.email,name:e.name}:null}signIn(e,{name:n}={}){var o;return Bn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,name:n??((o=this.config.user)==null?void 0:o.name)??null})}async confirmSignIn(e,n){var s;const o=await $n({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,code:n});return(s=this.config.user)!=null&&s.email||(this.config.user={email:o.email,name:o.name||void 0}),this.emit("signin",{email:o.email,name:o.name}),{email:o.email,name:o.name}}async signOut(){var o;const e=j(this.config.projectId),n=await En({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:e==null?void 0:e.token});return e!=null&&e.email&&((o=this.config.user)==null?void 0:o.email)===e.email&&(this.config.user=null),this.emit("signout",{email:(e==null?void 0:e.email)||null}),n}knownIssues(){var e;return bn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,sessionToken:(e=j(this.config.projectId))==null?void 0:e.token})}matchKnownIssues(e,{signal:n}={}){var o;return yn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,q:e||"",sessionToken:(o=j(this.config.projectId))==null?void 0:o.token,signal:n})}async meToo(e,{email:n,name:o}={}){var r,a;const s=j(this.config.projectId),i=await Ce();return xn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,bugId:e,reporterEmail:n||((r=this.config.user)==null?void 0:r.email),reporterName:o||((a=this.config.user)==null?void 0:a.name),metadata:{...i,user:this.config.user||void 0,...Object.keys(this.context).length?{context:this.context}:{},sdk:D},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},sessionToken:s==null?void 0:s.token})}snapshot(){return{user:this.config.user||null,context:{...this.context},console:this.consoleBuffer.all(),network:this.networkBuffer.all(),environment:Ie()}}clear(){this.consoleBuffer.clear(),this.networkBuffer.clear()}destroy(){this.endCall(),this.teardown.forEach(e=>{try{e()}catch{}}),this.teardown=[],this.notifier=null,this.started=!1}}d=new WeakSet,Z=function(e,n){const o=this.config[e];if(typeof o=="function")try{o(n)}catch(s){console.error(`[BugCatch] your ${e} callback threw:`,s)}},ct=function(){if(typeof window>"u"||typeof fetch!="function")return;const e=`bugcatch:hello:${this.config.projectId}`,n=new Date().toISOString().slice(0,10);try{if(window.localStorage.getItem(e)===n)return}catch{}const o=setTimeout(()=>{try{window.localStorage.setItem(e,n)}catch{}fetch(`${this.config.apiBase}/ingest/hello`,{method:"POST",keepalive:!0,headers:{"Content-Type":"application/json","X-BugCatch-Key":this.config.apiKey},body:JSON.stringify({projectId:this.config.projectId,version:D.version,identify:!!this.config.user,context:!!(this.context&&Object.keys(this.context).length),widget:!!this.config.widget,environment:this.config.environment||null,release:this.config.release||null})}).catch(()=>{})},5e3);this.teardown.push(()=>clearTimeout(o))},R=function(){const e=_();if(this.emit("unread",{count:e.length,updates:e}),!!this.config.updateToast){if(!this.notifier){if(!e.length)return;this.notifier=wn({accent:this.config.accent,position:this.config.widgetPosition,onRead:n=>this.markUpdateRead(n),onReadAll:()=>this.markUpdatesRead(),onCall:this.config.voice?n=>{this.markUpdateRead(n.id),this.startCall(n.bugId)}:null}),this.teardown.push(()=>{var n;return(n=this.notifier)==null?void 0:n.destroy()})}this.notifier.render(e)}},lt=function(e,n){const o=n==null?void 0:n.phase;if(!e||typeof o!="string"||this.phases.get(e)===o)return;this.phases.set(e,o);const s={bugId:e,phase:o,title:n.title??null,detail:n.detail??null};this.debugLog("assistant",s),b(this,d,Z).call(this,"onAssistantPhase",s),this.emit("assistant",s)},me=function(e,{title:n,via:o}){if(!(e!=null&&e.id))return;const s={bugId:e.id,title:n??null,via:o,result:e};this.debugLog("report accepted",s),b(this,d,Z).call(this,"onReportSubmitted",s),this.emit("report",s)},G=function(e,n){b(this,d,Z).call(this,"onError",{action:e,error:n}),this.emit("error",{action:e,error:n})},Q=async function({title:e,description:n="",priority:o="MEDIUM",metadata:s={},media:i=[],references:r=[],context:a=null,issue:c=null}){var h,u;const l=a?nt(this.context,a,E=>this.warn(E.replace("setContext()","report({ context })"))):this.context;return{projectId:this.config.projectId,...e?{title:e}:{},description:n,priority:o,url:window.location.href,reporterEmail:(h=this.config.user)==null?void 0:h.email,reporterName:(u=this.config.user)==null?void 0:u.name,metadata:{...await Ce(),release:this.config.release,environment:this.config.environment,buildId:this.config.buildId,...s,user:this.config.user||void 0,...Object.keys(l).length?{context:l}:{},sdk:D},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},...i.length?{attachments:i}:{},...r.length?{references:r}:{},...c?{issue:c}:{}}},we=function(e){if(typeof this.config.beforeSend!="function")return e;let n;try{n=this.config.beforeSend(e)}catch(o){return this.warn(`beforeSend threw, so nothing was sent: ${(o==null?void 0:o.message)||o}`),!1}return n===!1?!1:n&&typeof n=="object"?n:e},ut=async function(){const e=j(this.config.projectId),n=b(this,d,we).call(this,await b(this,d,Q).call(this,{}));if(n===!1)return this.debugLog("call cancelled by beforeSend"),{cancelled:!0};let o;try{o=await an({apiBase:this.config.apiBase,apiKey:this.config.apiKey,token:e==null?void 0:e.token,payload:n,watchToken:S()})}catch(s){throw s.status===401&&e&&he(this.config.projectId),b(this,d,G).call(this,"call",s),s}return b(this,d,me).call(this,o,{title:null,via:"call"}),o.watchToken&&(ce(o.watchToken),this.config.updates&&this.startWatching()),o},dt=async function(e){const{joinLiveCall:n,liveCallSupported:o,openMicrophone:s}=await F(this.config.chunkBase);if(!o())throw new Error("[BugCatch] this browser cannot make live calls.");const i=await s();let r,a=null;try{if(e)r=await cn({apiBase:this.config.apiBase,bugId:e});else if(a=await b(this,d,ut).call(this),e=a.id,r=a.live_call,!(r!=null&&r.realtime_url)){const l=new Error(`[BugCatch] the report was filed, but the team could not be rung${a.call_error?`: ${a.call_error}`:"."}`);throw l.filed=a,l.reason=a.call_error||null,l}}catch(l){for(const h of i.getTracks())h.stop();throw l}const c=await n({realtimeUrl:r.realtime_url,stream:i,ringsUntil:r.rings_until,onState:(l,h)=>{(l==="ended"||l==="failed"||l==="missed")&&(this.call=null),l==="missed"&&ln({apiBase:this.config.apiBase,bugId:e,callId:r.call_id}),typeof this.config.onCallState=="function"&&this.config.onCallState(l,{bugId:e,live:!0,...h}),this.emit("call",{bugId:e,live:!0,state:l,...h})}});return this.call=c,Object.assign(c,{bugId:e,callId:r.call_id,live:!0,filed:a,recorded:!!r.recorded})},ht=function(e){var s;const n=e.incomingCall;if(!this.config.voice||((s=this.ringing)==null?void 0:s.callId)===n.callId||this.call||this.callStarting)return;b(this,d,ee).call(this);const o={callId:n.callId,dismiss:()=>{}};this.ringing=o,F(this.config.chunkBase).then(({liveCallSupported:i,showIncomingCall:r})=>{if(this.ringing!==o||(this.ringing=null,!i())||this.call||this.callStarting)return;const a=r({call:n,accent:this.config.accent,position:this.config.widgetPosition,touched:An,onAnswer:()=>{b(this,d,ft).call(this,e.bugId,n)},onDecline:()=>{this.ringing=null,Xe({apiBase:this.config.apiBase,bugId:e.bugId,callId:n.callId}),this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"declined"})},onExpire:()=>{this.ringing=null,this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"missed"})}});if(this.ringing={callId:n.callId,dismiss:a},typeof this.config.onIncomingCall=="function")try{this.config.onIncomingCall({bugId:e.bugId,...n})}catch{}this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"ringing"})},()=>{this.ringing===o&&(this.ringing=null)})},ee=function(e){if(this.ringing&&!(e&&this.ringing.callId!==e)){try{this.ringing.dismiss()}catch{}this.ringing=null}},ft=async function(e,n){if(this.ringing=null,this.call||this.callStarting)return;this.callStarting=!0;let o,s;try{const r=await F(this.config.chunkBase);s=r.joinLiveCall,o=await r.openMicrophone()}catch(r){this.callStarting=!1,Xe({apiBase:this.config.apiBase,bugId:e,callId:n.callId}),this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:r});return}let i;try{i=await un({apiBase:this.config.apiBase,bugId:e,callId:n.callId})}catch(r){for(const a of o.getTracks())a.stop();this.callStarting=!1,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"missed",error:r});return}try{const r=await s({realtimeUrl:i.realtime_url,stream:o,onState:(a,c)=>{(a==="ended"||a==="failed"||a==="missed")&&(this.call=null),typeof this.config.onCallState=="function"&&this.config.onCallState(a,{bugId:e,live:!0,incoming:!0,...c}),this.emit("call",{bugId:e,live:!0,incoming:!0,state:a,...c})}});this.call=r,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"answered"})}catch(r){for(const a of o.getTracks())a.stop();this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:r})}finally{this.callStarting=!1}};const ge=new rt;return ge.Client=rt,ge.version=D.version,ge});
|
|
309
|
+
`)}return n}async function dn({apiBase:t}){const e=C();if(!e)return{reporter:null,reports:[]};const n=await fetch(`${t}/ingest/watch/reports${V()}`,{headers:{Authorization:`Bearer ${e}`}});if(n.status===401)return N(),{reporter:null,reports:[]};if(!n.ok)throw new Error(`[BugCatch] could not load your reports (HTTP ${n.status})`);return n.json()}async function hn({apiBase:t,bugId:e}){const n=C();if(!n)return null;const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}${V()}`,{headers:{Authorization:`Bearer ${n}`}});if(o.status===401)return N(),null;if(o.status===404)return null;if(!o.ok)throw new Error(`[BugCatch] could not load that report (HTTP ${o.status})`);return o.json()}async function fn({apiBase:t,bugId:e,body:n,attachments:o}){const s=C();if(!s)throw new Error("[BugCatch] nothing filed from this browser yet.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/messages`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({...n?{body:n}:{},...o!=null&&o.length?{attachments:o}:{}})});if(i.status===401)throw N(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!i.ok){let r="";try{const a=await i.json();r=Array.isArray(a.message)?a.message.join(", "):a.message||""}catch{}throw i.status===429?new Error(_(r)):new Error(r||`[BugCatch] could not send that (HTTP ${i.status}).`)}return i.json()}async function pn({apiBase:t,apiKey:e,projectId:n}){const o={agent:!1,live:!1};try{const s=await fetch(`${t}/ingest/calls?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!s.ok)return o;const i=await s.json();return i!=null&&i.available?i.kinds&&typeof i.kinds=="object"?{agent:!1,live:!!i.kinds.live}:{agent:!1,live:i.kind==="live"}:o}catch{return o}}async function gn({apiBase:t,apiKey:e,token:n,payload:o,watchToken:s}){const i=await fetch(`${t}/ingest/calls`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e,...n?{"X-BugCatch-Session":n}:{}},body:JSON.stringify(s?{...o,watchToken:s}:o)});if(!i.ok){let r="";try{const c=await i.json();r=Array.isArray(c.message)?c.message.join(", "):c.message||""}catch{}const a=new Error(i.status===429?_(r):r||`[BugCatch] the call could not be started (HTTP ${i.status}).`);throw a.status=i.status,a}return i.json()}async function Ze({apiBase:t,bugId:e}){const n=C();if(!n)return!1;try{const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{headers:{Authorization:`Bearer ${n}`}});if(!o.ok)return!1;const s=await o.json();return!!(s!=null&&s.offered)}catch{return!1}}async function mn({apiBase:t,bugId:e}){const n=C();if(!n)throw new Error("[BugCatch] nothing filed from this browser yet.");const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(o.status===401)throw N(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!o.ok){let s="";try{const i=await o.json();s=Array.isArray(i.message)?i.message.join(", "):i.message||""}catch{}throw new Error(s||`[BugCatch] the call could not be started (HTTP ${o.status}).`)}return o.json()}async function wn({apiBase:t,bugId:e,callId:n}){const o=C();if(o)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/give-up`,{method:"POST",headers:{Authorization:`Bearer ${o}`}})}catch{}}async function bn({apiBase:t,bugId:e,callId:n}){const o=C();if(!o)throw new Error("[BugCatch] nothing filed from this browser yet.");const s=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/answer`,{method:"POST",headers:{Authorization:`Bearer ${o}`}});if(s.status===401)throw N(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(s.status===409)throw new Error("[BugCatch] that call is no longer ringing.");if(!s.ok){let i="";try{const r=await s.json();i=Array.isArray(r.message)?r.message.join(", "):r.message||""}catch{}throw new Error(i||`[BugCatch] the call could not be answered (HTTP ${s.status}).`)}return s.json()}async function Ge({apiBase:t,bugId:e,callId:n}){const o=C();if(o)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/decline`,{method:"POST",headers:{Authorization:`Bearer ${o}`}})}catch{}}function yn({apiBase:t,onUpdate:e}){let n=!0,o=0,s=null;async function i(){const r=C();if(!r)throw new Error("nothing filed from this browser yet");s=new AbortController;const a=await fetch(`${t}/ingest/watch/stream${V()}`,{headers:{Authorization:`Bearer ${r}`,Accept:"text/event-stream"},signal:s.signal});if(a.status===401)throw n=!1,N(),new Error("subscription no longer valid");if(!a.ok||!a.body)throw new Error(`stream failed (${a.status})`);const c=Date.now(),l=a.body.getReader(),h=new TextDecoder;let u="";try{for(;;){const{value:B,done:y}=await l.read();if(y)break;u+=h.decode(B,{stream:!0}),u=un(u,w=>{if(w.type!=="ping")try{e(w)}catch{}})}}finally{Date.now()-c>=on&&(o=0)}}return(async()=>{for(;n;){try{await i()}catch(a){if((a==null?void 0:a.name)==="AbortError")return}if(!n)return;const r=Ye[Math.min(o,Ye.length-1)];o+=1,await new Promise(a=>setTimeout(a,r))}})(),()=>{n=!1,s==null||s.abort(),s=null}}const xn={OPEN:"is open",IN_PROGRESS:"is being worked on",RESOLVED:"has been fixed",CLOSED:"has been closed"},kn={status:null,severity:"#f2a54a",assignment:"#79a8ff",reply:"#4fd19a"},T={bg:"#111113",fg:"#f3f2ef",muted:"#b3b0aa",faint:"#8f8c86",ring:"rgba(255,255,255,.09)",brand:"#a59cff"};function Qe(t){return t!=null&&t.summary?t.summary:`Your report ${xn[t==null?void 0:t.status]||"was updated"}`}function vn(t){var e;return(t==null?void 0:t.kind)==="reply"&&((e=t.reply)!=null&&e.body)?`${t.reply.author?`${t.reply.author}: `:""}${t.reply.body}`:(t==null?void 0:t.title)||""}function Cn(t){const e=Date.parse(t||"");if(!Number.isFinite(e))return"";const n=Math.round((Date.now()-e)/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const o=Math.round(n/60);if(o<24)return`${o}h ago`;const s=Math.round(o/24);return s===1?"yesterday":`${s}d ago`}function In(){var t;try{const e=document.querySelector('[data-bugcatch="widget"]'),n=(t=e==null?void 0:e.shadowRoot)==null?void 0:t.querySelector(".dock"),o=(n==null?void 0:n.getBoundingClientRect().height)||0;return o?Math.round(o)+12:0}catch{return 0}}function Sn({accent:t=null,position:e="bottom-right",onRead:n=null,onReadAll:o=null,onCall:s=null}={}){const[i,r]=String(e).split("-"),a=i==="top",c=r==="left",l=new Map;let h=null,u=null;function B(){return h!=null&&h.isConnected||(h=document.createElement("div"),h.setAttribute("data-bugcatch","updates"),h.style.cssText=["position:fixed",`${a?"top":"bottom"}:${20+In()}px`,`${c?"left":"right"}:20px`,"z-index:2147482998","display:flex","flex-direction:column","gap:10px",`align-items:${c?"flex-start":"flex-end"}`,"width:min(320px,calc(100vw - 40px))","pointer-events:none"].join(";"),document.body.appendChild(h)),h}function y(f){if(!f._bcShown){f.remove();return}f.style.opacity="0",f.style.transform=`translateY(${a?-8:8}px)`,setTimeout(()=>f.remove(),250)}const w=t||ue,M=t?He(t):De;function j(f,k){const p=document.createElement("button");return p.type="button",p.textContent=f,p.style.cssText=["padding:6px 12px","border:0",`box-shadow:${k?"none":`inset 0 0 0 1px ${T.ring}`}`,"border-radius:999px",`background:${k?w:"rgba(255,255,255,.06)"}`,`color:${k?M:T.fg}`,"font:560 12px/1.4 inherit","cursor:pointer","white-space:nowrap"].join(";"),p}function A(f){var P;const k=document.createElement("div");k.setAttribute("role","status"),k.style.cssText=["box-sizing:border-box","width:100%","padding:13px 14px","border-radius:14px",`background:${T.bg}`,`color:${T.fg}`,'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',`box-shadow:0 0 0 1px ${T.ring},0 20px 44px -12px rgba(0,0,0,.55),0 4px 12px rgba(0,0,0,.25)`,"opacity:0",`transform:translateY(${a?-8:8}px)`,"transition:opacity .2s ease,transform .2s ease","pointer-events:auto"].join(";");const p=document.createElement("div");p.style.cssText="display:flex;align-items:baseline;gap:8px;font-weight:600;margin-bottom:2px";const b=document.createElement("span");b.setAttribute("aria-hidden","true"),b.style.cssText=`flex:none;width:7px;height:7px;border-radius:50%;transform:translateY(-1px);background:${kn[f==null?void 0:f.kind]||t||T.brand}`;const I=document.createElement("span");I.textContent=Qe(f),p.append(b,I);const g=document.createElement("div");g.style.cssText=(f==null?void 0:f.kind)==="reply"?`color:${T.muted};padding-left:15px;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden`:`color:${T.muted};padding-left:15px`,g.textContent=vn(f);const S=document.createElement("div");S.style.cssText="display:flex;align-items:center;gap:8px;margin-top:10px;padding-left:15px;flex-wrap:wrap";const O=document.createElement("span");O.style.cssText=`color:${T.faint};font-size:11px;margin-right:auto`,O.textContent=Cn(f==null?void 0:f.at);const x=j("Mark as read",!1);if(x.setAttribute("aria-label",`Mark as read: ${Qe(f)}`),x.addEventListener("click",()=>n==null?void 0:n(f.id)),S.append(O,x),(P=f==null?void 0:f.call)!=null&&P.offered&&typeof s=="function"){const ft=j("Talk it through",!0);ft.addEventListener("click",()=>s(f)),S.insertBefore(ft,x)}return k.append(p,g,S),k}function D(f){const k=document.createElement("div");k.style.cssText=["box-sizing:border-box","width:100%","display:flex","align-items:center","gap:8px","padding:8px 10px 8px 14px","border-radius:999px",`background:${T.bg}`,`color:${T.muted}`,'font:12px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',`box-shadow:0 0 0 1px ${T.ring},0 12px 30px -10px rgba(0,0,0,.5)`,"pointer-events:auto"].join(";");const p=document.createElement("span");p.style.cssText="margin-right:auto",p.textContent=`${f} more update${f===1?"":"s"}`;const b=j("Mark all as read",!1);return b.style.cssText+=";padding:4px 9px",b.addEventListener("click",()=>o==null?void 0:o()),k.append(p,b),k}return{render(f){const k=Array.isArray(f)?f:[];if(!k.length){for(const x of l.values())y(x);l.clear(),u==null||u.remove(),u=null,h==null||h.remove(),h=null;return}const p=k.slice(-3),b=new Set(p.map(x=>x.id)),I=B();for(const[x,P]of l)b.has(x)||(y(P),l.delete(x));const g=[];for(const x of p){if(l.has(x.id))continue;const P=A(x);l.set(x.id,P),g.push(P)}const S=a?[...p].reverse():p;for(const x of S)I.appendChild(l.get(x.id));const O=k.length-p.length;O>0?(u==null||u.remove(),u=D(O),a?I.appendChild(u):I.insertBefore(u,I.firstChild)):(u==null||u.remove(),u=null),requestAnimationFrame(()=>{for(const x of g)x.isConnected&&(x._bcShown=!0,x.style.opacity="1",x.style.transform="translateY(0)")})},destroy(){l.clear(),u=null,h==null||h.remove(),h=null}}}async function $n({apiBase:t,apiKey:e,projectId:n,sessionToken:o}){try{const s=await fetch(`${t}/ingest/known-issues?projectId=${encodeURIComponent(n)}`,{headers:pe(e,o)});if(!s.ok)return[];const i=await s.json();return Array.isArray(i==null?void 0:i.issues)?i.issues:[]}catch{return[]}}async function Bn({apiBase:t,apiKey:e,projectId:n,q:o,sessionToken:s,signal:i}){try{const r=`${t}/ingest/known-issues/match?projectId=${encodeURIComponent(n)}&q=${encodeURIComponent(o)}`,a=await fetch(r,{headers:pe(e,s),signal:i});if(!a.ok)return[];const c=await a.json();return Array.isArray(c==null?void 0:c.issues)?c.issues:[]}catch{return[]}}async function En({apiBase:t,apiKey:e,projectId:n,bugId:o,reporterEmail:s,reporterName:i,metadata:r,logs:a,sessionToken:c}){const l=C(),h=await fetch(`${t}/ingest/known-issues/${encodeURIComponent(o)}/join`,{method:"POST",headers:pe(e,c),body:JSON.stringify({projectId:n,reporterEmail:s,reporterName:i,metadata:r,logs:a,...l?{watchToken:l}:{}})});if(!h.ok)throw new Error(await Tn(h));const u=await h.json();return u!=null&&u.watchToken&&fe(u.watchToken),u}function pe(t,e){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function Tn(t){let e="";try{const n=await t.json();e=Array.isArray(n.message)?n.message.join(", "):n.message||""}catch{}return t.status===429?_(e):e||`Could not add you to this issue (HTTP ${t.status})`}async function An({apiBase:t,bugId:e,score:n,comment:o}){const s=C();if(!s)throw new Error("This browser cannot access that report.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/rating${V()}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({score:n,...o?{comment:o}:{}})}),r=await i.json().catch(()=>({}));if(!i.ok){const a=Array.isArray(r.message)?r.message.join(", "):r.message;throw new Error(a||"Could not send your rating. Please try again.")}return r}async function jn({apiBase:t,bugId:e,...n}){const o=C();if(!o)throw new Error("This browser cannot access that report.");const s=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/verification`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(n)}),i=await s.json().catch(()=>({}));if(!s.ok)throw new Error(i.message||"Could not record feedback. Please refresh and try again.");return i}const On="bugcatch.session.",ge=t=>`${On}${t}`,me=new Map;function R(t){var e;if(!t)return null;try{const n=(e=window.localStorage)==null?void 0:e.getItem(ge(t));if(n){const o=JSON.parse(n);if(o!=null&&o.token)return o}}catch{}return me.get(t)||null}function Ln(t,e){var o;if(!t||!(e!=null&&e.token))return;const n={token:e.token,email:e.email||null,name:e.name||null};me.set(t,n);try{(o=window.localStorage)==null||o.setItem(ge(t),JSON.stringify(n))}catch{}}function we(t){var e;if(t){me.delete(t);try{(e=window.localStorage)==null||e.removeItem(ge(t))}catch{}}}function Q({apiKey:t,token:e}){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function et(t){let e="";try{const n=await t.json();e=Array.isArray(n.message)?n.message.join(", "):n.message||""}catch{}return t.status===429?_(e):e||`Request failed (HTTP ${t.status})`}async function Rn({apiBase:t,apiKey:e,projectId:n,token:o}){const s={mode:"off",signedIn:null,signedOutReason:null};try{const i=await fetch(`${t}/ingest/login?projectId=${encodeURIComponent(n)}`,{headers:Q({apiKey:e,token:o})});if(!i.ok)return s;const r=await i.json();return{mode:r.mode==="optional"||r.mode==="required"?r.mode:"off",signedIn:r.signedIn||null,signedOutReason:r.signedOutReason||null}}catch{return s}}async function Mn({apiBase:t,apiKey:e,projectId:n,email:o,name:s}){const i=await fetch(`${t}/ingest/login/start`,{method:"POST",headers:Q({apiKey:e}),body:JSON.stringify({projectId:n,email:o,...s?{name:s}:{}})});if(!i.ok)throw new Error(await et(i));return i.json()}async function Kn({apiBase:t,apiKey:e,projectId:n,email:o,code:s}){const i=await fetch(`${t}/ingest/login`,{method:"POST",headers:Q({apiKey:e}),body:JSON.stringify({projectId:n,email:o,code:s})});if(!i.ok)throw new Error(await et(i));const r=await i.json(),a={token:r.sessionToken,email:r.email,name:r.name};return Ln(n,a),a}async function Un({apiBase:t,apiKey:e,projectId:n,token:o}){if(we(n),!o)return{signedOut:!0};try{await fetch(`${t}/ingest/logout`,{method:"POST",headers:Q({apiKey:e,token:o}),body:JSON.stringify({projectId:n})})}catch{}return{signedOut:!0}}let tt=!1;if(typeof window<"u"&&window.addEventListener)for(const t of["pointerdown","keydown","touchstart"])window.addEventListener(t,()=>{tt=!0},{once:!0,capture:!0,passive:!0});function Nn(){return tt}async function Pn({apiBase:t,apiKey:e,projectId:n}){const o={policy:"off",fields:[]};try{const s=await fetch(`${t}/ingest/reference-fields?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!s.ok)return o;const i=await s.json(),r=i.policy==="optional"||i.policy==="required"?i.policy:"off",a=Array.isArray(i.fields)?i.fields:[];return a.length?{policy:r,fields:a}:o}catch{return o}}async function _n({apiBase:t,apiKey:e,projectId:n}){try{const o=await fetch(`${t}/ingest/agent-issues?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!o.ok)return[];const s=await o.json();return(Array.isArray(s==null?void 0:s.issues)?s.issues:[]).filter(i=>i&&typeof i.key=="string"&&typeof i.title=="string").map(i=>({key:i.key,title:i.title,hint:typeof i.hint=="string"?i.hint:""}))}catch{return[]}}const Dn=5*6e4,nt="bugcatch:announcements:seen",Hn=40,zn=["info","success","warning","critical"],ot=t=>`bugcatch:announcements:${t}`;async function Fn({apiBase:t,apiKey:e,projectId:n,fresh:o=!1}){var s;if(!o){const i=Zn(n);if(i)return i}try{const i=await fetch(`${t}/ingest/announcements?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}}),r=i.ok?Vn((s=await i.json())==null?void 0:s.announcements):[];return Gn(n,r),r}catch{return[]}}function Xn(t,{on:e=Jn(),seen:n=rt()}={}){return(t||[]).filter(o=>Yn(o,e)&&!(o.dismissible&&n.includes(it(o))))}function qn(t){if(!(!(t!=null&&t.id)||!t.dismissible))try{const e=it(t),n=[...rt().filter(o=>o!==e),e];localStorage.setItem(nt,JSON.stringify(n.slice(-Hn)))}catch{}}function Wn(t){return typeof t!="string"||!t||t.startsWith("//")?null:t.startsWith("/")||/^(https?:\/\/|mailto:)./i.test(t)?t:null}function Jn(t=new Date){const e=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}`}function Yn(t,e){return!(t.startsOn&&e<t.startsOn||t.endsOn&&e>t.endsOn)}function it(t){return`${t.id}#${t.revision||0}`}function Vn(t){return(Array.isArray(t)?t:[]).filter(e=>e&&typeof e.id=="string"&&typeof e.title=="string"&&e.title.trim()).map(e=>{const n=e.placement==="launcher"?"launcher":"panel",o=Wn(e.ctaHref);return{id:e.id,revision:Number.isInteger(e.revision)?e.revision:0,title:e.title,body:typeof e.body=="string"?e.body:"",tone:zn.includes(e.tone)?e.tone:"info",ctaLabel:o&&typeof e.ctaLabel=="string"?e.ctaLabel:"",ctaHref:o&&typeof e.ctaLabel=="string"?o:"",placement:n,dismissible:n==="launcher"||e.dismissible!==!1,startsOn:typeof e.startsOn=="string"?e.startsOn:"",endsOn:typeof e.endsOn=="string"?e.endsOn:""}})}function rt(){try{const t=JSON.parse(localStorage.getItem(nt)||"[]");return Array.isArray(t)?t.filter(e=>typeof e=="string"):[]}catch{return[]}}function Zn(t){try{const e=JSON.parse(localStorage.getItem(ot(t))||"null");if(!e||!Array.isArray(e.list)||typeof e.at!="number")return null;const n=Date.now()-e.at;return n>=0&&n<Dn?e.list:null}catch{return null}}function Gn(t,e){try{localStorage.setItem(ot(t),JSON.stringify({at:Date.now(),list:e}))}catch{}}const ee=120,Qn=500,te=30,eo=1e3,be={loanId:["loanId","loanNumber"],applicationId:["applicationId"],customerNumber:["customerNumber","customerId"]},to=/[\u0000-\u001f\u007f]/;function no(t){if(typeof t=="number")return Number.isFinite(t)?String(t):null;if(typeof t!="string")return null;const e=t.trim();return!e||e.length>ee||to.test(e)?null:e}function L(t){return t===null?"null":Array.isArray(t)?"an array":typeof t=="object"?"an object":`a ${typeof t}`}function ye(t,e,n,o,s){for(const i of n){if(!(i in t)||t[i]===void 0||t[i]===null||t[i]==="")continue;const r=no(t[i]);if(r)return r;const a=t[i];s(typeof a=="string"&&a.trim().length>ee?`${o}.${i} is longer than ${ee} characters and was dropped — pass the identifier itself, not a sentence or a URL.`:`${o}.${i} should be a string or number, got ${L(a)} — it was dropped.`)}return null}function st(t){if(t===null||typeof t=="boolean")return{ok:!0,value:t};if(typeof t=="number")return Number.isFinite(t)?{ok:!0,value:t}:{ok:!1};if(typeof t=="string")return{ok:!0,value:t.slice(0,Qn)};if(typeof t=="object")try{const e=JSON.stringify(t);if(e&&e.length<=eo)return{ok:!0,value:JSON.parse(e)}}catch{}return{ok:!1}}const at=["email","name","phone"],oo=new Set(["id","userId",...at,...Object.values(be).flat()]);function ct(t,e=()=>{}){if(t==null)return null;if(typeof t!="object"||Array.isArray(t))return e(`identify() takes an object like { id, email, name } or null, got ${L(t)} — ignored.`),null;const n={};try{const o=ye(t,"id",["id","userId"],"identify()",e);o&&(n.id=o);for(const i of at){const r=t[i];if(r==null||r==="")continue;if(i==="phone"&&typeof r=="number"&&Number.isFinite(r)){n.phone=String(r);continue}if(typeof r!="string"){e(`identify().${i} should be a string, got ${L(r)} — it was dropped.`);continue}const a=r.trim().slice(0,i==="name"?200:ee);a&&(i==="email"&&!a.includes("@")&&e(`identify().email "${a}" does not look like an email address — reports cannot be threaded or followed up without one.`),n[i]=a)}for(const[i,r]of Object.entries(be)){const a=ye(t,i,r,"identify()",e);a&&(n[i]=a)}let s=0;for(const[i,r]of Object.entries(t)){if(oo.has(i)||r===void 0||typeof r=="function")continue;if(s>=te){e(`identify() was given more than ${te} extra fields; the rest were dropped.`);break}const a=st(r);if(!a.ok){e(`identify().${i} could not be sent (${L(r)} too large or not serialisable) — dropped.`);continue}n[i]=a.value,s+=1}}catch{}return!n.id&&!n.email&&e("identify() was called without an id or email — reports will not be attributed to anyone, and nothing can be looked up by user."),n}function lt(t,e,n=()=>{}){if(e===null)return{};const o={...t||{}};if(e===void 0)return o;if(typeof e!="object"||Array.isArray(e))return n(`setContext() takes an object like { loanId, screen } or null, got ${L(e)} — ignored.`),o;try{const s=new Map;for(const[i,r]of Object.entries(be))for(const a of r)s.set(a,i);for(const[i,r]of Object.entries(e)){const a=s.get(i);if(r==null){delete o[a||i];continue}if(a){const l=ye({[i]:r},a,[i],"setContext()",n);l?o[a]=l:delete o[a];continue}if(typeof r=="function")continue;if(!(i in o)&&Object.keys(o).length>=te){n(`setContext() holds at most ${te} keys; "${i}" was dropped.`);continue}const c=st(r);if(!c.ok){n(`setContext().${i} could not be sent (${L(r)} too large or not serialisable) — dropped.`);continue}o[i]=c.value}}catch{}return o}const ut=["apiBase","apiKey","projectId","consoleLimit","networkLimit","captureConsole","captureNetwork","captureErrors","widget","widgetPosition","theme","accent","attachments","maxAttachments","maxAttachmentBytes","maxRecordingMs","beforeSend","user","context","updates","updateToast","onUpdate","voice","onCallState","onIncomingCall","onReportSubmitted","onAssistantPhase","onError","debug","drafts","knownIssues","agentIssues","release","environment","buildId","chunkBase","announcements"],io=["beforeSend","onUpdate","onCallState","onIncomingCall","onReportSubmitted","onAssistantPhase","onError"];function ro(t){const e=t.toLowerCase().replace(/[-_]/g,"");return ut.find(n=>n.toLowerCase()===e)||null}const dt=/^(your[_-]|<|xxx|todo|changeme)/i,so=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function ao(t,{pageHost:e=""}={}){const n=[],o=[];if(!t||typeof t!="object")return n.push("init() takes an options object: BugCatch.init({ apiBase, apiKey, projectId })."),{errors:n,warnings:o};const{apiKey:s,projectId:i,apiBase:r}=t;s?typeof s!="string"?n.push(`apiKey must be a string, got ${L(s)}.`):dt.test(s)?n.push(`apiKey is still the placeholder "${s}" — paste the key you saved when you created it.`):so.test(s)?o.push("apiKey looks like a project id — did you swap apiKey and projectId?"):s.startsWith("bc_")||o.push('apiKey does not look like a BugCatch key (they start with "bc_live_") — reports will be refused with HTTP 401.'):n.push("apiKey is required — create one under Workspace Settings → API Keys."),i?typeof i!="string"?n.push(`projectId must be a string, got ${L(i)}.`):dt.test(i)?n.push(`projectId is still the placeholder "${i}".`):i.startsWith("bc_")?o.push("projectId looks like an API key — did you swap apiKey and projectId?"):/\s/.test(i)&&o.push("projectId contains whitespace — check it was copied cleanly."):n.push("projectId is required — copy it from Project Settings → Web SDK."),r==null?!e||/^(localhost|127\.|0\.0\.0\.0|\[::1\])/.test(e)||o.push("apiBase is not set, so reports go to http://localhost:3000 — set apiBase to your BugCatch API URL."):(typeof r!="string"||!/^https?:\/\//.test(r))&&o.push(`apiBase should be an absolute http(s) URL, got ${JSON.stringify(r)}.`);for(const a of Object.keys(t)){if(ut.includes(a))continue;const c=ro(a);o.push(c?`unknown option "${a}" — did you mean "${c}"?`:`unknown option "${a}" is ignored.`)}for(const a of io){const c=t[a];c!=null&&typeof c!="function"&&o.push(`${a} should be a function, got ${L(c)} — it will not be called.`)}return{errors:n,warnings:o}}function co(t){return typeof t=="string"?t.replace(/\/+$/,""):t}const X={name:"@sphoro/bugcatch-web-sdk",version:"0.20.0"},q={apiBase:"http://localhost:3000",apiKey:null,projectId:null,consoleLimit:100,networkLimit:50,captureConsole:!0,captureNetwork:!0,captureErrors:!0,widget:!0,widgetPosition:"bottom-right",theme:"auto",accent:null,announcements:!0,attachments:!0,maxAttachments:5,maxAttachmentBytes:25*1024*1024,maxRecordingMs:12e4,beforeSend:null,user:null,updates:!0,updateToast:!0,onUpdate:null,voice:!0,onCallState:null,onIncomingCall:null,onReportSubmitted:null,onAssistantPhase:null,onError:null,context:null,chunkBase:null,debug:!1};function lo(t){const e=C();return e?{...t,watchToken:e}:t}class ht{constructor(){gt(this,d);this.config={...q},this.started=!1,this.teardown=[],this.consoleBuffer=W(q.consoleLimit),this.networkBuffer=W(q.networkLimit),this.stopWatching=null,this.notifier=null,this.call=null,this.callStarting=!1,this.ringing=null,this.listeners=new Map,this.context={},this.warned=new Set,this.phases=new Map}warn(e){this.warned.has(e)||(this.warned.add(e),console.warn(`[BugCatch] ${e}`))}debugLog(...e){this.config.debug&&console.info("[BugCatch]",...e)}init(e={}){if(this.started)return console.warn("[BugCatch] init() called twice — ignoring the second call."),this;const{errors:n,warnings:o}=ao(e,{pageHost:typeof location<"u"?location.hostname:""});if(n.length)throw new Error(`[BugCatch] ${n[0]}`);for(const i of o)this.warn(i);const s=this.config.user;return this.config={...q,...e,apiBase:co(e.apiBase??q.apiBase)},this.config.user=e.user!==void 0?ct(e.user,i=>this.warn(i.replace("identify()","init({ user })"))):s||null,e.context&&this.setContext(e.context),this.consoleBuffer=W(this.config.consoleLimit),this.networkBuffer=W(this.config.networkLimit),this.config.captureConsole&&this.teardown.push(Tt(this.consoleBuffer)),this.config.captureNetwork&&this.teardown.push(At(this.networkBuffer)),this.config.captureErrors&&this.teardown.push(jt(this.consoleBuffer)),rn(this.config.projectId),this.config.widget&&this.teardown.push(Jt(this)),this.config.updates&&C()&&(this.startWatching(),queueMicrotask(()=>m(this,d,K).call(this))),this.started=!0,m(this,d,mt).call(this),this.debugLog("initialised",{version:X.version,apiBase:this.config.apiBase,projectId:this.config.projectId,user:this.config.user,context:this.context}),this}startWatching(){if(this.stopWatching)return this;this.stopWatching=yn({apiBase:this.config.apiBase,onUpdate:n=>{if(n!=null&&n.incomingCall){m(this,d,xt).call(this,n);return}if(n!=null&&n.callWithdrawn){m(this,d,re).call(this,n.callWithdrawn.callId);return}const o=an(n);typeof this.config.onUpdate=="function"&&this.config.onUpdate(o),this.emit("update",o),m(this,d,K).call(this)}}),this.teardown.push(()=>{var n;return(n=this.stopWatching)==null?void 0:n.call(this)}),this.teardown.push(()=>m(this,d,re).call(this));const e=n=>{(n.key===Z||n.key===null)&&m(this,d,K).call(this)};return window.addEventListener("storage",e),this.teardown.push(()=>window.removeEventListener("storage",e)),this}on(e,n){if(typeof n!="function")return()=>{};const o=this.listeners.get(e)||new Set;return o.add(n),this.listeners.set(e,o),()=>this.off(e,n)}off(e,n){var o;return(o=this.listeners.get(e))==null||o.delete(n),this}emit(e,n){for(const o of this.listeners.get(e)||[])try{o(n)}catch(s){console.error(`[BugCatch] a '${e}' listener threw:`,s)}}unreadUpdates(){return F()}markUpdateRead(e){return cn(e),m(this,d,K).call(this),this}markReportRead(e){return ln(e),m(this,d,K).call(this),this}markUpdatesRead(){return Ve(),m(this,d,K).call(this),this}async verifyFix(e,{result:n,resolvedAt:o,note:s}){const i=n==="STILL_HAPPENING"?await m(this,d,ie).call(this,{}):{};return jn({apiBase:this.config.apiBase,bugId:e,result:n,resolvedAt:o,note:s,metadata:i.metadata,logs:i.logs})}async rate(e,{score:n,comment:o}={}){return An({apiBase:this.config.apiBase,bugId:e,score:n,comment:o})}async myReport(e){const n=await hn({apiBase:this.config.apiBase,bugId:e});return m(this,d,wt).call(this,e,n==null?void 0:n.assistant),n}replyToReport(e,{body:n,attachments:o}={}){return fn({apiBase:this.config.apiBase,bugId:e,body:n,attachments:o})}async canCallNow(){return!!await this.callKind()}async callKind(){return(await this.callKinds()).live?"live":null}async callKinds(){var n;const e={agent:!1,live:!1};return!this.config.voice||!((n=this.config.user)!=null&&n.email)?e:this.kinds!==void 0?this.kinds:(this.kinds=await pn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.kinds)}canCall(e){return this.config.voice?Ze({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}async startCall(e){var n;if(!this.config.voice)throw new Error("[BugCatch] calling is switched off.");if(this.call||this.callStarting)throw new Error("[BugCatch] a call is already running.");this.callStarting=!0;try{if(!await this.callKind())throw new Error((n=this.config.user)!=null&&n.email?"[BugCatch] calling is not available on this project.":"[BugCatch] a call needs to know who is calling — call identify() with an email first.");return await m(this,d,yt).call(this,e)}finally{this.callStarting=!1}}startLiveCall(e){return this.startCall(e)}canCallTeam(e){return this.config.voice?Ze({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}endCall(){var e;return(e=this.call)==null||e.hangUp(),this.call=null,this}myReports(){return dn({apiBase:this.config.apiBase})}hasReports(){return!!C()}forgetReports(){var e;return(e=this.stopWatching)==null||e.call(this),this.stopWatching=null,this.endCall(),N(),m(this,d,K).call(this),this}identify(e){const n=ct(e,o=>this.warn(o));return e!=null&&!n?this:(this.config.user=n,this.debugLog("identify",n),this)}setContext(e){return this.context=lt(this.context,e,n=>this.warn(n)),this.debugLog("context",this.context),this}getContext(){return{...this.context}}open(){return this.started?this.widgetControls?(this.widgetControls.open(),this):(this.warn("open() needs the built-in widget; it was turned off with widget: false."),this):(this.warn("open() was called before init() — nothing to open yet."),this)}close(){var e;return(e=this.widgetControls)==null||e.close(),this}isOpen(){var e;return!!((e=this.widgetControls)!=null&&e.isOpen())}async uploadAttachment(e,n,o){if(!this.started)throw new Error("[BugCatch] call init() first.");return tn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,blob:e,mime:n||(e==null?void 0:e.type),onProgress:o})}async report({title:e,description:n="",priority:o="MEDIUM",metadata:s={},attachments:i=[],references:r=[],context:a=null,issue:c=null}={}){var j,A,D,f,k,p,b,I;if(!this.started)throw new Error("[BugCatch] call init() first.");if(typeof e!="string"||!e.trim())throw new Error("[BugCatch] a title is required.");["LOW","MEDIUM","HIGH","CRITICAL"].includes(String(o).toUpperCase())||(this.warn(`priority "${o}" is not one of LOW, MEDIUM, HIGH, CRITICAL — sent as MEDIUM.`),o="MEDIUM");const l=(i||[]).filter(g=>(g==null?void 0:g.storageKey)&&de(g.mime,Je)).map(g=>({type:g.type==="VIDEO"?"VIDEO":"SCREENSHOT",storageKey:g.storageKey,mime:de(g.mime,Je)})),h=(Array.isArray(r)?r:[]).filter(g=>g&&typeof g.key=="string"&&g.key&&(typeof g.value=="string"||typeof g.value=="number")).map(g=>({key:g.key.slice(0,64),value:String(g.value).trim().slice(0,120)})).filter(g=>g.value);Array.isArray(r)&&h.length<r.length&&this.warn("report({ references }) takes [{ key, value }] with string values; malformed entries were dropped.");let u=await m(this,d,ie).call(this,{title:e.trim(),description:typeof n=="string"?n:String(n??""),priority:String(o).toUpperCase(),metadata:s,media:l,references:h,context:a,issue:typeof c=="string"&&c?c.slice(0,32):null});const B=m(this,d,ve).call(this,u);if(B===!1)return{cancelled:!0};u=B,this.debugLog("sending report",{title:u.title,user:(j=u.metadata)==null?void 0:j.user,context:(A=u.metadata)==null?void 0:A.context,references:u.references,console:(k=(f=(D=u.logs)==null?void 0:D.console)==null?void 0:f.entries)==null?void 0:k.length,network:(I=(b=(p=u.logs)==null?void 0:p.network)==null?void 0:b.entries)==null?void 0:I.length});const y=R(this.config.projectId);let w;try{w=await fetch(`${this.config.apiBase}/ingest/bugs`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":this.config.apiKey,...y!=null&&y.token?{"X-BugCatch-Session":y.token}:{}},body:JSON.stringify(lo(u))})}catch(g){const S=new Error(`[BugCatch] could not reach ${this.config.apiBase} — check apiBase, and that this site's origin is allowed by the API.`);throw S.cause=g,m(this,d,oe).call(this,"report",S),S}if(w.status===401&&y&&we(this.config.projectId),!w.ok){let g="";try{const O=await w.json();g=Array.isArray(O.message)?O.message.join(", "):O.message||""}catch{}w.status===401&&!y&&(g||(g="the apiKey was not accepted")),w.status===403&&(g||(g="the apiKey is not allowed to report to this projectId"));const S=w.status===429?new Error(`[BugCatch] ${_(g)}`):new Error(`[BugCatch] report failed (HTTP ${w.status})${g?": "+g:""}`);throw S.status=w.status,m(this,d,oe).call(this,"report",S),S}const M=await w.json();return m(this,d,ke).call(this,M,{title:u.title??e.trim(),via:"form"}),M.watchToken&&(fe(M.watchToken),this.config.updates&&this.startWatching()),M}loginState(){var e;return Rn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:(e=R(this.config.projectId))==null?void 0:e.token})}referenceFields(){return this.refFields?this.refFields:(this.refFields=Pn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.refFields)}agentIssues(){return this.agentIssueList?this.agentIssueList:(this.agentIssueList=_n({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.agentIssueList)}async announcements(){const e=await Fn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId});return Xn(e)}dismissAnnouncement(e){qn(e)}signedInAs(){const e=R(this.config.projectId);return e?{email:e.email,name:e.name}:null}signIn(e,{name:n}={}){var o;return Mn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,name:n??((o=this.config.user)==null?void 0:o.name)??null})}async confirmSignIn(e,n){var s;const o=await Kn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,code:n});return(s=this.config.user)!=null&&s.email||(this.config.user={email:o.email,name:o.name||void 0}),this.emit("signin",{email:o.email,name:o.name}),{email:o.email,name:o.name}}async signOut(){var o;const e=R(this.config.projectId),n=await Un({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:e==null?void 0:e.token});return e!=null&&e.email&&((o=this.config.user)==null?void 0:o.email)===e.email&&(this.config.user=null),this.emit("signout",{email:(e==null?void 0:e.email)||null}),n}knownIssues(){var e;return $n({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,sessionToken:(e=R(this.config.projectId))==null?void 0:e.token})}matchKnownIssues(e,{signal:n}={}){var o;return Bn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,q:e||"",sessionToken:(o=R(this.config.projectId))==null?void 0:o.token,signal:n})}async meToo(e,{email:n,name:o}={}){var r,a;const s=R(this.config.projectId),i=await Ee();return En({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,bugId:e,reporterEmail:n||((r=this.config.user)==null?void 0:r.email),reporterName:o||((a=this.config.user)==null?void 0:a.name),metadata:{...i,user:this.config.user||void 0,...Object.keys(this.context).length?{context:this.context}:{},sdk:X},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},sessionToken:s==null?void 0:s.token})}snapshot(){return{user:this.config.user||null,context:{...this.context},console:this.consoleBuffer.all(),network:this.networkBuffer.all(),environment:Te()}}clear(){this.consoleBuffer.clear(),this.networkBuffer.clear()}destroy(){this.endCall(),this.teardown.forEach(e=>{try{e()}catch{}}),this.teardown=[],this.notifier=null,this.started=!1}}d=new WeakSet,ne=function(e,n){const o=this.config[e];if(typeof o=="function")try{o(n)}catch(s){console.error(`[BugCatch] your ${e} callback threw:`,s)}},mt=function(){if(typeof window>"u"||typeof fetch!="function")return;const e=`bugcatch:hello:${this.config.projectId}`,n=new Date().toISOString().slice(0,10);try{if(window.localStorage.getItem(e)===n)return}catch{}const o=setTimeout(()=>{try{window.localStorage.setItem(e,n)}catch{}fetch(`${this.config.apiBase}/ingest/hello`,{method:"POST",keepalive:!0,headers:{"Content-Type":"application/json","X-BugCatch-Key":this.config.apiKey},body:JSON.stringify({projectId:this.config.projectId,version:X.version,identify:!!this.config.user,context:!!(this.context&&Object.keys(this.context).length),widget:!!this.config.widget,environment:this.config.environment||null,release:this.config.release||null})}).catch(()=>{})},5e3);this.teardown.push(()=>clearTimeout(o))},K=function(){const e=F();if(this.emit("unread",{count:e.length,updates:e}),!!this.config.updateToast){if(!this.notifier){if(!e.length)return;this.notifier=Sn({accent:this.config.accent,position:this.config.widgetPosition,onRead:n=>this.markUpdateRead(n),onReadAll:()=>this.markUpdatesRead(),onCall:this.config.voice?n=>{this.markUpdateRead(n.id),this.startCall(n.bugId)}:null}),this.teardown.push(()=>{var n;return(n=this.notifier)==null?void 0:n.destroy()})}this.notifier.render(e)}},wt=function(e,n){const o=n==null?void 0:n.phase;if(!e||typeof o!="string"||this.phases.get(e)===o)return;this.phases.set(e,o);const s={bugId:e,phase:o,title:n.title??null,detail:n.detail??null};this.debugLog("assistant",s),m(this,d,ne).call(this,"onAssistantPhase",s),this.emit("assistant",s)},ke=function(e,{title:n,via:o}){if(!(e!=null&&e.id))return;const s={bugId:e.id,title:n??null,via:o,result:e};this.debugLog("report accepted",s),m(this,d,ne).call(this,"onReportSubmitted",s),this.emit("report",s)},oe=function(e,n){m(this,d,ne).call(this,"onError",{action:e,error:n}),this.emit("error",{action:e,error:n})},ie=async function({title:e,description:n="",priority:o="MEDIUM",metadata:s={},media:i=[],references:r=[],context:a=null,issue:c=null}){var h,u;const l=a?lt(this.context,a,B=>this.warn(B.replace("setContext()","report({ context })"))):this.context;return{projectId:this.config.projectId,...e?{title:e}:{},description:n,priority:o,url:window.location.href,reporterEmail:(h=this.config.user)==null?void 0:h.email,reporterName:(u=this.config.user)==null?void 0:u.name,metadata:{...await Ee(),release:this.config.release,environment:this.config.environment,buildId:this.config.buildId,...s,user:this.config.user||void 0,...Object.keys(l).length?{context:l}:{},sdk:X},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},...i.length?{attachments:i}:{},...r.length?{references:r}:{},...c?{issue:c}:{}}},ve=function(e){if(typeof this.config.beforeSend!="function")return e;let n;try{n=this.config.beforeSend(e)}catch(o){return this.warn(`beforeSend threw, so nothing was sent: ${(o==null?void 0:o.message)||o}`),!1}return n===!1?!1:n&&typeof n=="object"?n:e},bt=async function(){const e=R(this.config.projectId),n=m(this,d,ve).call(this,await m(this,d,ie).call(this,{}));if(n===!1)return this.debugLog("call cancelled by beforeSend"),{cancelled:!0};let o;try{o=await gn({apiBase:this.config.apiBase,apiKey:this.config.apiKey,token:e==null?void 0:e.token,payload:n,watchToken:C()})}catch(s){throw s.status===401&&e&&we(this.config.projectId),m(this,d,oe).call(this,"call",s),s}return m(this,d,ke).call(this,o,{title:null,via:"call"}),o.watchToken&&(fe(o.watchToken),this.config.updates&&this.startWatching()),o},yt=async function(e){const{joinLiveCall:n,liveCallSupported:o,openMicrophone:s}=await J(this.config.chunkBase);if(!o())throw new Error("[BugCatch] this browser cannot make live calls.");const i=await s();let r,a=null;try{if(e)r=await mn({apiBase:this.config.apiBase,bugId:e});else if(a=await m(this,d,bt).call(this),e=a.id,r=a.live_call,!(r!=null&&r.realtime_url)){const l=new Error(`[BugCatch] the report was filed, but the team could not be rung${a.call_error?`: ${a.call_error}`:"."}`);throw l.filed=a,l.reason=a.call_error||null,l}}catch(l){for(const h of i.getTracks())h.stop();throw l}const c=await n({realtimeUrl:r.realtime_url,stream:i,ringsUntil:r.rings_until,onState:(l,h)=>{(l==="ended"||l==="failed"||l==="missed")&&(this.call=null),l==="missed"&&wn({apiBase:this.config.apiBase,bugId:e,callId:r.call_id}),typeof this.config.onCallState=="function"&&this.config.onCallState(l,{bugId:e,live:!0,...h}),this.emit("call",{bugId:e,live:!0,state:l,...h})}});return this.call=c,Object.assign(c,{bugId:e,callId:r.call_id,live:!0,filed:a,recorded:!!r.recorded})},xt=function(e){var s;const n=e.incomingCall;if(!this.config.voice||((s=this.ringing)==null?void 0:s.callId)===n.callId||this.call||this.callStarting)return;m(this,d,re).call(this);const o={callId:n.callId,dismiss:()=>{}};this.ringing=o,J(this.config.chunkBase).then(({liveCallSupported:i,showIncomingCall:r})=>{if(this.ringing!==o||(this.ringing=null,!i())||this.call||this.callStarting)return;const a=r({call:n,accent:this.config.accent,position:this.config.widgetPosition,touched:Nn,onAnswer:()=>{m(this,d,kt).call(this,e.bugId,n)},onDecline:()=>{this.ringing=null,Ge({apiBase:this.config.apiBase,bugId:e.bugId,callId:n.callId}),this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"declined"})},onExpire:()=>{this.ringing=null,this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"missed"})}});if(this.ringing={callId:n.callId,dismiss:a},typeof this.config.onIncomingCall=="function")try{this.config.onIncomingCall({bugId:e.bugId,...n})}catch{}this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"ringing"})},()=>{this.ringing===o&&(this.ringing=null)})},re=function(e){if(this.ringing&&!(e&&this.ringing.callId!==e)){try{this.ringing.dismiss()}catch{}this.ringing=null}},kt=async function(e,n){if(this.ringing=null,this.call||this.callStarting)return;this.callStarting=!0;let o,s;try{const r=await J(this.config.chunkBase);s=r.joinLiveCall,o=await r.openMicrophone()}catch(r){this.callStarting=!1,Ge({apiBase:this.config.apiBase,bugId:e,callId:n.callId}),this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:r});return}let i;try{i=await bn({apiBase:this.config.apiBase,bugId:e,callId:n.callId})}catch(r){for(const a of o.getTracks())a.stop();this.callStarting=!1,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"missed",error:r});return}try{const r=await s({realtimeUrl:i.realtime_url,stream:o,onState:(a,c)=>{(a==="ended"||a==="failed"||a==="missed")&&(this.call=null),typeof this.config.onCallState=="function"&&this.config.onCallState(a,{bugId:e,live:!0,incoming:!0,...c}),this.emit("call",{bugId:e,live:!0,incoming:!0,state:a,...c})}});this.call=r,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"answered"})}catch(r){for(const a of o.getTracks())a.stop();this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:r})}finally{this.callStarting=!1}};const xe=new ht;return xe.Client=ht,xe.version=X.version,xe});
|
|
298
310
|
//# sourceMappingURL=bugcatch.umd.js.map
|