@bugsnag/node
Version:
Bugsnag error reporter for Node.js
1,492 lines (1,425 loc) • 92.6 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;
var Breadcrumb = /*#__PURE__*/function () {
function Breadcrumb(message, metadata, type, timestamp) {
if (timestamp === void 0) {
timestamp = new Date();
}
this.type = type;
this.message = message;
this.metadata = metadata;
this.timestamp = timestamp;
}
var _proto = Breadcrumb.prototype;
_proto.toJSON = function toJSON() {
return {
type: this.type,
name: this.message,
timestamp: this.timestamp,
metaData: this.metadata
};
};
return Breadcrumb;
}();
var _$Breadcrumb_7 = Breadcrumb;
var _$breadcrumbTypes_12 = ['navigation', 'request', 'process', 'log', 'user', 'state', 'error', 'manual'];
// Array#reduce
var _$reduce_22 = 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;
};
/* removed: var _$reduce_22 = require('./reduce'); */;
// Array#filter
var _$filter_17 = function (arr, fn) {
return _$reduce_22(arr, function (accum, item, i, arr) {
return !fn(item, i, arr) ? accum : accum.concat(item);
}, []);
};
/* removed: var _$reduce_22 = require('./reduce'); */;
// Array#includes
var _$includes_18 = function (arr, x) {
return _$reduce_22(arr, function (accum, item, i, arr) {
return accum === true || item === x;
}, false);
};
// Array#isArray
var _$isArray_19 = function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
};
/* eslint-disable-next-line no-prototype-builtins */
var _hasDontEnumBug = !{
toString: null
}.propertyIsEnumerable('toString');
var _dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
// Object#keys
var _$keys_20 = 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;
};
var _$intRange_31 = 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;
};
};
/* removed: var _$filter_17 = require('../es-utils/filter'); */;
/* removed: var _$isArray_19 = require('../es-utils/is-array'); */;
var _$listOfFunctions_32 = function (value) {
return typeof value === 'function' || _$isArray_19(value) && _$filter_17(value, function (f) {
return typeof f === 'function';
}).length === value.length;
};
var _$stringWithLength_33 = function (value) {
return typeof value === 'string' && !!value.length;
};
var _$config_9 = {};
/* removed: var _$filter_17 = require('./lib/es-utils/filter'); */;
/* removed: var _$reduce_22 = require('./lib/es-utils/reduce'); */;
/* removed: var _$keys_20 = require('./lib/es-utils/keys'); */;
/* removed: var _$isArray_19 = require('./lib/es-utils/is-array'); */;
/* removed: var _$includes_18 = require('./lib/es-utils/includes'); */;
/* removed: var _$intRange_31 = require('./lib/validators/int-range'); */;
/* removed: var _$stringWithLength_33 = require('./lib/validators/string-with-length'); */;
/* removed: var _$listOfFunctions_32 = require('./lib/validators/list-of-functions'); */;
/* removed: var _$breadcrumbTypes_12 = require('./lib/breadcrumb-types'); */;
var defaultErrorTypes = function () {
return {
unhandledExceptions: true,
unhandledRejections: true
};
};
_$config_9.schema = {
apiKey: {
defaultValue: function () {
return null;
},
message: 'is required',
validate: _$stringWithLength_33
},
appVersion: {
defaultValue: function () {
return undefined;
},
message: 'should be a string',
validate: function (value) {
return value === undefined || _$stringWithLength_33(value);
}
},
appType: {
defaultValue: function () {
return undefined;
},
message: 'should be a string',
validate: function (value) {
return value === undefined || _$stringWithLength_33(value);
}
},
autoDetectErrors: {
defaultValue: function () {
return true;
},
message: 'should be true|false',
validate: function (value) {
return value === true || value === false;
}
},
enabledErrorTypes: {
defaultValue: function () {
return defaultErrorTypes();
},
message: 'should be an object containing the flags { unhandledExceptions:true|false, unhandledRejections:true|false }',
allowPartialObject: true,
validate: function (value) {
// ensure we have an object
if (typeof value !== 'object' || !value) return false;
var providedKeys = _$keys_20(value);
var defaultKeys = _$keys_20(defaultErrorTypes());
// ensure it only has a subset of the allowed keys
if (_$filter_17(providedKeys, function (k) {
return _$includes_18(defaultKeys, k);
}).length < providedKeys.length) return false;
// ensure all of the values are boolean
if (_$filter_17(_$keys_20(value), function (k) {
return typeof value[k] !== 'boolean';
}).length > 0) return false;
return true;
}
},
onError: {
defaultValue: function () {
return [];
},
message: 'should be a function or array of functions',
validate: _$listOfFunctions_32
},
onSession: {
defaultValue: function () {
return [];
},
message: 'should be a function or array of functions',
validate: _$listOfFunctions_32
},
onBreadcrumb: {
defaultValue: function () {
return [];
},
message: 'should be a function or array of functions',
validate: _$listOfFunctions_32
},
endpoints: {
defaultValue: function (endpoints) {
// only apply the default value if no endpoints have been provided, otherwise prevent delivery by setting to null
if (typeof endpoints === 'undefined') {
return {
notify: 'https://notify.bugsnag.com',
sessions: 'https://sessions.bugsnag.com'
};
} else {
return {
notify: null,
sessions: null
};
}
},
message: 'should be an object containing endpoint URLs { notify, sessions }',
validate: function (val) {
return (
// first, ensure it's an object
val && typeof val === 'object' &&
// notify and sessions must always be set
_$stringWithLength_33(val.notify) && _$stringWithLength_33(val.sessions) &&
// ensure no keys other than notify/session are set on endpoints object
_$filter_17(_$keys_20(val), function (k) {
return !_$includes_18(['notify', 'sessions'], k);
}).length === 0
);
}
},
autoTrackSessions: {
defaultValue: function (val) {
return true;
},
message: 'should be true|false',
validate: function (val) {
return val === true || val === false;
}
},
enabledReleaseStages: {
defaultValue: function () {
return null;
},
message: 'should be an array of strings',
validate: function (value) {
return value === null || _$isArray_19(value) && _$filter_17(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 25;
},
message: 'should be a number ≤100',
validate: function (value) {
return _$intRange_31(0, 100)(value);
}
},
enabledBreadcrumbTypes: {
defaultValue: function () {
return _$breadcrumbTypes_12;
},
message: "should be null or a list of available breadcrumb types (" + _$breadcrumbTypes_12.join(',') + ")",
validate: function (value) {
return value === null || _$isArray_19(value) && _$reduce_22(value, function (accum, maybeType) {
if (accum === false) return accum;
return _$includes_18(_$breadcrumbTypes_12, maybeType);
}, true);
}
},
context: {
defaultValue: function () {
return undefined;
},
message: 'should be a string',
validate: function (value) {
return value === undefined || typeof value === 'string';
}
},
user: {
defaultValue: function () {
return {};
},
message: 'should be an object with { id, email, name } properties',
validate: function (value) {
return value === null || value && _$reduce_22(_$keys_20(value), function (accum, key) {
return accum && _$includes_18(['id', 'email', 'name'], key);
}, true);
}
},
metadata: {
defaultValue: function () {
return {};
},
message: 'should be an object',
validate: function (value) {
return typeof value === 'object' && value !== null;
}
},
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_22(['debug', 'info', 'warn', 'error'], function (accum, method) {
return accum && typeof value[method] === 'function';
}, true);
}
},
redactedKeys: {
defaultValue: function () {
return ['password'];
},
message: 'should be an array of strings|regexes',
validate: function (value) {
return _$isArray_19(value) && value.length === _$filter_17(value, function (s) {
return typeof s === 'string' || s && typeof s.test === 'function';
}).length;
}
},
plugins: {
defaultValue: function () {
return [];
},
message: 'should be an array of plugin objects',
validate: function (value) {
return _$isArray_19(value) && value.length === _$filter_17(value, function (p) {
return p && typeof p === 'object' && typeof p.load === 'function';
}).length;
}
},
featureFlags: {
defaultValue: function () {
return [];
},
message: 'should be an array of objects that have a "name" property',
validate: function (value) {
return _$isArray_19(value) && value.length === _$filter_17(value, function (feature) {
return feature && typeof feature === 'object' && typeof feature.name === 'string';
}).length;
}
},
reportUnhandledPromiseRejectionsAsHandled: {
defaultValue: function () {
return false;
},
message: 'should be true|false',
validate: function (value) {
return value === true || value === false;
}
},
sendPayloadChecksums: {
defaultValue: function () {
return false;
},
message: 'should be true|false',
validate: function (value) {
return value === true || value === false;
}
}
};
var _$errorStackParser_15 = require("error-stack-parser");
// extends helper from babel
// https://github.com/babel/babel/blob/916429b516e6466fd06588ee820e40e025d7f3a3/packages/babel-helpers/src/helpers.js#L377-L393
var _$assign_16 = 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;
};
/* removed: var _$reduce_22 = require('./reduce'); */;
// Array#map
var _$map_21 = function (arr, fn) {
return _$reduce_22(arr, function (accum, item, i, arr) {
return accum.concat(fn(item, i, arr));
}, []);
};
var _$safeJsonStringify_5 = function (data, replacer, space, opts) {
var redactedKeys = opts && opts.redactedKeys ? opts.redactedKeys : [];
var redactedPaths = opts && opts.redactedPaths ? opts.redactedPaths : [];
return JSON.stringify(prepareObjForSerialization(data, redactedKeys, redactedPaths), replacer, space);
};
var MAX_DEPTH = 20;
var MAX_EDGES = 25000;
var MIN_PRESERVED_DEPTH = 8;
var REPLACEMENT_NODE = '...';
function isError(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 shouldRedact(patterns, key) {
for (var i = 0, len = patterns.length; i < len; i++) {
if (typeof patterns[i] === 'string' && patterns[i].toLowerCase() === key.toLowerCase()) return true;
if (patterns[i] && typeof patterns[i].test === 'function' && patterns[i].test(key)) return true;
}
return false;
}
function __isArray_5(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, redactedKeys, redactedPaths) {
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(obj);
if (er) {
edges--;
var eResult = visit({
name: obj.name,
message: obj.message
}, path);
seen.pop();
return eResult;
}
if (__isArray_5(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(redactedPaths, path.join('.')) && shouldRedact(redactedKeys, prop)) {
result[prop] = '[REDACTED]';
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, []);
}
/* removed: var _$map_21 = require('./es-utils/map'); */;
/* removed: var _$filter_17 = require('./es-utils/filter'); */;
/* removed: var _$isArray_19 = require('./es-utils/is-array'); */;
/* removed: var _$safeJsonStringify_5 = require('@bugsnag/safe-json-stringify'); */;
function add(existingFeatures, existingFeatureKeys, name, variant) {
if (typeof name !== 'string') {
return;
}
if (variant === undefined) {
variant = null;
} else if (variant !== null && typeof variant !== 'string') {
variant = _$safeJsonStringify_5(variant);
}
var existingIndex = existingFeatureKeys[name];
if (typeof existingIndex === 'number') {
existingFeatures[existingIndex] = {
name: name,
variant: variant
};
return;
}
existingFeatures.push({
name: name,
variant: variant
});
existingFeatureKeys[name] = existingFeatures.length - 1;
}
function merge(existingFeatures, newFeatures, existingFeatureKeys) {
if (!_$isArray_19(newFeatures)) {
return;
}
for (var i = 0; i < newFeatures.length; ++i) {
var feature = newFeatures[i];
if (feature === null || typeof feature !== 'object') {
continue;
}
// 'add' will handle if 'name' doesn't exist & 'variant' is optional
add(existingFeatures, existingFeatureKeys, feature.name, feature.variant);
}
return existingFeatures;
}
// convert feature flags from a map of 'name -> variant' into the format required
// by the Bugsnag Event API:
// [{ featureFlag: 'name', variant: 'variant' }, { featureFlag: 'name 2' }]
function toEventApi(featureFlags) {
return _$map_21(_$filter_17(featureFlags, Boolean), function (_ref) {
var name = _ref.name,
variant = _ref.variant;
var flag = {
featureFlag: name
};
// don't add a 'variant' property unless there's actually a value
if (typeof variant === 'string') {
flag.variant = variant;
}
return flag;
});
}
function clear(features, featuresIndex, name) {
var existingIndex = featuresIndex[name];
if (typeof existingIndex === 'number') {
features[existingIndex] = null;
delete featuresIndex[name];
}
}
var _$featureFlagDelegate_23 = {
add: add,
clear: clear,
merge: merge,
toEventApi: toEventApi
};
// Given `err` which may be an error, does it have a stack property which is a string?
var _$hasStack_24 = 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;
};
var _$iserror_25 = require("iserror");
/* removed: var _$assign_16 = require('./es-utils/assign'); */;
var __add_27 = function (state, section, keyOrObj, maybeVal) {
var _updates;
if (!section) return;
var updates;
// addMetadata("section", null) -> clears section
if (keyOrObj === null) return __clear_27(state, section);
// normalise the two supported input types into object form
if (typeof keyOrObj === 'object') updates = keyOrObj;
if (typeof keyOrObj === 'string') updates = (_updates = {}, _updates[keyOrObj] = maybeVal, _updates);
// exit if we don't have an updates object at this point
if (!updates) return;
// preventing the __proto__ property from being used as a key
if (section === '__proto__' || section === 'constructor' || section === 'prototype') {
return;
}
// ensure a section with this name exists
if (!state[section]) state[section] = {};
// merge the updates with the existing section
state[section] = _$assign_16({}, state[section], updates);
};
var get = function (state, section, key) {
if (typeof section !== 'string') return undefined;
if (!key) {
return state[section];
}
if (state[section]) {
return state[section][key];
}
return undefined;
};
var __clear_27 = function (state, section, key) {
if (typeof section !== 'string') return;
// clear an entire section
if (!key) {
delete state[section];
return;
}
// preventing the __proto__ property from being used as a key
if (section === '__proto__' || section === 'constructor' || section === 'prototype') {
return;
}
// clear a single value from a section
if (state[section]) {
delete state[section][key];
}
};
var _$metadataDelegate_27 = {
add: __add_27,
get: get,
clear: __clear_27
};
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
/* removed: var _$errorStackParser_15 = require('./lib/error-stack-parser'); */;
var StackGenerator = require("stack-generator");
/* removed: var _$hasStack_24 = require('./lib/has-stack'); */;
/* removed: var _$map_21 = require('./lib/es-utils/map'); */;
/* removed: var _$reduce_22 = require('./lib/es-utils/reduce'); */;
/* removed: var _$filter_17 = require('./lib/es-utils/filter'); */;
/* removed: var _$assign_16 = require('./lib/es-utils/assign'); */;
/* removed: var _$metadataDelegate_27 = require('./lib/metadata-delegate'); */;
/* removed: var _$featureFlagDelegate_23 = require('./lib/feature-flag-delegate'); */;
/* removed: var _$iserror_25 = require('./lib/iserror'); */;
var Event = /*#__PURE__*/function () {
function Event(errorClass, errorMessage, stacktrace, handledState, originalError) {
if (stacktrace === void 0) {
stacktrace = [];
}
if (handledState === void 0) {
handledState = defaultHandledState();
}
this.apiKey = undefined;
this.context = undefined;
this.groupingHash = undefined;
this.originalError = originalError;
this._handledState = handledState;
this.severity = this._handledState.severity;
this.unhandled = this._handledState.unhandled;
this.app = {};
this.device = {};
this.request = {};
this.response = {};
this.breadcrumbs = [];
this.threads = [];
this._metadata = {};
this._features = [];
this._featuresIndex = {};
this._user = {};
this._session = undefined;
this._correlation = undefined;
this._groupingDiscriminator = undefined;
this.errors = [createBugsnagError(errorClass, errorMessage, Event.__type, stacktrace)];
// Flags.
// Note these are not initialised unless they are used
// to save unnecessary bytes in the browser bundle
/* this.attemptImmediateDelivery, default: true */
}
var _proto = Event.prototype;
_proto.addMetadata = function addMetadata(section, keyOrObj, maybeVal) {
return _$metadataDelegate_27.add(this._metadata, section, keyOrObj, maybeVal);
}
/**
* Associate this event with a specific trace. This is usually done automatically when
* using bugsnag-js-performance, but can also be set manually if required.
*
* @param traceId the ID of the trace the event occurred within
* @param spanId the ID of the span that the event occurred within
*/;
_proto.setTraceCorrelation = function setTraceCorrelation(traceId, spanId) {
if (typeof traceId === 'string') {
this._correlation = _extends({
traceId: traceId
}, typeof spanId === 'string' ? {
spanId: spanId
} : {});
}
};
_proto.getGroupingDiscriminator = function getGroupingDiscriminator() {
return this._groupingDiscriminator;
};
_proto.setGroupingDiscriminator = function setGroupingDiscriminator(value) {
var previousValue = this._groupingDiscriminator;
if (typeof value === 'string' || value === null || value === undefined) this._groupingDiscriminator = value;
return previousValue;
};
_proto.getMetadata = function getMetadata(section, key) {
return _$metadataDelegate_27.get(this._metadata, section, key);
};
_proto.clearMetadata = function clearMetadata(section, key) {
return _$metadataDelegate_27.clear(this._metadata, section, key);
};
_proto.addFeatureFlag = function addFeatureFlag(name, variant) {
if (variant === void 0) {
variant = null;
}
_$featureFlagDelegate_23.add(this._features, this._featuresIndex, name, variant);
};
_proto.addFeatureFlags = function addFeatureFlags(featureFlags) {
_$featureFlagDelegate_23.merge(this._features, featureFlags, this._featuresIndex);
};
_proto.getFeatureFlags = function getFeatureFlags() {
return _$featureFlagDelegate_23.toEventApi(this._features);
};
_proto.clearFeatureFlag = function clearFeatureFlag(name) {
_$featureFlagDelegate_23.clear(this._features, this._featuresIndex, name);
};
_proto.clearFeatureFlags = function clearFeatureFlags() {
this._features = [];
this._featuresIndex = {};
};
_proto.getUser = function getUser() {
return this._user;
};
_proto.setUser = function setUser(id, email, name) {
this._user = {
id: id,
email: email,
name: name
};
};
_proto.toJSON = function toJSON() {
return {
payloadVersion: '4',
exceptions: _$map_21(this.errors, function (er) {
return _$assign_16({}, er, {
message: er.errorMessage
});
}),
severity: this.severity,
unhandled: this._handledState.unhandled,
severityReason: this._handledState.severityReason,
app: this.app,
device: this.device,
request: this.request,
response: this.response,
breadcrumbs: this.breadcrumbs,
context: this.context,
groupingHash: this.groupingHash,
groupingDiscriminator: this._groupingDiscriminator,
metaData: this._metadata,
user: this._user,
session: this._session,
featureFlags: this.getFeatureFlags(),
correlation: this._correlation
};
};
return Event;
}(); // 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 ensureString = function (str) {
return typeof str === 'string' ? str : '';
};
function createBugsnagError(errorClass, errorMessage, type, stacktrace) {
return {
errorClass: ensureString(errorClass),
errorMessage: ensureString(errorMessage),
type: type,
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;
}
}, [])
};
}
function getCauseStack(error) {
if (error.cause) {
return [error].concat(getCauseStack(error.cause));
} else {
return [error];
}
}
// Helpers
Event.getStacktrace = function (error, errorFramesToSkip, backtraceFramesToSkip) {
if (_$hasStack_24(error)) return _$errorStackParser_15.parse(error).slice(errorFramesToSkip);
// error wasn't provided or didn't have a stacktrace so try to walk the callstack
try {
return _$filter_17(StackGenerator.backtrace(), function (frame) {
return (frame.functionName || '').indexOf('StackGenerator$$') === -1;
}).slice(1 + backtraceFramesToSkip);
} catch (e) {
return [];
}
};
Event.create = function (maybeError, tolerateNonErrors, handledState, component, errorFramesToSkip, logger) {
if (errorFramesToSkip === void 0) {
errorFramesToSkip = 0;
}
var _normaliseError = normaliseError(maybeError, tolerateNonErrors, component, logger),
error = _normaliseError[0],
internalFrames = _normaliseError[1];
var event;
try {
var stacktrace = Event.getStacktrace(error,
// if an error was created/throw in the normaliseError() function, we need to
// tell the getStacktrace() function to skip the number of frames we know will
// be from our own functions. This is added to the number of frames deep we
// were told about
internalFrames > 0 ? 1 + internalFrames + errorFramesToSkip : 0,
// if there's no stacktrace, the callstack may be walked to generated one.
// this is how many frames should be removed because they come from our library
1 + errorFramesToSkip);
event = new Event(error.name, error.message, stacktrace, handledState, maybeError);
} catch (e) {
event = new Event(error.name, error.message, [], handledState, maybeError);
}
if (error.name === 'InvalidError') {
event.addMetadata("" + component, 'non-error parameter', makeSerialisable(maybeError));
}
if (error.cause) {
var _event$errors;
var causes = getCauseStack(error).slice(1);
var normalisedCauses = _$map_21(causes, function (cause) {
// Only get stacktrace for error causes that are a valid JS Error and already have a stack
var stacktrace = _$iserror_25(cause) && _$hasStack_24(cause) ? _$errorStackParser_15.parse(cause) : [];
var _normaliseError2 = normaliseError(cause, true, 'error cause'),
error = _normaliseError2[0];
if (error.name === 'InvalidError') event.addMetadata('error cause', makeSerialisable(cause));
return createBugsnagError(error.name, error.message, Event.__type, stacktrace);
});
(_event$errors = event.errors).push.apply(_event$errors, normalisedCauses);
}
return event;
};
var makeSerialisable = function (err) {
if (err === null) return 'null';
if (err === undefined) return 'undefined';
return err;
};
var normaliseError = function (maybeError, tolerateNonErrors, component, logger) {
var error;
var internalFrames = 0;
var createAndLogInputError = function (reason) {
var verb = component === 'error cause' ? 'was' : 'received';
if (logger) logger.warn(component + " " + verb + " a non-error: \"" + reason + "\"");
var err = new Error(component + " " + verb + " a non-error. See \"" + component + "\" tab for more detail.");
err.name = 'InvalidError';
return err;
};
// In some cases:
//
// - the promise rejection handler (both in the browser and node)
// - the node uncaughtException handler
//
// We are really limited in what we can do to get a stacktrace. So we use the
// tolerateNonErrors option to ensure that the resulting error communicates as
// such.
if (!tolerateNonErrors) {
if (_$iserror_25(maybeError)) {
error = maybeError;
} else {
error = createAndLogInputError(typeof maybeError);
internalFrames += 2;
}
} else {
switch (typeof maybeError) {
case 'string':
case 'number':
case 'boolean':
error = new Error(String(maybeError));
internalFrames += 1;
break;
case 'function':
error = createAndLogInputError('function');
internalFrames += 2;
break;
case 'object':
if (maybeError !== null && _$iserror_25(maybeError)) {
error = maybeError;
} else if (maybeError !== null && hasNecessaryFields(maybeError)) {
error = new Error(maybeError.message || maybeError.errorMessage);
error.name = maybeError.name || maybeError.errorClass;
internalFrames += 1;
} else {
error = createAndLogInputError(maybeError === null ? 'null' : 'unsupported object');
internalFrames += 2;
}
break;
default:
error = createAndLogInputError('nothing');
internalFrames += 2;
}
}
if (!_$hasStack_24(error)) {
// in IE10/11 a new Error() doesn't have a stacktrace until you throw it, so try that here
try {
throw error;
} catch (e) {
if (_$hasStack_24(e)) {
error = e;
// if the error only got a stacktrace after we threw it here, we know it
// will only have one extra internal frame from this function, regardless
// of whether it went through createAndLogInputError() or not
internalFrames = 1;
}
}
}
return [error, internalFrames];
};
// default value for stacktrace.type
Event.__type = 'browserjs';
var hasNecessaryFields = function (error) {
return (typeof error.name === 'string' || typeof error.errorClass === 'string') && (typeof error.message === 'string' || typeof error.errorMessage === 'string');
};
var _$Event_10 = Event;
// This is a heavily modified/simplified version of
// https://github.com/othiym23/async-some
// with the logic flipped so that it is akin to the
// synchronous "every" method instead of "some".
// run the asynchronous test function (fn) over each item in the array (arr)
// in series until:
// - fn(item, cb) => calls cb(null, false)
// - or the end of the array is reached
// the callback (cb) will be passed (null, false) if any of the items in arr
// caused fn to call back with false, otherwise it will be passed (null, true)
var _$asyncEvery_11 = function (arr, fn, cb) {
var index = 0;
var next = function () {
if (index >= arr.length) return cb(null, true);
fn(arr[index], function (err, result) {
if (err) return cb(err);
if (result === false) return cb(null, false);
index++;
next();
});
};
next();
};
/* removed: var _$asyncEvery_11 = require('./async-every'); */;
var _$callbackRunner_13 = function (callbacks, event, onCallbackError, cb) {
// This function is how we support different kinds of callback:
// - synchronous - return value
// - node-style async with callback - cb(err, value)
// - promise/thenable - resolve(value)
// It normalises each of these into the lowest common denominator – a node-style callback
var runMaybeAsyncCallback = function (fn, cb) {
if (typeof fn !== 'function') return cb(null);
try {
// if function appears sync…
if (fn.length !== 2) {
var ret = fn(event);
// 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, val);
});
},
// reject
function (err) {
setTimeout(function () {
onCallbackError(err);
return cb(null, true);
});
});
}
return cb(null, ret);
}
// if function is async…
fn(event, function (err, result) {
if (err) {
onCallbackError(err);
return cb(null);
}
cb(null, result);
});
} catch (e) {
onCallbackError(e);
cb(null);
}
};
_$asyncEvery_11(callbacks, runMaybeAsyncCallback, cb);
};
var _$syncCallbackRunner_30 = function (callbacks, callbackArg, callbackType, logger) {
var ignore = false;
var cbs = callbacks.slice();
while (!ignore) {
if (!cbs.length) break;
try {
ignore = cbs.pop()(callbackArg) === false;
} catch (e) {
logger.error("Error occurred in " + callbackType + " callback, continuing anyway\u2026");
logger.error(e);
}
}
return ignore;
};
var _$pad_4 = function pad(num, size) {
var s = '000000000' + num;
return s.substr(s.length - size);
};
/* removed: var _$pad_4 = require('./pad.js'); */;
var os = require("os");
function getHostname() {
try {
return os.hostname();
} catch (e) {
/**
* This is most likely Windows 7 which is known to cause os.hostname() to break
* @see https://github.com/nodejs/node/issues/41297
* @see https://github.com/libuv/libuv/issues/3260
*
* Fallback to take hostname from environment variables
* @see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/hostname#notes
*/
// eslint-disable-next-line no-underscore-dangle
return process.env._CLUSTER_NETWORK_NAME_ || process.env.COMPUTERNAME || 'hostname';
}
}
var padding = 2,
pid = _$pad_4(process.pid.toString(36), padding),
hostname = getHostname(),
length = hostname.length,
hostId = _$pad_4(hostname.split('').reduce(function (prev, char) {
return +prev + char.charCodeAt(0);
}, +length + 36).toString(36), padding);
var _$fingerprint_2 = function fingerprint() {
return pid + hostId;
};
/**
* Check the provided value is a valid device id
* @param {unknown} value
* @returns
*/
var _$isCuid_3 = function isCuid(value) {
return typeof value === 'string' && /^c[a-z0-9]{20,32}$/.test(value);
};
/**
* 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_2 = require('./lib/fingerprint.js'); */;
/* removed: var _$isCuid_3 = require('./lib/is-cuid.js'); */;
/* removed: var _$pad_4 = require('./lib/pad.js'); */;
var c = 0,
blockSize = 4,
base = 36,
discreteValues = Math.pow(base, blockSize);
function randomBlock() {
return _$pad_4((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_4(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_2(),
// Grab some more chars from Math.random()
random = randomBlock() + randomBlock();
return letter + timestamp + counter + print + random;
}
cuid.fingerprint = _$fingerprint_2;
cuid.isCuid = _$isCuid_3;
var _$cuid_1 = cuid;
/* removed: var _$cuid_1 = require('@bugsnag/cuid'); */;
var Session = /*#__PURE__*/function () {
function Session() {
this.id = _$cuid_1();
this.startedAt = new Date();
this._handled = 0;
this._unhandled = 0;
this._user = {};
this.app = {};
this.device = {};
}
var _proto = Session.prototype;
_proto.getUser = function getUser() {
return this._user;
};
_proto.setUser = function setUser(id, email, name) {
this._user = {
id: id,
email: email,
name: name
};
};
_proto.toJSON = function toJSON() {
return {
id: this.id,
startedAt: this.startedAt,
events: {
handled: this._handled,
unhandled: this._unhandled
}
};
};
_proto._track = function _track(event) {
this[event._handledState.unhandled ? '_unhandled' : '_handled'] += 1;
};
return Session;
}();
var _$Session_34 = Session;
/* removed: var _$config_9 = require('./config'); */;
/* removed: var _$Event_10 = require('./event'); */;
/* removed: var _$Breadcrumb_7 = require('./breadcrumb'); */;
/* removed: var _$Session_34 = require('./session'); */;
/* removed: var _$map_21 = require('./lib/es-utils/map'); */;
/* removed: var _$includes_18 = require('./lib/es-utils/includes'); */;
/* removed: var _$filter_17 = require('./lib/es-utils/filter'); */;
/* removed: var _$reduce_22 = require('./lib/es-utils/reduce'); */;
/* removed: var _$keys_20 = require('./lib/es-utils/keys'); */;
/* removed: var _$assign_16 = require('./lib/es-utils/assign'); */;
/* removed: var _$callbackRunner_13 = require('./lib/callback-runner'); */;
/* removed: var _$metadataDelegate_27 = require('./lib/metadata-delegate'); */;
/* removed: var _$syncCallbackRunner_30 = require('./lib/sync-callback-runner'); */;
/* removed: var _$breadcrumbTypes_12 = require('./lib/breadcrumb-types'); */;
var __add_8 = _$featureFlagDelegate_23.add,
__clear_8 = _$featureFlagDelegate_23.clear,
__merge_8 = _$featureFlagDelegate_23.merge;
var SECONDARY_ENDPOINT_API_KEY_PREFIX = '00000';
var SECONDARY_NOTIFY_ENDPOINT = 'https://notify.bugsnag.smartbear.com';
var SECONDARY_SESSIONS_ENDPOINT = 'https://sessions.bugsnag.smartbear.com';
var noop = function () {};
var Client = /*#__PURE__*/function () {
function Client(configuration, schema, internalPlugins, notifier) {
var _this = this;
if (schema === void 0) {
schema = _$config_9.schema;
}
if (internalPlugins === void 0) {
internalPlugins = [];
}
// notifier id
this._notifier = notifier;
// intialise opts and config
this._config = {};
this._schema = schema;
// i/o
this._delivery = {
sendSession: noop,
sendEvent: noop
};
this._logger = {
debug: noop,
info: noop,
warn: noop,
error: noop
};
// plugins
this._plugins = {};
// state
this._breadcrumbs = [];
this._session = null;
this._metadata = {};
this._featuresIndex = {};
this._features = [];
this._context = undefined;
this._user = {};
this._groupingDiscriminator = undefined;
// callbacks:
// e: onError
// s: onSession
// sp: onSessionPayload
// b: onBreadcrumb
// (note these names are minified by hand because object
// properties are not safe to minify automatically)
this._cbs = {
e: [],
s: [],
sp: [],
b: []
};
// expose internal constructors
this.Client = Client;
this.Event = _$Event_10;
this.Breadcrumb = _$Breadcrumb_7;
this.Session = _$Session_34;
this._config = this._configure(configuration, internalPlugins);
_$map_21(internalPlugins.concat(this._config.plugins), function (pl) {
if (pl) _this._loadPlugin(pl);
});
// when notify() is called we need to know how many frames are from our own source
// this inital value is 1 not 0 because we wrap notify() to ensure it is always
// bound to have the client as its `this` value – see below.
this._depth = 1;
var self = this;
var notify = this.notify;
this.notify = function () {
return notify.apply(self, arguments);
};
}
var _proto = Client.prototype;
_proto.addMetadata = function addMetadata(section, keyOrObj, maybeVal) {
return _$metadataDelegate_27.add(this._metadata, section, keyOrObj, maybeVal);
};
_proto.getMetadata = function getMetadata(section, key) {
return _$metadataDelegate_27.get(this._metadata, section, key);
};
_proto.clearMetadata = function clearMetadata(section, key) {
return _$metadataDelegate_27.clear(this._metadata, section, key);
};
_proto.addFeatureFlag = function addFeatureFlag(name, variant) {
if (variant === void 0) {
variant = null;
}
__add_8(this._features, this._featuresIndex, name, variant);
};
_proto.addFeatureFlags = function addFeatureFlags(featureFlags) {
__merge_8(this._features, featureFlags, this._featuresIndex);
};
_proto.clearFeatureFlag = function clearFeatureFlag(name) {
__clear_8(this._features, this._featuresIndex, name);
};
_proto.clearFeatureFlags = function clearFeatureFlags() {
this._features = [];
this._featuresIndex = {};
};
_proto.getContext = function getContext() {
return this._context;
};
_proto.setContext = function setContext(c) {
this._context = c;
};
_proto.getGroupingDiscriminator = function getGroupingDiscriminator() {
return this._groupingDiscriminator;
};
_proto.setGroupingDiscriminator = function setGroupingDiscriminator(value) {
var previousValue = this._groupingDiscriminator;
if (typeof value === 'string' || value === null || value === undefined) this._groupingDiscriminator = value;
return previousValue;
};
_proto._configure = function _configure(opts, internalPlugins) {
var schema = _$reduce_22(internalPlugins, function (schema, plugin) {
if (plugin && plugin.configSchema) return _$assign_16({}, schema, plugin.configSchema);
return schema;
}, this._schema);
// sendPayloadChecksums is false by default unless custom endpoints are not specified
if (!opts.endpoints) {
opts.sendPayloadChecksums = 'sendPayloadChecksums' in opts ? opts.sendPayloadChecksums : true;
}
// accumulate configuration and error messages
var _reduce = _$reduce_22(_$keys_20(schema), function (accum, key) {
var defaultValue = schema[key].defaultValue(opts[key]);
if (opts[key] !== undefined) {
var valid = schema[key].validate(opts[key]);
if (!valid) {
accum.errors[key] = schema[key].message;
accum.config[key] = defaultValue;
} else {
if (schema[key].allowPartialObject) {
accum.config[key] = _$assign_16(defaultValue, opts[key]);
} else {
accum.config[key] = opts[key];
}
}
} else {
accum.config[key] = defaultValue;
}
return accum;
}, {
errors: {},
config: {}
}),
errors = _reduce.errors,
config = _reduce.config;
if (schema.apiKey) {
// missing api key is the only fatal error
if (!config.apiKey) throw new Error('No Bugsnag API Key set');
// warn about an apikey that is not of the expected format
if (!/^[0-9a-f]{32}$/i.test(config.apiKey)) errors.apiKey = 'should be a string of 32 hexadecimal characters';
if (opts.endpoints === undefined && config.apiKey.indexOf(SECONDARY_ENDPOINT_API_KEY_PREFIX) === 0) {
config.endpoints = {
notify: SECONDARY_NOTIFY_ENDPOINT,
sessions: SECONDARY_SESSIONS_ENDPOINT
};
}
}
// update and elevate some options
this._metadata = _$assign_16({}, config.metadata);
__merge_8(this._features, config.featureFlags, this._featuresIndex);
this._user = _$assign_16({}, config.user);
this._context = config.context;
if (config.logger) this._logger = config.logger;
// add callbacks
if (config.onError) this._cbs.e = this._cbs.e.concat(config.onError);
if (config.onBreadcrumb) this._cbs.b = this._cbs.b.concat(config.onBreadcrumb);
if (config.onSession) this._cbs.s = this._cbs.s.concat(config.onSession);
// finally warn about any invalid config where we fell back to the default
if (_$keys_20(errors).length) {
this._logger.warn(generateConfigErrorMessage(errors, opts));
}
return config;
};
_proto.getUser = function getUser() {
return this._user;
};
_proto.setUser = function setUser(id, email, name) {
this._user = {
id: id,
email: email,
name: name
};
};
_proto._loadPlugin = function _loadPlugin(plugin) {
var result = plugin.load(this);
// 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;
};
_proto.getPlugin = function getPlugin(name) {
return this._plugins["~" + name + "~"];
};
_proto._setDelivery = function _setDelivery(d) {
this._delivery = d(this);
};
_proto.startSession = function startSession() {
var session = new _$Session_34();
session.app.releaseStage = this._config.releaseStage;
session.app.version = this._config.appVersion;
session.app.type = this._config.appType;
session._user = _$assign_16({}, this._user);
// run onSession callbacks
var ignore = _$syncCallbackRunner_30(this._cbs.s, session, 'onSession', this._logger);
if (ignore) {
this._logger.debug('Session not started due to onSession callback');
return this;
}
return this._sessionDelegate.startSession(this, session);
};
_proto.addOnError = function addOnError(fn, front) {
if (front === void 0) {
front = false;
}
this._cbs.e[front ? 'unshift' : 'push'](fn);
};
_proto.removeOnError = function removeOnError(fn) {
this._cbs.e = _$filter_17(this._cbs.e, function (f) {
return f !== fn;
});
};
_proto._addOnSessionPayload = function _addOnSessionPayload(fn) {
this._cbs.sp.push(fn);
};
_proto.addOnSession = function addOnSession(fn) {
this._cbs.s.push(fn);
};
_proto.removeOnSession = function removeOnSession(fn) {
this._cbs.s = _$filter_17(this._cbs.s, function (f) {
return f !== fn;
});
};
_proto.addOnBreadcrumb = function addOnBreadcrumb(fn, front) {
if (front === void 0) {
front = false;
}
this._cbs.b[front ? 'unshift' : 'push'](fn);
};
_proto.removeOnBreadcrumb = function removeOnBreadcrumb(fn) {
this._cbs.b = _$filter_17(this._cbs.b, function (f) {
return f !== fn;
});
};
_proto.pauseSession = function pauseSession() {
return this._sessionDelegate.pauseSession(this);
};
_proto.resumeSession = function resumeSession() {
return this._sessionDelegate.resumeSession(this);
};
_proto.leaveBreadcrumb = function leaveBreadcrumb(message, metadata, type) {
// coerce bad values so that the defaults get set
message = typeof message === 'string' ? message : '';
type = typeof type === 'string' && _$includes_18(_$breadcrumbTypes_12, type) ? type : 'manual';
metadata = typeof metadata === 'object' && m