@bbearai/core 0.9.3 → 0.9.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/dist/index.d.mts CHANGED
@@ -72,6 +72,14 @@ interface EnhancedBugContext {
72
72
  pageLoadTime?: number;
73
73
  memoryUsage?: number;
74
74
  fps?: number;
75
+ /** First Contentful Paint (ms) */
76
+ fcp?: number;
77
+ /** Largest Contentful Paint (ms) */
78
+ lcp?: number;
79
+ /** Cumulative Layout Shift (score) */
80
+ cls?: number;
81
+ /** Time to First Byte (ms) */
82
+ ttfb?: number;
75
83
  };
76
84
  /** Browser/environment info */
77
85
  environment?: {
@@ -80,6 +88,10 @@ interface EnhancedBugContext {
80
88
  cookiesEnabled?: boolean;
81
89
  localStorage?: boolean;
82
90
  online?: boolean;
91
+ /** Effective connection type (e.g. '4g', '3g') */
92
+ connectionType?: string;
93
+ /** Downlink speed in Mbps */
94
+ connectionDownlink?: number;
83
95
  };
84
96
  }
85
97
  interface DeviceInfo {
@@ -96,6 +108,13 @@ interface DeviceInfo {
96
108
  width: number;
97
109
  height: number;
98
110
  };
111
+ /** Viewport dimensions (visible area) */
112
+ viewport?: {
113
+ width: number;
114
+ height: number;
115
+ };
116
+ /** Device pixel ratio */
117
+ devicePixelRatio?: number;
99
118
  /** User agent (web) */
100
119
  userAgent?: string;
101
120
  }
@@ -296,6 +315,17 @@ interface MonitoringEvent {
296
315
  clickCount?: number;
297
316
  /** CSS selector of the clicked element (rage clicks only) */
298
317
  targetSelector?: string;
318
+ /** Whether the tab was visible when the event fired */
319
+ tabVisible?: boolean;
320
+ /** CSS selector of the focused element at event time */
321
+ focusedElement?: string;
322
+ /** Rage click coordinates */
323
+ clickCoordinates?: {
324
+ x: number;
325
+ y: number;
326
+ };
327
+ /** Response body snippet for API failures (max 300 chars) */
328
+ apiErrorBody?: string;
299
329
  /** Sentry event ID — populated by @bbearai/sentry adapter */
300
330
  sentryEventId?: string;
301
331
  /** Sentry breadcrumbs — populated by @bbearai/sentry adapter */
package/dist/index.d.ts CHANGED
@@ -72,6 +72,14 @@ interface EnhancedBugContext {
72
72
  pageLoadTime?: number;
73
73
  memoryUsage?: number;
74
74
  fps?: number;
75
+ /** First Contentful Paint (ms) */
76
+ fcp?: number;
77
+ /** Largest Contentful Paint (ms) */
78
+ lcp?: number;
79
+ /** Cumulative Layout Shift (score) */
80
+ cls?: number;
81
+ /** Time to First Byte (ms) */
82
+ ttfb?: number;
75
83
  };
76
84
  /** Browser/environment info */
77
85
  environment?: {
@@ -80,6 +88,10 @@ interface EnhancedBugContext {
80
88
  cookiesEnabled?: boolean;
81
89
  localStorage?: boolean;
82
90
  online?: boolean;
91
+ /** Effective connection type (e.g. '4g', '3g') */
92
+ connectionType?: string;
93
+ /** Downlink speed in Mbps */
94
+ connectionDownlink?: number;
83
95
  };
84
96
  }
85
97
  interface DeviceInfo {
@@ -96,6 +108,13 @@ interface DeviceInfo {
96
108
  width: number;
97
109
  height: number;
98
110
  };
111
+ /** Viewport dimensions (visible area) */
112
+ viewport?: {
113
+ width: number;
114
+ height: number;
115
+ };
116
+ /** Device pixel ratio */
117
+ devicePixelRatio?: number;
99
118
  /** User agent (web) */
100
119
  userAgent?: string;
101
120
  }
@@ -296,6 +315,17 @@ interface MonitoringEvent {
296
315
  clickCount?: number;
297
316
  /** CSS selector of the clicked element (rage clicks only) */
298
317
  targetSelector?: string;
318
+ /** Whether the tab was visible when the event fired */
319
+ tabVisible?: boolean;
320
+ /** CSS selector of the focused element at event time */
321
+ focusedElement?: string;
322
+ /** Rage click coordinates */
323
+ clickCoordinates?: {
324
+ x: number;
325
+ y: number;
326
+ };
327
+ /** Response body snippet for API failures (max 300 chars) */
328
+ apiErrorBody?: string;
299
329
  /** Sentry event ID — populated by @bbearai/sentry adapter */
300
330
  sentryEventId?: string;
301
331
  /** Sentry breadcrumbs — populated by @bbearai/sentry adapter */
package/dist/index.js CHANGED
@@ -279,17 +279,43 @@ var ContextCaptureManager = class {
279
279
  }
280
280
  } catch {
281
281
  }
282
+ try {
283
+ const navigation = performance.getEntriesByType("navigation")[0];
284
+ if (navigation) {
285
+ metrics.ttfb = Math.round(navigation.responseStart - navigation.startTime);
286
+ }
287
+ const paintEntries = performance.getEntriesByType("paint");
288
+ const fcp = paintEntries.find((e) => e.name === "first-contentful-paint");
289
+ if (fcp) metrics.fcp = Math.round(fcp.startTime);
290
+ const lcpEntries = performance.getEntriesByType("largest-contentful-paint");
291
+ if (lcpEntries.length > 0) {
292
+ metrics.lcp = Math.round(lcpEntries[lcpEntries.length - 1].startTime);
293
+ }
294
+ const clsEntries = performance.getEntriesByType("layout-shift");
295
+ if (clsEntries.length > 0) {
296
+ metrics.cls = parseFloat(
297
+ clsEntries.filter((e) => !e.hadRecentInput).reduce((sum, e) => sum + (e.value ?? 0), 0).toFixed(4)
298
+ );
299
+ }
300
+ } catch {
301
+ }
282
302
  return Object.keys(metrics).length > 0 ? metrics : void 0;
283
303
  }
