nestjs-devtools 1.3.2 → 1.4.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.
@@ -4,16 +4,24 @@ exports.PROFILER_PAGE = void 0;
4
4
  const PROFILER_PAGE = (config) => {
5
5
  const { theme = 'dark' } = config ?? {};
6
6
  const dark = theme === 'dark';
7
- const bg = dark ? '#111827' : '#f8fafc';
8
- const fg = dark ? '#f3f4f6' : '#1f2937';
9
- const cardBg = dark ? '#1f2937' : '#ffffff';
10
- const borderClr = dark ? '#374151' : '#e5e7eb';
11
- const headerBg = dark ? '#1f2937' : '#ffffff';
12
- const dimText = dark ? '#9ca3af' : '#6b7280';
13
- const dimmerText = dark ? '#6b7280' : '#9ca3af';
14
- const accentText = dark ? '#60a5fa' : '#2563eb';
15
- const navBg = dark ? '#1f2937' : '#f1f5f9';
16
- const navFg = dark ? '#d1d5db' : '#475569';
7
+ const bg = dark ? '#0f172a' : '#f8fafc';
8
+ const fg = dark ? '#e2e8f0' : '#1e293b';
9
+ const cardBg = dark ? '#1e293b' : '#ffffff';
10
+ const borderClr = dark ? '#334155' : '#e2e8f0';
11
+ const headerBg = dark ? '#0f172a' : '#ffffff';
12
+ const dimText = dark ? '#64748b' : '#94a3b8';
13
+ const dimmerText = dark ? '#475569' : '#cbd5e1';
14
+ const accentText = dark ? '#38bdf8' : '#0284c7';
15
+ const labelFg = dark ? '#f1f5f9' : '#0f172a';
16
+ const navBg = dark ? '#1e293b' : '#f1f5f9';
17
+ const navFg = dark ? '#94a3b8' : '#475569';
18
+ const I = {
19
+ req: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M5 8h6M8 5l3 3-3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
20
+ perf: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 4v4l2.5 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
21
+ db: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><ellipse cx="8" cy="4.5" rx="5" ry="2" stroke="currentColor" stroke-width="1.5"/><path d="M3 4.5v7c0 1.1 2.2 2 5 2s5-.9 5-2v-7" stroke="currentColor" stroke-width="1.5"/><path d="M3 8c0 1.1 2.2 2 5 2s5-.9 5-2" stroke="currentColor" stroke-width="1.5"/></svg>',
22
+ routes: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
23
+ log: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M5 6h6M5 9h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
24
+ };
17
25
  return `<!DOCTYPE html>
18
26
  <html lang="en">
19
27
  <head>
@@ -23,69 +31,93 @@ const PROFILER_PAGE = (config) => {
23
31
  <style>
24
32
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
25
33
  body {
26
- font-family: -apple-system, BlinkMacSystemFont, Roboto, sans-serif;
27
- background: ${bg}; color: ${fg}; font-size: 13px; line-height: 1.5;
34
+ font-family: Inter,SF Pro,system-ui,-apple-system,sans-serif;
35
+ background: ${bg}; color: ${fg}; font-size: 13px; line-height: 1.6;
28
36
  min-height: 100vh;
29
37
  }
30
38
  .header {
31
- background: ${headerBg}; border-bottom: 2px solid #3b82f6;
32
- padding: 16px 24px; display: flex; align-items: center; gap: 12px;
39
+ background: ${headerBg}; border-bottom: 1px solid ${borderClr};
40
+ padding: 16px 28px; display: flex; align-items: center; gap: 14px;
41
+ position: sticky; top: 0; z-index: 10;
33
42
  }
34
- .header h1 { font-size: 18px; font-weight: 700; color: ${accentText}; }
43
+ .header h1 { font-size: 17px; font-weight: 700; color: ${accentText}; letter-spacing: -0.3px; }
35
44
  .header span { color: ${dimText}; font-size: 13px; }
36
- .container { max-width: 1200px; margin: 0 auto; padding: 24px; }
37
- .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin-bottom: 24px; }
45
+ .container { max-width: 1200px; margin: 0 auto; padding: 24px 28px; }
46
+ .nav { display: flex; gap: 4px; margin-bottom: 24px; background: ${navBg}; border-radius: 8px; padding: 3px; display: inline-flex; }
47
+ .nav button {
48
+ padding: 7px 16px; border-radius: 6px; border: none;
49
+ background: transparent; color: ${navFg}; cursor: pointer;
50
+ font-size: 13px; font-weight: 500; transition: all .12s ease;
51
+ }
52
+ .nav button.active { background: ${cardBg}; color: ${labelFg}; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
53
+ .nav button:hover:not(.active) { color: ${labelFg}; }
54
+ .section { display: none; }
55
+ .section.active { display: block; }
56
+ .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px; }
38
57
  .card {
39
58
  background: ${cardBg}; border-radius: 8px; border: 1px solid ${borderClr};
40
- overflow: hidden; cursor: pointer; transition: border-color .15s;
59
+ overflow: hidden; cursor: pointer; transition: border-color .15s ease;
41
60
  }
42
- .card:hover { border-color: #3b82f6; }
61
+ .card:hover { border-color: ${accentText}; }
43
62
  .card-header {
44
- padding: 12px 16px; display: flex; align-items: center; gap: 10px;
45
- border-bottom: 1px solid ${borderClr};
63
+ padding: 12px 14px; display: flex; align-items: center; gap: 9px;
64
+ user-select: none;
46
65
  }
47
- .card-header .icon { font-size: 18px; }
48
- .card-header .label { font-weight: 600; font-size: 13px; }
66
+ .card-header .icon { color: ${accentText}; width: 16px; height: 16px; flex-shrink: 0; }
67
+ .card-header .label { font-weight: 600; font-size: 13px; color: ${labelFg}; }
49
68
  .card-header .summary { color: ${dimText}; font-size: 11px; margin-left: auto; }
50
- .card-body { padding: 0; max-height: 0; overflow: hidden; transition: max-height .2s, padding .2s; }
51
- .card-body.open { max-height: 2000px; padding: 12px 16px; overflow-y: auto; }
69
+ .card-body { max-height: 0; overflow: hidden; transition: max-height .25s ease; }
70
+ .card-body.open { max-height: 2000px; }
71
+ .card-body-inner { padding: 0 14px 14px; }
52
72
  .card-body table { width: 100%; border-collapse: collapse; font-size: 12px; }
53
73
  .card-body td, .card-body th {
54
74
  padding: 6px 8px; border-bottom: 1px solid ${borderClr}; text-align: left;
55
75
  vertical-align: top; word-break: break-word;
56
76
  }
57
- .card-body th { color: ${dimText}; font-weight: 600; width: 120px; }
77
+ .card-body th { color: ${dimText}; font-weight: 500; width: 100px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.3px; }
78
+ .card-body tr:last-child td, .card-body tr:last-child th { border-bottom: none; }
58
79
  .badge {
59
- display: inline-block; padding: 2px 8px; border-radius: 4px;
60
- font-size: 11px; font-weight: 600;
61
- }
62
- .badge-get { background: #065f46; color: #6ee7b7; }
63
- .badge-post { background: #1e3a5f; color: #93c5fd; }
64
- .badge-put { background: #713f12; color: #fcd34d; }
65
- .badge-delete { background: #7f1d1d; color: #fca5a5; }
66
- .badge-patch { background: #581c87; color: #d8b4fe; }
67
- .empty { padding: 24px; text-align: center; color: ${dimmerText}; }
68
- .mono { font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; font-size: 11px; }
69
- .history-table { width: 100%; border-collapse: collapse; margin-top: 16px; }
70
- .history-table th { padding: 8px 12px; text-align: left; color: ${dimText}; font-weight: 600; border-bottom: 2px solid ${borderClr}; }
71
- .history-table td { padding: 8px 12px; border-bottom: 1px solid ${borderClr}; }
72
- .history-table tr:hover td { background: ${cardBg}; }
73
- .error-text { color: #ef4444; }
74
- .warn-text { color: #f59e0b; }
75
- .ok-text { color: #10b981; }
76
- .nav { display: flex; gap: 8px; margin-bottom: 24px; }
77
- .nav button {
78
- padding: 8px 16px; border-radius: 6px; border: 1px solid ${borderClr};
79
- background: ${navBg}; color: ${navFg}; cursor: pointer; font-size: 13px;
80
+ display: inline-block; padding: 2px 7px; border-radius: 4px;
81
+ font-size: 10px; font-weight: 600; letter-spacing: 0.2px;
80
82
  }
81
- .nav button.active { border-color: #3b82f6; color: ${accentText}; background: ${dark ? '#1e3a5f' : '#dbeafe'}; }
82
- .nav button:hover { background: ${dark ? '#374151' : '#e2e8f0'}; }
83
- .section { display: none; }
84
- .section.active { display: block; }
85
- .qlabel { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 700; margin-right: 4px; }
86
- .qlabel-1 { background: #3b82f6; color: #fff; }
87
- .qlabel-2 { background: #8b5cf6; color: #fff; }
88
- .qlabel-3 { background: #10b981; color: #fff; }
83
+ .badge-get { background: #065f4630; color: #34d399; }
84
+ .badge-post { background: #1e3a5f30; color: #93c5fd; }
85
+ .badge-put { background: #713f1230; color: #fcd34d; }
86
+ .badge-delete { background: #7f1d1d30; color: #fca5a5; }
87
+ .badge-patch { background: #581c8730; color: #d8b4fe; }
88
+ .badge-request { background: #0c4a6e30; color: #7dd3fc; }
89
+ .empty { padding: 20px; text-align: center; color: ${dimmerText}; font-size: 13px; }
90
+ .mono { font-family: ui-monospace,SF Mono,Menlo,monospace; font-size: 11px; }
91
+ .history-wrap { background: ${cardBg}; border: 1px solid ${borderClr}; border-radius: 8px; overflow: hidden; }
92
+ .history-table { width: 100%; border-collapse: collapse; font-size: 12px; }
93
+ .history-table th { padding: 10px 14px; text-align: left; color: ${dimText}; font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.3px; border-bottom: 1px solid ${borderClr}; background: ${dark ? '#0f172a' : '#f8fafc'}; }
94
+ .history-table td { padding: 10px 14px; border-bottom: 1px solid ${borderClr}; }
95
+ .history-table tr:last-child td { border-bottom: none; }
96
+ .history-table tr:hover td { background: ${dark ? '#33415520' : '#f1f5f9'}; }
97
+ .error-text { color: #f87171; font-weight: 600; }
98
+ .warn-text { color: #fbbf24; font-weight: 600; }
99
+ .ok-text { color: #34d399; font-weight: 600; }
100
+ .qlabel { display: inline-block; width: 18px; height: 18px; line-height: 18px; text-align: center; border-radius: 3px; font-size: 10px; font-weight: 700; margin-right: 6px; color: #fff; flex-shrink: 0; }
101
+ .qlabel-1 { background: #3b82f6; }
102
+ .qlabel-2 { background: #8b5cf6; }
103
+ .qlabel-3 { background: #10b981; }
104
+ .query-row { display: flex; align-items: flex-start; padding: 6px 0; gap: 6px; border-bottom: 1px solid ${borderClr}; }
105
+ .query-row:last-child { border-bottom: none; }
106
+ .query-sql { flex: 1; min-width: 0; }
107
+ .query-time { color: ${dark ? '#fbbf24' : '#b45309'}; white-space: nowrap; font-family: ui-monospace,SF Mono,monospace; font-size: 11px; }
108
+ .log-row { padding: 5px 0; border-bottom: 1px solid ${borderClr}; display: flex; align-items: flex-start; gap: 8px; }
109
+ .log-row:last-child { border-bottom: none; }
110
+ .log-level { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px; white-space: nowrap; }
111
+ .route-group { padding: 6px 0; }
112
+ .route-group-header { color: ${accentText}; font-weight: 600; font-size: 11px; padding: 4px 0; }
113
+ .route-item { padding: 2px 0 2px 14px; font-family: ui-monospace,SF Mono,monospace; font-size: 11px; }
114
+ .route-controller { color: ${dimText}; }
115
+ .exception-box { background: ${dark ? 'rgba(239,68,68,0.08)' : 'rgba(239,68,68,0.04)'}; border-radius: 6px; padding: 10px; }
116
+ .exception-box .msg { color: #f87171; font-weight: 600; font-size: 12px; margin-bottom: 6px; }
117
+ .exception-box .stack { font-family: ui-monospace,SF Mono,monospace; font-size: 11px; color: ${dimText}; white-space: pre-wrap; line-height: 1.4; }
118
+ .field-row { display: flex; padding: 4px 0; }
119
+ .field-label { color: ${dimText}; width: 100px; flex-shrink: 0; font-size: 11px; }
120
+ .field-value { color: ${labelFg}; word-break: break-all; }
89
121
  </style>
90
122
  </head>
91
123
  <body>
@@ -102,15 +134,19 @@ const PROFILER_PAGE = (config) => {
102
134
  <div class="grid" id="panel-grid"></div>
103
135
  </div>
104
136
  <div id="tab-history" class="section">
105
- <table class="history-table">
106
- <thead><tr><th>Time</th><th>Method</th><th>Path</th><th>Status</th><th>Duration</th></tr></thead>
107
- <tbody id="history-body"></tbody>
108
- </table>
137
+ <div class="history-wrap">
138
+ <table class="history-table">
139
+ <thead><tr><th>Time</th><th>Method</th><th>Path</th><th>Status</th><th>Duration</th></tr></thead>
140
+ <tbody id="history-body"></tbody>
141
+ </table>
142
+ </div>
109
143
  </div>
110
144
  </div>
111
145
  <script>
112
146
  (function() {
113
147
  var BASE = window.location.pathname.replace(/\\/__devtools\\/?$/, '');
148
+ var icons = ${JSON.stringify(I)};
149
+
114
150
  function escape(s) { return s==null?'':String(s).replace(/[&<>"]/g,function(m){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[m]}); }
115
151
 
116
152
  document.querySelectorAll('[data-tab]').forEach(function(btn){
@@ -130,51 +166,44 @@ const PROFILER_PAGE = (config) => {
130
166
  for (var k in d) {
131
167
  var v = d[k];
132
168
  if (k === 'queries' && Array.isArray(v)) {
169
+ if (v.length === 0) { h += '<tr><td colspan="2" style="padding:8px 0;color:${dimText}">No queries</td></tr>'; continue; }
133
170
  h += '<tr><th>Queries</th><td>';
134
171
  v.forEach(function(q,i){
135
172
  var cls = 'qlabel-'+((i%3)+1);
136
- h += '<div style="padding:4px 0;border-bottom:1px solid #1f2937">';
137
- h += '<span class="qlabel '+cls+'">#'+(i+1)+'</span>';
138
- h += '<span class="mono">'+escape(q.sql||'')+'</span>';
139
- h += '<span style="float:right;color:#fbbf24">'+escape(q.duration||'')+'</span>';
140
- h += '</div>';
173
+ h += '<div class="query-row"><span class="qlabel '+cls+'">'+(i+1)+'</span><span class="query-sql mono">'+escape(q.sql||'')+'</span><span class="query-time">'+escape(q.duration||'')+'</span></div>';
141
174
  });
142
175
  h += '</td></tr>';
143
176
  continue;
144
177
  }
145
178
  if (k === 'entries' && Array.isArray(v)) {
179
+ if (v.length === 0) { h += '<tr><td colspan="2" style="padding:8px 0;color:${dimText}">No entries</td></tr>'; continue; }
146
180
  h += '<tr><th>Logs</th><td>';
147
181
  v.forEach(function(e){
148
182
  var lc = e.level==='error' ? 'error-text' : e.level==='warn' ? 'warn-text' : '';
149
- h += '<div style="padding:3px 0;border-bottom:1px solid #1f2937">';
150
- h += '<span class="badge '+lc+'" style="background:#1f2937;text-transform:uppercase;font-size:10px;margin-right:6px">'+escape(e.level||'')+'</span>';
151
- h += '<span>'+escape(e.message||'')+'</span>';
152
- h += '</div>';
183
+ h += '<div class="log-row"><span class="log-level" style="color:'+lc+'">'+escape(e.level||'')+'</span><span>'+escape(e.message||'')+'</span></div>';
153
184
  });
154
185
  h += '</td></tr>';
155
186
  continue;
156
187
  }
157
188
  if (k === 'grouped' && Array.isArray(v)) {
189
+ if (v.length === 0) { h += '<tr><td colspan="2" style="padding:8px 0;color:${dimText}">No routes</td></tr>'; continue; }
158
190
  h += '<tr><th>Routes</th><td>';
159
191
  v.forEach(function(g){
160
- h += '<div style="font-weight:600;color:#60a5fa;padding:4px 0">'+escape(g.method||'')+' ('+(g.count||0)+')</div>';
192
+ h += '<div class="route-group"><div class="route-group-header">'+escape(g.method||'')+' <span style="color:${dimText};font-weight:400">('+(g.count||0)+')</span></div>';
161
193
  if (g.routes) g.routes.forEach(function(r){
162
- h += '<div style="padding:2px 0 2px 16px;font-family:monospace;font-size:11px">';
163
- h += escape(r.path||'')+' <span style="color:#6b7280">('+escape(r.controller||'')+')</span></div>';
194
+ h += '<div class="route-item">'+escape(r.path||'')+' <span class="route-controller">('+escape(r.controller||'')+')</span></div>';
164
195
  });
196
+ h += '</div>';
165
197
  });
166
198
  h += '</td></tr>';
167
199
  continue;
168
200
  }
169
201
  if (k === 'exception' && v && typeof v === 'object') {
170
- h += '<tr><th>Exception</th><td>';
171
- h += '<div class="error-text" style="font-weight:600">'+escape(v.message||'')+'</div>';
172
- h += '<pre class="mono" style="margin-top:6px;color:#9ca3af;white-space:pre-wrap">'+escape(v.stack||'')+'</pre>';
173
- h += '</td></tr>';
202
+ h += '<tr><td colspan="2"><div class="exception-box"><div class="msg">'+escape(v.message||'')+'</div><div class="stack">'+escape(v.stack||'')+'</div></div></td></tr>';
174
203
  continue;
175
204
  }
176
205
  if (k === 'stack') continue;
177
- h += '<tr><th>'+escape(k)+'</th><td>'+escape(typeof v==='object'?JSON.stringify(v):v)+'</td></tr>';
206
+ h += '<tr><th>'+escape(k)+'</th><td class="mono">'+escape(typeof v==='object'?JSON.stringify(v):v)+'</td></tr>';
178
207
  }
179
208
  h += '</table>';
180
209
  return h;
@@ -184,23 +213,39 @@ const PROFILER_PAGE = (config) => {
184
213
  fetch(BASE + '/__devtools/data').then(function(r){return r.json()}).then(function(d){
185
214
  var grid = document.getElementById('panel-grid');
186
215
  grid.innerHTML = '';
187
- var icons = {request:'🌐',performance:'⚡',database:'🗄️',routes:'📋',logs:'📝'};
188
- Object.keys(d).forEach(function(key){
216
+ var iconMap = {request:icons.req,performance:icons.perf,database:icons.db,routes:icons.routes,logs:icons.log};
217
+ var order = ['request','performance','database','routes','logs'];
218
+ order.forEach(function(key){
189
219
  var p = d[key];
190
220
  if (!p || !p.label) return;
191
221
  var card = document.createElement('div');
192
222
  card.className = 'card';
223
+ var icon = iconMap[key]||icons.log;
224
+ var bodyHtml = renderDetails(p);
193
225
  card.innerHTML =
194
- '<div class="card-header"><span class="icon">'+(icons[key]||'🔧')+'</span>'+
195
- '<span class="label">'+escape(p.label)+'</span>'+
196
- '<span class="summary">'+escape(p.summary||'')+'</span></div>'+
197
- '<div class="card-body">'+renderDetails(p)+'</div>';
226
+ '<div class="card-header"><span class="icon">'+icon+'</span><span class="label">'+escape(p.label)+'</span><span class="summary">'+escape(p.summary||'')+'</span></div>'+
227
+ '<div class="card-body"><div class="card-body-inner">'+bodyHtml+'</div></div>';
198
228
  card.querySelector('.card-header').addEventListener('click', function(){
199
229
  var body = card.querySelector('.card-body');
200
230
  body.classList.toggle('open');
201
231
  });
202
232
  grid.appendChild(card);
203
233
  });
234
+ for (var key in d) {
235
+ if (order.indexOf(key) !== -1) continue;
236
+ var p = d[key];
237
+ if (!p || !p.label) continue;
238
+ var card = document.createElement('div');
239
+ card.className = 'card';
240
+ card.innerHTML =
241
+ '<div class="card-header"><span class="icon">'+icons.log+'</span><span class="label">'+escape(p.label)+'</span><span class="summary">'+escape(p.summary||'')+'</span></div>'+
242
+ '<div class="card-body"><div class="card-body-inner">'+renderDetails(p)+'</div></div>';
243
+ card.querySelector('.card-header').addEventListener('click', function(){
244
+ var body = card.querySelector('.card-body');
245
+ body.classList.toggle('open');
246
+ });
247
+ grid.appendChild(card);
248
+ }
204
249
  }).catch(function(){
205
250
  document.getElementById('panel-grid').innerHTML = '<div class="empty">Failed to load profiler data. Make sure the server is running.</div>';
206
251
  });
@@ -218,11 +263,11 @@ const PROFILER_PAGE = (config) => {
218
263
  var statusClass = r.statusCode >= 400 ? 'error-text' : r.statusCode >= 300 ? 'warn-text' : 'ok-text';
219
264
  var methodBadge = 'badge-'+r.method.toLowerCase();
220
265
  tbody.innerHTML += '<tr>'+
221
- '<td>'+escape(new Date(r.timestamp).toLocaleTimeString())+'</td>'+
266
+ '<td style="color:${dimText}">'+escape(new Date(r.timestamp).toLocaleTimeString())+'</td>'+
222
267
  '<td><span class="badge '+methodBadge+'">'+escape(r.method)+'</span></td>'+
223
268
  '<td class="mono">'+escape(r.path)+'</td>'+
224
269
  '<td><span class="'+statusClass+'">'+r.statusCode+'</span></td>'+
225
- '<td>'+r.duration.toFixed(1)+' ms</td>'+
270
+ '<td class="mono" style="color:${dimText}">'+(r.duration!=null?r.duration.toFixed(1):'')+' ms</td>'+
226
271
  '</tr>';
227
272
  });
228
273
  }).catch(function(){
@@ -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;IACxC,MAAM,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACxC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3C,OAAO;;;;;;;;;;kBAUS,EAAE,YAAY,EAAE;;;;kBAIhB,QAAQ;;;2DAGiC,UAAU;0BAC3C,OAAO;;;;kBAIf,MAAM,2CAA2C,SAAS;;;;;;+BAM7C,SAAS;;;;mCAIL,OAAO;;;;;iDAKO,SAAS;;;2BAG/B,OAAO;;;;;;;;;;uDAUqB,UAAU;;;oEAGG,OAAO,gDAAgD,SAAS;oEAChE,SAAS;6CAChC,MAAM;;;;;;+DAMY,SAAS;kBACtD,KAAK,YAAY,KAAK;;uDAEe,UAAU,iBAAiB,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;oCAC1E,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA2JxD,CAAC;AACT,CAAC,CAAC;AA3OW,QAAA,aAAa,iBA2OxB"}
1
+ {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../toolbar/profiler.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TOOLBAR_TEMPLATE = void 0;
4
+ const I = {
5
+ req: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M5 8h6M8 5l3 3-3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
6
+ perf: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 4v4l2.5 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
7
+ db: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><ellipse cx="8" cy="4.5" rx="5" ry="2" stroke="currentColor" stroke-width="1.5"/><path d="M3 4.5v7c0 1.1 2.2 2 5 2s5-.9 5-2v-7" stroke="currentColor" stroke-width="1.5"/><path d="M3 8c0 1.1 2.2 2 5 2s5-.9 5-2" stroke="currentColor" stroke-width="1.5"/></svg>',
8
+ routes: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
9
+ log: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M5 6h6M5 9h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
10
+ close: '<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
11
+ profiler: '<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 3h12M2 8h12M2 13h8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="12" r="2.5" stroke="currentColor" stroke-width="1.5"/></svg>',
12
+ chevron: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
13
+ };
4
14
  const TOOLBAR_TEMPLATE = (config) => {
5
15
  const { position = 'bottom-left', theme = 'dark' } = config ?? {};
6
16
  const id = '__nestDevtools';
@@ -9,21 +19,23 @@ const TOOLBAR_TEMPLATE = (config) => {
9
19
  const isRight = position.endsWith('right');
10
20
  const outerPos = isTop ? 'top:0' : 'bottom:0';
11
21
  const outerSide = isRight ? 'right:0' : 'left:0';
12
- const outerBorder = isTop ? 'border-bottom:2px solid #3b82f6' : 'border-top:2px solid #3b82f6';
22
+ const outerBorder = isTop ? 'border-bottom:1px solid' : 'border-top:1px solid';
13
23
  const outerShadow = isTop
14
- ? 'box-shadow:0 4px 12px rgba(0,0,0,0.35)'
15
- : 'box-shadow:0 -4px 12px rgba(0,0,0,0.35)';
24
+ ? 'box-shadow:0 4px 24px rgba(0,0,0,0.3)'
25
+ : 'box-shadow:0 -4px 24px rgba(0,0,0,0.3)';
16
26
  const dark = theme === 'dark';
17
- const bg = dark ? '#1f2937' : '#ffffff';
18
- const fg = dark ? '#f3f4f6' : '#1f2937';
19
- const panelBg = dark ? '#111827' : '#f3f4f6';
20
- const borderClr = dark ? '#374151' : '#e5e7eb';
21
- const btnFg = dark ? '#d1d5db' : '#374151';
22
- const btnBg = dark ? '#374151' : '#e5e7eb';
23
- const btnHover = dark ? '#4b5563' : '#d1d5db';
24
- const dimText = dark ? '#9ca3af' : '#6b7280';
25
- const dimmerText = dark ? '#6b7280' : '#9ca3af';
26
- const accentText = dark ? '#60a5fa' : '#2563eb';
27
+ const bg = dark ? '#0f172a' : '#fafbfc';
28
+ const fg = dark ? '#e2e8f0' : '#1e293b';
29
+ const accent = dark ? '#38bdf8' : '#0284c7';
30
+ const accentBg = dark ? '#0c4a6e30' : '#e0f2fe';
31
+ const panelBg = dark ? '#1e293b' : '#ffffff';
32
+ const borderClr = dark ? '#1e293b' : '#e2e8f0';
33
+ const panelBorder = dark ? '#334155' : '#e2e8f0';
34
+ const btnFg = dark ? '#94a3b8' : '#475569';
35
+ const btnBg = dark ? '#1e293b' : '#f1f5f9';
36
+ const btnHover = dark ? '#334155' : '#e2e8f0';
37
+ const dimText = dark ? '#64748b' : '#94a3b8';
38
+ const labelFg = dark ? '#f1f5f9' : '#0f172a';
27
39
  const warnClr = '#f59e0b';
28
40
  const errClr = '#ef4444';
29
41
  const sqlTimeClr = dark ? '#fbbf24' : '#b45309';
@@ -32,90 +44,107 @@ const TOOLBAR_TEMPLATE = (config) => {
32
44
  var D=document, B=D.body, C='__nestDt'+'${uid}';
33
45
  var p = window.location.pathname.replace(\/[^\/]*$/,'') + '/__devtools';
34
46
  var c=D.createElement('div'); c.id=C;
35
- c.innerHTML='<div style="position:fixed;${outerPos};${outerSide};z-index:99999;font-family:system-ui,BlinkMacSystemFont,sans-serif;font-size:12px;background:${bg};color:${fg};${outerBorder};width:100%;${outerShadow}"><div style="display:flex;align-items:center;height:34px;padding:0 8px;gap:4px;overflow-x:auto;white-space:nowrap;scrollbar-width:none"><span style="font-weight:800;font-size:13px;color:${accentText};padding:0 10px 0 4px;letter-spacing:-0.5px">NDev</span><div id="'+C+'-bar"></div><a href="'+p+'" target="_blank" style="color:${dimmerText};text-decoration:none;padding:4px 8px;font-size:11px;margin-left:auto" title="Open profiler">&#x25A3;</a><span id="'+C+'-toggle" style="color:${dimmerText};cursor:pointer;padding:4px 8px;font-size:14px">&#x2039;</span></div><div id="'+C+'-panel" style="display:none;border-top:1px solid ${borderClr};background:${panelBg};font-size:12px;line-height:1.5"></div></div>';
47
+ c.innerHTML='<div style="position:fixed;${outerPos};${outerSide};z-index:99999;font-family:Inter,SF Pro,system-ui,-apple-system,sans-serif;font-size:12px;background:${bg};color:${fg};${outerBorder}:${borderClr};width:100%;${outerShadow}"><div style="display:flex;align-items:center;height:36px;padding:0 4px 0 10px;gap:2px;overflow-x:auto;white-space:nowrap;scrollbar-width:none"><span style="font-weight:700;font-size:13px;color:${accent};letter-spacing:-0.3px;padding-right:8px;flex-shrink:0">ND</span><div id="'+C+'-bar" style="display:flex;align-items:center;gap:2px;flex:1"></div><a href="'+p+'" target="_blank" style="display:inline-flex;align-items:center;gap:4px;color:${dimText};text-decoration:none;padding:4px 8px;font-size:11px;flex-shrink:0" title="Open profiler">${I.profiler}<span>Profiler</span></a><span id="'+C+'-toggle" style="display:inline-flex;align-items:center;color:${dimText};cursor:pointer;padding:4px 6px;font-size:10px;flex-shrink:0">${I.chevron}</span></div><div id="'+C+'-panel" style="display:none;border-top:1px solid ${panelBorder};background:${panelBg};font-size:12px;line-height:1.5;max-height:400px;overflow:hidden"></div></div>';
36
48
  B.appendChild(c);
37
49
 
38
50
  var lastActive=null;
39
51
  function renderPanel(name, detail) {
40
- var p=D.getElementById(C+'-panel');
41
- if (lastActive===name) { p.style.display='none'; lastActive=null; return; }
52
+ var pnl=D.getElementById(C+'-panel');
53
+ if (lastActive===name) { pnl.style.display='none'; lastActive=null; return; }
42
54
  lastActive=name;
43
- var h='<div style="padding:12px 16px;max-height:360px;overflow-y:auto">';
44
- h+='<div style="display:flex;align-items:center;margin-bottom:10px;gap:8px">';
45
- h+='<span style="font-weight:700;font-size:13px">'+detail.label+'</span>';
46
- h+='<span style="color:${dimText};font-size:11px">'+detail.summary+'</span>';
47
- h+='<span style="margin-left:auto;cursor:pointer;color:${dimmerText};font-size:16px" onclick="document.getElementById('+C+'-panel).style.display=\\'none\\';lastActive=null">\u00d7</span>';
55
+ var h='<div style="display:flex;align-items:center;gap:8px;padding:10px 14px;border-bottom:1px solid ${panelBorder}">';
56
+ h+='<span style="font-weight:600;font-size:13px;color:${labelFg}">'+escapeHtml(detail.label)+'</span>';
57
+ h+='<span style="color:${dimText};font-size:11px">'+escapeHtml(detail.summary)+'</span>';
58
+ h+='<span style="margin-left:auto;cursor:pointer;color:${dimText};display:inline-flex;padding:2px" onclick="document.getElementById('+C+'-panel).style.display=\\'none\\';lastActive=null">${I.close}</span>';
48
59
  h+='</div>';
49
- h+='<table style="width:100%;border-collapse:collapse">';
60
+ h+='<div style="padding:8px 14px 14px;overflow-y:auto;max-height:340px">';
61
+ h+='<table style="width:100%;border-collapse:collapse;font-size:12px">';
50
62
  for (var k in detail.details) {
51
63
  var v=detail.details[k];
52
64
  if (k==='queries' && Array.isArray(v)) {
65
+ if (v.length===0) { h+='<tr><td style="padding:8px;color:${dimText}">No queries recorded</td></tr>'; continue; }
53
66
  for (var i=0;i<v.length;i++) {
54
- h+='<tr><td style="padding:4px 8px;color:${dimText};border-bottom:1px solid ${borderClr};vertical-align:top;width:80px">#'+(i+1)+'</td><td style="padding:4px 8px;border-bottom:1px solid ${borderClr};font-family:monospace;font-size:11px;word-break:break-all">'+escapeHtml(v[i].sql||'')+'</td><td style="padding:4px 8px;border-bottom:1px solid ${borderClr};text-align:right;color:${sqlTimeClr}">'+escapeHtml(v[i].duration||'')+'</td></tr>';
67
+ h+='<tr><td style="padding:5px 8px;color:${dimText};vertical-align:top;width:28px;font-size:11px;font-weight:500">'+(i+1)+'</td><td style="padding:5px 8px;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:11px;word-break:break-all;color:${labelFg}">'+escapeHtml(v[i].sql||'')+'</td><td style="padding:5px 8px;text-align:right;color:${sqlTimeClr};white-space:nowrap;font-family:ui-monospace,SF Mono,monospace;font-size:11px">'+escapeHtml(v[i].duration||'')+'</td></tr>';
55
68
  }
56
69
  continue;
57
70
  }
58
71
  if (k==='entries' && Array.isArray(v)) {
72
+ if (v.length===0) { h+='<tr><td style="padding:8px;color:${dimText}">No entries</td></tr>'; continue; }
59
73
  for (var i=0;i<v.length;i++) {
60
74
  var e=v[i];
61
75
  var lc=e.level==='error'?'${errClr}':e.level==='warn'?'${warnClr}':'${dimText}';
62
- h+='<tr><td style="padding:3px 8px;color:'+lc+';border-bottom:1px solid ${borderClr};width:60px;text-transform:uppercase;font-weight:600;font-size:10px">'+escapeHtml(e.level||'')+'</td><td style="padding:3px 8px;border-bottom:1px solid ${borderClr};word-break:break-all">'+escapeHtml(e.message||'')+'</td></tr>';
76
+ var bgc=e.level==='error'?'rgba(239,68,68,0.08)':e.level==='warn'?'rgba(245,158,11,0.08)':'transparent';
77
+ h+='<tr style="background:'+bgc+'"><td style="padding:5px 8px;color:'+lc+';width:52px;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.3px">'+escapeHtml(e.level||'')+'</td><td style="padding:5px 8px;word-break:break-all;color:${labelFg}">'+escapeHtml(e.message||'')+'</td></tr>';
63
78
  }
64
79
  continue;
65
80
  }
66
81
  if (k==='grouped' && Array.isArray(v)) {
67
82
  for (var i=0;i<v.length;i++) {
68
83
  var g=v[i];
69
- h+='<tr><td colspan="3" style="padding:6px 8px;color:${accentText};font-weight:600;border-bottom:1px solid ${borderClr}">'+escapeHtml(g.method||'')+' ('+(g.count||0)+')</td></tr>';
84
+ h+='<tr><td colspan="2" style="padding:7px 8px 3px;color:${accent};font-weight:600;font-size:11px">'+escapeHtml(g.method||'')+' <span style="color:${dimText};font-weight:400">('+(g.count||0)+')</span></td></tr>';
70
85
  if (g.routes) {
71
86
  for (var j=0;j<g.routes.length;j++) {
72
- h+='<tr><td style="padding:2px 8px 2px 24px;border-bottom:1px solid ${borderClr};font-family:monospace;font-size:11px" colspan="3">'+escapeHtml(g.routes[j].path||'')+' <span style="color:${dimmerText}">('+escapeHtml(g.routes[j].controller||'')+')</span></td></tr>';
87
+ h+='<tr><td style="padding:2px 8px 2px 16px;font-family:ui-monospace,SF Mono,monospace;font-size:11px;color:${labelFg}" colspan="2">'+escapeHtml(g.routes[j].path||'')+' <span style="color:${dimText}">('+escapeHtml(g.routes[j].controller||'')+')</span></td></tr>';
73
88
  }
74
89
  }
75
90
  }
76
91
  continue;
77
92
  }
78
- h+='<tr><td style="padding:4px 8px;color:${dimText};border-bottom:1px solid ${borderClr};width:120px;vertical-align:top">'+escapeHtml(k)+'</td><td style="padding:4px 8px;border-bottom:1px solid ${borderClr};word-break:break-all">'+escapeHtml(String(v))+'</td></tr>';
93
+ if (k==='exception' && v && typeof v==='object') {
94
+ h+='<tr><td style="padding:5px 8px;color:${errClr};font-weight:600" colspan="2">'+escapeHtml(v.message||'')+'</td></tr>';
95
+ h+='<tr><td colspan="2" style="padding:5px 8px"><pre style="font-family:ui-monospace,SF Mono,monospace;font-size:11px;color:${dimText};white-space:pre-wrap;margin:0;line-height:1.4">'+escapeHtml(v.stack||'')+'</pre></td></tr>';
96
+ continue;
97
+ }
98
+ if (k==='stack') continue;
99
+ if (typeof v==='object' && v!==null) continue;
100
+ h+='<tr><td style="padding:4px 8px;color:${dimText};width:90px;vertical-align:top;font-size:11px">'+escapeHtml(k)+'</td><td style="padding:4px 8px;word-break:break-all;color:${labelFg}">'+escapeHtml(String(v))+'</td></tr>';
79
101
  }
80
102
  h+='</table></div>';
81
- p.innerHTML=h;
82
- p.style.display='block';
83
- D.getElementById(C+'-toggle').innerHTML='&#x203a;';
103
+ pnl.innerHTML=h;
104
+ pnl.style.display='block';
105
+ D.getElementById(C+'-toggle').innerHTML='${I.chevron}';
84
106
  }
85
107
 
86
108
  function escapeHtml(s) {
87
109
  if (s==null) return '';
88
- return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
110
+ return String(s).replace(/[&<>"]/g,function(m){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[m]});
89
111
  }
90
112
 
113
+ var icons = {
114
+ request: '${I.req}',
115
+ performance: '${I.perf}',
116
+ database: '${I.db}',
117
+ routes: '${I.routes}',
118
+ logs: '${I.log}',
119
+ };
120
+
91
121
  var furl = p + '/data';
92
122
  fetch(furl).then(function(r){return r.json()}).then(function(d){
93
123
  var bar=D.getElementById(C+'-bar');
124
+ var order=['request','performance','database','routes','logs'];
94
125
  var panels=[];
95
- if(d.request) panels.push(d.request);
96
- if(d.performance) panels.push(d.performance);
97
- if(d.database) panels.push(d.database);
98
- if(d.routes) panels.push(d.routes);
99
- if(d.logs) panels.push(d.logs);
100
- for(var k in d){if(panels.indexOf(d[k])===-1&&d[k]&&d[k].label)panels.push(d[k]);}
101
- var icons={request:'🌐',performance:'⚡',database:'🗄️',routes:'📋',logs:'📝','default':'🔧'};
102
- panels.forEach(function(p,i){
103
- var ic=icons[p.label.toLowerCase()]||icons['default'];
126
+ for(var oi=0;oi<order.length;oi++){if(d[order[oi]])panels.push({key:order[oi],data:d[order[oi]]});}
127
+ for(var k in d){var found=false;for(var pi=0;pi<panels.length;pi++){if(panels[pi].key===k){found=true;break}}if(!found&&d[k]&&d[k].label)panels.push({key:k,data:d[k]});}
128
+ panels.forEach(function(item,idx){
129
+ var p=item.data;
130
+ var ic=icons[item.key]||'${I.log}';
104
131
  var btn=D.createElement('span');
105
- btn.style.cssText='display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:4px;cursor:pointer;color:${btnFg};background:${btnBg};margin:0 2px;transition:background .15s';
106
- btn.innerHTML=ic+' '+escapeHtml(p.summary);
107
- btn.onmouseenter=function(){this.style.background='${btnHover}'};
108
- btn.onmouseleave=function(){this.style.background='${btnBg}'};
132
+ btn.style.cssText='display:inline-flex;align-items:center;gap:5px;padding:4px 10px;border-radius:6px;cursor:pointer;color:${btnFg};background:${btnBg};margin:0 1px;transition:all .12s ease;font-size:11px;font-weight:500';
133
+ btn.innerHTML=ic+'<span>'+escapeHtml(p.summary)+'</span>';
134
+ btn.onmouseenter=function(){this.style.background='${btnHover}';this.style.color='${fg}'};
135
+ btn.onmouseleave=function(){this.style.background='${btnBg}';this.style.color='${btnFg}'};
109
136
  btn.onclick=function(n){return function(){
110
- var key=Object.keys(d).filter(function(k){return d[k]===d[n]})[0];
137
+ var key=Object.keys(d).filter(function(kr){return d[kr]===d[n]})[0];
111
138
  renderPanel(key,d[key]);
112
- }}(i);
139
+ }}(item.key);
113
140
  bar.appendChild(btn);
114
141
  });
115
142
  D.getElementById(C+'-toggle').onclick=function(){
116
143
  var pnl=D.getElementById(C+'-panel');
117
- pnl.style.display=pnl.style.display==='none'?'block':'none';
118
- this.innerHTML=pnl.style.display==='block'?'\u203A':'\u2039';
144
+ var isOpen=pnl.style.display==='block';
145
+ pnl.style.display=isOpen?'none':'block';
146
+ this.innerHTML=isOpen?'${I.chevron}':'${I.close}';
147
+ if(isOpen)lastActive=null;
119
148
  };
120
149
  }).catch(function(){});
121
150
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../toolbar/template.ts"],"names":[],"mappings":";;;AAKO,MAAM,gBAAgB,GAAG,CAAC,MAAuC,EAAE,EAAE;IAC1E,MAAM,EAAE,QAAQ,GAAG,aAAa,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAClE,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjD,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,8BAA8B,CAAC;IAC/F,MAAM,WAAW,GAAG,KAAK;QACvB,CAAC,CAAC,wCAAwC;QAC1C,CAAC,CAAC,yCAAyC,CAAC;IAE9C,MAAM,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACxC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAChD,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1B,MAAM,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhD,OAAO,eAAe,EAAE;;4CAEkB,GAAG;;;4CAGH,QAAQ,IAAI,SAAS,gGAAgG,EAAE,UAAU,EAAE,IAAI,WAAW,eAAe,WAAW,8LAA8L,UAAU,kIAAkI,UAAU,iJAAiJ,UAAU,uIAAuI,SAAS,eAAe,OAAO;;;;;;;;;;;6BAWh1B,OAAO;6DACyB,UAAU;;;;;;;qDAOlB,OAAO,4BAA4B,SAAS,qGAAqG,SAAS,mJAAmJ,SAAS,2BAA2B,UAAU;;;;;;;sCAO1W,MAAM,uBAAuB,OAAO,MAAM,OAAO;oFACH,SAAS,2JAA2J,SAAS;;;;;;;iEAOhM,UAAU,4CAA4C,SAAS;;;oFAG5C,SAAS,8GAA8G,UAAU;;;;;;iDAMpK,OAAO,4BAA4B,SAAS,6GAA6G,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;kIA2BjF,KAAK,eAAe,KAAK;;2DAEhG,QAAQ;2DACR,KAAK;;;;;;;;;;;;;;UActD,CAAC;AACX,CAAC,CAAC;AA3HW,QAAA,gBAAgB,oBA2H3B"}
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../toolbar/template.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestjs-devtools",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Symfony-style debug toolbar for NestJS applications",
5
5
  "keywords": [
6
6
  "nestjs",