nestjs-devtools 1.5.2 → 1.5.4

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.
@@ -42,14 +42,14 @@ let DevtoolsController = class DevtoolsController {
42
42
  panels[collector.name] = { label: collector.name, summary: 'Error collecting data' };
43
43
  }
44
44
  }
45
- res.json(panels);
45
+ res.send(panels);
46
46
  }
47
47
  getHistory(res) {
48
- res.json(this.devtoolsService.getHistorySummary());
48
+ res.send(this.devtoolsService.getHistorySummary());
49
49
  }
50
50
  getRequestDetail(id, res) {
51
51
  const history = this.devtoolsService.getHistory();
52
- res.json(history.find((r) => r.id === id) ?? null);
52
+ res.send(history.find((r) => r.id === id) ?? null);
53
53
  }
54
54
  };
55
55
  exports.DevtoolsController = DevtoolsController;
@@ -64,7 +64,15 @@ const PROFILER_PAGE = (config) => {
64
64
  .panel-body tr:last-child td, .panel-body tr:last-child th { border-bottom: none; }
65
65
  .empty { color: #bbb; font-size: 12px; }
66
66
  .mono { font-family: SF Mono,Menlo,monospace; font-size: 11px; }
67
- .query-table { width: 100%; }
67
+ #history-detail { display: none; margin-top: 12px; }
68
+ #history-detail.open { display: block; }
69
+ #history-body tr { cursor: pointer; }
70
+ #history-body tr:hover { background: #f0f7ff; }
71
+ #history-body tr.selected { background: #e1effa; }
72
+ .detail-section { margin-bottom: 12px; }
73
+ .detail-section:last-child { margin-bottom: 0; }
74
+ .detail-section h4 { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; color: #999; margin-bottom: 6px; }
75
+ .query-table { width: 100%; }
68
76
  .query-row { display: flex; align-items: flex-start; padding: 5px 0; gap: 6px; border-bottom: 1px solid #eee; font-size: 11px; }
69
77
  .query-row:last-child { border-bottom: none; }
70
78
  .query-num { color: #999; width: 22px; flex-shrink: 0; }
@@ -122,6 +130,9 @@ const PROFILER_PAGE = (config) => {
122
130
  <thead><tr style="background:#fafafa"><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Time</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Method</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Path</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Status</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Duration</th></tr></thead>
123
131
  <tbody id="history-body"></tbody>
124
132
  </table>
133
+ <div id="history-detail" class="panel">
134
+ <div id="history-detail-body" class="panel-body open" style="display:block;padding:16px"></div>
135
+ </div>
125
136
  </div>
126
137
  </div>
127
138
  </div>
@@ -249,25 +260,75 @@ const PROFILER_PAGE = (config) => {
249
260
  });
250
261
  }
251
262
 
263
+ function renderRequestDetail(d) {
264
+ if (!d) return '<span class="empty">No details available</span>';
265
+ var h = '<div class="detail-section"><h4>Request</h4><table>'+
266
+ '<tr><th style="width:80px">Method</th><td><span class="badge badge-'+d.method.toLowerCase()+'">'+escape(d.method)+'</span></td></tr>'+
267
+ '<tr><th>Path</th><td class="mono">'+escape(d.path)+'</td></tr>'+
268
+ '<tr><th>Status</th><td><span class="status-badge status-'+(d.statusCode||'')+'">'+escape(d.statusCode||'')+'</span></td></tr>'+
269
+ '<tr><th>Duration</th><td>'+(d.duration!=null?d.duration.toFixed(1):'')+' ms</td></tr>'+
270
+ '<tr><th>Memory</th><td>'+escape(d.memory||'')+'</td></tr>'+
271
+ '<tr><th>Route</th><td class="mono" style="font-size:10px">'+escape(d.route||'')+'</td></tr>'+
272
+ '<tr><th>Time</th><td>'+escape(new Date(d.timestamp).toLocaleTimeString())+'</td></tr>'+
273
+ '</table></div>';
274
+ if (d.queries && d.queries.length>0) {
275
+ h += '<div class="detail-section"><h4>Queries ('+d.queries.length+')</h4>';
276
+ d.queries.forEach(function(q,i){
277
+ h += '<div class="query-row"><span class="query-num">'+(i+1)+'</span><span class="query-sql">'+escape(q.sql||'')+'</span><span class="query-time">'+escape(q.duration||'')+'</span></div>';
278
+ });
279
+ h += '</div>';
280
+ }
281
+ if (d.logs && d.logs.length>0) {
282
+ h += '<div class="detail-section"><h4>Logs ('+d.logs.length+')</h4>';
283
+ d.logs.forEach(function(e){
284
+ var lc = e.level==='error' ? 'log-error' : e.level==='warn' ? 'log-warn' : 'log-info';
285
+ h += '<div class="log-row"><span class="log-level '+lc+'">'+escape(e.level||'')+'</span><span>'+escape(e.message||'')+'</span></div>';
286
+ });
287
+ h += '</div>';
288
+ }
289
+ if (d.exception) {
290
+ h += '<div class="detail-section"><h4>Exception</h4><div class="exception-box"><div class="msg">'+escape(d.exception.message||'')+'</div><div class="stack">'+escape(d.exception.stack||'')+'</div></div></div>';
291
+ }
292
+ return h;
293
+ }
294
+
252
295
  function loadHistory() {
253
296
  fetch(BASE + '/__devtools/history').then(function(r){return r.json()}).then(function(rows){
254
297
  var tbody = document.getElementById('history-body');
298
+ var detail = document.getElementById('history-detail');
255
299
  tbody.innerHTML = '';
256
300
  if (!rows || rows.length===0) {
257
301
  tbody.innerHTML = '<tr><td colspan="5" style="padding:20px;text-align:center;color:#bbb">No requests recorded yet</td></tr>';
258
302
  return;
259
303
  }
304
+ var selectedId = tbody.getAttribute('data-selected');
260
305
  rows.forEach(function(r){
261
306
  var sc = r.statusCode;
262
307
  var scCls = sc>=400 ? 'error-text' : sc>=300 ? 'warn-text' : 'ok-text';
263
308
  var mCls = 'badge-'+r.method.toLowerCase();
264
- tbody.innerHTML += '<tr>'+
309
+ var sel = r.id===selectedId ? ' selected' : '';
310
+ var tr = document.createElement('tr');
311
+ tr.className = sel;
312
+ tr.innerHTML =
265
313
  '<td style="padding:8px 12px;border-bottom:1px solid #eee;color:#888">'+escape(new Date(r.timestamp).toLocaleTimeString())+'</td>'+
266
314
  '<td style="padding:8px 12px;border-bottom:1px solid #eee"><span class="badge '+mCls+'">'+escape(r.method)+'</span></td>'+
267
315
  '<td style="padding:8px 12px;border-bottom:1px solid #eee;font-family:SF Mono,Menlo,monospace;font-size:11px">'+escape(r.path)+'</td>'+
268
316
  '<td style="padding:8px 12px;border-bottom:1px solid #eee"><span class="'+scCls+'">'+sc+'</span></td>'+
269
- '<td style="padding:8px 12px;border-bottom:1px solid #eee;color:#888;font-family:SF Mono,Menlo,monospace">'+(r.duration!=null?r.duration.toFixed(1):'')+' ms</td>'+
270
- '</tr>';
317
+ '<td style="padding:8px 12px;border-bottom:1px solid #eee;color:#888;font-family:SF Mono,Menlo,monospace">'+(r.duration!=null?r.duration.toFixed(1):'')+' ms</td>';
318
+ tr.addEventListener('click', function(){
319
+ document.querySelectorAll('#history-body tr').forEach(function(t){t.classList.remove('selected')});
320
+ tr.classList.add('selected');
321
+ tbody.setAttribute('data-selected', r.id);
322
+ fetch(BASE + '/__devtools/request/' + r.id).then(function(r2){return r2.json()}).then(function(detailData){
323
+ document.getElementById('history-detail-body').innerHTML = renderRequestDetail(detailData);
324
+ detail.classList.add('open');
325
+ }).catch(function(e){
326
+ console.error('[Devtools] Failed to load request detail:', e);
327
+ document.getElementById('history-detail-body').innerHTML = '<span class="empty">Failed to load detail</span>';
328
+ detail.classList.add('open');
329
+ });
330
+ });
331
+ tbody.appendChild(tr);
271
332
  });
272
333
  }).catch(function(e){
273
334
  console.error('[Devtools] Failed to load history:', e);
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../toolbar/profiler.ts"],"names":[],"mappings":";;;AAIO,MAAM,aAAa,GAAG,CAAC,MAAoC,EAAE,EAAE;IACpE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAExC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAoRD,CAAC;AACT,CAAC,CAAC;AAxRW,QAAA,aAAa,iBAwRxB"}
1
+ {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../toolbar/profiler.ts"],"names":[],"mappings":";;;AAIO,MAAM,aAAa,GAAG,CAAC,MAAoC,EAAE,EAAE;IACpE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAExC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiVD,CAAC;AACT,CAAC,CAAC;AArVW,QAAA,aAAa,iBAqVxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestjs-devtools",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Symfony-style debug toolbar for NestJS applications",
5
5
  "keywords": [
6
6
  "nestjs",