284
304
  getEnvironmentInfo() {
285
305
  if (typeof window === "undefined" || typeof navigator === "undefined" || typeof document === "undefined") return void 0;
286
- return {
306
+ const env = {
287
307
  language: navigator.language,
288
308
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
289
309
  cookiesEnabled: navigator.cookieEnabled ?? false,
290
310
  localStorage: typeof localStorage !== "undefined",
291
311
  online: navigator.onLine ?? true
292
312
  };
313
+ const conn = navigator.connection;
314
+ if (conn) {
315
+ env.connectionType = conn.effectiveType;
316
+ env.connectionDownlink = conn.downlink;
317
+ }
318
+ return env;
293
319
  }
294
320
  };
295
321
  var contextCapture = new ContextCaptureManager();
@@ -571,6 +597,10 @@ var ErrorMonitor = class {
571
597
  ...event.requestMethod ? { requestMethod: event.requestMethod } : {},
572
598
  ...event.clickCount ? { clickCount: event.clickCount } : {},
573
599
  ...event.targetSelector ? { targetSelector: event.targetSelector } : {},
600
+ ...event.tabVisible !== void 0 ? { tabVisible: event.tabVisible } : {},
601
+ ...event.focusedElement ? { focusedElement: event.focusedElement } : {},
602
+ ...event.clickCoordinates ? { clickCoordinates: event.clickCoordinates } : {},
603
+ ...event.apiErrorBody ? { apiErrorBody: event.apiErrorBody } : {},
574
604
  ...event.sentryEventId ? { sentryEventId: event.sentryEventId } : {}
575
605
  }
576
606
  },
@@ -664,7 +694,9 @@ var WebCrashHandler = class {
664
694
  message: msg,
665
695
  route,
666
696
  timestamp: Date.now(),
667
- error: error ?? new Error(msg)
697
+ error: error ?? new Error(msg),
698
+ tabVisible: !document.hidden,
699
+ focusedElement: document.activeElement instanceof Element ? getSelector(document.activeElement) : void 0
668
700
  });
