Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bugsnag/browser-performance

Package Overview
Dependencies
Maintainers
10
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bugsnag/browser-performance - npm Package Compare versions

Comparing version 0.0.2-alpha.2 to 0.0.2-alpha.3

dist/auto-instrumentation/route-change-plugin.js

19

dist/auto-instrumentation/full-page-load-plugin.js

@@ -23,12 +23,13 @@ class FullPageLoadPlugin {

}
const route = configuration.routingProvider.resolveRoute(new URL(this.location.href));
const startTime = 0; // TODO: Ensure this correctly resolves to timeOrigin
const span = this.spanFactory.startSpan(`[FullPageLoad]${route}`, startTime);
// Browser attributes
span.setAttribute('bugsnag.span.category', 'full_page_load');
span.setAttribute('bugsnag.browser.page.referrer', this.document.referrer);
span.setAttribute('bugsnag.browser.page.route', route);
const url = new URL(this.location.href);
this.onSettle((endTime) => {
// note: we don't need to check if we were backgrounded here
// as the span factory already checks for backgrounding on all open spans
if (this.wasBackgrounded)
return;
const route = configuration.routingProvider.resolveRoute(url);
const startTime = 0;
const span = this.spanFactory.startSpan(`[FullPageLoad]${route}`, startTime);
// Browser attributes
span.setAttribute('bugsnag.span.category', 'full_page_load');
span.setAttribute('bugsnag.browser.page.referrer', this.document.referrer);
span.setAttribute('bugsnag.browser.page.route', route);
this.webVitals.attachTo(span);

@@ -35,0 +36,0 @@ this.spanFactory.endSpan(span, endTime);

import { createClient } from '@bugsnag/core-performance';
import { FullPageLoadPlugin } from './auto-instrumentation/full-page-load-plugin.js';
import { NetworkRequestPlugin } from './auto-instrumentation/network-request-plugin.js';
import { RouteChangePlugin } from './auto-instrumentation/route-change-plugin.js';
import createBrowserBackgroundingListener from './backgrounding-listener.js';
import createClock from './clock.js';
import { createSchema } from './config.js';
import { createDefaultRoutingProvider } from './default-routing-provider.js';
import createBrowserDeliveryFactory from './delivery.js';
import idGenerator from './id-generator.js';
import createOnSettle from './on-settle/index.js';
import createFetchRequestTracker from './request-tracker/request-tracker-fetch.js';
import createXmlHttpRequestTracker from './request-tracker/request-tracker-xhr.js';
import createResourceAttributesSource from './resource-attributes-source.js';
import createSpanAttributesSource from './span-attributes-source.js';
import createFetchRequestTracker from './request-tracker/request-tracker-fetch.js';
import createXmlHttpRequestTracker from './request-tracker/request-tracker-xhr.js';
import { NetworkRequestPlugin } from './auto-instrumentation/network-request-plugin.js';
import { WebVitals } from './web-vitals.js';

@@ -24,2 +26,3 @@

const onSettle = createOnSettle(clock, window, fetchRequestTracker, xhrRequestTracker, performance);
const DefaultRoutingProvider = createDefaultRoutingProvider(onSettle, window.location);
const BugsnagPerformance = createClient({

@@ -32,10 +35,11 @@ backgroundingListener,

idGenerator,
schema: createSchema(window.location.hostname),
schema: createSchema(window.location.hostname, new DefaultRoutingProvider()),
plugins: (spanFactory) => [
onSettle,
new FullPageLoadPlugin(document, window.location, spanFactory, webVitals, onSettle, backgroundingListener),
new NetworkRequestPlugin(spanFactory, fetchRequestTracker, xhrRequestTracker)
new NetworkRequestPlugin(spanFactory, fetchRequestTracker, xhrRequestTracker),
new RouteChangePlugin(spanFactory, clock, window.location)
]
});
export { BugsnagPerformance as default };
export { DefaultRoutingProvider, BugsnagPerformance as default, onSettle };
import { schema, isStringOrRegExpArray } from '@bugsnag/core-performance';
import { DefaultRoutingProvider, isRoutingProvider } from './routing-provider.js';
import { isRoutingProvider } from './routing-provider.js';
function createSchema(hostname) {
function createSchema(hostname, defaultRoutingProvider) {
return Object.assign(Object.assign({}, schema), { releaseStage: Object.assign(Object.assign({}, schema.releaseStage), { defaultValue: hostname === 'localhost' ? 'development' : 'production' }), autoInstrumentFullPageLoads: {

@@ -13,4 +13,8 @@ defaultValue: true,

validate: (value) => value === true || value === false
}, autoInstrumentRouteChanges: {
defaultValue: true,
message: 'should be true|false',
validate: (value) => value === true || value === false
}, routingProvider: {
defaultValue: new DefaultRoutingProvider(),
defaultValue: defaultRoutingProvider,
message: 'should be a routing provider',

@@ -17,0 +21,0 @@ validate: isRoutingProvider

@@ -1,2 +0,1 @@

export { default } from './browser.js';
export { DefaultRoutingProvider } from './routing-provider.js';
export { DefaultRoutingProvider, default, onSettle } from './browser.js';

@@ -25,3 +25,4 @@ import { Settler } from './settler.js';

// there's only ever one navigation entry
const entry = performance.getEntriesByType('navigation')[0];
// PLAT-10204 Prevent snags occuring due to DOM scanning bots like BuiltWith https://builtwith.com/biup
const entry = typeof performance.getEntriesByType === 'function' ? performance.getEntriesByType('navigation')[0] : undefined;
let settledTime;

@@ -28,0 +29,0 @@ if (isPerformanceNavigationTiming(entry)) {

@@ -5,3 +5,3 @@ import { ResourceAttributes } from '@bugsnag/core-performance';

return function resourceAttributesSource(config) {
const attributes = new ResourceAttributes(config.releaseStage, config.appVersion, 'bugsnag.performance.browser', '0.0.2-alpha.1');
const attributes = new ResourceAttributes(config.releaseStage, config.appVersion, 'bugsnag.performance.browser', '0.0.2-alpha.2');
attributes.set('browser.user_agent', navigator.userAgent);

@@ -8,0 +8,0 @@ // chromium only

import { isObject } from '@bugsnag/core-performance';
const defaultRouteResolver = (url) => url.pathname;
class DefaultRoutingProvider {
constructor(resolveRoute = defaultRouteResolver) {
this.resolveRoute = resolveRoute;
}
}
const isRoutingProvider = (value) => isObject(value) &&
typeof value.resolveRoute === 'function';
typeof value.resolveRoute === 'function' &&
typeof value.listenForRouteChanges === 'function';
export { DefaultRoutingProvider, isRoutingProvider };
export { isRoutingProvider };

@@ -0,3 +1,10 @@

export declare const onSettle: import("./on-settle").OnSettlePlugin;
export declare const DefaultRoutingProvider: {
new (resolveRoute?: import("./routing-provider").RouteResolver): {
resolveRoute: import("./routing-provider").RouteResolver;
listenForRouteChanges(startRouteChangeSpan: import("./routing-provider").StartRouteChangeCallback): void;
};
};
declare const BugsnagPerformance: import("@bugsnag/core-performance").BugsnagPerformance<import("./config").BrowserConfiguration>;
export default BugsnagPerformance;
//# sourceMappingURL=browser.d.ts.map

@@ -6,2 +6,3 @@ import { type ConfigOption, type Configuration, type CoreSchema } from '@bugsnag/core-performance';

autoInstrumentNetworkRequests: ConfigOption<boolean>;
autoInstrumentRouteChanges: ConfigOption<boolean>;
routingProvider: ConfigOption<RoutingProvider>;

@@ -14,2 +15,3 @@ settleIgnoreUrls: ConfigOption<Array<string | RegExp>>;

autoInstrumentNetworkRequests?: boolean;
autoInstrumentRouteChanges?: boolean;
routingProvider?: RoutingProvider;

@@ -19,3 +21,3 @@ settleIgnoreUrls?: Array<string | RegExp>;

}
export declare function createSchema(hostname: string): BrowserSchema;
export declare function createSchema(hostname: string, defaultRoutingProvider: RoutingProvider): BrowserSchema;
//# sourceMappingURL=config.d.ts.map

@@ -1,4 +0,4 @@

export { default } from './browser';
export { DefaultRoutingProvider, type RoutingProvider, type RouteResolver } from './routing-provider';
export { type Configuration } from '@bugsnag/core-performance';
export { DefaultRoutingProvider, default, onSettle } from './browser';
export { type BrowserConfiguration } from './config';
export { type RouteResolver, type RoutingProvider } from './routing-provider';
//# sourceMappingURL=index.d.ts.map

@@ -0,10 +1,9 @@

import { type Span, type Time } from '@bugsnag/core-performance';
export type StartRouteChangeCallback = (newRoute: string, routeChangeTime?: Time) => Span;
export interface RoutingProvider {
resolveRoute: RouteResolver;
resolveRoute: (url: URL) => string;
listenForRouteChanges: (startRouteChangeSpan: StartRouteChangeCallback) => void;
}
export type RouteResolver = (url: URL) => string;
export declare class DefaultRoutingProvider implements RoutingProvider {
resolveRoute: RouteResolver;
constructor(resolveRoute?: RouteResolver);
}
export declare const isRoutingProvider: (value: unknown) => value is RoutingProvider;
//# sourceMappingURL=routing-provider.d.ts.map

@@ -11,6 +11,7 @@ import { type Clock, type SpanInternal } from '@bugsnag/core-performance';

export declare class WebVitals {
private performance;
private clock;
private readonly performance;
private readonly clock;
private readonly observers;
private largestContentfulPaint;
private observer;
private cumulativeLayoutShift;
constructor(performance: PerformanceWithNavigationTiming, clock: Clock, PerformanceObserverClass?: typeof PerformanceObserver);

@@ -21,5 +22,6 @@ attachTo(span: SpanInternal): void;

private firstInputDelay;
private cumulativeLayoutShift;
private observeLargestContentfulPaint;
private observeLayoutShift;
}
export {};
//# sourceMappingURL=web-vitals.d.ts.map

@@ -5,11 +5,11 @@ class WebVitals {

this.clock = clock;
if (PerformanceObserverClass &&
Array.isArray(PerformanceObserverClass.supportedEntryTypes) &&
PerformanceObserverClass.supportedEntryTypes.includes('largest-contentful-paint')) {
this.observer = new PerformanceObserverClass((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1]; // Use the latest LCP candidate
this.largestContentfulPaint = lastEntry.startTime;
});
this.observer.observe({ type: 'largest-contentful-paint', buffered: true });
this.observers = [];
if (PerformanceObserverClass && Array.isArray(PerformanceObserverClass.supportedEntryTypes)) {
const supportedEntryTypes = PerformanceObserverClass.supportedEntryTypes;
if (supportedEntryTypes.includes('largest-contentful-paint')) {
this.observeLargestContentfulPaint(PerformanceObserverClass);
}
if (supportedEntryTypes.includes('layout-shift')) {
this.observeLayoutShift(PerformanceObserverClass);
}
}

@@ -31,5 +31,4 @@ }

}
const cumulativeLayoutShift = this.cumulativeLayoutShift();
if (cumulativeLayoutShift) {
span.setAttribute('bugsnag.metrics.cls', cumulativeLayoutShift);
if (this.cumulativeLayoutShift) {
span.setAttribute('bugsnag.metrics.cls', this.cumulativeLayoutShift);
}

@@ -39,4 +38,6 @@ if (this.largestContentfulPaint) {

}
if (this.observer) {
this.observer.disconnect();
// as there is only 1 page load span, we don't need to keep observing
// performance events, so can disconnect from any observers we've registered
for (const observer of this.observers) {
observer.disconnect();
}

@@ -75,32 +76,48 @@ }

}
cumulativeLayoutShift() {
observeLargestContentfulPaint(PerformanceObserverClass) {
const observer = new PerformanceObserverClass((list) => {
const entries = list.getEntries();
if (entries.length > 0) {
// Use the latest LCP candidate
this.largestContentfulPaint = entries[entries.length - 1].startTime;
}
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
this.observers.push(observer);
}
observeLayoutShift(PerformanceObserverClass) {
let session;
for (const entry of this.performance.getEntriesByType('layout-shift')) {
// ignore entries with recent input as it's likely the layout shifted due
// to user input and this metric only cares about unexpected layout
// shifts
if (entry.hadRecentInput) {
continue;
const observer = new PerformanceObserverClass((list) => {
for (const entry of list.getEntries()) {
// ignore entries with recent input as it's likely the layout shifted due
// to user input and this metric only cares about unexpected layout
// shifts
if (entry.hadRecentInput) {
continue;
}
// include this entry in the current session if we have a current session
// and this entry fits into the session window (it occurred less than 1
// second after the previous entry and the session duration is less than
// 5 seconds), otherwise start a new session
if (session &&
entry.startTime - session.previousStartTime < 1000 &&
entry.startTime - session.firstStartTime < 5000) {
session.value += entry.value;
session.previousStartTime = entry.startTime;
}
else {
session = {
value: entry.value,
firstStartTime: entry.startTime,
previousStartTime: entry.startTime
};
}
}
// include this entry in the current session if we have a current session
// and this entry fits into the session window (it occurred less than 1
// second after the previous entry and the session duration is less than
// 5 seconds), otherwise start a new session
if (session &&
entry.startTime - session.previousStartTime < 1000 &&
entry.startTime - session.firstStartTime < 5000) {
session.value += entry.value;
session.previousStartTime = entry.startTime;
(this.cumulativeLayoutShift === undefined || session.value > this.cumulativeLayoutShift)) {
this.cumulativeLayoutShift = session.value;
}
else {
session = {
value: entry.value,
firstStartTime: entry.startTime,
previousStartTime: entry.startTime
};
}
}
if (session) {
return session.value;
}
});
observer.observe({ type: 'layout-shift', buffered: true });
this.observers.push(observer);
}

@@ -107,0 +124,0 @@ }

{
"name": "@bugsnag/browser-performance",
"version": "0.0.2-alpha.2",
"version": "0.0.2-alpha.3",
"description": "BugSnag performance monitoring for browsers",

@@ -22,3 +22,3 @@ "homepage": "https://www.bugsnag.com/",

"dependencies": {
"@bugsnag/core-performance": "^0.0.2-alpha.2"
"@bugsnag/core-performance": "^0.0.2-alpha.3"
},

@@ -31,3 +31,3 @@ "type": "module",

],
"gitHead": "c45e1fd9589027021cb56e8e8b41ed9c1999d25f"
"gitHead": "27db39a417a02d300bbc2ff8226f22d37a2b3d70"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc