@bugsnag/node
Version:
Bugsnag error reporter for Node.js
1,644 lines (1,342 loc) • 68.3 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.bugsnag = f()}})(function(){var define,module,exports;
// minimal implementations of useful ES functionality
// all we really need for arrays is reduce – everything else is just sugar!
// Array#reduce
var reduce = function (arr, fn, accum) {
var val = accum;
for (var i = 0, len = arr.length; i < len; i++) {
val = fn(val, arr[i], i, arr);
}
return val;
}; // Array#filter
var filter = function (arr, fn) {
return reduce(arr, function (accum, item, i, arr) {
return !fn(item, i, arr) ? accum : accum.concat(item);
}, []);
}; // Array#map
var map = function (arr, fn) {
return reduce(arr, function (accum, item, i, arr) {
return accum.concat(fn(item, i, arr));
}, []);
}; // Array#includes
var includes = function (arr, x) {
return reduce(arr, function (accum, item, i, arr) {
return accum === true || item === x;
}, false);
};
var _hasDontEnumBug = !{
toString: null
}.propertyIsEnumerable('toString');
var _dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor']; // Object#keys
var keys = function (obj) {
// stripped down version of
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/Keys
var result = [];
var prop;
for (prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (!_hasDontEnumBug) return result;
for (var i = 0, len = _dontEnums.length; i < len; i++) {
if (Object.prototype.hasOwnProperty.call(obj, _dontEnums[i])) result.push(_dontEnums[i]);
}
return result;
}; // Array#isArray
var isArray = function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
};
var _pad = function (n) {
return n < 10 ? "0" + n : n;
}; // Date#toISOString
var isoDate = function () {
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
var d = new Date();
return d.getUTCFullYear() + '-' + _pad(d.getUTCMonth() + 1) + '-' + _pad(d.getUTCDate()) + 'T' + _pad(d.getUTCHours()) + ':' + _pad(d.getUTCMinutes()) + ':' + _pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z';
};
var _$esUtils_8 = {
map: map,
reduce: reduce,
filter: filter,
includes: includes,
keys: keys,
isArray: isArray,
isoDate: isoDate
};
var __isoDate_2 = _$esUtils_8.isoDate;
var BugsnagBreadcrumb =
/*#__PURE__*/
function () {
function BugsnagBreadcrumb(name, metaData, type, timestamp) {
if (name === void 0) {
name = '[anonymous]';
}
if (metaData === void 0) {
metaData = {};
}
if (type === void 0) {
type = 'manual';
}
if (timestamp === void 0) {
timestamp = __isoDate_2();
}
this.type = type;
this.name = name;
this.metaData = metaData;
this.timestamp = timestamp;
}
var _proto = BugsnagBreadcrumb.prototype;
_proto.toJSON = function toJSON() {
return {
type: this.type,
name: this.name,
timestamp: this.timestamp,
metaData: this.metaData
};
};
return BugsnagBreadcrumb;
}();
var _$BugsnagBreadcrumb_2 = BugsnagBreadcrumb;
var _$validators_17 = {};
_$validators_17.intRange = function (min, max) {
if (min === void 0) {
min = 1;
}
if (max === void 0) {
max = Infinity;
}
return function (value) {
return typeof value === 'number' && parseInt('' + value, 10) === value && value >= min && value <= max;
};
};
_$validators_17.stringWithLength = function (value) {
return typeof value === 'string' && !!value.length;
};
var _$config_4 = {};
var __filter_4 = _$esUtils_8.filter,
__reduce_4 = _$esUtils_8.reduce,
__keys_4 = _$esUtils_8.keys,
__isArray_4 = _$esUtils_8.isArray,
__includes_4 = _$esUtils_8.includes;
var intRange = _$validators_17.intRange,
stringWithLength = _$validators_17.stringWithLength;
_$config_4.schema = {
apiKey: {
defaultValue: function () {
return null;
},
message: 'is required',
validate: stringWithLength
},
appVersion: {
defaultValue: function () {
return null;
},
message: 'should be a string',
validate: function (value) {
return value === null || stringWithLength(value);
}
},
appType: {
defaultValue: function () {
return null;
},
message: 'should be a string',
validate: function (value) {
return value === null || stringWithLength(value);
}
},
autoNotify: {
defaultValue: function () {
return true;
},
message: 'should be true|false',
validate: function (value) {
return value === true || value === false;
}
},
beforeSend: {
defaultValue: function () {
return [];
},
message: 'should be a function or array of functions',
validate: function (value) {
return typeof value === 'function' || __isArray_4(value) && __filter_4(value, function (f) {
return typeof f === 'function';
}).length === value.length;
}
},
endpoints: {
defaultValue: function () {
return {
notify: 'https://notify.bugsnag.com',
sessions: 'https://sessions.bugsnag.com'
};
},
message: 'should be an object containing endpoint URLs { notify, sessions }. sessions is optional if autoCaptureSessions=false',
validate: function (val, obj) {
return (// first, ensure it's an object
val && typeof val === 'object' && // endpoints.notify must always be set
stringWithLength(val.notify) && ( // endpoints.sessions must be set unless session tracking is explicitly off
obj.autoCaptureSessions === false || stringWithLength(val.sessions)) && // ensure no keys other than notify/session are set on endpoints object
__filter_4(__keys_4(val), function (k) {
return !__includes_4(['notify', 'sessions'], k);
}).length === 0
);
}
},
autoCaptureSessions: {
defaultValue: function (val, opts) {
return opts.endpoints === undefined || !!opts.endpoints && !!opts.endpoints.sessions;
},
message: 'should be true|false',
validate: function (val) {
return val === true || val === false;
}
},
notifyReleaseStages: {
defaultValue: function () {
return null;
},
message: 'should be an array of strings',
validate: function (value) {
return value === null || __isArray_4(value) && __filter_4(value, function (f) {
return typeof f === 'string';
}).length === value.length;
}
},
releaseStage: {
defaultValue: function () {
return 'production';
},
message: 'should be a string',
validate: function (value) {
return typeof value === 'string' && value.length;
}
},
maxBreadcrumbs: {
defaultValue: function () {
return 20;
},
message: 'should be a number ≤40',
validate: function (value) {
return intRange(0, 40)(value);
}
},
autoBreadcrumbs: {
defaultValue: function () {
return true;
},
message: 'should be true|false',
validate: function (value) {
return typeof value === 'boolean';
}
},
user: {
defaultValue: function () {
return null;
},
message: '(object) user should be an object',
validate: function (value) {
return typeof value === 'object';
}
},
metaData: {
defaultValue: function () {
return null;
},
message: 'should be an object',
validate: function (value) {
return typeof value === 'object';
}
},
logger: {
defaultValue: function () {
return undefined;
},
message: 'should be null or an object with methods { debug, info, warn, error }',
validate: function (value) {
return !value || value && __reduce_4(['debug', 'info', 'warn', 'error'], function (accum, method) {
return accum && typeof value[method] === 'function';
}, true);
}
},
filters: {
defaultValue: function () {
return ['password'];
},
message: 'should be an array of strings|regexes',
validate: function (value) {
return __isArray_4(value) && value.length === __filter_4(value, function (s) {
return typeof s === 'string' || s && typeof s.test === 'function';
}).length;
}
}
};
_$config_4.mergeDefaults = function (opts, schema) {
if (!opts || !schema) throw new Error('opts and schema objects are required');
return __reduce_4(__keys_4(schema), function (accum, key) {
accum[key] = opts[key] !== undefined ? opts[key] : schema[key].defaultValue(opts[key], opts);
return accum;
}, {});
};
_$config_4.validate = function (opts, schema) {
if (!opts || !schema) throw new Error('opts and schema objects are required');
var errors = __reduce_4(__keys_4(schema), function (accum, key) {
if (schema[key].validate(opts[key], opts)) return accum;
return accum.concat({
key: key,
message: schema[key].message,
value: opts[key]
});
}, []);
return {
valid: !errors.length,
errors: errors
};
};
// This is a heavily modified/simplified version of
// https://github.com/othiym23/async-some
//
// We can't use that because:
// a) it inflates the bundle size to over 10kB
// b) it depends on a module that uses Object.keys()
// (which we can't use due to ie8 support)
// run the asynchronous test function (fn) over each item in the array (arr)
// in series until:
// - fn(item, cb) => calls cb(null, true)
// - or the end of the array is reached
// the callback (cb) will be passed true if any of the items resulted in a true
// callback, otherwise false
var _$asyncSome_5 = function (arr, fn, cb) {
var length = arr.length;
var index = 0;
var next = function () {
if (index >= length) return cb(null, false);
fn(arr[index], function (err, result) {
if (err) return cb(err, false);
if (result === true) return cb(null, true);
index++;
next();
});
};
next();
};
var _$inferReleaseStage_10 = function (client) {
return client.app && typeof client.app.releaseStage === 'string' ? client.app.releaseStage : client.config.releaseStage;
};
var _$iserror_11 = require("iserror");
var _$runBeforeSend_16 = function (report, onError) {
return function (fn, cb) {
if (typeof fn !== 'function') return cb(null, false);
try {
// if function appears sync…
if (fn.length !== 2) {
var ret = fn(report); // check if it returned a "thenable" (promise)
if (ret && typeof ret.then === 'function') {
return ret.then( // resolve
function (val) {
return setTimeout(function () {
return cb(null, shouldPreventSend(report, val));
}, 0);
}, // reject
function (err) {
setTimeout(function () {
onError(err);
return cb(null, false);
});
});
}
return cb(null, shouldPreventSend(report, ret));
} // if function is async…
fn(report, function (err, result) {
if (err) {
onError(err);
return cb(null, false);
}
cb(null, shouldPreventSend(report, result));
});
} catch (e) {
onError(e);
cb(null, false);
}
};
};
var shouldPreventSend = function (report, value) {
return report.isIgnored() || value === false;
};
var _$errorStackParser_7 = require("error-stack-parser");
// Given `err` which may be an error, does it have a stack property which is a string?
var _$hasStack_9 = function (err) {
return !!err && (!!err.stack || !!err.stacktrace || !!err['opera#sourceloc']) && typeof (err.stack || err.stacktrace || err['opera#sourceloc']) === 'string' && err.stack !== err.name + ": " + err.message;
};
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* removed: var _$errorStackParser_7 = require('./lib/error-stack-parser'); */;
var StackGenerator = require("stack-generator");
/* removed: var _$hasStack_9 = require('./lib/has-stack'); */;
var __reduce_22 = _$esUtils_8.reduce,
__filter_22 = _$esUtils_8.filter;
var BugsnagReport =
/*#__PURE__*/
function () {
function BugsnagReport(errorClass, errorMessage, stacktrace, handledState, originalError) {
if (stacktrace === void 0) {
stacktrace = [];
}
if (handledState === void 0) {
handledState = defaultHandledState();
}
// duck-typing ftw >_<
this.__isBugsnagReport = true;
this._ignored = false; // private (un)handled state
this._handledState = handledState; // setable props
this.app = undefined;
this.apiKey = undefined;
this.breadcrumbs = [];
this.context = undefined;
this.device = undefined;
this.errorClass = stringOrFallback(errorClass, '[no error class]');
this.errorMessage = stringOrFallback(errorMessage, '[no error message]');
this.groupingHash = undefined;
this.metaData = {};
this.request = undefined;
this.severity = this._handledState.severity;
this.stacktrace = __reduce_22(stacktrace, function (accum, frame) {
var f = formatStackframe(frame); // don't include a stackframe if none of its properties are defined
try {
if (JSON.stringify(f) === '{}') return accum;
return accum.concat(f);
} catch (e) {
return accum;
}
}, []);
this.user = undefined;
this.session = undefined;
this.originalError = originalError;
}
var _proto = BugsnagReport.prototype;
_proto.ignore = function ignore() {
this._ignored = true;
};
_proto.isIgnored = function isIgnored() {
return this._ignored;
};
_proto.updateMetaData = function updateMetaData(section) {
var _updates;
if (!section) return this;
var updates; // updateMetaData("section", null) -> removes section
if ((arguments.length <= 1 ? undefined : arguments[1]) === null) return this.removeMetaData(section); // updateMetaData("section", "property", null) -> removes property from section
if ((arguments.length <= 2 ? undefined : arguments[2]) === null) return this.removeMetaData(section, arguments.length <= 1 ? undefined : arguments[1], arguments.length <= 2 ? undefined : arguments[2]); // normalise the two supported input types into object form
if (typeof (arguments.length <= 1 ? undefined : arguments[1]) === 'object') updates = arguments.length <= 1 ? undefined : arguments[1];
if (typeof (arguments.length <= 1 ? undefined : arguments[1]) === 'string') updates = (_updates = {}, _updates[arguments.length <= 1 ? undefined : arguments[1]] = arguments.length <= 2 ? undefined : arguments[2], _updates); // exit if we don't have an updates object at this point
if (!updates) return this; // ensure a section with this name exists
if (!this.metaData[section]) this.metaData[section] = {}; // merge the updates with the existing section
this.metaData[section] = _extends({}, this.metaData[section], updates);
return this;
};
_proto.removeMetaData = function removeMetaData(section, property) {
if (typeof section !== 'string') return this; // remove an entire section
if (!property) {
delete this.metaData[section];
return this;
} // remove a single property from a section
if (this.metaData[section]) {
delete this.metaData[section][property];
return this;
}
return this;
};
_proto.toJSON = function toJSON() {
return {
payloadVersion: '4',
exceptions: [{
errorClass: this.errorClass,
message: this.errorMessage,
stacktrace: this.stacktrace,
type: process.env.IS_BROWSER ? 'browserjs' : 'nodejs'
}],
severity: this.severity,
unhandled: this._handledState.unhandled,
severityReason: this._handledState.severityReason,
app: this.app,
device: this.device,
breadcrumbs: this.breadcrumbs,
context: this.context,
user: this.user,
metaData: this.metaData,
groupingHash: this.groupingHash,
request: this.request,
session: this.session
};
};
return BugsnagReport;
}(); // takes a stacktrace.js style stackframe (https://github.com/stacktracejs/stackframe)
// and returns a Bugsnag compatible stackframe (https://docs.bugsnag.com/api/error-reporting/#json-payload)
var formatStackframe = function (frame) {
var f = {
file: frame.fileName,
method: normaliseFunctionName(frame.functionName),
lineNumber: frame.lineNumber,
columnNumber: frame.columnNumber,
code: undefined,
inProject: undefined // Some instances result in no file:
// - calling notify() from chrome's terminal results in no file/method.
// - non-error exception thrown from global code in FF
// This adds one.
};
if (f.lineNumber > -1 && !f.file && !f.method) {
f.file = 'global code';
}
return f;
};
var normaliseFunctionName = function (name) {
return /^global code$/i.test(name) ? 'global code' : name;
};
var defaultHandledState = function () {
return {
unhandled: false,
severity: 'warning',
severityReason: {
type: 'handledException'
}
};
};
var stringOrFallback = function (str, fallback) {
return typeof str === 'string' && str ? str : fallback;
}; // Helpers
BugsnagReport.getStacktrace = function (error, errorFramesToSkip, generatedFramesToSkip) {
if (errorFramesToSkip === void 0) {
errorFramesToSkip = 0;
}
if (generatedFramesToSkip === void 0) {
generatedFramesToSkip = 0;
}
if (_$hasStack_9(error)) return _$errorStackParser_7.parse(error).slice(errorFramesToSkip); // error wasn't provided or didn't have a stacktrace so try to walk the callstack
return __filter_22(StackGenerator.backtrace(), function (frame) {
return (frame.functionName || '').indexOf('StackGenerator$$') === -1;
}).slice(1 + generatedFramesToSkip);
};
BugsnagReport.ensureReport = function (reportOrError, errorFramesToSkip, generatedFramesToSkip) {
if (errorFramesToSkip === void 0) {
errorFramesToSkip = 0;
}
if (generatedFramesToSkip === void 0) {
generatedFramesToSkip = 0;
}
// notify() can be called with a Report object. In this case no action is required
if (reportOrError.__isBugsnagReport) return reportOrError;
try {
var stacktrace = BugsnagReport.getStacktrace(reportOrError, errorFramesToSkip, 1 + generatedFramesToSkip);
return new BugsnagReport(reportOrError.name, reportOrError.message, stacktrace, undefined, reportOrError);
} catch (e) {
return new BugsnagReport(reportOrError.name, reportOrError.message, [], undefined, reportOrError);
}
};
var _$BugsnagReport_22 = BugsnagReport;
var _$pad_20 = function pad(num, size) {
var s = '000000000' + num;
return s.substr(s.length - size);
};
/* removed: var _$pad_20 = require('./pad.js'); */;
var os = require("os"),
padding = 2,
pid = _$pad_20(process.pid.toString(36), padding),
hostname = os.hostname(),
length = hostname.length,
hostId = _$pad_20(hostname.split('').reduce(function (prev, char) {
return +prev + char.charCodeAt(0);
}, +length + 36).toString(36), padding);
var _$fingerprint_19 = function fingerprint() {
return pid + hostId;
};
/**
* cuid.js
* Collision-resistant UID generator for browsers and node.
* Sequential for fast db lookups and recency sorting.
* Safe for element IDs and server-side lookups.
*
* Extracted from CLCTR
*
* Copyright (c) Eric Elliott 2012
* MIT License
*/
/* removed: var _$fingerprint_19 = require('./lib/fingerprint.js'); */;
/* removed: var _$pad_20 = require('./lib/pad.js'); */;
var c = 0,
blockSize = 4,
base = 36,
discreteValues = Math.pow(base, blockSize);
function randomBlock() {
return _$pad_20((Math.random() * discreteValues << 0).toString(base), blockSize);
}
function safeCounter() {
c = c < discreteValues ? c : 0;
c++; // this is not subliminal
return c - 1;
}
function cuid() {
// Starting with a lowercase letter makes
// it HTML element ID friendly.
var letter = 'c',
// hard-coded allows for sequential access
// timestamp
// warning: this exposes the exact date and time
// that the uid was created.
timestamp = new Date().getTime().toString(base),
// Prevent same-machine collisions.
counter = _$pad_20(safeCounter().toString(base), blockSize),
// A few chars to generate distinct ids for different
// clients (so different computers are far less
// likely to generate the same id)
print = _$fingerprint_19(),
// Grab some more chars from Math.random()
random = randomBlock() + randomBlock();
return letter + timestamp + counter + print + random;
}
cuid.fingerprint = _$fingerprint_19;
var _$cuid_18 = cuid;
var __isoDate_23 = _$esUtils_8.isoDate;
/* removed: var _$cuid_18 = require('@bugsnag/cuid'); */;
var Session =
/*#__PURE__*/
function () {
function Session() {
this.id = _$cuid_18();
this.startedAt = __isoDate_23();
this._handled = 0;
this._unhandled = 0;
}
var _proto = Session.prototype;
_proto.toJSON = function toJSON() {
return {
id: this.id,
startedAt: this.startedAt,
events: {
handled: this._handled,
unhandled: this._unhandled
}
};
};
_proto.trackError = function trackError(report) {
this[report._handledState.unhandled ? '_unhandled' : '_handled'] += 1;
};
return Session;
}();
var _$Session_23 = Session;
function ___extends_3() { ___extends_3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return ___extends_3.apply(this, arguments); }
/* removed: var _$config_4 = require('./config'); */;
/* removed: var _$BugsnagReport_22 = require('./report'); */;
/* removed: var _$BugsnagBreadcrumb_2 = require('./breadcrumb'); */;
/* removed: var _$Session_23 = require('./session'); */;
var __map_3 = _$esUtils_8.map,
__includes_3 = _$esUtils_8.includes,
__isArray_3 = _$esUtils_8.isArray;
/* removed: var _$inferReleaseStage_10 = require('./lib/infer-release-stage'); */;
/* removed: var _$iserror_11 = require('./lib/iserror'); */;
/* removed: var _$asyncSome_5 = require('./lib/async-some'); */;
/* removed: var _$runBeforeSend_16 = require('./lib/run-before-send'); */;
var LOG_USAGE_ERR_PREFIX = "Usage error.";
var REPORT_USAGE_ERR_PREFIX = "Bugsnag usage error.";
var BugsnagClient =
/*#__PURE__*/
function () {
function BugsnagClient(notifier) {
if (!notifier || !notifier.name || !notifier.version || !notifier.url) {
throw new Error('`notifier` argument is required');
} // notifier id
this.notifier = notifier; // configure() should be called before notify()
this._configured = false; // intialise opts and config
this._opts = {};
this.config = {}; // // i/o
this._delivery = {
sendSession: function () {},
sendReport: function () {}
};
this._logger = {
debug: function () {},
info: function () {},
warn: function () {},
error: function () {} // plugins
};
this._plugins = {};
this._session = null;
this.breadcrumbs = []; // setable props
this.app = {};
this.context = undefined;
this.device = undefined;
this.metaData = undefined;
this.request = undefined;
this.user = {}; // expose internal constructors
this.BugsnagClient = BugsnagClient;
this.BugsnagReport = _$BugsnagReport_22;
this.BugsnagBreadcrumb = _$BugsnagBreadcrumb_2;
this.BugsnagSession = _$Session_23;
var self = this;
var notify = this.notify;
this.notify = function () {
return notify.apply(self, arguments);
};
}
var _proto = BugsnagClient.prototype;
_proto.setOptions = function setOptions(opts) {
this._opts = ___extends_3({}, this._opts, opts);
};
_proto.configure = function configure(partialSchema) {
if (partialSchema === void 0) {
partialSchema = _$config_4.schema;
}
var conf = _$config_4.mergeDefaults(this._opts, partialSchema);
var validity = _$config_4.validate(conf, partialSchema);
if (!validity.valid === true) throw new Error(generateConfigErrorMessage(validity.errors)); // update and elevate some special options if they were passed in at this point
if (typeof conf.beforeSend === 'function') conf.beforeSend = [conf.beforeSend];
if (conf.appVersion) this.app.version = conf.appVersion;
if (conf.appType) this.app.type = conf.appType;
if (conf.metaData) this.metaData = conf.metaData;
if (conf.user) this.user = conf.user;
if (conf.logger) this.logger(conf.logger); // merge with existing config
this.config = ___extends_3({}, this.config, conf);
this._configured = true;
return this;
};
_proto.use = function use(plugin) {
if (!this._configured) throw new Error('client not configured');
if (plugin.configSchema) this.configure(plugin.configSchema);
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var result = plugin.init.apply(plugin, [this].concat(args)); // JS objects are not the safest way to store arbitrarily keyed values,
// so bookend the key with some characters that prevent tampering with
// stuff like __proto__ etc. (only store the result if the plugin had a
// name)
if (plugin.name) this._plugins["~" + plugin.name + "~"] = result;
return this;
};
_proto.getPlugin = function getPlugin(name) {
return this._plugins["~" + name + "~"];
};
_proto.delivery = function delivery(d) {
this._delivery = d;
return this;
};
_proto.logger = function logger(l, sid) {
this._logger = l;
return this;
};
_proto.sessionDelegate = function sessionDelegate(s) {
this._sessionDelegate = s;
return this;
};
_proto.startSession = function startSession() {
if (!this._sessionDelegate) {
this._logger.warn('No session implementation is installed');
return this;
}
return this._sessionDelegate.startSession(this);
};
_proto.leaveBreadcrumb = function leaveBreadcrumb(name, metaData, type, timestamp) {
if (!this._configured) throw new Error('client not configured'); // coerce bad values so that the defaults get set
name = name || undefined;
type = typeof type === 'string' ? type : undefined;
timestamp = typeof timestamp === 'string' ? timestamp : undefined;
metaData = typeof metaData === 'object' && metaData !== null ? metaData : undefined; // if no name and no metaData, usefulness of this crumb is questionable at best so discard
if (typeof name !== 'string' && !metaData) return;
var crumb = new _$BugsnagBreadcrumb_2(name, metaData, type, timestamp); // push the valid crumb onto the queue and maintain the length
this.breadcrumbs.push(crumb);
if (this.breadcrumbs.length > this.config.maxBreadcrumbs) {
this.breadcrumbs = this.breadcrumbs.slice(this.breadcrumbs.length - this.config.maxBreadcrumbs);
}
return this;
};
_proto.notify = function notify(error, opts, cb) {
var _this = this;
if (opts === void 0) {
opts = {};
}
if (cb === void 0) {
cb = function () {};
}
if (!this._configured) throw new Error('client not configured'); // releaseStage can be set via config.releaseStage or client.app.releaseStage
var releaseStage = _$inferReleaseStage_10(this); // ensure we have an error (or a reasonable object representation of an error)
var _normaliseError = normaliseError(error, opts, this._logger),
err = _normaliseError.err,
errorFramesToSkip = _normaliseError.errorFramesToSkip,
_opts = _normaliseError._opts;
if (_opts) opts = _opts; // ensure opts is an object
if (typeof opts !== 'object' || opts === null) opts = {}; // create a report from the error, if it isn't one already
var report = _$BugsnagReport_22.ensureReport(err, errorFramesToSkip, 2);
report.app = ___extends_3({}, {
releaseStage: releaseStage
}, report.app, this.app);
report.context = report.context || opts.context || this.context || undefined;
report.device = ___extends_3({}, report.device, this.device, opts.device);
report.request = ___extends_3({}, report.request, this.request, opts.request);
report.user = ___extends_3({}, report.user, this.user, opts.user);
report.metaData = ___extends_3({}, report.metaData, this.metaData, opts.metaData);
report.breadcrumbs = this.breadcrumbs.slice(0);
if (this._session) {
this._session.trackError(report);
report.session = this._session;
} // set severity if supplied
if (opts.severity !== undefined) {
report.severity = opts.severity;
report._handledState.severityReason = {
type: 'userSpecifiedSeverity'
};
} // exit early if the reports should not be sent on the current releaseStage
if (__isArray_3(this.config.notifyReleaseStages) && !__includes_3(this.config.notifyReleaseStages, releaseStage)) {
this._logger.warn("Report not sent due to releaseStage/notifyReleaseStages configuration");
return cb(null, report);
}
var originalSeverity = report.severity;
var beforeSend = [].concat(opts.beforeSend).concat(this.config.beforeSend);
var onBeforeSendErr = function (err) {
_this._logger.error("Error occurred in beforeSend callback, continuing anyway\u2026");
_this._logger.error(err);
};
_$asyncSome_5(beforeSend, _$runBeforeSend_16(report, onBeforeSendErr), function (err, preventSend) {
if (err) onBeforeSendErr(err);
if (preventSend) {
_this._logger.debug("Report not sent due to beforeSend callback");
return cb(null, report);
} // only leave a crumb for the error if actually got sent
if (_this.config.autoBreadcrumbs) {
_this.leaveBreadcrumb(report.errorClass, {
errorClass: report.errorClass,
errorMessage: report.errorMessage,
severity: report.severity
}, 'error');
}
if (originalSeverity !== report.severity) {
report._handledState.severityReason = {
type: 'userCallbackSetSeverity'
};
}
_this._delivery.sendReport(_this._logger, _this.config, {
apiKey: report.apiKey || _this.config.apiKey,
notifier: _this.notifier,
events: [report]
}, function (err) {
return cb(err, report);
});
});
};
return BugsnagClient;
}();
var normaliseError = function (error, opts, logger) {
var synthesizedErrorFramesToSkip = 3;
var createAndLogUsageError = function (reason) {
var msg = generateNotifyUsageMessage(reason);
logger.warn(LOG_USAGE_ERR_PREFIX + " " + msg);
return new Error(REPORT_USAGE_ERR_PREFIX + " " + msg);
};
var err;
var errorFramesToSkip = 0;
var _opts;
switch (typeof error) {
case 'string':
if (typeof opts === 'string') {
// ≤v3 used to have a notify('ErrorName', 'Error message') interface
// report usage/deprecation errors if this function is called like that
err = createAndLogUsageError('string/string');
_opts = {
metaData: {
notifier: {
notifyArgs: [error, opts]
}
}
};
} else {
err = new Error(String(error));
errorFramesToSkip = synthesizedErrorFramesToSkip;
}
break;
case 'number':
case 'boolean':
err = new Error(String(error));
break;
case 'function':
err = createAndLogUsageError('function');
break;
case 'object':
if (error !== null && (_$iserror_11(error) || error.__isBugsnagReport)) {
err = error;
} else if (error !== null && hasNecessaryFields(error)) {
err = new Error(error.message || error.errorMessage);
err.name = error.name || error.errorClass;
errorFramesToSkip = synthesizedErrorFramesToSkip;
} else {
err = createAndLogUsageError(error === null ? 'null' : 'unsupported object');
}
break;
default:
err = createAndLogUsageError('nothing');
}
return {
err: err,
errorFramesToSkip: errorFramesToSkip,
_opts: _opts
};
};
var hasNecessaryFields = function (error) {
return (typeof error.name === 'string' || typeof error.errorClass === 'string') && (typeof error.message === 'string' || typeof error.errorMessage === 'string');
};
var generateConfigErrorMessage = function (errors) {
return "Bugsnag configuration error\n" + __map_3(errors, function (err) {
return "\"" + err.key + "\" " + err.message + " \n got " + stringify(err.value);
}).join('\n\n');
};
var generateNotifyUsageMessage = function (actual) {
return "notify() expected error/opts parameters, got " + actual;
};
var stringify = function (val) {
return typeof val === 'object' ? JSON.stringify(val) : String(val);
};
var _$BugsnagClient_3 = BugsnagClient;
var _$safeJsonStringify_21 = function (data, replacer, space, opts) {
var filterKeys = opts && opts.filterKeys ? opts.filterKeys : [];
var filterPaths = opts && opts.filterPaths ? opts.filterPaths : [];
return JSON.stringify(prepareObjForSerialization(data, filterKeys, filterPaths), replacer, space);
};
var MAX_DEPTH = 20;
var MAX_EDGES = 25000;
var MIN_PRESERVED_DEPTH = 8;
var REPLACEMENT_NODE = '...';
function __isError_21(o) {
return o instanceof Error || /^\[object (Error|(Dom)?Exception)\]$/.test(Object.prototype.toString.call(o));
}
function throwsMessage(err) {
return '[Throws: ' + (err ? err.message : '?') + ']';
}
function find(haystack, needle) {
for (var i = 0, len = haystack.length; i < len; i++) {
if (haystack[i] === needle) return true;
}
return false;
} // returns true if the string `path` starts with any of the provided `paths`
function isDescendent(paths, path) {
for (var i = 0, len = paths.length; i < len; i++) {
if (path.indexOf(paths[i]) === 0) return true;
}
return false;
}
function shouldFilter(patterns, key) {
for (var i = 0, len = patterns.length; i < len; i++) {
if (typeof patterns[i] === 'string' && patterns[i] === key) return true;
if (patterns[i] && typeof patterns[i].test === 'function' && patterns[i].test(key)) return true;
}
return false;
}
function __isArray_21(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
function safelyGetProp(obj, prop) {
try {
return obj[prop];
} catch (err) {
return throwsMessage(err);
}
}
function prepareObjForSerialization(obj, filterKeys, filterPaths) {
var seen = []; // store references to objects we have seen before
var edges = 0;
function visit(obj, path) {
function edgesExceeded() {
return path.length > MIN_PRESERVED_DEPTH && edges > MAX_EDGES;
}
edges++;
if (path.length > MAX_DEPTH) return REPLACEMENT_NODE;
if (edgesExceeded()) return REPLACEMENT_NODE;
if (obj === null || typeof obj !== 'object') return obj;
if (find(seen, obj)) return '[Circular]';
seen.push(obj);
if (typeof obj.toJSON === 'function') {
try {
// we're not going to count this as an edge because it
// replaces the value of the currently visited object
edges--;
var fResult = visit(obj.toJSON(), path);
seen.pop();
return fResult;
} catch (err) {
return throwsMessage(err);
}
}
var er = __isError_21(obj);
if (er) {
edges--;
var eResult = visit({
name: obj.name,
message: obj.message
}, path);
seen.pop();
return eResult;
}
if (__isArray_21(obj)) {
var aResult = [];
for (var i = 0, len = obj.length; i < len; i++) {
if (edgesExceeded()) {
aResult.push(REPLACEMENT_NODE);
break;
}
aResult.push(visit(obj[i], path.concat('[]')));
}
seen.pop();
return aResult;
}
var result = {};
try {
for (var prop in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, prop)) continue;
if (isDescendent(filterPaths, path.join('.')) && shouldFilter(filterKeys, prop)) {
result[prop] = '[Filtered]';
continue;
}
if (edgesExceeded()) {
result[prop] = REPLACEMENT_NODE;
break;
}
result[prop] = visit(safelyGetProp(obj, prop), path.concat(prop));
}
} catch (e) {}
seen.pop();
return result;
}
return visit(obj, []);
}
var _$jsonPayload_12 = {};
/* removed: var _$safeJsonStringify_21 = require('@bugsnag/safe-json-stringify'); */;
var REPORT_FILTER_PATHS = ['events.[].app', 'events.[].metaData', 'events.[].user', 'events.[].breadcrumbs', 'events.[].request', 'events.[].device'];
var SESSION_FILTER_PATHS = ['device', 'app', 'user'];
_$jsonPayload_12.report = function (report, filterKeys) {
var payload = _$safeJsonStringify_21(report, null, null, {
filterPaths: REPORT_FILTER_PATHS,
filterKeys: filterKeys
});
if (payload.length > 10e5) {
delete report.events[0].metaData;
report.events[0].metaData = {
notifier: "WARNING!\nSerialized payload was " + payload.length / 10e5 + "MB (limit = 1MB)\nmetaData was removed"
};
payload = _$safeJsonStringify_21(report, null, null, {
filterPaths: REPORT_FILTER_PATHS,
filterKeys: filterKeys
});
if (payload.length > 10e5) throw new Error('payload exceeded 1MB limit');
}
return payload;
};
_$jsonPayload_12.session = function (report, filterKeys) {
var payload = _$safeJsonStringify_21(report, null, null, {
filterPaths: SESSION_FILTER_PATHS,
filterKeys: filterKeys
});
if (payload.length > 10e5) throw new Error('payload exceeded 1MB limit');
return payload;
};
var http = require("http");
var https = require("https");
var ___require_25 = require("url"),
parse = ___require_25.parse;
var _$request_25 = function (_ref, cb) {
var url = _ref.url,
headers = _ref.headers,
body = _ref.body,
agent = _ref.agent;
var didError = false;
var onError = function (err) {
if (didError) return;
didError = true;
cb(err);
};
var parsedUrl = parse(url);
var secure = parsedUrl.protocol === 'https:';
var transport = secure ? https : http;
var req = transport.request({
method: 'POST',
hostname: parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.path,
headers: headers
});
req.on('error', onError);
req.on('response', function (res) {
bufferResponse(res, function (err, body) {
if (err) return onError(err);
if (res.statusCode < 200 || res.statusCode >= 300) {
return onError(new Error("Bad statusCode from API: " + res.statusCode + "\n" + body));
}
cb(null, body);
});
});
req.write(body);
req.end();
};
var bufferResponse = function (stream, cb) {
var data = '';
stream.on('error', cb);
stream.setEncoding('utf8');
stream.on('data', function (d) {
data += d;
});
stream.on('end', function () {
return cb(null, data);
});
};
/* removed: var _$jsonPayload_12 = require('@bugsnag/core/lib/json-payload'); */;
var __isoDate_24 = _$esUtils_8.isoDate;
/* removed: var _$request_25 = require('./request'); */;
var _$delivery_24 = function () {
return {
sendReport: function (logger, config, report, cb) {
if (cb === void 0) {
cb = function () {};
}
var _cb = function (err) {
if (err) logger.error("Report failed to send\u2026\n" + (err && err.stack ? err.stack : err), err);
cb(err);
};
try {
_$request_25({
url: config.endpoints.notify,
headers: {
'Content-Type': 'application/json',
'Bugsnag-Api-Key': report.apiKey || config.apiKey,
'Bugsnag-Payload-Version': '4',
'Bugsnag-Sent-At': __isoDate_24()
},
body: _$jsonPayload_12.report(report, config.filters),
agent: config.agent
}, function (err, body) {
return _cb(err);
});
} catch (e) {
_cb(e);
}
},
sendSession: function (logger, config, session, cb) {
if (cb === void 0) {
cb = function () {};
}
var _cb = function (err) {
if (err) logger.error("Session failed to send\u2026\n" + (err && err.stack ? err.stack : err), err);
cb(err);
};
try {
_$request_25({
url: config.endpoints.sessions,
headers: {
'Content-Type': 'application/json',
'Bugsnag-Api-Key': config.apiKey,
'Bugsnag-Payload-Version': '1',
'Bugsnag-Sent-At': __isoDate_24()
},
body: _$jsonPayload_12.session(session, config.filters),
agent: config.agent
}, function (err) {
return _cb(err);
});
} catch (e) {
_cb(e);
}
}
};
};
// for now just expose the builtin process global from node.js
var _$process_1 = global.process;
function ___extends_26() { ___extends_26 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return ___extends_26.apply(this, arguments); }
var schema = _$config_4.schema;
var __reduce_26 = _$esUtils_8.reduce;
var __stringWithLength_26 = _$validators_17.stringWithLength;
var __os_26 = require("os");
/* removed: var _$process_1 = require('process'); */;
var _$config_26 = {
projectRoot: {
defaultValue: function () {
return _$process_1.cwd();
},
validate: function (value) {
return value === null || __stringWithLength_26(value);
},
message: 'should be string'
},
hostname: {
defaultValue: function () {
return __os_26.hostname();
},
message: 'should be a string',
validate: function (value) {
return value === null || __stringWithLength_26(value);
}
},
logger: ___extends_26({}, schema.logger, {
defaultValue: function () {
return getPrefixedConsole();
}
}),
releaseStage: ___extends_26({}, schema.releaseStage, {
defaultValue: function () {
return _$process_1.env.NODE_ENV || 'production';
}
}),
agent: {
defaultValue: function () {
return undefined;
},
message: 'should be an HTTP(s) agent',
validate: function (value) {
return value === undefined || isAgent(value);
}
},
onUncaughtException: {
defaultValue: function () {
return function (err, report, logger) {
logger.error("Uncaught exception" + getContext(report) + ", the process will now terminate\u2026\n" + (err && err.stack ? err.stack : err));
_$process_1.exit(1);
};
},
message: 'should be a function',
validate: function (value) {
return typeof value === 'function';
}
},
onUnhandledRejection: {
defaultValue: function () {
return function (err, report, logger) {
logger.error("Unhandled rejection" + getContext(report) + "\u2026\n" + (err && err.stack ? err.stack : err));
};
},
message: 'should be a function',
validate: function (value) {
return typeof value === 'function';
}
}
};
var getPrefixedConsole = function () {
return __reduce_26(['debug', 'info', 'warn', 'error'], function (accum, method) {
var consoleMethod = console[method] || console.log;
accum[method] = consoleMethod.bind(console, '[bugsnag]');
return accum;
}, {});
};
var getContext = function (report) {
return report.request && Object.keys(report.request).length ? " at " + report.request.httpMethod + " " + (report.request.path || report.request.url) : "";
};
var isAgent = function (value) {
return typeof value === 'object' && value !== null || typeof value === 'boolean';
};
var _$nodeFallbackStack_13 = {};
// The utilities in this file are used to save the stackframes from a known execution context
// to use when a subsequent error has no stack frames. This happens with a lot of
// node's builtin async callbacks when they return from the native layer with no context
// for example:
//
// fs.readFile('does not exist', (err) => {
// /* node 8 */
// err.stack = "ENOENT: no such file or directory, open 'nope'"
// /* node 4,6 */
// err.stack = "Error: ENOENT: no such file or directory, open 'nope'\n at Error (native)"
// })
// Gets the stack string for the current execution context
_$nodeFallbackStack_13.getStack = function () {
// slice(3) removes the first line + this function's frame + the caller's frame,
// so the stack begins with the caller of this function
return new Error().stack.split('\n').slice(3).join('\n');
}; // Given an Error and a fallbackStack from getStack(), use the fallbackStack
// if error.stack has no genuine stackframes (according to the example above)
_$nodeFallbackStack_13.maybeUseFallbackStack = function (err, fallbackStack) {
var lines = err.stack.split('\n');
if (lines.length === 1 || lines.length === 2 && /at Error \(native\)/.test(lines[1])) {
err.stack = lines[0] + "\n" + fallbackStack;
}
return err;
};
/* removed: var _$BugsnagReport_22 = require('../report'); */;
/* removed: var _$iserror_11 = require('./iserror'); */;
var _$reportFromError_15 = function (maybeError, handledState) {
var actualError = _$iserror_11(maybeError) ? maybeError : new Error('Handled a non-error. See "error" tab for more detail.');
var report = new _$BugsnagReport_22(actualError.name, actualError.message, _$BugsnagReport_22.getStacktrace(actualError), handledState, maybeError);
if (maybeError !== actualError) report.updateMetaData('error', 'non-error value', String(maybeError));
return report;
};
/* eslint node/no-deprecated-api: [error, {ignoreModuleItems: ["domain"]}] */
var domain = require("domain");
/* removed: var _$reportFromError_15 = require('@bugsnag/core/lib/report-from-error'); */;
var getStack = _$nodeFallbackStack_13.getStack,
maybeUseFallbackStack = _$nodeFallbackStack_13.maybeUseFallbackStack;
var _$contextualize_28 = {
name: 'contextualize',
init: function (client) {
var contextualize = function (fn, opts) {
// capture a stacktrace in case a resulting error has nothing
var fallbackStack = getStack();
var dom = domain.create();
dom.on('error', function (err) {
// check if the stacktrace has no context, if so, if so append the frames we created earlier
if (err.stack) maybeUseFallbackStack(err, fallbackStack);
var report = _$reportFromError_15(err, {
severity: 'error',
unhandled: true,
severityReason: {
type: 'unhandledException'
}
});
client.notify(report, opts, function (e, report) {
if (e) client._logger.error('Failed to send report to Bugsnag');
client.config.onUncaughtException(err, report, client._logger);
});
});
process.nextTick(function () {
return dom.run(fn);
});
};
return contextualize;
}
};
/* removed: var _$reportFromError_15 = require('@bugsnag/core/lib/report-from-error'); */;
var __getStack_29 = _$nodeFallbackStack_13.getStack,
__maybeUseFallbackStack_29 = _$nodeFallbackStack_13.maybeUseFallbackStack;
var _$intercept_29 = {
name: 'intercept',
init: function (client) {
var intercept = function (opts, cb) {
if (cb === void 0) {
cb = function () {};
}
if (typeof opts === 'function') {
cb = opts;
opts = {};
} // capture a stacktrace in case a resulting error has nothing
var fallbackStack = __getStack_29();
return function (err) {
if (err) {
// check if the stacktrace has no context, if so, if so append the frames we created earlier
if (err.stack) __maybeUseFallbackStack_29(err, fallbackStack);
var report = _$reportFromError_15(err, {
severity: 'warning',
unhandled: false,
severityReason: {
type: 'callbackErrorIntercept'
}
});
client.notify(report, opts);
return;
}
for (var _len = arguments.length, data = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
data[_key - 1] = arguments[_key];
}
cb.apply(void 0, data); // eslint-disable-line
};
};
return intercept;
}
};
function ___extends_30() { ___extends_30 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return ___extends_30.apply(this, arguments); }
var __isoDate_30 = _$esUtils_8.isoDate;
/*
* Automatically detects browser device details
*/
var _$device_30 = {
init: function (client) {
var device = {
hostname: client.config.hostname // merge with anything already set on the client
};
client.device = ___e