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.
- package/dist/index.cjs +264 -80
- package/dist/index.js +740 -523
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
"use strict";var
|
|
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
|
|
3
|
-
Data: ${JSON.stringify(n.data)}`:"";return`[${o}] ${
|
|
4
|
-
Source: ${
|
|
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,
|
|
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: ${
|
|
9
|
-
--bg-secondary: ${
|
|
10
|
-
--bg-hover: ${
|
|
11
|
-
--bg-header: ${
|
|
12
|
-
--text-primary: ${
|
|
13
|
-
--text-secondary: ${
|
|
14
|
-
--text-muted: ${
|
|
15
|
-
--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: ${
|
|
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: ${
|
|
103
|
+
background: ${u.buttonBg};
|
|
99
104
|
color: white;
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
.devlogger-btn-primary:hover {
|
|
103
|
-
background: ${
|
|
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: ${
|
|
128
|
+
background: ${u.scrollbar};
|
|
124
129
|
border-radius: 4px;
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
.devlogger-logs::-webkit-scrollbar-thumb:hover {
|
|
128
|
-
background: ${
|
|
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: ${
|
|
175
|
+
color: ${u.levelDebug};
|
|
171
176
|
}
|
|
172
177
|
|
|
173
178
|
.log-level-info {
|
|
174
179
|
background: rgba(55, 148, 255, 0.15);
|
|
175
|
-
color: ${
|
|
180
|
+
color: ${u.levelInfo};
|
|
176
181
|
}
|
|
177
182
|
|
|
178
183
|
.log-level-warn {
|
|
179
184
|
background: rgba(204, 167, 0, 0.15);
|
|
180
|
-
color: ${
|
|
185
|
+
color: ${u.levelWarn};
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
.log-level-error {
|
|
184
189
|
background: rgba(241, 76, 76, 0.15);
|
|
185
|
-
color: ${
|
|
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: ${
|
|
209
|
+
color: ${u.levelInfo};
|
|
205
210
|
}
|
|
206
211
|
|
|
207
212
|
.log-context {
|
|
208
213
|
font-size: 10px;
|
|
209
|
-
color: ${
|
|
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 ${
|
|
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: ${
|
|
280
|
+
color: ${u.levelInfo};
|
|
276
281
|
background: rgba(55, 148, 255, 0.15);
|
|
277
282
|
}
|
|
278
283
|
|
|
279
284
|
.span-status-success {
|
|
280
|
-
color: ${
|
|
285
|
+
color: ${u.levelInfo};
|
|
281
286
|
background: rgba(55, 148, 255, 0.15);
|
|
282
287
|
}
|
|
283
288
|
|
|
284
289
|
.span-status-error {
|
|
285
|
-
color: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
455
|
-
border-color: ${
|
|
498
|
+
background: ${u.levelDebug};
|
|
499
|
+
border-color: ${u.levelDebug};
|
|
456
500
|
}
|
|
457
501
|
|
|
458
502
|
.filter-level-btn.active[data-level="info"] {
|
|
459
|
-
background: ${
|
|
460
|
-
border-color: ${
|
|
503
|
+
background: ${u.levelInfo};
|
|
504
|
+
border-color: ${u.levelInfo};
|
|
461
505
|
}
|
|
462
506
|
|
|
463
507
|
.filter-level-btn.active[data-level="warn"] {
|
|
464
|
-
background: ${
|
|
465
|
-
border-color: ${
|
|
508
|
+
background: ${u.levelWarn};
|
|
509
|
+
border-color: ${u.levelWarn};
|
|
466
510
|
}
|
|
467
511
|
|
|
468
512
|
.filter-level-btn.active[data-level="error"] {
|
|
469
|
-
background: ${
|
|
470
|
-
border-color: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
673
|
+
color: ${u.levelInfo};
|
|
630
674
|
}
|
|
631
|
-
`;function
|
|
632
|
-
`)}catch{return"[Unable to display data]"}}function
|
|
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="${
|
|
678
|
+
<button class="log-data-toggle" data-target="${i}">
|
|
635
679
|
diff
|
|
636
680
|
</button>
|
|
637
|
-
<div class="log-data-content" id="${
|
|
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="${
|
|
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="${
|
|
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">${
|
|
650
|
-
${
|
|
651
|
-
<span class="log-source" title="${
|
|
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">${
|
|
697
|
+
<div class="log-message">${_(t.message)}</div>
|
|
654
698
|
${a()}
|
|
655
|
-
`,n){const l=e.querySelector(".log-data-toggle"),c=e.querySelector(`#${
|
|
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
|
|
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="${
|
|
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="${
|
|
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
|
|
1902
|
+
`}function ye(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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">${
|
|
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">${
|
|
1938
|
+
<span class="devlogger-shortcut">${pt()}</span>
|
|
1755
1939
|
</div>
|
|
1756
|
-
`,
|
|
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
|
-
`,
|
|
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">${
|
|
1762
|
-
<span class="span-status span-status-${
|
|
1763
|
-
<span class="span-duration">${
|
|
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,
|
|
1846
|
-
<strong>${
|
|
1847
|
-
Status: ${
|
|
1848
|
-
${
|
|
1849
|
-
${
|
|
1850
|
-
`);return}}for(const
|
|
1851
|
-
<strong>[${
|
|
1852
|
-
<small>${new Date(
|
|
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
|
|
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;
|