@mantiq/heartbeat 0.3.2 → 0.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mantiq/heartbeat",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Observability, APM & queue monitoring for MantiqJS",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -136,6 +136,16 @@ export class HeartbeatMiddleware implements Middleware {
136
136
  }
137
137
  }
138
138
 
139
+ // Attach debug stats header: duration;memory;status;queries
140
+ if (process.env.APP_DEBUG === 'true' && response!) {
141
+ try {
142
+ const mem = (Math.abs(process.memoryUsage().rss - startMemory) / 1024 / 1024).toFixed(1)
143
+ const headers = new Headers(response!.headers)
144
+ headers.set('X-Heartbeat', `${Math.round(duration)}ms;${mem}MB;${response!.status};0q`)
145
+ response = new Response(response!.body, { status: response!.status, statusText: response!.statusText, headers })
146
+ } catch { /* ignore */ }
147
+ }
148
+
139
149
  // Flush entries (fire-and-forget)
140
150
  this.heartbeat.flush()
141
151
  }
@@ -20,8 +20,8 @@ export function renderWidget(data: {
20
20
  #__mw{position:fixed;bottom:16px;right:16px;z-index:99999;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;font-size:12px}
21
21
  #__mw_pill{display:flex;align-items:center;gap:6px;background:#0a0a0b;border:1px solid #27272a;border-radius:100px;padding:7px 14px 7px 10px;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.5);color:#71717a;transition:border-color .2s;user-select:none}
22
22
  #__mw_pill:hover{border-color:#34d399}
23
- #__mw_logo{display:flex;align-items:center;gap:5px;color:#34d399;font-weight:700;font-size:11px;letter-spacing:-.01em;border-right:1px solid #27272a;padding-right:8px;margin-right:2px}
24
- #__mw_logo span{width:5px;height:5px;border-radius:50%;background:#34d399}
23
+ #__mw_logo{display:flex;align-items:center;border-right:1px solid #27272a;padding-right:8px;margin-right:2px}
24
+ #__mw_logo span{width:7px;height:7px;border-radius:50%;background:#34d399}
25
25
  #__mw_stats{display:flex;align-items:center;gap:6px}
26
26
  #__mw_stats b{color:#fafafa;font-weight:600}
27
27
  #__mw_dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}
@@ -30,8 +30,6 @@ export function renderWidget(data: {
30
30
  #__mw_panel header{padding:14px 16px;border-bottom:1px solid #1e1e1e;display:flex;align-items:center;justify-content:space-between}
31
31
  #__mw_panel header .brand{display:flex;align-items:center;gap:6px;color:#fafafa;font-weight:700;font-size:12px;letter-spacing:-.01em}
32
32
  #__mw_panel header .brand i{width:6px;height:6px;border-radius:50%;background:#34d399}
33
- #__mw_panel header a{color:#52525b;text-decoration:none;font-size:11px}
34
- #__mw_panel header a:hover{color:#34d399}
35
33
  #__mw_grid{display:grid;grid-template-columns:1fr 1fr;gap:0}
36
34
  #__mw_grid .cell{padding:14px 16px;border-bottom:1px solid #1e1e1e}
37
35
  #__mw_grid .cell:nth-child(odd){border-right:1px solid #1e1e1e}
@@ -44,7 +42,7 @@ export function renderWidget(data: {
44
42
  </style>
45
43
  <div id="__mw">
46
44
  <div id="__mw_pill" onclick="document.getElementById('__mw_panel').style.display=document.getElementById('__mw_panel').style.display==='none'?'block':'none'">
47
- <div id="__mw_logo"><span></span>mantiq</div>
45
+ <div id="__mw_logo"><span></span></div>
48
46
  <div id="__mw_stats">
49
47
  <span id="__mw_dot" style="background:${statusColor}"></span>
50
48
  <b>${durationMs}ms</b>
@@ -57,7 +55,6 @@ export function renderWidget(data: {
57
55
  <div id="__mw_panel">
58
56
  <header>
59
57
  <div class="brand"><i></i>mantiq</div>
60
- <a href="${dashboardPath}">Dashboard &rarr;</a>
61
58
  </header>
62
59
  <div id="__mw_grid">
63
60
  <div class="cell"><label>Duration</label><div class="val">${durationMs}<small>ms</small></div></div>
@@ -70,6 +67,41 @@ export function renderWidget(data: {
70
67
  </div>
71
68
  </div>
72
69
  </div>
73
- <script>document.addEventListener('keydown',function(e){if(e.key==='Escape')document.getElementById('__mw_panel').style.display='none'});</script>
70
+ <script>
71
+ (function(){
72
+ document.addEventListener('keydown',function(e){if(e.key==='Escape')document.getElementById('__mw_panel').style.display='none'});
73
+
74
+ // Intercept fetch to read X-Heartbeat header and update widget
75
+ var _fetch=window.fetch;
76
+ window.fetch=function(){
77
+ return _fetch.apply(this,arguments).then(function(res){
78
+ var h=res.headers.get('X-Heartbeat');
79
+ if(h)updateWidget(h);
80
+ return res;
81
+ });
82
+ };
83
+
84
+ function updateWidget(header){
85
+ // Format: 15ms;1.6MB;200;0q
86
+ var p=header.split(';');
87
+ if(p.length<4)return;
88
+ var dur=p[0],mem=p[1],status=parseInt(p[2]),queries=p[3];
89
+ var sc=status>=500?'#f87171':status>=400?'#fbbf24':'#34d399';
90
+
91
+ // Update pill
92
+ var pill=document.getElementById('__mw_stats');
93
+ if(pill)pill.innerHTML='<span id="__mw_dot" style="width:5px;height:5px;border-radius:50%;background:'+sc+';flex-shrink:0"></span><b style="color:#fafafa;font-weight:600">'+dur+'</b><span id="__mw_sep" style="color:#27272a">&middot;</span><span>'+mem+'</span><span id="__mw_sep" style="color:#27272a">&middot;</span><span>'+queries+'</span>';
94
+
95
+ // Update panel grid
96
+ var cells=document.querySelectorAll('#__mw_grid .cell .val');
97
+ if(cells.length>=4){
98
+ cells[0].innerHTML=dur.replace('ms','')+'<small>ms</small>';
99
+ cells[1].innerHTML=mem.replace('MB','')+'<small>MB</small>';
100
+ cells[2].innerHTML=status;cells[2].style.color=sc;
101
+ cells[3].innerHTML=queries.replace('q','');
102
+ }
103
+ }
104
+ })();
105
+ </script>
74
106
  <!-- /mantiq:heartbeat-widget -->`
75
107
  }