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

honeybadger-js

Package Overview
Dependencies
Maintainers
2
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

honeybadger-js - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0-beta.0

6

CHANGELOG.md

@@ -8,2 +8,8 @@ # Change Log

## [2.1.0-beta.0] - 2019-11-13
### Added
- Add Breadcrumbs (#210). See [the
docs](https://docs.honeybadger.io/lib/javascript/guides/breadcrumbs.html)
for more info.
## [2.0.0] - 2019-07-24

@@ -10,0 +16,0 @@ ### Added

633

dist/honeybadger.cjs.js
'use strict';
function sanitize(obj, maxDepth) {
let seenObjects = [];
function seen(obj) {
if (!obj || typeof(obj) !== 'object') { return false; }
for (let i = 0; i < seenObjects.length; i++) {
const value = seenObjects[i];
if (value === obj) {
return true;
}
}
seenObjects.push(obj);
return false;
}
function canSerialize(obj) {
// Functions are TMI and Symbols can't convert to strings.
if (/function|symbol/.test(typeof(obj))) { return false; }
// No prototype, likely created with `Object.create(null)`.
if (typeof obj === 'object' && typeof obj.hasOwnProperty === 'undefined') { return false; }
return true;
}
function serialize(obj, depth) {
if (!depth) { depth = 0; }
if (depth >= maxDepth) {
return '[DEPTH]';
}
// Inspect invalid types
if (!canSerialize(obj)) { return Object.prototype.toString.call(obj); }
// Halt circular references
if (seen(obj)) {
return '[RECURSION]';
}
// Serialize inside arrays
if (Array.isArray(obj)) {
return obj.map(o => serialize(o, depth+1));
}
// Serialize inside objects
if (typeof(obj) === 'object') {
let ret = {};
for (const k in obj) {
const v = obj[k];
if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
ret[k] = serialize(v, depth+1);
}
}
return ret;
}
// Return everything else untouched
return obj;
}
return serialize(obj);
}
/**
* Converts an HTMLElement into a human-readable string.
* @param {!HTMLElement} element
* @return {string}
*/
function stringNameOfElement(element) {
if (!element || !element.tagName) { return ''; }
let name = element.tagName.toLowerCase();
// Ignore the root <html> element in selectors and events.
if (name === 'html') { return ''; }
if (element.id) {
name += `#${element.id}`;
}
const stringClassNames = element.getAttribute('class');
if (stringClassNames) {
stringClassNames.split(/\s+/).forEach(className => {
name += `.${className}`;
});
}
['alt', 'name', 'title', 'type'].forEach(attrName => {
let attr = element.getAttribute(attrName);
if (attr) {
name += `[${attrName}="${attr}"]`;
}
});
const siblings = getSiblings(element);
if (siblings.length > 1) {
name += `:nth-child(${Array.prototype.indexOf.call(siblings, element) + 1})`;
}
return name;
}
function stringSelectorOfElement(element) {
const name = stringNameOfElement(element);
if (element.parentNode && element.parentNode.tagName) {
const parentName = stringSelectorOfElement(element.parentNode);
if (parentName.length > 0) {
return `${parentName} > ${name}`;
}
}
return name;
}
function stringTextOfElement(element) {
return truncate((element.textContent || element.innerText || element.value || '').trim(), 300);
}
function nativeFetch() {
if (!window.fetch) { return false; }
if (isNative(window.fetch)) { return true; }
// If fetch isn't native, it may be wrapped by someone else. Try to get
// a pristine function from an iframe.
try {
const sandbox = document.createElement('iframe');
sandbox.style.display = 'none';
document.head.appendChild(sandbox);
const result = sandbox.contentWindow.fetch && isNative(sandbox.contentWindow.fetch);
document.head.removeChild(sandbox);
return result;
} catch(err) {
if (console && console.warn) {
console.warn('failed to detect native fetch via iframe: ' + err);
}
}
return false;
}
function isNative(func) {
return func.toString().indexOf('native') !== -1;
}
function parseURL(url) {
// Regexp: https://tools.ietf.org/html/rfc3986#appendix-B
const match = url.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/) || {};
return {
protocol: match[2],
host: match[4],
pathname: match[5],
};
}
function localURLPathname(url) {
const parsed = parseURL(url);
const parsedDocURL = parseURL(document.URL);
// URL must be relative
if (!parsed.host || parsed.protocol) { return parsed.pathname; }
// Same domain
if (parsed.protocol === parsedDocURL.protocol && parsed.host === parsedDocURL.host) {
return parsed.pathname;
}
// x-domain
return `${parsed.protocol}://${parsed.host}${parsed.pathname}`;
}
// Helpers
function getSiblings(element) {
try {
const nodes = element.parentNode.childNodes;
const siblings = [];
Array.prototype.forEach.call(nodes, node => {
if (node.tagName && node.tagName === element.tagName) {
siblings.push(node);
}
});
return siblings;
} catch(e) {
return [];
}
}
function truncate(string, length) {
if (string.length > length) {
string = string.substr(0, length) + '...';
}
return string;
}
function builder() {
var VERSION = '2.0.0',
var VERSION = '2.1.0-beta.0',
NOTIFIER = {
name: 'honeybadger.js',
name: 'honeybadger-js',
url: 'https://github.com/honeybadger-io/honeybadger-js',

@@ -81,3 +279,3 @@ version: VERSION,

// access the stack property first.
return err.stacktrace || err.stack || undefined
return err.stacktrace || err.stack || undefined;
}

@@ -152,3 +350,4 @@

beforeNotifyHandlers: [],
errorsSent: 0
breadcrumbs: [],
errorsSent: 0,
};

