@bugjar/reporter 0.1.1 → 0.1.2

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.
@@ -18888,7 +18888,7 @@ async function IA(t) {
18888
18888
  }))
18889
18889
  }, u = await gc(`${e}/upload-url`, {
18890
18890
  method: "POST",
18891
- headers: { "Content-Type": "application/json" },
18891
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
18892
18892
  body: JSON.stringify({
18893
18893
  projectKey: n,
18894
18894
  manifest: a,
@@ -18916,7 +18916,7 @@ async function IA(t) {
18916
18916
  await Promise.all(m);
18917
18917
  const g = await gc(`${e}/reports/${c}/finalize`, {
18918
18918
  method: "POST",
18919
- headers: { "Content-Type": "application/json" },
18919
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
18920
18920
  body: JSON.stringify({
18921
18921
  projectKey: n,
18922
18922
  finalizeToken: d,
@@ -19189,7 +19189,7 @@ class $A {
19189
19189
  try {
19190
19190
  const n = await fetch(
19191
19191
  `${this.config.apiUrl}/capture-invitations/${encodeURIComponent(e)}/scope`,
19192
- { method: "GET" }
19192
+ { method: "GET", headers: { Accept: "application/json" } }
19193
19193
  );
19194
19194
  if (!n.ok) {
19195
19195
  const s = await n.json().catch(() => ({}));
package/dist/index.cjs CHANGED
@@ -146,5 +146,5 @@ PERFORMANCE OF THIS SOFTWARE.
146
146
  outline: none;
147
147
  box-shadow: 0 0 0 3px ${s}, 0 6px 24px -8px rgba(0, 0, 0, 0.28);
148
148
  }
149
- `}),g.jsxs("button",{type:"button",className:"bugjar-trigger",onClick:t,children:[g.jsx(aw,{size:14,stroke:2}),e]})]})}function nw(r,e){const t=r.match(/^#([0-9a-f]{6})$/i);if(!t)return r;const i=parseInt(t[1],16),s=Math.max(0,Math.round((i>>16&255)*(1-e))),n=Math.max(0,Math.round((i>>8&255)*(1-e))),o=Math.max(0,Math.round((i&255)*(1-e)));return`#${(s<<16|n<<8|o).toString(16).padStart(6,"0")}`}function ow(r,e){const t=r.match(/^#([0-9a-f]{6})$/i);if(!t)return r;const i=parseInt(t[1],16);return`rgba(${i>>16&255}, ${i>>8&255}, ${i&255}, ${e})`}function aw({size:r=14,stroke:e=1.7}){return g.jsxs("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",style:{flexShrink:0},"aria-hidden":"true",children:[g.jsx("ellipse",{cx:"12",cy:"13",rx:"5",ry:"6",stroke:"currentColor",strokeWidth:e}),g.jsx("path",{d:"M12 7 V4 M9 5 l3 2 3-2 M5 11 l-2.5 -1 M5 15 l-2.5 1 M19 11 l2.5 -1 M19 15 l2.5 1 M9 18 l-2 2 M15 18 l2 2",stroke:"currentColor",strokeWidth:e,strokeLinecap:"round",strokeLinejoin:"round"})]})}function lw({children:r}){return g.jsx("div",{style:{background:"#111827",color:"white",padding:"10px 16px",borderRadius:8,fontFamily:"system-ui",fontSize:13},children:r})}function cw({color:r,url:e,onDismiss:t}){return g.jsxs("div",{style:{background:"white",padding:16,borderRadius:8,border:`2px solid ${r}`,fontFamily:"system-ui",fontSize:13,boxShadow:"0 10px 30px rgba(0,0,0,0.2)",maxWidth:320},children:[g.jsx("div",{style:{fontWeight:600,marginBottom:6},children:"Report sent — thank you!"}),e&&g.jsx("a",{href:e,target:"_blank",rel:"noreferrer",style:{color:r},children:"View in dashboard →"}),g.jsx("div",{style:{marginTop:12,textAlign:"right"},children:g.jsx(xs,{onClick:t,children:"Close"})})]})}function uw({error:r,onDismiss:e,onDownload:t}){return g.jsxs("div",{style:{background:"white",padding:16,borderRadius:8,border:"2px solid #ef4444",fontFamily:"system-ui",fontSize:13,boxShadow:"0 10px 30px rgba(0,0,0,0.2)",maxWidth:360},children:[g.jsx("div",{style:{fontWeight:600,marginBottom:6,color:"#b91c1c"},children:"Upload failed"}),g.jsx("div",{style:{color:"#4b5563",marginBottom:4,fontFamily:"ui-monospace, monospace",fontSize:12,wordBreak:"break-word"},children:r}),g.jsx("div",{style:{color:"#9ca3af",fontSize:11,lineHeight:1.5,marginTop:6},children:"Your report is still in memory. You can save it as a file and email it to support, or dismiss this toast to discard."}),g.jsxs("div",{style:{marginTop:12,display:"flex",gap:8,justifyContent:"flex-end"},children:[g.jsx(xs,{onClick:e,children:"Discard"}),g.jsx(xs,{onClick:t,children:"Download as file"})]})]})}function xs({onClick:r,children:e}){return g.jsx("button",{onClick:r,style:{background:"white",color:"#111827",border:"1px solid #d1d5db",borderRadius:6,padding:"10px 18px",fontWeight:500,fontSize:13,cursor:"pointer"},children:e})}const hw=typeof window<"u"?window.fetch.bind(window):fetch;async function fw(r){const{apiUrl:e,projectKey:t,userToken:i,captureToken:s,report:n,attachments:o}=r,a=n.rrwebEvents.length>0,l={replay:a?{sizeBytes:yw(n.rrwebEvents),durationMs:n.durationMs}:null,audio:n.audioBlob?{sizeBytes:n.audioBlob.size}:null,screenshot:{sizeBytes:n.screenshotBlob.size},attachments:o.map(p=>({filename:p.name,sizeBytes:p.size,mimeType:p.type}))},c=await Es(`${e}/upload-url`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectKey:t,manifest:l,...i?{userToken:i}:{},...s?{captureToken:s}:{}})});if(!c.ok)throw new Error(`upload-url failed: ${c.status} ${(await c.text()).slice(0,200)}`);const{reportId:u,finalizeToken:h,uploads:f}=await c.json(),d=[];f.replay&&a&&d.push(Cr(f.replay.url,new Blob([JSON.stringify(n.rrwebEvents)],{type:"application/json"}))),f.audio&&n.audioBlob&&d.push(Cr(f.audio.url,n.audioBlob)),d.push(Cr(f.screenshot.url,n.screenshotBlob));for(let p=0;p<o.length;p++){const y=o[p],b=f.attachments[p];if(!y||!b)throw new Error(`Server returned ${f.attachments.length} presigns for ${o.length} attachments`);d.push(Cr(b.url,y))}await Promise.all(d);const m=await Es(`${e}/reports/${u}/finalize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectKey:t,finalizeToken:h,description:n.description,durationMs:n.durationMs,consoleLogs:n.consoleLogs,networkEvents:n.networkEvents,annotations:n.annotations,url:n.url,userAgent:n.userAgent,viewport:n.viewport,redactionSummary:n.redactionSummary,strictMode:n.strictMode,attachmentIds:f.attachments.map(p=>p.id)})});if(!m.ok)throw new Error(`finalize failed: ${m.status}`);const{dashboardUrl:w}=await m.json();return{reportId:u,dashboardUrl:w}}async function Cr(r,e){const t=await Es(r,{method:"PUT",headers:{"Content-Type":e.type||"application/octet-stream"},body:e});if(!t.ok){const i=await t.text().catch(()=>"");throw new Error(`PUT ${Yr(r)} failed: ${t.status} ${i.slice(0,160)}`)}}const xr=[200,800,3200],Ho=3e4;async function Es(r,e){let t=null;for(let i=0;i<=xr.length;i++){try{const o=await gw(r,e);if(!dw(o.status)||i===xr.length)return o}catch(o){if(t=o,i===xr.length)throw o}const s=xr[i],n=(Math.random()-.5)*.5*s;await pw(s+n)}throw t instanceof Error?t:new Error(`retryingFetch exhausted attempts for ${Yr(r)}`)}function dw(r){return r===408||r===502||r===503||r===504}function pw(r){return new Promise(e=>setTimeout(e,Math.max(0,r)))}function mw(r,e){return!r||typeof AbortSignal.any!="function"?e:AbortSignal.any([r,e])}async function gw(r,e){const t=AbortSignal.timeout(Ho),i=mw(e.signal,t);try{return await hw(r,{...e,signal:i})}catch(s){const n=(e.method??"GET").toUpperCase();if(t.aborted&&!e.signal?.aborted)throw new Error(`${n} ${Yr(r)} timed out after ${Ho/1e3}s`);const a=s,l=a?.cause instanceof Error?`: ${a.cause.message}`:a?.cause?`: ${String(a.cause)}`:"",c=s instanceof Error?s.message:String(s);throw new Error(`${n} ${Yr(r)} failed: ${c}${l}`)}}function Yr(r){try{const e=new URL(r),t=e.pathname.length>60?`${e.pathname.slice(0,57)}…`:e.pathname;return`${e.host}${t}`}catch{return r.slice(0,80)}}function yw(r){try{return new Blob([JSON.stringify(r)]).size}catch{return 0}}async function ww(r,e){const t={reportId:r.reportId,createdAt:r.createdAt,durationMs:r.durationMs,description:r.description,url:r.url,userAgent:r.userAgent,viewport:r.viewport,consoleLogs:r.consoleLogs,networkEvents:r.networkEvents,annotations:r.annotations,redactionSummary:r.redactionSummary,strictMode:r.strictMode,attachmentNames:e.map(n=>n.name)},i=new Blob([JSON.stringify({manifest:t,rrwebEvents:r.rrwebEvents},null,2)],{type:"application/json"}),s=document.createElement("a");s.href=URL.createObjectURL(i),s.download=`bugjar-report-${r.reportId}.json`,s.click(),URL.revokeObjectURL(s.href)}class bw{constructor(){k(this,"config",null);k(this,"root",null);k(this,"host",null);k(this,"markupHost",null);k(this,"markupController",null);k(this,"consoleCapture",null);k(this,"networkCapture",null);k(this,"recorder",null);k(this,"view","idle");k(this,"isRecording",!1);k(this,"elapsedMs",0);k(this,"capturedReport",null);k(this,"preview",null);k(this,"previewObjectUrls",[]);k(this,"error",null);k(this,"failedAttachments",null);k(this,"errorObserved",!1);k(this,"sessionId",null);k(this,"persistedActiveMs",0);k(this,"resumingToast",null);k(this,"lastRecording",null);k(this,"finalizingInFlight",!1)}init(e){if(this.config)return this.publicApi();this.config=vw(e),this.host=document.createElement("div"),this.host.setAttribute("data-bugjar-block","true"),this.host.id="bugjar-root",document.body.appendChild(this.host),this.root=Ii(this.host);const t=()=>this.onErrorObserved();this.consoleCapture=Tc(this.config.capture.consoleBufferSize,t),this.networkCapture=$c(this.config.capture.networkBufferSize,t);const i=Sw(this.config.captureTokenParam);return i&&this.applyCaptureToken(i),this.render(),this.attemptRecovery(),this.publicApi()}async attemptRecovery(){if(!this.config)return;const e=this.config.projectKey,t=Zc(e);if(!t)return;if(!Xc(t)){We(e);try{await Yt(t.sessionId)}catch{}return}let i=null;try{i=await Uc(t.sessionId)}catch{We(e);return}if(!i){We(e);return}const s=Math.max(0,i.maxDurationMs-i.activeMs);if(s<500){We(e);try{await Yt(i.sessionId)}catch{}return}try{this.consoleCapture.hydrate(i.consoleEntries),this.networkCapture.hydrate(i.networkEvents)}catch(o){this.config.onError?.(o instanceof Error?o:new Error(String(o)))}this.sessionId=i.sessionId,this.persistedActiveMs=i.activeMs,this.view="active",this.isRecording=!0,this.elapsedMs=i.activeMs,this.resumingToast={remainingMs:s},this.ensureMarkupLayer(),this.render();const n=new pn({sessionId:i.sessionId,projectKey:e,persistedActiveMs:i.activeMs,strictMode:this.config.strictMode,disabledCategories:this.config.disabledCategories,captureMicrophone:this.config.capture.captureMicrophone,maxDurationSec:this.config.capture.maxDurationSec,consoleCapture:this.consoleCapture,networkCapture:this.networkCapture,onTick:o=>{this.elapsedMs=o,this.render()},onStop:o=>{this.lastRecording={events:o.events,audioBlob:o.audioBlob,durationMs:o.durationMs},this.isRecording=!1,this.recorder=null,this.render()}});n.hydrateEvents(i.events),n.hydrateAudioChunks(i.audioChunks),this.recorder=n;try{await n.start()}catch(o){this.recorder=null,this.sessionId=null,this.persistedActiveMs=0,this.isRecording=!1,this.view="idle",this.resumingToast=null,We(e);try{await Yt(i.sessionId)}catch{}this.config.onError?.(o instanceof Error?o:new Error(String(o))),this.render();return}window.setTimeout(()=>{this.resumingToast=null,this.render()},3500)}onErrorObserved(){this.errorObserved||(this.errorObserved=!0,this.render())}publicApi(){return{open:()=>this.open(),close:()=>this.close()}}async applyCaptureToken(e){if(this.config&&this.config.captureToken!==e)try{const t=await fetch(`${this.config.apiUrl}/capture-invitations/${encodeURIComponent(e)}/scope`,{method:"GET"});if(!t.ok){const n=await t.json().catch(()=>({}));throw new Error(`capture-token scope fetch failed (${t.status}): ${n.error?.code??"unknown"}`)}const{disableCategories:i}=await t.json(),s=eu(i);this.config.captureToken=e,this.config.disabledCategories=s}catch(t){this.config.onError?.(t instanceof Error?t:new Error(String(t)))}}ensureMarkupLayer(){if(this.markupController)return this.markupController;const e=document.createElement("div");return e.id="bugjar-markup-layer",document.body.appendChild(e),this.markupHost=e,this.markupController=new Pc(e),this.markupController}teardownMarkupLayer(){this.markupController&&(this.markupController.destroy(),this.markupController=null),this.markupHost&&(this.markupHost.remove(),this.markupHost=null)}open(){if(!this.config)throw new Error("BugJar.init() must be called first");this.view="active",this.isRecording=!1,this.elapsedMs=0,this.lastRecording=null,this.ensureMarkupLayer(),this.render()}close(){this.view="idle",this.isRecording=!1,this.elapsedMs=0,this.capturedReport=null,this.preview=null,this.error=null,this.lastRecording=null,this.resumingToast=null,this.releasePreviewObjectUrls(),this.recorder&&(this.recorder.stop().catch(()=>{}),this.recorder=null),this.discardPersistedSession(),this.teardownMarkupLayer(),this.render()}discardPersistedSession(){if(!this.config||!this.sessionId)return;const e=this.config.projectKey,t=this.sessionId;We(e),Yt(t).catch(()=>{}),this.sessionId=null,this.persistedActiveMs=0}releasePreviewObjectUrls(){for(const e of this.previewObjectUrls)try{URL.revokeObjectURL(e)}catch{}this.previewObjectUrls=[]}render(){if(!this.root||!this.config)return;const{showTrigger:e,showOnError:t}=this.config.ui,i=e&&(this.errorObserved||!t);this.root.render(g.jsx(le.StrictMode,{children:g.jsx(rw,{projectKey:this.config.projectKey,primaryColor:this.config.ui.primaryColor,position:this.config.ui.position,maxDurationSec:this.config.capture.maxDurationSec,strictMode:this.config.strictMode,triggerVisible:i,triggerLabel:this.config.ui.triggerLabel,view:this.view,isRecording:this.isRecording,hasRecording:this.lastRecording!==null,elapsedMs:this.elapsedMs,preview:this.preview,error:this.error,resumingToast:this.resumingToast,onOpenActive:()=>this.open(),onCancel:()=>this.close(),onStartRecording:async()=>{await this.startRecording()},onStopRecording:async()=>{await this.stopRecording()},onToggleMicMute:s=>this.recorder?.toggleMic(s),onFinalize:async()=>{await this.finalizeReport()},onBackToMarkup:()=>this.backToMarkup(),onSendReport:async s=>{await this.sendReport(s)},onDownloadFailed:async()=>{await this.downloadOnDemand()},onSelectTool:s=>this.markupController?.setTool(s),onSelectColor:s=>this.markupController?.setColor(s),onUndoMarkup:()=>this.markupController?.undo()})}))}async startRecording(){if(!this.config||this.isRecording||this.recorder)return;this.discardPersistedSession(),this.isRecording=!0,this.elapsedMs=0,this.lastRecording=null,this.persistedActiveMs=0;const e=hn();this.sessionId=e;const t={sessionId:e,projectKey:this.config.projectKey,startedAt:Date.now(),activeMs:0,maxDurationMs:this.config.capture.maxDurationSec*1e3,events:[],audioChunks:[],consoleEntries:[],networkEvents:[],lastSeenAt:Date.now()};try{await zc(t)}catch(i){this.config.onError?.(i instanceof Error?i:new Error(String(i)))}this.render(),this.recorder=new pn({sessionId:e,projectKey:this.config.projectKey,persistedActiveMs:0,strictMode:this.config.strictMode,disabledCategories:this.config.disabledCategories,captureMicrophone:this.config.capture.captureMicrophone,maxDurationSec:this.config.capture.maxDurationSec,consoleCapture:this.consoleCapture,networkCapture:this.networkCapture,onTick:i=>{this.elapsedMs=i,this.render()},onStop:i=>{this.lastRecording={events:i.events,audioBlob:i.audioBlob,durationMs:i.durationMs},this.isRecording=!1,this.recorder=null,this.render()}});try{await this.recorder.start()}catch(i){await this.recorder.stop().catch(()=>{}),this.recorder=null,this.isRecording=!1,this.lastRecording=null,this.discardPersistedSession(),this.error=i instanceof Error?i.message:String(i),this.config.onError?.(i instanceof Error?i:new Error(String(i))),this.render()}}async stopRecording(){this.recorder&&await this.recorder.stop()}async finalizeReport(){if(this.config&&!this.finalizingInFlight){this.finalizingInFlight=!0;try{this.recorder&&await this.recorder.stop(),this.discardPersistedSession();const e=Jo(),t={disabledCategories:this.config.disabledCategories},i=this.lastRecording,s=i?nu(i.events,e,t):[],n=i?this.consoleCapture.snapshot().map(m=>xt(m,e,t)):[],o=i?this.networkCapture.snapshot().map(m=>{const w=xt(m,e,t);return{...w,url:Di(w.url,e)}}):[],a=await gh(),l={width:window.innerWidth,height:window.innerHeight},c=i?.audioBlob??null,u=i?.durationMs??0,h={reportId:hn(),createdAt:Date.now(),durationMs:u,rrwebEvents:s,audioBlob:c,screenshotBlob:a,consoleLogs:n,networkEvents:o,annotations:[],description:"",url:Di(location.href,e),userAgent:navigator.userAgent,viewport:l,redactionSummary:e,strictMode:this.config.strictMode};this.capturedReport=h,this.releasePreviewObjectUrls();const f=URL.createObjectURL(a),d=c?URL.createObjectURL(c):null;this.previewObjectUrls=[f,d].filter(m=>m!==null),this.preview={hasReplay:s.length>0,durationMs:u,replayEvents:s,replayEventCount:s.length,hasAudio:c!==null,audioBlobUrl:d,consoleLogs:n,networkEvents:o,redactionSummary:e,screenshotUrl:f,capturedViewport:l,pageUrl:location.href,userAgent:navigator.userAgent,reportUrl:null},this.view="preview",this.render()}finally{this.finalizingInFlight=!1}}}backToMarkup(){this.preview=null,this.capturedReport=null,this.view="active",this.render()}async sendReport(e){if(!(!this.capturedReport||!this.config)){this.capturedReport.description=e.description,this.capturedReport.annotations=e.annotations,this.view="uploading",this.render();try{const{reportId:t,dashboardUrl:i}=await fw({apiUrl:this.config.apiUrl,projectKey:this.config.projectKey,userToken:this.config.userToken,captureToken:this.config.captureToken,report:this.capturedReport,attachments:e.attachments});this.preview&&(this.preview.reportUrl=i),this.view="success",this.teardownMarkupLayer(),this.config.onReportSubmitted?.(t),this.render()}catch(t){this.error=t instanceof Error?t.message:String(t),this.failedAttachments=e.attachments,this.view="failed",this.config.onError?.(t instanceof Error?t:new Error(String(t))),this.render()}}}async downloadOnDemand(){if(this.capturedReport)try{await ww(this.capturedReport,this.failedAttachments??[])}catch(e){this.config?.onError?.(e instanceof Error?e:new Error(String(e)))}}}function vw(r){return{projectKey:r.projectKey,apiUrl:Ch,userToken:r.userToken??null,user:r.user??{id:""},strictMode:r.strictMode??!1,capture:{...vh,...r.capture??{}},ui:{...Sh,...r.ui??{}},onReportSubmitted:r.onReportSubmitted??(()=>{}),onError:r.onError??(()=>{}),captureTokenParam:r.captureTokenParam??"bugjar_capture",captureToken:null,disabledCategories:new Set}}function Sw(r){if(typeof window>"u"||!window.location)return null;try{const t=new URLSearchParams(window.location.search).get(r);return t&&t.length>0?t:null}catch{return null}}const yc=new bw,_i=yc,wc={init:r=>_i.init(r),open:()=>_i.open(),close:()=>_i.close()};typeof window<"u"&&(window.BugJar=wc);exports.BugJar=wc;exports._client=yc;
149
+ `}),g.jsxs("button",{type:"button",className:"bugjar-trigger",onClick:t,children:[g.jsx(aw,{size:14,stroke:2}),e]})]})}function nw(r,e){const t=r.match(/^#([0-9a-f]{6})$/i);if(!t)return r;const i=parseInt(t[1],16),s=Math.max(0,Math.round((i>>16&255)*(1-e))),n=Math.max(0,Math.round((i>>8&255)*(1-e))),o=Math.max(0,Math.round((i&255)*(1-e)));return`#${(s<<16|n<<8|o).toString(16).padStart(6,"0")}`}function ow(r,e){const t=r.match(/^#([0-9a-f]{6})$/i);if(!t)return r;const i=parseInt(t[1],16);return`rgba(${i>>16&255}, ${i>>8&255}, ${i&255}, ${e})`}function aw({size:r=14,stroke:e=1.7}){return g.jsxs("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",style:{flexShrink:0},"aria-hidden":"true",children:[g.jsx("ellipse",{cx:"12",cy:"13",rx:"5",ry:"6",stroke:"currentColor",strokeWidth:e}),g.jsx("path",{d:"M12 7 V4 M9 5 l3 2 3-2 M5 11 l-2.5 -1 M5 15 l-2.5 1 M19 11 l2.5 -1 M19 15 l2.5 1 M9 18 l-2 2 M15 18 l2 2",stroke:"currentColor",strokeWidth:e,strokeLinecap:"round",strokeLinejoin:"round"})]})}function lw({children:r}){return g.jsx("div",{style:{background:"#111827",color:"white",padding:"10px 16px",borderRadius:8,fontFamily:"system-ui",fontSize:13},children:r})}function cw({color:r,url:e,onDismiss:t}){return g.jsxs("div",{style:{background:"white",padding:16,borderRadius:8,border:`2px solid ${r}`,fontFamily:"system-ui",fontSize:13,boxShadow:"0 10px 30px rgba(0,0,0,0.2)",maxWidth:320},children:[g.jsx("div",{style:{fontWeight:600,marginBottom:6},children:"Report sent — thank you!"}),e&&g.jsx("a",{href:e,target:"_blank",rel:"noreferrer",style:{color:r},children:"View in dashboard →"}),g.jsx("div",{style:{marginTop:12,textAlign:"right"},children:g.jsx(xs,{onClick:t,children:"Close"})})]})}function uw({error:r,onDismiss:e,onDownload:t}){return g.jsxs("div",{style:{background:"white",padding:16,borderRadius:8,border:"2px solid #ef4444",fontFamily:"system-ui",fontSize:13,boxShadow:"0 10px 30px rgba(0,0,0,0.2)",maxWidth:360},children:[g.jsx("div",{style:{fontWeight:600,marginBottom:6,color:"#b91c1c"},children:"Upload failed"}),g.jsx("div",{style:{color:"#4b5563",marginBottom:4,fontFamily:"ui-monospace, monospace",fontSize:12,wordBreak:"break-word"},children:r}),g.jsx("div",{style:{color:"#9ca3af",fontSize:11,lineHeight:1.5,marginTop:6},children:"Your report is still in memory. You can save it as a file and email it to support, or dismiss this toast to discard."}),g.jsxs("div",{style:{marginTop:12,display:"flex",gap:8,justifyContent:"flex-end"},children:[g.jsx(xs,{onClick:e,children:"Discard"}),g.jsx(xs,{onClick:t,children:"Download as file"})]})]})}function xs({onClick:r,children:e}){return g.jsx("button",{onClick:r,style:{background:"white",color:"#111827",border:"1px solid #d1d5db",borderRadius:6,padding:"10px 18px",fontWeight:500,fontSize:13,cursor:"pointer"},children:e})}const hw=typeof window<"u"?window.fetch.bind(window):fetch;async function fw(r){const{apiUrl:e,projectKey:t,userToken:i,captureToken:s,report:n,attachments:o}=r,a=n.rrwebEvents.length>0,l={replay:a?{sizeBytes:yw(n.rrwebEvents),durationMs:n.durationMs}:null,audio:n.audioBlob?{sizeBytes:n.audioBlob.size}:null,screenshot:{sizeBytes:n.screenshotBlob.size},attachments:o.map(p=>({filename:p.name,sizeBytes:p.size,mimeType:p.type}))},c=await Es(`${e}/upload-url`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({projectKey:t,manifest:l,...i?{userToken:i}:{},...s?{captureToken:s}:{}})});if(!c.ok)throw new Error(`upload-url failed: ${c.status} ${(await c.text()).slice(0,200)}`);const{reportId:u,finalizeToken:h,uploads:f}=await c.json(),d=[];f.replay&&a&&d.push(Cr(f.replay.url,new Blob([JSON.stringify(n.rrwebEvents)],{type:"application/json"}))),f.audio&&n.audioBlob&&d.push(Cr(f.audio.url,n.audioBlob)),d.push(Cr(f.screenshot.url,n.screenshotBlob));for(let p=0;p<o.length;p++){const y=o[p],b=f.attachments[p];if(!y||!b)throw new Error(`Server returned ${f.attachments.length} presigns for ${o.length} attachments`);d.push(Cr(b.url,y))}await Promise.all(d);const m=await Es(`${e}/reports/${u}/finalize`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({projectKey:t,finalizeToken:h,description:n.description,durationMs:n.durationMs,consoleLogs:n.consoleLogs,networkEvents:n.networkEvents,annotations:n.annotations,url:n.url,userAgent:n.userAgent,viewport:n.viewport,redactionSummary:n.redactionSummary,strictMode:n.strictMode,attachmentIds:f.attachments.map(p=>p.id)})});if(!m.ok)throw new Error(`finalize failed: ${m.status}`);const{dashboardUrl:w}=await m.json();return{reportId:u,dashboardUrl:w}}async function Cr(r,e){const t=await Es(r,{method:"PUT",headers:{"Content-Type":e.type||"application/octet-stream"},body:e});if(!t.ok){const i=await t.text().catch(()=>"");throw new Error(`PUT ${Yr(r)} failed: ${t.status} ${i.slice(0,160)}`)}}const xr=[200,800,3200],Ho=3e4;async function Es(r,e){let t=null;for(let i=0;i<=xr.length;i++){try{const o=await gw(r,e);if(!dw(o.status)||i===xr.length)return o}catch(o){if(t=o,i===xr.length)throw o}const s=xr[i],n=(Math.random()-.5)*.5*s;await pw(s+n)}throw t instanceof Error?t:new Error(`retryingFetch exhausted attempts for ${Yr(r)}`)}function dw(r){return r===408||r===502||r===503||r===504}function pw(r){return new Promise(e=>setTimeout(e,Math.max(0,r)))}function mw(r,e){return!r||typeof AbortSignal.any!="function"?e:AbortSignal.any([r,e])}async function gw(r,e){const t=AbortSignal.timeout(Ho),i=mw(e.signal,t);try{return await hw(r,{...e,signal:i})}catch(s){const n=(e.method??"GET").toUpperCase();if(t.aborted&&!e.signal?.aborted)throw new Error(`${n} ${Yr(r)} timed out after ${Ho/1e3}s`);const a=s,l=a?.cause instanceof Error?`: ${a.cause.message}`:a?.cause?`: ${String(a.cause)}`:"",c=s instanceof Error?s.message:String(s);throw new Error(`${n} ${Yr(r)} failed: ${c}${l}`)}}function Yr(r){try{const e=new URL(r),t=e.pathname.length>60?`${e.pathname.slice(0,57)}…`:e.pathname;return`${e.host}${t}`}catch{return r.slice(0,80)}}function yw(r){try{return new Blob([JSON.stringify(r)]).size}catch{return 0}}async function ww(r,e){const t={reportId:r.reportId,createdAt:r.createdAt,durationMs:r.durationMs,description:r.description,url:r.url,userAgent:r.userAgent,viewport:r.viewport,consoleLogs:r.consoleLogs,networkEvents:r.networkEvents,annotations:r.annotations,redactionSummary:r.redactionSummary,strictMode:r.strictMode,attachmentNames:e.map(n=>n.name)},i=new Blob([JSON.stringify({manifest:t,rrwebEvents:r.rrwebEvents},null,2)],{type:"application/json"}),s=document.createElement("a");s.href=URL.createObjectURL(i),s.download=`bugjar-report-${r.reportId}.json`,s.click(),URL.revokeObjectURL(s.href)}class bw{constructor(){k(this,"config",null);k(this,"root",null);k(this,"host",null);k(this,"markupHost",null);k(this,"markupController",null);k(this,"consoleCapture",null);k(this,"networkCapture",null);k(this,"recorder",null);k(this,"view","idle");k(this,"isRecording",!1);k(this,"elapsedMs",0);k(this,"capturedReport",null);k(this,"preview",null);k(this,"previewObjectUrls",[]);k(this,"error",null);k(this,"failedAttachments",null);k(this,"errorObserved",!1);k(this,"sessionId",null);k(this,"persistedActiveMs",0);k(this,"resumingToast",null);k(this,"lastRecording",null);k(this,"finalizingInFlight",!1)}init(e){if(this.config)return this.publicApi();this.config=vw(e),this.host=document.createElement("div"),this.host.setAttribute("data-bugjar-block","true"),this.host.id="bugjar-root",document.body.appendChild(this.host),this.root=Ii(this.host);const t=()=>this.onErrorObserved();this.consoleCapture=Tc(this.config.capture.consoleBufferSize,t),this.networkCapture=$c(this.config.capture.networkBufferSize,t);const i=Sw(this.config.captureTokenParam);return i&&this.applyCaptureToken(i),this.render(),this.attemptRecovery(),this.publicApi()}async attemptRecovery(){if(!this.config)return;const e=this.config.projectKey,t=Zc(e);if(!t)return;if(!Xc(t)){We(e);try{await Yt(t.sessionId)}catch{}return}let i=null;try{i=await Uc(t.sessionId)}catch{We(e);return}if(!i){We(e);return}const s=Math.max(0,i.maxDurationMs-i.activeMs);if(s<500){We(e);try{await Yt(i.sessionId)}catch{}return}try{this.consoleCapture.hydrate(i.consoleEntries),this.networkCapture.hydrate(i.networkEvents)}catch(o){this.config.onError?.(o instanceof Error?o:new Error(String(o)))}this.sessionId=i.sessionId,this.persistedActiveMs=i.activeMs,this.view="active",this.isRecording=!0,this.elapsedMs=i.activeMs,this.resumingToast={remainingMs:s},this.ensureMarkupLayer(),this.render();const n=new pn({sessionId:i.sessionId,projectKey:e,persistedActiveMs:i.activeMs,strictMode:this.config.strictMode,disabledCategories:this.config.disabledCategories,captureMicrophone:this.config.capture.captureMicrophone,maxDurationSec:this.config.capture.maxDurationSec,consoleCapture:this.consoleCapture,networkCapture:this.networkCapture,onTick:o=>{this.elapsedMs=o,this.render()},onStop:o=>{this.lastRecording={events:o.events,audioBlob:o.audioBlob,durationMs:o.durationMs},this.isRecording=!1,this.recorder=null,this.render()}});n.hydrateEvents(i.events),n.hydrateAudioChunks(i.audioChunks),this.recorder=n;try{await n.start()}catch(o){this.recorder=null,this.sessionId=null,this.persistedActiveMs=0,this.isRecording=!1,this.view="idle",this.resumingToast=null,We(e);try{await Yt(i.sessionId)}catch{}this.config.onError?.(o instanceof Error?o:new Error(String(o))),this.render();return}window.setTimeout(()=>{this.resumingToast=null,this.render()},3500)}onErrorObserved(){this.errorObserved||(this.errorObserved=!0,this.render())}publicApi(){return{open:()=>this.open(),close:()=>this.close()}}async applyCaptureToken(e){if(this.config&&this.config.captureToken!==e)try{const t=await fetch(`${this.config.apiUrl}/capture-invitations/${encodeURIComponent(e)}/scope`,{method:"GET",headers:{Accept:"application/json"}});if(!t.ok){const n=await t.json().catch(()=>({}));throw new Error(`capture-token scope fetch failed (${t.status}): ${n.error?.code??"unknown"}`)}const{disableCategories:i}=await t.json(),s=eu(i);this.config.captureToken=e,this.config.disabledCategories=s}catch(t){this.config.onError?.(t instanceof Error?t:new Error(String(t)))}}ensureMarkupLayer(){if(this.markupController)return this.markupController;const e=document.createElement("div");return e.id="bugjar-markup-layer",document.body.appendChild(e),this.markupHost=e,this.markupController=new Pc(e),this.markupController}teardownMarkupLayer(){this.markupController&&(this.markupController.destroy(),this.markupController=null),this.markupHost&&(this.markupHost.remove(),this.markupHost=null)}open(){if(!this.config)throw new Error("BugJar.init() must be called first");this.view="active",this.isRecording=!1,this.elapsedMs=0,this.lastRecording=null,this.ensureMarkupLayer(),this.render()}close(){this.view="idle",this.isRecording=!1,this.elapsedMs=0,this.capturedReport=null,this.preview=null,this.error=null,this.lastRecording=null,this.resumingToast=null,this.releasePreviewObjectUrls(),this.recorder&&(this.recorder.stop().catch(()=>{}),this.recorder=null),this.discardPersistedSession(),this.teardownMarkupLayer(),this.render()}discardPersistedSession(){if(!this.config||!this.sessionId)return;const e=this.config.projectKey,t=this.sessionId;We(e),Yt(t).catch(()=>{}),this.sessionId=null,this.persistedActiveMs=0}releasePreviewObjectUrls(){for(const e of this.previewObjectUrls)try{URL.revokeObjectURL(e)}catch{}this.previewObjectUrls=[]}render(){if(!this.root||!this.config)return;const{showTrigger:e,showOnError:t}=this.config.ui,i=e&&(this.errorObserved||!t);this.root.render(g.jsx(le.StrictMode,{children:g.jsx(rw,{projectKey:this.config.projectKey,primaryColor:this.config.ui.primaryColor,position:this.config.ui.position,maxDurationSec:this.config.capture.maxDurationSec,strictMode:this.config.strictMode,triggerVisible:i,triggerLabel:this.config.ui.triggerLabel,view:this.view,isRecording:this.isRecording,hasRecording:this.lastRecording!==null,elapsedMs:this.elapsedMs,preview:this.preview,error:this.error,resumingToast:this.resumingToast,onOpenActive:()=>this.open(),onCancel:()=>this.close(),onStartRecording:async()=>{await this.startRecording()},onStopRecording:async()=>{await this.stopRecording()},onToggleMicMute:s=>this.recorder?.toggleMic(s),onFinalize:async()=>{await this.finalizeReport()},onBackToMarkup:()=>this.backToMarkup(),onSendReport:async s=>{await this.sendReport(s)},onDownloadFailed:async()=>{await this.downloadOnDemand()},onSelectTool:s=>this.markupController?.setTool(s),onSelectColor:s=>this.markupController?.setColor(s),onUndoMarkup:()=>this.markupController?.undo()})}))}async startRecording(){if(!this.config||this.isRecording||this.recorder)return;this.discardPersistedSession(),this.isRecording=!0,this.elapsedMs=0,this.lastRecording=null,this.persistedActiveMs=0;const e=hn();this.sessionId=e;const t={sessionId:e,projectKey:this.config.projectKey,startedAt:Date.now(),activeMs:0,maxDurationMs:this.config.capture.maxDurationSec*1e3,events:[],audioChunks:[],consoleEntries:[],networkEvents:[],lastSeenAt:Date.now()};try{await zc(t)}catch(i){this.config.onError?.(i instanceof Error?i:new Error(String(i)))}this.render(),this.recorder=new pn({sessionId:e,projectKey:this.config.projectKey,persistedActiveMs:0,strictMode:this.config.strictMode,disabledCategories:this.config.disabledCategories,captureMicrophone:this.config.capture.captureMicrophone,maxDurationSec:this.config.capture.maxDurationSec,consoleCapture:this.consoleCapture,networkCapture:this.networkCapture,onTick:i=>{this.elapsedMs=i,this.render()},onStop:i=>{this.lastRecording={events:i.events,audioBlob:i.audioBlob,durationMs:i.durationMs},this.isRecording=!1,this.recorder=null,this.render()}});try{await this.recorder.start()}catch(i){await this.recorder.stop().catch(()=>{}),this.recorder=null,this.isRecording=!1,this.lastRecording=null,this.discardPersistedSession(),this.error=i instanceof Error?i.message:String(i),this.config.onError?.(i instanceof Error?i:new Error(String(i))),this.render()}}async stopRecording(){this.recorder&&await this.recorder.stop()}async finalizeReport(){if(this.config&&!this.finalizingInFlight){this.finalizingInFlight=!0;try{this.recorder&&await this.recorder.stop(),this.discardPersistedSession();const e=Jo(),t={disabledCategories:this.config.disabledCategories},i=this.lastRecording,s=i?nu(i.events,e,t):[],n=i?this.consoleCapture.snapshot().map(m=>xt(m,e,t)):[],o=i?this.networkCapture.snapshot().map(m=>{const w=xt(m,e,t);return{...w,url:Di(w.url,e)}}):[],a=await gh(),l={width:window.innerWidth,height:window.innerHeight},c=i?.audioBlob??null,u=i?.durationMs??0,h={reportId:hn(),createdAt:Date.now(),durationMs:u,rrwebEvents:s,audioBlob:c,screenshotBlob:a,consoleLogs:n,networkEvents:o,annotations:[],description:"",url:Di(location.href,e),userAgent:navigator.userAgent,viewport:l,redactionSummary:e,strictMode:this.config.strictMode};this.capturedReport=h,this.releasePreviewObjectUrls();const f=URL.createObjectURL(a),d=c?URL.createObjectURL(c):null;this.previewObjectUrls=[f,d].filter(m=>m!==null),this.preview={hasReplay:s.length>0,durationMs:u,replayEvents:s,replayEventCount:s.length,hasAudio:c!==null,audioBlobUrl:d,consoleLogs:n,networkEvents:o,redactionSummary:e,screenshotUrl:f,capturedViewport:l,pageUrl:location.href,userAgent:navigator.userAgent,reportUrl:null},this.view="preview",this.render()}finally{this.finalizingInFlight=!1}}}backToMarkup(){this.preview=null,this.capturedReport=null,this.view="active",this.render()}async sendReport(e){if(!(!this.capturedReport||!this.config)){this.capturedReport.description=e.description,this.capturedReport.annotations=e.annotations,this.view="uploading",this.render();try{const{reportId:t,dashboardUrl:i}=await fw({apiUrl:this.config.apiUrl,projectKey:this.config.projectKey,userToken:this.config.userToken,captureToken:this.config.captureToken,report:this.capturedReport,attachments:e.attachments});this.preview&&(this.preview.reportUrl=i),this.view="success",this.teardownMarkupLayer(),this.config.onReportSubmitted?.(t),this.render()}catch(t){this.error=t instanceof Error?t.message:String(t),this.failedAttachments=e.attachments,this.view="failed",this.config.onError?.(t instanceof Error?t:new Error(String(t))),this.render()}}}async downloadOnDemand(){if(this.capturedReport)try{await ww(this.capturedReport,this.failedAttachments??[])}catch(e){this.config?.onError?.(e instanceof Error?e:new Error(String(e)))}}}function vw(r){return{projectKey:r.projectKey,apiUrl:Ch,userToken:r.userToken??null,user:r.user??{id:""},strictMode:r.strictMode??!1,capture:{...vh,...r.capture??{}},ui:{...Sh,...r.ui??{}},onReportSubmitted:r.onReportSubmitted??(()=>{}),onError:r.onError??(()=>{}),captureTokenParam:r.captureTokenParam??"bugjar_capture",captureToken:null,disabledCategories:new Set}}function Sw(r){if(typeof window>"u"||!window.location)return null;try{const t=new URLSearchParams(window.location.search).get(r);return t&&t.length>0?t:null}catch{return null}}const yc=new bw,_i=yc,wc={init:r=>_i.init(r),open:()=>_i.open(),close:()=>_i.close()};typeof window<"u"&&(window.BugJar=wc);exports.BugJar=wc;exports._client=yc;
150
150
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -13256,7 +13256,7 @@ async function mw(r) {
13256
13256
  }))
13257
13257
  }, c = await Rs(`${e}/upload-url`, {
13258
13258
  method: "POST",
13259
- headers: { "Content-Type": "application/json" },
13259
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
13260
13260
  body: JSON.stringify({
13261
13261
  projectKey: t,
13262
13262
  manifest: l,
@@ -13284,7 +13284,7 @@ async function mw(r) {
13284
13284
  await Promise.all(d);
13285
13285
  const m = await Rs(`${e}/reports/${u}/finalize`, {
13286
13286
  method: "POST",
13287
- headers: { "Content-Type": "application/json" },
13287
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
13288
13288
  body: JSON.stringify({
13289
13289
  projectKey: t,
13290
13290
  finalizeToken: h,
@@ -13557,7 +13557,7 @@ class Cw {
13557
13557
  try {
13558
13558
  const t = await fetch(
13559
13559
  `${this.config.apiUrl}/capture-invitations/${encodeURIComponent(e)}/scope`,
13560
- { method: "GET" }
13560
+ { method: "GET", headers: { Accept: "application/json" } }
13561
13561
  );
13562
13562
  if (!t.ok) {
13563
13563
  const n = await t.json().catch(() => ({}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bugjar/reporter",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Privacy-first bug reporting SDK. DOM replay + redaction + markup, runs only on user consent.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",