devlog-ui 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +264 -80
  2. package/dist/index.js +740 -523
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1,18 +1,18 @@
1
- "use strict";var Oe=Object.defineProperty;var Ne=(t,e,n)=>e in t?Oe(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var p=(t,e,n)=>Ne(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var Z=typeof document<"u"?document.currentScript:null;const ue={debug:0,info:1,warn:2,error:3};function w(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function A(t,e){if(t===e)return!0;if(typeof t!=typeof e)return!1;if(t===null||e===null)return t===e;if(Array.isArray(t)&&Array.isArray(e))return t.length!==e.length?!1:t.every((n,o)=>A(n,e[o]));if(w(t)&&w(e)){const n=Object.keys(t),o=Object.keys(e);return n.length!==o.length?!1:n.every(r=>A(t[r],e[r]))}return!1}function te(t){if(t===void 0)return"undefined";if(t===null)return"null";if(typeof t=="string")return`"${t}"`;if(typeof t=="number"||typeof t=="boolean")return String(t);if(Array.isArray(t))return t.length===0?"[]":t.length<=3?`[${t.map(te).join(", ")}]`:`[${t.length} items]`;if(w(t)){const e=Object.keys(t);return e.length===0?"{}":e.length<=2?`{${e.map(n=>`${n}: ${te(t[n])}`).join(", ")}}`:`{${e.length} keys}`}return String(t)}function re(t,e,n="",o=!1){const r=[];if(!w(t)&&!w(e))return A(t,e)?o&&r.push({path:n||"(root)",type:"unchanged",oldValue:t,newValue:e}):r.push({path:n||"(root)",type:"changed",oldValue:t,newValue:e}),r;if(!w(t))return r.push({path:n||"(root)",type:"changed",oldValue:t,newValue:e}),r;if(!w(e))return r.push({path:n||"(root)",type:"changed",oldValue:t,newValue:e}),r;const s=new Set([...Object.keys(t),...Object.keys(e)]);for(const a of s){const l=n?`${n}.${a}`:a,c=t[a],d=e[a],f=a in t,h=a in e;!f&&h?r.push({path:l,type:"added",newValue:d}):f&&!h?r.push({path:l,type:"removed",oldValue:c}):w(c)&&w(d)?r.push(...re(c,d,l,o)):Array.isArray(c)&&Array.isArray(d)?A(c,d)?o&&r.push({path:l,type:"unchanged",oldValue:c,newValue:d}):r.push({path:l,type:"changed",oldValue:c,newValue:d}):A(c,d)?o&&r.push({path:l,type:"unchanged",oldValue:c,newValue:d}):r.push({path:l,type:"changed",oldValue:c,newValue:d})}return r}function ne(t,e){const n=re(t,e,"",!1),o={added:0,removed:0,changed:0,unchanged:0};for(const r of n)o[r.type]++;return{changes:n,summary:o}}function ze(t){return t.summary.added>0||t.summary.removed>0||t.summary.changed>0}const Pe={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1};function qe(){try{if(typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Z&&Z.tagName.toUpperCase()==="SCRIPT"&&Z.src||new URL("index.cjs",document.baseURI).href}<"u"&&Pe)return!1;const t=globalThis.process;if(t?.env){const e=t.env.DEVLOGGER_ENABLED||t.env.REACT_APP_DEVLOGGER_ENABLED;if(e==="false"||e==="0")return!1;if(e==="true"||e==="1")return!0;if(t.env.NODE_ENV==="production")return!1}return!0}catch{return!0}}const Ue={maxLogs:1e3,persist:!1,minLevel:"debug",enabled:qe(),shortcutAction:"toggle",showToggleButton:!0,spanCollapsed:!1};function Ve(){const t="devlogger_session_id";try{const e=sessionStorage.getItem(t);if(e)return e;const n=`session_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;return sessionStorage.setItem(t,n),n}catch{return`session_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}}function je(){return`log_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}function we(){try{const t=new Error().stack;if(!t)return{file:"unknown",line:0};const e=t.split(`
2
- `);for(let n=4;n<e.length;n++){const o=e[n];if(!o||o.includes("logger.ts")||o.includes("logger.js"))continue;const r=o.match(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(r)return{function:r[1]||void 0,file:fe(r[2]||"unknown"),line:parseInt(r[3]||"0",10),column:parseInt(r[4]||"0",10)};const s=o.match(/(.+)?@(.+?):(\d+):(\d+)/);if(s)return{function:s[1]||void 0,file:fe(s[2]||"unknown"),line:parseInt(s[3]||"0",10),column:parseInt(s[4]||"0",10)}}return{file:"unknown",line:0}}catch{return{file:"unknown",line:0}}}function fe(t){let e=t.replace(/^webpack:\/\/[^/]*\//,"").replace(/^\/@fs/,"").replace(/^file:\/\//,"").replace(/\?.*$/,"");const n=e.split("/");return n.length>2&&(e=n.slice(-2).join("/")),e}function We(){return`span_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}class G{constructor(e,n,o,r){p(this,"logger");p(this,"_event");p(this,"_ended",!1);this.logger=e,this._event={id:We(),name:n,startTime:Date.now(),status:"running",parentId:r,context:o,source:we(),sessionId:e.getSessionId()},e.notifySpan(this._event)}get id(){return this._event.id}get event(){return this._event}get ended(){return this._ended}debug(e,...n){this._ended||this.logger.logWithSpan("debug",e,n,this._event.id,this._event.context)}info(e,...n){this._ended||this.logger.logWithSpan("info",e,n,this._event.id,this._event.context)}warn(e,...n){this._ended||this.logger.logWithSpan("warn",e,n,this._event.id,this._event.context)}error(e,...n){this._ended||this.logger.logWithSpan("error",e,n,this._event.id,this._event.context)}span(e,n){const o={...this._event.context,...n};return new G(this.logger,e,o,this._event.id)}end(){this.finish("success")}fail(e){e&&this.error(typeof e=="string"?e:e.message,e),this.finish("error")}finish(e){this._ended||(this._ended=!0,this._event.endTime=Date.now(),this._event.duration=this._event.endTime-this._event.startTime,this._event.status=e,this.logger.notifySpan(this._event))}}class se{constructor(e,n){p(this,"logger");p(this,"context");this.logger=e,this.context=n}debug(e,...n){this.logger.logWithContext("debug",e,n,this.context)}info(e,...n){this.logger.logWithContext("info",e,n,this.context)}warn(e,...n){this.logger.logWithContext("warn",e,n,this.context)}error(e,...n){this.logger.logWithContext("error",e,n,this.context)}span(e,n){return this.logger.span(e,{...this.context,...n})}withContext(e){return new se(this.logger,{...this.context,...e})}}class Ge{constructor(){p(this,"logs",[]);p(this,"spans",new Map);p(this,"subscribers",new Set);p(this,"spanSubscribers",new Set);p(this,"config",{...Ue});p(this,"sessionId");p(this,"globalContext",{});this.sessionId=Ve()}log(e,n,o,r,s){try{if(!this.config.enabled||ue[e]<ue[this.config.minLevel])return;const a=Object.keys(this.globalContext).length>0||r?{...this.globalContext,...r}:void 0,l={id:je(),timestamp:Date.now(),level:e,message:String(n),data:this.safeCloneData(o),source:we(),sessionId:this.sessionId,context:a,spanId:s};this.store(l),this.notify(l)}catch(a){typeof console<"u"&&console.warn&&console.warn("[DevLogger] Internal error:",a)}}logWithContext(e,n,o,r){this.log(e,n,o,r)}logWithSpan(e,n,o,r,s){this.log(e,n,o,s,r)}notifySpan(e){this.spans.set(e.id,e);for(const n of this.spanSubscribers)try{n(e)}catch{}}safeCloneData(e){return e.map(n=>this.safeClone(n))}safeClone(e,n=new WeakSet){if(e==null||typeof e!="object")return e;if(e instanceof Error)return{__type:"Error",name:e.name,message:e.message,stack:e.stack};if(e instanceof Date)return{__type:"Date",value:e.toISOString()};if(e instanceof RegExp)return{__type:"RegExp",value:e.toString()};if(n.has(e))return"[Circular Reference]";if(n.add(e),Array.isArray(e))return e.map(o=>this.safeClone(o,n));try{const o={};for(const r of Object.keys(e))o[r]=this.safeClone(e[r],n);return o}catch{return"[Uncloneable Object]"}}store(e){for(this.logs.push(e);this.logs.length>this.config.maxLogs;)this.logs.shift()}notify(e){for(const n of this.subscribers)try{n(e)}catch{}}info(e,...n){this.log("info",e,n)}warn(e,...n){this.log("warn",e,n)}error(e,...n){this.log("error",e,n)}debug(e,...n){this.log("debug",e,n)}configure(e){try{this.config={...this.config,...e}}catch{}}clear(){try{this.logs=[],this.spans.clear()}catch{}}importLogs(e){try{if(!Array.isArray(e)||e.length===0)return;const n=new Set(this.logs.map(r=>r.id)),o=e.filter(r=>!n.has(r.id));for(this.logs=[...o,...this.logs];this.logs.length>this.config.maxLogs;)this.logs.shift()}catch{}}getLogs(){return this.logs}subscribe(e){try{return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}catch{return()=>{}}}getSessionId(){return this.sessionId}getConfig(){return{...this.config}}isEnabled(){return this.config.enabled}span(e,n){try{return new G(this,e,n)}catch{return new G(this,e,n)}}getSpans(){return Array.from(this.spans.values())}getSpan(e){return this.spans.get(e)}getSpanLogs(e){return this.logs.filter(n=>n.spanId===e)}subscribeSpans(e){try{return this.spanSubscribers.add(e),()=>{this.spanSubscribers.delete(e)}}catch{return()=>{}}}setGlobalContext(e){try{this.globalContext={...e}}catch{}}updateGlobalContext(e){try{this.globalContext={...this.globalContext,...e}}catch{}}getGlobalContext(){return{...this.globalContext}}clearGlobalContext(){this.globalContext={}}withContext(e){return new se(this,e)}exportLogs(e={}){try{const{format:n="json",lastMs:o,levels:r,search:s,pretty:a=!0}=e;let l=[...this.logs];if(o!==void 0&&o>0){const c=Date.now()-o;l=l.filter(d=>d.timestamp>=c)}if(r&&r.length>0){const c=new Set(r);l=l.filter(d=>c.has(d.level))}if(s){const c=s.toLowerCase();l=l.filter(d=>d.message.toLowerCase().includes(c)||JSON.stringify(d.data).toLowerCase().includes(c))}return n==="text"?this.formatLogsAsText(l):a?JSON.stringify(l,null,2):JSON.stringify(l)}catch{return"[]"}}formatLogsAsText(e){return e.map(n=>{const o=new Date(n.timestamp).toISOString(),r=n.level.toUpperCase().padEnd(5),s=`${n.source.file}:${n.source.line}`,a=n.context?` [${Object.entries(n.context).map(([d,f])=>`${d}=${f}`).join(", ")}]`:"",l=n.spanId?` (span: ${n.spanId})`:"",c=n.data.length>0?`
3
- Data: ${JSON.stringify(n.data)}`:"";return`[${o}] ${r} ${n.message}${a}${l}
4
- Source: ${s}${c}`}).join(`
1
+ "use strict";var Ue=Object.defineProperty;var Pe=(t,e,n)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var f=(t,e,n)=>Pe(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var Z=typeof document<"u"?document.currentScript:null;const pe={debug:0,info:1,warn:2,error:3};function w(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function z(t,e){if(t===e)return!0;if(typeof t!=typeof e)return!1;if(t===null||e===null)return t===e;if(Array.isArray(t)&&Array.isArray(e))return t.length!==e.length?!1:t.every((n,o)=>z(n,e[o]));if(w(t)&&w(e)){const n=Object.keys(t),o=Object.keys(e);return n.length!==o.length?!1:n.every(s=>z(t[s],e[s]))}return!1}function ne(t){if(t===void 0)return"undefined";if(t===null)return"null";if(typeof t=="string")return`"${t}"`;if(typeof t=="number"||typeof t=="boolean")return String(t);if(Array.isArray(t))return t.length===0?"[]":t.length<=3?`[${t.map(ne).join(", ")}]`:`[${t.length} items]`;if(w(t)){const e=Object.keys(t);return e.length===0?"{}":e.length<=2?`{${e.map(n=>`${n}: ${ne(t[n])}`).join(", ")}}`:`{${e.length} keys}`}return String(t)}function se(t,e,n="",o=!1){const s=[];if(!w(t)&&!w(e))return z(t,e)?o&&s.push({path:n||"(root)",type:"unchanged",oldValue:t,newValue:e}):s.push({path:n||"(root)",type:"changed",oldValue:t,newValue:e}),s;if(!w(t))return s.push({path:n||"(root)",type:"changed",oldValue:t,newValue:e}),s;if(!w(e))return s.push({path:n||"(root)",type:"changed",oldValue:t,newValue:e}),s;const i=new Set([...Object.keys(t),...Object.keys(e)]);for(const a of i){const l=n?`${n}.${a}`:a,c=t[a],d=e[a],p=a in t,h=a in e;!p&&h?s.push({path:l,type:"added",newValue:d}):p&&!h?s.push({path:l,type:"removed",oldValue:c}):w(c)&&w(d)?s.push(...se(c,d,l,o)):Array.isArray(c)&&Array.isArray(d)?z(c,d)?o&&s.push({path:l,type:"unchanged",oldValue:c,newValue:d}):s.push({path:l,type:"changed",oldValue:c,newValue:d}):z(c,d)?o&&s.push({path:l,type:"unchanged",oldValue:c,newValue:d}):s.push({path:l,type:"changed",oldValue:c,newValue:d})}return s}function re(t,e){const n=se(t,e,"",!1),o={added:0,removed:0,changed:0,unchanged:0};for(const s of n)o[s.type]++;return{changes:n,summary:o}}function qe(t){return t.summary.added>0||t.summary.removed>0||t.summary.changed>0}const Ve={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1};function je(){try{if(typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Z&&Z.tagName.toUpperCase()==="SCRIPT"&&Z.src||new URL("index.cjs",document.baseURI).href}<"u"&&Ve)return!1;const t=globalThis.process;if(t?.env){const e=t.env.DEVLOGGER_ENABLED||t.env.REACT_APP_DEVLOGGER_ENABLED;if(e==="false"||e==="0")return!1;if(e==="true"||e==="1")return!0;if(t.env.NODE_ENV==="production")return!1}return!0}catch{return!0}}const We={maxLogs:1e3,persist:!1,minLevel:"debug",enabled:je(),shortcutAction:"toggle",showToggleButton:!0,spanCollapsed:!1};function Je(){const t="devlogger_session_id";try{const e=sessionStorage.getItem(t);if(e)return e;const n=`session_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;return sessionStorage.setItem(t,n),n}catch{return`session_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}}function Ge(){return`log_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}function Se(){try{const t=new Error().stack;if(!t)return{file:"unknown",line:0};const e=t.split(`
2
+ `);for(let n=4;n<e.length;n++){const o=e[n];if(!o||o.includes("logger.ts")||o.includes("logger.js"))continue;const s=o.match(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(s)return{function:s[1]||void 0,file:fe(s[2]||"unknown"),line:parseInt(s[3]||"0",10),column:parseInt(s[4]||"0",10)};const i=o.match(/(.+)?@(.+?):(\d+):(\d+)/);if(i)return{function:i[1]||void 0,file:fe(i[2]||"unknown"),line:parseInt(i[3]||"0",10),column:parseInt(i[4]||"0",10)}}return{file:"unknown",line:0}}catch{return{file:"unknown",line:0}}}function fe(t){let e=t.replace(/^webpack:\/\/[^/]*\//,"").replace(/^\/@fs/,"").replace(/^file:\/\//,"").replace(/\?.*$/,"");const n=e.split("/");return n.length>2&&(e=n.slice(-2).join("/")),e}function Xe(){return`span_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}class J{constructor(e,n,o,s){f(this,"logger");f(this,"_event");f(this,"_ended",!1);this.logger=e,this._event={id:Xe(),name:n,startTime:Date.now(),status:"running",parentId:s,context:o,source:Se(),sessionId:e.getSessionId()},e.notifySpan(this._event)}get id(){return this._event.id}get event(){return this._event}get ended(){return this._ended}debug(e,...n){this._ended||this.logger.logWithSpan("debug",e,n,this._event.id,this._event.context)}info(e,...n){this._ended||this.logger.logWithSpan("info",e,n,this._event.id,this._event.context)}warn(e,...n){this._ended||this.logger.logWithSpan("warn",e,n,this._event.id,this._event.context)}error(e,...n){this._ended||this.logger.logWithSpan("error",e,n,this._event.id,this._event.context)}span(e,n){const o={...this._event.context,...n};return new J(this.logger,e,o,this._event.id)}end(){this.finish("success")}fail(e){e&&this.error(typeof e=="string"?e:e.message,e),this.finish("error")}finish(e){this._ended||(this._ended=!0,this._event.endTime=Date.now(),this._event.duration=this._event.endTime-this._event.startTime,this._event.status=e,this.logger.notifySpan(this._event))}}class ie{constructor(e,n){f(this,"logger");f(this,"context");this.logger=e,this.context=n}debug(e,...n){this.logger.logWithContext("debug",e,n,this.context)}info(e,...n){this.logger.logWithContext("info",e,n,this.context)}warn(e,...n){this.logger.logWithContext("warn",e,n,this.context)}error(e,...n){this.logger.logWithContext("error",e,n,this.context)}span(e,n){return this.logger.span(e,{...this.context,...n})}withContext(e){return new ie(this.logger,{...this.context,...e})}}class Ye{constructor(){f(this,"logs",[]);f(this,"spans",new Map);f(this,"subscribers",new Set);f(this,"spanSubscribers",new Set);f(this,"config",{...We});f(this,"sessionId");f(this,"globalContext",{});this.sessionId=Je()}log(e,n,o,s,i){try{if(!this.config.enabled||pe[e]<pe[this.config.minLevel])return;const a=Object.keys(this.globalContext).length>0||s?{...this.globalContext,...s}:void 0,l={id:Ge(),timestamp:Date.now(),level:e,message:String(n),data:this.safeCloneData(o),source:Se(),sessionId:this.sessionId,context:a,spanId:i};this.store(l),this.notify(l)}catch(a){typeof console<"u"&&console.warn&&console.warn("[DevLogger] Internal error:",a)}}logWithContext(e,n,o,s){this.log(e,n,o,s)}logWithSpan(e,n,o,s,i){this.log(e,n,o,i,s)}notifySpan(e){this.spans.set(e.id,e);for(const n of this.spanSubscribers)try{n(e)}catch{}}safeCloneData(e){return e.map(n=>this.safeClone(n))}safeClone(e,n=new WeakSet){if(e==null||typeof e!="object")return e;if(e instanceof Error)return{__type:"Error",name:e.name,message:e.message,stack:e.stack};if(e instanceof Date)return{__type:"Date",value:e.toISOString()};if(e instanceof RegExp)return{__type:"RegExp",value:e.toString()};if(n.has(e))return"[Circular Reference]";if(n.add(e),Array.isArray(e))return e.map(o=>this.safeClone(o,n));try{const o={};for(const s of Object.keys(e))o[s]=this.safeClone(e[s],n);return o}catch{return"[Uncloneable Object]"}}store(e){for(this.logs.push(e);this.logs.length>this.config.maxLogs;)this.logs.shift()}notify(e){for(const n of this.subscribers)try{n(e)}catch{}}info(e,...n){this.log("info",e,n)}warn(e,...n){this.log("warn",e,n)}error(e,...n){this.log("error",e,n)}debug(e,...n){this.log("debug",e,n)}configure(e){try{this.config={...this.config,...e}}catch{}}clear(){try{this.logs=[],this.spans.clear()}catch{}}importLogs(e){try{if(!Array.isArray(e)||e.length===0)return;const n=new Set(this.logs.map(s=>s.id)),o=e.filter(s=>!n.has(s.id));for(this.logs=[...o,...this.logs];this.logs.length>this.config.maxLogs;)this.logs.shift()}catch{}}getLogs(){return this.logs}subscribe(e){try{return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}catch{return()=>{}}}getSessionId(){return this.sessionId}getConfig(){return{...this.config}}isEnabled(){return this.config.enabled}span(e,n){try{return new J(this,e,n)}catch{return new J(this,e,n)}}getSpans(){return Array.from(this.spans.values())}getSpan(e){return this.spans.get(e)}getSpanLogs(e){return this.logs.filter(n=>n.spanId===e)}subscribeSpans(e){try{return this.spanSubscribers.add(e),()=>{this.spanSubscribers.delete(e)}}catch{return()=>{}}}setGlobalContext(e){try{this.globalContext={...e}}catch{}}updateGlobalContext(e){try{this.globalContext={...this.globalContext,...e}}catch{}}getGlobalContext(){return{...this.globalContext}}clearGlobalContext(){this.globalContext={}}withContext(e){return new ie(this,e)}exportLogs(e={}){try{const{format:n="json",lastMs:o,levels:s,search:i,pretty:a=!0}=e;let l=[...this.logs];if(o!==void 0&&o>0){const c=Date.now()-o;l=l.filter(d=>d.timestamp>=c)}if(s&&s.length>0){const c=new Set(s);l=l.filter(d=>c.has(d.level))}if(i){const c=i.toLowerCase();l=l.filter(d=>d.message.toLowerCase().includes(c)||JSON.stringify(d.data).toLowerCase().includes(c))}return n==="text"?this.formatLogsAsText(l):a?JSON.stringify(l,null,2):JSON.stringify(l)}catch{return"[]"}}formatLogsAsText(e){return e.map(n=>{const o=new Date(n.timestamp).toISOString(),s=n.level.toUpperCase().padEnd(5),i=`${n.source.file}:${n.source.line}`,a=n.context?` [${Object.entries(n.context).map(([d,p])=>`${d}=${p}`).join(", ")}]`:"",l=n.spanId?` (span: ${n.spanId})`:"",c=n.data.length>0?`
3
+ Data: ${JSON.stringify(n.data)}`:"";return`[${o}] ${s} ${n.message}${a}${l}
4
+ Source: ${i}${c}`}).join(`
5
5
 
6
- `)}async copyLogs(e={}){try{const n=this.exportLogs(e);return await navigator.clipboard.writeText(n),!0}catch{return!1}}diff(e,n,o,r="info"){try{const s=ne(n,o);return this.log(r,e,[{__type:"Diff",diff:s,oldObj:this.safeClone(n),newObj:this.safeClone(o)}]),s}catch{return{changes:[],summary:{added:0,removed:0,changed:0,unchanged:0}}}}computeDiff(e,n){try{return ne(e,n)}catch{return{changes:[],summary:{added:0,removed:0,changed:0,unchanged:0}}}}}const u=new Ge,g={bgPrimary:"#1e1e1e",bgSecondary:"#252526",bgHover:"#2a2a2a",bgHeader:"#333333",textPrimary:"#cccccc",textSecondary:"#858585",textMuted:"#6e6e6e",levelDebug:"#6e6e6e",levelInfo:"#3794ff",levelWarn:"#cca700",levelError:"#f14c4c",border:"#3c3c3c",scrollbar:"#4a4a4a",scrollbarHover:"#5a5a5a",buttonBg:"#0e639c",buttonHover:"#1177bb"},Je=`
6
+ `)}async copyLogs(e={}){try{const n=this.exportLogs(e);return await navigator.clipboard.writeText(n),!0}catch{return!1}}diff(e,n,o,s="info"){try{const i=re(n,o);return this.log(s,e,[{__type:"Diff",diff:i,oldObj:this.safeClone(n),newObj:this.safeClone(o)}]),i}catch{return{changes:[],summary:{added:0,removed:0,changed:0,unchanged:0}}}}computeDiff(e,n){try{return re(e,n)}catch{return{changes:[],summary:{added:0,removed:0,changed:0,unchanged:0}}}}}const g=new Ye,u={bgPrimary:"#1e1e1e",bgSecondary:"#252526",bgHover:"#2a2a2a",bgHeader:"#333333",textPrimary:"#cccccc",textSecondary:"#858585",textMuted:"#6e6e6e",levelDebug:"#6e6e6e",levelInfo:"#3794ff",levelWarn:"#cca700",levelError:"#f14c4c",border:"#3c3c3c",scrollbar:"#4a4a4a",scrollbarHover:"#5a5a5a",buttonBg:"#0e639c",buttonHover:"#1177bb"},Ke=`
7
7
  :host {
8
- --bg-primary: ${g.bgPrimary};
9
- --bg-secondary: ${g.bgSecondary};
10
- --bg-hover: ${g.bgHover};
11
- --bg-header: ${g.bgHeader};
12
- --text-primary: ${g.textPrimary};
13
- --text-secondary: ${g.textSecondary};
14
- --text-muted: ${g.textMuted};
15
- --border: ${g.border};
8
+ --bg-primary: ${u.bgPrimary};
9
+ --bg-secondary: ${u.bgSecondary};
10
+ --bg-hover: ${u.bgHover};
11
+ --bg-header: ${u.bgHeader};
12
+ --text-primary: ${u.textPrimary};
13
+ --text-secondary: ${u.textSecondary};
14
+ --text-muted: ${u.textMuted};
15
+ --border: ${u.border};
16
16
 
17
17
  all: initial;
18
18
  font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
@@ -65,7 +65,7 @@
65
65
  }
66
66
 
67
67
  .devlogger-badge {
68
- background: ${g.levelInfo};
68
+ background: ${u.levelInfo};
69
69
  color: white;
70
70
  padding: 2px 6px;
71
71
  border-radius: 10px;
@@ -94,13 +94,18 @@
94
94
  color: var(--text-primary);
95
95
  }
96
96
 
97
+ .devlogger-btn.active {
98
+ background: var(--bg-hover);
99
+ color: var(--text-primary);
100
+ }
101
+
97
102
  .devlogger-btn-primary {
98
- background: ${g.buttonBg};
103
+ background: ${u.buttonBg};
99
104
  color: white;
100
105
  }
101
106
 
102
107
  .devlogger-btn-primary:hover {
103
- background: ${g.buttonHover};
108
+ background: ${u.buttonHover};
104
109
  color: white;
105
110
  }
106
111
 
@@ -120,12 +125,12 @@
120
125
  }
121
126
 
122
127
  .devlogger-logs::-webkit-scrollbar-thumb {
123
- background: ${g.scrollbar};
128
+ background: ${u.scrollbar};
124
129
  border-radius: 4px;
125
130
  }
126
131
 
127
132
  .devlogger-logs::-webkit-scrollbar-thumb:hover {
128
- background: ${g.scrollbarHover};
133
+ background: ${u.scrollbarHover};
129
134
  }
130
135
 
131
136
  .devlogger-empty {
@@ -167,22 +172,22 @@
167
172
 
168
173
  .log-level-debug {
169
174
  background: rgba(110, 110, 110, 0.2);
170
- color: ${g.levelDebug};
175
+ color: ${u.levelDebug};
171
176
  }
172
177
 
173
178
  .log-level-info {
174
179
  background: rgba(55, 148, 255, 0.15);
175
- color: ${g.levelInfo};
180
+ color: ${u.levelInfo};
176
181
  }
177
182
 
178
183
  .log-level-warn {
179
184
  background: rgba(204, 167, 0, 0.15);
180
- color: ${g.levelWarn};
185
+ color: ${u.levelWarn};
181
186
  }
182
187
 
183
188
  .log-level-error {
184
189
  background: rgba(241, 76, 76, 0.15);
185
- color: ${g.levelError};
190
+ color: ${u.levelError};
186
191
  }
187
192
 
188
193
  .log-time {
@@ -201,12 +206,12 @@
201
206
  }
202
207
 
203
208
  .log-source:hover {
204
- color: ${g.levelInfo};
209
+ color: ${u.levelInfo};
205
210
  }
206
211
 
207
212
  .log-context {
208
213
  font-size: 10px;
209
- color: ${g.levelInfo};
214
+ color: ${u.levelInfo};
210
215
  background: rgba(55, 148, 255, 0.1);
211
216
  padding: 2px 6px;
212
217
  border-radius: 3px;
@@ -217,7 +222,7 @@
217
222
  }
218
223
 
219
224
  .log-entry-in-span {
220
- border-left: 2px solid ${g.levelInfo};
225
+ border-left: 2px solid ${u.levelInfo};
221
226
  padding-left: 10px;
222
227
  }
223
228
 
@@ -272,17 +277,17 @@
272
277
  }
273
278
 
274
279
  .span-status-running {
275
- color: ${g.levelInfo};
280
+ color: ${u.levelInfo};
276
281
  background: rgba(55, 148, 255, 0.15);
277
282
  }
278
283
 
279
284
  .span-status-success {
280
- color: ${g.levelInfo};
285
+ color: ${u.levelInfo};
281
286
  background: rgba(55, 148, 255, 0.15);
282
287
  }
283
288
 
284
289
  .span-status-error {
285
- color: ${g.levelError};
290
+ color: ${u.levelError};
286
291
  background: rgba(241, 76, 76, 0.15);
287
292
  }
288
293
 
@@ -366,7 +371,7 @@
366
371
  width: 48px;
367
372
  height: 48px;
368
373
  border-radius: 50%;
369
- background: ${g.buttonBg};
374
+ background: ${u.buttonBg};
370
375
  color: white;
371
376
  border: none;
372
377
  cursor: pointer;
@@ -380,7 +385,7 @@
380
385
  }
381
386
 
382
387
  .devlogger-toggle:hover {
383
- background: ${g.buttonHover};
388
+ background: ${u.buttonHover};
384
389
  transform: scale(1.05);
385
390
  }
386
391
 
@@ -404,6 +409,45 @@
404
409
  opacity: 0.7;
405
410
  }
406
411
 
412
+ /* Resource Monitor */
413
+ .resource-container {
414
+ background: var(--bg-secondary);
415
+ border-bottom: 1px solid var(--border);
416
+ padding: 8px 12px;
417
+ display: none;
418
+ }
419
+
420
+ .resource-header {
421
+ display: flex;
422
+ align-items: center;
423
+ justify-content: space-between;
424
+ margin-bottom: 6px;
425
+ color: var(--text-secondary);
426
+ font-size: 11px;
427
+ }
428
+
429
+ .resource-metrics {
430
+ display: grid;
431
+ grid-template-columns: 1fr auto;
432
+ gap: 6px 12px;
433
+ font-size: 11px;
434
+ }
435
+
436
+ .resource-label {
437
+ color: var(--text-muted);
438
+ }
439
+
440
+ .resource-value {
441
+ color: var(--text-primary);
442
+ font-weight: 600;
443
+ }
444
+
445
+ .resource-note {
446
+ margin-top: 6px;
447
+ color: var(--text-muted);
448
+ font-size: 11px;
449
+ }
450
+
407
451
  /* Filter Bar */
408
452
  .filter-bar {
409
453
  padding: 8px 12px;
@@ -414,7 +458,7 @@
414
458
 
415
459
  .filter-bar.filter-active {
416
460
  background: rgba(55, 148, 255, 0.08);
417
- border-bottom-color: ${g.levelInfo};
461
+ border-bottom-color: ${u.levelInfo};
418
462
  }
419
463
 
420
464
  .filter-row {
@@ -451,23 +495,23 @@
451
495
  }
452
496
 
453
497
  .filter-level-btn.active[data-level="debug"] {
454
- background: ${g.levelDebug};
455
- border-color: ${g.levelDebug};
498
+ background: ${u.levelDebug};
499
+ border-color: ${u.levelDebug};
456
500
  }
457
501
 
458
502
  .filter-level-btn.active[data-level="info"] {
459
- background: ${g.levelInfo};
460
- border-color: ${g.levelInfo};
503
+ background: ${u.levelInfo};
504
+ border-color: ${u.levelInfo};
461
505
  }
462
506
 
463
507
  .filter-level-btn.active[data-level="warn"] {
464
- background: ${g.levelWarn};
465
- border-color: ${g.levelWarn};
508
+ background: ${u.levelWarn};
509
+ border-color: ${u.levelWarn};
466
510
  }
467
511
 
468
512
  .filter-level-btn.active[data-level="error"] {
469
- background: ${g.levelError};
470
- border-color: ${g.levelError};
513
+ background: ${u.levelError};
514
+ border-color: ${u.levelError};
471
515
  }
472
516
 
473
517
  .filter-search {
@@ -496,7 +540,7 @@
496
540
  }
497
541
 
498
542
  .filter-input:focus {
499
- border-color: ${g.levelInfo};
543
+ border-color: ${u.levelInfo};
500
544
  }
501
545
 
502
546
  .filter-clear-btn {
@@ -505,21 +549,21 @@
505
549
  border: none;
506
550
  border-radius: 4px;
507
551
  background: rgba(241, 76, 76, 0.2);
508
- color: ${g.levelError};
552
+ color: ${u.levelError};
509
553
  cursor: pointer;
510
554
  font-size: 12px;
511
555
  transition: all 0.15s ease;
512
556
  }
513
557
 
514
558
  .filter-clear-btn:hover {
515
- background: ${g.levelError};
559
+ background: ${u.levelError};
516
560
  color: white;
517
561
  }
518
562
 
519
563
  .filter-status {
520
564
  margin-top: 6px;
521
565
  font-size: 10px;
522
- color: ${g.levelInfo};
566
+ color: ${u.levelInfo};
523
567
  }
524
568
 
525
569
  /* No results state */
@@ -569,12 +613,12 @@
569
613
 
570
614
  .diff-count.diff-removed {
571
615
  background: rgba(241, 76, 76, 0.2);
572
- color: ${g.levelError};
616
+ color: ${u.levelError};
573
617
  }
574
618
 
575
619
  .diff-count.diff-changed {
576
620
  background: rgba(204, 167, 0, 0.2);
577
- color: ${g.levelWarn};
621
+ color: ${u.levelWarn};
578
622
  }
579
623
 
580
624
  .diff-count.diff-unchanged {
@@ -602,12 +646,12 @@
602
646
 
603
647
  .diff-entry.diff-removed {
604
648
  background: rgba(241, 76, 76, 0.1);
605
- color: ${g.levelError};
649
+ color: ${u.levelError};
606
650
  }
607
651
 
608
652
  .diff-entry.diff-changed {
609
653
  background: rgba(204, 167, 0, 0.1);
610
- color: ${g.levelWarn};
654
+ color: ${u.levelWarn};
611
655
  }
612
656
 
613
657
  .diff-icon {
@@ -626,33 +670,33 @@
626
670
  }
627
671
 
628
672
  .log-data-diff .log-data-toggle {
629
- color: ${g.levelInfo};
673
+ color: ${u.levelInfo};
630
674
  }
631
- `;function Xe(t){const e=new Date(t),n=e.getHours().toString().padStart(2,"0"),o=e.getMinutes().toString().padStart(2,"0"),r=e.getSeconds().toString().padStart(2,"0"),s=e.getMilliseconds().toString().padStart(3,"0");return`${n}:${o}:${r}.${s}`}function pe(t){return t.file==="unknown"?"unknown":`${t.file}:${t.line}`}function Le(t){return t!==null&&typeof t=="object"&&t.__type==="Diff"&&t.diff!==void 0}function $(t){if(t===void 0)return"undefined";if(t===null)return"null";if(typeof t=="string")return`"${t}"`;if(typeof t=="number"||typeof t=="boolean")return String(t);if(Array.isArray(t))return t.length===0?"[]":t.length<=3?`[${t.map($).join(", ")}]`:`[${t.length} items]`;if(typeof t=="object"){const e=Object.keys(t);return e.length===0?"{}":e.length<=2?`{${e.map(n=>`${n}: ${$(t[n])}`).join(", ")}}`:`{${e.length} keys}`}return String(t)}function Ye(t){const e=`diff-${t.type}`,n=t.type==="added"?"+":t.type==="removed"?"-":t.type==="changed"?"~":" ";let o="";return t.type==="added"?o=$(t.newValue):t.type==="removed"?o=$(t.oldValue):t.type==="changed"&&(o=`${$(t.oldValue)} → ${$(t.newValue)}`),`<div class="diff-entry ${e}"><span class="diff-icon">${n}</span> <span class="diff-path">${t.path}</span>: <span class="diff-value">${o}</span></div>`}function Ke(t){const{diff:e}=t,{summary:n,changes:o}=e;let r='<div class="diff-container">';if(r+='<div class="diff-summary">',n.added>0&&(r+=`<span class="diff-count diff-added">+${n.added}</span>`),n.removed>0&&(r+=`<span class="diff-count diff-removed">-${n.removed}</span>`),n.changed>0&&(r+=`<span class="diff-count diff-changed">~${n.changed}</span>`),n.added===0&&n.removed===0&&n.changed===0&&(r+='<span class="diff-count diff-unchanged">No changes</span>'),r+="</div>",o.length>0){r+='<div class="diff-changes">';for(const s of o)r+=Ye(s);r+="</div>"}return r+="</div>",r}function Qe(t){if(t.length===0)return"";try{return t.map(e=>typeof e=="string"?e:JSON.stringify(e,null,2)).join(`
632
- `)}catch{return"[Unable to display data]"}}function Ze(t){return t.some(Le)}function B(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function et(t){return!t||Object.keys(t).length===0?"":Object.entries(t).map(([e,n])=>`${e}=${n}`).join(" · ")}function J(t){const e=document.createElement("div");e.className=`log-entry${t.spanId?" log-entry-in-span":""}`,e.dataset.id=t.id,t.spanId&&(e.dataset.spanId=t.spanId);const n=t.data.length>0,o=Ze(t.data),r=t.context&&Object.keys(t.context).length>0,s=`data-${t.id}`,a=()=>{if(!n)return"";if(o){const l=t.data.find(Le);if(l)return`
675
+ `;function Qe(t){const e=new Date(t),n=e.getHours().toString().padStart(2,"0"),o=e.getMinutes().toString().padStart(2,"0"),s=e.getSeconds().toString().padStart(2,"0"),i=e.getMilliseconds().toString().padStart(3,"0");return`${n}:${o}:${s}.${i}`}function he(t){return t.file==="unknown"?"unknown":`${t.file}:${t.line}`}function Ce(t){return t!==null&&typeof t=="object"&&t.__type==="Diff"&&t.diff!==void 0}function E(t){if(t===void 0)return"undefined";if(t===null)return"null";if(typeof t=="string")return`"${t}"`;if(typeof t=="number"||typeof t=="boolean")return String(t);if(Array.isArray(t))return t.length===0?"[]":t.length<=3?`[${t.map(E).join(", ")}]`:`[${t.length} items]`;if(typeof t=="object"){const e=Object.keys(t);return e.length===0?"{}":e.length<=2?`{${e.map(n=>`${n}: ${E(t[n])}`).join(", ")}}`:`{${e.length} keys}`}return String(t)}function Ze(t){const e=`diff-${t.type}`,n=t.type==="added"?"+":t.type==="removed"?"-":t.type==="changed"?"~":" ";let o="";return t.type==="added"?o=E(t.newValue):t.type==="removed"?o=E(t.oldValue):t.type==="changed"&&(o=`${E(t.oldValue)} → ${E(t.newValue)}`),`<div class="diff-entry ${e}"><span class="diff-icon">${n}</span> <span class="diff-path">${t.path}</span>: <span class="diff-value">${o}</span></div>`}function et(t){const{diff:e}=t,{summary:n,changes:o}=e;let s='<div class="diff-container">';if(s+='<div class="diff-summary">',n.added>0&&(s+=`<span class="diff-count diff-added">+${n.added}</span>`),n.removed>0&&(s+=`<span class="diff-count diff-removed">-${n.removed}</span>`),n.changed>0&&(s+=`<span class="diff-count diff-changed">~${n.changed}</span>`),n.added===0&&n.removed===0&&n.changed===0&&(s+='<span class="diff-count diff-unchanged">No changes</span>'),s+="</div>",o.length>0){s+='<div class="diff-changes">';for(const i of o)s+=Ze(i);s+="</div>"}return s+="</div>",s}function tt(t){if(t.length===0)return"";try{return t.map(e=>typeof e=="string"?e:JSON.stringify(e,null,2)).join(`
676
+ `)}catch{return"[Unable to display data]"}}function nt(t){return t.some(Ce)}function _(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function rt(t){return!t||Object.keys(t).length===0?"":Object.entries(t).map(([e,n])=>`${e}=${n}`).join(" · ")}function G(t){const e=document.createElement("div");e.className=`log-entry${t.spanId?" log-entry-in-span":""}`,e.dataset.id=t.id,t.spanId&&(e.dataset.spanId=t.spanId);const n=t.data.length>0,o=nt(t.data),s=t.context&&Object.keys(t.context).length>0,i=`data-${t.id}`,a=()=>{if(!n)return"";if(o){const l=t.data.find(Ce);if(l)return`
633
677
  <div class="log-data log-data-diff">
634
- <button class="log-data-toggle" data-target="${s}">
678
+ <button class="log-data-toggle" data-target="${i}">
635
679
  diff
636
680
  </button>
637
- <div class="log-data-content" id="${s}">${Ke(l)}</div>
681
+ <div class="log-data-content" id="${i}">${et(l)}</div>
638
682
  </div>
639
683
  `}return`
640
684
  <div class="log-data">
641
- <button class="log-data-toggle" data-target="${s}">
685
+ <button class="log-data-toggle" data-target="${i}">
642
686
  ${t.data.length} item${t.data.length>1?"s":""}
643
687
  </button>
644
- <pre class="log-data-content" id="${s}">${B(Qe(t.data))}</pre>
688
+ <pre class="log-data-content" id="${i}">${_(tt(t.data))}</pre>
645
689
  </div>
646
690
  `};if(e.innerHTML=`
647
691
  <div class="log-entry-header">
648
692
  <span class="log-level log-level-${t.level}">${t.level}</span>
649
- <span class="log-time">${Xe(t.timestamp)}</span>
650
- ${r?`<span class="log-context" title="Context">${B(et(t.context))}</span>`:""}
651
- <span class="log-source" title="${B(pe(t.source))}">${B(pe(t.source))}</span>
693
+ <span class="log-time">${Qe(t.timestamp)}</span>
694
+ ${s?`<span class="log-context" title="Context">${_(rt(t.context))}</span>`:""}
695
+ <span class="log-source" title="${_(he(t.source))}">${_(he(t.source))}</span>
652
696
  </div>
653
- <div class="log-message">${B(t.message)}</div>
697
+ <div class="log-message">${_(t.message)}</div>
654
698
  ${a()}
655
- `,n){const l=e.querySelector(".log-data-toggle"),c=e.querySelector(`#${s}`);l&&c&&l.addEventListener("click",()=>{l.classList.toggle("expanded"),c.classList.toggle("visible")})}return e}function tt(){const t=document.createElement("div");return t.className="devlogger-empty",t.textContent="No logs yet...",t}const nt="devlogger-sync";function ot(){return`sender_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}class rt{constructor(){p(this,"channel",null);p(this,"handlers",new Set);p(this,"senderId");p(this,"isConnected",!1);this.senderId=ot(),this.connect()}connect(){try{if(typeof BroadcastChannel>"u"){console.warn("[DevLogger] BroadcastChannel not supported");return}this.channel=new BroadcastChannel(nt),this.channel.onmessage=e=>{this.handleMessage(e.data)},this.channel.onmessageerror=()=>{console.warn("[DevLogger] Channel message error")},this.isConnected=!0}catch(e){console.warn("[DevLogger] Failed to connect to channel:",e),this.isConnected=!1}}handleMessage(e){if(e.senderId!==this.senderId)for(const n of this.handlers)try{n(e)}catch{}}send(e,n){try{if(!this.channel||!this.isConnected)return;const o={type:e,payload:n,senderId:this.senderId,timestamp:Date.now()};this.channel.postMessage(o)}catch{}}sendLog(e){this.send("NEW_LOG",e)}requestSync(){this.send("SYNC_REQUEST")}sendSyncResponse(e){this.send("SYNC_RESPONSE",e)}sendClear(){this.send("CLEAR_LOGS")}subscribe(e){return this.handlers.add(e),()=>{this.handlers.delete(e)}}isActive(){return this.isConnected}getSenderId(){return this.senderId}close(){try{this.channel&&(this.channel.close(),this.channel=null),this.handlers.clear(),this.isConnected=!1}catch{}}}const N=new rt,he=500,be=700;let b=null;function st(){try{if(b&&!b.closed)return b.focus(),b;const t=Math.max(0,(screen.width-he)/2),e=Math.max(0,(screen.height-be)/2),n=at();return b=window.open("","devlogger-popout",`width=${he},height=${be},left=${t},top=${e},resizable=yes,scrollbars=yes`),b?(b.document.open(),b.document.write(n),b.document.close(),b.addEventListener("load",()=>{setTimeout(()=>{N.sendSyncResponse(u.getLogs())},100)}),b):(console.warn("[DevLogger] Pop-out blocked by browser"),null)}catch(t){return console.warn("[DevLogger] Failed to open pop-out:",t),null}}function me(){try{b&&!b.closed&&b.close(),b=null}catch{}}function it(){return b!==null&&!b.closed}function at(){return`<!DOCTYPE html>
699
+ `,n){const l=e.querySelector(".log-data-toggle"),c=e.querySelector(`#${i}`);l&&c&&l.addEventListener("click",()=>{l.classList.toggle("expanded"),c.classList.toggle("visible")})}return e}function ot(){const t=document.createElement("div");return t.className="devlogger-empty",t.textContent="No logs yet...",t}const st="devlogger-sync";function it(){return`sender_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}class at{constructor(){f(this,"channel",null);f(this,"handlers",new Set);f(this,"senderId");f(this,"isConnected",!1);this.senderId=it(),this.connect()}connect(){try{if(typeof BroadcastChannel>"u"){console.warn("[DevLogger] BroadcastChannel not supported");return}this.channel=new BroadcastChannel(st),this.channel.onmessage=e=>{this.handleMessage(e.data)},this.channel.onmessageerror=()=>{console.warn("[DevLogger] Channel message error")},this.isConnected=!0}catch(e){console.warn("[DevLogger] Failed to connect to channel:",e),this.isConnected=!1}}handleMessage(e){if(e.senderId!==this.senderId)for(const n of this.handlers)try{n(e)}catch{}}send(e,n){try{if(!this.channel||!this.isConnected)return;const o={type:e,payload:n,senderId:this.senderId,timestamp:Date.now()};this.channel.postMessage(o)}catch{}}sendLog(e){this.send("NEW_LOG",e)}requestSync(){this.send("SYNC_REQUEST")}sendSyncResponse(e){this.send("SYNC_RESPONSE",e)}sendClear(){this.send("CLEAR_LOGS")}subscribe(e){return this.handlers.add(e),()=>{this.handlers.delete(e)}}isActive(){return this.isConnected}getSenderId(){return this.senderId}close(){try{this.channel&&(this.channel.close(),this.channel=null),this.handlers.clear(),this.isConnected=!1}catch{}}}const A=new at,me=500,be=700;let m=null;function lt(){try{if(m&&!m.closed)return m.focus(),m;const t=Math.max(0,(screen.width-me)/2),e=Math.max(0,(screen.height-be)/2),n=dt();return m=window.open("","devlogger-popout",`width=${me},height=${be},left=${t},top=${e},resizable=yes,scrollbars=yes`),m?(m.document.open(),m.document.write(n),m.document.close(),m.addEventListener("load",()=>{setTimeout(()=>{A.sendSyncResponse(g.getLogs())},100)}),m):(console.warn("[DevLogger] Pop-out blocked by browser"),null)}catch(t){return console.warn("[DevLogger] Failed to open pop-out:",t),null}}function ve(){try{m&&!m.closed&&m.close(),m=null}catch{}}function ct(){return m!==null&&!m.closed}function dt(){return`<!DOCTYPE html>
656
700
  <html lang="en">
657
701
  <head>
658
702
  <meta charset="UTF-8">
@@ -786,6 +830,45 @@
786
830
  color: white;
787
831
  }
788
832
 
833
+ /* Resource Monitor */
834
+ .resource-container {
835
+ background: var(--bg-secondary);
836
+ border-bottom: 1px solid var(--border);
837
+ padding: 8px 12px;
838
+ display: none;
839
+ }
840
+
841
+ .resource-header {
842
+ display: flex;
843
+ align-items: center;
844
+ justify-content: space-between;
845
+ margin-bottom: 6px;
846
+ color: var(--text-secondary);
847
+ font-size: 11px;
848
+ }
849
+
850
+ .resource-metrics {
851
+ display: grid;
852
+ grid-template-columns: 1fr auto;
853
+ gap: 6px 12px;
854
+ font-size: 11px;
855
+ }
856
+
857
+ .resource-label {
858
+ color: var(--text-muted);
859
+ }
860
+
861
+ .resource-value {
862
+ color: var(--text-primary);
863
+ font-weight: 600;
864
+ }
865
+
866
+ .resource-note {
867
+ margin-top: 6px;
868
+ color: var(--text-muted);
869
+ font-size: 11px;
870
+ }
871
+
789
872
  /* Timeline Container */
790
873
  .timeline-container {
791
874
  position: relative;
@@ -1086,6 +1169,7 @@
1086
1169
  <button class="btn btn-copy" id="btn-copy-text" title="Copy as Text">TXT</button>
1087
1170
  <button class="btn btn-timeline" id="btn-timeline" title="Toggle Timeline">Timeline</button>
1088
1171
  <button class="btn btn-timeline" id="btn-timeline-pause" title="Pause/Resume Timeline" style="display: none;">⏸</button>
1172
+ <button class="btn btn-timeline" id="btn-resources" title="Toggle Resource Monitor">Resources</button>
1089
1173
  <button class="btn" id="btn-clear">Clear</button>
1090
1174
  </div>
1091
1175
  </div>
@@ -1100,6 +1184,24 @@
1100
1184
  </div>
1101
1185
  </div>
1102
1186
 
1187
+ <div class="resource-container" id="resource-container">
1188
+ <div class="resource-header">
1189
+ <span>Resource Monitor</span>
1190
+ <span id="resource-status"></span>
1191
+ </div>
1192
+ <div class="resource-metrics" id="resource-metrics">
1193
+ <span class="resource-label">JS Heap Used</span>
1194
+ <span class="resource-value" id="resource-heap-used">-</span>
1195
+ <span class="resource-label">JS Heap Total</span>
1196
+ <span class="resource-value" id="resource-heap-total">-</span>
1197
+ <span class="resource-label">JS Heap Limit</span>
1198
+ <span class="resource-value" id="resource-heap-limit">-</span>
1199
+ </div>
1200
+ <div class="resource-note" id="resource-note" style="display: none;">
1201
+ Resource metrics are available only in Chrome.
1202
+ </div>
1203
+ </div>
1204
+
1103
1205
  <div class="filter-bar" id="filter-bar">
1104
1206
  <div class="filter-row">
1105
1207
  <div class="filter-levels">
@@ -1149,9 +1251,17 @@
1149
1251
  const btnCopyText = document.getElementById('btn-copy-text');
1150
1252
  const btnTimeline = document.getElementById('btn-timeline');
1151
1253
  const btnTimelinePause = document.getElementById('btn-timeline-pause');
1254
+ const btnResources = document.getElementById('btn-resources');
1152
1255
  const timelineContainer = document.getElementById('timeline-container');
1153
1256
  const timelineCanvas = document.getElementById('timeline-canvas');
1154
1257
  const timelineTooltip = document.getElementById('timeline-tooltip');
1258
+ const resourceContainer = document.getElementById('resource-container');
1259
+ const resourceStatus = document.getElementById('resource-status');
1260
+ const resourceMetrics = document.getElementById('resource-metrics');
1261
+ const resourceNote = document.getElementById('resource-note');
1262
+ const resourceHeapUsed = document.getElementById('resource-heap-used');
1263
+ const resourceHeapTotal = document.getElementById('resource-heap-total');
1264
+ const resourceHeapLimit = document.getElementById('resource-heap-limit');
1155
1265
  const filterBar = document.getElementById('filter-bar');
1156
1266
 
1157
1267
  // Timeline state
@@ -1159,6 +1269,9 @@
1159
1269
  let timelineWindow = 30000; // 30 seconds default
1160
1270
  let timelineInterval = null;
1161
1271
  let timelinePaused = false;
1272
+ let resourceVisible = false;
1273
+ let resourceInterval = null;
1274
+ const resourceSupported = typeof performance !== 'undefined' && performance && 'memory' in performance;
1162
1275
  const LEVEL_COLORS = {
1163
1276
  debug: '#6e6e6e',
1164
1277
  info: '#3794ff',
@@ -1294,6 +1407,47 @@
1294
1407
  }
1295
1408
  }
1296
1409
 
1410
+ function formatBytes(bytes) {
1411
+ if (typeof bytes !== 'number' || !isFinite(bytes)) return '-';
1412
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
1413
+ }
1414
+
1415
+ function updateResourceSupportUI() {
1416
+ if (!resourceStatus || !resourceMetrics || !resourceNote) return;
1417
+ if (resourceSupported) {
1418
+ resourceStatus.textContent = 'Chrome API';
1419
+ resourceMetrics.style.display = 'grid';
1420
+ resourceNote.style.display = 'none';
1421
+ } else {
1422
+ resourceStatus.textContent = 'Unsupported';
1423
+ resourceMetrics.style.display = 'none';
1424
+ resourceNote.style.display = 'block';
1425
+ }
1426
+ }
1427
+
1428
+ function updateResourceMetrics() {
1429
+ if (!resourceSupported || !resourceHeapUsed || !resourceHeapTotal || !resourceHeapLimit) {
1430
+ return;
1431
+ }
1432
+ const memory = performance.memory;
1433
+ resourceHeapUsed.textContent = formatBytes(memory.usedJSHeapSize);
1434
+ resourceHeapTotal.textContent = formatBytes(memory.totalJSHeapSize);
1435
+ resourceHeapLimit.textContent = formatBytes(memory.jsHeapSizeLimit);
1436
+ }
1437
+
1438
+ function startResourceUpdates() {
1439
+ if (resourceInterval || !resourceSupported) return;
1440
+ updateResourceMetrics();
1441
+ resourceInterval = setInterval(updateResourceMetrics, 1000);
1442
+ }
1443
+
1444
+ function stopResourceUpdates() {
1445
+ if (resourceInterval) {
1446
+ clearInterval(resourceInterval);
1447
+ resourceInterval = null;
1448
+ }
1449
+ }
1450
+
1297
1451
  // Render all logs
1298
1452
  function renderAllLogs() {
1299
1453
  const filteredLogs = getFilteredLogs();
@@ -1563,6 +1717,18 @@
1563
1717
  }
1564
1718
  });
1565
1719
 
1720
+ btnResources.addEventListener('click', () => {
1721
+ resourceVisible = !resourceVisible;
1722
+ btnResources.classList.toggle('active', resourceVisible);
1723
+ resourceContainer.style.display = resourceVisible ? 'block' : 'none';
1724
+ if (resourceVisible) {
1725
+ updateResourceSupportUI();
1726
+ startResourceUpdates();
1727
+ } else {
1728
+ stopResourceUpdates();
1729
+ }
1730
+ });
1731
+
1566
1732
  // Timeline: Time window buttons
1567
1733
  document.querySelectorAll('.timeline-btn[data-window]').forEach(btn => {
1568
1734
  btn.addEventListener('click', (e) => {
@@ -1714,7 +1880,7 @@
1714
1880
  connect();
1715
1881
  <\/script>
1716
1882
  </body>
1717
- </html>`}function z(){return{levels:new Set(["debug","info","warn","error"]),search:"",file:""}}function lt(t,e){if(e.levels.size>0&&!e.levels.has(t.level)||e.file&&!t.source.file.toLowerCase().includes(e.file.toLowerCase()))return!1;if(e.search){const n=e.search.toLowerCase(),o=t.message.toLowerCase().includes(n),r=JSON.stringify(t.data).toLowerCase().includes(n);if(!o&&!r)return!1}return!0}function V(t,e){return t.filter(n=>lt(n,e))}function ie(t){return!(t.levels.size===4)||t.search!==""||t.file!==""}function ct(t,e,n){const o=ie(t);return`
1883
+ </html>`}function O(){return{levels:new Set(["debug","info","warn","error"]),search:"",file:""}}function ut(t,e){if(e.levels.size>0&&!e.levels.has(t.level)||e.file&&!t.source.file.toLowerCase().includes(e.file.toLowerCase()))return!1;if(e.search){const n=e.search.toLowerCase(),o=t.message.toLowerCase().includes(n),s=JSON.stringify(t.data).toLowerCase().includes(n);if(!o&&!s)return!1}return!0}function V(t,e){return t.filter(n=>ut(n,e))}function ae(t){return!(t.levels.size===4)||t.search!==""||t.file!==""}function gt(t,e,n){const o=ae(t);return`
1718
1884
  <div class="filter-bar ${o?"filter-active":""}">
1719
1885
  <div class="filter-row">
1720
1886
  <div class="filter-levels">
@@ -1724,45 +1890,63 @@
1724
1890
  <button class="filter-level-btn ${t.levels.has("error")?"active":""}" data-level="error" title="Error">E</button>
1725
1891
  </div>
1726
1892
  <div class="filter-search">
1727
- <input type="text" class="filter-input" placeholder="Search logs..." value="${ve(t.search)}" data-filter="search">
1893
+ <input type="text" class="filter-input" placeholder="Search logs..." value="${ye(t.search)}" data-filter="search">
1728
1894
  </div>
1729
1895
  <div class="filter-file">
1730
- <input type="text" class="filter-input filter-file-input" placeholder="Filter by file..." value="${ve(t.file)}" data-filter="file">
1896
+ <input type="text" class="filter-input filter-file-input" placeholder="Filter by file..." value="${ye(t.file)}" data-filter="file">
1731
1897
  </div>
1732
1898
  ${o?'<button class="filter-clear-btn" title="Clear filters">✕</button>':""}
1733
1899
  </div>
1734
1900
  ${o?`<div class="filter-status">Showing ${n} of ${e} logs</div>`:""}
1735
1901
  </div>
1736
- `}function ve(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}const ee={key:"l",ctrlKey:!0,shiftKey:!0};function ae(){return u.getConfig().shortcutAction==="popout"?"popout":"toggle"}function dt(){return ae()==="popout"?"Ctrl+Shift+L to open pop-out":"Ctrl+Shift+L to toggle"}function gt(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function Se(t){return t.duration===void 0?"running":`${Math.round(t.duration)}ms`}function ye(t,e){const n=t.textContent;t.textContent=e?"✓":"✗",t.disabled=!0,setTimeout(()=>{t.textContent=n,t.disabled=!1},1e3)}const i={initialized:!1,visible:!1,host:null,shadow:null,container:null,logsList:null,filterBar:null,toggleBtn:null,badge:null,unsubscribe:null,spanUnsubscribe:null,channelUnsubscribe:null,filter:z()};function ut(t){const e=document.createElement("style");if(e.textContent=Je,t.appendChild(e),u.getConfig().showToggleButton){const s=document.createElement("button");s.className="devlogger-toggle",s.innerHTML="📋",s.title=ae()==="popout"?"Toggle DevLogger":"Toggle DevLogger (Ctrl+Shift+L)",s.addEventListener("click",()=>T.toggle()),t.appendChild(s),i.toggleBtn=s}const n=document.createElement("div");n.className="devlogger-container hidden";const o=u.getLogs(),r=V(o,i.filter);n.innerHTML=`
1902
+ `}function ye(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}const ee={key:"l",ctrlKey:!0,shiftKey:!0};function le(){return g.getConfig().shortcutAction==="popout"?"popout":"toggle"}function pt(){return le()==="popout"?"Ctrl+Shift+L to open pop-out":"Ctrl+Shift+L to toggle"}function ft(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function ke(t){return t.duration===void 0?"running":`${Math.round(t.duration)}ms`}function xe(t,e){const n=t.textContent;t.textContent=e?"✓":"✗",t.disabled=!0,setTimeout(()=>{t.textContent=n,t.disabled=!1},1e3)}const r={initialized:!1,visible:!1,host:null,shadow:null,container:null,logsList:null,filterBar:null,toggleBtn:null,badge:null,resourceContainer:null,resourceStatus:null,resourceMetrics:null,resourceNote:null,resourceHeapUsed:null,resourceHeapTotal:null,resourceHeapLimit:null,resourceVisible:!1,resourceInterval:null,resourceSupported:typeof performance<"u"&&"memory"in performance,unsubscribe:null,spanUnsubscribe:null,channelUnsubscribe:null,filter:O()};function ht(t){const e=document.createElement("style");if(e.textContent=Ke,t.appendChild(e),g.getConfig().showToggleButton){const i=document.createElement("button");i.className="devlogger-toggle",i.innerHTML="📋",i.title=le()==="popout"?"Toggle DevLogger":"Toggle DevLogger (Ctrl+Shift+L)",i.addEventListener("click",()=>T.toggle()),t.appendChild(i),r.toggleBtn=i}const n=document.createElement("div");n.className="devlogger-container hidden";const o=g.getLogs(),s=V(o,r.filter);n.innerHTML=`
1737
1903
  <div class="devlogger-header">
1738
1904
  <div class="devlogger-title">
1739
1905
  DevLogger
1740
- <span class="devlogger-badge">${r.length}</span>
1906
+ <span class="devlogger-badge">${s.length}</span>
1741
1907
  </div>
1742
1908
  <div class="devlogger-actions">
1743
1909
  <button class="devlogger-btn" data-action="copy-json" title="Copy as JSON">JSON</button>
1744
1910
  <button class="devlogger-btn" data-action="copy-text" title="Copy as Text">TXT</button>
1745
1911
  <button class="devlogger-btn" data-action="clear" title="Clear logs">Clear</button>
1912
+ <button class="devlogger-btn" data-action="resources" title="Toggle Resource Monitor">Resources</button>
1746
1913
  <button class="devlogger-btn devlogger-btn-primary" data-action="popout" title="Open in new window">Pop-out</button>
1747
1914
  <button class="devlogger-btn" data-action="close" title="Close">✕</button>
1748
1915
  </div>
1749
1916
  </div>
1917
+ <div class="resource-container" id="devlogger-resources">
1918
+ <div class="resource-header">
1919
+ <span>Resource Monitor</span>
1920
+ <span class="resource-status" id="devlogger-resources-status"></span>
1921
+ </div>
1922
+ <div class="resource-metrics" id="devlogger-resources-metrics">
1923
+ <span class="resource-label">JS Heap Used</span>
1924
+ <span class="resource-value" id="devlogger-heap-used">-</span>
1925
+ <span class="resource-label">JS Heap Total</span>
1926
+ <span class="resource-value" id="devlogger-heap-total">-</span>
1927
+ <span class="resource-label">JS Heap Limit</span>
1928
+ <span class="resource-value" id="devlogger-heap-limit">-</span>
1929
+ </div>
1930
+ <div class="resource-note" id="devlogger-resources-note" style="display: none;">
1931
+ Resource metrics are available only in Chrome.
1932
+ </div>
1933
+ </div>
1750
1934
  <div class="filter-bar-container"></div>
1751
1935
  <div class="devlogger-logs"></div>
1752
1936
  <div class="devlogger-footer">
1753
1937
  <span class="devlogger-log-count">${o.length} logs</span>
1754
- <span class="devlogger-shortcut">${dt()}</span>
1938
+ <span class="devlogger-shortcut">${pt()}</span>
1755
1939
  </div>
1756
- `,i.badge=n.querySelector(".devlogger-badge"),i.logsList=n.querySelector(".devlogger-logs"),i.filterBar=n.querySelector(".filter-bar-container"),n.querySelectorAll("[data-action]").forEach(s=>{s.addEventListener("click",a=>{const l=a.currentTarget.dataset.action,c=a.currentTarget;switch(l){case"clear":u.clear(),N.sendClear(),y();break;case"popout":T.popout();break;case"close":T.close();break;case"copy-json":u.copyLogs({format:"json"}).then(d=>{ye(c,d)});break;case"copy-text":u.copyLogs({format:"text"}).then(d=>{ye(c,d)});break}})}),t.appendChild(n),i.container=n,R(),y()}function R(){if(!i.filterBar)return;const t=u.getLogs(),e=V(t,i.filter);i.filterBar.innerHTML=ct(i.filter,t.length,e.length),ft()}function ft(){if(!i.filterBar)return;i.filterBar.querySelectorAll(".filter-level-btn").forEach(o=>{o.addEventListener("click",r=>{const s=r.currentTarget.dataset.level;i.filter.levels.has(s)?i.filter.levels.delete(s):i.filter.levels.add(s),R(),y()})});const t=i.filterBar.querySelector('[data-filter="search"]');t&&t.addEventListener("input",o=>{i.filter.search=o.target.value,oe(),y()});const e=i.filterBar.querySelector('[data-filter="file"]');e&&e.addEventListener("input",o=>{i.filter.file=o.target.value,oe(),y()});const n=i.filterBar.querySelector(".filter-clear-btn");n&&n.addEventListener("click",()=>{i.filter=z(),R(),y()})}function y(){if(!i.logsList)return;const t=u.getLogs(),e=V(t,i.filter);if(i.logsList.innerHTML="",t.length===0)i.logsList.appendChild(tt());else if(e.length===0){const n=document.createElement("div");n.className="devlogger-no-results",n.innerHTML=`
1940
+ `,r.badge=n.querySelector(".devlogger-badge"),r.logsList=n.querySelector(".devlogger-logs"),r.filterBar=n.querySelector(".filter-bar-container"),r.resourceContainer=n.querySelector("#devlogger-resources"),r.resourceStatus=n.querySelector("#devlogger-resources-status"),r.resourceMetrics=n.querySelector("#devlogger-resources-metrics"),r.resourceNote=n.querySelector("#devlogger-resources-note"),r.resourceHeapUsed=n.querySelector("#devlogger-heap-used"),r.resourceHeapTotal=n.querySelector("#devlogger-heap-total"),r.resourceHeapLimit=n.querySelector("#devlogger-heap-limit"),n.querySelectorAll("[data-action]").forEach(i=>{i.addEventListener("click",a=>{const l=a.currentTarget.dataset.action,c=a.currentTarget;switch(l){case"clear":g.clear(),A.sendClear(),y();break;case"resources":vt(c);break;case"popout":T.popout();break;case"close":T.close();break;case"copy-json":g.copyLogs({format:"json"}).then(d=>{xe(c,d)});break;case"copy-text":g.copyLogs({format:"text"}).then(d=>{xe(c,d)});break}})}),t.appendChild(n),r.container=n,R(),y()}function te(t){return Number.isFinite(t)?`${(t/(1024*1024)).toFixed(1)} MB`:"-"}function mt(){!r.resourceStatus||!r.resourceMetrics||!r.resourceNote||(r.resourceSupported?(r.resourceStatus.textContent="Chrome API",r.resourceMetrics.style.display="grid",r.resourceNote.style.display="none"):(r.resourceStatus.textContent="Unsupported",r.resourceMetrics.style.display="none",r.resourceNote.style.display="block"))}function we(){if(!r.resourceSupported)return;const t=performance.memory;!t||!r.resourceHeapUsed||!r.resourceHeapTotal||!r.resourceHeapLimit||(r.resourceHeapUsed.textContent=te(t.usedJSHeapSize),r.resourceHeapTotal.textContent=te(t.totalJSHeapSize),r.resourceHeapLimit.textContent=te(t.jsHeapSizeLimit))}function bt(){r.resourceInterval||!r.resourceSupported||(we(),r.resourceInterval=window.setInterval(we,1e3))}function Ee(){r.resourceInterval&&(clearInterval(r.resourceInterval),r.resourceInterval=null)}function vt(t){r.resourceContainer&&(r.resourceVisible=!r.resourceVisible,r.resourceContainer.style.display=r.resourceVisible?"block":"none",t&&t.classList.toggle("active",r.resourceVisible),r.resourceVisible?(mt(),bt()):Ee())}function R(){if(!r.filterBar)return;const t=g.getLogs(),e=V(t,r.filter);r.filterBar.innerHTML=gt(r.filter,t.length,e.length),yt()}function yt(){if(!r.filterBar)return;r.filterBar.querySelectorAll(".filter-level-btn").forEach(o=>{o.addEventListener("click",s=>{const i=s.currentTarget.dataset.level;r.filter.levels.has(i)?r.filter.levels.delete(i):r.filter.levels.add(i),R(),y()})});const t=r.filterBar.querySelector('[data-filter="search"]');t&&t.addEventListener("input",o=>{r.filter.search=o.target.value,oe(),y()});const e=r.filterBar.querySelector('[data-filter="file"]');e&&e.addEventListener("input",o=>{r.filter.file=o.target.value,oe(),y()});const n=r.filterBar.querySelector(".filter-clear-btn");n&&n.addEventListener("click",()=>{r.filter=O(),R(),y()})}function y(){if(!r.logsList)return;const t=g.getLogs(),e=V(t,r.filter);if(r.logsList.innerHTML="",t.length===0)r.logsList.appendChild(ot());else if(e.length===0){const n=document.createElement("div");n.className="devlogger-no-results",n.innerHTML=`
1757
1941
  <span class="devlogger-no-results-icon">🔍</span>
1758
1942
  <span class="devlogger-no-results-text">No logs match your filter</span>
1759
- `,i.logsList.appendChild(n)}else{const n=document.createDocumentFragment(),o=new Map,r=new Map,s=new Map;for(const a of e){if(!a.spanId){n.appendChild(J(a));continue}let l=o.get(a.spanId);if(!l){const d=u.getSpan(a.spanId);l=ke(a.spanId,d),o.set(a.spanId,l);const f=l.querySelector(".span-logs");f&&r.set(a.spanId,f),n.appendChild(l)}const c=r.get(a.spanId);c&&c.appendChild(J(a)),s.set(a.spanId,(s.get(a.spanId)??0)+1)}for(const[a,l]of s){const d=o.get(a)?.querySelector(".span-count");d&&(d.textContent=`${l} log${l===1?"":"s"}`)}i.logsList.appendChild(n)}Ce(e.length,t.length),le()}function pt(t){if(!i.logsList)return;const e=u.getLogs(),n=V(e,i.filter);if(n.some(r=>r.id===t.id)){const r=i.logsList.querySelector(".devlogger-empty, .devlogger-no-results");if(r&&r.remove(),t.spanId){let s=i.logsList.querySelector(`.span-group[data-span-id="${t.spanId}"]`);if(!s){const l=u.getSpan(t.spanId);s=ke(t.spanId,l),i.logsList.appendChild(s)}const a=s.querySelector(".span-logs");a&&(a.appendChild(J(t)),ht(s,a))}else i.logsList.appendChild(J(t))}Ce(n.length,e.length),oe(),le()}function Ce(t,e){i.badge&&(i.badge.textContent=String(t));const n=i.container?.querySelector(".devlogger-log-count");n&&(ie(i.filter)?n.textContent=`${t} of ${e} logs`:n.textContent=`${e} logs`)}function oe(){if(!i.filterBar)return;const t=u.getLogs(),e=V(t,i.filter),n=ie(i.filter),o=i.filterBar.querySelector(".filter-bar");o&&o.classList.toggle("filter-active",n);let r=i.filterBar.querySelector(".filter-status");if(n){r||(r=document.createElement("div"),r.className="filter-status",o?.appendChild(r)),r.textContent=`Showing ${e.length} of ${t.length} logs`;let s=i.filterBar.querySelector(".filter-clear-btn");s||(s=document.createElement("button"),s.className="filter-clear-btn",s.setAttribute("title","Clear filters"),s.textContent="✕",s.addEventListener("click",()=>{i.filter=z(),R(),y()}),i.filterBar.querySelector(".filter-row")?.appendChild(s))}else r?.remove(),i.filterBar.querySelector(".filter-clear-btn")?.remove()}function le(){i.logsList&&i.visible&&(i.logsList.scrollTop=i.logsList.scrollHeight)}function ht(t,e){const n=t.querySelector(".span-count");if(n){const o=e.querySelectorAll(".log-entry").length;n.textContent=`${o} log${o===1?"":"s"}`}}function ke(t,e){const n=document.createElement("div");n.className="span-group",n.dataset.spanId=t;const o=e?.name??"Span",r=e?.status??"running",s=e?Se(e):"running",a=document.createElement("div");a.className="span-header",a.innerHTML=`
1943
+ `,r.logsList.appendChild(n)}else{const n=document.createDocumentFragment(),o=new Map,s=new Map,i=new Map;for(const a of e){if(!a.spanId){n.appendChild(G(a));continue}let l=o.get(a.spanId);if(!l){const d=g.getSpan(a.spanId);l=Te(a.spanId,d),o.set(a.spanId,l);const p=l.querySelector(".span-logs");p&&s.set(a.spanId,p),n.appendChild(l)}const c=s.get(a.spanId);c&&c.appendChild(G(a)),i.set(a.spanId,(i.get(a.spanId)??0)+1)}for(const[a,l]of i){const d=o.get(a)?.querySelector(".span-count");d&&(d.textContent=`${l} log${l===1?"":"s"}`)}r.logsList.appendChild(n)}$e(e.length,t.length),ce()}function xt(t){if(!r.logsList)return;const e=g.getLogs(),n=V(e,r.filter);if(n.some(s=>s.id===t.id)){const s=r.logsList.querySelector(".devlogger-empty, .devlogger-no-results");if(s&&s.remove(),t.spanId){let i=r.logsList.querySelector(`.span-group[data-span-id="${t.spanId}"]`);if(!i){const l=g.getSpan(t.spanId);i=Te(t.spanId,l),r.logsList.appendChild(i)}const a=i.querySelector(".span-logs");a&&(a.appendChild(G(t)),wt(i,a))}else r.logsList.appendChild(G(t))}$e(n.length,e.length),oe(),ce()}function $e(t,e){r.badge&&(r.badge.textContent=String(t));const n=r.container?.querySelector(".devlogger-log-count");n&&(ae(r.filter)?n.textContent=`${t} of ${e} logs`:n.textContent=`${e} logs`)}function oe(){if(!r.filterBar)return;const t=g.getLogs(),e=V(t,r.filter),n=ae(r.filter),o=r.filterBar.querySelector(".filter-bar");o&&o.classList.toggle("filter-active",n);let s=r.filterBar.querySelector(".filter-status");if(n){s||(s=document.createElement("div"),s.className="filter-status",o?.appendChild(s)),s.textContent=`Showing ${e.length} of ${t.length} logs`;let i=r.filterBar.querySelector(".filter-clear-btn");i||(i=document.createElement("button"),i.className="filter-clear-btn",i.setAttribute("title","Clear filters"),i.textContent="✕",i.addEventListener("click",()=>{r.filter=O(),R(),y()}),r.filterBar.querySelector(".filter-row")?.appendChild(i))}else s?.remove(),r.filterBar.querySelector(".filter-clear-btn")?.remove()}function ce(){r.logsList&&r.visible&&(r.logsList.scrollTop=r.logsList.scrollHeight)}function wt(t,e){const n=t.querySelector(".span-count");if(n){const o=e.querySelectorAll(".log-entry").length;n.textContent=`${o} log${o===1?"":"s"}`}}function Te(t,e){const n=document.createElement("div");n.className="span-group",n.dataset.spanId=t;const o=e?.name??"Span",s=e?.status??"running",i=e?ke(e):"running",a=document.createElement("div");a.className="span-header",a.innerHTML=`
1760
1944
  <button class="span-toggle" type="button" aria-label="Toggle span logs"></button>
1761
- <span class="span-title">${gt(o)}</span>
1762
- <span class="span-status span-status-${r}">${r}</span>
1763
- <span class="span-duration">${s}</span>
1945
+ <span class="span-title">${ft(o)}</span>
1946
+ <span class="span-status span-status-${s}">${s}</span>
1947
+ <span class="span-duration">${i}</span>
1764
1948
  <span class="span-count">0 logs</span>
1765
- `;const l=document.createElement("div");l.className="span-logs",u.getConfig().spanCollapsed&&n.classList.add("collapsed");const c=a.querySelector(".span-toggle"),d=()=>{n.classList.toggle("collapsed")};return a.addEventListener("click",f=>{f.target?.closest(".span-toggle")||d()}),c?.addEventListener("click",()=>d()),n.appendChild(a),n.appendChild(l),n}function bt(t){const e=i.logsList?.querySelector(`.span-group[data-span-id="${t.id}"]`);if(!e)return;const n=e.querySelector(".span-title");n&&(n.textContent=t.name);const o=e.querySelector(".span-status");o&&(o.textContent=t.status,o.className=`span-status span-status-${t.status}`);const r=e.querySelector(".span-duration");r&&(r.textContent=Se(t))}function xe(t){t.key.toLowerCase()===ee.key&&t.ctrlKey===ee.ctrlKey&&t.shiftKey===ee.shiftKey&&(t.preventDefault(),ae()==="popout"?T.popout():T.toggle())}function mt(t){switch(t.type){case"CLEAR_LOGS":u.clear(),y();break;case"SYNC_REQUEST":N.sendSyncResponse(u.getLogs());break}}const T={init(){try{if(i.initialized||!u.isEnabled()||typeof document>"u")return;const t=document.createElement("div");t.id="devlogger-host",document.body.appendChild(t),i.host=t;const e=t.attachShadow({mode:"open"});i.shadow=e,ut(e),i.unsubscribe=u.subscribe(n=>{pt(n),N.sendLog(n)}),i.spanUnsubscribe=u.subscribeSpans(n=>{bt(n)}),i.channelUnsubscribe=N.subscribe(mt),document.addEventListener("keydown",xe),i.initialized=!0}catch(t){console.warn("[DevLogger UI] Init error:",t)}},open(){try{i.initialized||this.init(),i.container&&(i.container.classList.remove("hidden"),i.visible=!0,le())}catch{}},close(){try{i.container&&(i.container.classList.add("hidden"),i.visible=!1)}catch{}},toggle(){i.visible?this.close():this.open()},popout(){try{i.initialized||this.init(),st()}catch(t){console.warn("[DevLogger] Failed to open pop-out:",t)}},closePopout(){me()},isPopoutOpen(){return it()},setFilter(t){try{t.levels!==void 0&&(i.filter.levels=t.levels),t.search!==void 0&&(i.filter.search=t.search),t.file!==void 0&&(i.filter.file=t.file),R(),y()}catch{}},getFilter(){return{...i.filter,levels:new Set(i.filter.levels)}},clearFilter(){try{i.filter=z(),R(),y()}catch{}},destroy(){try{me(),i.unsubscribe&&(i.unsubscribe(),i.unsubscribe=null),i.spanUnsubscribe&&(i.spanUnsubscribe(),i.spanUnsubscribe=null),i.channelUnsubscribe&&(i.channelUnsubscribe(),i.channelUnsubscribe=null),document.removeEventListener("keydown",xe),i.host&&(i.host.remove(),i.host=null),i.initialized=!1,i.visible=!1,i.shadow=null,i.container=null,i.logsList=null,i.filterBar=null,i.toggleBtn=null,i.badge=null,i.spanUnsubscribe=null,i.filter=z()}catch{}},isVisible(){return i.visible},isInitialized(){return i.initialized}},$e={captureErrors:!0,captureRejections:!0,errorPrefix:"[Uncaught Error]",rejectionPrefix:"[Unhandled Rejection]"};let P=!1,L={...$e},q=null,H=null;function vt(t,e,n,o,r){try{const s=r||(t instanceof ErrorEvent?t.error:null),a=s?.message||String(t),l=s?.stack;u.error(`${L.errorPrefix} ${a}`,{source:e||"unknown",line:n||0,column:o||0,stack:l,originalError:s?{name:s.name,message:s.message,stack:s.stack}:void 0})}catch{}if(q)try{return q(t,e,n,o,r)??!1}catch{}return!1}function yt(t){try{const e=t.reason;let n,o={};e instanceof Error?(n=e.message,o={name:e.name,message:e.message,stack:e.stack}):typeof e=="string"?n=e:(n="Unknown rejection reason",o={reason:e}),u.error(`${L.rejectionPrefix} ${n}`,o)}catch{}}function xt(t={}){if(P){L={...L,...t};return}try{if(typeof window>"u")return;L={...$e,...t},q=window.onerror,L.captureErrors&&(window.onerror=vt),L.captureRejections&&(H=yt,window.addEventListener("unhandledrejection",H)),P=!0}catch{}}function wt(){if(P)try{if(typeof window>"u")return;window.onerror=q,H&&window.removeEventListener("unhandledrejection",H),q=null,H=null,P=!1}catch{}}function Lt(){return P}function St(){return{...L}}const Ct={install:xt,uninstall:wt,isActive:Lt,getConfig:St},X="devlogger_persisted_logs",ce="devlogger_session_active",Ee={storage:"session",maxPersisted:500,debounceMs:100};let D=!1,S={...Ee},U=[],x=null,de=!1,W=null;function k(){try{return typeof window>"u"?null:S.storage==="local"?localStorage:sessionStorage}catch{return null}}function kt(){try{const t=k();return t?t.getItem(ce)==="active":!1}catch{return!1}}function $t(){try{const t=k();if(!t)return;t.setItem(ce,"active")}catch{}}function Te(){try{const t=k();if(!t)return;t.removeItem(ce)}catch{}}function Ie(t){try{const e=k();if(!e)return;const n=t.slice(-S.maxPersisted),o=JSON.stringify(n);e.setItem(X,o)}catch(e){if(e instanceof DOMException&&e.name==="QuotaExceededError")try{const n=k();if(!n)return;const o=t.slice(-Math.floor(S.maxPersisted/2));n.setItem(X,JSON.stringify(o))}catch{}}}function Re(){try{const t=k();if(!t)return[];const e=t.getItem(X);if(!e)return[];const n=JSON.parse(e);return Array.isArray(n)?n.filter(o=>o&&typeof o.id=="string"&&typeof o.timestamp=="number"&&typeof o.level=="string"&&typeof o.message=="string"):[]}catch{return[]}}function Et(){try{const t=k();if(!t)return;t.removeItem(X)}catch{}}function Tt(t){U=t,x&&clearTimeout(x),x=setTimeout(()=>{Ie(U),x=null},S.debounceMs)}function Y(){try{x&&(clearTimeout(x),x=null),U.length>0&&Ie(U),Te()}catch{}}function It(){if(!D)return;const t=u.getLogs();Tt([...t])}function Rt(t={}){if(D){S={...S,...t};return}try{if(typeof window>"u")return;S={...Ee,...t},de=kt(),$t(),W=u.subscribe(It),window.addEventListener("beforeunload",Y),window.addEventListener("pagehide",Y),D=!0}catch{}}function Dt(){if(D)try{if(typeof window>"u")return;x&&(clearTimeout(x),x=null),W&&(W(),W=null),window.removeEventListener("beforeunload",Y),window.removeEventListener("pagehide",Y),Te(),D=!1}catch{}}function _t(){return de}function Mt(){return Re()}function Bt(){try{const t=Re();return t.length===0?0:(u.importLogs(t),t.length)}catch{return 0}}function Ft(){Et(),U=[],de=!1}function At(){return D}function Ht(){return{...S}}const Ot={enable:Rt,disable:Dt,isActive:At,hadCrash:_t,getPersistedLogs:Mt,rehydrate:Bt,clear:Ft,getConfig:Ht},De={captureFetch:!0,captureXHR:!0,includeHeaders:!1,includeBody:!1,includeResponse:!1,maxResponseLength:1e3,ignorePatterns:[],context:{}};let E=null,O=null,I=null,F=!1,m={...De};function _e(t){for(const e of m.ignorePatterns)if(typeof e=="string"){if(t.includes(e))return!0}else if(e.test(t))return!0;return!1}function Me(t){try{const e=new URL(t,window.location.origin);return{host:e.host,path:e.pathname+e.search,full:e.href}}catch{return{host:"unknown",path:t,full:t}}}function Be(t,e){return t.length<=e?t:t.slice(0,e)+"... (truncated)"}function K(t){try{return JSON.parse(t)}catch{return t}}function Nt(){return async function(e,n){const o=typeof e=="string"?e:e instanceof URL?e.href:e.url;if(_e(o))return E(e,n);const{host:r,path:s}=Me(o),a=n?.method||"GET",l=`${a} ${s}`,c=u.span(l,{...m.context,type:"fetch",method:a,host:r});if(c.info(`Request started: ${o}`),m.includeHeaders&&n?.headers&&c.debug("Request headers",n.headers),m.includeBody&&n?.body)try{const f=typeof n.body=="string"?K(n.body):n.body;c.debug("Request body",f)}catch{c.debug("Request body","[Unable to parse]")}const d=performance.now();try{const f=await E(e,n),h=Math.round(performance.now()-d);if(f.ok){if(c.info(`Response: ${f.status} ${f.statusText} (${h}ms)`),m.includeResponse)try{const Q=await f.clone().text(),v=K(Be(Q,m.maxResponseLength));c.debug("Response body",v)}catch{c.debug("Response body","[Unable to read]")}c.end()}else c.warn(`Response: ${f.status} ${f.statusText} (${h}ms)`),c.fail();return f}catch(f){const h=Math.round(performance.now()-d);throw c.error(`Request failed after ${h}ms`,f),c.fail(),f}}}function zt(){O=XMLHttpRequest.prototype.open,I=XMLHttpRequest.prototype.send,XMLHttpRequest.prototype.open=function(t,e,n=!0,o,r){const s=typeof e=="string"?e:e.href;return this.__networkCapture={method:t,url:s,ignored:_e(s)},O.call(this,t,e,n,o,r)},XMLHttpRequest.prototype.send=function(t){const e=this.__networkCapture;if(!e||e.ignored)return I.call(this,t);const{method:n,url:o}=e,{host:r,path:s}=Me(o),a=`${n} ${s}`,l=u.span(a,{...m.context,type:"xhr",method:n,host:r});if(l.info(`XHR Request started: ${o}`),m.includeBody&&t)try{const d=typeof t=="string"?K(t):t;l.debug("Request body",d)}catch{l.debug("Request body","[Unable to parse]")}const c=performance.now();return this.addEventListener("load",()=>{const d=Math.round(performance.now()-c);if(this.status>=200&&this.status<400){if(l.info(`Response: ${this.status} ${this.statusText} (${d}ms)`),m.includeResponse&&this.responseText){const f=K(Be(this.responseText,m.maxResponseLength));l.debug("Response body",f)}l.end()}else l.warn(`Response: ${this.status} ${this.statusText} (${d}ms)`),l.fail()}),this.addEventListener("error",()=>{const d=Math.round(performance.now()-c);l.error(`XHR Request failed after ${d}ms`),l.fail()}),this.addEventListener("abort",()=>{const d=Math.round(performance.now()-c);l.warn(`XHR Request aborted after ${d}ms`),l.fail()}),this.addEventListener("timeout",()=>{const d=Math.round(performance.now()-c);l.error(`XHR Request timeout after ${d}ms`),l.fail()}),I.call(this,t)}}function Pt(){O&&(XMLHttpRequest.prototype.open=O,O=null),I&&(XMLHttpRequest.prototype.send=I,I=null)}const qt={install(t={}){try{if(F)return;m={...De,...t},m.captureFetch&&typeof globalThis.fetch=="function"&&(E=globalThis.fetch,globalThis.fetch=Nt()),m.captureXHR&&typeof XMLHttpRequest<"u"&&zt(),F=!0,u.debug("[NetworkCapture] Installed",{fetch:m.captureFetch,xhr:m.captureXHR})}catch(e){console.warn("[NetworkCapture] Install error:",e)}},uninstall(){try{if(!F)return;E&&(globalThis.fetch=E,E=null),Pt(),F=!1,u.debug("[NetworkCapture] Uninstalled")}catch(t){console.warn("[NetworkCapture] Uninstall error:",t)}},isActive(){return F},getConfig(){return{...m}},addIgnorePattern(t){m.ignorePatterns.push(t)}},Ut={debug:"#6e6e6e",info:"#3794ff",warn:"#cca700",error:"#f14c4c"},Vt={running:"#3794ff",success:"#4caf50",error:"#f14c4c"};class Fe{constructor(e){p(this,"container");p(this,"config");p(this,"canvas",null);p(this,"ctx",null);p(this,"intervalId",null);p(this,"tooltip",null);p(this,"spanBounds",new Map);p(this,"logBounds",new Map);const n=typeof e.container=="string"?document.querySelector(e.container):e.container;if(!n)throw new Error("Timeline: Container not found");this.container=n,this.config={container:n,timeWindow:e.timeWindow??6e4,refreshInterval:e.refreshInterval??1e3,showSpans:e.showSpans??!0,showLogs:e.showLogs??!0,height:e.height??200},this.init()}init(){this.container.innerHTML=`
1949
+ `;const l=document.createElement("div");l.className="span-logs",g.getConfig().spanCollapsed&&n.classList.add("collapsed");const c=a.querySelector(".span-toggle"),d=()=>{n.classList.toggle("collapsed")};return a.addEventListener("click",p=>{p.target?.closest(".span-toggle")||d()}),c?.addEventListener("click",()=>d()),n.appendChild(a),n.appendChild(l),n}function Lt(t){const e=r.logsList?.querySelector(`.span-group[data-span-id="${t.id}"]`);if(!e)return;const n=e.querySelector(".span-title");n&&(n.textContent=t.name);const o=e.querySelector(".span-status");o&&(o.textContent=t.status,o.className=`span-status span-status-${t.status}`);const s=e.querySelector(".span-duration");s&&(s.textContent=ke(t))}function Le(t){t.key.toLowerCase()===ee.key&&t.ctrlKey===ee.ctrlKey&&t.shiftKey===ee.shiftKey&&(t.preventDefault(),le()==="popout"?T.popout():T.toggle())}function St(t){switch(t.type){case"CLEAR_LOGS":g.clear(),y();break;case"SYNC_REQUEST":A.sendSyncResponse(g.getLogs());break}}const T={init(){try{if(r.initialized||!g.isEnabled()||typeof document>"u")return;const t=document.createElement("div");t.id="devlogger-host",document.body.appendChild(t),r.host=t;const e=t.attachShadow({mode:"open"});r.shadow=e,ht(e),r.unsubscribe=g.subscribe(n=>{xt(n),A.sendLog(n)}),r.spanUnsubscribe=g.subscribeSpans(n=>{Lt(n)}),r.channelUnsubscribe=A.subscribe(St),document.addEventListener("keydown",Le),r.initialized=!0}catch(t){console.warn("[DevLogger UI] Init error:",t)}},open(){try{r.initialized||this.init(),r.container&&(r.container.classList.remove("hidden"),r.visible=!0,ce())}catch{}},close(){try{r.container&&(r.container.classList.add("hidden"),r.visible=!1)}catch{}},toggle(){r.visible?this.close():this.open()},popout(){try{r.initialized||this.init(),lt()}catch(t){console.warn("[DevLogger] Failed to open pop-out:",t)}},closePopout(){ve()},isPopoutOpen(){return ct()},setFilter(t){try{t.levels!==void 0&&(r.filter.levels=t.levels),t.search!==void 0&&(r.filter.search=t.search),t.file!==void 0&&(r.filter.file=t.file),R(),y()}catch{}},getFilter(){return{...r.filter,levels:new Set(r.filter.levels)}},clearFilter(){try{r.filter=O(),R(),y()}catch{}},destroy(){try{ve(),r.unsubscribe&&(r.unsubscribe(),r.unsubscribe=null),r.spanUnsubscribe&&(r.spanUnsubscribe(),r.spanUnsubscribe=null),Ee(),r.channelUnsubscribe&&(r.channelUnsubscribe(),r.channelUnsubscribe=null),document.removeEventListener("keydown",Le),r.host&&(r.host.remove(),r.host=null),r.initialized=!1,r.visible=!1,r.shadow=null,r.container=null,r.logsList=null,r.filterBar=null,r.toggleBtn=null,r.badge=null,r.resourceContainer=null,r.resourceStatus=null,r.resourceMetrics=null,r.resourceNote=null,r.resourceHeapUsed=null,r.resourceHeapTotal=null,r.resourceHeapLimit=null,r.resourceVisible=!1,r.resourceInterval=null,r.spanUnsubscribe=null,r.filter=O()}catch{}},isVisible(){return r.visible},isInitialized(){return r.initialized}},Ie={captureErrors:!0,captureRejections:!0,errorPrefix:"[Uncaught Error]",rejectionPrefix:"[Unhandled Rejection]"};let U=!1,L={...Ie},P=null,N=null;function Ct(t,e,n,o,s){try{const i=s||(t instanceof ErrorEvent?t.error:null),a=i?.message||String(t),l=i?.stack;g.error(`${L.errorPrefix} ${a}`,{source:e||"unknown",line:n||0,column:o||0,stack:l,originalError:i?{name:i.name,message:i.message,stack:i.stack}:void 0})}catch{}if(P)try{return P(t,e,n,o,s)??!1}catch{}return!1}function kt(t){try{const e=t.reason;let n,o={};e instanceof Error?(n=e.message,o={name:e.name,message:e.message,stack:e.stack}):typeof e=="string"?n=e:(n="Unknown rejection reason",o={reason:e}),g.error(`${L.rejectionPrefix} ${n}`,o)}catch{}}function Et(t={}){if(U){L={...L,...t};return}try{if(typeof window>"u")return;L={...Ie,...t},P=window.onerror,L.captureErrors&&(window.onerror=Ct),L.captureRejections&&(N=kt,window.addEventListener("unhandledrejection",N)),U=!0}catch{}}function $t(){if(U)try{if(typeof window>"u")return;window.onerror=P,N&&window.removeEventListener("unhandledrejection",N),P=null,N=null,U=!1}catch{}}function Tt(){return U}function It(){return{...L}}const Rt={install:Et,uninstall:$t,isActive:Tt,getConfig:It},X="devlogger_persisted_logs",de="devlogger_session_active",Re={storage:"session",maxPersisted:500,debounceMs:100};let M=!1,S={...Re},q=[],x=null,ue=!1,W=null;function k(){try{return typeof window>"u"?null:S.storage==="local"?localStorage:sessionStorage}catch{return null}}function Mt(){try{const t=k();return t?t.getItem(de)==="active":!1}catch{return!1}}function Ht(){try{const t=k();if(!t)return;t.setItem(de,"active")}catch{}}function Me(){try{const t=k();if(!t)return;t.removeItem(de)}catch{}}function He(t){try{const e=k();if(!e)return;const n=t.slice(-S.maxPersisted),o=JSON.stringify(n);e.setItem(X,o)}catch(e){if(e instanceof DOMException&&e.name==="QuotaExceededError")try{const n=k();if(!n)return;const o=t.slice(-Math.floor(S.maxPersisted/2));n.setItem(X,JSON.stringify(o))}catch{}}}function De(){try{const t=k();if(!t)return[];const e=t.getItem(X);if(!e)return[];const n=JSON.parse(e);return Array.isArray(n)?n.filter(o=>o&&typeof o.id=="string"&&typeof o.timestamp=="number"&&typeof o.level=="string"&&typeof o.message=="string"):[]}catch{return[]}}function Dt(){try{const t=k();if(!t)return;t.removeItem(X)}catch{}}function _t(t){q=t,x&&clearTimeout(x),x=setTimeout(()=>{He(q),x=null},S.debounceMs)}function Y(){try{x&&(clearTimeout(x),x=null),q.length>0&&He(q),Me()}catch{}}function Bt(){if(!M)return;const t=g.getLogs();_t([...t])}function zt(t={}){if(M){S={...S,...t};return}try{if(typeof window>"u")return;S={...Re,...t},ue=Mt(),Ht(),W=g.subscribe(Bt),window.addEventListener("beforeunload",Y),window.addEventListener("pagehide",Y),M=!0}catch{}}function Nt(){if(M)try{if(typeof window>"u")return;x&&(clearTimeout(x),x=null),W&&(W(),W=null),window.removeEventListener("beforeunload",Y),window.removeEventListener("pagehide",Y),Me(),M=!1}catch{}}function Ft(){return ue}function At(){return De()}function Ot(){try{const t=De();return t.length===0?0:(g.importLogs(t),t.length)}catch{return 0}}function Ut(){Dt(),q=[],ue=!1}function Pt(){return M}function qt(){return{...S}}const Vt={enable:zt,disable:Nt,isActive:Pt,hadCrash:Ft,getPersistedLogs:At,rehydrate:Ot,clear:Ut,getConfig:qt},_e={captureFetch:!0,captureXHR:!0,includeHeaders:!1,includeBody:!1,includeResponse:!1,maxResponseLength:1e3,ignorePatterns:[],context:{}};let $=null,F=null,I=null,B=!1,b={..._e};function Be(t){for(const e of b.ignorePatterns)if(typeof e=="string"){if(t.includes(e))return!0}else if(e.test(t))return!0;return!1}function ze(t){try{const e=new URL(t,window.location.origin);return{host:e.host,path:e.pathname+e.search,full:e.href}}catch{return{host:"unknown",path:t,full:t}}}function Ne(t,e){return t.length<=e?t:t.slice(0,e)+"... (truncated)"}function K(t){try{return JSON.parse(t)}catch{return t}}function jt(){return async function(e,n){const o=typeof e=="string"?e:e instanceof URL?e.href:e.url;if(Be(o))return $(e,n);const{host:s,path:i}=ze(o),a=n?.method||"GET",l=`${a} ${i}`,c=g.span(l,{...b.context,type:"fetch",method:a,host:s});if(c.info(`Request started: ${o}`),b.includeHeaders&&n?.headers&&c.debug("Request headers",n.headers),b.includeBody&&n?.body)try{const p=typeof n.body=="string"?K(n.body):n.body;c.debug("Request body",p)}catch{c.debug("Request body","[Unable to parse]")}const d=performance.now();try{const p=await $(e,n),h=Math.round(performance.now()-d);if(p.ok){if(c.info(`Response: ${p.status} ${p.statusText} (${h}ms)`),b.includeResponse)try{const Q=await p.clone().text(),v=K(Ne(Q,b.maxResponseLength));c.debug("Response body",v)}catch{c.debug("Response body","[Unable to read]")}c.end()}else c.warn(`Response: ${p.status} ${p.statusText} (${h}ms)`),c.fail();return p}catch(p){const h=Math.round(performance.now()-d);throw c.error(`Request failed after ${h}ms`,p),c.fail(),p}}}function Wt(){F=XMLHttpRequest.prototype.open,I=XMLHttpRequest.prototype.send,XMLHttpRequest.prototype.open=function(t,e,n=!0,o,s){const i=typeof e=="string"?e:e.href;return this.__networkCapture={method:t,url:i,ignored:Be(i)},F.call(this,t,e,n,o,s)},XMLHttpRequest.prototype.send=function(t){const e=this.__networkCapture;if(!e||e.ignored)return I.call(this,t);const{method:n,url:o}=e,{host:s,path:i}=ze(o),a=`${n} ${i}`,l=g.span(a,{...b.context,type:"xhr",method:n,host:s});if(l.info(`XHR Request started: ${o}`),b.includeBody&&t)try{const d=typeof t=="string"?K(t):t;l.debug("Request body",d)}catch{l.debug("Request body","[Unable to parse]")}const c=performance.now();return this.addEventListener("load",()=>{const d=Math.round(performance.now()-c);if(this.status>=200&&this.status<400){if(l.info(`Response: ${this.status} ${this.statusText} (${d}ms)`),b.includeResponse&&this.responseText){const p=K(Ne(this.responseText,b.maxResponseLength));l.debug("Response body",p)}l.end()}else l.warn(`Response: ${this.status} ${this.statusText} (${d}ms)`),l.fail()}),this.addEventListener("error",()=>{const d=Math.round(performance.now()-c);l.error(`XHR Request failed after ${d}ms`),l.fail()}),this.addEventListener("abort",()=>{const d=Math.round(performance.now()-c);l.warn(`XHR Request aborted after ${d}ms`),l.fail()}),this.addEventListener("timeout",()=>{const d=Math.round(performance.now()-c);l.error(`XHR Request timeout after ${d}ms`),l.fail()}),I.call(this,t)}}function Jt(){F&&(XMLHttpRequest.prototype.open=F,F=null),I&&(XMLHttpRequest.prototype.send=I,I=null)}const Gt={install(t={}){try{if(B)return;b={..._e,...t},b.captureFetch&&typeof globalThis.fetch=="function"&&($=globalThis.fetch,globalThis.fetch=jt()),b.captureXHR&&typeof XMLHttpRequest<"u"&&Wt(),B=!0,g.debug("[NetworkCapture] Installed",{fetch:b.captureFetch,xhr:b.captureXHR})}catch(e){console.warn("[NetworkCapture] Install error:",e)}},uninstall(){try{if(!B)return;$&&(globalThis.fetch=$,$=null),Jt(),B=!1,g.debug("[NetworkCapture] Uninstalled")}catch(t){console.warn("[NetworkCapture] Uninstall error:",t)}},isActive(){return B},getConfig(){return{...b}},addIgnorePattern(t){b.ignorePatterns.push(t)}},Xt={debug:"#6e6e6e",info:"#3794ff",warn:"#cca700",error:"#f14c4c"},Yt={running:"#3794ff",success:"#4caf50",error:"#f14c4c"};class Fe{constructor(e){f(this,"container");f(this,"config");f(this,"canvas",null);f(this,"ctx",null);f(this,"intervalId",null);f(this,"tooltip",null);f(this,"spanBounds",new Map);f(this,"logBounds",new Map);const n=typeof e.container=="string"?document.querySelector(e.container):e.container;if(!n)throw new Error("Timeline: Container not found");this.container=n,this.config={container:n,timeWindow:e.timeWindow??6e4,refreshInterval:e.refreshInterval??1e3,showSpans:e.showSpans??!0,showLogs:e.showLogs??!0,height:e.height??200},this.init()}init(){this.container.innerHTML=`
1766
1950
  <div class="devlogger-timeline" style="
1767
1951
  position: relative;
1768
1952
  background: #1e1e1e;
@@ -1842,12 +2026,12 @@
1842
2026
  pointer-events: none;
1843
2027
  "></div>
1844
2028
  </div>
1845
- `,this.canvas=this.container.querySelector(".timeline-canvas"),this.tooltip=this.container.querySelector(".timeline-tooltip"),this.canvas&&(this.ctx=this.canvas.getContext("2d"),this.resizeCanvas()),this.container.querySelectorAll("[data-window]").forEach(e=>{e.addEventListener("click",n=>{const o=n.currentTarget,r=parseInt(o.dataset.window||"60000",10);this.setTimeWindow(r),this.container.querySelectorAll("[data-window]").forEach(s=>{const a=s;a===o?(a.style.background="#0e639c",a.style.borderColor="#0e639c",a.style.color="white"):(a.style.background="transparent",a.style.borderColor="#3c3c3c",a.style.color="#858585")})})}),this.canvas&&(this.canvas.addEventListener("mousemove",this.handleMouseMove.bind(this)),this.canvas.addEventListener("mouseleave",this.handleMouseLeave.bind(this))),this.startRefresh()}resizeCanvas(){if(!this.canvas)return;const e=this.container.getBoundingClientRect();this.canvas.width=e.width-2,this.canvas.height=this.config.height,this.render()}startRefresh(){this.intervalId||(this.intervalId=window.setInterval(()=>this.render(),this.config.refreshInterval),this.render())}stopRefresh(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null)}setTimeWindow(e){this.config.timeWindow=e,this.render()}render(){if(!this.canvas||!this.ctx)return;const e=this.ctx,n=this.canvas.width,o=this.canvas.height,r=Date.now(),s=r-this.config.timeWindow;e.fillStyle="#1e1e1e",e.fillRect(0,0,n,o),this.spanBounds.clear(),this.logBounds.clear(),this.drawTimeGrid(e,n,o,s,r);const a=u.getLogs().filter(c=>c.timestamp>=s),l=u.getSpans().filter(c=>c.startTime>=s||c.endTime&&c.endTime>=s);this.config.showSpans&&this.drawSpans(e,l,n,o,s,r),this.config.showLogs&&this.drawLogs(e,a,n,o,s,r)}drawTimeGrid(e,n,o,r,s){const a=s-r,l=6;e.strokeStyle="#333",e.lineWidth=1,e.font="10px SF Mono, monospace",e.fillStyle="#666";for(let c=0;c<=l;c++){const d=c/l*n,f=r+a*c/l;e.beginPath(),e.moveTo(d,0),e.lineTo(d,o),e.stroke();const h=new Date(f),C=`${h.getMinutes().toString().padStart(2,"0")}:${h.getSeconds().toString().padStart(2,"0")}`;e.fillText(C,d+2,o-4)}}drawSpans(e,n,o,r,s,a){const l=a-s,c=20,d=4,f=20,h=n.filter(v=>!v.parentId);let C=f;const Q=(v,_,Gt=0)=>{const M=(v.startTime-s)/l*o,Ae=((v.endTime||a)-s)/l*o,j=Math.max(Ae-M,2),ge=Vt[v.status];e.fillStyle=ge+"40",e.fillRect(M,_,j,c),e.strokeStyle=ge,e.lineWidth=1,e.strokeRect(M,_,j,c),e.fillStyle="#ccc",e.font="10px SF Mono, monospace";const He=v.duration?`${v.name} (${v.duration}ms)`:v.name;return e.fillText(He,M+4,_+14,j-8),this.spanBounds.set(v.id,{x:M,y:_,w:j,h:c}),_+c+d};for(const v of h)C=Q(v,C)}drawLogs(e,n,o,r,s,a){const l=a-s,c=8,d=30;for(const f of n){const h=(f.timestamp-s)/l*o,C=Ut[f.level];e.fillStyle=C,e.beginPath(),e.moveTo(h,r-d),e.lineTo(h-c/2,r-d-c),e.lineTo(h+c/2,r-d-c),e.closePath(),e.fill(),this.logBounds.set(f.id,{x:h,y:r-d-c/2,r:c})}}handleMouseMove(e){if(!this.canvas||!this.tooltip)return;const n=this.canvas.getBoundingClientRect(),o=e.clientX-n.left,r=e.clientY-n.top;for(const s of u.getSpans()){const a=this.spanBounds.get(s.id);if(a&&o>=a.x&&o<=a.x+a.w&&r>=a.y&&r<=a.y+a.h){this.showTooltip(e,`
1846
- <strong>${s.name}</strong><br>
1847
- Status: ${s.status}<br>
1848
- ${s.duration!==void 0?`Duration: ${s.duration}ms`:"Running..."}<br>
1849
- ${s.context?`Context: ${JSON.stringify(s.context)}`:""}
1850
- `);return}}for(const s of u.getLogs()){const a=this.logBounds.get(s.id);if(a&&Math.sqrt((o-a.x)**2+(r-a.y)**2)<=a.r){this.showTooltip(e,`
1851
- <strong>[${s.level.toUpperCase()}]</strong> ${s.message}<br>
1852
- <small>${new Date(s.timestamp).toISOString()}</small>
1853
- `);return}}this.hideTooltip()}handleMouseLeave(){this.hideTooltip()}showTooltip(e,n){this.tooltip&&(this.tooltip.innerHTML=n,this.tooltip.style.display="block",this.tooltip.style.left=`${e.offsetX+10}px`,this.tooltip.style.top=`${e.offsetY+10}px`)}hideTooltip(){this.tooltip&&(this.tooltip.style.display="none")}destroy(){this.stopRefresh(),this.container.innerHTML=""}}function jt(t){return new Fe(t)}const Wt="0.1.0";exports.DevLoggerUI=T;exports.ErrorCapture=Ct;exports.LogPersistence=Ot;exports.NetworkCapture=qt;exports.Timeline=Fe;exports.VERSION=Wt;exports.computeDiff=re;exports.createDiffResult=ne;exports.createTimeline=jt;exports.formatValue=te;exports.hasChanges=ze;exports.logger=u;
2029
+ `,this.canvas=this.container.querySelector(".timeline-canvas"),this.tooltip=this.container.querySelector(".timeline-tooltip"),this.canvas&&(this.ctx=this.canvas.getContext("2d"),this.resizeCanvas()),this.container.querySelectorAll("[data-window]").forEach(e=>{e.addEventListener("click",n=>{const o=n.currentTarget,s=parseInt(o.dataset.window||"60000",10);this.setTimeWindow(s),this.container.querySelectorAll("[data-window]").forEach(i=>{const a=i;a===o?(a.style.background="#0e639c",a.style.borderColor="#0e639c",a.style.color="white"):(a.style.background="transparent",a.style.borderColor="#3c3c3c",a.style.color="#858585")})})}),this.canvas&&(this.canvas.addEventListener("mousemove",this.handleMouseMove.bind(this)),this.canvas.addEventListener("mouseleave",this.handleMouseLeave.bind(this))),this.startRefresh()}resizeCanvas(){if(!this.canvas)return;const e=this.container.getBoundingClientRect();this.canvas.width=e.width-2,this.canvas.height=this.config.height,this.render()}startRefresh(){this.intervalId||(this.intervalId=window.setInterval(()=>this.render(),this.config.refreshInterval),this.render())}stopRefresh(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null)}setTimeWindow(e){this.config.timeWindow=e,this.render()}render(){if(!this.canvas||!this.ctx)return;const e=this.ctx,n=this.canvas.width,o=this.canvas.height,s=Date.now(),i=s-this.config.timeWindow;e.fillStyle="#1e1e1e",e.fillRect(0,0,n,o),this.spanBounds.clear(),this.logBounds.clear(),this.drawTimeGrid(e,n,o,i,s);const a=g.getLogs().filter(c=>c.timestamp>=i),l=g.getSpans().filter(c=>c.startTime>=i||c.endTime&&c.endTime>=i);this.config.showSpans&&this.drawSpans(e,l,n,o,i,s),this.config.showLogs&&this.drawLogs(e,a,n,o,i,s)}drawTimeGrid(e,n,o,s,i){const a=i-s,l=6;e.strokeStyle="#333",e.lineWidth=1,e.font="10px SF Mono, monospace",e.fillStyle="#666";for(let c=0;c<=l;c++){const d=c/l*n,p=s+a*c/l;e.beginPath(),e.moveTo(d,0),e.lineTo(d,o),e.stroke();const h=new Date(p),C=`${h.getMinutes().toString().padStart(2,"0")}:${h.getSeconds().toString().padStart(2,"0")}`;e.fillText(C,d+2,o-4)}}drawSpans(e,n,o,s,i,a){const l=a-i,c=20,d=4,p=20,h=n.filter(v=>!v.parentId);let C=p;const Q=(v,H,Zt=0)=>{const D=(v.startTime-i)/l*o,Ae=((v.endTime||a)-i)/l*o,j=Math.max(Ae-D,2),ge=Yt[v.status];e.fillStyle=ge+"40",e.fillRect(D,H,j,c),e.strokeStyle=ge,e.lineWidth=1,e.strokeRect(D,H,j,c),e.fillStyle="#ccc",e.font="10px SF Mono, monospace";const Oe=v.duration?`${v.name} (${v.duration}ms)`:v.name;return e.fillText(Oe,D+4,H+14,j-8),this.spanBounds.set(v.id,{x:D,y:H,w:j,h:c}),H+c+d};for(const v of h)C=Q(v,C)}drawLogs(e,n,o,s,i,a){const l=a-i,c=8,d=30;for(const p of n){const h=(p.timestamp-i)/l*o,C=Xt[p.level];e.fillStyle=C,e.beginPath(),e.moveTo(h,s-d),e.lineTo(h-c/2,s-d-c),e.lineTo(h+c/2,s-d-c),e.closePath(),e.fill(),this.logBounds.set(p.id,{x:h,y:s-d-c/2,r:c})}}handleMouseMove(e){if(!this.canvas||!this.tooltip)return;const n=this.canvas.getBoundingClientRect(),o=e.clientX-n.left,s=e.clientY-n.top;for(const i of g.getSpans()){const a=this.spanBounds.get(i.id);if(a&&o>=a.x&&o<=a.x+a.w&&s>=a.y&&s<=a.y+a.h){this.showTooltip(e,`
2030
+ <strong>${i.name}</strong><br>
2031
+ Status: ${i.status}<br>
2032
+ ${i.duration!==void 0?`Duration: ${i.duration}ms`:"Running..."}<br>
2033
+ ${i.context?`Context: ${JSON.stringify(i.context)}`:""}
2034
+ `);return}}for(const i of g.getLogs()){const a=this.logBounds.get(i.id);if(a&&Math.sqrt((o-a.x)**2+(s-a.y)**2)<=a.r){this.showTooltip(e,`
2035
+ <strong>[${i.level.toUpperCase()}]</strong> ${i.message}<br>
2036
+ <small>${new Date(i.timestamp).toISOString()}</small>
2037
+ `);return}}this.hideTooltip()}handleMouseLeave(){this.hideTooltip()}showTooltip(e,n){this.tooltip&&(this.tooltip.innerHTML=n,this.tooltip.style.display="block",this.tooltip.style.left=`${e.offsetX+10}px`,this.tooltip.style.top=`${e.offsetY+10}px`)}hideTooltip(){this.tooltip&&(this.tooltip.style.display="none")}destroy(){this.stopRefresh(),this.container.innerHTML=""}}function Kt(t){return new Fe(t)}const Qt="0.1.0";exports.DevLoggerUI=T;exports.ErrorCapture=Rt;exports.LogPersistence=Vt;exports.NetworkCapture=Gt;exports.Timeline=Fe;exports.VERSION=Qt;exports.computeDiff=se;exports.createDiffResult=re;exports.createTimeline=Kt;exports.formatValue=ne;exports.hasChanges=qe;exports.logger=g;