@@ -192,2 +391,6 @@ if (typeof opts === 'object') {

function breadcrumbsEnabled() {
return config('breadcrumbsEnabled', false);
}
function baseURL() {

@@ -197,29 +400,2 @@ return 'http' + ((config('ssl', true) && 's') || '') + '://' + config('host', 'api.honeybadger.io');

function canSerialize(obj) {
// Functions are TMI and Symbols can't convert to strings.
if (/function|symbol/.test(typeof(obj))) { return false; }
// No prototype, likely created with `Object.create(null)`.
if (typeof obj === 'object' && typeof obj.hasOwnProperty === 'undefined') { return false; }
return true;
}
function serialize(obj, depth) {
var k, v, ret;
ret = {};
if (!depth) { depth = 0; }
if (depth >= config('max_depth', 8)) {
return '[MAX DEPTH REACHED]';
}
for (k in obj) {
v = obj[k];
if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
if (!canSerialize(v)) { v = Object.prototype.toString.call(v); }
ret[k] = (typeof v === 'object' ? serialize(v, depth+1) : v);
}
}
return ret;
}
function request(apiKey, payload) {

@@ -234,3 +410,3 @@ try {

x.send(JSON.stringify(serialize(payload)));
x.send(JSON.stringify(sanitize(payload, config('max_depth', 8))));
} catch(err) {

@@ -307,2 +483,13 @@ log('Unable to send error report: error while initializing request', err, payload);

self.addBreadcrumb('Honeybadger Notice', {
category: 'notice',
metadata: {
message: err.message,
name: err.name,
stack: err.stack
}
});
err.breadcrumbs = self.breadcrumbs.slice();
let stack_before_handlers = err.stack;

@@ -326,2 +513,6 @@ if (checkHandlers(self.beforeNotifyHandlers, err)) { return false; }

'notifier': NOTIFIER,
'breadcrumbs': {
'enabled': breadcrumbsEnabled(),
'trail': err.breadcrumbs,
},
'error': {

@@ -381,3 +572,4 @@ 'class': err.name,

// removeEventListener.
function wrap(fn, force) {
function wrap(fn, opts) {
if (!opts) { opts = {}; }
try {

@@ -391,8 +583,20 @@ if (typeof fn !== 'function') { return fn; }

// object and there is a window.onerror handler available instead.
if ((preferCatch && (onerror || force)) || (force && !onerror)) {
if ((preferCatch && (onerror || opts.force)) || (opts.force && !onerror)) {
try {
return fn.apply(this, arguments);
} catch (e) {
notify(e);
throw(e);
} catch (err) {
let generated = { stack: stackTrace(err) };
self.addBreadcrumb(
opts.component ? `${opts.component}: ${err.name}` : err.name,
{
category: 'error',
metadata: {
message: err.message,
name: err.name,
stack: generated.stack
}
}
);
notify(err, generated);
throw(err);
}

@@ -441,3 +645,3 @@ } else {

self.wrap = function(func) {
return wrap(func, true);
return wrap(func, { force: true });
};

@@ -477,2 +681,3 @@

self.beforeNotifyHandlers = [];
self.breadcrumbs = [];
for (var k in self) {

@@ -495,2 +700,26 @@ if (indexOf.call(defaultProps, k) == -1) {

self.addBreadcrumb = function(message, opts) {
if (!breadcrumbsEnabled()) return;
opts = opts || {};
const metadata = opts.metadata || undefined;
const category = opts.category || 'custom';
const timestamp = new Date().toISOString();
self.breadcrumbs.push({
category: category,
message: message,
metadata: metadata || {},
timestamp: timestamp,
});
const limit = config('maxBreadcrumbs', 40);
if (self.breadcrumbs.length > limit) {
self.breadcrumbs = self.breadcrumbs.slice(self.breadcrumbs.length - limit);
}
return self;
};
// Install instrumentation.

@@ -500,3 +729,3 @@ // This should happen once for the first factory call.

if (notSingleton) { return; }
if (!object || !name || !replacement) { return; }
if (!object || !name || !replacement || !(name in object)) { return; }
var original = object[name];

@@ -506,19 +735,257 @@ object[name] = replacement(original);

var instrumentTimer = function(original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
return function(func, delay) {
if (typeof func === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
func = wrap(func);
return original(function() {
func.apply(null, args);
}, delay);
} else {
return original(func, delay);
// Breadcrumbs: instrument click events
(function() {
window.addEventListener('click', (event) => {
let message, selector, text;
try {
message = stringNameOfElement(event.target);
selector = stringSelectorOfElement(event.target);
text = stringTextOfElement(event.target);
} catch(e) {
message = 'UI Click';
selector = '[unknown]';
text = '[unknown]';
}
// There's nothing to display
if (message.length === 0) { return; }
self.addBreadcrumb(message, {
category: 'ui.click',
metadata: {
selector,
text,
event,
},
});
}, true);
})();
// Breadcrumbs: instrument XMLHttpRequest
(function() {
// -- On xhr.open: capture initial metadata
instrument(XMLHttpRequest.prototype, 'open', function(original) {
return function() {
const xhr = this;
const url = arguments[1];
const method = typeof arguments[0] === 'string' ? arguments[0].toUpperCase() : arguments[0];
const message = `${method} ${localURLPathname(url)}`;
this.__hb_xhr = {
type: 'xhr',
method,
url,
message,
};
if (typeof original === 'function') {
original.apply(xhr, arguments);
}
};
});
// -- On xhr.send: set up xhr.onreadystatechange to report breadcrumb
instrument(XMLHttpRequest.prototype, 'send', function(original) {
return function() {
const xhr = this;
function onreadystatechangeHandler() {
if (xhr.readyState === 4) {
let message;
if (xhr.__hb_xhr) {
xhr.__hb_xhr.status_code = xhr.status;
message = xhr.__hb_xhr.message;
delete xhr.__hb_xhr.message;
}
self.addBreadcrumb(message || 'XMLHttpRequest', {
category: 'request',
metadata: xhr.__hb_xhr,
});
}
}
if ('onreadystatechange' in xhr && typeof xhr.onreadystatechange === 'function') {
instrument(xhr, 'onreadystatechange', function(original) {
return function() {
onreadystatechangeHandler();
if (typeof original === 'function') {
original.apply(this, arguments);
}
};
});
} else {
xhr.onreadystatechange = onreadystatechangeHandler;
}
if (typeof original === 'function') {
original.apply(xhr, arguments);
}
};
});
})();
// Breadcrumbs: instrument fetch
(function() {
if (!nativeFetch()) {
// Polyfills use XHR.
return;
}
};
instrument(window, 'setTimeout', instrumentTimer);
instrument(window, 'setInterval', instrumentTimer);
instrument(window, 'fetch', function(original) {
return function() {
const input = arguments[0];
let method = 'GET';
let url;
if (typeof input === 'string') {
url = input;
} else if ('Request' in window && input instanceof Request) {
url = input.url;
if (input.method) {
method = input.method;
}
} else {
url = String(input);
}
if (arguments[1] && arguments[1].method) {
method = arguments[1].method;
}
if (typeof method === 'string') {
method = method.toUpperCase();
}
const message = `${method} ${localURLPathname(url)}`;
const metadata = {
type: 'fetch',
method,
url,
};
return original
.apply(this, arguments)
.then(function(response) {
metadata.status_code = response.status;
self.addBreadcrumb(message, {
category: 'request',
metadata,
});
return response;
})
.catch(function(error) {
self.addBreadcrumb('fetch error', {
category: 'error',
metadata,
});
throw error;
});
};
});
})();
// Breadcrumbs: instrument navigation
(function() {
// The last known href of the current page
let lastHref = window.location.href;
function recordUrlChange(from, to) {
lastHref = to;
self.addBreadcrumb('Page changed', {
category: 'navigation',
metadata: {
from,
to,
},
});
}
// https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate
instrument(window, 'onpopstate', function(original) {
return function() {
recordUrlChange(lastHref, window.location.href);
if (original) {
return original.apply(this, arguments);
}
};
});
// https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
// https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
function historyWrapper(original) {
return function() {
const url = arguments.length > 2 ? arguments[2] : undefined;
if (url) {
recordUrlChange(lastHref, String(url));
}
return original.apply(this, arguments);
};
}
instrument(window.history, 'pushState', historyWrapper);
instrument(window.history, 'replaceState', historyWrapper);
})();
// Breadcrumbs: instrument console
(function() {
function inspectArray(obj) {
if (!Array.isArray(obj)) { return ''; }
return obj.map(value => {
try {
return String(value);
} catch (e) {
return '[unknown]';
}
}).join(' ');
}
['debug', 'info', 'warn', 'error', 'log'].forEach(level => {
instrument(window.console, level, function(original) {
return function() {
const args = Array.prototype.slice.call(arguments);
const message = inspectArray(args);
const opts = {
category: 'log',
metadata: {
level: level,
arguments: sanitize(args, 3),
},
};
self.addBreadcrumb(message, opts);
if (typeof original === 'function') {
Function.prototype.apply.call(original, window.console, arguments);
}
};
});
});
})();
// Wrap timers
(function() {
function instrumentTimer(wrapOpts) {
return function(original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
return function(func, delay) {
if (typeof func === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
func = wrap(func, wrapOpts);
return original(function() {
func.apply(null, args);
}, delay);
} else {
return original(func, delay);
}
};
};
} instrument(window, 'setTimeout', instrumentTimer({ component: 'setTimeout' }));
instrument(window, 'setInterval', instrumentTimer({ component: 'setInterval' }));
})();
// Wrap event listeners
// Event targets borrowed from bugsnag-js:

@@ -530,2 +997,4 @@ // See https://github.com/bugsnag/bugsnag-js/blob/d55af916a4d3c7757f979d887f9533fe1a04cc93/src/bugsnag.js#L542

instrument(prototype, 'addEventListener', function(original) {
const wrapOpts = {component: `${prop}.prototype.addEventListener`};
// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

@@ -535,3 +1004,3 @@ return function(type, listener, useCapture, wantsUntrusted) {

if (listener && listener.handleEvent != null) {
listener.handleEvent = wrap(listener.handleEvent);
listener.handleEvent = wrap(listener.handleEvent, wrapOpts);
}

@@ -542,3 +1011,3 @@ } catch(e) {

}
return original.call(this, type, wrap(listener), useCapture, wantsUntrusted);
return original.call(this, type, wrap(listener, wrapOpts), useCapture, wantsUntrusted);
};

@@ -555,2 +1024,3 @@ });

// Wrap window.onerror
instrument(window, 'onerror', function(original) {

@@ -571,17 +1041,31 @@ function onerror(msg, url, line, col, err) {

// simulate v8 stack
var stack = [msg, '\n at ? (', url || 'unknown', ':', line || 0, ':', col || 0, ')'].join('');
// Simulate v8 stack
const simulatedStack = [msg, '\n at ? (', url || 'unknown', ':', line || 0, ':', col || 0, ')'].join('');
let generated;
if (err) {
var generated = { stack: stackTrace(err) };
if (!generated.stack) { generated = {stack: stack}; }
notify(err, generated);
return;
generated = { stack: stackTrace(err) };
if (!generated.stack) { generated = {stack: simulatedStack}; }
} else {
// Important: leave `generated` undefined
err = {
name: 'window.onerror',
message: msg,
stack: simulatedStack
};
}
notify({
name: 'window.onerror',
message: msg,
stack: stack
});
self.addBreadcrumb(
(err.name === 'window.onerror' || !err.name) ? 'window.onerror' : `window.onerror: ${err.name}`,
{
category: 'error',
metadata: {
message: err.message,
name: err.name,
stack: generated ? generated.stack : err.stack
}
}
);
notify(err, generated);
}

@@ -598,2 +1082,3 @@ // See https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror

// Wrap window.onunhandledrejection
instrument(window, 'onunhandledrejection', function(original) {

@@ -617,9 +1102,15 @@ // See https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event

let stack = stackTrace(reason) || stackFallback;
notify({
let err = {
name: reason.name,
message: `UnhandledPromiseRejectionWarning: ${reason}`,
stack
});
};
self.addBreadcrumb(
`window.onunhandledrejection: ${err.name}`,
{
category: 'error',
metadata: err
}
);
notify(err);
return;

@@ -640,3 +1131,3 @@ }

}
}
};
});

@@ -643,0 +1134,0 @@

@@ -0,5 +1,203 @@

function sanitize(obj, maxDepth) {
let seenObjects = [];
function seen(obj) {
if (!obj || typeof(obj) !== 'object') { return false; }
for (let i = 0; i < seenObjects.length; i++) {
const value = seenObjects[i];
if (value === obj) {
return true;
}
}
seenObjects.push(obj);
return false;
}
function canSerialize(obj) {
// Functions are TMI and Symbols can't convert to strings.
if (/function|symbol/.test(typeof(obj))) { return false; }
// No prototype, likely created with `Object.create(null)`.
if (typeof obj === 'object' && typeof obj.hasOwnProperty === 'undefined') { return false; }
return true;
}
function serialize(obj, depth) {
if (!depth) { depth = 0; }
if (depth >= maxDepth) {
return '[DEPTH]';
}
// Inspect invalid types
if (!canSerialize(obj)) { return Object.prototype.toString.call(obj); }
// Halt circular references
if (seen(obj)) {
return '[RECURSION]';
}
// Serialize inside arrays
if (Array.isArray(obj)) {
return obj.map(o => serialize(o, depth+1));
}
// Serialize inside objects
if (typeof(obj) === 'object') {
let ret = {};
for (const k in obj) {
const v = obj[k];
if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
ret[k] = serialize(v, depth+1);
}
}
return ret;
}
// Return everything else untouched
return obj;
}
return serialize(obj);
}
/**
* Converts an HTMLElement into a human-readable string.
* @param {!HTMLElement} element
* @return {string}
*/
function stringNameOfElement(element) {
if (!element || !element.tagName) { return ''; }
let name = element.tagName.toLowerCase();
// Ignore the root <html> element in selectors and events.
if (name === 'html') { return ''; }
if (element.id) {
name += `#${element.id}`;
}
const stringClassNames = element.getAttribute('class');
if (stringClassNames) {
stringClassNames.split(/\s+/).forEach(className => {
name += `.${className}`;
});
}
['alt', 'name', 'title', 'type'].forEach(attrName => {
let attr = element.getAttribute(attrName);
if (attr) {
name += `[${attrName}="${attr}"]`;
}
});
const siblings = getSiblings(element);
if (siblings.length > 1) {
name += `:nth-child(${Array.prototype.indexOf.call(siblings, element) + 1})`;
}
return name;
}
function stringSelectorOfElement(element) {
const name = stringNameOfElement(element);
if (element.parentNode && element.parentNode.tagName) {
const parentName = stringSelectorOfElement(element.parentNode);
if (parentName.length > 0) {
return `${parentName} > ${name}`;
}
}
return name;
}
function stringTextOfElement(element) {
return truncate((element.textContent || element.innerText || element.value || '').trim(), 300);
}
function nativeFetch() {
if (!window.fetch) { return false; }
if (isNative(window.fetch)) { return true; }
// If fetch isn't native, it may be wrapped by someone else. Try to get
// a pristine function from an iframe.
try {
const sandbox = document.createElement('iframe');
sandbox.style.display = 'none';
document.head.appendChild(sandbox);
const result = sandbox.contentWindow.fetch && isNative(sandbox.contentWindow.fetch);
document.head.removeChild(sandbox);
return result;
} catch(err) {
if (console && console.warn) {
console.warn('failed to detect native fetch via iframe: ' + err);
}
}
return false;
}
function isNative(func) {
return func.toString().indexOf('native') !== -1;
}
function parseURL(url) {
// Regexp: https://tools.ietf.org/html/rfc3986#appendix-B
const match = url.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/) || {};
return {
protocol: match[2],
host: match[4],
pathname: match[5],
};
}
function localURLPathname(url) {
const parsed = parseURL(url);
const parsedDocURL = parseURL(document.URL);
// URL must be relative
if (!parsed.host || parsed.protocol) { return parsed.pathname; }
// Same domain
if (parsed.protocol === parsedDocURL.protocol && parsed.host === parsedDocURL.host) {
return parsed.pathname;
}
// x-domain
return `${parsed.protocol}://${parsed.host}${parsed.pathname}`;
}
// Helpers
function getSiblings(element) {
try {
const nodes = element.parentNode.childNodes;
const siblings = [];
Array.prototype.forEach.call(nodes, node => {
if (node.tagName && node.tagName === element.tagName) {
siblings.push(node);
}
});
return siblings;
} catch(e) {
return [];
}
}
function truncate(string, length) {
if (string.length > length) {
string = string.substr(0, length) + '...';
}
return string;
}
function builder() {
var VERSION = '2.0.0',
var VERSION = '2.1.0-beta.0',
NOTIFIER = {
name: 'honeybadger.js',
name: 'honeybadger-js',
url: 'https://github.com/honeybadger-io/honeybadger-js',

@@ -79,3 +277,3 @@ version: VERSION,

// access the stack property first.
return err.stacktrace || err.stack || undefined
return err.stacktrace || err.stack || undefined;
}

@@ -150,3 +348,4 @@

beforeNotifyHandlers: [],
errorsSent: 0
breadcrumbs: [],
errorsSent: 0,
};

@@ -190,2 +389,6 @@ if (typeof opts === 'object') {

function breadcrumbsEnabled() {
return config('breadcrumbsEnabled', false);
}
function baseURL() {

@@ -195,29 +398,2 @@ return 'http' + ((config('ssl', true) && 's') || '') + '://' + config('host', 'api.honeybadger.io');

function canSerialize(obj) {
// Functions are TMI and Symbols can't convert to strings.
if (/function|symbol/.test(typeof(obj))) { return false; }
// No prototype, likely created with `Object.create(null)`.
if (typeof obj === 'object' && typeof obj.hasOwnProperty === 'undefined') { return false; }
return true;
}
function serialize(obj, depth) {
var k, v, ret;
ret = {};
if (!depth) { depth = 0; }
if (depth >= config('max_depth', 8)) {
return '[MAX DEPTH REACHED]';
}
for (k in obj) {
v = obj[k];
if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
if (!canSerialize(v)) { v = Object.prototype.toString.call(v); }
ret[k] = (typeof v === 'object' ? serialize(v, depth+1) : v);
}
}
return ret;
}
function request(apiKey, payload) {

@@ -232,3 +408,3 @@ try {

x.send(JSON.stringify(serialize(payload)));
x.send(JSON.stringify(sanitize(payload, config('max_depth', 8))));
} catch(err) {

@@ -305,2 +481,13 @@ log('Unable to send error report: error while initializing request', err, payload);

self.addBreadcrumb('Honeybadger Notice', {
category: 'notice',
metadata: {
message: err.message,
name: err.name,
stack: err.stack
}
});
err.breadcrumbs = self.breadcrumbs.slice();
let stack_before_handlers = err.stack;

@@ -324,2 +511,6 @@ if (checkHandlers(self.beforeNotifyHandlers, err)) { return false; }

'notifier': NOTIFIER,
'breadcrumbs': {
'enabled': breadcrumbsEnabled(),
'trail': err.breadcrumbs,
},
'error': {

@@ -379,3 +570,4 @@ 'class': err.name,

// removeEventListener.
function wrap(fn, force) {
function wrap(fn, opts) {
if (!opts) { opts = {}; }
try {

@@ -389,8 +581,20 @@ if (typeof fn !== 'function') { return fn; }

// object and there is a window.onerror handler available instead.
if ((preferCatch && (onerror || force)) || (force && !onerror)) {
if ((preferCatch && (onerror || opts.force)) || (opts.force && !onerror)) {
try {
return fn.apply(this, arguments);
} catch (e) {
notify(e);
throw(e);
} catch (err) {
let generated = { stack: stackTrace(err) };
self.addBreadcrumb(
opts.component ? `${opts.component}: ${err.name}` : err.name,
{
category: 'error',
metadata: {
message: err.message,
name: err.name,
stack: generated.stack
}
}
);
notify(err, generated);
throw(err);
}

@@ -439,3 +643,3 @@ } else {

self.wrap = function(func) {
return wrap(func, true);
return wrap(func, { force: true });
};

@@ -475,2 +679,3 @@

self.beforeNotifyHandlers = [];
self.breadcrumbs = [];
for (var k in self) {

@@ -493,2 +698,26 @@ if (indexOf.call(defaultProps, k) == -1) {

self.addBreadcrumb = function(message, opts) {
if (!breadcrumbsEnabled()) return;
opts = opts || {};
const metadata = opts.metadata || undefined;
const category = opts.category || 'custom';
const timestamp = new Date().toISOString();
self.breadcrumbs.push({
category: category,
message: message,
metadata: metadata || {},
timestamp: timestamp,
});
const limit = config('maxBreadcrumbs', 40);
if (self.breadcrumbs.length > limit) {
self.breadcrumbs = self.breadcrumbs.slice(self.breadcrumbs.length - limit);
}
return self;
};
// Install instrumentation.

@@ -498,3 +727,3 @@ // This should happen once for the first factory call.

if (notSingleton) { return; }
if (!object || !name || !replacement) { return; }
if (!object || !name || !replacement || !(name in object)) { return; }
var original = object[name];

@@ -504,19 +733,257 @@ object[name] = replacement(original);

var instrumentTimer = function(original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
return function(func, delay) {
if (typeof func === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
func = wrap(func);
return original(function() {
func.apply(null, args);
}, delay);
} else {
return original(func, delay);
// Breadcrumbs: instrument click events
(function() {
window.addEventListener('click', (event) => {
let message, selector, text;
try {
message = stringNameOfElement(event.target);
selector = stringSelectorOfElement(event.target);
text = stringTextOfElement(event.target);
} catch(e) {
message = 'UI Click';
selector = '[unknown]';
text = '[unknown]';
}
// There's nothing to display
if (message.length === 0) { return; }
self.addBreadcrumb(message, {
category: 'ui.click',
metadata: {
selector,
text,
event,
},
});
}, true);
})();
// Breadcrumbs: instrument XMLHttpRequest
(function() {
// -- On xhr.open: capture initial metadata
instrument(XMLHttpRequest.prototype, 'open', function(original) {
return function() {
const xhr = this;
const url = arguments[1];
const method = typeof arguments[0] === 'string' ? arguments[0].toUpperCase() : arguments[0];
const message = `${method} ${localURLPathname(url)}`;
this.__hb_xhr = {
type: 'xhr',
method,
url,
message,
};
if (typeof original === 'function') {
original.apply(xhr, arguments);
}
};
});
// -- On xhr.send: set up xhr.onreadystatechange to report breadcrumb
instrument(XMLHttpRequest.prototype, 'send', function(original) {
return function() {
const xhr = this;
function onreadystatechangeHandler() {
if (xhr.readyState === 4) {
let message;
if (xhr.__hb_xhr) {
xhr.__hb_xhr.status_code = xhr.status;
message = xhr.__hb_xhr.message;
delete xhr.__hb_xhr.message;
}
self.addBreadcrumb(message || 'XMLHttpRequest', {
category: 'request',
metadata: xhr.__hb_xhr,
});
}
}
if ('onreadystatechange' in xhr && typeof xhr.onreadystatechange === 'function') {
instrument(xhr, 'onreadystatechange', function(original) {
return function() {
onreadystatechangeHandler();
if (typeof original === 'function') {
original.apply(this, arguments);
}
};
});
} else {
xhr.onreadystatechange = onreadystatechangeHandler;
}
if (typeof original === 'function') {
original.apply(xhr, arguments);
}
};
});
})();
// Breadcrumbs: instrument fetch
(function() {
if (!nativeFetch()) {
// Polyfills use XHR.
return;
}
};
instrument(window, 'setTimeout', instrumentTimer);
instrument(window, 'setInterval', instrumentTimer);
instrument(window, 'fetch', function(original) {
return function() {
const input = arguments[0];
let method = 'GET';
let url;
if (typeof input === 'string') {
url = input;
} else if ('Request' in window && input instanceof Request) {
url = input.url;
if (input.method) {
method = input.method;
}
} else {
url = String(input);
}
if (arguments[1] && arguments[1].method) {
method = arguments[1].method;
}
if (typeof method === 'string') {
method = method.toUpperCase();
}
const message = `${method} ${localURLPathname(url)}`;
const metadata = {
type: 'fetch',
method,
url,
};
return original
.apply(this, arguments)
.then(function(response) {
metadata.status_code = response.status;
self.addBreadcrumb(message, {
category: 'request',
metadata,
});
return response;
})
.catch(function(error) {
self.addBreadcrumb('fetch error', {
category: 'error',
metadata,
});
throw error;
});
};
});
})();
// Breadcrumbs: instrument navigation
(function() {
// The last known href of the current page
let lastHref = window.location.href;
function recordUrlChange(from, to) {
lastHref = to;
self.addBreadcrumb('Page changed', {
category: 'navigation',
metadata: {
from,
to,
},
});
}
// https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate
instrument(window, 'onpopstate', function(original) {
return function() {
recordUrlChange(lastHref, window.location.href);
if (original) {
return original.apply(this, arguments);
}
};
});
// https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
// https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
function historyWrapper(original) {
return function() {
const url = arguments.length > 2 ? arguments[2] : undefined;
if (url) {
recordUrlChange(lastHref, String(url));
}
return original.apply(this, arguments);
};
}
instrument(window.history, 'pushState', historyWrapper);
instrument(window.history, 'replaceState', historyWrapper);
})();
// Breadcrumbs: instrument console
(function() {
function inspectArray(obj) {
if (!Array.isArray(obj)) { return ''; }
return obj.map(value => {
try {
return String(value);
} catch (e) {
return '[unknown]';
}
}).join(' ');
}
['debug', 'info', 'warn', 'error', 'log'].forEach(level => {
instrument(window.console, level, function(original) {
return function() {
const args = Array.prototype.slice.call(arguments);
const message = inspectArray(args);
const opts = {
category: 'log',
metadata: {
level: level,
arguments: sanitize(args, 3),
},
};
self.addBreadcrumb(message, opts);
if (typeof original === 'function') {
Function.prototype.apply.call(original, window.console, arguments);
}
};
});
});
})();
// Wrap timers
(function() {
function instrumentTimer(wrapOpts) {
return function(original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
return function(func, delay) {
if (typeof func === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
func = wrap(func, wrapOpts);
return original(function() {
func.apply(null, args);
}, delay);
} else {
return original(func, delay);
}
};
};
} instrument(window, 'setTimeout', instrumentTimer({ component: 'setTimeout' }));
instrument(window, 'setInterval', instrumentTimer({ component: 'setInterval' }));
})();
// Wrap event listeners
// Event targets borrowed from bugsnag-js:

@@ -528,2 +995,4 @@ // See https://github.com/bugsnag/bugsnag-js/blob/d55af916a4d3c7757f979d887f9533fe1a04cc93/src/bugsnag.js#L542

instrument(prototype, 'addEventListener', function(original) {
const wrapOpts = {component: `${prop}.prototype.addEventListener`};
// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

@@ -533,3 +1002,3 @@ return function(type, listener, useCapture, wantsUntrusted) {

if (listener && listener.handleEvent != null) {
listener.handleEvent = wrap(listener.handleEvent);
listener.handleEvent = wrap(listener.handleEvent, wrapOpts);
}

@@ -540,3 +1009,3 @@ } catch(e) {

}
return original.call(this, type, wrap(listener), useCapture, wantsUntrusted);
return original.call(this, type, wrap(listener, wrapOpts), useCapture, wantsUntrusted);
};

@@ -553,2 +1022,3 @@ });

// Wrap window.onerror
instrument(window, 'onerror', function(original) {

@@ -569,17 +1039,31 @@ function onerror(msg, url, line, col, err) {

// simulate v8 stack
var stack = [msg, '\n at ? (', url || 'unknown', ':', line || 0, ':', col || 0, ')'].join('');
// Simulate v8 stack
const simulatedStack = [msg, '\n at ? (', url || 'unknown', ':', line || 0, ':', col || 0, ')'].join('');
let generated;
if (err) {
var generated = { stack: stackTrace(err) };
if (!generated.stack) { generated = {stack: stack}; }
notify(err, generated);
return;
generated = { stack: stackTrace(err) };
if (!generated.stack) { generated = {stack: simulatedStack}; }
} else {
// Important: leave `generated` undefined
err = {
name: 'window.onerror',
message: msg,
stack: simulatedStack
};
}
notify({
name: 'window.onerror',
message: msg,
stack: stack
});
self.addBreadcrumb(
(err.name === 'window.onerror' || !err.name) ? 'window.onerror' : `window.onerror: ${err.name}`,
{
category: 'error',
metadata: {
message: err.message,
name: err.name,
stack: generated ? generated.stack : err.stack
}
}
);
notify(err, generated);
}

@@ -596,2 +1080,3 @@ // See https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror

// Wrap window.onunhandledrejection
instrument(window, 'onunhandledrejection', function(original) {

@@ -615,9 +1100,15 @@ // See https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event

let stack = stackTrace(reason) || stackFallback;
notify({
let err = {
name: reason.name,
message: `UnhandledPromiseRejectionWarning: ${reason}`,
stack
});
};
self.addBreadcrumb(
`window.onunhandledrejection: ${err.name}`,
{
category: 'error',
metadata: err
}
);
notify(err);
return;

@@ -638,3 +1129,3 @@ }

}
}
};
});

@@ -641,0 +1132,0 @@

@@ -21,6 +21,227 @@ (function (global, factory) {

function sanitize(obj, maxDepth) {
var seenObjects = [];
function seen(obj) {
if (!obj || _typeof(obj) !== 'object') {
return false;
}
for (var i = 0; i < seenObjects.length; i++) {
var value = seenObjects[i];
if (value === obj) {
return true;
}
}
seenObjects.push(obj);
return false;
}
function canSerialize(obj) {
// Functions are TMI and Symbols can't convert to strings.
if (/function|symbol/.test(_typeof(obj))) {
return false;
} // No prototype, likely created with `Object.create(null)`.
if (_typeof(obj) === 'object' && typeof obj.hasOwnProperty === 'undefined') {
return false;
}
return true;
}
function serialize(obj, depth) {
if (!depth) {
depth = 0;
}
if (depth >= maxDepth) {
return '[DEPTH]';
} // Inspect invalid types
if (!canSerialize(obj)) {
return Object.prototype.toString.call(obj);
} // Halt circular references
if (seen(obj)) {
return '[RECURSION]';
} // Serialize inside arrays
if (Array.isArray(obj)) {
return obj.map(function (o) {
return serialize(o, depth + 1);
});
} // Serialize inside objects
if (_typeof(obj) === 'object') {
var ret = {};
for (var k in obj) {
var v = obj[k];
if (Object.prototype.hasOwnProperty.call(obj, k) && k != null && v != null) {
ret[k] = serialize(v, depth + 1);
}
}
return ret;
} // Return everything else untouched
return obj;
}
return serialize(obj);
}
/**
* Converts an HTMLElement into a human-readable string.
* @param {!HTMLElement} element
* @return {string}
*/
function stringNameOfElement(element) {
if (!element || !element.tagName) {
return '';
}
var name = element.tagName.toLowerCase(); // Ignore the root <html> element in selectors and events.
if (name === 'html') {
return '';
}
if (element.id) {
name += "#".concat(element.id);
}
var stringClassNames = element.getAttribute('class');
if (stringClassNames) {
stringClassNames.split(/\s+/).forEach(function (className) {
name += ".".concat(className);
});
}
['alt', 'name', 'title', 'type'].forEach(function (attrName) {
var attr = element.getAttribute(attrName);
if (attr) {
name += "[".concat(attrName, "=\"").concat(attr, "\"]");
}
});
var siblings = getSiblings(element);
if (siblings.length > 1) {
name += ":nth-child(".concat(Array.prototype.indexOf.call(siblings, element) + 1, ")");
}
return name;
}
function stringSelectorOfElement(element) {
var name = stringNameOfElement(element);
if (element.parentNode && element.parentNode.tagName) {
var parentName = stringSelectorOfElement(element.parentNode);
if (parentName.length > 0) {
return "".concat(parentName, " > ").concat(name);
}
}
return name;
}
function stringTextOfElement(element) {
return truncate((element.textContent || element.innerText || element.value || '').trim(), 300);
}
function nativeFetch() {
if (!window.fetch) {
return false;
}
if (isNative(window.fetch)) {
return true;
} // If fetch isn't native, it may be wrapped by someone else. Try to get
// a pristine function from an iframe.
try {
var sandbox = document.createElement('iframe');
sandbox.style.display = 'none';
document.head.appendChild(sandbox);
var result = sandbox.contentWindow.fetch && isNative(sandbox.contentWindow.fetch);
document.head.removeChild(sandbox);
return result;
} catch (err) {
if (console && console.warn) {
console.warn('failed to detect native fetch via iframe: ' + err);
}
}
return false;
}
function isNative(func) {
return func.toString().indexOf('native') !== -1;
}
function parseURL(url) {
// Regexp: https://tools.ietf.org/html/rfc3986#appendix-B
var match = url.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/) || {};
return {
protocol: match[2],
host: match[4],
pathname: match[5]
};
}
function localURLPathname(url) {
var parsed = parseURL(url);
var parsedDocURL = parseURL(document.URL); // URL must be relative
if (!parsed.host || parsed.protocol) {
return parsed.pathname;
} // Same domain
if (parsed.protocol === parsedDocURL.protocol && parsed.host === parsedDocURL.host) {
return parsed.pathname;
} // x-domain
return "".concat(parsed.protocol, "://").concat(parsed.host).concat(parsed.pathname);
} // Helpers
function getSiblings(element) {
try {
var nodes = element.parentNode.childNodes;
var siblings = [];
Array.prototype.forEach.call(nodes, function (node) {
if (node.tagName && node.tagName === element.tagName) {
siblings.push(node);
}
});
return siblings;
} catch (e) {
return [];
}
}
function truncate(string, length) {
if (string.length > length) {
string = string.substr(0, length) + '...';
}
return string;
}
function builder() {
var VERSION = '2.0.0',
var VERSION = '2.1.0-beta.0',
NOTIFIER = {
name: 'honeybadger.js',
name: 'honeybadger-js',
url: 'https://github.com/honeybadger-io/honeybadger-js',

@@ -208,2 +429,3 @@ version: VERSION,

beforeNotifyHandlers: [],
breadcrumbs: [],
errorsSent: 0

@@ -268,2 +490,6 @@ };

function breadcrumbsEnabled() {
return config('breadcrumbsEnabled', false);
}
function baseURL() {

@@ -273,43 +499,2 @@ return 'http' + (config('ssl', true) && 's' || '') + '://' + config('host', 'api.honeybadger.io');

function canSerialize(obj) {
// Functions are TMI and Symbols can't convert to strings.
if (/function|symbol/.test(_typeof(obj))) {
return false;
} // No prototype, likely created with `Object.create(null)`.
if (_typeof(obj) === 'object' && typeof obj.hasOwnProperty === 'undefined') {
return false;
}
return true;
}
function serialize(obj, depth) {
var k, v, ret;
ret = {};
if (!depth) {
depth = 0;
}
if (depth >= config('max_depth', 8)) {
return '[MAX DEPTH REACHED]';
}
for (k in obj) {
v = obj[k];
if (Object.prototype.hasOwnProperty.call(obj, k) && k != null && v != null) {
if (!canSerialize(v)) {
v = Object.prototype.toString.call(v);
}
ret[k] = _typeof(v) === 'object' ? serialize(v, depth + 1) : v;
}
}
return ret;
}
function request(apiKey, payload) {

@@ -322,3 +507,3 @@ try {

x.setRequestHeader('Accept', 'text/json, application/json');
x.send(JSON.stringify(serialize(payload)));
x.send(JSON.stringify(sanitize(payload, config('max_depth', 8))));
} catch (err) {

@@ -404,2 +589,11 @@ log('Unable to send error report: error while initializing request', err, payload);

});
self.addBreadcrumb('Honeybadger Notice', {
category: 'notice',
metadata: {
message: err.message,
name: err.name,
stack: err.stack
}
});
err.breadcrumbs = self.breadcrumbs.slice();
var stack_before_handlers = err.stack;

@@ -430,2 +624,6 @@

'notifier': NOTIFIER,
'breadcrumbs': {
'enabled': breadcrumbsEnabled(),
'trail': err.breadcrumbs
},
'error': {

@@ -487,3 +685,7 @@ 'class': err.name,

function wrap(fn, force) {
function wrap(fn, opts) {
if (!opts) {
opts = {};
}
try {

@@ -503,8 +705,19 @@ if (typeof fn !== 'function') {

if (preferCatch && (onerror || force) || force && !onerror) {
if (preferCatch && (onerror || opts.force) || opts.force && !onerror) {
try {
return fn.apply(this, arguments);
} catch (e) {
notify(e);
throw e;
} catch (err) {
var generated = {
stack: stackTrace(err)
};
self.addBreadcrumb(opts.component ? "".concat(opts.component, ": ").concat(err.name) : err.name, {
category: 'error',
metadata: {
message: err.message,
name: err.name,
stack: generated.stack
}
});
notify(err, generated);
throw err;
}

@@ -565,3 +778,5 @@ } else {

self.wrap = function (func) {
return wrap(func, true);
return wrap(func, {
force: true
});
};

@@ -611,2 +826,3 @@

self.beforeNotifyHandlers = [];
self.breadcrumbs = [];

@@ -629,2 +845,23 @@ for (var k in self) {

return VERSION;
};
self.addBreadcrumb = function (message, opts) {
if (!breadcrumbsEnabled()) return;
opts = opts || {};
var metadata = opts.metadata || undefined;
var category = opts.category || 'custom';
var timestamp = new Date().toISOString();
self.breadcrumbs.push({
category: category,
message: message,
metadata: metadata || {},
timestamp: timestamp
});
var limit = config('maxBreadcrumbs', 40);
if (self.breadcrumbs.length > limit) {
self.breadcrumbs = self.breadcrumbs.slice(self.breadcrumbs.length - limit);
}
return self;
}; // Install instrumentation.

@@ -639,3 +876,3 @@ // This should happen once for the first factory call.

if (!object || !name || !replacement) {
if (!object || !name || !replacement || !(name in object)) {
return;

@@ -646,23 +883,266 @@ }

object[name] = replacement(original);
}
} // Breadcrumbs: instrument click events
var instrumentTimer = function instrumentTimer(original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
return function (func, delay) {
if (typeof func === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
func = wrap(func);
return original(function () {
func.apply(null, args);
}, delay);
} else {
return original(func, delay);
(function () {
window.addEventListener('click', function (event) {
var message, selector, text;
try {
message = stringNameOfElement(event.target);
selector = stringSelectorOfElement(event.target);
text = stringTextOfElement(event.target);
} catch (e) {
message = 'UI Click';
selector = '[unknown]';
text = '[unknown]';
} // There's nothing to display
if (message.length === 0) {
return;
}
};
};
self.addBreadcrumb(message, {
category: 'ui.click',
metadata: {
selector: selector,
text: text,
event: event
}
});
}, true);
})(); // Breadcrumbs: instrument XMLHttpRequest
instrument(window, 'setTimeout', instrumentTimer);
instrument(window, 'setInterval', instrumentTimer); // Event targets borrowed from bugsnag-js:
(function () {
// -- On xhr.open: capture initial metadata
instrument(XMLHttpRequest.prototype, 'open', function (original) {
return function () {
var xhr = this;
var url = arguments[1];
var method = typeof arguments[0] === 'string' ? arguments[0].toUpperCase() : arguments[0];
var message = "".concat(method, " ").concat(localURLPathname(url));
this.__hb_xhr = {
type: 'xhr',
method: method,
url: url,
message: message
};
if (typeof original === 'function') {
original.apply(xhr, arguments);
}
};
}); // -- On xhr.send: set up xhr.onreadystatechange to report breadcrumb
instrument(XMLHttpRequest.prototype, 'send', function (original) {
return function () {
var xhr = this;
function onreadystatechangeHandler() {
if (xhr.readyState === 4) {
var message;
if (xhr.__hb_xhr) {
xhr.__hb_xhr.status_code = xhr.status;
message = xhr.__hb_xhr.message;
delete xhr.__hb_xhr.message;
}
self.addBreadcrumb(message || 'XMLHttpRequest', {
category: 'request',
metadata: xhr.__hb_xhr
});
}
}
if ('onreadystatechange' in xhr && typeof xhr.onreadystatechange === 'function') {
instrument(xhr, 'onreadystatechange', function (original) {
return function () {
onreadystatechangeHandler();
if (typeof original === 'function') {
original.apply(this, arguments);
}
};
});
} else {
xhr.onreadystatechange = onreadystatechangeHandler;
}
if (typeof original === 'function') {
original.apply(xhr, arguments);
}
};
});
})(); // Breadcrumbs: instrument fetch
(function () {
if (!nativeFetch()) {
// Polyfills use XHR.
return;
}
instrument(window, 'fetch', function (original) {
return function () {
var input = arguments[0];
var method = 'GET';
var url;
if (typeof input === 'string') {
url = input;
} else if ('Request' in window && input instanceof Request) {
url = input.url;
if (input.method) {
method = input.method;
}
} else {
url = String(input);
}
if (arguments[1] && arguments[1].method) {
method = arguments[1].method;
}
if (typeof method === 'string') {
method = method.toUpperCase();
}
var message = "".concat(method, " ").concat(localURLPathname(url));
var metadata = {
type: 'fetch',
method: method,
url: url
};
return original.apply(this, arguments).then(function (response) {
metadata.status_code = response.status;
self.addBreadcrumb(message, {
category: 'request',
metadata: metadata
});
return response;
}).catch(function (error) {
self.addBreadcrumb('fetch error', {
category: 'error',
metadata: metadata
});
throw error;
});
};
});
})(); // Breadcrumbs: instrument navigation
(function () {
// The last known href of the current page
var lastHref = window.location.href;
function recordUrlChange(from, to) {
lastHref = to;
self.addBreadcrumb('Page changed', {
category: 'navigation',
metadata: {
from: from,
to: to
}
});
} // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate
instrument(window, 'onpopstate', function (original) {
return function () {
recordUrlChange(lastHref, window.location.href);
if (original) {
return original.apply(this, arguments);
}
};
}); // https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
// https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
function historyWrapper(original) {
return function () {
var url = arguments.length > 2 ? arguments[2] : undefined;
if (url) {
recordUrlChange(lastHref, String(url));
}
return original.apply(this, arguments);
};
}
instrument(window.history, 'pushState', historyWrapper);
instrument(window.history, 'replaceState', historyWrapper);
})(); // Breadcrumbs: instrument console
(function () {
function inspectArray(obj) {
if (!Array.isArray(obj)) {
return '';
}
return obj.map(function (value) {
try {
return String(value);
} catch (e) {
return '[unknown]';
}
}).join(' ');
}
['debug', 'info', 'warn', 'error', 'log'].forEach(function (level) {
instrument(window.console, level, function (original) {
return function () {
var args = Array.prototype.slice.call(arguments);
var message = inspectArray(args);
var opts = {
category: 'log',
metadata: {
level: level,
arguments: sanitize(args, 3)
}
};
self.addBreadcrumb(message, opts);
if (typeof original === 'function') {
Function.prototype.apply.call(original, window.console, arguments);
}
};
});
});
})(); // Wrap timers
(function () {
function instrumentTimer(wrapOpts) {
return function (original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
return function (func, delay) {
if (typeof func === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
func = wrap(func, wrapOpts);
return original(function () {
func.apply(null, args);
}, delay);
} else {
return original(func, delay);
}
};
};
}
instrument(window, 'setTimeout', instrumentTimer({
component: 'setTimeout'
}));
instrument(window, 'setInterval', instrumentTimer({
component: 'setInterval'
}));
})(); // Wrap event listeners
// Event targets borrowed from bugsnag-js:
// See https://github.com/bugsnag/bugsnag-js/blob/d55af916a4d3c7757f979d887f9533fe1a04cc93/src/bugsnag.js#L542
'EventTarget Window Node ApplicationCache AudioTrackList ChannelMergerNode CryptoOperation EventSource FileReader HTMLUnknownElement IDBDatabase IDBRequest IDBTransaction KeyOperation MediaController MessagePort ModalWindow Notification SVGElementInstance Screen TextTrack TextTrackCue TextTrackList WebSocket WebSocketWorker Worker XMLHttpRequest XMLHttpRequestEventTarget XMLHttpRequestUpload'.replace(/\w+/g, function (prop) {

@@ -673,7 +1153,10 @@ var prototype = window[prop] && window[prop].prototype;

instrument(prototype, 'addEventListener', function (original) {
// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
var wrapOpts = {
component: "".concat(prop, ".prototype.addEventListener")
}; // See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
return function (type, listener, useCapture, wantsUntrusted) {
try {
if (listener && listener.handleEvent != null) {
listener.handleEvent = wrap(listener.handleEvent);
listener.handleEvent = wrap(listener.handleEvent, wrapOpts);
}

@@ -685,3 +1168,3 @@ } catch (e) {

return original.call(this, type, wrap(listener), useCapture, wantsUntrusted);
return original.call(this, type, wrap(listener, wrapOpts), useCapture, wantsUntrusted);
};

@@ -696,3 +1179,4 @@ });

}
});
}); // Wrap window.onerror
instrument(window, 'onerror', function (original) {

@@ -714,9 +1198,10 @@ function onerror(msg, url, line, col, err) {

return;
} // simulate v8 stack
} // Simulate v8 stack
var stack = [msg, '\n at ? (', url || 'unknown', ':', line || 0, ':', col || 0, ')'].join('');
var simulatedStack = [msg, '\n at ? (', url || 'unknown', ':', line || 0, ':', col || 0, ')'].join('');
var generated;
if (err) {
var generated = {
generated = {
stack: stackTrace(err)

@@ -727,15 +1212,23 @@ };

generated = {
stack: stack
stack: simulatedStack
};
}
notify(err, generated);
return;
} else {
// Important: leave `generated` undefined
err = {
name: 'window.onerror',
message: msg,
stack: simulatedStack
};
}
notify({
name: 'window.onerror',
message: msg,
stack: stack
self.addBreadcrumb(err.name === 'window.onerror' || !err.name ? 'window.onerror' : "window.onerror: ".concat(err.name), {
category: 'error',
metadata: {
message: err.message,
name: err.name,
stack: generated ? generated.stack : err.stack
}
});
notify(err, generated);
} // See https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror

@@ -753,3 +1246,4 @@

};
});
}); // Wrap window.onunhandledrejection
instrument(window, 'onunhandledrejection', function (original) {

@@ -776,7 +1270,12 @@ // See https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event

var stack = stackTrace(reason) || stackFallback;
notify({
var err = {
name: reason.name,
message: "UnhandledPromiseRejectionWarning: ".concat(reason),
stack: stack
};
self.addBreadcrumb("window.onunhandledrejection: ".concat(err.name), {
category: 'error',
metadata: err
});
notify(err);
return;

@@ -783,0 +1282,0 @@ }

2

dist/honeybadger.min.js

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

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).Honeybadger=n()}(this,function(){"use strict";function R(e){return(R="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var e=function(){var b,w,j="2.0.0",k={name:"honeybadger.js",url:"https://github.com/honeybadger-io/honeybadger-js",version:j,language:"javascript"},E=!1,x=!1;function _(e,n){var t={};for(var r in e)t[r]=e[r];for(var r in n)t[r]=n[r];return t}function S(e,n){var t=_(e,n);return e.context&&n.context&&(t.context=_(e.context,n.context)),t}function T(e){return!!b&&b.name===e.name&&b.message===e.message&&b.stack===e.stack}function O(e){return e.stacktrace||e.stack||void 0}return function(e){var c=x,n=[],u=[],f={context:{},beforeNotifyHandlers:[],errorsSent:0};if("object"===R(e))for(var t in e)f[t]=e[t];function s(){var e=window.console;if(e){var n=Array.prototype.slice.call(arguments);n.unshift("[Honeybadger]"),e.log.apply(e,n)}}function l(){if(p("debug"))return s.apply(this,arguments)}function p(e,n){var t=f[e];return void 0===t&&(t=f[e.toLowerCase()]),"false"===t&&(t=!1),void 0!==t?t:n}function d(){return!c&&p("onerror",!0)}function r(e,n){try{var t=new XMLHttpRequest;t.open("POST","http"+(p("ssl",!0)?"s":"")+"://"+p("host","api.honeybadger.io")+"/v1/notices/js",p("async",!0)),t.setRequestHeader("X-API-Key",e),t.setRequestHeader("Content-Type","application/json"),t.setRequestHeader("Accept","text/json, application/json"),t.send(JSON.stringify(function e(n,t){var r,o,i,a;if(i={},t||(t=0),t>=p("max_depth",8))return"[MAX DEPTH REACHED]";for(r in n)o=n[r],Object.prototype.hasOwnProperty.call(n,r)&&null!=r&&null!=o&&((/function|symbol/.test(R(a=o))||"object"===R(a)&&void 0===a.hasOwnProperty)&&(o=Object.prototype.toString.call(o)),i[r]="object"===R(o)?e(o,t+1):o);return i}(n)))}catch(e){s("Unable to send error report: error while initializing request",e,n)}}function v(e){if(b=w=null,p("disabled",!1))return l("Dropping notice: honeybadger.js is disabled",e),!1;var n,t=p("apiKey",p("api_key"));return t?(n=p("maxErrors"))&&f.errorsSent>=n?(l("Dropping notice: max errors exceeded",e),!1):(f.errorsSent++,r(t,e),!0):(s("Unable to send error report: no API key has been configured"),!1)}function y(e,n){if(e||(e={}),"[object Error]"===Object.prototype.toString.call(e)){var t=e;e=_(e,{name:t.name,message:t.message,stack:O(t)})}if("object"!==R(e)){var r=String(e);e={message:r}}if(T(e))return!1;if(w&&E&&v(w),function(e){for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n))return!1;return!0}(e))return!1;var o;n&&(e.stack=n.stack,o=n.generator);var i=(e=_(e,{name:e.name||"Error",context:_(f.context,e.context),url:e.url||document.URL,projectRoot:e.projectRoot||e.project_root||p("projectRoot",p("project_root",window.location.protocol+"//"+window.location.host)),environment:e.environment||p("environment"),component:e.component||p("component"),action:e.action||p("action"),revision:e.revision||p("revision")})).stack;if(function(e,n){var t,r;for(t=0,r=e.length;t<r;t++)if(!1===(0,e[t])(n))return!0;return!1}(f.beforeNotifyHandlers,e))return!1;if(e.stack!=i&&(o=void 0),function(e,n){var t=e.message;for(var r in n)if(t.match(n[r]))return!0;return!1}(e,p("ignorePatterns")))return!1;var a,c=((a={}).HTTP_USER_AGENT=navigator.userAgent,document.referrer.match(/\S/)&&(a.HTTP_REFERER=document.referrer),a);"string"==typeof e.cookies?c.HTTP_COOKIE=e.cookies:"object"===R(e.cookies)&&(c.HTTP_COOKIE=function(e){if("object"===R(e)){var n=[];for(var t in e)n.push(t+"="+e[t]);return n.join(";")}}(e.cookies));var s={notifier:k,error:{class:e.name,message:e.message,backtrace:e.stack,generator:o,fingerprint:e.fingerprint},request:{url:e.url,component:e.component,action:e.action,context:e.context,cgi_data:c,params:e.params},server:{project_root:e.projectRoot,environment_name:e.environment,revision:e.revision}};return w=s,b=e,E?(l("Deferring notice",e,s),window.setTimeout(function(){T(e)&&v(s)})):(l("Queuing notice",e,s),u.push(s)),e}var o=!0;if(window.atob||(o=!1),window.ErrorEvent)try{0===new window.ErrorEvent("").colno&&(o=!1)}catch(e){}function i(n,t){try{return"function"!=typeof n?n:(e=n,"function"!=typeof Object.isExtensible||Object.isExtensible(e)?(n.___hb||(n.___hb=function(){var e=d();if(!(o&&(e||t)||t&&!e))return n.apply(this,arguments);try{return n.apply(this,arguments)}catch(e){throw y(e),e}}),n.___hb.___hb=n.___hb,n.___hb):n)}catch(e){return n}var e}f.notify=function(e,n,t){if(e||(e={}),"[object Error]"===Object.prototype.toString.call(e)){var r=e;e=_(e,{name:r.name,message:r.message,stack:O(r)})}return"object"!==R(e)&&(e={message:String(e)}),n&&"object"!==R(n)&&(n={name:String(n)}),n&&(e=S(e,n)),"object"===R(t)&&(e=S(e,t)),y(e,function(e){var n;if(e&&(n=O(e)))return{stack:n,generator:void 0};try{throw new Error("")}catch(e){if(n=O(e))return{stack:n,generator:"throw"}}n=["<call-stack>"];for(var t=arguments.callee;t&&n.length<10;){/function(?:\s+([\w$]+))+\s*\(/.test(t.toString())?n.push(RegExp.$1||"<anonymous>"):n.push("<anonymous>");try{t=t.caller}catch(e){break}}return{stack:n.join("\n"),generator:"walk"}}(e))},f.wrap=function(e){return i(e,!0)},f.setContext=function(e){return"object"===R(e)&&(f.context=_(f.context,e)),f},f.resetContext=function(e){return"object"===R(e)?f.context=_({},e):f.context={},f},f.configure=function(e){for(var n in e)f[n]=e[n];return f},f.beforeNotify=function(e){return f.beforeNotifyHandlers.push(e),f};var a=[].indexOf||function(e){for(var n=0,t=this.length;n<t;n++)if(n in this&&this[n]===e)return n;return-1};function m(e,n,t){if(!c&&e&&n&&t){var r=e[n];e[n]=t(r)}}f.reset=function(){for(var e in f.context={},f.beforeNotifyHandlers=[],f)-1==a.call(n,e)&&(f[e]=void 0);return f.resetMaxErrors(),f},f.resetMaxErrors=function(){return f.errorsSent=0},f.getVersion=function(){return j};var g=function(r){return function(e,n){if("function"!=typeof e)return r(e,n);var t=Array.prototype.slice.call(arguments,2);return e=i(e),r(function(){e.apply(null,t)},n)}};for(var t in m(window,"setTimeout",g),m(window,"setInterval",g),"EventTarget Window Node ApplicationCache AudioTrackList ChannelMergerNode CryptoOperation EventSource FileReader HTMLUnknownElement IDBDatabase IDBRequest IDBTransaction KeyOperation MediaController MessagePort ModalWindow Notification SVGElementInstance Screen TextTrack TextTrackCue TextTrackList WebSocket WebSocketWorker Worker XMLHttpRequest XMLHttpRequestEventTarget XMLHttpRequestUpload".replace(/\w+/g,function(e){var n=window[e]&&window[e].prototype;n&&n.hasOwnProperty&&n.hasOwnProperty("addEventListener")&&(m(n,"addEventListener",function(o){return function(e,n,t,r){try{n&&null!=n.handleEvent&&(n.handleEvent=i(n.handleEvent))}catch(e){s(e)}return o.call(this,e,i(n),t,r)}}),m(n,"removeEventListener",function(o){return function(e,n,t,r){return o.call(this,e,n,t,r),o.call(this,e,i(n),t,r)}}))}),m(window,"onerror",function(i){return function(e,n,t,r,o){return function(e,n,t,r,o){if(l("window.onerror callback invoked",arguments),!b&&d())if(0===t&&/Script error\.?/.test(e))s("Ignoring cross-domain script error: enable CORS to track these types of errors",arguments);else{var i=[e,"\n at ? (",n||"unknown",":",t||0,":",r||0,")"].join("");if(o){var a={stack:O(o)};return a.stack||(a={stack:i}),y(o,a)}y({name:"window.onerror",message:e,stack:i})}}(e,n,t,r,o),!("function"!=typeof i||!p("_onerror_call_orig",!0))&&i.apply(this,arguments)}}),m(window,"onunhandledrejection",function(n){function t(e){if(l("window.onunhandledrejection callback invoked",arguments),!b&&!c&&p("onunhandledrejection",!0)){var n=e.reason;if(n instanceof Error){var t=n.fileName||"unknown",r=n.lineNumber||0,o="".concat(n.message,"\n at ? (").concat(t,":").concat(r,")"),i=O(n)||o;y({name:n.name,message:"UnhandledPromiseRejectionWarning: ".concat(n),stack:i})}else{var a="string"==typeof n?n:JSON.stringify(n);y({name:"window.onunhandledrejection",message:"UnhandledPromiseRejectionWarning: ".concat(a)})}}}return function(e){t(e),"function"==typeof n&&n.apply(this,arguments)}}),x=!0,f)n.push(t);if(l("Initializing honeybadger.js "+j),/complete|interactive|loaded/.test(document.readyState))E=!0,l("honeybadger.js 2.0.0 ready");else{l("Installing ready handler");var h=function(){var e;for(E=!0,l("honeybadger.js 2.0.0 ready");e=u.pop();)v(e)};document.addEventListener?document.addEventListener("DOMContentLoaded",h,!0):window.attachEvent("onload",h)}return f}}(),n=e();return n.factory=e,n});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Honeybadger=e()}(this,function(){"use strict";function T(t){return(T="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function N(t,i){var u=[];return function e(t,n){if(n||(n=0),i<=n)return"[DEPTH]";if(/function|symbol/.test(T(r=t))||"object"===T(r)&&void 0===r.hasOwnProperty)return Object.prototype.toString.call(t);var r;if(function(t){if(!t||"object"!==T(t))return!1;for(var e=0;e<u.length;e++)if(u[e]===t)return!0;return u.push(t),!1}(t))return"[RECURSION]";if(Array.isArray(t))return t.map(function(t){return e(t,n+1)});if("object"!==T(t))return t;var o={};for(var a in t){var c=t[a];Object.prototype.hasOwnProperty.call(t,a)&&null!=a&&null!=c&&(o[a]=e(c,n+1))}return o}(t)}function H(n){if(!n||!n.tagName)return"";var r=n.tagName.toLowerCase();if("html"===r)return"";n.id&&(r+="#".concat(n.id));var t=n.getAttribute("class");t&&t.split(/\s+/).forEach(function(t){r+=".".concat(t)}),["alt","name","title","type"].forEach(function(t){var e=n.getAttribute(t);e&&(r+="[".concat(t,'="').concat(e,'"]'))});var e=function(e){try{var t=e.parentNode.childNodes,n=[];return Array.prototype.forEach.call(t,function(t){t.tagName&&t.tagName===e.tagName&&n.push(t)}),n}catch(t){return[]}}(n);return 1<e.length&&(r+=":nth-child(".concat(Array.prototype.indexOf.call(e,n)+1,")")),r}function L(t){return-1!==t.toString().indexOf("native")}function r(t){var e=t.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/)||{};return{protocol:e[2],host:e[4],pathname:e[5]}}function C(t){var e=r(t),n=r(document.URL);return!e.host||e.protocol?e.pathname:e.protocol===n.protocol&&e.host===n.host?e.pathname:"".concat(e.protocol,"://").concat(e.host).concat(e.pathname)}var t=function(){var b,w,k="2.1.0-beta.0",_={name:"honeybadger-js",url:"https://github.com/honeybadger-io/honeybadger-js",version:k,language:"javascript"},j=!1,x=!1;function E(t,e){var n={};for(var r in t)n[r]=t[r];for(var r in e)n[r]=e[r];return n}function S(t,e){var n=E(t,e);return t.context&&e.context&&(n.context=E(t.context,e.context)),n}function R(t){return!!b&&b.name===t.name&&b.message===t.message&&b.stack===t.stack}function O(t){return t.stacktrace||t.stack||void 0}return function(t){var u=x,e=[],s=[],f={context:{},beforeNotifyHandlers:[],breadcrumbs:[],errorsSent:0};if("object"===T(t))for(var n in t)f[n]=t[n];function i(){var t=window.console;if(t){var e=Array.prototype.slice.call(arguments);e.unshift("[Honeybadger]"),t.log.apply(t,e)}}function d(){if(l("debug"))return i.apply(this,arguments)}function l(t,e){var n=f[t];return void 0===n&&(n=f[t.toLowerCase()]),"false"===n&&(n=!1),void 0!==n?n:e}function p(){return!u&&l("onerror",!0)}function m(){return l("breadcrumbsEnabled",!1)}function r(t,e){try{var n=new XMLHttpRequest;n.open("POST","http"+(l("ssl",!0)?"s":"")+"://"+l("host","api.honeybadger.io")+"/v1/notices/js",l("async",!0)),n.setRequestHeader("X-API-Key",t),n.setRequestHeader("Content-Type","application/json"),n.setRequestHeader("Accept","text/json, application/json"),n.send(JSON.stringify(N(e,l("max_depth",8))))}catch(t){i("Unable to send error report: error while initializing request",t,e)}}function h(t){if(b=w=null,l("disabled",!1))return d("Dropping notice: honeybadger.js is disabled",t),!1;var e,n=l("apiKey",l("api_key"));return n?(e=l("maxErrors"))&&f.errorsSent>=e?(d("Dropping notice: max errors exceeded",t),!1):(f.errorsSent++,r(n,t),!0):(i("Unable to send error report: no API key has been configured"),!1)}function y(t,e){if(t||(t={}),"[object Error]"===Object.prototype.toString.call(t)){var n=t;t=E(t,{name:n.name,message:n.message,stack:O(n)})}if("object"!==T(t)){var r=String(t);t={message:r}}if(R(t))return!1;if(w&&j&&h(w),function(t){for(var e in t)if(Object.prototype.hasOwnProperty.call(t,e))return!1;return!0}(t))return!1;var o;e&&(t.stack=e.stack,o=e.generator),t=E(t,{name:t.name||"Error",context:E(f.context,t.context),url:t.url||document.URL,projectRoot:t.projectRoot||t.project_root||l("projectRoot",l("project_root",window.location.protocol+"//"+window.location.host)),environment:t.environment||l("environment"),component:t.component||l("component"),action:t.action||l("action"),revision:t.revision||l("revision")}),f.addBreadcrumb("Honeybadger Notice",{category:"notice",metadata:{message:t.message,name:t.name,stack:t.stack}}),t.breadcrumbs=f.breadcrumbs.slice();var a=t.stack;if(function(t,e){var n,r;for(n=0,r=t.length;n<r;n++)if(!1===(0,t[n])(e))return!0;return!1}(f.beforeNotifyHandlers,t))return!1;if(t.stack!=a&&(o=void 0),function(t,e){var n=t.message;for(var r in e)if(n.match(e[r]))return!0;return!1}(t,l("ignorePatterns")))return!1;var c,i=((c={}).HTTP_USER_AGENT=navigator.userAgent,document.referrer.match(/\S/)&&(c.HTTP_REFERER=document.referrer),c);"string"==typeof t.cookies?i.HTTP_COOKIE=t.cookies:"object"===T(t.cookies)&&(i.HTTP_COOKIE=function(t){if("object"===T(t)){var e=[];for(var n in t)e.push(n+"="+t[n]);return e.join(";")}}(t.cookies));var u={notifier:_,breadcrumbs:{enabled:m(),trail:t.breadcrumbs},error:{class:t.name,message:t.message,backtrace:t.stack,generator:o,fingerprint:t.fingerprint},request:{url:t.url,component:t.component,action:t.action,context:t.context,cgi_data:i,params:t.params},server:{project_root:t.projectRoot,environment_name:t.environment,revision:t.revision}};return w=u,b=t,j?(d("Deferring notice",t,u),window.setTimeout(function(){R(t)&&h(u)})):(d("Queuing notice",t,u),s.push(u)),t}var o=!0;if(window.atob||(o=!1),window.ErrorEvent)try{0===new window.ErrorEvent("").colno&&(o=!1)}catch(t){}function c(n,r){r||(r={});try{return"function"!=typeof n?n:(t=n,"function"!=typeof Object.isExtensible||Object.isExtensible(t)?(n.___hb||(n.___hb=function(){var t=p();if(!(o&&(t||r.force)||r.force&&!t))return n.apply(this,arguments);try{return n.apply(this,arguments)}catch(t){var e={stack:O(t)};throw f.addBreadcrumb(r.component?"".concat(r.component,": ").concat(t.name):t.name,{category:"error",metadata:{message:t.message,name:t.name,stack:e.stack}}),y(t,e),t}}),n.___hb.___hb=n.___hb,n.___hb):n)}catch(t){return n}var t}f.notify=function(t,e,n){if(t||(t={}),"[object Error]"===Object.prototype.toString.call(t)){var r=t;t=E(t,{name:r.name,message:r.message,stack:O(r)})}return"object"!==T(t)&&(t={message:String(t)}),e&&"object"!==T(e)&&(e={name:String(e)}),e&&(t=S(t,e)),"object"===T(n)&&(t=S(t,n)),y(t,function(t){var e;if(t&&(e=O(t)))return{stack:e,generator:void 0};try{throw new Error("")}catch(t){if(e=O(t))return{stack:e,generator:"throw"}}e=["<call-stack>"];for(var n=arguments.callee;n&&e.length<10;){/function(?:\s+([\w$]+))+\s*\(/.test(n.toString())?e.push(RegExp.$1||"<anonymous>"):e.push("<anonymous>");try{n=n.caller}catch(t){break}}return{stack:e.join("\n"),generator:"walk"}}(t))},f.wrap=function(t){return c(t,{force:!0})},f.setContext=function(t){return"object"===T(t)&&(f.context=E(f.context,t)),f},f.resetContext=function(t){return"object"===T(t)?f.context=E({},t):f.context={},f},f.configure=function(t){for(var e in t)f[e]=t[e];return f},f.beforeNotify=function(t){return f.beforeNotifyHandlers.push(t),f};var a=[].indexOf||function(t){for(var e=0,n=this.length;e<n;e++)if(e in this&&this[e]===t)return e;return-1};function g(t,e,n){if(!u&&t&&e&&n&&e in t){var r=t[e];t[e]=n(r)}}for(var n in f.reset=function(){for(var t in f.context={},f.beforeNotifyHandlers=[],f.breadcrumbs=[],f)-1==a.call(e,t)&&(f[t]=void 0);return f.resetMaxErrors(),f},f.resetMaxErrors=function(){return f.errorsSent=0},f.getVersion=function(){return k},f.addBreadcrumb=function(t,e){if(m()){var n=(e=e||{}).metadata||void 0,r=e.category||"custom",o=(new Date).toISOString();f.breadcrumbs.push({category:r,message:t,metadata:n||{},timestamp:o});var a=l("maxBreadcrumbs",40);return f.breadcrumbs.length>a&&(f.breadcrumbs=f.breadcrumbs.slice(f.breadcrumbs.length-a)),f}},window.addEventListener("click",function(t){var e,n,r,o,a,c;try{e=H(t.target),n=function t(e){var n=H(e);if(e.parentNode&&e.parentNode.tagName){var r=t(e.parentNode);if(0<r.length)return"".concat(r," > ").concat(n)}return n}(t.target),o=t.target,a=(o.textContent||o.innerText||o.value||"").trim(),c=300,a.length>c&&(a=a.substr(0,c)+"..."),r=a}catch(t){e="UI Click",r=n="[unknown]"}0!==e.length&&f.addBreadcrumb(e,{category:"ui.click",metadata:{selector:n,text:r,event:t}})},!0),g(XMLHttpRequest.prototype,"open",function(r){return function(){var t=arguments[1],e="string"==typeof arguments[0]?arguments[0].toUpperCase():arguments[0],n="".concat(e," ").concat(C(t));this.__hb_xhr={type:"xhr",method:e,url:t,message:n},"function"==typeof r&&r.apply(this,arguments)}}),g(XMLHttpRequest.prototype,"send",function(t){return function(){var e=this;function n(){var t;4===e.readyState&&(e.__hb_xhr&&(e.__hb_xhr.status_code=e.status,t=e.__hb_xhr.message,delete e.__hb_xhr.message),f.addBreadcrumb(t||"XMLHttpRequest",{category:"request",metadata:e.__hb_xhr}))}"onreadystatechange"in e&&"function"==typeof e.onreadystatechange?g(e,"onreadystatechange",function(t){return function(){n(),"function"==typeof t&&t.apply(this,arguments)}}):e.onreadystatechange=n,"function"==typeof t&&t.apply(e,arguments)}}),function(){if(!window.fetch)return!1;if(L(window.fetch))return!0;try{var t=document.createElement("iframe");t.style.display="none",document.head.appendChild(t);var e=t.contentWindow.fetch&&L(t.contentWindow.fetch);return document.head.removeChild(t),e}catch(t){console&&console.warn&&console.warn("failed to detect native fetch via iframe: "+t)}return!1}()&&g(window,"fetch",function(a){return function(){var t,e=arguments[0],n="GET";"string"==typeof e?t=e:"Request"in window&&e instanceof Request?(t=e.url,e.method&&(n=e.method)):t=String(e),arguments[1]&&arguments[1].method&&(n=arguments[1].method),"string"==typeof n&&(n=n.toUpperCase());var r="".concat(n," ").concat(C(t)),o={type:"fetch",method:n,url:t};return a.apply(this,arguments).then(function(t){return o.status_code=t.status,f.addBreadcrumb(r,{category:"request",metadata:o}),t}).catch(function(t){throw f.addBreadcrumb("fetch error",{category:"error",metadata:o}),t})}}),function(){var n=window.location.href;function r(t,e){n=e,f.addBreadcrumb("Page changed",{category:"navigation",metadata:{from:t,to:e}})}function t(e){return function(){var t=2<arguments.length?arguments[2]:void 0;return t&&r(n,String(t)),e.apply(this,arguments)}}g(window,"onpopstate",function(t){return function(){if(r(n,window.location.href),t)return t.apply(this,arguments)}}),g(window.history,"pushState",t),g(window.history,"replaceState",t)}(),["debug","info","warn","error","log"].forEach(function(a){g(window.console,a,function(o){return function(){var t,e=Array.prototype.slice.call(arguments),n=(t=e,Array.isArray(t)?t.map(function(t){try{return String(t)}catch(t){return"[unknown]"}}).join(" "):""),r={category:"log",metadata:{level:a,arguments:N(e,3)}};f.addBreadcrumb(n,r),"function"==typeof o&&Function.prototype.apply.call(o,window.console,arguments)}})}),function(){function t(o){return function(r){return function(t,e){if("function"!=typeof t)return r(t,e);var n=Array.prototype.slice.call(arguments,2);return t=c(t,o),r(function(){t.apply(null,n)},e)}}}g(window,"setTimeout",t({component:"setTimeout"})),g(window,"setInterval",t({component:"setInterval"}))}(),"EventTarget Window Node ApplicationCache AudioTrackList ChannelMergerNode CryptoOperation EventSource FileReader HTMLUnknownElement IDBDatabase IDBRequest IDBTransaction KeyOperation MediaController MessagePort ModalWindow Notification SVGElementInstance Screen TextTrack TextTrackCue TextTrackList WebSocket WebSocketWorker Worker XMLHttpRequest XMLHttpRequestEventTarget XMLHttpRequestUpload".replace(/\w+/g,function(t){var e=window[t]&&window[t].prototype;e&&e.hasOwnProperty&&e.hasOwnProperty("addEventListener")&&(g(e,"addEventListener",function(o){var a={component:"".concat(t,".prototype.addEventListener")};return function(t,e,n,r){try{e&&null!=e.handleEvent&&(e.handleEvent=c(e.handleEvent,a))}catch(t){i(t)}return o.call(this,t,c(e,a),n,r)}}),g(e,"removeEventListener",function(o){return function(t,e,n,r){return o.call(this,t,e,n,r),o.call(this,t,c(e),n,r)}}))}),g(window,"onerror",function(a){return function(t,e,n,r,o){return function(t,e,n,r,o){if(d("window.onerror callback invoked",arguments),!b&&p())if(0===n&&/Script error\.?/.test(t))i("Ignoring cross-domain script error: enable CORS to track these types of errors",arguments);else{var a,c=[t,"\n at ? (",e||"unknown",":",n||0,":",r||0,")"].join("");o?(a={stack:O(o)}).stack||(a={stack:c}):o={name:"window.onerror",message:t,stack:c},f.addBreadcrumb("window.onerror"!==o.name&&o.name?"window.onerror: ".concat(o.name):"window.onerror",{category:"error",metadata:{message:o.message,name:o.name,stack:a?a.stack:o.stack}}),y(o,a)}}(t,e,n,r,o),!("function"!=typeof a||!l("_onerror_call_orig",!0))&&a.apply(this,arguments)}}),g(window,"onunhandledrejection",function(e){function n(t){if(d("window.onunhandledrejection callback invoked",arguments),!b&&!u&&l("onunhandledrejection",!0)){var e=t.reason;if(e instanceof Error){var n=e.fileName||"unknown",r=e.lineNumber||0,o="".concat(e.message,"\n at ? (").concat(n,":").concat(r,")"),a=O(e)||o,c={name:e.name,message:"UnhandledPromiseRejectionWarning: ".concat(e),stack:a};return f.addBreadcrumb("window.onunhandledrejection: ".concat(c.name),{category:"error",metadata:c}),void y(c)}var i="string"==typeof e?e:JSON.stringify(e);y({name:"window.onunhandledrejection",message:"UnhandledPromiseRejectionWarning: ".concat(i)})}}return function(t){n(t),"function"==typeof e&&e.apply(this,arguments)}}),x=!0,f)e.push(n);if(d("Initializing honeybadger.js "+k),/complete|interactive|loaded/.test(document.readyState))j=!0,d("honeybadger.js "+k+" ready");else{d("Installing ready handler");var v=function(){var t;for(j=!0,d("honeybadger.js "+k+" ready");t=s.pop();)h(t)};document.addEventListener?document.addEventListener("DOMContentLoaded",v,!0):window.attachEvent("onload",v)}return f}}(),e=t();return e.factory=t,e});
//# sourceMappingURL=honeybadger.min.js.map

@@ -14,2 +14,3 @@ declare module "honeybadger-js" {

disabled?: boolean;
maxErrors?: number;
ignorePatterns?: RegExp[];

@@ -30,2 +31,3 @@ async?: boolean;

context: any;
cookies?: string;
}

@@ -32,0 +34,0 @@

{
"name": "honeybadger-js",
"description": "A JavaScript library for integrating apps with the Honeybadger Rails Error Notifier.",
"version": "2.0.0",
"version": "2.1.0-beta.0",
"license": "MIT",

@@ -37,11 +37,19 @@ "homepage": "https://github.com/honeybadger-io/honeybadger-js",

"@babel/preset-env": "^7.3.4",
"jasmine": "^3.3.1",
"jasmine-core": "^3.3.0",
"karma": "^4.0.1",
"babel-eslint": "^10.0.3",
"eslint": "^6.1.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-config-prettier": "^6.4.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-prettier": "^3.1.1",
"jasmine": "^3.5.0",
"jasmine-core": "^3.5.0",
"karma": "^4.3.0",
"karma-browserstack-launcher": "^1.5.1",
"karma-chrome-launcher": "^3.0.0",
"karma-jasmine": "^2.0.1",
"karma-rollup-preprocessor": "^7.0.0",
"karma-sauce-launcher": "^2.0.2",
"karma-sinon": "^1.0.5",
"puppeteer": "^1.13.0",
"prettier": "^1.18.2",
"promise-polyfill": "8.1.3",
"puppeteer": "^1.20.0",
"rollup": "^1.0.0",

@@ -53,3 +61,4 @@ "rollup-plugin-babel": "^4.3.2",

"rollup-plugin-uglify": "^6.0.2",
"sinon": "^7.3.1"
"sinon": "^7.3.1",
"whatwg-fetch": "^3.0.0"
},

@@ -56,0 +65,0 @@ "readmeFilename": "README.md",

# Honeybadger Client-Side Javascript Library
[![CircleCI](https://circleci.com/gh/honeybadger-io/honeybadger-js.svg?style=svg)](https://circleci.com/gh/honeybadger-io/honeybadger-js)
[![Build Status](https://app.saucelabs.com/buildstatus/honeybadger_os)](https://app.saucelabs.com/builds/16ac6c22e2ea4140b3051bf21fb579da)

@@ -28,4 +27,4 @@ A client-side JavaScript library for integrating apps with the :zap: [Honeybadger Error Notifier](http://honeybadger.io). For server-side javascript, check out our [NodeJS library](https://github.com/honeybadger-io/honeybadger-node).

2. To run the test suite by itself, use `npm test`.
3. To run the tests across all supported platforms, set up a [Sauce Labs](https://saucelabs.com/)
account and use `SAUCE_USERNAME=your_username SAUCE_ACCESS_KEY=your-access-key npm run test:ci`.
3. To run the tests across all supported platforms, set up a [BrowserStack](https://www.browserstack.com/)
account and use `BROWSERSTACK_USERNAME=your_username BROWSERSTACK_ACCESS_KEY=your-access-key npm run test:ci`.

@@ -63,1 +62,5 @@ ## Releasing

The Honeybadger gem is MIT licensed. See the [MIT-LICENSE](https://raw.github.com/honeybadger-io/honeybadger-js/master/MIT-LICENSE) file in this repository for details.
---
<p><a href="https://www.browserstack.com/"><img src="/browserstack-logo.png" width="150"></a><br>
<small>We use <a href="https://www.browserstack.com/">BrowserStack</a> to run our automated integration tests on multiple platforms in CI.</small></p>

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