669
701
  if (typeof this.prevOnError === "function") {
670
702
  return this.prevOnError(message, source, lineno, colno, error);
@@ -682,7 +714,9 @@ var WebCrashHandler = class {
682
714
  message: msg,
683
715
  route,
684
716
  timestamp: Date.now(),
685
- error
717
+ error,
718
+ tabVisible: !document.hidden,
719
+ focusedElement: document.activeElement instanceof Element ? getSelector(document.activeElement) : void 0
686
720
  });
687
721
  };
688
722
  window.addEventListener("unhandledrejection", this.rejectionHandler);
@@ -711,6 +745,13 @@ var WebApiFailureHandler = class {
711
745
  const method = (init?.method ?? "GET").toUpperCase();
712
746
  const route = currentRoute();
713
747
  const msg = `${method} ${url} failed with ${response.status}`;
748
+ let apiErrorBody;
749
+ try {
750
+ const cloned = response.clone();
751
+ const text = await cloned.text();
752
+ if (text) apiErrorBody = text.slice(0, 300);
753
+ } catch {
754
+ }
714
755
  onEvent({
715
756
  source: "api_failure",
716
757
  fingerprint: generateFingerprint("api_failure", msg, route),
@@ -719,7 +760,9 @@ var WebApiFailureHandler = class {
719
760
  timestamp: Date.now(),
720
761
  requestUrl: url,
721
762
  requestMethod: method,
722
- statusCode: response.status
763
+ statusCode: response.status,
764
+ tabVisible: !document.hidden,
765
+ apiErrorBody
723
766
  });
724
767
  }
725
768
  return response;
@@ -745,7 +788,8 @@ var WebRageClickHandler = class {
745
788
  route,
746
789
  timestamp: Date.now(),
747
790
  clickCount: rageEvent.clickCount,
748
- targetSelector: rageEvent.targetSelector
791
+ targetSelector: rageEvent.targetSelector,
792
+ clickCoordinates: { x: rageEvent.x, y: rageEvent.y }
749
793
  });
750
794
  });
751
795
  }
@@ -2505,6 +2549,8 @@ var BugBearClient = class {
2505
2549
  height: window.screen.height
2506
2550
  };
2507
2551
  }
2552
+ info.viewport = { width: window.innerWidth, height: window.innerHeight };
2553
+ info.devicePixelRatio = window.devicePixelRatio;
2508
2554
  return info;
2509
2555
  }
2510
2556
  return { platform: "web" };
package/dist/index.mjs CHANGED
@@ -233,17 +233,43 @@ var ContextCaptureManager = class {
233
233
  }
234
234
  } catch {
235
235
  }
236
+ try {
237
+ const navigation = performance.getEntriesByType("navigation")[0];
238
+ if (navigation) {
239
+ metrics.ttfb = Math.round(navigation.responseStart - navigation.startTime);
240
+ }
241
+ const paintEntries = performance.getEntriesByType("paint");
242
+ const fcp = paintEntries.find((e) => e.name === "first-contentful-paint");
243
+ if (fcp) metrics.fcp = Math.round(fcp.startTime);
244
+ const lcpEntries = performance.getEntriesByType("largest-contentful-paint");
245
+ if (lcpEntries.length > 0) {
246
+ metrics.lcp = Math.round(lcpEntries[lcpEntries.length - 1].startTime);
247
+ }
248
+ const clsEntries = performance.getEntriesByType("layout-shift");
249
+ if (clsEntries.length > 0) {
250
+ metrics.cls = parseFloat(
251
+ clsEntries.filter((e) => !e.hadRecentInput).reduce((sum, e) => sum + (e.value ?? 0), 0).toFixed(4)
252
+ );
253
+ }
254
+ } catch {
255
+ }
236
256
  return Object.keys(metrics).length > 0 ? metrics : void 0;
237
257
  }
238
258
  getEnvironmentInfo() {
239
259
  if (typeof window === "undefined" || typeof navigator === "undefined" || typeof document === "undefined") return void 0;
240
- return {
260
+ const env = {
241
261
  language: navigator.language,
242
262
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
243
263
  cookiesEnabled: navigator.cookieEnabled ?? false,
244
264
  localStorage: typeof localStorage !== "undefined",
245
265
  online: navigator.onLine ?? true
246
266
  };
267
+ const conn = navigator.connection;
268
+ if (conn) {
269
+ env.connectionType = conn.effectiveType;
270
+ env.connectionDownlink = conn.downlink;
271
+ }
272
+ return env;
247
273
  }
248
274
  };
