+57
-9
@@ -1,3 +0,3 @@ | ||
| 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var f="0.1.0",_={maxReports:50,maxBreadcrumbs:20,maxClicks:20,widget:false,collectors:{errors:true,console:true,network:true,clicks:true,interactions:true,performance:true,memory:true},rateLimit:{maxEvents:10,windowMs:1e3},beforeReport:r=>r,debug:false};var b=class{constructor(){this.listeners=new Map;}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t);}emit(e,t){this.listeners.get(e)?.forEach(o=>{try{o(t);}catch{}});}clear(){this.listeners.clear();}};var m=class{constructor(e){this.capacity=e;this.head=0;this._size=0;this.buffer=new Array(e);}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this._size<this.capacity&&this._size++;}toArray(){if(this._size===0)return [];let e=[],t=this._size<this.capacity?0:this.head;for(let o=0;o<this._size;o++){let n=(t+o)%this.capacity;e.push(this.buffer[n]);}return e}get size(){return this._size}get isFull(){return this._size===this.capacity}peek(){if(this._size===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}find(e){return this.toArray().find(e)}forEach(e){this.toArray().forEach(e);}clear(){this.buffer=new Array(this.capacity),this.head=0,this._size=0;}};var v=class{constructor(e,t){this.maxEvents=e;this.windowMs=t;this.timestamps=[];}allow(){let e=Date.now();return this.timestamps=this.timestamps.filter(t=>e-t<this.windowMs),this.timestamps.length>=this.maxEvents?false:(this.timestamps.push(e),true)}reset(){this.timestamps=[];}};function q(r){let e=5381;for(let t=0;t<r.length;t++)e=(e<<5)+e+r.charCodeAt(t)&4294967295;return (e>>>0).toString(36)}function I(r){let e;switch(r.kind){case "error":{let t=r.stack?.split(` | ||
| `)[1]?.trim()||"";e=`${r.name}:${r.message}:${t}`;break}case "console":e=`console:${r.level}:${r.args.join(",")}`;break;case "network":e=`network:${r.method}:${r.url}:${r.status}`;break;case "performance":e=`performance:${r.metric}:${Math.floor(r.value/100)*100}`;break;case "memory":e=`memory:${Math.floor(r.heapUsagePercent*10)/10}`;break}return q(e)}function A(){let r=new Uint8Array(8);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(36).padStart(2,"0")).join("").slice(0,12)}var W=3e3,y=class{constructor(e,t,o){this.eventBus=e;this.contextCollector=t;this.options=o;this.unsubscribers=[];this.reports=new m(o.maxReports),this.breadcrumbs=new m(o.maxBreadcrumbs),this.rateLimiter=new v(o.rateLimit.maxEvents,o.rateLimit.windowMs),this.subscribe();}subscribe(){this.unsubscribers.push(this.eventBus.on("error:captured",e=>{this.addBreadcrumb({category:"error",message:e.message}),this.handleCapturedEvent("error",e);}),this.eventBus.on("console:captured",e=>{this.addBreadcrumb({category:"console",message:`console.${e.level}: ${e.args.join(", ")}`}),e.level==="error"&&this.handleCapturedEvent("console",e);}),this.eventBus.on("network:captured",e=>{this.handleCapturedEvent("network",e);}),this.eventBus.on("performance:captured",e=>{this.addBreadcrumb({category:"performance",message:`${e.metric}: ${e.value}ms`}),this.handleCapturedEvent("performance",e);}),this.eventBus.on("memory:captured",e=>{this.handleCapturedEvent("memory",e);}),this.eventBus.on("breadcrumb:added",e=>{this.addBreadcrumb(e);}));}async handleCapturedEvent(e,t){if(!this.rateLimiter.allow())return;let o=I(t),n=this.reports.find(l=>l.fingerprint===o);if(n){n.count++,n.timestamp=new Date().toISOString(),this.eventBus.emit("report:deduplicated",n);return}let i={id:A(),fingerprint:o,type:e,timestamp:new Date().toISOString(),count:1,payload:t,breadcrumbs:this.breadcrumbs.toArray(),context:this.contextCollector.snapshot()};if(this.options.screenshotFn)try{i.screenshot=await Promise.race([this.options.screenshotFn(),new Promise((l,a)=>setTimeout(()=>a(new Error("screenshot timeout")),W))]);}catch{}let s=this.options.beforeReport(i);s&&(i=s,this.reports.push(i),this.eventBus.emit("report:created",i));}addBreadcrumb(e){this.breadcrumbs.push({...e,timestamp:new Date().toISOString()});}getReports(){return this.reports.toArray()}clear(){this.reports.clear(),this.breadcrumbs.clear(),this.unsubscribers.forEach(e=>e()),this.unsubscribers=[];}get reportCount(){return this.reports.size}};var w=class{constructor(e){this.eventBus=e;this.name="error";this.originalOnError=null;this.rejectionHandler=null;}setup(){this.originalOnError=window.onerror,window.onerror=(e,t,o,n,i)=>{let s={kind:"error",message:String(e),stack:i?.stack,filename:t??void 0,lineno:o??void 0,colno:n??void 0,name:i?.name};return this.eventBus.emit("error:captured",s),this.originalOnError?this.originalOnError.call(window,e,t,o,n,i):false},this.rejectionHandler=e=>{let t=e.reason,o={kind:"error",message:t instanceof Error?t.message:String(t),stack:t instanceof Error?t.stack:void 0,name:t instanceof Error?t.name:"UnhandledRejection"};this.eventBus.emit("error:captured",o);},window.addEventListener("unhandledrejection",this.rejectionHandler);}teardown(){window.onerror=this.originalOnError,this.originalOnError=null,this.rejectionHandler&&(window.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null);}};function g(r,e){let t=new WeakSet;return JSON.stringify(r,(o,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return "[Circular]";t.add(n);}return typeof n=="function"?"[Function]":typeof n=="symbol"?n.toString():n instanceof Error?{name:n.name,message:n.message,stack:n.stack}:n},e)}var x=class{constructor(e){this.eventBus=e;this.name="console";this.originalError=null;this.originalWarn=null;}setup(){this.originalError=console.error,this.originalWarn=console.warn,console.error=(...e)=>{let t={kind:"console",level:"error",args:e.map(o=>g(o))};this.eventBus.emit("console:captured",t),this.originalError.apply(console,e);},console.warn=(...e)=>{let t={kind:"console",level:"warn",args:e.map(o=>g(o))};this.eventBus.emit("console:captured",t),this.originalWarn.apply(console,e);};}teardown(){this.originalError&&(console.error=this.originalError),this.originalWarn&&(console.warn=this.originalWarn),this.originalError=null,this.originalWarn=null;}};var E=class{constructor(e){this.eventBus=e;this.name="network";this.originalFetch=null;this.originalXhrOpen=null;this.originalXhrSend=null;}setup(){this.patchFetch(),this.patchXHR();}patchFetch(){this.originalFetch=window.fetch;let e=this.eventBus,t=this.originalFetch;window.fetch=function(o,n){let i=n?.method?.toUpperCase()||"GET",s=typeof o=="string"?o:o instanceof URL?o.href:o.url,l=performance.now();return t.call(window,o,n).then(a=>{let p=Math.round(performance.now()-l);if(a.status>=400){let u={kind:"network",method:i,url:s,status:a.status,statusText:a.statusText,duration:p};e.emit("network:captured",u);}return e.emit("breadcrumb:added",{category:"network",message:`${i} ${s} -> ${a.status}`}),a},a=>{let p=Math.round(performance.now()-l),u={kind:"network",method:i,url:s,status:0,statusText:a.message||"Network Error",duration:p};throw e.emit("network:captured",u),a})};}patchXHR(){this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let e=this.eventBus,t=this.originalXhrOpen,o=this.originalXhrSend;XMLHttpRequest.prototype.open=function(n,i,...s){return this.__ghostbug_method=n.toUpperCase(),this.__ghostbug_url=String(i),t.apply(this,[n,i,...s])},XMLHttpRequest.prototype.send=function(n){let i=performance.now(),s=this;return s.addEventListener("loadend",function(){let l=Math.round(performance.now()-i),a=s.__ghostbug_method||"UNKNOWN",p=s.__ghostbug_url||"";if(s.status>=400||s.status===0){let u={kind:"network",method:a,url:p,status:s.status,statusText:s.statusText,duration:l};e.emit("network:captured",u);}e.emit("breadcrumb:added",{category:"network",message:`${a} ${p} -> ${s.status}`});}),o.call(this,n)};}teardown(){this.originalFetch&&(window.fetch=this.originalFetch,this.originalFetch=null),this.originalXhrOpen&&(XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=null),this.originalXhrSend&&(XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=null);}};function F(r){if(r.id)return `#${r.id}`;let e=r.getAttribute("data-testid");if(e)return `[data-testid="${e}"]`;let t=[],o=r,n=0;for(;o&&o!==document.documentElement&&n<5;){let i=o.tagName.toLowerCase();if(o.id){t.unshift(`#${o.id}`);break}let s=Array.from(o.classList).slice(0,2);s.length>0&&(i+="."+s.join("."));let l=o.parentElement;if(l){let a=o.tagName,p=Array.from(l.children).filter(u=>u.tagName===a);if(p.length>1){let u=p.indexOf(o)+1;i+=`:nth-child(${u})`;}}t.unshift(i),o=l,n++;}return t.join(" > ")}var k=class{constructor(e,t){this.eventBus=e;this.name="click";this.handler=null;this.clicks=new m(t);}setup(){this.handler=e=>{let t=e.target;if(!t)return;let o={timestamp:new Date().toISOString(),selector:F(t),tagName:t.tagName.toLowerCase(),text:(t.textContent||"").trim().slice(0,100),position:{x:e.clientX,y:e.clientY}};this.clicks.push(o),this.eventBus.emit("click:captured",o),this.eventBus.emit("breadcrumb:added",{category:"click",message:`Clicked ${o.tagName} "${o.text}"`,data:{selector:o.selector}});},document.addEventListener("click",this.handler,true);}getClickTrail(){return this.clicks.toArray()}teardown(){this.handler&&(document.removeEventListener("click",this.handler,true),this.handler=null),this.clicks.clear();}};var C=class{constructor(e){this.getMeta=e;this.name="context";}setup(){}teardown(){}snapshot(){let e=this.getMeta?.();return {url:window.location.href,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},devicePixelRatio:window.devicePixelRatio||1,timestamp:new Date().toISOString(),memory:performance.memory?{usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize}:void 0,user:e?.user,tags:e?.tags}}};var S=class{constructor(e){this.eventBus=e;this.name="interactions";this.handlers=[];this.scrollTimer=null;this.resizeTimer=null;}setup(){this.addHandler(window,"scroll",this.onScroll.bind(this),{passive:true,capture:true}),this.addHandler(document,"input",this.onInput.bind(this),true),this.addHandler(document,"change",this.onChange.bind(this),true),this.addHandler(window,"popstate",this.onPopState.bind(this)),this.addHandler(window,"hashchange",this.onHashChange.bind(this)),this.addHandler(document,"visibilitychange",this.onVisibilityChange.bind(this)),this.addHandler(window,"resize",this.onResize.bind(this),{passive:true});}addHandler(e,t,o,n){e.addEventListener(t,o,n),this.handlers.push({target:e,event:t,handler:o});}onScroll(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Scrolled",data:{x:window.scrollX,y:window.scrollY}});},300);}onInput(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"",i=t.type?`[type="${t.type}"]`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Input on ${o}${n}${i}`});}onChange(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Change on ${o}${n}`});}onPopState(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Navigated to ${window.location.href}`});}onHashChange(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Hash changed to ${window.location.hash}`});}onVisibilityChange(){this.eventBus.emit("breadcrumb:added",{category:"visibility",message:document.hidden?"Tab hidden":"Tab visible"});}onResize(){this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Window resized",data:{width:window.innerWidth,height:window.innerHeight}});},300);}teardown(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.resizeTimer&&clearTimeout(this.resizeTimer),this.handlers.forEach(({target:e,event:t,handler:o})=>{e.removeEventListener(t,o);}),this.handlers=[];}};var B=class{constructor(e){this.eventBus=e;this.name="performance";this.observers=[];}setup(){typeof PerformanceObserver>"u"||(this.observe("longtask",e=>{e.forEach(t=>{if(t.duration<50)return;let o={kind:"performance",metric:"longtask",value:Math.round(t.duration),entries:[{name:t.name,duration:t.duration,startTime:t.startTime}]};this.eventBus.emit("performance:captured",o),this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Long task: ${Math.round(t.duration)}ms`});});}),this.observe("largest-contentful-paint",e=>{let t=e[e.length-1];t&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`LCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});}),this.observe("paint",e=>{e.forEach(t=>{t.name==="first-contentful-paint"&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`FCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});});}),this.observe("layout-shift",e=>{e.forEach(t=>{let o=t.value;o>.1&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Layout shift: ${o.toFixed(4)}`,data:{cls:o}});});}));}observe(e,t){try{let o=new PerformanceObserver(n=>{t(n.getEntries());});o.observe({type:e,buffered:!0}),this.observers.push(o);}catch{}}teardown(){this.observers.forEach(e=>e.disconnect()),this.observers=[];}};function j(){let r=performance.memory;return !r||typeof r.usedJSHeapSize!="number"?null:r}var R=class{constructor(e){this.eventBus=e;this.name="memory";this.intervalId=null;this.baselineUsed=null;}setup(){let e=j();e&&(this.baselineUsed=e.usedJSHeapSize,this.intervalId=setInterval(()=>{let t=j();if(!t)return;let o=t.usedJSHeapSize/t.jsHeapSizeLimit,n=this.baselineUsed>0?(t.usedJSHeapSize-this.baselineUsed)/this.baselineUsed:0;this.eventBus.emit("breadcrumb:added",{category:"memory",message:`Heap: ${(o*100).toFixed(1)}% used (${(t.usedJSHeapSize/1048576).toFixed(1)}MB)`,data:{usedJSHeapSize:t.usedJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit}});let i=o>=.9,s=n>=.5;if(i||s){let a={kind:"memory",message:i?`Heap usage critical: ${(o*100).toFixed(1)}% of limit`:`Heap growth spike: ${(n*100).toFixed(1)}% since init`,usedJSHeapSize:t.usedJSHeapSize,totalJSHeapSize:t.totalJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit,heapUsagePercent:o,heapGrowthPercent:n};this.eventBus.emit("memory:captured",a);}},1e4));}teardown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.baselineUsed=null;}};var U=` | ||
| 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var b="0.1.0",I={maxReports:50,maxBreadcrumbs:20,maxClicks:20,widget:false,collectors:{errors:true,console:true,network:true,clicks:true,interactions:true,performance:true,memory:true},rateLimit:{maxEvents:10,windowMs:1e3},beforeReport:r=>r,debug:false};var v=class{constructor(){this.listeners=new Map;}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t);}emit(e,t){this.listeners.get(e)?.forEach(o=>{try{o(t);}catch{}});}clear(){this.listeners.clear();}};var m=class{constructor(e){this.capacity=e;this.head=0;this._size=0;this.buffer=new Array(e);}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this._size<this.capacity&&this._size++;}toArray(){if(this._size===0)return [];let e=[],t=this._size<this.capacity?0:this.head;for(let o=0;o<this._size;o++){let n=(t+o)%this.capacity;e.push(this.buffer[n]);}return e}get size(){return this._size}get isFull(){return this._size===this.capacity}peek(){if(this._size===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}find(e){return this.toArray().find(e)}forEach(e){this.toArray().forEach(e);}clear(){this.buffer=new Array(this.capacity),this.head=0,this._size=0;}};var y=class{constructor(e,t){this.maxEvents=e;this.windowMs=t;this.timestamps=[];}allow(){let e=Date.now();return this.timestamps=this.timestamps.filter(t=>e-t<this.windowMs),this.timestamps.length>=this.maxEvents?false:(this.timestamps.push(e),true)}reset(){this.timestamps=[];}};function X(r){let e=5381;for(let t=0;t<r.length;t++)e=(e<<5)+e+r.charCodeAt(t)&4294967295;return (e>>>0).toString(36)}function A(r){let e;switch(r.kind){case "error":{let t=r.stack?.split(` | ||
| `)[1]?.trim()||"";e=`${r.name}:${r.message}:${t}`;break}case "console":e=`console:${r.level}:${r.args.join(",")}`;break;case "network":e=`network:${r.method}:${r.url}:${r.status}`;break;case "performance":e=`performance:${r.metric}:${Math.floor(r.value/100)*100}`;break;case "memory":e=`memory:${Math.floor(r.heapUsagePercent*10)/10}`;break}return X(e)}function j(){let r=new Uint8Array(8);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(36).padStart(2,"0")).join("").slice(0,12)}var w=class{constructor(e,t,o){this.eventBus=e;this.contextCollector=t;this.options=o;this.unsubscribers=[];this.reports=new m(o.maxReports),this.breadcrumbs=new m(o.maxBreadcrumbs),this.rateLimiter=new y(o.rateLimit.maxEvents,o.rateLimit.windowMs),this.subscribe();}subscribe(){this.unsubscribers.push(this.eventBus.on("error:captured",e=>{this.addBreadcrumb({category:"error",message:e.message}),this.handleCapturedEvent("error",e);}),this.eventBus.on("console:captured",e=>{this.addBreadcrumb({category:"console",message:`console.${e.level}: ${e.args.join(", ")}`}),e.level==="error"&&this.handleCapturedEvent("console",e);}),this.eventBus.on("network:captured",e=>{this.handleCapturedEvent("network",e);}),this.eventBus.on("performance:captured",e=>{this.addBreadcrumb({category:"performance",message:`${e.metric}: ${e.value}ms`}),this.handleCapturedEvent("performance",e);}),this.eventBus.on("memory:captured",e=>{this.handleCapturedEvent("memory",e);}),this.eventBus.on("breadcrumb:added",e=>{this.addBreadcrumb(e);}));}async handleCapturedEvent(e,t){if(!this.rateLimiter.allow())return;let o=A(t),n=this.reports.find(l=>l.fingerprint===o);if(n){n.count++,n.timestamp=new Date().toISOString(),this.eventBus.emit("report:deduplicated",n);return}let i={id:j(),fingerprint:o,type:e,timestamp:new Date().toISOString(),count:1,payload:t,breadcrumbs:this.breadcrumbs.toArray(),context:this.contextCollector.snapshot()},a=this.options.beforeReport(i);a&&(i=a,this.reports.push(i),this.eventBus.emit("report:created",i));}addBreadcrumb(e){this.breadcrumbs.push({...e,timestamp:new Date().toISOString()});}getReports(){return this.reports.toArray()}clear(){this.reports.clear(),this.breadcrumbs.clear(),this.unsubscribers.forEach(e=>e()),this.unsubscribers=[];}get reportCount(){return this.reports.size}};var x=class{constructor(e){this.eventBus=e;this.name="error";this.originalOnError=null;this.rejectionHandler=null;}setup(){this.originalOnError=window.onerror,window.onerror=(e,t,o,n,i)=>{let a={kind:"error",message:String(e),stack:i?.stack,filename:t??void 0,lineno:o??void 0,colno:n??void 0,name:i?.name};return this.eventBus.emit("error:captured",a),this.originalOnError?this.originalOnError.call(window,e,t,o,n,i):false},this.rejectionHandler=e=>{let t=e.reason,o={kind:"error",message:t instanceof Error?t.message:String(t),stack:t instanceof Error?t.stack:void 0,name:t instanceof Error?t.name:"UnhandledRejection"};this.eventBus.emit("error:captured",o);},window.addEventListener("unhandledrejection",this.rejectionHandler);}teardown(){window.onerror=this.originalOnError,this.originalOnError=null,this.rejectionHandler&&(window.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null);}};function f(r,e){let t=new WeakSet;return JSON.stringify(r,(o,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return "[Circular]";t.add(n);}return typeof n=="function"?"[Function]":typeof n=="symbol"?n.toString():n instanceof Error?{name:n.name,message:n.message,stack:n.stack}:n},e)}var E=class{constructor(e){this.eventBus=e;this.name="console";this.originalError=null;this.originalWarn=null;}setup(){this.originalError=console.error,this.originalWarn=console.warn,console.error=(...e)=>{let t={kind:"console",level:"error",args:e.map(o=>f(o))};this.eventBus.emit("console:captured",t),this.originalError.apply(console,e);},console.warn=(...e)=>{let t={kind:"console",level:"warn",args:e.map(o=>f(o))};this.eventBus.emit("console:captured",t),this.originalWarn.apply(console,e);};}teardown(){this.originalError&&(console.error=this.originalError),this.originalWarn&&(console.warn=this.originalWarn),this.originalError=null,this.originalWarn=null;}};var k=class{constructor(e){this.eventBus=e;this.name="network";this.originalFetch=null;this.originalXhrOpen=null;this.originalXhrSend=null;}setup(){this.patchFetch(),this.patchXHR();}patchFetch(){this.originalFetch=window.fetch;let e=this.eventBus,t=this.originalFetch;window.fetch=function(o,n){let i=n?.method?.toUpperCase()||"GET",a=typeof o=="string"?o:o instanceof URL?o.href:o.url,l=performance.now();return t.call(window,o,n).then(s=>{let p=Math.round(performance.now()-l);if(s.status>=400){let u={kind:"network",method:i,url:a,status:s.status,statusText:s.statusText,duration:p};e.emit("network:captured",u);}return e.emit("breadcrumb:added",{category:"network",message:`${i} ${a} -> ${s.status}`}),s},s=>{let p=Math.round(performance.now()-l),u={kind:"network",method:i,url:a,status:0,statusText:s.message||"Network Error",duration:p};throw e.emit("network:captured",u),s})};}patchXHR(){this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let e=this.eventBus,t=this.originalXhrOpen,o=this.originalXhrSend;XMLHttpRequest.prototype.open=function(n,i,...a){return this.__ghostbug_method=n.toUpperCase(),this.__ghostbug_url=String(i),t.apply(this,[n,i,...a])},XMLHttpRequest.prototype.send=function(n){let i=performance.now(),a=this;return a.addEventListener("loadend",function(){let l=Math.round(performance.now()-i),s=a.__ghostbug_method||"UNKNOWN",p=a.__ghostbug_url||"";if(a.status>=400||a.status===0){let u={kind:"network",method:s,url:p,status:a.status,statusText:a.statusText,duration:l};e.emit("network:captured",u);}e.emit("breadcrumb:added",{category:"network",message:`${s} ${p} -> ${a.status}`});}),o.call(this,n)};}teardown(){this.originalFetch&&(window.fetch=this.originalFetch,this.originalFetch=null),this.originalXhrOpen&&(XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=null),this.originalXhrSend&&(XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=null);}};function U(r){if(r.id)return `#${r.id}`;let e=r.getAttribute("data-testid");if(e)return `[data-testid="${e}"]`;let t=[],o=r,n=0;for(;o&&o!==document.documentElement&&n<5;){let i=o.tagName.toLowerCase();if(o.id){t.unshift(`#${o.id}`);break}let a=Array.from(o.classList).slice(0,2);a.length>0&&(i+="."+a.join("."));let l=o.parentElement;if(l){let s=o.tagName,p=Array.from(l.children).filter(u=>u.tagName===s);if(p.length>1){let u=p.indexOf(o)+1;i+=`:nth-child(${u})`;}}t.unshift(i),o=l,n++;}return t.join(" > ")}var C=class{constructor(e,t){this.eventBus=e;this.name="click";this.handler=null;this.clicks=new m(t);}setup(){this.handler=e=>{let t=e.target;if(!t)return;let o={timestamp:new Date().toISOString(),selector:U(t),tagName:t.tagName.toLowerCase(),text:(t.textContent||"").trim().slice(0,100),position:{x:e.clientX,y:e.clientY}};this.clicks.push(o),this.eventBus.emit("click:captured",o),this.eventBus.emit("breadcrumb:added",{category:"click",message:`Clicked ${o.tagName} "${o.text}"`,data:{selector:o.selector}});},document.addEventListener("click",this.handler,true);}getClickTrail(){return this.clicks.toArray()}teardown(){this.handler&&(document.removeEventListener("click",this.handler,true),this.handler=null),this.clicks.clear();}};var S=class{constructor(e){this.getMeta=e;this.name="context";}setup(){}teardown(){}snapshot(){let e=this.getMeta?.();return {url:window.location.href,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},devicePixelRatio:window.devicePixelRatio||1,timestamp:new Date().toISOString(),memory:performance.memory?{usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize}:void 0,user:e?.user,tags:e?.tags}}};var B=class{constructor(e){this.eventBus=e;this.name="interactions";this.handlers=[];this.scrollTimer=null;this.resizeTimer=null;}setup(){this.addHandler(window,"scroll",this.onScroll.bind(this),{passive:true,capture:true}),this.addHandler(document,"input",this.onInput.bind(this),true),this.addHandler(document,"change",this.onChange.bind(this),true),this.addHandler(window,"popstate",this.onPopState.bind(this)),this.addHandler(window,"hashchange",this.onHashChange.bind(this)),this.addHandler(document,"visibilitychange",this.onVisibilityChange.bind(this)),this.addHandler(window,"resize",this.onResize.bind(this),{passive:true});}addHandler(e,t,o,n){e.addEventListener(t,o,n),this.handlers.push({target:e,event:t,handler:o});}onScroll(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Scrolled",data:{x:window.scrollX,y:window.scrollY}});},300);}onInput(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"",i=t.type?`[type="${t.type}"]`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Input on ${o}${n}${i}`});}onChange(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Change on ${o}${n}`});}onPopState(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Navigated to ${window.location.href}`});}onHashChange(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Hash changed to ${window.location.hash}`});}onVisibilityChange(){this.eventBus.emit("breadcrumb:added",{category:"visibility",message:document.hidden?"Tab hidden":"Tab visible"});}onResize(){this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Window resized",data:{width:window.innerWidth,height:window.innerHeight}});},300);}teardown(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.resizeTimer&&clearTimeout(this.resizeTimer),this.handlers.forEach(({target:e,event:t,handler:o})=>{e.removeEventListener(t,o);}),this.handlers=[];}};var R=class{constructor(e){this.eventBus=e;this.name="performance";this.observers=[];}setup(){typeof PerformanceObserver>"u"||(this.observe("longtask",e=>{e.forEach(t=>{if(t.duration<50)return;let o={kind:"performance",metric:"longtask",value:Math.round(t.duration),entries:[{name:t.name,duration:t.duration,startTime:t.startTime}]};this.eventBus.emit("performance:captured",o),this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Long task: ${Math.round(t.duration)}ms`});});}),this.observe("largest-contentful-paint",e=>{let t=e[e.length-1];t&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`LCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});}),this.observe("paint",e=>{e.forEach(t=>{t.name==="first-contentful-paint"&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`FCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});});}),this.observe("layout-shift",e=>{e.forEach(t=>{let o=t.value;o>.1&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Layout shift: ${o.toFixed(4)}`,data:{cls:o}});});}));}observe(e,t){try{let o=new PerformanceObserver(n=>{t(n.getEntries());});o.observe({type:e,buffered:!0}),this.observers.push(o);}catch{}}teardown(){this.observers.forEach(e=>e.disconnect()),this.observers=[];}};function F(){let r=performance.memory;return !r||typeof r.usedJSHeapSize!="number"?null:r}var T=class{constructor(e){this.eventBus=e;this.name="memory";this.intervalId=null;this.baselineUsed=null;}setup(){let e=F();e&&(this.baselineUsed=e.usedJSHeapSize,this.intervalId=setInterval(()=>{let t=F();if(!t)return;let o=t.usedJSHeapSize/t.jsHeapSizeLimit,n=this.baselineUsed>0?(t.usedJSHeapSize-this.baselineUsed)/this.baselineUsed:0;this.eventBus.emit("breadcrumb:added",{category:"memory",message:`Heap: ${(o*100).toFixed(1)}% used (${(t.usedJSHeapSize/1048576).toFixed(1)}MB)`,data:{usedJSHeapSize:t.usedJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit}});let i=o>=.9,a=n>=.5;if(i||a){let s={kind:"memory",message:i?`Heap usage critical: ${(o*100).toFixed(1)}% of limit`:`Heap growth spike: ${(n*100).toFixed(1)}% since init`,usedJSHeapSize:t.usedJSHeapSize,totalJSHeapSize:t.totalJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit,heapUsagePercent:o,heapGrowthPercent:n};this.eventBus.emit("memory:captured",s);}},1e4));}teardown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.baselineUsed=null;}};var D=` | ||
| :host { | ||
@@ -165,16 +165,63 @@ all: initial; | ||
| .gb-report-item { | ||
| padding: 10px 16px; | ||
| border-bottom: 1px solid #f0f0f0; | ||
| cursor: pointer; | ||
| transition: background 0.15s; | ||
| } | ||
| .gb-report-item:hover { | ||
| .gb-report-item:last-child { | ||
| border-bottom: none; | ||
| } | ||
| .gb-report-summary { | ||
| padding: 10px 16px; | ||
| cursor: pointer; | ||
| } | ||
| .gb-report-summary:hover { | ||
| background: #f8f9fa; | ||
| } | ||
| .gb-report-item:last-child { | ||
| border-bottom: none; | ||
| .gb-report-detail { | ||
| display: none; | ||
| padding: 0 16px 12px; | ||
| border-top: 1px dashed #e8e8e8; | ||
| } | ||
| .gb-report-item.gb-expanded .gb-report-detail { | ||
| display: block; | ||
| } | ||
| .gb-detail-section { | ||
| margin-top: 8px; | ||
| } | ||
| .gb-detail-label { | ||
| font-size: 10px; | ||
| font-weight: 700; | ||
| text-transform: uppercase; | ||
| letter-spacing: 0.5px; | ||
| color: #999; | ||
| margin-bottom: 2px; | ||
| } | ||
| .gb-detail-value { | ||
| font-size: 12px; | ||
| color: #555; | ||
| word-break: break-word; | ||
| line-height: 1.4; | ||
| } | ||
| .gb-detail-pre { | ||
| font-size: 11px; | ||
| font-family: 'SF Mono', Menlo, Monaco, monospace; | ||
| background: #f5f5f5; | ||
| padding: 8px; | ||
| border-radius: 6px; | ||
| overflow-x: auto; | ||
| max-height: 120px; | ||
| overflow-y: auto; | ||
| color: #333; | ||
| white-space: pre-wrap; | ||
| word-break: break-word; | ||
| } | ||
| .gb-report-type { | ||
@@ -257,4 +304,5 @@ display: inline-block; | ||
| } | ||
| `;var J='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></svg>';function D(){let r=document.createElement("button");r.className="gb-fab",r.setAttribute("aria-label","ghostbug - bug reports");let e=document.createElement("span");e.innerHTML=J,r.appendChild(e);let t=document.createElement("span");return t.className="gb-badge",t.setAttribute("data-count","0"),t.textContent="0",r.appendChild(t),r}function G(r){let e=document.createElement("div");e.className=`gb-panel gb-pos-${r}`;let t=document.createElement("div");t.className="gb-header";let o=document.createElement("span");o.className="gb-header-title",o.textContent="ghostbug",t.appendChild(o);let n=document.createElement("button");n.className="gb-header-btn gb-copy-btn",n.textContent="Copy MD",t.appendChild(n);let i=document.createElement("button");i.className="gb-header-btn gb-download-btn",i.textContent="Export",t.appendChild(i);let s=document.createElement("button");s.className="gb-close-btn",s.textContent="\xD7",s.setAttribute("aria-label","Close"),t.appendChild(s),e.appendChild(t);let l=document.createElement("div");l.className="gb-report-list";let a=document.createElement("div");return a.className="gb-empty",a.textContent="No bugs captured yet.",l.appendChild(a),e.appendChild(l),e}function X(r){let e=document.createElement("div");e.className="gb-report-item";let t=document.createElement("span");if(t.className=`gb-report-type gb-type-${r.payload.kind==="error"?"error":r.payload.kind}`,t.textContent=r.type,e.appendChild(t),r.count>1){let s=document.createElement("span");s.className="gb-report-count",s.textContent=`\xD7${r.count}`,e.appendChild(s);}let o=document.createElement("div");o.className="gb-report-message",o.textContent=V(r),e.appendChild(o);let n=document.createElement("div");n.className="gb-report-meta";let i=r.timestamp.split("T")[1]?.split(".")[0]||r.timestamp;return n.textContent=`${i} \xB7 ${r.context.url}`,e.appendChild(n),e}function V(r){switch(r.payload.kind){case "error":return r.payload.message;case "console":return r.payload.args.join(", ");case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `${r.payload.metric}: ${r.payload.value}ms`;case "memory":return r.payload.message}}function T(r){return g({generator:"ghostbug",version:f,exportedAt:new Date().toISOString(),reportCount:r.length,reports:r},2)}function L(r){let e=[];return e.push(`# Bug Report \u2014 ghostbug v${f}`),e.push(`**Generated:** ${new Date().toISOString()}`),e.push(`**Reports:** ${r.length}`),e.push(""),e.push("---"),e.push(""),r.forEach((t,o)=>{e.push(`## ${o+1}. ${Y(t)}`),e.push(""),e.push(`- **Type:** ${t.type}`),e.push(`- **Time:** ${t.timestamp}`),e.push(`- **Occurrences:** ${t.count}`),e.push(`- **URL:** ${t.context.url}`),e.push(`- **Browser:** ${Q(t.context.userAgent)}`),e.push(`- **Viewport:** ${t.context.viewport.width}x${t.context.viewport.height}`),e.push(""),e.push(...K(t.payload)),e.push(""),t.breadcrumbs.length>0&&(e.push("### Breadcrumbs"),e.push(""),e.push("| Time | Category | Event |"),e.push("|------|----------|-------|"),t.breadcrumbs.forEach(n=>{let i=n.timestamp.split("T")[1]?.split(".")[0]||n.timestamp;e.push(`| ${i} | ${n.category} | ${n.message} |`);}),e.push("")),e.push("---"),e.push("");}),e.join(` | ||
| `)}function Y(r){switch(r.payload.kind){case "error":return `${r.payload.name||"Error"}: ${r.payload.message}`;case "console":return `Console ${r.payload.level}: ${r.payload.args[0]||""}`;case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `Performance: ${r.payload.metric} ${r.payload.value}ms`;case "memory":return `Memory: ${r.payload.message}`}}function K(r){let e=[];switch(r.kind){case "error":r.stack&&(e.push("### Stack Trace"),e.push(""),e.push("```"),e.push(r.stack),e.push("```")),r.filename&&e.push(`**File:** ${r.filename}:${r.lineno}:${r.colno}`);break;case "console":e.push("### Console Output"),e.push(""),e.push("```"),r.args.forEach(t=>e.push(t)),e.push("```");break;case "network":e.push("### Network Details"),e.push(""),e.push(`- **Method:** ${r.method}`),e.push(`- **URL:** ${r.url}`),e.push(`- **Status:** ${r.status} ${r.statusText}`),e.push(`- **Duration:** ${r.duration}ms`);break;case "performance":e.push("### Performance Details"),e.push(""),e.push(`- **Metric:** ${r.metric}`),e.push(`- **Value:** ${r.value}ms`),r.entries.length>0&&e.push(`- **Start Time:** ${Math.round(r.entries[0].startTime)}ms`);break;case "memory":e.push("### Memory Details"),e.push(""),e.push(`- **Used:** ${(r.usedJSHeapSize/1048576).toFixed(1)}MB`),e.push(`- **Limit:** ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB`),e.push(`- **Usage:** ${(r.heapUsagePercent*100).toFixed(1)}%`),e.push(`- **Growth since init:** ${(r.heapGrowthPercent*100).toFixed(1)}%`);break}return e}function Q(r){if(r.includes("Chrome")){let e=r.match(/Chrome\/(\d+)/);return e?`Chrome ${e[1]}`:"Chrome"}if(r.includes("Firefox")){let e=r.match(/Firefox\/(\d+)/);return e?`Firefox ${e[1]}`:"Firefox"}if(r.includes("Safari")&&!r.includes("Chrome")){let e=r.match(/Version\/(\d+)/);return e?`Safari ${e[1]}`:"Safari"}return r.slice(0,50)}var P=class{constructor(e,t,o){this.eventBus=e;this.reportManager=t;this.options=o;this.hostElement=null;this.shadowRoot=null;this.panel=null;this.badge=null;this.reportList=null;this.isExpanded=false;this.unsubscribers=[];}mount(){this.hostElement=document.createElement("div"),this.hostElement.id="ghostbug-widget";let e=this.hostElement.style;e.position="fixed",e.zIndex=String(this.options.zIndex),e.margin="0",e.padding="0",this.applyPosition(e),this.shadowRoot=this.hostElement.attachShadow({mode:"closed"});let t=document.createElement("style");t.textContent=U,this.shadowRoot.appendChild(t);let o=document.createElement("div");o.className="gb-container";let n=D();this.badge=n.querySelector(".gb-badge"),n.addEventListener("click",()=>this.toggle()),o.appendChild(n),this.panel=G(this.options.position),o.appendChild(this.panel),this.panel.querySelector(".gb-close-btn")?.addEventListener("click",()=>this.toggle()),this.panel.querySelector(".gb-copy-btn")?.addEventListener("click",()=>this.copyMarkdown()),this.panel.querySelector(".gb-download-btn")?.addEventListener("click",()=>this.downloadJSON()),this.reportList=this.panel.querySelector(".gb-report-list"),this.shadowRoot.appendChild(o),document.body.appendChild(this.hostElement),this.unsubscribers.push(this.eventBus.on("report:created",()=>this.update()),this.eventBus.on("report:deduplicated",()=>this.update())),this.options.collapsed||this.toggle();}applyPosition(e){let t=this.options.position;e.top=t.startsWith("top")?"16px":"auto",e.bottom=t.startsWith("bottom")?"16px":"auto",e.left=t.endsWith("left")?"16px":"auto",e.right=t.endsWith("right")?"16px":"auto";}toggle(){this.isExpanded=!this.isExpanded,this.isExpanded?(this.panel?.classList.add("gb-open"),this.renderReportList()):this.panel?.classList.remove("gb-open");}update(){this.updateBadge(),this.isExpanded&&this.renderReportList();}updateBadge(){if(!this.badge)return;let e=this.reportManager.reportCount;this.badge.textContent=String(e),this.badge.setAttribute("data-count",String(e));}renderReportList(){if(!this.reportList)return;this.reportList.textContent="";let e=this.reportManager.getReports();if(e.length===0){let o=document.createElement("div");o.className="gb-empty",o.textContent="No bugs captured yet.",this.reportList.appendChild(o);return}[...e].reverse().forEach(o=>{let n=X(o);this.reportList.appendChild(n);});}copyMarkdown(){let e=L(this.reportManager.getReports());navigator.clipboard.writeText(e).then(()=>this.showToast("Copied to clipboard!"),()=>this.showToast("Copy failed"));}downloadJSON(){let e=T(this.reportManager.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download="ghostbug-report.json",n.click(),URL.revokeObjectURL(o);}showToast(e){if(!this.shadowRoot)return;let t=document.createElement("div");t.className="gb-toast",t.textContent=e,this.shadowRoot.appendChild(t),requestAnimationFrame(()=>{t.classList.add("gb-show");}),setTimeout(()=>{t.classList.remove("gb-show"),setTimeout(()=>t.remove(),300);},2e3);}unmount(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.hostElement?.remove(),this.hostElement=null,this.shadowRoot=null,this.panel=null,this.badge=null,this.reportList=null;}};var c=null,h=null,d=[],H=null,$=new Set,M=false,z,O;function Z(r,e){return e?{maxReports:e.maxReports??r.maxReports,maxBreadcrumbs:e.maxBreadcrumbs??r.maxBreadcrumbs,maxClicks:e.maxClicks??r.maxClicks,widget:e.widget??r.widget,collectors:{...r.collectors,...e.collectors},rateLimit:{...r.rateLimit,...e.rateLimit},beforeReport:e.beforeReport??r.beforeReport,debug:e.debug??r.debug,screenshotFn:e.screenshotFn}:{...r}}function ee(r){if(M){r?.debug&&console.warn("[ghostbug] Already initialized. Call destroy() first.");return}let e=Z(_,r);c=new b;let t=new C(()=>({user:z,tags:O}));if(h=new y(c,t,e),e.collectors.errors&&d.push(new w(c)),e.collectors.console&&d.push(new x(c)),e.collectors.network&&d.push(new E(c)),e.collectors.clicks&&d.push(new k(c,e.maxClicks)),e.collectors.interactions&&d.push(new S(c)),e.collectors.performance&&d.push(new B(c)),e.collectors.memory&&d.push(new R(c)),d.push(t),d.forEach(o=>o.setup()),c.on("report:created",o=>{$.forEach(n=>{try{n(o);}catch{}});}),e.widget){let o=typeof e.widget=="object"?{position:e.widget.position||"bottom-right",collapsed:e.widget.collapsed??true,zIndex:e.widget.zIndex??2147483647}:{position:"bottom-right",collapsed:true,zIndex:2147483647};H=new P(c,h,o),H.mount();}M=true;}function te(){return N(),h.getReports()}function re(r="ghostbug-report.json"){N();let e=T(h.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download=r,n.click(),URL.revokeObjectURL(o);}function oe(){return N(),L(h.getReports())}function ne(r){return $.add(r),()=>$.delete(r)}function ie(r){z=r;}function se(r){O={...O,...r};}function ae(){H?.unmount(),H=null,d.forEach(r=>r.teardown()),d=[],c?.clear(),c=null,h?.clear(),h=null,$.clear(),z=void 0,O=void 0,M=false;}function N(){if(!M)throw new Error("[ghostbug] Not initialized. Call ghostbug.init() first.")}var nt={init:ee,getReports:te,download:re,toMarkdown:oe,onBug:ne,setUser:ie,setTags:se,destroy:ae};exports.default=nt;exports.destroy=ae;exports.download=re;exports.getReports=te;exports.init=ee;exports.onBug=ne;exports.setTags=se;exports.setUser=ie;exports.toMarkdown=oe;//# sourceMappingURL=index.cjs.map | ||
| `;var W='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></svg>';function J(){let r=document.createElement("button");r.className="gb-fab",r.setAttribute("aria-label","ghostbug - bug reports");let e=document.createElement("span");e.innerHTML=W,r.appendChild(e);let t=document.createElement("span");return t.className="gb-badge",t.setAttribute("data-count","0"),t.textContent="0",r.appendChild(t),r}function G(r){let e=document.createElement("div");e.className=`gb-panel gb-pos-${r}`;let t=document.createElement("div");t.className="gb-header";let o=document.createElement("span");o.className="gb-header-title",o.textContent="ghostbug",t.appendChild(o);let n=document.createElement("button");n.className="gb-header-btn gb-copy-btn",n.textContent="Copy MD",t.appendChild(n);let i=document.createElement("button");i.className="gb-header-btn gb-download-btn",i.textContent="Export",t.appendChild(i);let a=document.createElement("button");a.className="gb-close-btn",a.textContent="\xD7",a.setAttribute("aria-label","Close"),t.appendChild(a),e.appendChild(t);let l=document.createElement("div");l.className="gb-report-list";let s=document.createElement("div");return s.className="gb-empty",s.textContent="No bugs captured yet.",l.appendChild(s),e.appendChild(l),e}function q(r){let e=document.createElement("div");e.className="gb-report-item";let t=document.createElement("div");t.className="gb-report-summary";let o=document.createElement("span");if(o.className=`gb-report-type gb-type-${r.payload.kind==="error"?"error":r.payload.kind}`,o.textContent=r.type,t.appendChild(o),r.count>1){let s=document.createElement("span");s.className="gb-report-count",s.textContent=`\xD7${r.count}`,t.appendChild(s);}let n=document.createElement("div");n.className="gb-report-message",n.textContent=Y(r),t.appendChild(n);let i=document.createElement("div");i.className="gb-report-meta";let a=r.timestamp.split("T")[1]?.split(".")[0]||r.timestamp;i.textContent=`${a} \xB7 ${r.context.url}`,t.appendChild(i),e.appendChild(t);let l=document.createElement("div");if(l.className="gb-report-detail",l.appendChild(V(r.payload)),r.context.user){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">User</div><div class="gb-detail-value">${g(JSON.stringify(r.context.user))}</div>`,l.appendChild(s);}if(r.context.tags){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">Tags</div><div class="gb-detail-value">${g(JSON.stringify(r.context.tags))}</div>`,l.appendChild(s);}if(r.breadcrumbs.length>0){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">Breadcrumbs</div><div class="gb-detail-value">${r.breadcrumbs.length} events</div>`,l.appendChild(s);}return e.appendChild(l),t.addEventListener("click",()=>{e.classList.toggle("gb-expanded");}),e}function g(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function V(r){let e=document.createElement("div");switch(e.className="gb-detail-section",r.kind){case "error":{if(r.stack){let t=document.createElement("div");t.className="gb-detail-label",t.textContent="Stack Trace",e.appendChild(t);let o=document.createElement("pre");o.className="gb-detail-pre",o.textContent=r.stack,e.appendChild(o);}if(r.filename){let t=document.createElement("div");t.className="gb-detail-value",t.textContent=`${r.filename}:${r.lineno}:${r.colno}`,e.appendChild(t);}break}case "console":{let t=document.createElement("div");t.className="gb-detail-label",t.textContent="Output",e.appendChild(t);let o=document.createElement("pre");o.className="gb-detail-pre",o.textContent=r.args.join(` | ||
| `),e.appendChild(o);break}case "network":{e.innerHTML=`<div class="gb-detail-label">Request</div><div class="gb-detail-value">${g(r.method)} ${g(r.url)}<br>Status: ${r.status} ${g(r.statusText)}<br>Duration: ${r.duration}ms</div>`;break}case "performance":{e.innerHTML=`<div class="gb-detail-label">Performance</div><div class="gb-detail-value">Metric: ${g(r.metric)}<br>Value: ${r.value}ms</div>`;break}case "memory":{e.innerHTML=`<div class="gb-detail-label">Memory</div><div class="gb-detail-value">Used: ${(r.usedJSHeapSize/1048576).toFixed(1)}MB<br>Limit: ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB<br>Usage: ${(r.heapUsagePercent*100).toFixed(1)}%</div>`;break}}return e}function Y(r){switch(r.payload.kind){case "error":return r.payload.message;case "console":return r.payload.args.join(", ");case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `${r.payload.metric}: ${r.payload.value}ms`;case "memory":return r.payload.message}}function L(r){return f({generator:"ghostbug",version:b,exportedAt:new Date().toISOString(),reportCount:r.length,reports:r},2)}function P(r){let e=[];return e.push(`# Bug Report \u2014 ghostbug v${b}`),e.push(`**Generated:** ${new Date().toISOString()}`),e.push(`**Reports:** ${r.length}`),e.push(""),e.push("---"),e.push(""),r.forEach((t,o)=>{e.push(`## ${o+1}. ${K(t)}`),e.push(""),e.push(`- **Type:** ${t.type}`),e.push(`- **Time:** ${t.timestamp}`),e.push(`- **Occurrences:** ${t.count}`),e.push(`- **URL:** ${t.context.url}`),e.push(`- **Browser:** ${Z(t.context.userAgent)}`),e.push(`- **Viewport:** ${t.context.viewport.width}x${t.context.viewport.height}`),e.push(""),e.push(...Q(t.payload)),e.push(""),t.context.user&&(e.push("### User Context"),e.push(""),e.push("```json"),e.push(JSON.stringify(t.context.user,null,2)),e.push("```"),e.push("")),t.context.tags&&(e.push("### Tags"),e.push(""),e.push("```json"),e.push(JSON.stringify(t.context.tags,null,2)),e.push("```"),e.push("")),t.breadcrumbs.length>0&&(e.push("### Breadcrumbs"),e.push(""),e.push("| Time | Category | Event |"),e.push("|------|----------|-------|"),t.breadcrumbs.forEach(n=>{let i=n.timestamp.split("T")[1]?.split(".")[0]||n.timestamp;e.push(`| ${i} | ${n.category} | ${n.message} |`);}),e.push("")),e.push("---"),e.push("");}),e.join(` | ||
| `)}function K(r){switch(r.payload.kind){case "error":return `${r.payload.name||"Error"}: ${r.payload.message}`;case "console":return `Console ${r.payload.level}: ${r.payload.args[0]||""}`;case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `Performance: ${r.payload.metric} ${r.payload.value}ms`;case "memory":return `Memory: ${r.payload.message}`}}function Q(r){let e=[];switch(r.kind){case "error":r.stack&&(e.push("### Stack Trace"),e.push(""),e.push("```"),e.push(r.stack),e.push("```")),r.filename&&e.push(`**File:** ${r.filename}:${r.lineno}:${r.colno}`);break;case "console":e.push("### Console Output"),e.push(""),e.push("```"),r.args.forEach(t=>e.push(t)),e.push("```");break;case "network":e.push("### Network Details"),e.push(""),e.push(`- **Method:** ${r.method}`),e.push(`- **URL:** ${r.url}`),e.push(`- **Status:** ${r.status} ${r.statusText}`),e.push(`- **Duration:** ${r.duration}ms`);break;case "performance":e.push("### Performance Details"),e.push(""),e.push(`- **Metric:** ${r.metric}`),e.push(`- **Value:** ${r.value}ms`),r.entries.length>0&&e.push(`- **Start Time:** ${Math.round(r.entries[0].startTime)}ms`);break;case "memory":e.push("### Memory Details"),e.push(""),e.push(`- **Used:** ${(r.usedJSHeapSize/1048576).toFixed(1)}MB`),e.push(`- **Limit:** ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB`),e.push(`- **Usage:** ${(r.heapUsagePercent*100).toFixed(1)}%`),e.push(`- **Growth since init:** ${(r.heapGrowthPercent*100).toFixed(1)}%`);break}return e}function Z(r){if(r.includes("Chrome")){let e=r.match(/Chrome\/(\d+)/);return e?`Chrome ${e[1]}`:"Chrome"}if(r.includes("Firefox")){let e=r.match(/Firefox\/(\d+)/);return e?`Firefox ${e[1]}`:"Firefox"}if(r.includes("Safari")&&!r.includes("Chrome")){let e=r.match(/Version\/(\d+)/);return e?`Safari ${e[1]}`:"Safari"}return r.slice(0,50)}var $=class{constructor(e,t,o){this.eventBus=e;this.reportManager=t;this.options=o;this.hostElement=null;this.shadowRoot=null;this.panel=null;this.badge=null;this.reportList=null;this.isExpanded=false;this.unsubscribers=[];}mount(){this.hostElement=document.createElement("div"),this.hostElement.id="ghostbug-widget";let e=this.hostElement.style;e.position="fixed",e.zIndex=String(this.options.zIndex),e.margin="0",e.padding="0",this.applyPosition(e),this.shadowRoot=this.hostElement.attachShadow({mode:"closed"});let t=document.createElement("style");t.textContent=D,this.shadowRoot.appendChild(t);let o=document.createElement("div");o.className="gb-container";let n=J();this.badge=n.querySelector(".gb-badge"),n.addEventListener("click",()=>this.toggle()),o.appendChild(n),this.panel=G(this.options.position),o.appendChild(this.panel),this.panel.querySelector(".gb-close-btn")?.addEventListener("click",()=>this.toggle()),this.panel.querySelector(".gb-copy-btn")?.addEventListener("click",()=>this.copyMarkdown()),this.panel.querySelector(".gb-download-btn")?.addEventListener("click",()=>this.downloadJSON()),this.reportList=this.panel.querySelector(".gb-report-list"),this.shadowRoot.appendChild(o),document.body.appendChild(this.hostElement),this.unsubscribers.push(this.eventBus.on("report:created",()=>this.update()),this.eventBus.on("report:deduplicated",()=>this.update())),this.options.collapsed||this.toggle();}applyPosition(e){let t=this.options.position;e.top=t.startsWith("top")?"16px":"auto",e.bottom=t.startsWith("bottom")?"16px":"auto",e.left=t.endsWith("left")?"16px":"auto",e.right=t.endsWith("right")?"16px":"auto";}toggle(){this.isExpanded=!this.isExpanded,this.isExpanded?(this.panel?.classList.add("gb-open"),this.renderReportList()):this.panel?.classList.remove("gb-open");}update(){this.updateBadge(),this.isExpanded&&this.renderReportList();}updateBadge(){if(!this.badge)return;let e=this.reportManager.reportCount;this.badge.textContent=String(e),this.badge.setAttribute("data-count",String(e));}renderReportList(){if(!this.reportList)return;this.reportList.textContent="";let e=this.reportManager.getReports();if(e.length===0){let o=document.createElement("div");o.className="gb-empty",o.textContent="No bugs captured yet.",this.reportList.appendChild(o);return}[...e].reverse().forEach(o=>{let n=q(o);this.reportList.appendChild(n);});}copyMarkdown(){let e=P(this.reportManager.getReports());navigator.clipboard.writeText(e).then(()=>this.showToast("Copied to clipboard!"),()=>this.showToast("Copy failed"));}downloadJSON(){let e=L(this.reportManager.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download="ghostbug-report.json",n.click(),URL.revokeObjectURL(o);}showToast(e){if(!this.shadowRoot)return;let t=document.createElement("div");t.className="gb-toast",t.textContent=e,this.shadowRoot.appendChild(t),requestAnimationFrame(()=>{t.classList.add("gb-show");}),setTimeout(()=>{t.classList.remove("gb-show"),setTimeout(()=>t.remove(),300);},2e3);}unmount(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.hostElement?.remove(),this.hostElement=null,this.shadowRoot=null,this.panel=null,this.badge=null,this.reportList=null;}};var d=null,h=null,c=[],H=null,M=new Set,O=false,z,N;function ee(r,e){return e?{maxReports:e.maxReports??r.maxReports,maxBreadcrumbs:e.maxBreadcrumbs??r.maxBreadcrumbs,maxClicks:e.maxClicks??r.maxClicks,widget:e.widget??r.widget,collectors:{...r.collectors,...e.collectors},rateLimit:{...r.rateLimit,...e.rateLimit},beforeReport:e.beforeReport??r.beforeReport,debug:e.debug??r.debug}:{...r}}function te(r){if(O){r?.debug&&console.warn("[ghostbug] Already initialized. Call destroy() first.");return}let e=ee(I,r);d=new v;let t=new S(()=>({user:z,tags:N}));if(h=new w(d,t,e),e.collectors.errors&&c.push(new x(d)),e.collectors.console&&c.push(new E(d)),e.collectors.network&&c.push(new k(d)),e.collectors.clicks&&c.push(new C(d,e.maxClicks)),e.collectors.interactions&&c.push(new B(d)),e.collectors.performance&&c.push(new R(d)),e.collectors.memory&&c.push(new T(d)),c.push(t),c.forEach(o=>o.setup()),d.on("report:created",o=>{M.forEach(n=>{try{n(o);}catch{}});}),e.widget){let o=typeof e.widget=="object"?{position:e.widget.position||"bottom-right",collapsed:e.widget.collapsed??true,zIndex:e.widget.zIndex??2147483647}:{position:"bottom-right",collapsed:true,zIndex:2147483647};H=new $(d,h,o),H.mount();}O=true;}function re(){return _(),h.getReports()}function oe(r="ghostbug-report.json"){_();let e=L(h.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download=r,n.click(),URL.revokeObjectURL(o);}function ne(){return _(),P(h.getReports())}function ie(r){return M.add(r),()=>M.delete(r)}function se(r){z=r;}function ae(r){N={...N,...r};}function le(){H?.unmount(),H=null,c.forEach(r=>r.teardown()),c=[],d?.clear(),d=null,h?.clear(),h=null,M.clear(),z=void 0,N=void 0,O=false;}function _(){if(!O)throw new Error("[ghostbug] Not initialized. Call ghostbug.init() first.")}var it={init:te,getReports:re,download:oe,toMarkdown:ne,onBug:ie,setUser:se,setTags:ae,destroy:le};exports.default=it;exports.destroy=le;exports.download=oe;exports.getReports=re;exports.init=te;exports.onBug=ie;exports.setTags=ae;exports.setUser=se;exports.toMarkdown=ne;//# sourceMappingURL=index.cjs.map | ||
| //# sourceMappingURL=index.cjs.map |
+0
-3
@@ -18,4 +18,2 @@ interface GhostbugOptions { | ||
| debug?: boolean; | ||
| /** Async function that returns a screenshot data URL. Called on each new bug report. */ | ||
| screenshotFn?: () => Promise<string>; | ||
| } | ||
@@ -53,3 +51,2 @@ interface CollectorToggle { | ||
| context: PageContext; | ||
| screenshot?: string; | ||
| } | ||
@@ -56,0 +53,0 @@ interface ErrorPayload { |
+0
-3
@@ -18,4 +18,2 @@ interface GhostbugOptions { | ||
| debug?: boolean; | ||
| /** Async function that returns a screenshot data URL. Called on each new bug report. */ | ||
| screenshotFn?: () => Promise<string>; | ||
| } | ||
@@ -53,3 +51,2 @@ interface CollectorToggle { | ||
| context: PageContext; | ||
| screenshot?: string; | ||
| } | ||
@@ -56,0 +53,0 @@ interface ErrorPayload { |
+57
-9
@@ -1,3 +0,3 @@ | ||
| "use strict";var ghostbug=(()=>{var z=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var oe=Object.prototype.hasOwnProperty;var ne=(r,e)=>{for(var t in e)z(r,t,{get:e[t],enumerable:!0})},ie=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of re(e))!oe.call(r,n)&&n!==t&&z(r,n,{get:()=>e[n],enumerable:!(o=te(e,n))||o.enumerable});return r};var se=r=>ie(z({},"__esModule",{value:!0}),r);var fe={};ne(fe,{default:()=>ge,destroy:()=>ee,download:()=>V,getReports:()=>J,init:()=>W,onBug:()=>K,setTags:()=>Z,setUser:()=>Q,toMarkdown:()=>Y});var f="0.1.0",I={maxReports:50,maxBreadcrumbs:20,maxClicks:20,widget:!1,collectors:{errors:!0,console:!0,network:!0,clicks:!0,interactions:!0,performance:!0,memory:!0},rateLimit:{maxEvents:10,windowMs:1e3},beforeReport:r=>r,debug:!1};var b=class{constructor(){this.listeners=new Map}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){this.listeners.get(e)?.forEach(o=>{try{o(t)}catch{}})}clear(){this.listeners.clear()}};var m=class{constructor(e){this.capacity=e;this.head=0;this._size=0;this.buffer=new Array(e)}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this._size<this.capacity&&this._size++}toArray(){if(this._size===0)return[];let e=[],t=this._size<this.capacity?0:this.head;for(let o=0;o<this._size;o++){let n=(t+o)%this.capacity;e.push(this.buffer[n])}return e}get size(){return this._size}get isFull(){return this._size===this.capacity}peek(){if(this._size===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}find(e){return this.toArray().find(e)}forEach(e){this.toArray().forEach(e)}clear(){this.buffer=new Array(this.capacity),this.head=0,this._size=0}};var v=class{constructor(e,t){this.maxEvents=e;this.windowMs=t;this.timestamps=[]}allow(){let e=Date.now();return this.timestamps=this.timestamps.filter(t=>e-t<this.windowMs),this.timestamps.length>=this.maxEvents?!1:(this.timestamps.push(e),!0)}reset(){this.timestamps=[]}};function ae(r){let e=5381;for(let t=0;t<r.length;t++)e=(e<<5)+e+r.charCodeAt(t)&4294967295;return(e>>>0).toString(36)}function A(r){let e;switch(r.kind){case"error":{let t=r.stack?.split(` | ||
| `)[1]?.trim()||"";e=`${r.name}:${r.message}:${t}`;break}case"console":e=`console:${r.level}:${r.args.join(",")}`;break;case"network":e=`network:${r.method}:${r.url}:${r.status}`;break;case"performance":e=`performance:${r.metric}:${Math.floor(r.value/100)*100}`;break;case"memory":e=`memory:${Math.floor(r.heapUsagePercent*10)/10}`;break}return ae(e)}function F(){let r=new Uint8Array(8);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(36).padStart(2,"0")).join("").slice(0,12)}var le=3e3,y=class{constructor(e,t,o){this.eventBus=e;this.contextCollector=t;this.options=o;this.unsubscribers=[];this.reports=new m(o.maxReports),this.breadcrumbs=new m(o.maxBreadcrumbs),this.rateLimiter=new v(o.rateLimit.maxEvents,o.rateLimit.windowMs),this.subscribe()}subscribe(){this.unsubscribers.push(this.eventBus.on("error:captured",e=>{this.addBreadcrumb({category:"error",message:e.message}),this.handleCapturedEvent("error",e)}),this.eventBus.on("console:captured",e=>{this.addBreadcrumb({category:"console",message:`console.${e.level}: ${e.args.join(", ")}`}),e.level==="error"&&this.handleCapturedEvent("console",e)}),this.eventBus.on("network:captured",e=>{this.handleCapturedEvent("network",e)}),this.eventBus.on("performance:captured",e=>{this.addBreadcrumb({category:"performance",message:`${e.metric}: ${e.value}ms`}),this.handleCapturedEvent("performance",e)}),this.eventBus.on("memory:captured",e=>{this.handleCapturedEvent("memory",e)}),this.eventBus.on("breadcrumb:added",e=>{this.addBreadcrumb(e)}))}async handleCapturedEvent(e,t){if(!this.rateLimiter.allow())return;let o=A(t),n=this.reports.find(l=>l.fingerprint===o);if(n){n.count++,n.timestamp=new Date().toISOString(),this.eventBus.emit("report:deduplicated",n);return}let i={id:F(),fingerprint:o,type:e,timestamp:new Date().toISOString(),count:1,payload:t,breadcrumbs:this.breadcrumbs.toArray(),context:this.contextCollector.snapshot()};if(this.options.screenshotFn)try{i.screenshot=await Promise.race([this.options.screenshotFn(),new Promise((l,a)=>setTimeout(()=>a(new Error("screenshot timeout")),le))])}catch{}let s=this.options.beforeReport(i);s&&(i=s,this.reports.push(i),this.eventBus.emit("report:created",i))}addBreadcrumb(e){this.breadcrumbs.push({...e,timestamp:new Date().toISOString()})}getReports(){return this.reports.toArray()}clear(){this.reports.clear(),this.breadcrumbs.clear(),this.unsubscribers.forEach(e=>e()),this.unsubscribers=[]}get reportCount(){return this.reports.size}};var w=class{constructor(e){this.eventBus=e;this.name="error";this.originalOnError=null;this.rejectionHandler=null}setup(){this.originalOnError=window.onerror,window.onerror=(e,t,o,n,i)=>{let s={kind:"error",message:String(e),stack:i?.stack,filename:t??void 0,lineno:o??void 0,colno:n??void 0,name:i?.name};return this.eventBus.emit("error:captured",s),this.originalOnError?this.originalOnError.call(window,e,t,o,n,i):!1},this.rejectionHandler=e=>{let t=e.reason,o={kind:"error",message:t instanceof Error?t.message:String(t),stack:t instanceof Error?t.stack:void 0,name:t instanceof Error?t.name:"UnhandledRejection"};this.eventBus.emit("error:captured",o)},window.addEventListener("unhandledrejection",this.rejectionHandler)}teardown(){window.onerror=this.originalOnError,this.originalOnError=null,this.rejectionHandler&&(window.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null)}};function g(r,e){let t=new WeakSet;return JSON.stringify(r,(o,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return"[Circular]";t.add(n)}return typeof n=="function"?"[Function]":typeof n=="symbol"?n.toString():n instanceof Error?{name:n.name,message:n.message,stack:n.stack}:n},e)}var x=class{constructor(e){this.eventBus=e;this.name="console";this.originalError=null;this.originalWarn=null}setup(){this.originalError=console.error,this.originalWarn=console.warn,console.error=(...e)=>{let t={kind:"console",level:"error",args:e.map(o=>g(o))};this.eventBus.emit("console:captured",t),this.originalError.apply(console,e)},console.warn=(...e)=>{let t={kind:"console",level:"warn",args:e.map(o=>g(o))};this.eventBus.emit("console:captured",t),this.originalWarn.apply(console,e)}}teardown(){this.originalError&&(console.error=this.originalError),this.originalWarn&&(console.warn=this.originalWarn),this.originalError=null,this.originalWarn=null}};var E=class{constructor(e){this.eventBus=e;this.name="network";this.originalFetch=null;this.originalXhrOpen=null;this.originalXhrSend=null}setup(){this.patchFetch(),this.patchXHR()}patchFetch(){this.originalFetch=window.fetch;let e=this.eventBus,t=this.originalFetch;window.fetch=function(o,n){let i=n?.method?.toUpperCase()||"GET",s=typeof o=="string"?o:o instanceof URL?o.href:o.url,l=performance.now();return t.call(window,o,n).then(a=>{let p=Math.round(performance.now()-l);if(a.status>=400){let u={kind:"network",method:i,url:s,status:a.status,statusText:a.statusText,duration:p};e.emit("network:captured",u)}return e.emit("breadcrumb:added",{category:"network",message:`${i} ${s} -> ${a.status}`}),a},a=>{let p=Math.round(performance.now()-l),u={kind:"network",method:i,url:s,status:0,statusText:a.message||"Network Error",duration:p};throw e.emit("network:captured",u),a})}}patchXHR(){this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let e=this.eventBus,t=this.originalXhrOpen,o=this.originalXhrSend;XMLHttpRequest.prototype.open=function(n,i,...s){return this.__ghostbug_method=n.toUpperCase(),this.__ghostbug_url=String(i),t.apply(this,[n,i,...s])},XMLHttpRequest.prototype.send=function(n){let i=performance.now(),s=this;return s.addEventListener("loadend",function(){let l=Math.round(performance.now()-i),a=s.__ghostbug_method||"UNKNOWN",p=s.__ghostbug_url||"";if(s.status>=400||s.status===0){let u={kind:"network",method:a,url:p,status:s.status,statusText:s.statusText,duration:l};e.emit("network:captured",u)}e.emit("breadcrumb:added",{category:"network",message:`${a} ${p} -> ${s.status}`})}),o.call(this,n)}}teardown(){this.originalFetch&&(window.fetch=this.originalFetch,this.originalFetch=null),this.originalXhrOpen&&(XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=null),this.originalXhrSend&&(XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=null)}};function j(r){if(r.id)return`#${r.id}`;let e=r.getAttribute("data-testid");if(e)return`[data-testid="${e}"]`;let t=[],o=r,n=0;for(;o&&o!==document.documentElement&&n<5;){let i=o.tagName.toLowerCase();if(o.id){t.unshift(`#${o.id}`);break}let s=Array.from(o.classList).slice(0,2);s.length>0&&(i+="."+s.join("."));let l=o.parentElement;if(l){let a=o.tagName,p=Array.from(l.children).filter(u=>u.tagName===a);if(p.length>1){let u=p.indexOf(o)+1;i+=`:nth-child(${u})`}}t.unshift(i),o=l,n++}return t.join(" > ")}var k=class{constructor(e,t){this.eventBus=e;this.name="click";this.handler=null;this.clicks=new m(t)}setup(){this.handler=e=>{let t=e.target;if(!t)return;let o={timestamp:new Date().toISOString(),selector:j(t),tagName:t.tagName.toLowerCase(),text:(t.textContent||"").trim().slice(0,100),position:{x:e.clientX,y:e.clientY}};this.clicks.push(o),this.eventBus.emit("click:captured",o),this.eventBus.emit("breadcrumb:added",{category:"click",message:`Clicked ${o.tagName} "${o.text}"`,data:{selector:o.selector}})},document.addEventListener("click",this.handler,!0)}getClickTrail(){return this.clicks.toArray()}teardown(){this.handler&&(document.removeEventListener("click",this.handler,!0),this.handler=null),this.clicks.clear()}};var C=class{constructor(e){this.getMeta=e;this.name="context"}setup(){}teardown(){}snapshot(){let e=this.getMeta?.();return{url:window.location.href,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},devicePixelRatio:window.devicePixelRatio||1,timestamp:new Date().toISOString(),memory:performance.memory?{usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize}:void 0,user:e?.user,tags:e?.tags}}};var S=class{constructor(e){this.eventBus=e;this.name="interactions";this.handlers=[];this.scrollTimer=null;this.resizeTimer=null}setup(){this.addHandler(window,"scroll",this.onScroll.bind(this),{passive:!0,capture:!0}),this.addHandler(document,"input",this.onInput.bind(this),!0),this.addHandler(document,"change",this.onChange.bind(this),!0),this.addHandler(window,"popstate",this.onPopState.bind(this)),this.addHandler(window,"hashchange",this.onHashChange.bind(this)),this.addHandler(document,"visibilitychange",this.onVisibilityChange.bind(this)),this.addHandler(window,"resize",this.onResize.bind(this),{passive:!0})}addHandler(e,t,o,n){e.addEventListener(t,o,n),this.handlers.push({target:e,event:t,handler:o})}onScroll(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Scrolled",data:{x:window.scrollX,y:window.scrollY}})},300)}onInput(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"",i=t.type?`[type="${t.type}"]`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Input on ${o}${n}${i}`})}onChange(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Change on ${o}${n}`})}onPopState(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Navigated to ${window.location.href}`})}onHashChange(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Hash changed to ${window.location.hash}`})}onVisibilityChange(){this.eventBus.emit("breadcrumb:added",{category:"visibility",message:document.hidden?"Tab hidden":"Tab visible"})}onResize(){this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Window resized",data:{width:window.innerWidth,height:window.innerHeight}})},300)}teardown(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.resizeTimer&&clearTimeout(this.resizeTimer),this.handlers.forEach(({target:e,event:t,handler:o})=>{e.removeEventListener(t,o)}),this.handlers=[]}};var B=class{constructor(e){this.eventBus=e;this.name="performance";this.observers=[]}setup(){typeof PerformanceObserver>"u"||(this.observe("longtask",e=>{e.forEach(t=>{if(t.duration<50)return;let o={kind:"performance",metric:"longtask",value:Math.round(t.duration),entries:[{name:t.name,duration:t.duration,startTime:t.startTime}]};this.eventBus.emit("performance:captured",o),this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Long task: ${Math.round(t.duration)}ms`})})}),this.observe("largest-contentful-paint",e=>{let t=e[e.length-1];t&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`LCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}})}),this.observe("paint",e=>{e.forEach(t=>{t.name==="first-contentful-paint"&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`FCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}})})}),this.observe("layout-shift",e=>{e.forEach(t=>{let o=t.value;o>.1&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Layout shift: ${o.toFixed(4)}`,data:{cls:o}})})}))}observe(e,t){try{let o=new PerformanceObserver(n=>{t(n.getEntries())});o.observe({type:e,buffered:!0}),this.observers.push(o)}catch{}}teardown(){this.observers.forEach(e=>e.disconnect()),this.observers=[]}};function U(){let r=performance.memory;return!r||typeof r.usedJSHeapSize!="number"?null:r}var R=class{constructor(e){this.eventBus=e;this.name="memory";this.intervalId=null;this.baselineUsed=null}setup(){let e=U();e&&(this.baselineUsed=e.usedJSHeapSize,this.intervalId=setInterval(()=>{let t=U();if(!t)return;let o=t.usedJSHeapSize/t.jsHeapSizeLimit,n=this.baselineUsed>0?(t.usedJSHeapSize-this.baselineUsed)/this.baselineUsed:0;this.eventBus.emit("breadcrumb:added",{category:"memory",message:`Heap: ${(o*100).toFixed(1)}% used (${(t.usedJSHeapSize/1048576).toFixed(1)}MB)`,data:{usedJSHeapSize:t.usedJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit}});let i=o>=.9,s=n>=.5;if(i||s){let a={kind:"memory",message:i?`Heap usage critical: ${(o*100).toFixed(1)}% of limit`:`Heap growth spike: ${(n*100).toFixed(1)}% since init`,usedJSHeapSize:t.usedJSHeapSize,totalJSHeapSize:t.totalJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit,heapUsagePercent:o,heapGrowthPercent:n};this.eventBus.emit("memory:captured",a)}},1e4))}teardown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.baselineUsed=null}};var D=` | ||
| "use strict";var ghostbug=(()=>{var z=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var ne=Object.prototype.hasOwnProperty;var ie=(t,e)=>{for(var r in e)z(t,r,{get:e[r],enumerable:!0})},se=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of oe(e))!ne.call(t,n)&&n!==r&&z(t,n,{get:()=>e[n],enumerable:!(o=re(e,n))||o.enumerable});return t};var ae=t=>se(z({},"__esModule",{value:!0}),t);var be={};ie(be,{default:()=>fe,destroy:()=>te,download:()=>Y,getReports:()=>V,init:()=>W,onBug:()=>Q,setTags:()=>ee,setUser:()=>Z,toMarkdown:()=>K});var b="0.1.0",A={maxReports:50,maxBreadcrumbs:20,maxClicks:20,widget:!1,collectors:{errors:!0,console:!0,network:!0,clicks:!0,interactions:!0,performance:!0,memory:!0},rateLimit:{maxEvents:10,windowMs:1e3},beforeReport:t=>t,debug:!1};var v=class{constructor(){this.listeners=new Map}on(e,r){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(r),()=>this.off(e,r)}off(e,r){this.listeners.get(e)?.delete(r)}emit(e,r){this.listeners.get(e)?.forEach(o=>{try{o(r)}catch{}})}clear(){this.listeners.clear()}};var m=class{constructor(e){this.capacity=e;this.head=0;this._size=0;this.buffer=new Array(e)}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this._size<this.capacity&&this._size++}toArray(){if(this._size===0)return[];let e=[],r=this._size<this.capacity?0:this.head;for(let o=0;o<this._size;o++){let n=(r+o)%this.capacity;e.push(this.buffer[n])}return e}get size(){return this._size}get isFull(){return this._size===this.capacity}peek(){if(this._size===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}find(e){return this.toArray().find(e)}forEach(e){this.toArray().forEach(e)}clear(){this.buffer=new Array(this.capacity),this.head=0,this._size=0}};var y=class{constructor(e,r){this.maxEvents=e;this.windowMs=r;this.timestamps=[]}allow(){let e=Date.now();return this.timestamps=this.timestamps.filter(r=>e-r<this.windowMs),this.timestamps.length>=this.maxEvents?!1:(this.timestamps.push(e),!0)}reset(){this.timestamps=[]}};function le(t){let e=5381;for(let r=0;r<t.length;r++)e=(e<<5)+e+t.charCodeAt(r)&4294967295;return(e>>>0).toString(36)}function j(t){let e;switch(t.kind){case"error":{let r=t.stack?.split(` | ||
| `)[1]?.trim()||"";e=`${t.name}:${t.message}:${r}`;break}case"console":e=`console:${t.level}:${t.args.join(",")}`;break;case"network":e=`network:${t.method}:${t.url}:${t.status}`;break;case"performance":e=`performance:${t.metric}:${Math.floor(t.value/100)*100}`;break;case"memory":e=`memory:${Math.floor(t.heapUsagePercent*10)/10}`;break}return le(e)}function U(){let t=new Uint8Array(8);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(36).padStart(2,"0")).join("").slice(0,12)}var w=class{constructor(e,r,o){this.eventBus=e;this.contextCollector=r;this.options=o;this.unsubscribers=[];this.reports=new m(o.maxReports),this.breadcrumbs=new m(o.maxBreadcrumbs),this.rateLimiter=new y(o.rateLimit.maxEvents,o.rateLimit.windowMs),this.subscribe()}subscribe(){this.unsubscribers.push(this.eventBus.on("error:captured",e=>{this.addBreadcrumb({category:"error",message:e.message}),this.handleCapturedEvent("error",e)}),this.eventBus.on("console:captured",e=>{this.addBreadcrumb({category:"console",message:`console.${e.level}: ${e.args.join(", ")}`}),e.level==="error"&&this.handleCapturedEvent("console",e)}),this.eventBus.on("network:captured",e=>{this.handleCapturedEvent("network",e)}),this.eventBus.on("performance:captured",e=>{this.addBreadcrumb({category:"performance",message:`${e.metric}: ${e.value}ms`}),this.handleCapturedEvent("performance",e)}),this.eventBus.on("memory:captured",e=>{this.handleCapturedEvent("memory",e)}),this.eventBus.on("breadcrumb:added",e=>{this.addBreadcrumb(e)}))}async handleCapturedEvent(e,r){if(!this.rateLimiter.allow())return;let o=j(r),n=this.reports.find(l=>l.fingerprint===o);if(n){n.count++,n.timestamp=new Date().toISOString(),this.eventBus.emit("report:deduplicated",n);return}let i={id:U(),fingerprint:o,type:e,timestamp:new Date().toISOString(),count:1,payload:r,breadcrumbs:this.breadcrumbs.toArray(),context:this.contextCollector.snapshot()},a=this.options.beforeReport(i);a&&(i=a,this.reports.push(i),this.eventBus.emit("report:created",i))}addBreadcrumb(e){this.breadcrumbs.push({...e,timestamp:new Date().toISOString()})}getReports(){return this.reports.toArray()}clear(){this.reports.clear(),this.breadcrumbs.clear(),this.unsubscribers.forEach(e=>e()),this.unsubscribers=[]}get reportCount(){return this.reports.size}};var x=class{constructor(e){this.eventBus=e;this.name="error";this.originalOnError=null;this.rejectionHandler=null}setup(){this.originalOnError=window.onerror,window.onerror=(e,r,o,n,i)=>{let a={kind:"error",message:String(e),stack:i?.stack,filename:r??void 0,lineno:o??void 0,colno:n??void 0,name:i?.name};return this.eventBus.emit("error:captured",a),this.originalOnError?this.originalOnError.call(window,e,r,o,n,i):!1},this.rejectionHandler=e=>{let r=e.reason,o={kind:"error",message:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0,name:r instanceof Error?r.name:"UnhandledRejection"};this.eventBus.emit("error:captured",o)},window.addEventListener("unhandledrejection",this.rejectionHandler)}teardown(){window.onerror=this.originalOnError,this.originalOnError=null,this.rejectionHandler&&(window.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null)}};function f(t,e){let r=new WeakSet;return JSON.stringify(t,(o,n)=>{if(typeof n=="object"&&n!==null){if(r.has(n))return"[Circular]";r.add(n)}return typeof n=="function"?"[Function]":typeof n=="symbol"?n.toString():n instanceof Error?{name:n.name,message:n.message,stack:n.stack}:n},e)}var E=class{constructor(e){this.eventBus=e;this.name="console";this.originalError=null;this.originalWarn=null}setup(){this.originalError=console.error,this.originalWarn=console.warn,console.error=(...e)=>{let r={kind:"console",level:"error",args:e.map(o=>f(o))};this.eventBus.emit("console:captured",r),this.originalError.apply(console,e)},console.warn=(...e)=>{let r={kind:"console",level:"warn",args:e.map(o=>f(o))};this.eventBus.emit("console:captured",r),this.originalWarn.apply(console,e)}}teardown(){this.originalError&&(console.error=this.originalError),this.originalWarn&&(console.warn=this.originalWarn),this.originalError=null,this.originalWarn=null}};var k=class{constructor(e){this.eventBus=e;this.name="network";this.originalFetch=null;this.originalXhrOpen=null;this.originalXhrSend=null}setup(){this.patchFetch(),this.patchXHR()}patchFetch(){this.originalFetch=window.fetch;let e=this.eventBus,r=this.originalFetch;window.fetch=function(o,n){let i=n?.method?.toUpperCase()||"GET",a=typeof o=="string"?o:o instanceof URL?o.href:o.url,l=performance.now();return r.call(window,o,n).then(s=>{let p=Math.round(performance.now()-l);if(s.status>=400){let u={kind:"network",method:i,url:a,status:s.status,statusText:s.statusText,duration:p};e.emit("network:captured",u)}return e.emit("breadcrumb:added",{category:"network",message:`${i} ${a} -> ${s.status}`}),s},s=>{let p=Math.round(performance.now()-l),u={kind:"network",method:i,url:a,status:0,statusText:s.message||"Network Error",duration:p};throw e.emit("network:captured",u),s})}}patchXHR(){this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let e=this.eventBus,r=this.originalXhrOpen,o=this.originalXhrSend;XMLHttpRequest.prototype.open=function(n,i,...a){return this.__ghostbug_method=n.toUpperCase(),this.__ghostbug_url=String(i),r.apply(this,[n,i,...a])},XMLHttpRequest.prototype.send=function(n){let i=performance.now(),a=this;return a.addEventListener("loadend",function(){let l=Math.round(performance.now()-i),s=a.__ghostbug_method||"UNKNOWN",p=a.__ghostbug_url||"";if(a.status>=400||a.status===0){let u={kind:"network",method:s,url:p,status:a.status,statusText:a.statusText,duration:l};e.emit("network:captured",u)}e.emit("breadcrumb:added",{category:"network",message:`${s} ${p} -> ${a.status}`})}),o.call(this,n)}}teardown(){this.originalFetch&&(window.fetch=this.originalFetch,this.originalFetch=null),this.originalXhrOpen&&(XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=null),this.originalXhrSend&&(XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=null)}};function F(t){if(t.id)return`#${t.id}`;let e=t.getAttribute("data-testid");if(e)return`[data-testid="${e}"]`;let r=[],o=t,n=0;for(;o&&o!==document.documentElement&&n<5;){let i=o.tagName.toLowerCase();if(o.id){r.unshift(`#${o.id}`);break}let a=Array.from(o.classList).slice(0,2);a.length>0&&(i+="."+a.join("."));let l=o.parentElement;if(l){let s=o.tagName,p=Array.from(l.children).filter(u=>u.tagName===s);if(p.length>1){let u=p.indexOf(o)+1;i+=`:nth-child(${u})`}}r.unshift(i),o=l,n++}return r.join(" > ")}var C=class{constructor(e,r){this.eventBus=e;this.name="click";this.handler=null;this.clicks=new m(r)}setup(){this.handler=e=>{let r=e.target;if(!r)return;let o={timestamp:new Date().toISOString(),selector:F(r),tagName:r.tagName.toLowerCase(),text:(r.textContent||"").trim().slice(0,100),position:{x:e.clientX,y:e.clientY}};this.clicks.push(o),this.eventBus.emit("click:captured",o),this.eventBus.emit("breadcrumb:added",{category:"click",message:`Clicked ${o.tagName} "${o.text}"`,data:{selector:o.selector}})},document.addEventListener("click",this.handler,!0)}getClickTrail(){return this.clicks.toArray()}teardown(){this.handler&&(document.removeEventListener("click",this.handler,!0),this.handler=null),this.clicks.clear()}};var S=class{constructor(e){this.getMeta=e;this.name="context"}setup(){}teardown(){}snapshot(){let e=this.getMeta?.();return{url:window.location.href,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},devicePixelRatio:window.devicePixelRatio||1,timestamp:new Date().toISOString(),memory:performance.memory?{usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize}:void 0,user:e?.user,tags:e?.tags}}};var B=class{constructor(e){this.eventBus=e;this.name="interactions";this.handlers=[];this.scrollTimer=null;this.resizeTimer=null}setup(){this.addHandler(window,"scroll",this.onScroll.bind(this),{passive:!0,capture:!0}),this.addHandler(document,"input",this.onInput.bind(this),!0),this.addHandler(document,"change",this.onChange.bind(this),!0),this.addHandler(window,"popstate",this.onPopState.bind(this)),this.addHandler(window,"hashchange",this.onHashChange.bind(this)),this.addHandler(document,"visibilitychange",this.onVisibilityChange.bind(this)),this.addHandler(window,"resize",this.onResize.bind(this),{passive:!0})}addHandler(e,r,o,n){e.addEventListener(r,o,n),this.handlers.push({target:e,event:r,handler:o})}onScroll(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Scrolled",data:{x:window.scrollX,y:window.scrollY}})},300)}onInput(e){let r=e.target;if(!r)return;let o=r.tagName.toLowerCase(),n=r.id?`#${r.id}`:"",i=r.type?`[type="${r.type}"]`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Input on ${o}${n}${i}`})}onChange(e){let r=e.target;if(!r)return;let o=r.tagName.toLowerCase(),n=r.id?`#${r.id}`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Change on ${o}${n}`})}onPopState(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Navigated to ${window.location.href}`})}onHashChange(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Hash changed to ${window.location.hash}`})}onVisibilityChange(){this.eventBus.emit("breadcrumb:added",{category:"visibility",message:document.hidden?"Tab hidden":"Tab visible"})}onResize(){this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Window resized",data:{width:window.innerWidth,height:window.innerHeight}})},300)}teardown(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.resizeTimer&&clearTimeout(this.resizeTimer),this.handlers.forEach(({target:e,event:r,handler:o})=>{e.removeEventListener(r,o)}),this.handlers=[]}};var R=class{constructor(e){this.eventBus=e;this.name="performance";this.observers=[]}setup(){typeof PerformanceObserver>"u"||(this.observe("longtask",e=>{e.forEach(r=>{if(r.duration<50)return;let o={kind:"performance",metric:"longtask",value:Math.round(r.duration),entries:[{name:r.name,duration:r.duration,startTime:r.startTime}]};this.eventBus.emit("performance:captured",o),this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Long task: ${Math.round(r.duration)}ms`})})}),this.observe("largest-contentful-paint",e=>{let r=e[e.length-1];r&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`LCP: ${Math.round(r.startTime)}ms`,data:{value:r.startTime}})}),this.observe("paint",e=>{e.forEach(r=>{r.name==="first-contentful-paint"&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`FCP: ${Math.round(r.startTime)}ms`,data:{value:r.startTime}})})}),this.observe("layout-shift",e=>{e.forEach(r=>{let o=r.value;o>.1&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Layout shift: ${o.toFixed(4)}`,data:{cls:o}})})}))}observe(e,r){try{let o=new PerformanceObserver(n=>{r(n.getEntries())});o.observe({type:e,buffered:!0}),this.observers.push(o)}catch{}}teardown(){this.observers.forEach(e=>e.disconnect()),this.observers=[]}};function D(){let t=performance.memory;return!t||typeof t.usedJSHeapSize!="number"?null:t}var T=class{constructor(e){this.eventBus=e;this.name="memory";this.intervalId=null;this.baselineUsed=null}setup(){let e=D();e&&(this.baselineUsed=e.usedJSHeapSize,this.intervalId=setInterval(()=>{let r=D();if(!r)return;let o=r.usedJSHeapSize/r.jsHeapSizeLimit,n=this.baselineUsed>0?(r.usedJSHeapSize-this.baselineUsed)/this.baselineUsed:0;this.eventBus.emit("breadcrumb:added",{category:"memory",message:`Heap: ${(o*100).toFixed(1)}% used (${(r.usedJSHeapSize/1048576).toFixed(1)}MB)`,data:{usedJSHeapSize:r.usedJSHeapSize,jsHeapSizeLimit:r.jsHeapSizeLimit}});let i=o>=.9,a=n>=.5;if(i||a){let s={kind:"memory",message:i?`Heap usage critical: ${(o*100).toFixed(1)}% of limit`:`Heap growth spike: ${(n*100).toFixed(1)}% since init`,usedJSHeapSize:r.usedJSHeapSize,totalJSHeapSize:r.totalJSHeapSize,jsHeapSizeLimit:r.jsHeapSizeLimit,heapUsagePercent:o,heapGrowthPercent:n};this.eventBus.emit("memory:captured",s)}},1e4))}teardown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.baselineUsed=null}};var J=` | ||
| :host { | ||
@@ -165,16 +165,63 @@ all: initial; | ||
| .gb-report-item { | ||
| padding: 10px 16px; | ||
| border-bottom: 1px solid #f0f0f0; | ||
| cursor: pointer; | ||
| transition: background 0.15s; | ||
| } | ||
| .gb-report-item:hover { | ||
| .gb-report-item:last-child { | ||
| border-bottom: none; | ||
| } | ||
| .gb-report-summary { | ||
| padding: 10px 16px; | ||
| cursor: pointer; | ||
| } | ||
| .gb-report-summary:hover { | ||
| background: #f8f9fa; | ||
| } | ||
| .gb-report-item:last-child { | ||
| border-bottom: none; | ||
| .gb-report-detail { | ||
| display: none; | ||
| padding: 0 16px 12px; | ||
| border-top: 1px dashed #e8e8e8; | ||
| } | ||
| .gb-report-item.gb-expanded .gb-report-detail { | ||
| display: block; | ||
| } | ||
| .gb-detail-section { | ||
| margin-top: 8px; | ||
| } | ||
| .gb-detail-label { | ||
| font-size: 10px; | ||
| font-weight: 700; | ||
| text-transform: uppercase; | ||
| letter-spacing: 0.5px; | ||
| color: #999; | ||
| margin-bottom: 2px; | ||
| } | ||
| .gb-detail-value { | ||
| font-size: 12px; | ||
| color: #555; | ||
| word-break: break-word; | ||
| line-height: 1.4; | ||
| } | ||
| .gb-detail-pre { | ||
| font-size: 11px; | ||
| font-family: 'SF Mono', Menlo, Monaco, monospace; | ||
| background: #f5f5f5; | ||
| padding: 8px; | ||
| border-radius: 6px; | ||
| overflow-x: auto; | ||
| max-height: 120px; | ||
| overflow-y: auto; | ||
| color: #333; | ||
| white-space: pre-wrap; | ||
| word-break: break-word; | ||
| } | ||
| .gb-report-type { | ||
@@ -257,4 +304,5 @@ display: inline-block; | ||
| } | ||
| `;var ce='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></svg>';function G(){let r=document.createElement("button");r.className="gb-fab",r.setAttribute("aria-label","ghostbug - bug reports");let e=document.createElement("span");e.innerHTML=ce,r.appendChild(e);let t=document.createElement("span");return t.className="gb-badge",t.setAttribute("data-count","0"),t.textContent="0",r.appendChild(t),r}function X(r){let e=document.createElement("div");e.className=`gb-panel gb-pos-${r}`;let t=document.createElement("div");t.className="gb-header";let o=document.createElement("span");o.className="gb-header-title",o.textContent="ghostbug",t.appendChild(o);let n=document.createElement("button");n.className="gb-header-btn gb-copy-btn",n.textContent="Copy MD",t.appendChild(n);let i=document.createElement("button");i.className="gb-header-btn gb-download-btn",i.textContent="Export",t.appendChild(i);let s=document.createElement("button");s.className="gb-close-btn",s.textContent="\xD7",s.setAttribute("aria-label","Close"),t.appendChild(s),e.appendChild(t);let l=document.createElement("div");l.className="gb-report-list";let a=document.createElement("div");return a.className="gb-empty",a.textContent="No bugs captured yet.",l.appendChild(a),e.appendChild(l),e}function q(r){let e=document.createElement("div");e.className="gb-report-item";let t=document.createElement("span");if(t.className=`gb-report-type gb-type-${r.payload.kind==="error"?"error":r.payload.kind}`,t.textContent=r.type,e.appendChild(t),r.count>1){let s=document.createElement("span");s.className="gb-report-count",s.textContent=`\xD7${r.count}`,e.appendChild(s)}let o=document.createElement("div");o.className="gb-report-message",o.textContent=de(r),e.appendChild(o);let n=document.createElement("div");n.className="gb-report-meta";let i=r.timestamp.split("T")[1]?.split(".")[0]||r.timestamp;return n.textContent=`${i} \xB7 ${r.context.url}`,e.appendChild(n),e}function de(r){switch(r.payload.kind){case"error":return r.payload.message;case"console":return r.payload.args.join(", ");case"network":return`${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case"performance":return`${r.payload.metric}: ${r.payload.value}ms`;case"memory":return r.payload.message}}function T(r){return g({generator:"ghostbug",version:f,exportedAt:new Date().toISOString(),reportCount:r.length,reports:r},2)}function L(r){let e=[];return e.push(`# Bug Report \u2014 ghostbug v${f}`),e.push(`**Generated:** ${new Date().toISOString()}`),e.push(`**Reports:** ${r.length}`),e.push(""),e.push("---"),e.push(""),r.forEach((t,o)=>{e.push(`## ${o+1}. ${pe(t)}`),e.push(""),e.push(`- **Type:** ${t.type}`),e.push(`- **Time:** ${t.timestamp}`),e.push(`- **Occurrences:** ${t.count}`),e.push(`- **URL:** ${t.context.url}`),e.push(`- **Browser:** ${me(t.context.userAgent)}`),e.push(`- **Viewport:** ${t.context.viewport.width}x${t.context.viewport.height}`),e.push(""),e.push(...ue(t.payload)),e.push(""),t.breadcrumbs.length>0&&(e.push("### Breadcrumbs"),e.push(""),e.push("| Time | Category | Event |"),e.push("|------|----------|-------|"),t.breadcrumbs.forEach(n=>{let i=n.timestamp.split("T")[1]?.split(".")[0]||n.timestamp;e.push(`| ${i} | ${n.category} | ${n.message} |`)}),e.push("")),e.push("---"),e.push("")}),e.join(` | ||
| `)}function pe(r){switch(r.payload.kind){case"error":return`${r.payload.name||"Error"}: ${r.payload.message}`;case"console":return`Console ${r.payload.level}: ${r.payload.args[0]||""}`;case"network":return`${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case"performance":return`Performance: ${r.payload.metric} ${r.payload.value}ms`;case"memory":return`Memory: ${r.payload.message}`}}function ue(r){let e=[];switch(r.kind){case"error":r.stack&&(e.push("### Stack Trace"),e.push(""),e.push("```"),e.push(r.stack),e.push("```")),r.filename&&e.push(`**File:** ${r.filename}:${r.lineno}:${r.colno}`);break;case"console":e.push("### Console Output"),e.push(""),e.push("```"),r.args.forEach(t=>e.push(t)),e.push("```");break;case"network":e.push("### Network Details"),e.push(""),e.push(`- **Method:** ${r.method}`),e.push(`- **URL:** ${r.url}`),e.push(`- **Status:** ${r.status} ${r.statusText}`),e.push(`- **Duration:** ${r.duration}ms`);break;case"performance":e.push("### Performance Details"),e.push(""),e.push(`- **Metric:** ${r.metric}`),e.push(`- **Value:** ${r.value}ms`),r.entries.length>0&&e.push(`- **Start Time:** ${Math.round(r.entries[0].startTime)}ms`);break;case"memory":e.push("### Memory Details"),e.push(""),e.push(`- **Used:** ${(r.usedJSHeapSize/1048576).toFixed(1)}MB`),e.push(`- **Limit:** ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB`),e.push(`- **Usage:** ${(r.heapUsagePercent*100).toFixed(1)}%`),e.push(`- **Growth since init:** ${(r.heapGrowthPercent*100).toFixed(1)}%`);break}return e}function me(r){if(r.includes("Chrome")){let e=r.match(/Chrome\/(\d+)/);return e?`Chrome ${e[1]}`:"Chrome"}if(r.includes("Firefox")){let e=r.match(/Firefox\/(\d+)/);return e?`Firefox ${e[1]}`:"Firefox"}if(r.includes("Safari")&&!r.includes("Chrome")){let e=r.match(/Version\/(\d+)/);return e?`Safari ${e[1]}`:"Safari"}return r.slice(0,50)}var P=class{constructor(e,t,o){this.eventBus=e;this.reportManager=t;this.options=o;this.hostElement=null;this.shadowRoot=null;this.panel=null;this.badge=null;this.reportList=null;this.isExpanded=!1;this.unsubscribers=[]}mount(){this.hostElement=document.createElement("div"),this.hostElement.id="ghostbug-widget";let e=this.hostElement.style;e.position="fixed",e.zIndex=String(this.options.zIndex),e.margin="0",e.padding="0",this.applyPosition(e),this.shadowRoot=this.hostElement.attachShadow({mode:"closed"});let t=document.createElement("style");t.textContent=D,this.shadowRoot.appendChild(t);let o=document.createElement("div");o.className="gb-container";let n=G();this.badge=n.querySelector(".gb-badge"),n.addEventListener("click",()=>this.toggle()),o.appendChild(n),this.panel=X(this.options.position),o.appendChild(this.panel),this.panel.querySelector(".gb-close-btn")?.addEventListener("click",()=>this.toggle()),this.panel.querySelector(".gb-copy-btn")?.addEventListener("click",()=>this.copyMarkdown()),this.panel.querySelector(".gb-download-btn")?.addEventListener("click",()=>this.downloadJSON()),this.reportList=this.panel.querySelector(".gb-report-list"),this.shadowRoot.appendChild(o),document.body.appendChild(this.hostElement),this.unsubscribers.push(this.eventBus.on("report:created",()=>this.update()),this.eventBus.on("report:deduplicated",()=>this.update())),this.options.collapsed||this.toggle()}applyPosition(e){let t=this.options.position;e.top=t.startsWith("top")?"16px":"auto",e.bottom=t.startsWith("bottom")?"16px":"auto",e.left=t.endsWith("left")?"16px":"auto",e.right=t.endsWith("right")?"16px":"auto"}toggle(){this.isExpanded=!this.isExpanded,this.isExpanded?(this.panel?.classList.add("gb-open"),this.renderReportList()):this.panel?.classList.remove("gb-open")}update(){this.updateBadge(),this.isExpanded&&this.renderReportList()}updateBadge(){if(!this.badge)return;let e=this.reportManager.reportCount;this.badge.textContent=String(e),this.badge.setAttribute("data-count",String(e))}renderReportList(){if(!this.reportList)return;this.reportList.textContent="";let e=this.reportManager.getReports();if(e.length===0){let o=document.createElement("div");o.className="gb-empty",o.textContent="No bugs captured yet.",this.reportList.appendChild(o);return}[...e].reverse().forEach(o=>{let n=q(o);this.reportList.appendChild(n)})}copyMarkdown(){let e=L(this.reportManager.getReports());navigator.clipboard.writeText(e).then(()=>this.showToast("Copied to clipboard!"),()=>this.showToast("Copy failed"))}downloadJSON(){let e=T(this.reportManager.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download="ghostbug-report.json",n.click(),URL.revokeObjectURL(o)}showToast(e){if(!this.shadowRoot)return;let t=document.createElement("div");t.className="gb-toast",t.textContent=e,this.shadowRoot.appendChild(t),requestAnimationFrame(()=>{t.classList.add("gb-show")}),setTimeout(()=>{t.classList.remove("gb-show"),setTimeout(()=>t.remove(),300)},2e3)}unmount(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.hostElement?.remove(),this.hostElement=null,this.shadowRoot=null,this.panel=null,this.badge=null,this.reportList=null}};var c=null,h=null,d=[],H=null,$=new Set,M=!1,N,O;function he(r,e){return e?{maxReports:e.maxReports??r.maxReports,maxBreadcrumbs:e.maxBreadcrumbs??r.maxBreadcrumbs,maxClicks:e.maxClicks??r.maxClicks,widget:e.widget??r.widget,collectors:{...r.collectors,...e.collectors},rateLimit:{...r.rateLimit,...e.rateLimit},beforeReport:e.beforeReport??r.beforeReport,debug:e.debug??r.debug,screenshotFn:e.screenshotFn}:{...r}}function W(r){if(M){r?.debug&&console.warn("[ghostbug] Already initialized. Call destroy() first.");return}let e=he(I,r);c=new b;let t=new C(()=>({user:N,tags:O}));if(h=new y(c,t,e),e.collectors.errors&&d.push(new w(c)),e.collectors.console&&d.push(new x(c)),e.collectors.network&&d.push(new E(c)),e.collectors.clicks&&d.push(new k(c,e.maxClicks)),e.collectors.interactions&&d.push(new S(c)),e.collectors.performance&&d.push(new B(c)),e.collectors.memory&&d.push(new R(c)),d.push(t),d.forEach(o=>o.setup()),c.on("report:created",o=>{$.forEach(n=>{try{n(o)}catch{}})}),e.widget){let o=typeof e.widget=="object"?{position:e.widget.position||"bottom-right",collapsed:e.widget.collapsed??!0,zIndex:e.widget.zIndex??2147483647}:{position:"bottom-right",collapsed:!0,zIndex:2147483647};H=new P(c,h,o),H.mount()}M=!0}function J(){return _(),h.getReports()}function V(r="ghostbug-report.json"){_();let e=T(h.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download=r,n.click(),URL.revokeObjectURL(o)}function Y(){return _(),L(h.getReports())}function K(r){return $.add(r),()=>$.delete(r)}function Q(r){N=r}function Z(r){O={...O,...r}}function ee(){H?.unmount(),H=null,d.forEach(r=>r.teardown()),d=[],c?.clear(),c=null,h?.clear(),h=null,$.clear(),N=void 0,O=void 0,M=!1}function _(){if(!M)throw new Error("[ghostbug] Not initialized. Call ghostbug.init() first.")}var ge={init:W,getReports:J,download:V,toMarkdown:Y,onBug:K,setUser:Q,setTags:Z,destroy:ee};return se(fe);})(); | ||
| `;var de='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></svg>';function G(){let t=document.createElement("button");t.className="gb-fab",t.setAttribute("aria-label","ghostbug - bug reports");let e=document.createElement("span");e.innerHTML=de,t.appendChild(e);let r=document.createElement("span");return r.className="gb-badge",r.setAttribute("data-count","0"),r.textContent="0",t.appendChild(r),t}function q(t){let e=document.createElement("div");e.className=`gb-panel gb-pos-${t}`;let r=document.createElement("div");r.className="gb-header";let o=document.createElement("span");o.className="gb-header-title",o.textContent="ghostbug",r.appendChild(o);let n=document.createElement("button");n.className="gb-header-btn gb-copy-btn",n.textContent="Copy MD",r.appendChild(n);let i=document.createElement("button");i.className="gb-header-btn gb-download-btn",i.textContent="Export",r.appendChild(i);let a=document.createElement("button");a.className="gb-close-btn",a.textContent="\xD7",a.setAttribute("aria-label","Close"),r.appendChild(a),e.appendChild(r);let l=document.createElement("div");l.className="gb-report-list";let s=document.createElement("div");return s.className="gb-empty",s.textContent="No bugs captured yet.",l.appendChild(s),e.appendChild(l),e}function X(t){let e=document.createElement("div");e.className="gb-report-item";let r=document.createElement("div");r.className="gb-report-summary";let o=document.createElement("span");if(o.className=`gb-report-type gb-type-${t.payload.kind==="error"?"error":t.payload.kind}`,o.textContent=t.type,r.appendChild(o),t.count>1){let s=document.createElement("span");s.className="gb-report-count",s.textContent=`\xD7${t.count}`,r.appendChild(s)}let n=document.createElement("div");n.className="gb-report-message",n.textContent=pe(t),r.appendChild(n);let i=document.createElement("div");i.className="gb-report-meta";let a=t.timestamp.split("T")[1]?.split(".")[0]||t.timestamp;i.textContent=`${a} \xB7 ${t.context.url}`,r.appendChild(i),e.appendChild(r);let l=document.createElement("div");if(l.className="gb-report-detail",l.appendChild(ce(t.payload)),t.context.user){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">User</div><div class="gb-detail-value">${g(JSON.stringify(t.context.user))}</div>`,l.appendChild(s)}if(t.context.tags){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">Tags</div><div class="gb-detail-value">${g(JSON.stringify(t.context.tags))}</div>`,l.appendChild(s)}if(t.breadcrumbs.length>0){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">Breadcrumbs</div><div class="gb-detail-value">${t.breadcrumbs.length} events</div>`,l.appendChild(s)}return e.appendChild(l),r.addEventListener("click",()=>{e.classList.toggle("gb-expanded")}),e}function g(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function ce(t){let e=document.createElement("div");switch(e.className="gb-detail-section",t.kind){case"error":{if(t.stack){let r=document.createElement("div");r.className="gb-detail-label",r.textContent="Stack Trace",e.appendChild(r);let o=document.createElement("pre");o.className="gb-detail-pre",o.textContent=t.stack,e.appendChild(o)}if(t.filename){let r=document.createElement("div");r.className="gb-detail-value",r.textContent=`${t.filename}:${t.lineno}:${t.colno}`,e.appendChild(r)}break}case"console":{let r=document.createElement("div");r.className="gb-detail-label",r.textContent="Output",e.appendChild(r);let o=document.createElement("pre");o.className="gb-detail-pre",o.textContent=t.args.join(` | ||
| `),e.appendChild(o);break}case"network":{e.innerHTML=`<div class="gb-detail-label">Request</div><div class="gb-detail-value">${g(t.method)} ${g(t.url)}<br>Status: ${t.status} ${g(t.statusText)}<br>Duration: ${t.duration}ms</div>`;break}case"performance":{e.innerHTML=`<div class="gb-detail-label">Performance</div><div class="gb-detail-value">Metric: ${g(t.metric)}<br>Value: ${t.value}ms</div>`;break}case"memory":{e.innerHTML=`<div class="gb-detail-label">Memory</div><div class="gb-detail-value">Used: ${(t.usedJSHeapSize/1048576).toFixed(1)}MB<br>Limit: ${(t.jsHeapSizeLimit/1048576).toFixed(1)}MB<br>Usage: ${(t.heapUsagePercent*100).toFixed(1)}%</div>`;break}}return e}function pe(t){switch(t.payload.kind){case"error":return t.payload.message;case"console":return t.payload.args.join(", ");case"network":return`${t.payload.method} ${t.payload.url} \u2192 ${t.payload.status}`;case"performance":return`${t.payload.metric}: ${t.payload.value}ms`;case"memory":return t.payload.message}}function L(t){return f({generator:"ghostbug",version:b,exportedAt:new Date().toISOString(),reportCount:t.length,reports:t},2)}function P(t){let e=[];return e.push(`# Bug Report \u2014 ghostbug v${b}`),e.push(`**Generated:** ${new Date().toISOString()}`),e.push(`**Reports:** ${t.length}`),e.push(""),e.push("---"),e.push(""),t.forEach((r,o)=>{e.push(`## ${o+1}. ${ue(r)}`),e.push(""),e.push(`- **Type:** ${r.type}`),e.push(`- **Time:** ${r.timestamp}`),e.push(`- **Occurrences:** ${r.count}`),e.push(`- **URL:** ${r.context.url}`),e.push(`- **Browser:** ${he(r.context.userAgent)}`),e.push(`- **Viewport:** ${r.context.viewport.width}x${r.context.viewport.height}`),e.push(""),e.push(...me(r.payload)),e.push(""),r.context.user&&(e.push("### User Context"),e.push(""),e.push("```json"),e.push(JSON.stringify(r.context.user,null,2)),e.push("```"),e.push("")),r.context.tags&&(e.push("### Tags"),e.push(""),e.push("```json"),e.push(JSON.stringify(r.context.tags,null,2)),e.push("```"),e.push("")),r.breadcrumbs.length>0&&(e.push("### Breadcrumbs"),e.push(""),e.push("| Time | Category | Event |"),e.push("|------|----------|-------|"),r.breadcrumbs.forEach(n=>{let i=n.timestamp.split("T")[1]?.split(".")[0]||n.timestamp;e.push(`| ${i} | ${n.category} | ${n.message} |`)}),e.push("")),e.push("---"),e.push("")}),e.join(` | ||
| `)}function ue(t){switch(t.payload.kind){case"error":return`${t.payload.name||"Error"}: ${t.payload.message}`;case"console":return`Console ${t.payload.level}: ${t.payload.args[0]||""}`;case"network":return`${t.payload.method} ${t.payload.url} \u2192 ${t.payload.status}`;case"performance":return`Performance: ${t.payload.metric} ${t.payload.value}ms`;case"memory":return`Memory: ${t.payload.message}`}}function me(t){let e=[];switch(t.kind){case"error":t.stack&&(e.push("### Stack Trace"),e.push(""),e.push("```"),e.push(t.stack),e.push("```")),t.filename&&e.push(`**File:** ${t.filename}:${t.lineno}:${t.colno}`);break;case"console":e.push("### Console Output"),e.push(""),e.push("```"),t.args.forEach(r=>e.push(r)),e.push("```");break;case"network":e.push("### Network Details"),e.push(""),e.push(`- **Method:** ${t.method}`),e.push(`- **URL:** ${t.url}`),e.push(`- **Status:** ${t.status} ${t.statusText}`),e.push(`- **Duration:** ${t.duration}ms`);break;case"performance":e.push("### Performance Details"),e.push(""),e.push(`- **Metric:** ${t.metric}`),e.push(`- **Value:** ${t.value}ms`),t.entries.length>0&&e.push(`- **Start Time:** ${Math.round(t.entries[0].startTime)}ms`);break;case"memory":e.push("### Memory Details"),e.push(""),e.push(`- **Used:** ${(t.usedJSHeapSize/1048576).toFixed(1)}MB`),e.push(`- **Limit:** ${(t.jsHeapSizeLimit/1048576).toFixed(1)}MB`),e.push(`- **Usage:** ${(t.heapUsagePercent*100).toFixed(1)}%`),e.push(`- **Growth since init:** ${(t.heapGrowthPercent*100).toFixed(1)}%`);break}return e}function he(t){if(t.includes("Chrome")){let e=t.match(/Chrome\/(\d+)/);return e?`Chrome ${e[1]}`:"Chrome"}if(t.includes("Firefox")){let e=t.match(/Firefox\/(\d+)/);return e?`Firefox ${e[1]}`:"Firefox"}if(t.includes("Safari")&&!t.includes("Chrome")){let e=t.match(/Version\/(\d+)/);return e?`Safari ${e[1]}`:"Safari"}return t.slice(0,50)}var $=class{constructor(e,r,o){this.eventBus=e;this.reportManager=r;this.options=o;this.hostElement=null;this.shadowRoot=null;this.panel=null;this.badge=null;this.reportList=null;this.isExpanded=!1;this.unsubscribers=[]}mount(){this.hostElement=document.createElement("div"),this.hostElement.id="ghostbug-widget";let e=this.hostElement.style;e.position="fixed",e.zIndex=String(this.options.zIndex),e.margin="0",e.padding="0",this.applyPosition(e),this.shadowRoot=this.hostElement.attachShadow({mode:"closed"});let r=document.createElement("style");r.textContent=J,this.shadowRoot.appendChild(r);let o=document.createElement("div");o.className="gb-container";let n=G();this.badge=n.querySelector(".gb-badge"),n.addEventListener("click",()=>this.toggle()),o.appendChild(n),this.panel=q(this.options.position),o.appendChild(this.panel),this.panel.querySelector(".gb-close-btn")?.addEventListener("click",()=>this.toggle()),this.panel.querySelector(".gb-copy-btn")?.addEventListener("click",()=>this.copyMarkdown()),this.panel.querySelector(".gb-download-btn")?.addEventListener("click",()=>this.downloadJSON()),this.reportList=this.panel.querySelector(".gb-report-list"),this.shadowRoot.appendChild(o),document.body.appendChild(this.hostElement),this.unsubscribers.push(this.eventBus.on("report:created",()=>this.update()),this.eventBus.on("report:deduplicated",()=>this.update())),this.options.collapsed||this.toggle()}applyPosition(e){let r=this.options.position;e.top=r.startsWith("top")?"16px":"auto",e.bottom=r.startsWith("bottom")?"16px":"auto",e.left=r.endsWith("left")?"16px":"auto",e.right=r.endsWith("right")?"16px":"auto"}toggle(){this.isExpanded=!this.isExpanded,this.isExpanded?(this.panel?.classList.add("gb-open"),this.renderReportList()):this.panel?.classList.remove("gb-open")}update(){this.updateBadge(),this.isExpanded&&this.renderReportList()}updateBadge(){if(!this.badge)return;let e=this.reportManager.reportCount;this.badge.textContent=String(e),this.badge.setAttribute("data-count",String(e))}renderReportList(){if(!this.reportList)return;this.reportList.textContent="";let e=this.reportManager.getReports();if(e.length===0){let o=document.createElement("div");o.className="gb-empty",o.textContent="No bugs captured yet.",this.reportList.appendChild(o);return}[...e].reverse().forEach(o=>{let n=X(o);this.reportList.appendChild(n)})}copyMarkdown(){let e=P(this.reportManager.getReports());navigator.clipboard.writeText(e).then(()=>this.showToast("Copied to clipboard!"),()=>this.showToast("Copy failed"))}downloadJSON(){let e=L(this.reportManager.getReports()),r=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(r),n=document.createElement("a");n.href=o,n.download="ghostbug-report.json",n.click(),URL.revokeObjectURL(o)}showToast(e){if(!this.shadowRoot)return;let r=document.createElement("div");r.className="gb-toast",r.textContent=e,this.shadowRoot.appendChild(r),requestAnimationFrame(()=>{r.classList.add("gb-show")}),setTimeout(()=>{r.classList.remove("gb-show"),setTimeout(()=>r.remove(),300)},2e3)}unmount(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.hostElement?.remove(),this.hostElement=null,this.shadowRoot=null,this.panel=null,this.badge=null,this.reportList=null}};var d=null,h=null,c=[],H=null,M=new Set,O=!1,_,N;function ge(t,e){return e?{maxReports:e.maxReports??t.maxReports,maxBreadcrumbs:e.maxBreadcrumbs??t.maxBreadcrumbs,maxClicks:e.maxClicks??t.maxClicks,widget:e.widget??t.widget,collectors:{...t.collectors,...e.collectors},rateLimit:{...t.rateLimit,...e.rateLimit},beforeReport:e.beforeReport??t.beforeReport,debug:e.debug??t.debug}:{...t}}function W(t){if(O){t?.debug&&console.warn("[ghostbug] Already initialized. Call destroy() first.");return}let e=ge(A,t);d=new v;let r=new S(()=>({user:_,tags:N}));if(h=new w(d,r,e),e.collectors.errors&&c.push(new x(d)),e.collectors.console&&c.push(new E(d)),e.collectors.network&&c.push(new k(d)),e.collectors.clicks&&c.push(new C(d,e.maxClicks)),e.collectors.interactions&&c.push(new B(d)),e.collectors.performance&&c.push(new R(d)),e.collectors.memory&&c.push(new T(d)),c.push(r),c.forEach(o=>o.setup()),d.on("report:created",o=>{M.forEach(n=>{try{n(o)}catch{}})}),e.widget){let o=typeof e.widget=="object"?{position:e.widget.position||"bottom-right",collapsed:e.widget.collapsed??!0,zIndex:e.widget.zIndex??2147483647}:{position:"bottom-right",collapsed:!0,zIndex:2147483647};H=new $(d,h,o),H.mount()}O=!0}function V(){return I(),h.getReports()}function Y(t="ghostbug-report.json"){I();let e=L(h.getReports()),r=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(r),n=document.createElement("a");n.href=o,n.download=t,n.click(),URL.revokeObjectURL(o)}function K(){return I(),P(h.getReports())}function Q(t){return M.add(t),()=>M.delete(t)}function Z(t){_=t}function ee(t){N={...N,...t}}function te(){H?.unmount(),H=null,c.forEach(t=>t.teardown()),c=[],d?.clear(),d=null,h?.clear(),h=null,M.clear(),_=void 0,N=void 0,O=!1}function I(){if(!O)throw new Error("[ghostbug] Not initialized. Call ghostbug.init() first.")}var fe={init:W,getReports:V,download:Y,toMarkdown:K,onBug:Q,setUser:Z,setTags:ee,destroy:te};return ae(be);})(); | ||
| //# sourceMappingURL=index.iife.js.map |
+57
-9
@@ -1,3 +0,3 @@ | ||
| var f="0.1.0",_={maxReports:50,maxBreadcrumbs:20,maxClicks:20,widget:false,collectors:{errors:true,console:true,network:true,clicks:true,interactions:true,performance:true,memory:true},rateLimit:{maxEvents:10,windowMs:1e3},beforeReport:r=>r,debug:false};var b=class{constructor(){this.listeners=new Map;}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t);}emit(e,t){this.listeners.get(e)?.forEach(o=>{try{o(t);}catch{}});}clear(){this.listeners.clear();}};var m=class{constructor(e){this.capacity=e;this.head=0;this._size=0;this.buffer=new Array(e);}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this._size<this.capacity&&this._size++;}toArray(){if(this._size===0)return [];let e=[],t=this._size<this.capacity?0:this.head;for(let o=0;o<this._size;o++){let n=(t+o)%this.capacity;e.push(this.buffer[n]);}return e}get size(){return this._size}get isFull(){return this._size===this.capacity}peek(){if(this._size===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}find(e){return this.toArray().find(e)}forEach(e){this.toArray().forEach(e);}clear(){this.buffer=new Array(this.capacity),this.head=0,this._size=0;}};var v=class{constructor(e,t){this.maxEvents=e;this.windowMs=t;this.timestamps=[];}allow(){let e=Date.now();return this.timestamps=this.timestamps.filter(t=>e-t<this.windowMs),this.timestamps.length>=this.maxEvents?false:(this.timestamps.push(e),true)}reset(){this.timestamps=[];}};function q(r){let e=5381;for(let t=0;t<r.length;t++)e=(e<<5)+e+r.charCodeAt(t)&4294967295;return (e>>>0).toString(36)}function I(r){let e;switch(r.kind){case "error":{let t=r.stack?.split(` | ||
| `)[1]?.trim()||"";e=`${r.name}:${r.message}:${t}`;break}case "console":e=`console:${r.level}:${r.args.join(",")}`;break;case "network":e=`network:${r.method}:${r.url}:${r.status}`;break;case "performance":e=`performance:${r.metric}:${Math.floor(r.value/100)*100}`;break;case "memory":e=`memory:${Math.floor(r.heapUsagePercent*10)/10}`;break}return q(e)}function A(){let r=new Uint8Array(8);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(36).padStart(2,"0")).join("").slice(0,12)}var W=3e3,y=class{constructor(e,t,o){this.eventBus=e;this.contextCollector=t;this.options=o;this.unsubscribers=[];this.reports=new m(o.maxReports),this.breadcrumbs=new m(o.maxBreadcrumbs),this.rateLimiter=new v(o.rateLimit.maxEvents,o.rateLimit.windowMs),this.subscribe();}subscribe(){this.unsubscribers.push(this.eventBus.on("error:captured",e=>{this.addBreadcrumb({category:"error",message:e.message}),this.handleCapturedEvent("error",e);}),this.eventBus.on("console:captured",e=>{this.addBreadcrumb({category:"console",message:`console.${e.level}: ${e.args.join(", ")}`}),e.level==="error"&&this.handleCapturedEvent("console",e);}),this.eventBus.on("network:captured",e=>{this.handleCapturedEvent("network",e);}),this.eventBus.on("performance:captured",e=>{this.addBreadcrumb({category:"performance",message:`${e.metric}: ${e.value}ms`}),this.handleCapturedEvent("performance",e);}),this.eventBus.on("memory:captured",e=>{this.handleCapturedEvent("memory",e);}),this.eventBus.on("breadcrumb:added",e=>{this.addBreadcrumb(e);}));}async handleCapturedEvent(e,t){if(!this.rateLimiter.allow())return;let o=I(t),n=this.reports.find(l=>l.fingerprint===o);if(n){n.count++,n.timestamp=new Date().toISOString(),this.eventBus.emit("report:deduplicated",n);return}let i={id:A(),fingerprint:o,type:e,timestamp:new Date().toISOString(),count:1,payload:t,breadcrumbs:this.breadcrumbs.toArray(),context:this.contextCollector.snapshot()};if(this.options.screenshotFn)try{i.screenshot=await Promise.race([this.options.screenshotFn(),new Promise((l,a)=>setTimeout(()=>a(new Error("screenshot timeout")),W))]);}catch{}let s=this.options.beforeReport(i);s&&(i=s,this.reports.push(i),this.eventBus.emit("report:created",i));}addBreadcrumb(e){this.breadcrumbs.push({...e,timestamp:new Date().toISOString()});}getReports(){return this.reports.toArray()}clear(){this.reports.clear(),this.breadcrumbs.clear(),this.unsubscribers.forEach(e=>e()),this.unsubscribers=[];}get reportCount(){return this.reports.size}};var w=class{constructor(e){this.eventBus=e;this.name="error";this.originalOnError=null;this.rejectionHandler=null;}setup(){this.originalOnError=window.onerror,window.onerror=(e,t,o,n,i)=>{let s={kind:"error",message:String(e),stack:i?.stack,filename:t??void 0,lineno:o??void 0,colno:n??void 0,name:i?.name};return this.eventBus.emit("error:captured",s),this.originalOnError?this.originalOnError.call(window,e,t,o,n,i):false},this.rejectionHandler=e=>{let t=e.reason,o={kind:"error",message:t instanceof Error?t.message:String(t),stack:t instanceof Error?t.stack:void 0,name:t instanceof Error?t.name:"UnhandledRejection"};this.eventBus.emit("error:captured",o);},window.addEventListener("unhandledrejection",this.rejectionHandler);}teardown(){window.onerror=this.originalOnError,this.originalOnError=null,this.rejectionHandler&&(window.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null);}};function g(r,e){let t=new WeakSet;return JSON.stringify(r,(o,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return "[Circular]";t.add(n);}return typeof n=="function"?"[Function]":typeof n=="symbol"?n.toString():n instanceof Error?{name:n.name,message:n.message,stack:n.stack}:n},e)}var x=class{constructor(e){this.eventBus=e;this.name="console";this.originalError=null;this.originalWarn=null;}setup(){this.originalError=console.error,this.originalWarn=console.warn,console.error=(...e)=>{let t={kind:"console",level:"error",args:e.map(o=>g(o))};this.eventBus.emit("console:captured",t),this.originalError.apply(console,e);},console.warn=(...e)=>{let t={kind:"console",level:"warn",args:e.map(o=>g(o))};this.eventBus.emit("console:captured",t),this.originalWarn.apply(console,e);};}teardown(){this.originalError&&(console.error=this.originalError),this.originalWarn&&(console.warn=this.originalWarn),this.originalError=null,this.originalWarn=null;}};var E=class{constructor(e){this.eventBus=e;this.name="network";this.originalFetch=null;this.originalXhrOpen=null;this.originalXhrSend=null;}setup(){this.patchFetch(),this.patchXHR();}patchFetch(){this.originalFetch=window.fetch;let e=this.eventBus,t=this.originalFetch;window.fetch=function(o,n){let i=n?.method?.toUpperCase()||"GET",s=typeof o=="string"?o:o instanceof URL?o.href:o.url,l=performance.now();return t.call(window,o,n).then(a=>{let p=Math.round(performance.now()-l);if(a.status>=400){let u={kind:"network",method:i,url:s,status:a.status,statusText:a.statusText,duration:p};e.emit("network:captured",u);}return e.emit("breadcrumb:added",{category:"network",message:`${i} ${s} -> ${a.status}`}),a},a=>{let p=Math.round(performance.now()-l),u={kind:"network",method:i,url:s,status:0,statusText:a.message||"Network Error",duration:p};throw e.emit("network:captured",u),a})};}patchXHR(){this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let e=this.eventBus,t=this.originalXhrOpen,o=this.originalXhrSend;XMLHttpRequest.prototype.open=function(n,i,...s){return this.__ghostbug_method=n.toUpperCase(),this.__ghostbug_url=String(i),t.apply(this,[n,i,...s])},XMLHttpRequest.prototype.send=function(n){let i=performance.now(),s=this;return s.addEventListener("loadend",function(){let l=Math.round(performance.now()-i),a=s.__ghostbug_method||"UNKNOWN",p=s.__ghostbug_url||"";if(s.status>=400||s.status===0){let u={kind:"network",method:a,url:p,status:s.status,statusText:s.statusText,duration:l};e.emit("network:captured",u);}e.emit("breadcrumb:added",{category:"network",message:`${a} ${p} -> ${s.status}`});}),o.call(this,n)};}teardown(){this.originalFetch&&(window.fetch=this.originalFetch,this.originalFetch=null),this.originalXhrOpen&&(XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=null),this.originalXhrSend&&(XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=null);}};function F(r){if(r.id)return `#${r.id}`;let e=r.getAttribute("data-testid");if(e)return `[data-testid="${e}"]`;let t=[],o=r,n=0;for(;o&&o!==document.documentElement&&n<5;){let i=o.tagName.toLowerCase();if(o.id){t.unshift(`#${o.id}`);break}let s=Array.from(o.classList).slice(0,2);s.length>0&&(i+="."+s.join("."));let l=o.parentElement;if(l){let a=o.tagName,p=Array.from(l.children).filter(u=>u.tagName===a);if(p.length>1){let u=p.indexOf(o)+1;i+=`:nth-child(${u})`;}}t.unshift(i),o=l,n++;}return t.join(" > ")}var k=class{constructor(e,t){this.eventBus=e;this.name="click";this.handler=null;this.clicks=new m(t);}setup(){this.handler=e=>{let t=e.target;if(!t)return;let o={timestamp:new Date().toISOString(),selector:F(t),tagName:t.tagName.toLowerCase(),text:(t.textContent||"").trim().slice(0,100),position:{x:e.clientX,y:e.clientY}};this.clicks.push(o),this.eventBus.emit("click:captured",o),this.eventBus.emit("breadcrumb:added",{category:"click",message:`Clicked ${o.tagName} "${o.text}"`,data:{selector:o.selector}});},document.addEventListener("click",this.handler,true);}getClickTrail(){return this.clicks.toArray()}teardown(){this.handler&&(document.removeEventListener("click",this.handler,true),this.handler=null),this.clicks.clear();}};var C=class{constructor(e){this.getMeta=e;this.name="context";}setup(){}teardown(){}snapshot(){let e=this.getMeta?.();return {url:window.location.href,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},devicePixelRatio:window.devicePixelRatio||1,timestamp:new Date().toISOString(),memory:performance.memory?{usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize}:void 0,user:e?.user,tags:e?.tags}}};var S=class{constructor(e){this.eventBus=e;this.name="interactions";this.handlers=[];this.scrollTimer=null;this.resizeTimer=null;}setup(){this.addHandler(window,"scroll",this.onScroll.bind(this),{passive:true,capture:true}),this.addHandler(document,"input",this.onInput.bind(this),true),this.addHandler(document,"change",this.onChange.bind(this),true),this.addHandler(window,"popstate",this.onPopState.bind(this)),this.addHandler(window,"hashchange",this.onHashChange.bind(this)),this.addHandler(document,"visibilitychange",this.onVisibilityChange.bind(this)),this.addHandler(window,"resize",this.onResize.bind(this),{passive:true});}addHandler(e,t,o,n){e.addEventListener(t,o,n),this.handlers.push({target:e,event:t,handler:o});}onScroll(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Scrolled",data:{x:window.scrollX,y:window.scrollY}});},300);}onInput(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"",i=t.type?`[type="${t.type}"]`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Input on ${o}${n}${i}`});}onChange(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Change on ${o}${n}`});}onPopState(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Navigated to ${window.location.href}`});}onHashChange(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Hash changed to ${window.location.hash}`});}onVisibilityChange(){this.eventBus.emit("breadcrumb:added",{category:"visibility",message:document.hidden?"Tab hidden":"Tab visible"});}onResize(){this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Window resized",data:{width:window.innerWidth,height:window.innerHeight}});},300);}teardown(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.resizeTimer&&clearTimeout(this.resizeTimer),this.handlers.forEach(({target:e,event:t,handler:o})=>{e.removeEventListener(t,o);}),this.handlers=[];}};var B=class{constructor(e){this.eventBus=e;this.name="performance";this.observers=[];}setup(){typeof PerformanceObserver>"u"||(this.observe("longtask",e=>{e.forEach(t=>{if(t.duration<50)return;let o={kind:"performance",metric:"longtask",value:Math.round(t.duration),entries:[{name:t.name,duration:t.duration,startTime:t.startTime}]};this.eventBus.emit("performance:captured",o),this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Long task: ${Math.round(t.duration)}ms`});});}),this.observe("largest-contentful-paint",e=>{let t=e[e.length-1];t&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`LCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});}),this.observe("paint",e=>{e.forEach(t=>{t.name==="first-contentful-paint"&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`FCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});});}),this.observe("layout-shift",e=>{e.forEach(t=>{let o=t.value;o>.1&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Layout shift: ${o.toFixed(4)}`,data:{cls:o}});});}));}observe(e,t){try{let o=new PerformanceObserver(n=>{t(n.getEntries());});o.observe({type:e,buffered:!0}),this.observers.push(o);}catch{}}teardown(){this.observers.forEach(e=>e.disconnect()),this.observers=[];}};function j(){let r=performance.memory;return !r||typeof r.usedJSHeapSize!="number"?null:r}var R=class{constructor(e){this.eventBus=e;this.name="memory";this.intervalId=null;this.baselineUsed=null;}setup(){let e=j();e&&(this.baselineUsed=e.usedJSHeapSize,this.intervalId=setInterval(()=>{let t=j();if(!t)return;let o=t.usedJSHeapSize/t.jsHeapSizeLimit,n=this.baselineUsed>0?(t.usedJSHeapSize-this.baselineUsed)/this.baselineUsed:0;this.eventBus.emit("breadcrumb:added",{category:"memory",message:`Heap: ${(o*100).toFixed(1)}% used (${(t.usedJSHeapSize/1048576).toFixed(1)}MB)`,data:{usedJSHeapSize:t.usedJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit}});let i=o>=.9,s=n>=.5;if(i||s){let a={kind:"memory",message:i?`Heap usage critical: ${(o*100).toFixed(1)}% of limit`:`Heap growth spike: ${(n*100).toFixed(1)}% since init`,usedJSHeapSize:t.usedJSHeapSize,totalJSHeapSize:t.totalJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit,heapUsagePercent:o,heapGrowthPercent:n};this.eventBus.emit("memory:captured",a);}},1e4));}teardown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.baselineUsed=null;}};var U=` | ||
| var b="0.1.0",I={maxReports:50,maxBreadcrumbs:20,maxClicks:20,widget:false,collectors:{errors:true,console:true,network:true,clicks:true,interactions:true,performance:true,memory:true},rateLimit:{maxEvents:10,windowMs:1e3},beforeReport:r=>r,debug:false};var v=class{constructor(){this.listeners=new Map;}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t);}emit(e,t){this.listeners.get(e)?.forEach(o=>{try{o(t);}catch{}});}clear(){this.listeners.clear();}};var m=class{constructor(e){this.capacity=e;this.head=0;this._size=0;this.buffer=new Array(e);}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this._size<this.capacity&&this._size++;}toArray(){if(this._size===0)return [];let e=[],t=this._size<this.capacity?0:this.head;for(let o=0;o<this._size;o++){let n=(t+o)%this.capacity;e.push(this.buffer[n]);}return e}get size(){return this._size}get isFull(){return this._size===this.capacity}peek(){if(this._size===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}find(e){return this.toArray().find(e)}forEach(e){this.toArray().forEach(e);}clear(){this.buffer=new Array(this.capacity),this.head=0,this._size=0;}};var y=class{constructor(e,t){this.maxEvents=e;this.windowMs=t;this.timestamps=[];}allow(){let e=Date.now();return this.timestamps=this.timestamps.filter(t=>e-t<this.windowMs),this.timestamps.length>=this.maxEvents?false:(this.timestamps.push(e),true)}reset(){this.timestamps=[];}};function X(r){let e=5381;for(let t=0;t<r.length;t++)e=(e<<5)+e+r.charCodeAt(t)&4294967295;return (e>>>0).toString(36)}function A(r){let e;switch(r.kind){case "error":{let t=r.stack?.split(` | ||
| `)[1]?.trim()||"";e=`${r.name}:${r.message}:${t}`;break}case "console":e=`console:${r.level}:${r.args.join(",")}`;break;case "network":e=`network:${r.method}:${r.url}:${r.status}`;break;case "performance":e=`performance:${r.metric}:${Math.floor(r.value/100)*100}`;break;case "memory":e=`memory:${Math.floor(r.heapUsagePercent*10)/10}`;break}return X(e)}function j(){let r=new Uint8Array(8);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(36).padStart(2,"0")).join("").slice(0,12)}var w=class{constructor(e,t,o){this.eventBus=e;this.contextCollector=t;this.options=o;this.unsubscribers=[];this.reports=new m(o.maxReports),this.breadcrumbs=new m(o.maxBreadcrumbs),this.rateLimiter=new y(o.rateLimit.maxEvents,o.rateLimit.windowMs),this.subscribe();}subscribe(){this.unsubscribers.push(this.eventBus.on("error:captured",e=>{this.addBreadcrumb({category:"error",message:e.message}),this.handleCapturedEvent("error",e);}),this.eventBus.on("console:captured",e=>{this.addBreadcrumb({category:"console",message:`console.${e.level}: ${e.args.join(", ")}`}),e.level==="error"&&this.handleCapturedEvent("console",e);}),this.eventBus.on("network:captured",e=>{this.handleCapturedEvent("network",e);}),this.eventBus.on("performance:captured",e=>{this.addBreadcrumb({category:"performance",message:`${e.metric}: ${e.value}ms`}),this.handleCapturedEvent("performance",e);}),this.eventBus.on("memory:captured",e=>{this.handleCapturedEvent("memory",e);}),this.eventBus.on("breadcrumb:added",e=>{this.addBreadcrumb(e);}));}async handleCapturedEvent(e,t){if(!this.rateLimiter.allow())return;let o=A(t),n=this.reports.find(l=>l.fingerprint===o);if(n){n.count++,n.timestamp=new Date().toISOString(),this.eventBus.emit("report:deduplicated",n);return}let i={id:j(),fingerprint:o,type:e,timestamp:new Date().toISOString(),count:1,payload:t,breadcrumbs:this.breadcrumbs.toArray(),context:this.contextCollector.snapshot()},a=this.options.beforeReport(i);a&&(i=a,this.reports.push(i),this.eventBus.emit("report:created",i));}addBreadcrumb(e){this.breadcrumbs.push({...e,timestamp:new Date().toISOString()});}getReports(){return this.reports.toArray()}clear(){this.reports.clear(),this.breadcrumbs.clear(),this.unsubscribers.forEach(e=>e()),this.unsubscribers=[];}get reportCount(){return this.reports.size}};var x=class{constructor(e){this.eventBus=e;this.name="error";this.originalOnError=null;this.rejectionHandler=null;}setup(){this.originalOnError=window.onerror,window.onerror=(e,t,o,n,i)=>{let a={kind:"error",message:String(e),stack:i?.stack,filename:t??void 0,lineno:o??void 0,colno:n??void 0,name:i?.name};return this.eventBus.emit("error:captured",a),this.originalOnError?this.originalOnError.call(window,e,t,o,n,i):false},this.rejectionHandler=e=>{let t=e.reason,o={kind:"error",message:t instanceof Error?t.message:String(t),stack:t instanceof Error?t.stack:void 0,name:t instanceof Error?t.name:"UnhandledRejection"};this.eventBus.emit("error:captured",o);},window.addEventListener("unhandledrejection",this.rejectionHandler);}teardown(){window.onerror=this.originalOnError,this.originalOnError=null,this.rejectionHandler&&(window.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null);}};function f(r,e){let t=new WeakSet;return JSON.stringify(r,(o,n)=>{if(typeof n=="object"&&n!==null){if(t.has(n))return "[Circular]";t.add(n);}return typeof n=="function"?"[Function]":typeof n=="symbol"?n.toString():n instanceof Error?{name:n.name,message:n.message,stack:n.stack}:n},e)}var E=class{constructor(e){this.eventBus=e;this.name="console";this.originalError=null;this.originalWarn=null;}setup(){this.originalError=console.error,this.originalWarn=console.warn,console.error=(...e)=>{let t={kind:"console",level:"error",args:e.map(o=>f(o))};this.eventBus.emit("console:captured",t),this.originalError.apply(console,e);},console.warn=(...e)=>{let t={kind:"console",level:"warn",args:e.map(o=>f(o))};this.eventBus.emit("console:captured",t),this.originalWarn.apply(console,e);};}teardown(){this.originalError&&(console.error=this.originalError),this.originalWarn&&(console.warn=this.originalWarn),this.originalError=null,this.originalWarn=null;}};var k=class{constructor(e){this.eventBus=e;this.name="network";this.originalFetch=null;this.originalXhrOpen=null;this.originalXhrSend=null;}setup(){this.patchFetch(),this.patchXHR();}patchFetch(){this.originalFetch=window.fetch;let e=this.eventBus,t=this.originalFetch;window.fetch=function(o,n){let i=n?.method?.toUpperCase()||"GET",a=typeof o=="string"?o:o instanceof URL?o.href:o.url,l=performance.now();return t.call(window,o,n).then(s=>{let p=Math.round(performance.now()-l);if(s.status>=400){let u={kind:"network",method:i,url:a,status:s.status,statusText:s.statusText,duration:p};e.emit("network:captured",u);}return e.emit("breadcrumb:added",{category:"network",message:`${i} ${a} -> ${s.status}`}),s},s=>{let p=Math.round(performance.now()-l),u={kind:"network",method:i,url:a,status:0,statusText:s.message||"Network Error",duration:p};throw e.emit("network:captured",u),s})};}patchXHR(){this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let e=this.eventBus,t=this.originalXhrOpen,o=this.originalXhrSend;XMLHttpRequest.prototype.open=function(n,i,...a){return this.__ghostbug_method=n.toUpperCase(),this.__ghostbug_url=String(i),t.apply(this,[n,i,...a])},XMLHttpRequest.prototype.send=function(n){let i=performance.now(),a=this;return a.addEventListener("loadend",function(){let l=Math.round(performance.now()-i),s=a.__ghostbug_method||"UNKNOWN",p=a.__ghostbug_url||"";if(a.status>=400||a.status===0){let u={kind:"network",method:s,url:p,status:a.status,statusText:a.statusText,duration:l};e.emit("network:captured",u);}e.emit("breadcrumb:added",{category:"network",message:`${s} ${p} -> ${a.status}`});}),o.call(this,n)};}teardown(){this.originalFetch&&(window.fetch=this.originalFetch,this.originalFetch=null),this.originalXhrOpen&&(XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=null),this.originalXhrSend&&(XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=null);}};function U(r){if(r.id)return `#${r.id}`;let e=r.getAttribute("data-testid");if(e)return `[data-testid="${e}"]`;let t=[],o=r,n=0;for(;o&&o!==document.documentElement&&n<5;){let i=o.tagName.toLowerCase();if(o.id){t.unshift(`#${o.id}`);break}let a=Array.from(o.classList).slice(0,2);a.length>0&&(i+="."+a.join("."));let l=o.parentElement;if(l){let s=o.tagName,p=Array.from(l.children).filter(u=>u.tagName===s);if(p.length>1){let u=p.indexOf(o)+1;i+=`:nth-child(${u})`;}}t.unshift(i),o=l,n++;}return t.join(" > ")}var C=class{constructor(e,t){this.eventBus=e;this.name="click";this.handler=null;this.clicks=new m(t);}setup(){this.handler=e=>{let t=e.target;if(!t)return;let o={timestamp:new Date().toISOString(),selector:U(t),tagName:t.tagName.toLowerCase(),text:(t.textContent||"").trim().slice(0,100),position:{x:e.clientX,y:e.clientY}};this.clicks.push(o),this.eventBus.emit("click:captured",o),this.eventBus.emit("breadcrumb:added",{category:"click",message:`Clicked ${o.tagName} "${o.text}"`,data:{selector:o.selector}});},document.addEventListener("click",this.handler,true);}getClickTrail(){return this.clicks.toArray()}teardown(){this.handler&&(document.removeEventListener("click",this.handler,true),this.handler=null),this.clicks.clear();}};var S=class{constructor(e){this.getMeta=e;this.name="context";}setup(){}teardown(){}snapshot(){let e=this.getMeta?.();return {url:window.location.href,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},devicePixelRatio:window.devicePixelRatio||1,timestamp:new Date().toISOString(),memory:performance.memory?{usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize}:void 0,user:e?.user,tags:e?.tags}}};var B=class{constructor(e){this.eventBus=e;this.name="interactions";this.handlers=[];this.scrollTimer=null;this.resizeTimer=null;}setup(){this.addHandler(window,"scroll",this.onScroll.bind(this),{passive:true,capture:true}),this.addHandler(document,"input",this.onInput.bind(this),true),this.addHandler(document,"change",this.onChange.bind(this),true),this.addHandler(window,"popstate",this.onPopState.bind(this)),this.addHandler(window,"hashchange",this.onHashChange.bind(this)),this.addHandler(document,"visibilitychange",this.onVisibilityChange.bind(this)),this.addHandler(window,"resize",this.onResize.bind(this),{passive:true});}addHandler(e,t,o,n){e.addEventListener(t,o,n),this.handlers.push({target:e,event:t,handler:o});}onScroll(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Scrolled",data:{x:window.scrollX,y:window.scrollY}});},300);}onInput(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"",i=t.type?`[type="${t.type}"]`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Input on ${o}${n}${i}`});}onChange(e){let t=e.target;if(!t)return;let o=t.tagName.toLowerCase(),n=t.id?`#${t.id}`:"";this.eventBus.emit("breadcrumb:added",{category:"interaction",message:`Change on ${o}${n}`});}onPopState(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Navigated to ${window.location.href}`});}onHashChange(){this.eventBus.emit("breadcrumb:added",{category:"navigation",message:`Hash changed to ${window.location.hash}`});}onVisibilityChange(){this.eventBus.emit("breadcrumb:added",{category:"visibility",message:document.hidden?"Tab hidden":"Tab visible"});}onResize(){this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.eventBus.emit("breadcrumb:added",{category:"interaction",message:"Window resized",data:{width:window.innerWidth,height:window.innerHeight}});},300);}teardown(){this.scrollTimer&&clearTimeout(this.scrollTimer),this.resizeTimer&&clearTimeout(this.resizeTimer),this.handlers.forEach(({target:e,event:t,handler:o})=>{e.removeEventListener(t,o);}),this.handlers=[];}};var R=class{constructor(e){this.eventBus=e;this.name="performance";this.observers=[];}setup(){typeof PerformanceObserver>"u"||(this.observe("longtask",e=>{e.forEach(t=>{if(t.duration<50)return;let o={kind:"performance",metric:"longtask",value:Math.round(t.duration),entries:[{name:t.name,duration:t.duration,startTime:t.startTime}]};this.eventBus.emit("performance:captured",o),this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Long task: ${Math.round(t.duration)}ms`});});}),this.observe("largest-contentful-paint",e=>{let t=e[e.length-1];t&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`LCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});}),this.observe("paint",e=>{e.forEach(t=>{t.name==="first-contentful-paint"&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`FCP: ${Math.round(t.startTime)}ms`,data:{value:t.startTime}});});}),this.observe("layout-shift",e=>{e.forEach(t=>{let o=t.value;o>.1&&this.eventBus.emit("breadcrumb:added",{category:"performance",message:`Layout shift: ${o.toFixed(4)}`,data:{cls:o}});});}));}observe(e,t){try{let o=new PerformanceObserver(n=>{t(n.getEntries());});o.observe({type:e,buffered:!0}),this.observers.push(o);}catch{}}teardown(){this.observers.forEach(e=>e.disconnect()),this.observers=[];}};function F(){let r=performance.memory;return !r||typeof r.usedJSHeapSize!="number"?null:r}var T=class{constructor(e){this.eventBus=e;this.name="memory";this.intervalId=null;this.baselineUsed=null;}setup(){let e=F();e&&(this.baselineUsed=e.usedJSHeapSize,this.intervalId=setInterval(()=>{let t=F();if(!t)return;let o=t.usedJSHeapSize/t.jsHeapSizeLimit,n=this.baselineUsed>0?(t.usedJSHeapSize-this.baselineUsed)/this.baselineUsed:0;this.eventBus.emit("breadcrumb:added",{category:"memory",message:`Heap: ${(o*100).toFixed(1)}% used (${(t.usedJSHeapSize/1048576).toFixed(1)}MB)`,data:{usedJSHeapSize:t.usedJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit}});let i=o>=.9,a=n>=.5;if(i||a){let s={kind:"memory",message:i?`Heap usage critical: ${(o*100).toFixed(1)}% of limit`:`Heap growth spike: ${(n*100).toFixed(1)}% since init`,usedJSHeapSize:t.usedJSHeapSize,totalJSHeapSize:t.totalJSHeapSize,jsHeapSizeLimit:t.jsHeapSizeLimit,heapUsagePercent:o,heapGrowthPercent:n};this.eventBus.emit("memory:captured",s);}},1e4));}teardown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.baselineUsed=null;}};var D=` | ||
| :host { | ||
@@ -165,16 +165,63 @@ all: initial; | ||
| .gb-report-item { | ||
| padding: 10px 16px; | ||
| border-bottom: 1px solid #f0f0f0; | ||
| cursor: pointer; | ||
| transition: background 0.15s; | ||
| } | ||
| .gb-report-item:hover { | ||
| .gb-report-item:last-child { | ||
| border-bottom: none; | ||
| } | ||
| .gb-report-summary { | ||
| padding: 10px 16px; | ||
| cursor: pointer; | ||
| } | ||
| .gb-report-summary:hover { | ||
| background: #f8f9fa; | ||
| } | ||
| .gb-report-item:last-child { | ||
| border-bottom: none; | ||
| .gb-report-detail { | ||
| display: none; | ||
| padding: 0 16px 12px; | ||
| border-top: 1px dashed #e8e8e8; | ||
| } | ||
| .gb-report-item.gb-expanded .gb-report-detail { | ||
| display: block; | ||
| } | ||
| .gb-detail-section { | ||
| margin-top: 8px; | ||
| } | ||
| .gb-detail-label { | ||
| font-size: 10px; | ||
| font-weight: 700; | ||
| text-transform: uppercase; | ||
| letter-spacing: 0.5px; | ||
| color: #999; | ||
| margin-bottom: 2px; | ||
| } | ||
| .gb-detail-value { | ||
| font-size: 12px; | ||
| color: #555; | ||
| word-break: break-word; | ||
| line-height: 1.4; | ||
| } | ||
| .gb-detail-pre { | ||
| font-size: 11px; | ||
| font-family: 'SF Mono', Menlo, Monaco, monospace; | ||
| background: #f5f5f5; | ||
| padding: 8px; | ||
| border-radius: 6px; | ||
| overflow-x: auto; | ||
| max-height: 120px; | ||
| overflow-y: auto; | ||
| color: #333; | ||
| white-space: pre-wrap; | ||
| word-break: break-word; | ||
| } | ||
| .gb-report-type { | ||
@@ -257,4 +304,5 @@ display: inline-block; | ||
| } | ||
| `;var J='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></svg>';function D(){let r=document.createElement("button");r.className="gb-fab",r.setAttribute("aria-label","ghostbug - bug reports");let e=document.createElement("span");e.innerHTML=J,r.appendChild(e);let t=document.createElement("span");return t.className="gb-badge",t.setAttribute("data-count","0"),t.textContent="0",r.appendChild(t),r}function G(r){let e=document.createElement("div");e.className=`gb-panel gb-pos-${r}`;let t=document.createElement("div");t.className="gb-header";let o=document.createElement("span");o.className="gb-header-title",o.textContent="ghostbug",t.appendChild(o);let n=document.createElement("button");n.className="gb-header-btn gb-copy-btn",n.textContent="Copy MD",t.appendChild(n);let i=document.createElement("button");i.className="gb-header-btn gb-download-btn",i.textContent="Export",t.appendChild(i);let s=document.createElement("button");s.className="gb-close-btn",s.textContent="\xD7",s.setAttribute("aria-label","Close"),t.appendChild(s),e.appendChild(t);let l=document.createElement("div");l.className="gb-report-list";let a=document.createElement("div");return a.className="gb-empty",a.textContent="No bugs captured yet.",l.appendChild(a),e.appendChild(l),e}function X(r){let e=document.createElement("div");e.className="gb-report-item";let t=document.createElement("span");if(t.className=`gb-report-type gb-type-${r.payload.kind==="error"?"error":r.payload.kind}`,t.textContent=r.type,e.appendChild(t),r.count>1){let s=document.createElement("span");s.className="gb-report-count",s.textContent=`\xD7${r.count}`,e.appendChild(s);}let o=document.createElement("div");o.className="gb-report-message",o.textContent=V(r),e.appendChild(o);let n=document.createElement("div");n.className="gb-report-meta";let i=r.timestamp.split("T")[1]?.split(".")[0]||r.timestamp;return n.textContent=`${i} \xB7 ${r.context.url}`,e.appendChild(n),e}function V(r){switch(r.payload.kind){case "error":return r.payload.message;case "console":return r.payload.args.join(", ");case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `${r.payload.metric}: ${r.payload.value}ms`;case "memory":return r.payload.message}}function T(r){return g({generator:"ghostbug",version:f,exportedAt:new Date().toISOString(),reportCount:r.length,reports:r},2)}function L(r){let e=[];return e.push(`# Bug Report \u2014 ghostbug v${f}`),e.push(`**Generated:** ${new Date().toISOString()}`),e.push(`**Reports:** ${r.length}`),e.push(""),e.push("---"),e.push(""),r.forEach((t,o)=>{e.push(`## ${o+1}. ${Y(t)}`),e.push(""),e.push(`- **Type:** ${t.type}`),e.push(`- **Time:** ${t.timestamp}`),e.push(`- **Occurrences:** ${t.count}`),e.push(`- **URL:** ${t.context.url}`),e.push(`- **Browser:** ${Q(t.context.userAgent)}`),e.push(`- **Viewport:** ${t.context.viewport.width}x${t.context.viewport.height}`),e.push(""),e.push(...K(t.payload)),e.push(""),t.breadcrumbs.length>0&&(e.push("### Breadcrumbs"),e.push(""),e.push("| Time | Category | Event |"),e.push("|------|----------|-------|"),t.breadcrumbs.forEach(n=>{let i=n.timestamp.split("T")[1]?.split(".")[0]||n.timestamp;e.push(`| ${i} | ${n.category} | ${n.message} |`);}),e.push("")),e.push("---"),e.push("");}),e.join(` | ||
| `)}function Y(r){switch(r.payload.kind){case "error":return `${r.payload.name||"Error"}: ${r.payload.message}`;case "console":return `Console ${r.payload.level}: ${r.payload.args[0]||""}`;case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `Performance: ${r.payload.metric} ${r.payload.value}ms`;case "memory":return `Memory: ${r.payload.message}`}}function K(r){let e=[];switch(r.kind){case "error":r.stack&&(e.push("### Stack Trace"),e.push(""),e.push("```"),e.push(r.stack),e.push("```")),r.filename&&e.push(`**File:** ${r.filename}:${r.lineno}:${r.colno}`);break;case "console":e.push("### Console Output"),e.push(""),e.push("```"),r.args.forEach(t=>e.push(t)),e.push("```");break;case "network":e.push("### Network Details"),e.push(""),e.push(`- **Method:** ${r.method}`),e.push(`- **URL:** ${r.url}`),e.push(`- **Status:** ${r.status} ${r.statusText}`),e.push(`- **Duration:** ${r.duration}ms`);break;case "performance":e.push("### Performance Details"),e.push(""),e.push(`- **Metric:** ${r.metric}`),e.push(`- **Value:** ${r.value}ms`),r.entries.length>0&&e.push(`- **Start Time:** ${Math.round(r.entries[0].startTime)}ms`);break;case "memory":e.push("### Memory Details"),e.push(""),e.push(`- **Used:** ${(r.usedJSHeapSize/1048576).toFixed(1)}MB`),e.push(`- **Limit:** ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB`),e.push(`- **Usage:** ${(r.heapUsagePercent*100).toFixed(1)}%`),e.push(`- **Growth since init:** ${(r.heapGrowthPercent*100).toFixed(1)}%`);break}return e}function Q(r){if(r.includes("Chrome")){let e=r.match(/Chrome\/(\d+)/);return e?`Chrome ${e[1]}`:"Chrome"}if(r.includes("Firefox")){let e=r.match(/Firefox\/(\d+)/);return e?`Firefox ${e[1]}`:"Firefox"}if(r.includes("Safari")&&!r.includes("Chrome")){let e=r.match(/Version\/(\d+)/);return e?`Safari ${e[1]}`:"Safari"}return r.slice(0,50)}var P=class{constructor(e,t,o){this.eventBus=e;this.reportManager=t;this.options=o;this.hostElement=null;this.shadowRoot=null;this.panel=null;this.badge=null;this.reportList=null;this.isExpanded=false;this.unsubscribers=[];}mount(){this.hostElement=document.createElement("div"),this.hostElement.id="ghostbug-widget";let e=this.hostElement.style;e.position="fixed",e.zIndex=String(this.options.zIndex),e.margin="0",e.padding="0",this.applyPosition(e),this.shadowRoot=this.hostElement.attachShadow({mode:"closed"});let t=document.createElement("style");t.textContent=U,this.shadowRoot.appendChild(t);let o=document.createElement("div");o.className="gb-container";let n=D();this.badge=n.querySelector(".gb-badge"),n.addEventListener("click",()=>this.toggle()),o.appendChild(n),this.panel=G(this.options.position),o.appendChild(this.panel),this.panel.querySelector(".gb-close-btn")?.addEventListener("click",()=>this.toggle()),this.panel.querySelector(".gb-copy-btn")?.addEventListener("click",()=>this.copyMarkdown()),this.panel.querySelector(".gb-download-btn")?.addEventListener("click",()=>this.downloadJSON()),this.reportList=this.panel.querySelector(".gb-report-list"),this.shadowRoot.appendChild(o),document.body.appendChild(this.hostElement),this.unsubscribers.push(this.eventBus.on("report:created",()=>this.update()),this.eventBus.on("report:deduplicated",()=>this.update())),this.options.collapsed||this.toggle();}applyPosition(e){let t=this.options.position;e.top=t.startsWith("top")?"16px":"auto",e.bottom=t.startsWith("bottom")?"16px":"auto",e.left=t.endsWith("left")?"16px":"auto",e.right=t.endsWith("right")?"16px":"auto";}toggle(){this.isExpanded=!this.isExpanded,this.isExpanded?(this.panel?.classList.add("gb-open"),this.renderReportList()):this.panel?.classList.remove("gb-open");}update(){this.updateBadge(),this.isExpanded&&this.renderReportList();}updateBadge(){if(!this.badge)return;let e=this.reportManager.reportCount;this.badge.textContent=String(e),this.badge.setAttribute("data-count",String(e));}renderReportList(){if(!this.reportList)return;this.reportList.textContent="";let e=this.reportManager.getReports();if(e.length===0){let o=document.createElement("div");o.className="gb-empty",o.textContent="No bugs captured yet.",this.reportList.appendChild(o);return}[...e].reverse().forEach(o=>{let n=X(o);this.reportList.appendChild(n);});}copyMarkdown(){let e=L(this.reportManager.getReports());navigator.clipboard.writeText(e).then(()=>this.showToast("Copied to clipboard!"),()=>this.showToast("Copy failed"));}downloadJSON(){let e=T(this.reportManager.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download="ghostbug-report.json",n.click(),URL.revokeObjectURL(o);}showToast(e){if(!this.shadowRoot)return;let t=document.createElement("div");t.className="gb-toast",t.textContent=e,this.shadowRoot.appendChild(t),requestAnimationFrame(()=>{t.classList.add("gb-show");}),setTimeout(()=>{t.classList.remove("gb-show"),setTimeout(()=>t.remove(),300);},2e3);}unmount(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.hostElement?.remove(),this.hostElement=null,this.shadowRoot=null,this.panel=null,this.badge=null,this.reportList=null;}};var c=null,h=null,d=[],H=null,$=new Set,M=false,z,O;function Z(r,e){return e?{maxReports:e.maxReports??r.maxReports,maxBreadcrumbs:e.maxBreadcrumbs??r.maxBreadcrumbs,maxClicks:e.maxClicks??r.maxClicks,widget:e.widget??r.widget,collectors:{...r.collectors,...e.collectors},rateLimit:{...r.rateLimit,...e.rateLimit},beforeReport:e.beforeReport??r.beforeReport,debug:e.debug??r.debug,screenshotFn:e.screenshotFn}:{...r}}function ee(r){if(M){r?.debug&&console.warn("[ghostbug] Already initialized. Call destroy() first.");return}let e=Z(_,r);c=new b;let t=new C(()=>({user:z,tags:O}));if(h=new y(c,t,e),e.collectors.errors&&d.push(new w(c)),e.collectors.console&&d.push(new x(c)),e.collectors.network&&d.push(new E(c)),e.collectors.clicks&&d.push(new k(c,e.maxClicks)),e.collectors.interactions&&d.push(new S(c)),e.collectors.performance&&d.push(new B(c)),e.collectors.memory&&d.push(new R(c)),d.push(t),d.forEach(o=>o.setup()),c.on("report:created",o=>{$.forEach(n=>{try{n(o);}catch{}});}),e.widget){let o=typeof e.widget=="object"?{position:e.widget.position||"bottom-right",collapsed:e.widget.collapsed??true,zIndex:e.widget.zIndex??2147483647}:{position:"bottom-right",collapsed:true,zIndex:2147483647};H=new P(c,h,o),H.mount();}M=true;}function te(){return N(),h.getReports()}function re(r="ghostbug-report.json"){N();let e=T(h.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download=r,n.click(),URL.revokeObjectURL(o);}function oe(){return N(),L(h.getReports())}function ne(r){return $.add(r),()=>$.delete(r)}function ie(r){z=r;}function se(r){O={...O,...r};}function ae(){H?.unmount(),H=null,d.forEach(r=>r.teardown()),d=[],c?.clear(),c=null,h?.clear(),h=null,$.clear(),z=void 0,O=void 0,M=false;}function N(){if(!M)throw new Error("[ghostbug] Not initialized. Call ghostbug.init() first.")}var nt={init:ee,getReports:te,download:re,toMarkdown:oe,onBug:ne,setUser:ie,setTags:se,destroy:ae};export{nt as default,ae as destroy,re as download,te as getReports,ee as init,ne as onBug,se as setTags,ie as setUser,oe as toMarkdown};//# sourceMappingURL=index.js.map | ||
| `;var W='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></svg>';function J(){let r=document.createElement("button");r.className="gb-fab",r.setAttribute("aria-label","ghostbug - bug reports");let e=document.createElement("span");e.innerHTML=W,r.appendChild(e);let t=document.createElement("span");return t.className="gb-badge",t.setAttribute("data-count","0"),t.textContent="0",r.appendChild(t),r}function G(r){let e=document.createElement("div");e.className=`gb-panel gb-pos-${r}`;let t=document.createElement("div");t.className="gb-header";let o=document.createElement("span");o.className="gb-header-title",o.textContent="ghostbug",t.appendChild(o);let n=document.createElement("button");n.className="gb-header-btn gb-copy-btn",n.textContent="Copy MD",t.appendChild(n);let i=document.createElement("button");i.className="gb-header-btn gb-download-btn",i.textContent="Export",t.appendChild(i);let a=document.createElement("button");a.className="gb-close-btn",a.textContent="\xD7",a.setAttribute("aria-label","Close"),t.appendChild(a),e.appendChild(t);let l=document.createElement("div");l.className="gb-report-list";let s=document.createElement("div");return s.className="gb-empty",s.textContent="No bugs captured yet.",l.appendChild(s),e.appendChild(l),e}function q(r){let e=document.createElement("div");e.className="gb-report-item";let t=document.createElement("div");t.className="gb-report-summary";let o=document.createElement("span");if(o.className=`gb-report-type gb-type-${r.payload.kind==="error"?"error":r.payload.kind}`,o.textContent=r.type,t.appendChild(o),r.count>1){let s=document.createElement("span");s.className="gb-report-count",s.textContent=`\xD7${r.count}`,t.appendChild(s);}let n=document.createElement("div");n.className="gb-report-message",n.textContent=Y(r),t.appendChild(n);let i=document.createElement("div");i.className="gb-report-meta";let a=r.timestamp.split("T")[1]?.split(".")[0]||r.timestamp;i.textContent=`${a} \xB7 ${r.context.url}`,t.appendChild(i),e.appendChild(t);let l=document.createElement("div");if(l.className="gb-report-detail",l.appendChild(V(r.payload)),r.context.user){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">User</div><div class="gb-detail-value">${g(JSON.stringify(r.context.user))}</div>`,l.appendChild(s);}if(r.context.tags){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">Tags</div><div class="gb-detail-value">${g(JSON.stringify(r.context.tags))}</div>`,l.appendChild(s);}if(r.breadcrumbs.length>0){let s=document.createElement("div");s.className="gb-detail-section",s.innerHTML=`<div class="gb-detail-label">Breadcrumbs</div><div class="gb-detail-value">${r.breadcrumbs.length} events</div>`,l.appendChild(s);}return e.appendChild(l),t.addEventListener("click",()=>{e.classList.toggle("gb-expanded");}),e}function g(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function V(r){let e=document.createElement("div");switch(e.className="gb-detail-section",r.kind){case "error":{if(r.stack){let t=document.createElement("div");t.className="gb-detail-label",t.textContent="Stack Trace",e.appendChild(t);let o=document.createElement("pre");o.className="gb-detail-pre",o.textContent=r.stack,e.appendChild(o);}if(r.filename){let t=document.createElement("div");t.className="gb-detail-value",t.textContent=`${r.filename}:${r.lineno}:${r.colno}`,e.appendChild(t);}break}case "console":{let t=document.createElement("div");t.className="gb-detail-label",t.textContent="Output",e.appendChild(t);let o=document.createElement("pre");o.className="gb-detail-pre",o.textContent=r.args.join(` | ||
| `),e.appendChild(o);break}case "network":{e.innerHTML=`<div class="gb-detail-label">Request</div><div class="gb-detail-value">${g(r.method)} ${g(r.url)}<br>Status: ${r.status} ${g(r.statusText)}<br>Duration: ${r.duration}ms</div>`;break}case "performance":{e.innerHTML=`<div class="gb-detail-label">Performance</div><div class="gb-detail-value">Metric: ${g(r.metric)}<br>Value: ${r.value}ms</div>`;break}case "memory":{e.innerHTML=`<div class="gb-detail-label">Memory</div><div class="gb-detail-value">Used: ${(r.usedJSHeapSize/1048576).toFixed(1)}MB<br>Limit: ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB<br>Usage: ${(r.heapUsagePercent*100).toFixed(1)}%</div>`;break}}return e}function Y(r){switch(r.payload.kind){case "error":return r.payload.message;case "console":return r.payload.args.join(", ");case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `${r.payload.metric}: ${r.payload.value}ms`;case "memory":return r.payload.message}}function L(r){return f({generator:"ghostbug",version:b,exportedAt:new Date().toISOString(),reportCount:r.length,reports:r},2)}function P(r){let e=[];return e.push(`# Bug Report \u2014 ghostbug v${b}`),e.push(`**Generated:** ${new Date().toISOString()}`),e.push(`**Reports:** ${r.length}`),e.push(""),e.push("---"),e.push(""),r.forEach((t,o)=>{e.push(`## ${o+1}. ${K(t)}`),e.push(""),e.push(`- **Type:** ${t.type}`),e.push(`- **Time:** ${t.timestamp}`),e.push(`- **Occurrences:** ${t.count}`),e.push(`- **URL:** ${t.context.url}`),e.push(`- **Browser:** ${Z(t.context.userAgent)}`),e.push(`- **Viewport:** ${t.context.viewport.width}x${t.context.viewport.height}`),e.push(""),e.push(...Q(t.payload)),e.push(""),t.context.user&&(e.push("### User Context"),e.push(""),e.push("```json"),e.push(JSON.stringify(t.context.user,null,2)),e.push("```"),e.push("")),t.context.tags&&(e.push("### Tags"),e.push(""),e.push("```json"),e.push(JSON.stringify(t.context.tags,null,2)),e.push("```"),e.push("")),t.breadcrumbs.length>0&&(e.push("### Breadcrumbs"),e.push(""),e.push("| Time | Category | Event |"),e.push("|------|----------|-------|"),t.breadcrumbs.forEach(n=>{let i=n.timestamp.split("T")[1]?.split(".")[0]||n.timestamp;e.push(`| ${i} | ${n.category} | ${n.message} |`);}),e.push("")),e.push("---"),e.push("");}),e.join(` | ||
| `)}function K(r){switch(r.payload.kind){case "error":return `${r.payload.name||"Error"}: ${r.payload.message}`;case "console":return `Console ${r.payload.level}: ${r.payload.args[0]||""}`;case "network":return `${r.payload.method} ${r.payload.url} \u2192 ${r.payload.status}`;case "performance":return `Performance: ${r.payload.metric} ${r.payload.value}ms`;case "memory":return `Memory: ${r.payload.message}`}}function Q(r){let e=[];switch(r.kind){case "error":r.stack&&(e.push("### Stack Trace"),e.push(""),e.push("```"),e.push(r.stack),e.push("```")),r.filename&&e.push(`**File:** ${r.filename}:${r.lineno}:${r.colno}`);break;case "console":e.push("### Console Output"),e.push(""),e.push("```"),r.args.forEach(t=>e.push(t)),e.push("```");break;case "network":e.push("### Network Details"),e.push(""),e.push(`- **Method:** ${r.method}`),e.push(`- **URL:** ${r.url}`),e.push(`- **Status:** ${r.status} ${r.statusText}`),e.push(`- **Duration:** ${r.duration}ms`);break;case "performance":e.push("### Performance Details"),e.push(""),e.push(`- **Metric:** ${r.metric}`),e.push(`- **Value:** ${r.value}ms`),r.entries.length>0&&e.push(`- **Start Time:** ${Math.round(r.entries[0].startTime)}ms`);break;case "memory":e.push("### Memory Details"),e.push(""),e.push(`- **Used:** ${(r.usedJSHeapSize/1048576).toFixed(1)}MB`),e.push(`- **Limit:** ${(r.jsHeapSizeLimit/1048576).toFixed(1)}MB`),e.push(`- **Usage:** ${(r.heapUsagePercent*100).toFixed(1)}%`),e.push(`- **Growth since init:** ${(r.heapGrowthPercent*100).toFixed(1)}%`);break}return e}function Z(r){if(r.includes("Chrome")){let e=r.match(/Chrome\/(\d+)/);return e?`Chrome ${e[1]}`:"Chrome"}if(r.includes("Firefox")){let e=r.match(/Firefox\/(\d+)/);return e?`Firefox ${e[1]}`:"Firefox"}if(r.includes("Safari")&&!r.includes("Chrome")){let e=r.match(/Version\/(\d+)/);return e?`Safari ${e[1]}`:"Safari"}return r.slice(0,50)}var $=class{constructor(e,t,o){this.eventBus=e;this.reportManager=t;this.options=o;this.hostElement=null;this.shadowRoot=null;this.panel=null;this.badge=null;this.reportList=null;this.isExpanded=false;this.unsubscribers=[];}mount(){this.hostElement=document.createElement("div"),this.hostElement.id="ghostbug-widget";let e=this.hostElement.style;e.position="fixed",e.zIndex=String(this.options.zIndex),e.margin="0",e.padding="0",this.applyPosition(e),this.shadowRoot=this.hostElement.attachShadow({mode:"closed"});let t=document.createElement("style");t.textContent=D,this.shadowRoot.appendChild(t);let o=document.createElement("div");o.className="gb-container";let n=J();this.badge=n.querySelector(".gb-badge"),n.addEventListener("click",()=>this.toggle()),o.appendChild(n),this.panel=G(this.options.position),o.appendChild(this.panel),this.panel.querySelector(".gb-close-btn")?.addEventListener("click",()=>this.toggle()),this.panel.querySelector(".gb-copy-btn")?.addEventListener("click",()=>this.copyMarkdown()),this.panel.querySelector(".gb-download-btn")?.addEventListener("click",()=>this.downloadJSON()),this.reportList=this.panel.querySelector(".gb-report-list"),this.shadowRoot.appendChild(o),document.body.appendChild(this.hostElement),this.unsubscribers.push(this.eventBus.on("report:created",()=>this.update()),this.eventBus.on("report:deduplicated",()=>this.update())),this.options.collapsed||this.toggle();}applyPosition(e){let t=this.options.position;e.top=t.startsWith("top")?"16px":"auto",e.bottom=t.startsWith("bottom")?"16px":"auto",e.left=t.endsWith("left")?"16px":"auto",e.right=t.endsWith("right")?"16px":"auto";}toggle(){this.isExpanded=!this.isExpanded,this.isExpanded?(this.panel?.classList.add("gb-open"),this.renderReportList()):this.panel?.classList.remove("gb-open");}update(){this.updateBadge(),this.isExpanded&&this.renderReportList();}updateBadge(){if(!this.badge)return;let e=this.reportManager.reportCount;this.badge.textContent=String(e),this.badge.setAttribute("data-count",String(e));}renderReportList(){if(!this.reportList)return;this.reportList.textContent="";let e=this.reportManager.getReports();if(e.length===0){let o=document.createElement("div");o.className="gb-empty",o.textContent="No bugs captured yet.",this.reportList.appendChild(o);return}[...e].reverse().forEach(o=>{let n=q(o);this.reportList.appendChild(n);});}copyMarkdown(){let e=P(this.reportManager.getReports());navigator.clipboard.writeText(e).then(()=>this.showToast("Copied to clipboard!"),()=>this.showToast("Copy failed"));}downloadJSON(){let e=L(this.reportManager.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download="ghostbug-report.json",n.click(),URL.revokeObjectURL(o);}showToast(e){if(!this.shadowRoot)return;let t=document.createElement("div");t.className="gb-toast",t.textContent=e,this.shadowRoot.appendChild(t),requestAnimationFrame(()=>{t.classList.add("gb-show");}),setTimeout(()=>{t.classList.remove("gb-show"),setTimeout(()=>t.remove(),300);},2e3);}unmount(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.hostElement?.remove(),this.hostElement=null,this.shadowRoot=null,this.panel=null,this.badge=null,this.reportList=null;}};var d=null,h=null,c=[],H=null,M=new Set,O=false,z,N;function ee(r,e){return e?{maxReports:e.maxReports??r.maxReports,maxBreadcrumbs:e.maxBreadcrumbs??r.maxBreadcrumbs,maxClicks:e.maxClicks??r.maxClicks,widget:e.widget??r.widget,collectors:{...r.collectors,...e.collectors},rateLimit:{...r.rateLimit,...e.rateLimit},beforeReport:e.beforeReport??r.beforeReport,debug:e.debug??r.debug}:{...r}}function te(r){if(O){r?.debug&&console.warn("[ghostbug] Already initialized. Call destroy() first.");return}let e=ee(I,r);d=new v;let t=new S(()=>({user:z,tags:N}));if(h=new w(d,t,e),e.collectors.errors&&c.push(new x(d)),e.collectors.console&&c.push(new E(d)),e.collectors.network&&c.push(new k(d)),e.collectors.clicks&&c.push(new C(d,e.maxClicks)),e.collectors.interactions&&c.push(new B(d)),e.collectors.performance&&c.push(new R(d)),e.collectors.memory&&c.push(new T(d)),c.push(t),c.forEach(o=>o.setup()),d.on("report:created",o=>{M.forEach(n=>{try{n(o);}catch{}});}),e.widget){let o=typeof e.widget=="object"?{position:e.widget.position||"bottom-right",collapsed:e.widget.collapsed??true,zIndex:e.widget.zIndex??2147483647}:{position:"bottom-right",collapsed:true,zIndex:2147483647};H=new $(d,h,o),H.mount();}O=true;}function re(){return _(),h.getReports()}function oe(r="ghostbug-report.json"){_();let e=L(h.getReports()),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t),n=document.createElement("a");n.href=o,n.download=r,n.click(),URL.revokeObjectURL(o);}function ne(){return _(),P(h.getReports())}function ie(r){return M.add(r),()=>M.delete(r)}function se(r){z=r;}function ae(r){N={...N,...r};}function le(){H?.unmount(),H=null,c.forEach(r=>r.teardown()),c=[],d?.clear(),d=null,h?.clear(),h=null,M.clear(),z=void 0,N=void 0,O=false;}function _(){if(!O)throw new Error("[ghostbug] Not initialized. Call ghostbug.init() first.")}var it={init:te,getReports:re,download:oe,toMarkdown:ne,onBug:ie,setUser:se,setTags:ae,destroy:le};export{it as default,le as destroy,oe as download,re as getReports,te as init,ie as onBug,ae as setTags,se as setUser,ne as toMarkdown};//# sourceMappingURL=index.js.map | ||
| //# sourceMappingURL=index.js.map |
+18
-8
| { | ||
| "name": "ghostbug", | ||
| "version": "0.2.0-beta.0", | ||
| "version": "0.2.0", | ||
| "description": "Zero-config automatic bug context collector SDK for the browser", | ||
@@ -14,3 +14,3 @@ "author": "Sounak Das", | ||
| }, | ||
| "homepage": "https://github.com/LittleBoy9/ghostbug#readme", | ||
| "homepage": "https://littleboy9.github.io/ghostbug/", | ||
| "type": "module", | ||
@@ -38,12 +38,22 @@ "main": "./dist/index.cjs", | ||
| "keywords": [ | ||
| "bug", | ||
| "error", | ||
| "debug", | ||
| "report", | ||
| "ghostbug", | ||
| "error-tracking", | ||
| "bug-reporter", | ||
| "browser", | ||
| "javascript", | ||
| "sdk", | ||
| "error-tracking", | ||
| "error-monitoring", | ||
| "console-capture", | ||
| "network-monitoring", | ||
| "performance-monitoring", | ||
| "memory-leak", | ||
| "click-tracking", | ||
| "breadcrumbs", | ||
| "debugging", | ||
| "developer-tools", | ||
| "ghostbug" | ||
| "sentry-alternative", | ||
| "zero-dependency", | ||
| "lightweight", | ||
| "frontend", | ||
| "qa" | ||
| ], | ||
@@ -50,0 +60,0 @@ "scripts": { |
+151
-62
@@ -1,21 +0,44 @@ | ||
| # ghostbug | ||
| <p align="center"> | ||
| <img src="https://em-content.zobj.net/source/apple/391/ghost_1f47b.png" width="80" alt="ghostbug" /> | ||
| </p> | ||
| Zero-config automatic bug context collector for the browser. Drop it in, forget about it. When something breaks, you already have everything you need. | ||
| <h1 align="center">ghostbug</h1> | ||
| [](https://www.npmjs.com/package/ghostbug) | ||
| [](https://bundlephobia.com/package/ghostbug) | ||
| [](https://github.com/sounakdas/ghostbug/blob/main/LICENSE) | ||
| <p align="center"> | ||
| <strong>Zero-config bug context collector for the browser.</strong><br /> | ||
| Drop it in, forget about it. When something breaks, you already have everything you need. | ||
| </p> | ||
| <p align="center"> | ||
| <a href="https://www.npmjs.com/package/ghostbug"><img src="https://img.shields.io/npm/v/ghostbug.svg?style=flat-square&color=10b981" alt="npm version" /></a> | ||
| <a href="https://bundlephobia.com/package/ghostbug"><img src="https://img.shields.io/bundlephobia/minzip/ghostbug?style=flat-square&color=6ee7b7&label=size" alt="bundle size" /></a> | ||
| <a href="https://github.com/LittleBoy9/ghostbug/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/ghostbug.svg?style=flat-square&color=8b5cf6" alt="license" /></a> | ||
| <img src="https://img.shields.io/badge/dependencies-0-10b981?style=flat-square" alt="zero dependencies" /> | ||
| <img src="https://img.shields.io/badge/tests-81%20passing-6ee7b7?style=flat-square" alt="tests passing" /> | ||
| </p> | ||
| <p align="center"> | ||
| <a href="https://littleboy9.github.io/ghostbug/"><strong>Website</strong></a> · | ||
| <a href="https://www.npmjs.com/package/ghostbug"><strong>npm</strong></a> · | ||
| <a href="https://github.com/LittleBoy9/ghostbug"><strong>GitHub</strong></a> | ||
| </p> | ||
| --- | ||
| ## Why ghostbug? | ||
| Testers spend 90% of their time manually collecting bug context — screenshots, error messages, console logs, steps to reproduce. ghostbug eliminates that by silently capturing everything in the background. | ||
| Testers spend 90% of their time manually collecting bug context — error messages, console logs, network failures, steps to reproduce. **ghostbug eliminates that** by silently capturing everything in the background. | ||
| | | Sentry / LogRocket | ghostbug | | ||
| | | Sentry / LogRocket | ghostbug | | ||
| |---|---|---| | ||
| | Setup | Account, API keys, config | `ghostbug.init()` | | ||
| | Server needed | Yes (paid) | No — everything local | | ||
| | Bundle size | 50-200KB+ | **~7KB gzipped** | | ||
| | Dependencies | Multiple | **Zero** | | ||
| | Output | Dashboard (another tab) | JSON / Markdown you paste into GitHub Issues | | ||
| | **Setup** | Account, API keys, config | `ghostbug.init()` | | ||
| | **Server needed** | Yes (paid SaaS) | **No** — 100% client-side | | ||
| | **Bundle size** | 50–200KB+ | **~7KB gzipped** | | ||
| | **Dependencies** | Multiple | **Zero** | | ||
| | **Data privacy** | Sent to their servers | **Stays in the browser** | | ||
| | **Output** | Dashboard (another tab) | JSON / Markdown for GitHub Issues | | ||
| | **Pricing** | Free tier / Paid | **Free forever** | | ||
| --- | ||
| ## Install | ||
@@ -27,2 +50,11 @@ | ||
| ```bash | ||
| # or | ||
| yarn add ghostbug | ||
| # or | ||
| pnpm add ghostbug | ||
| ``` | ||
| --- | ||
| ## Quick Start | ||
@@ -36,10 +68,17 @@ | ||
| That's it. ghostbug now auto-captures: | ||
| That's it. ghostbug now silently auto-captures: | ||
| - **JS errors** — `window.onerror` + unhandled promise rejections | ||
| - **Console errors** — `console.error()` and `console.warn()` | ||
| - **Failed network requests** — `fetch` and `XMLHttpRequest` (4xx/5xx) | ||
| - **User click trail** — last 20 clicks with element selectors | ||
| - **Page context** — URL, browser, viewport, timestamp | ||
| | Collector | What it catches | | ||
| |---|---| | ||
| | **Errors** | `window.onerror` + unhandled promise rejections with stack traces | | ||
| | **Console** | `console.error()` and `console.warn()` with full arguments | | ||
| | **Network** | Failed `fetch` and `XMLHttpRequest` (4xx/5xx) with timing | | ||
| | **Clicks** | Last 20 user clicks with element selectors and positions | | ||
| | **Interactions** | Form input, scroll, and resize events | | ||
| | **Performance** | Long Tasks, FCP, LCP, layout shifts via PerformanceObserver | | ||
| | **Memory** | Heap usage sampling, high usage (>90%) and rapid growth (>50%) alerts | | ||
| | **Context** | URL, browser, viewport, device pixel ratio, referrer | | ||
| --- | ||
| ## API | ||
@@ -69,10 +108,11 @@ | ||
| clicks: true, | ||
| interactions: true, | ||
| performance: true, | ||
| memory: true, | ||
| }, | ||
| // Max reports stored (oldest dropped when full) | ||
| maxReports: 50, | ||
| maxReports: 50, // Max reports stored (oldest dropped when full) | ||
| maxBreadcrumbs: 20, // Max breadcrumb trail per report | ||
| maxClicks: 20, // Max click trail entries | ||
| // Max breadcrumb trail per report | ||
| maxBreadcrumbs: 20, | ||
| // Rate limiting (prevent flood from error loops) | ||
@@ -83,6 +123,8 @@ rateLimit: { maxEvents: 10, windowMs: 1000 }, | ||
| beforeReport: (report) => { | ||
| // Return false to discard | ||
| // Return false/null to discard | ||
| // Return modified report to transform | ||
| return report; | ||
| }, | ||
| debug: false, // Enable SDK debug logging | ||
| }); | ||
@@ -97,3 +139,2 @@ ``` | ||
| const reports = ghostbug.getReports(); | ||
| console.log(reports); | ||
| ``` | ||
@@ -110,3 +151,4 @@ | ||
| Example output: | ||
| <details> | ||
| <summary><strong>Example markdown output</strong></summary> | ||
@@ -134,2 +176,4 @@ ```markdown | ||
| </details> | ||
| ### `ghostbug.download(filename?)` | ||
@@ -140,3 +184,3 @@ | ||
| ```js | ||
| ghostbug.download(); // downloads ghostbug-report.json | ||
| ghostbug.download(); // ghostbug-report.json | ||
| ghostbug.download("my-bugs.json"); // custom filename | ||
@@ -151,3 +195,3 @@ ``` | ||
| const unsubscribe = ghostbug.onBug((report) => { | ||
| // Send to Slack | ||
| // Send to Slack, your API, anywhere | ||
| fetch("/api/slack-webhook", { | ||
@@ -163,2 +207,18 @@ method: "POST", | ||
| ### `ghostbug.setUser(user)` | ||
| Attach user context to every report. | ||
| ```js | ||
| ghostbug.setUser({ id: "user-42", plan: "pro", email: "dev@example.com" }); | ||
| ``` | ||
| ### `ghostbug.setTags(tags)` | ||
| Add custom tags to every report. Merges with existing tags. | ||
| ```js | ||
| ghostbug.setTags({ environment: "staging", version: "2.1.0" }); | ||
| ``` | ||
| ### `ghostbug.destroy()` | ||
@@ -172,2 +232,4 @@ | ||
| --- | ||
| ## Framework Integration | ||
@@ -217,4 +279,19 @@ | ||
| ### Plain HTML | ||
| ### Svelte | ||
| ```svelte | ||
| <!-- +layout.svelte --> | ||
| <script> | ||
| import { onMount, onDestroy } from "svelte"; | ||
| import ghostbug from "ghostbug"; | ||
| onMount(() => ghostbug.init({ widget: true })); | ||
| onDestroy(() => ghostbug.destroy()); | ||
| </script> | ||
| <slot /> | ||
| ``` | ||
| ### Plain HTML (CDN) | ||
| ```html | ||
@@ -227,5 +304,7 @@ <script src="https://unpkg.com/ghostbug/dist/index.iife.js"></script> | ||
| --- | ||
| ## Widget | ||
| Enable the floating widget for testers — a small bug icon that shows captured bugs with copy/export buttons. | ||
| Enable the floating widget for testers: | ||
@@ -237,9 +316,11 @@ ```js | ||
| The widget: | ||
| - Shows a bug count badge | ||
| - Shows a **live bug count** badge | ||
| - Click to expand and see all captured bugs | ||
| - **Copy MD** — copies markdown to clipboard | ||
| - **Export** — downloads JSON file | ||
| - Uses Shadow DOM — styles never leak into your app | ||
| - Uses **Shadow DOM** — styles never leak into your app | ||
| - Fully isolated — your CSS won't break it | ||
| --- | ||
| ## Bug Report Structure | ||
@@ -253,12 +334,20 @@ | ||
| fingerprint: string; // Hash for deduplication | ||
| type: "error" | "console" | "network"; | ||
| type: "error" | "unhandled-rejection" | "console" | "network" | "performance" | "memory"; | ||
| timestamp: string; // ISO 8601 | ||
| count: number; // Occurrences (deduped) | ||
| payload: { ... }; // Error details | ||
| breadcrumbs: [ ... ]; // Events leading up to the bug | ||
| payload: { ... }; // Error/network/console/perf/memory details | ||
| breadcrumbs: [ // Events leading up to the bug | ||
| { timestamp, category, message, data } | ||
| ]; | ||
| context: { | ||
| url: string; | ||
| referrer: string; | ||
| userAgent: string; | ||
| language: string; | ||
| viewport: { width, height }; | ||
| // ... | ||
| screen: { width, height }; | ||
| devicePixelRatio: number; | ||
| memory?: { usedJSHeapSize, totalJSHeapSize }; | ||
| user?: { ... }; // From setUser() | ||
| tags?: { ... }; // From setTags() | ||
| }; | ||
@@ -268,37 +357,37 @@ } | ||
| --- | ||
| ## How It Works | ||
| - **Error capture** — Patches `window.onerror` and listens for `unhandledrejection` | ||
| - **Console capture** — Monkey-patches `console.error` / `console.warn` (always calls originals) | ||
| - **Network capture** — Patches `fetch` and `XMLHttpRequest` (only captures 4xx/5xx, never alters responses) | ||
| - **Click tracking** — Uses capture-phase click listener (catches clicks even with `stopPropagation`) | ||
| - **Deduplication** — Identical errors increment a counter instead of creating duplicate reports | ||
| - **Rate limiting** — Token-bucket algorithm prevents floods from error loops | ||
| - **Ring buffer** — Fixed-capacity storage prevents memory leaks in long-running apps | ||
| - **Safe teardown** — `destroy()` restores all original APIs | ||
| | Mechanism | Details | | ||
| |---|---| | ||
| | **Error capture** | Patches `window.onerror` and listens for `unhandledrejection` | | ||
| | **Console capture** | Monkey-patches `console.error` / `console.warn` (always calls originals) | | ||
| | **Network capture** | Patches `fetch` and `XMLHttpRequest` (only captures 4xx/5xx, never alters responses) | | ||
| | **Click tracking** | Uses capture-phase click listener (catches clicks even with `stopPropagation`) | | ||
| | **Interactions** | Listens for `input`, `scroll`, `resize` events as breadcrumbs | | ||
| | **Performance** | Uses `PerformanceObserver` for long-task, paint, and layout-shift entries | | ||
| | **Memory** | Samples `performance.memory` every 10s, flags high usage and rapid growth | | ||
| | **Deduplication** | Identical errors increment a counter instead of creating duplicate reports | | ||
| | **Rate limiting** | Token-bucket algorithm prevents floods from error loops | | ||
| | **Ring buffer** | Fixed-capacity storage prevents memory leaks in long-running apps | | ||
| | **Safe teardown** | `destroy()` restores all original APIs cleanly | | ||
| --- | ||
| ## Development | ||
| ```bash | ||
| # Install dependencies | ||
| npm install | ||
| npm install # Install dependencies | ||
| npm run build # Build (ESM + CJS + IIFE) | ||
| npm test # Run tests | ||
| npm run test:watch # Watch mode | ||
| npm run typecheck # TypeScript strict check | ||
| npm run lint # ESLint | ||
| ``` | ||
| # Build (ESM + CJS + IIFE) | ||
| npm run build | ||
| --- | ||
| # Run tests | ||
| npm test | ||
| # Watch mode | ||
| npm run test:watch | ||
| # Type check | ||
| npm run typecheck | ||
| # Lint | ||
| npm run lint | ||
| ``` | ||
| ## License | ||
| MIT | ||
| MIT — do whatever you want. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
437948
9.57%1254
13.18%378
30.8%