@mantiq/heartbeat 0.3.4 → 0.3.6

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.4",
3
+ "version": "0.3.6",
4
4
  "description": "Observability, APM & queue monitoring for MantiqJS",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -136,28 +136,41 @@ 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
-
149
139
  // Flush entries (fire-and-forget)
150
140
  this.heartbeat.flush()
151
141
  }
152
142
 
153
- // Inject debug widget into HTML responses when APP_DEBUG=true
143
+ // Debug mode: attach X-Heartbeat header + inject widget
154
144
  if (process.env.APP_DEBUG === 'true' && response!) {
155
- const ct = response!.headers.get('content-type') ?? ''
156
- if (ct.includes('text/html') && response!.status < 400) {
157
- const duration = performance.now() - startTime
158
- const memUsage = process.memoryUsage().rss - startMemory
159
- response = await this.injectWidget(response!, duration, memUsage)
160
- }
145
+ const totalDuration = performance.now() - startTime
146
+ const totalMemory = Math.abs(process.memoryUsage().rss - startMemory)
147
+ const mem = (totalMemory / 1024 / 1024).toFixed(1)
148
+ const statsHeader = `${Math.round(totalDuration)}ms;${mem}MB;${response!.status};0q`
149
+
150
+ try {
151
+ const ct = response!.headers.get('content-type') ?? ''
152
+ const isHtml = ct.includes('text/html') && response!.status < 400
153
+ const cloned = response!.clone()
154
+ const body = await cloned.text()
155
+ const headers = new Headers(response!.headers)
156
+
157
+ headers.set('X-Heartbeat', statsHeader)
158
+ headers.set('Access-Control-Expose-Headers', [headers.get('Access-Control-Expose-Headers'), 'X-Heartbeat'].filter(Boolean).join(', '))
159
+
160
+ let finalBody = body
161
+ if (isHtml && this.heartbeat.config.widget?.enabled !== false && body.includes('</body>')) {
162
+ const widget = renderWidget({
163
+ duration: totalDuration,
164
+ memory: totalMemory,
165
+ status: response!.status,
166
+ queries: 0,
167
+ dashboardPath: this.heartbeat.config.dashboard.path,
168
+ })
169
+ finalBody = body.replace('</body>', widget + '\n</body>')
170
+ }
171
+
172
+ response = new Response(finalBody, { status: response!.status, statusText: response!.statusText, headers })
173
+ } catch (e) { console.error('[Heartbeat Widget]', e) }
161
174
  }
162
175
 
163
176
  return response!
@@ -224,29 +237,4 @@ export class HeartbeatMiddleware implements Middleware {
224
237
  }
225
238
  }
226
239
 
227
- private async injectWidget(response: Response, duration: number, memory: number): Promise<Response> {
228
- if (this.heartbeat.config.widget?.enabled === false) return response
229
-
230
- try {
231
- const html = await response.text()
232
- if (!html.includes('</body>')) return new Response(html, { status: response.status, statusText: response.statusText, headers: response.headers })
233
-
234
- const widget = renderWidget({
235
- duration,
236
- memory: Math.abs(memory),
237
- status: response.status,
238
- queries: 0, // TODO: wire up query count from QueryWatcher
239
- dashboardPath: this.heartbeat.config.dashboard.path,
240
- })
241
-
242
- const injected = html.replace('</body>', widget + '\n</body>')
243
- return new Response(injected, {
244
- status: response.status,
245
- statusText: response.statusText,
246
- headers: response.headers,
247
- })
248
- } catch {
249
- return response
250
- }
251
- }
252
240
  }