249
275
  var contextCapture = new ContextCaptureManager();
@@ -525,6 +551,10 @@ var ErrorMonitor = class {
525
551
  ...event.requestMethod ? { requestMethod: event.requestMethod } : {},
526
552
  ...event.clickCount ? { clickCount: event.clickCount } : {},
527
553
  ...event.targetSelector ? { targetSelector: event.targetSelector } : {},
554
+ ...event.tabVisible !== void 0 ? { tabVisible: event.tabVisible } : {},
555
+ ...event.focusedElement ? { focusedElement: event.focusedElement } : {},
556
+ ...event.clickCoordinates ? { clickCoordinates: event.clickCoordinates } : {},
557
+ ...event.apiErrorBody ? { apiErrorBody: event.apiErrorBody } : {},
528
558
  ...event.sentryEventId ? { sentryEventId: event.sentryEventId } : {}
529
559
  }
530
560
  },
@@ -618,7 +648,9 @@ var WebCrashHandler = class {
618
648
  message: msg,
619
649
  route,
620
650
  timestamp: Date.now(),
621
- error: error ?? new Error(msg)
651
+ error: error ?? new Error(msg),
652
+ tabVisible: !document.hidden,
653
+ focusedElement: document.activeElement instanceof Element ? getSelector(document.activeElement) : void 0
622
654
  });
623
655
  if (typeof this.prevOnError === "function") {
624
656
  return this.prevOnError(message, source, lineno, colno, error);
@@ -636,7 +668,9 @@ var WebCrashHandler = class {
636
668
  message: msg,
637
669
  route,
638
670
  timestamp: Date.now(),
639
- error
671
+ error,
672
+ tabVisible: !document.hidden,
673
+ focusedElement: document.activeElement instanceof Element ? getSelector(document.activeElement) : void 0
640
674
  });
641
675
  };
642
676
  window.addEventListener("unhandledrejection", this.rejectionHandler);
@@ -665,6 +699,13 @@ var WebApiFailureHandler = class {
665
699
  const method = (init?.method ?? "GET").toUpperCase();
666
700
  const route = currentRoute();
667
701
  const msg = `${method} ${url} failed with ${response.status}`;
702
+ let apiErrorBody;
703
+ try {
704
+ const cloned = response.clone();
705
+ const text = await cloned.text();
706
+ if (text) apiErrorBody = text.slice(0, 300);
707
+ } catch {
708
+ }
668
709
  onEvent({
669
710
  source: "api_failure",
670
711
  fingerprint: generateFingerprint("api_failure", msg, route),
@@ -673,7 +714,9 @@ var WebApiFailureHandler = class {
673
714
  timestamp: Date.now(),
674
715
  requestUrl: url,
675
716
  requestMethod: method,
676
- statusCode: response.status
717
+ statusCode: response.status,
718
+ tabVisible: !document.hidden,
719
+ apiErrorBody
677
720
  });
678
721
  }
679
722
  return response;
@@ -699,7 +742,8 @@ var WebRageClickHandler = class {
699
742
  route,
700
743
  timestamp: Date.now(),
701
744
  clickCount: rageEvent.clickCount,
702
- targetSelector: rageEvent.targetSelector
745
+ targetSelector: rageEvent.targetSelector,
746
+ clickCoordinates: { x: rageEvent.x, y: rageEvent.y }
703
747
  });
704
748
  });
705
749
  }
@@ -2459,6 +2503,8 @@ var BugBearClient = class {
2459
2503
  height: window.screen.height
2460
2504
  };
2461
2505
  }
2506
+ info.viewport = { width: window.innerWidth, height: window.innerHeight };
2507
+ info.devicePixelRatio = window.devicePixelRatio;
2462
2508
  return info;
2463
2509
  }
2464
2510
  return { platform: "web" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/core",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Core utilities and types for BugBear QA platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",