History

Update Raven.js

Thibaut Courouble committed 8 years ago

Commit 4dc85f81 parent 0bd82891 file · +2544 −2655Browse files

Showing the changes to assets/javascripts (1 of 1 file). Show all

Unified · Split

assets/javascripts/vendor/raven.js+2544−2655
@@ -1,4 +1,4 @@
1−/*! Raven.js 3.18.0 (b771bb2) | github.com/getsentry/raven-js */
1+/*! Raven.js 3.20.1 (42adaf5) | github.com/getsentry/raven-js */
22
33 /*
44 * Includes TraceKit
@@ -10,322 +10,270 @@ · 5 unmodified lines
1010 *
1111 */
1212
13−(function(f) {
14− if (typeof exports === 'object' && typeof module !== 'undefined') {
15− module.exports = f();
16− } else if (typeof define === 'function' && define.amd) {
17− define([], f);
18− } else {
19− var g;
20− if (typeof window !== 'undefined') {
21− g = window;
22− } else if (typeof global !== 'undefined') {
23− g = global;
24− } else if (typeof self !== 'undefined') {
25− g = self;
26− } else {
27− g = this;
28− }
29− g.Raven = f();
30− }
31−})(function() {
32− var define, module, exports;
33− return (function e(t, n, r) {
34− function s(o, u) {
35− if (!n[o]) {
36− if (!t[o]) {
37− var a = typeof require == 'function' && require;
38− if (!u && a) return a(o, !0);
39− if (i) return i(o, !0);
40− var f = new Error("Cannot find module '" + o + "'");
41− throw ((f.code = 'MODULE_NOT_FOUND'), f);
42− }
43− var l = (n[o] = {exports: {}});
44− t[o][0].call(
45− l.exports,
46− function(e) {
47− var n = t[o][1][e];
48− return s(n ? n : e);
49− },
50− l,
51− l.exports,
52− e,
53− t,
54− n,
55− r
56− );
57− }
58− return n[o].exports;
59− }
60− var i = typeof require == 'function' && require;
61− for (var o = 0; o < r.length; o++) s(r[o]);
62− return s;
63− })(
64− {
65− 1: [
66− function(_dereq_, module, exports) {
67− function RavenConfigError(message) {
68− this.name = 'RavenConfigError';
69− this.message = message;
70− }
71− RavenConfigError.prototype = new Error();
72− RavenConfigError.prototype.constructor = RavenConfigError;
73−
74− module.exports = RavenConfigError;
75− },
76− {}
77− ],
78− 2: [
79− function(_dereq_, module, exports) {
80− var wrapMethod = function(console, level, callback) {
81− var originalConsoleLevel = console[level];
82− var originalConsole = console;
83−
84− if (!(level in console)) {
85− return;
86− }
13+(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.Raven = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
14+function RavenConfigError(message) {
15+ this.name = 'RavenConfigError';
16+ this.message = message;
17+}
18+RavenConfigError.prototype = new Error();
19+RavenConfigError.prototype.constructor = RavenConfigError;
8720
88− var sentryLevel = level === 'warn' ? 'warning' : level;
89−
90− console[level] = function() {
91− var args = [].slice.call(arguments);
92−
93− var msg = '' + args.join(' ');
94− var data = {
95− level: sentryLevel,
96− logger: 'console',
97− extra: {arguments: args}
98− };
99−
100− if (level === 'assert') {
101− if (args[0] === false) {
102− // Default browsers message
103− msg =
104− 'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert');
105− data.extra.arguments = args.slice(1);
106− callback && callback(msg, data);
107− }
108− } else {
109− callback && callback(msg, data);
110− }
111−
112− // this fails for some browsers. :(
113− if (originalConsoleLevel) {
114− // IE9 doesn't allow calling apply on console functions directly
115− // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193
116− Function.prototype.apply.call(
117− originalConsoleLevel,
118− originalConsole,
119− args
120− );
121− }
122− };
123− };
124−
125− module.exports = {
126− wrapMethod: wrapMethod
127− };
128− },
129− {}
130− ],
131− 3: [
132− function(_dereq_, module, exports) {
133− (function(global) {
134− /*global XDomainRequest:false, __DEV__:false*/
21+module.exports = RavenConfigError;
13522
136− var TraceKit = _dereq_(6);
137− var stringify = _dereq_(7);
138− var RavenConfigError = _dereq_(1);
139− var utils = _dereq_(5);
23+},{}],2:[function(_dereq_,module,exports){
24+var wrapMethod = function(console, level, callback) {
25+ var originalConsoleLevel = console[level];
26+ var originalConsole = console;
14027
141− var isError = utils.isError,
142− isObject = utils.isObject;
28+ if (!(level in console)) {
29+ return;
30+ }
14331
144− var wrapConsoleMethod = _dereq_(2).wrapMethod;
32+ var sentryLevel = level === 'warn' ? 'warning' : level;
14533
146− var dsnKeys = 'source protocol user pass host port path'.split(' '),
147− dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
34+ console[level] = function() {
35+ var args = [].slice.call(arguments);
14836
149− function now() {
150− return +new Date();
151− }
37+ var msg = '' + args.join(' ');
38+ var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}};
15239
153− // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
154− var _window =
155− typeof window !== 'undefined'
156− ? window
157− : typeof global !== 'undefined'
158− ? global
159− : typeof self !== 'undefined' ? self : {};
160− var _document = _window.document;
161− var _navigator = _window.navigator;
162−
163− function keepOriginalCallback(original, callback) {
164− return isFunction(callback)
165− ? function(data) {
166− return callback(data, original);
167− }
168− : callback;
169− }
40+ if (level === 'assert') {
41+ if (args[0] === false) {
42+ // Default browsers message
43+ msg = 'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert');
44+ data.extra.arguments = args.slice(1);
45+ callback && callback(msg, data);
46+ }
47+ } else {
48+ callback && callback(msg, data);
49+ }
17050
171− // First, check for JSON support
172− // If there is no JSON, we no-op the core features of Raven
173− // since JSON is required to encode the payload
174− function Raven() {
175− this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
176− // Raven can run in contexts where there's no document (react-native)
177− this._hasDocument = !isUndefined(_document);
178− this._hasNavigator = !isUndefined(_navigator);
179− this._lastCapturedException = null;
180− this._lastData = null;
181− this._lastEventId = null;
182− this._globalServer = null;
183− this._globalKey = null;
184− this._globalProject = null;
185− this._globalContext = {};
186− this._globalOptions = {
187− logger: 'javascript',
188− ignoreErrors: [],
189− ignoreUrls: [],
190− whitelistUrls: [],
191− includePaths: [],
192− collectWindowErrors: true,
193− maxMessageLength: 0,
194−
195− // By default, truncates URL values to 250 chars
196− maxUrlLength: 250,
197− stackTraceLimit: 50,
198− autoBreadcrumbs: true,
199− instrument: true,
200− sampleRate: 1
201− };
202− this._ignoreOnError = 0;
203− this._isRavenInstalled = false;
204− this._originalErrorStackTraceLimit = Error.stackTraceLimit;
205− // capture references to window.console *and* all its methods first
206− // before the console plugin has a chance to monkey patch
207− this._originalConsole = _window.console || {};
208− this._originalConsoleMethods = {};
209− this._plugins = [];
210− this._startTime = now();
211− this._wrappedBuiltIns = [];
212− this._breadcrumbs = [];
213− this._lastCapturedEvent = null;
214− this._keypressTimeout;
215− this._location = _window.location;
216− this._lastHref = this._location && this._location.href;
217− this._resetBackoff();
218−
219− // eslint-disable-next-line guard-for-in
220− for (var method in this._originalConsole) {
221− this._originalConsoleMethods[method] = this._originalConsole[method];
222− }
223− }
51+ // this fails for some browsers. :(
52+ if (originalConsoleLevel) {
53+ // IE9 doesn't allow calling apply on console functions directly
54+ // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193
55+ Function.prototype.apply.call(originalConsoleLevel, originalConsole, args);
56+ }
57+ };
58+};
59+
60+module.exports = {
61+ wrapMethod: wrapMethod
62+};
63+
64+},{}],3:[function(_dereq_,module,exports){
65+(function (global){
66+/*global XDomainRequest:false */
67+
68+var TraceKit = _dereq_(6);
69+var stringify = _dereq_(7);
70+var RavenConfigError = _dereq_(1);
71+
72+var utils = _dereq_(5);
73+var isError = utils.isError;
74+var isObject = utils.isObject;
75+var isErrorEvent = utils.isErrorEvent;
76+var isUndefined = utils.isUndefined;
77+var isFunction = utils.isFunction;
78+var isString = utils.isString;
79+var isArray = utils.isArray;
80+var isEmptyObject = utils.isEmptyObject;
81+var each = utils.each;
82+var objectMerge = utils.objectMerge;
83+var truncate = utils.truncate;
84+var objectFrozen = utils.objectFrozen;
85+var hasKey = utils.hasKey;
86+var joinRegExp = utils.joinRegExp;
87+var urlencode = utils.urlencode;
88+var uuid4 = utils.uuid4;
89+var htmlTreeAsString = utils.htmlTreeAsString;
90+var isSameException = utils.isSameException;
91+var isSameStacktrace = utils.isSameStacktrace;
92+var parseUrl = utils.parseUrl;
93+var fill = utils.fill;
94+
95+var wrapConsoleMethod = _dereq_(2).wrapMethod;
96+
97+var dsnKeys = 'source protocol user pass host port path'.split(' '),
98+ dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
99+
100+function now() {
101+ return +new Date();
102+}
103+
104+// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
105+var _window =
106+ typeof window !== 'undefined'
107+ ? window
108+ : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
109+var _document = _window.document;
110+var _navigator = _window.navigator;
111+
112+function keepOriginalCallback(original, callback) {
113+ return isFunction(callback)
114+ ? function(data) {
115+ return callback(data, original);
116+ }
117+ : callback;
118+}
119+
120+// First, check for JSON support
121+// If there is no JSON, we no-op the core features of Raven
122+// since JSON is required to encode the payload
123+function Raven() {
124+ this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
125+ // Raven can run in contexts where there's no document (react-native)
126+ this._hasDocument = !isUndefined(_document);
127+ this._hasNavigator = !isUndefined(_navigator);
128+ this._lastCapturedException = null;
129+ this._lastData = null;
130+ this._lastEventId = null;
131+ this._globalServer = null;
132+ this._globalKey = null;
133+ this._globalProject = null;
134+ this._globalContext = {};
135+ this._globalOptions = {
136+ logger: 'javascript',
137+ ignoreErrors: [],
138+ ignoreUrls: [],
139+ whitelistUrls: [],
140+ includePaths: [],
141+ collectWindowErrors: true,
142+ maxMessageLength: 0,
143+
144+ // By default, truncates URL values to 250 chars
145+ maxUrlLength: 250,
146+ stackTraceLimit: 50,
147+ autoBreadcrumbs: true,
148+ instrument: true,
149+ sampleRate: 1
150+ };
151+ this._ignoreOnError = 0;
152+ this._isRavenInstalled = false;
153+ this._originalErrorStackTraceLimit = Error.stackTraceLimit;
154+ // capture references to window.console *and* all its methods first
155+ // before the console plugin has a chance to monkey patch
156+ this._originalConsole = _window.console || {};
157+ this._originalConsoleMethods = {};
158+ this._plugins = [];
159+ this._startTime = now();
160+ this._wrappedBuiltIns = [];
161+ this._breadcrumbs = [];
162+ this._lastCapturedEvent = null;
163+ this._keypressTimeout;
164+ this._location = _window.location;
165+ this._lastHref = this._location && this._location.href;
166+ this._resetBackoff();
167+
168+ // eslint-disable-next-line guard-for-in
169+ for (var method in this._originalConsole) {
170+ this._originalConsoleMethods[method] = this._originalConsole[method];
171+ }
172+}
224173
225− /*
174+/*
226175 * The core Raven singleton
227176 *
228177 * @this {Raven}
229178 */
230179
231− Raven.prototype = {
232− // Hardcode version string so that raven source can be loaded directly via
233− // webpack (using a build step causes webpack #1617). Grunt verifies that
234− // this value matches package.json during build.
235− // See: https://github.com/getsentry/raven-js/issues/465
236− VERSION: '3.18.0',
180+Raven.prototype = {
181+ // Hardcode version string so that raven source can be loaded directly via
182+ // webpack (using a build step causes webpack #1617). Grunt verifies that
183+ // this value matches package.json during build.
184+ // See: https://github.com/getsentry/raven-js/issues/465
185+ VERSION: '3.20.1',
237186
238− debug: false,
187+ debug: false,
239188
240− TraceKit: TraceKit, // alias to TraceKit
189+ TraceKit: TraceKit, // alias to TraceKit
241190
242− /*
191+ /*
243192 * Configure Raven with a DSN and extra options
244193 *
245194 * @param {string} dsn The public Sentry DSN
246195 * @param {object} options Set of global options [optional]
247196 * @return {Raven}
248197 */
249− config: function(dsn, options) {
250− var self = this;
251−
252− if (self._globalServer) {
253− this._logDebug('error', 'Error: Raven has already been configured');
254− return self;
255− }
256− if (!dsn) return self;
257−
258− var globalOptions = self._globalOptions;
259−
260− // merge in options
261− if (options) {
262− each(options, function(key, value) {
263− // tags and extra are special and need to be put into context
264− if (key === 'tags' || key === 'extra' || key === 'user') {
265− self._globalContext[key] = value;
266− } else {
267− globalOptions[key] = value;
268− }
269− });
270− }
198+ config: function(dsn, options) {
199+ var self = this;
271200
272− self.setDSN(dsn);
273−
274− // "Script error." is hard coded into browsers for errors that it can't read.
275− // this is the result of a script being pulled in from an external domain and CORS.
276− globalOptions.ignoreErrors.push(/^Script error\.?$/);
277− globalOptions.ignoreErrors.push(
278− /^Javascript error: Script error\.? on line 0$/
279− );
280−
281− // join regexp rules into one big rule
282− globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
283− globalOptions.ignoreUrls = globalOptions.ignoreUrls.length
284− ? joinRegExp(globalOptions.ignoreUrls)
285− : false;
286− globalOptions.whitelistUrls = globalOptions.whitelistUrls.length
287− ? joinRegExp(globalOptions.whitelistUrls)
288− : false;
289− globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
290− globalOptions.maxBreadcrumbs = Math.max(
291− 0,
292− Math.min(globalOptions.maxBreadcrumbs || 100, 100)
293− ); // default and hard limit is 100
294−
295− var autoBreadcrumbDefaults = {
296− xhr: true,
297− console: true,
298− dom: true,
299− location: true
300− };
201+ if (self._globalServer) {
202+ this._logDebug('error', 'Error: Raven has already been configured');
203+ return self;
204+ }
205+ if (!dsn) return self;
206+
207+ var globalOptions = self._globalOptions;
208+
209+ // merge in options
210+ if (options) {
211+ each(options, function(key, value) {
212+ // tags and extra are special and need to be put into context
213+ if (key === 'tags' || key === 'extra' || key === 'user') {
214+ self._globalContext[key] = value;
215+ } else {
216+ globalOptions[key] = value;
217+ }
218+ });
219+ }
301220
302− var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
303− if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
304− autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
305− } else if (autoBreadcrumbs !== false) {
306− autoBreadcrumbs = autoBreadcrumbDefaults;
307− }
308− globalOptions.autoBreadcrumbs = autoBreadcrumbs;
221+ self.setDSN(dsn);
222+
223+ // "Script error." is hard coded into browsers for errors that it can't read.
224+ // this is the result of a script being pulled in from an external domain and CORS.
225+ globalOptions.ignoreErrors.push(/^Script error\.?$/);
226+ globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
227+
228+ // join regexp rules into one big rule
229+ globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
230+ globalOptions.ignoreUrls = globalOptions.ignoreUrls.length
231+ ? joinRegExp(globalOptions.ignoreUrls)
232+ : false;
233+ globalOptions.whitelistUrls = globalOptions.whitelistUrls.length
234+ ? joinRegExp(globalOptions.whitelistUrls)
235+ : false;
236+ globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
237+ globalOptions.maxBreadcrumbs = Math.max(
238+ 0,
239+ Math.min(globalOptions.maxBreadcrumbs || 100, 100)
240+ ); // default and hard limit is 100
241+
242+ var autoBreadcrumbDefaults = {
243+ xhr: true,
244+ console: true,
245+ dom: true,
246+ location: true,
247+ sentry: true
248+ };
249+
250+ var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
251+ if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
252+ autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
253+ } else if (autoBreadcrumbs !== false) {
254+ autoBreadcrumbs = autoBreadcrumbDefaults;
255+ }
256+ globalOptions.autoBreadcrumbs = autoBreadcrumbs;
309257
310− var instrumentDefaults = {
311− tryCatch: true
312− };
258+ var instrumentDefaults = {
259+ tryCatch: true
260+ };
313261
314− var instrument = globalOptions.instrument;
315− if ({}.toString.call(instrument) === '[object Object]') {
316− instrument = objectMerge(instrumentDefaults, instrument);
317− } else if (instrument !== false) {
318− instrument = instrumentDefaults;
319− }
320− globalOptions.instrument = instrument;
262+ var instrument = globalOptions.instrument;
263+ if ({}.toString.call(instrument) === '[object Object]') {
264+ instrument = objectMerge(instrumentDefaults, instrument);
265+ } else if (instrument !== false) {
266+ instrument = instrumentDefaults;
267+ }
268+ globalOptions.instrument = instrument;
321269
322− TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
270+ TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
323271
324− // return for chaining
325− return self;
326− },
272+ // return for chaining
273+ return self;
274+ },
327275
328− /*
276+ /*
329277 * Installs a global window.onerror error handler
330278 * to capture and report uncaught exceptions.
331279 * At this point, install() is required to be called due
@@ -333,63 +281,58 @@ · 1 unmodified line
333281 *
334282 * @return {Raven}
335283 */
336− install: function() {
337− var self = this;
338− if (self.isSetup() && !self._isRavenInstalled) {
339− TraceKit.report.subscribe(function() {
340− self._handleOnErrorStackInfo.apply(self, arguments);
341− });
342− if (
343− self._globalOptions.instrument &&
344− self._globalOptions.instrument.tryCatch
345− ) {
346− self._instrumentTryCatch();
347− }
284+ install: function() {
285+ var self = this;
286+ if (self.isSetup() && !self._isRavenInstalled) {
287+ TraceKit.report.subscribe(function() {
288+ self._handleOnErrorStackInfo.apply(self, arguments);
289+ });
348290
349− if (self._globalOptions.autoBreadcrumbs) self._instrumentBreadcrumbs();
291+ self._patchFunctionToString();
350292
351− // Install all of the plugins
352− self._drainPlugins();
293+ if (self._globalOptions.instrument && self._globalOptions.instrument.tryCatch) {
294+ self._instrumentTryCatch();
295+ }
353296
354− self._isRavenInstalled = true;
355− }
297+ if (self._globalOptions.autoBreadcrumbs) self._instrumentBreadcrumbs();
356298
357− Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
358− return this;
359− },
299+ // Install all of the plugins
300+ self._drainPlugins();
360301
361− /*
302+ self._isRavenInstalled = true;
303+ }
304+
305+ Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
306+ return this;
307+ },
308+
309+ /*
362310 * Set the DSN (can be called multiple time unlike config)
363311 *
364312 * @param {string} dsn The public Sentry DSN
365313 */
366− setDSN: function(dsn) {
367− var self = this,
368− uri = self._parseDSN(dsn),
369− lastSlash = uri.path.lastIndexOf('/'),
370− path = uri.path.substr(1, lastSlash);
371−
372− self._dsn = dsn;
373− self._globalKey = uri.user;
374− self._globalSecret = uri.pass && uri.pass.substr(1);
375− self._globalProject = uri.path.substr(lastSlash + 1);
376−
377− self._globalServer = self._getGlobalServer(uri);
378−
379− self._globalEndpoint =
380− self._globalServer +
381− '/' +
382− path +
383− 'api/' +
384− self._globalProject +
385− '/store/';
386−
387− // Reset backoff state since we may be pointing at a
388− // new project/server
389− this._resetBackoff();
390− },
391−
392− /*
314+ setDSN: function(dsn) {
315+ var self = this,
316+ uri = self._parseDSN(dsn),
317+ lastSlash = uri.path.lastIndexOf('/'),
318+ path = uri.path.substr(1, lastSlash);
319+
320+ self._dsn = dsn;
321+ self._globalKey = uri.user;
322+ self._globalSecret = uri.pass && uri.pass.substr(1);
323+ self._globalProject = uri.path.substr(lastSlash + 1);
324+
325+ self._globalServer = self._getGlobalServer(uri);
326+
327+ self._globalEndpoint =
328+ self._globalServer + '/' + path + 'api/' + self._globalProject + '/store/';
329+
330+ // Reset backoff state since we may be pointing at a
331+ // new project/server
332+ this._resetBackoff();
333+ },
334+
335+ /*
393336 * Wrap code within a context so Raven can capture errors
394337 * reliably across domains that is executed immediately.
395338 *
@@ -397,17 +340,17 @@ · 1 unmodified line
397340 * @param {function} func The callback to be immediately executed within the context
398341 * @param {array} args An array of arguments to be called with the callback [optional]
399342 */
400− context: function(options, func, args) {
401− if (isFunction(options)) {
402− args = func || [];
403− func = options;
404− options = undefined;
405− }
343+ context: function(options, func, args) {
344+ if (isFunction(options)) {
345+ args = func || [];
346+ func = options;
347+ options = undefined;
348+ }
406349
407− return this.wrap(options, func).apply(this, args);
408− },
350+ return this.wrap(options, func).apply(this, args);
351+ },
409352
410− /*
353+ /*
411354 * Wrap code within a context and returns back a new function to be executed
412355 *
413356 * @param {object} options A specific set of options for this context [optional]
@@ -415,381 +358,397 @@ · 1 unmodified line
415358 * @param {function} func A function to call before the try/catch wrapper [optional, private]
416359 * @return {function} The newly wrapped functions with a context
417360 */
418− wrap: function(options, func, _before) {
419− var self = this;
420− // 1 argument has been passed, and it's not a function
421− // so just return it
422− if (isUndefined(func) && !isFunction(options)) {
423− return options;
424− }
425−
426− // options is optional
427− if (isFunction(options)) {
428− func = options;
429− options = undefined;
430− }
361+ wrap: function(options, func, _before) {
362+ var self = this;
363+ // 1 argument has been passed, and it's not a function
364+ // so just return it
365+ if (isUndefined(func) && !isFunction(options)) {
366+ return options;
367+ }
431368
432− // At this point, we've passed along 2 arguments, and the second one
433− // is not a function either, so we'll just return the second argument.
434− if (!isFunction(func)) {
435− return func;
436− }
369+ // options is optional
370+ if (isFunction(options)) {
371+ func = options;
372+ options = undefined;
373+ }
437374
438− // We don't wanna wrap it twice!
439− try {
440− if (func.__raven__) {
441− return func;
442− }
375+ // At this point, we've passed along 2 arguments, and the second one
376+ // is not a function either, so we'll just return the second argument.
377+ if (!isFunction(func)) {
378+ return func;
379+ }
443380
444− // If this has already been wrapped in the past, return that
445− if (func.__raven_wrapper__) {
446− return func.__raven_wrapper__;
447− }
448− } catch (e) {
449− // Just accessing custom props in some Selenium environments
450− // can cause a "Permission denied" exception (see raven-js#495).
451− // Bail on wrapping and return the function as-is (defers to window.onerror).
452− return func;
453− }
381+ // We don't wanna wrap it twice!
382+ try {
383+ if (func.__raven__) {
384+ return func;
385+ }
454386
455− function wrapped() {
456− var args = [],
457− i = arguments.length,
458− deep = !options || (options && options.deep !== false);
387+ // If this has already been wrapped in the past, return that
388+ if (func.__raven_wrapper__) {
389+ return func.__raven_wrapper__;
390+ }
391+ } catch (e) {
392+ // Just accessing custom props in some Selenium environments
393+ // can cause a "Permission denied" exception (see raven-js#495).
394+ // Bail on wrapping and return the function as-is (defers to window.onerror).
395+ return func;
396+ }
459397
460− if (_before && isFunction(_before)) {
461− _before.apply(this, arguments);
462− }
398+ function wrapped() {
399+ var args = [],
400+ i = arguments.length,
401+ deep = !options || (options && options.deep !== false);
463402
464− // Recursively wrap all of a function's arguments that are
465− // functions themselves.
466− while (i--)
467− args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
403+ if (_before && isFunction(_before)) {
404+ _before.apply(this, arguments);
405+ }
468406
469− try {
470− // Attempt to invoke user-land function
471− // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
472− // means Raven caught an error invoking your application code. This is
473− // expected behavior and NOT indicative of a bug with Raven.js.
474− return func.apply(this, args);
475− } catch (e) {
476− self._ignoreNextOnError();
477− self.captureException(e, options);
478− throw e;
479− }
480− }
407+ // Recursively wrap all of a function's arguments that are
408+ // functions themselves.
409+ while (i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
410+
411+ try {
412+ // Attempt to invoke user-land function
413+ // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
414+ // means Raven caught an error invoking your application code. This is
415+ // expected behavior and NOT indicative of a bug with Raven.js.
416+ return func.apply(this, args);
417+ } catch (e) {
418+ self._ignoreNextOnError();
419+ self.captureException(e, options);
420+ throw e;
421+ }
422+ }
481423
482− // copy over properties of the old function
483− for (var property in func) {
484− if (hasKey(func, property)) {
485− wrapped[property] = func[property];
486− }
487− }
488− wrapped.prototype = func.prototype;
424+ // copy over properties of the old function
425+ for (var property in func) {
426+ if (hasKey(func, property)) {
427+ wrapped[property] = func[property];
428+ }
429+ }
430+ wrapped.prototype = func.prototype;
489431
490− func.__raven_wrapper__ = wrapped;
491− // Signal that this function has been wrapped already
492− // for both debugging and to prevent it to being wrapped twice
493− wrapped.__raven__ = true;
494− wrapped.__inner__ = func;
432+ func.__raven_wrapper__ = wrapped;
433+ // Signal that this function has been wrapped/filled already
434+ // for both debugging and to prevent it to being wrapped/filled twice
435+ wrapped.__raven__ = true;
436+ wrapped.__orig__ = func;
495437
496− return wrapped;
497− },
438+ return wrapped;
439+ },
498440
499− /*
441+ /*
500442 * Uninstalls the global error handler.
501443 *
502444 * @return {Raven}
503445 */
504− uninstall: function() {
505− TraceKit.report.uninstall();
446+ uninstall: function() {
447+ TraceKit.report.uninstall();
506448
507− this._restoreBuiltIns();
449+ this._unpatchFunctionToString();
450+ this._restoreBuiltIns();
508451
509− Error.stackTraceLimit = this._originalErrorStackTraceLimit;
510− this._isRavenInstalled = false;
452+ Error.stackTraceLimit = this._originalErrorStackTraceLimit;
453+ this._isRavenInstalled = false;
511454
512− return this;
513− },
455+ return this;
456+ },
514457
515− /*
458+ /*
516459 * Manually capture an exception and send it over to Sentry
517460 *
518461 * @param {error} ex An exception to be logged
519462 * @param {object} options A specific set of options for this error [optional]
520463 * @return {Raven}
521464 */
522− captureException: function(ex, options) {
523− // If not an Error is passed through, recall as a message instead
524− if (!isError(ex)) {
525− return this.captureMessage(
526− ex,
527− objectMerge(
528− {
529− trimHeadFrames: 1,
530− stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
531− },
532− options
533− )
534− );
535− }
536−
537− // Store the raw exception object for potential debugging and introspection
538− this._lastCapturedException = ex;
465+ captureException: function(ex, options) {
466+ // Cases for sending ex as a message, rather than an exception
467+ var isNotError = !isError(ex);
468+ var isNotErrorEvent = !isErrorEvent(ex);
469+ var isErrorEventWithoutError = isErrorEvent(ex) && !ex.error;
470+
471+ if ((isNotError && isNotErrorEvent) || isErrorEventWithoutError) {
472+ return this.captureMessage(
473+ ex,
474+ objectMerge(
475+ {
476+ trimHeadFrames: 1,
477+ stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
478+ },
479+ options
480+ )
481+ );
482+ }
539483
540− // TraceKit.report will re-raise any exception passed to it,
541− // which means you have to wrap it in try/catch. Instead, we
542− // can wrap it here and only re-raise if TraceKit.report
543− // raises an exception different from the one we asked to
544− // report on.
545− try {
546− var stack = TraceKit.computeStackTrace(ex);
547− this._handleStackInfo(stack, options);
548− } catch (ex1) {
549− if (ex !== ex1) {
550− throw ex1;
551− }
552− }
484+ // Get actual Error from ErrorEvent
485+ if (isErrorEvent(ex)) ex = ex.error;
486+
487+ // Store the raw exception object for potential debugging and introspection
488+ this._lastCapturedException = ex;
489+
490+ // TraceKit.report will re-raise any exception passed to it,
491+ // which means you have to wrap it in try/catch. Instead, we
492+ // can wrap it here and only re-raise if TraceKit.report
493+ // raises an exception different from the one we asked to
494+ // report on.
495+ try {
496+ var stack = TraceKit.computeStackTrace(ex);
497+ this._handleStackInfo(stack, options);
498+ } catch (ex1) {
499+ if (ex !== ex1) {
500+ throw ex1;
501+ }
502+ }
553503
554− return this;
555− },
504+ return this;
505+ },
556506
557− /*
507+ /*
558508 * Manually send a message to Sentry
559509 *
560510 * @param {string} msg A plain message to be captured in Sentry
561511 * @param {object} options A specific set of options for this message [optional]
562512 * @return {Raven}
563513 */
564− captureMessage: function(msg, options) {
565− // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an
566− // early call; we'll error on the side of logging anything called before configuration since it's
567− // probably something you should see:
568− if (
569− !!this._globalOptions.ignoreErrors.test &&
570− this._globalOptions.ignoreErrors.test(msg)
571− ) {
572− return;
573− }
514+ captureMessage: function(msg, options) {
515+ // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an
516+ // early call; we'll error on the side of logging anything called before configuration since it's
517+ // probably something you should see:
518+ if (
519+ !!this._globalOptions.ignoreErrors.test &&
520+ this._globalOptions.ignoreErrors.test(msg)
521+ ) {
522+ return;
523+ }
574524
575− options = options || {};
576−
577− var data = objectMerge(
578− {
579− message: msg + '' // Make sure it's actually a string
580− },
581− options
582− );
583−
584− if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
585− var ex;
586− // Generate a "synthetic" stack trace from this point.
587− // NOTE: If you are a Sentry user, and you are seeing this stack frame, it is NOT indicative
588− // of a bug with Raven.js. Sentry generates synthetic traces either by configuration,
589− // or if it catches a thrown object without a "stack" property.
590− try {
591− throw new Error(msg);
592− } catch (ex1) {
593− ex = ex1;
594− }
525+ options = options || {};
526+
527+ var data = objectMerge(
528+ {
529+ message: msg + '' // Make sure it's actually a string
530+ },
531+ options
532+ );
533+
534+ var ex;
535+ // Generate a "synthetic" stack trace from this point.
536+ // NOTE: If you are a Sentry user, and you are seeing this stack frame, it is NOT indicative
537+ // of a bug with Raven.js. Sentry generates synthetic traces either by configuration,
538+ // or if it catches a thrown object without a "stack" property.
539+ try {
540+ throw new Error(msg);
541+ } catch (ex1) {
542+ ex = ex1;
543+ }
595544
596− // null exception name so `Error` isn't prefixed to msg
597− ex.name = null;
598−
599− options = objectMerge(
600− {
601− // fingerprint on msg, not stack trace (legacy behavior, could be
602− // revisited)
603− fingerprint: msg,
604− // since we know this is a synthetic trace, the top N-most frames
605− // MUST be from Raven.js, so mark them as in_app later by setting
606− // trimHeadFrames
607− trimHeadFrames: (options.trimHeadFrames || 0) + 1
608− },
609− options
610− );
611−
612− var stack = TraceKit.computeStackTrace(ex);
613− var frames = this._prepareFrames(stack, options);
614− data.stacktrace = {
615− // Sentry expects frames oldest to newest
616− frames: frames.reverse()
617− };
618− }
545+ // null exception name so `Error` isn't prefixed to msg
546+ ex.name = null;
547+ var stack = TraceKit.computeStackTrace(ex);
548+
549+ // stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1]
550+ var initialCall = isArray(stack.stack) && stack.stack[1];
551+ var fileurl = (initialCall && initialCall.url) || '';
552+
553+ if (
554+ !!this._globalOptions.ignoreUrls.test &&
555+ this._globalOptions.ignoreUrls.test(fileurl)
556+ ) {
557+ return;
558+ }
619559
620− // Fire away!
621− this._send(data);
560+ if (
561+ !!this._globalOptions.whitelistUrls.test &&
562+ !this._globalOptions.whitelistUrls.test(fileurl)
563+ ) {
564+ return;
565+ }
622566
623− return this;
624− },
567+ if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
568+ options = objectMerge(
569+ {
570+ // fingerprint on msg, not stack trace (legacy behavior, could be
571+ // revisited)
572+ fingerprint: msg,
573+ // since we know this is a synthetic trace, the top N-most frames
574+ // MUST be from Raven.js, so mark them as in_app later by setting
575+ // trimHeadFrames
576+ trimHeadFrames: (options.trimHeadFrames || 0) + 1
577+ },
578+ options
579+ );
580+
581+ var frames = this._prepareFrames(stack, options);
582+ data.stacktrace = {
583+ // Sentry expects frames oldest to newest
584+ frames: frames.reverse()
585+ };
586+ }
625587
626− captureBreadcrumb: function(obj) {
627− var crumb = objectMerge(
628− {
629− timestamp: now() / 1000
630− },
631− obj
632− );
588+ // Fire away!
589+ this._send(data);
633590
634− if (isFunction(this._globalOptions.breadcrumbCallback)) {
635− var result = this._globalOptions.breadcrumbCallback(crumb);
591+ return this;
592+ },
636593
637− if (isObject(result) && !isEmptyObject(result)) {
638− crumb = result;
639− } else if (result === false) {
640− return this;
641− }
642− }
594+ captureBreadcrumb: function(obj) {
595+ var crumb = objectMerge(
596+ {
597+ timestamp: now() / 1000
598+ },
599+ obj
600+ );
643601
644− this._breadcrumbs.push(crumb);
645− if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
646− this._breadcrumbs.shift();
647− }
648− return this;
649− },
602+ if (isFunction(this._globalOptions.breadcrumbCallback)) {
603+ var result = this._globalOptions.breadcrumbCallback(crumb);
604+
605+ if (isObject(result) && !isEmptyObject(result)) {
606+ crumb = result;
607+ } else if (result === false) {
608+ return this;
609+ }
610+ }
650611
651− addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
652− var pluginArgs = [].slice.call(arguments, 1);
612+ this._breadcrumbs.push(crumb);
613+ if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
614+ this._breadcrumbs.shift();
615+ }
616+ return this;
617+ },
653618
654− this._plugins.push([plugin, pluginArgs]);
655− if (this._isRavenInstalled) {
656− this._drainPlugins();
657− }
619+ addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
620+ var pluginArgs = [].slice.call(arguments, 1);
658621
659− return this;
660− },
622+ this._plugins.push([plugin, pluginArgs]);
623+ if (this._isRavenInstalled) {
624+ this._drainPlugins();
625+ }
626+
627+ return this;
628+ },
661629
662− /*
630+ /*
663631 * Set/clear a user to be sent along with the payload.
664632 *
665633 * @param {object} user An object representing user data [optional]
666634 * @return {Raven}
667635 */
668− setUserContext: function(user) {
669− // Intentionally do not merge here since that's an unexpected behavior.
670− this._globalContext.user = user;
636+ setUserContext: function(user) {
637+ // Intentionally do not merge here since that's an unexpected behavior.
638+ this._globalContext.user = user;
671639
672− return this;
673− },
640+ return this;
641+ },
674642
675− /*
643+ /*
676644 * Merge extra attributes to be sent along with the payload.
677645 *
678646 * @param {object} extra An object representing extra data [optional]
679647 * @return {Raven}
680648 */
681− setExtraContext: function(extra) {
682− this._mergeContext('extra', extra);
649+ setExtraContext: function(extra) {
650+ this._mergeContext('extra', extra);
683651
684− return this;
685− },
652+ return this;
653+ },
686654
687− /*
655+ /*
688656 * Merge tags to be sent along with the payload.
689657 *
690658 * @param {object} tags An object representing tags [optional]
691659 * @return {Raven}
692660 */
693− setTagsContext: function(tags) {
694− this._mergeContext('tags', tags);
661+ setTagsContext: function(tags) {
662+ this._mergeContext('tags', tags);
695663
696− return this;
697− },
664+ return this;
665+ },
698666
699− /*
667+ /*
700668 * Clear all of the context.
701669 *
702670 * @return {Raven}
703671 */
704− clearContext: function() {
705− this._globalContext = {};
672+ clearContext: function() {
673+ this._globalContext = {};
706674
707− return this;
708− },
675+ return this;
676+ },
709677
710− /*
678+ /*
711679 * Get a copy of the current context. This cannot be mutated.
712680 *
713681 * @return {object} copy of context
714682 */
715− getContext: function() {
716− // lol javascript
717− return JSON.parse(stringify(this._globalContext));
718− },
683+ getContext: function() {
684+ // lol javascript
685+ return JSON.parse(stringify(this._globalContext));
686+ },
719687
720− /*
688+ /*
721689 * Set environment of application
722690 *
723691 * @param {string} environment Typically something like 'production'.
724692 * @return {Raven}
725693 */
726− setEnvironment: function(environment) {
727− this._globalOptions.environment = environment;
694+ setEnvironment: function(environment) {
695+ this._globalOptions.environment = environment;
728696
729− return this;
730− },
697+ return this;
698+ },
731699
732− /*
700+ /*
733701 * Set release version of application
734702 *
735703 * @param {string} release Typically something like a git SHA to identify version
736704 * @return {Raven}
737705 */
738− setRelease: function(release) {
739− this._globalOptions.release = release;
706+ setRelease: function(release) {
707+ this._globalOptions.release = release;
740708
741− return this;
742− },
709+ return this;
710+ },
743711
744− /*
712+ /*
745713 * Set the dataCallback option
746714 *
747715 * @param {function} callback The callback to run which allows the
748716 * data blob to be mutated before sending
749717 * @return {Raven}
750718 */
751− setDataCallback: function(callback) {
752− var original = this._globalOptions.dataCallback;
753− this._globalOptions.dataCallback = keepOriginalCallback(
754− original,
755− callback
756− );
757− return this;
758− },
759−
760− /*
719+ setDataCallback: function(callback) {
720+ var original = this._globalOptions.dataCallback;
721+ this._globalOptions.dataCallback = keepOriginalCallback(original, callback);
722+ return this;
723+ },
724+
725+ /*
761726 * Set the breadcrumbCallback option
762727 *
763728 * @param {function} callback The callback to run which allows filtering
764729 * or mutating breadcrumbs
765730 * @return {Raven}
766731 */
767− setBreadcrumbCallback: function(callback) {
768− var original = this._globalOptions.breadcrumbCallback;
769− this._globalOptions.breadcrumbCallback = keepOriginalCallback(
770− original,
771− callback
772− );
773− return this;
774− },
775−
776− /*
732+ setBreadcrumbCallback: function(callback) {
733+ var original = this._globalOptions.breadcrumbCallback;
734+ this._globalOptions.breadcrumbCallback = keepOriginalCallback(original, callback);
735+ return this;
736+ },
737+
738+ /*
777739 * Set the shouldSendCallback option
778740 *
779741 * @param {function} callback The callback to run which allows
780742 * introspecting the blob before sending
781743 * @return {Raven}
782744 */
783− setShouldSendCallback: function(callback) {
784− var original = this._globalOptions.shouldSendCallback;
785− this._globalOptions.shouldSendCallback = keepOriginalCallback(
786− original,
787− callback
788− );
789− return this;
790− },
791−
792− /**
745+ setShouldSendCallback: function(callback) {
746+ var original = this._globalOptions.shouldSendCallback;
747+ this._globalOptions.shouldSendCallback = keepOriginalCallback(original, callback);
748+ return this;
749+ },
750+
751+ /**
793752 * Override the default HTTP transport mechanism that transmits data
794753 * to the Sentry server.
795754 *
@@ -798,438 +757,443 @@ · 2 unmodified lines
798757 *
799758 * @return {Raven}
800759 */
801− setTransport: function(transport) {
802− this._globalOptions.transport = transport;
760+ setTransport: function(transport) {
761+ this._globalOptions.transport = transport;
803762
804− return this;
805− },
763+ return this;
764+ },
806765
807− /*
766+ /*
808767 * Get the latest raw exception that was captured by Raven.
809768 *
810769 * @return {error}
811770 */
812− lastException: function() {
813− return this._lastCapturedException;
814− },
771+ lastException: function() {
772+ return this._lastCapturedException;
773+ },
815774
816− /*
775+ /*
817776 * Get the last event id
818777 *
819778 * @return {string}
820779 */
821− lastEventId: function() {
822− return this._lastEventId;
823− },
780+ lastEventId: function() {
781+ return this._lastEventId;
782+ },
824783
825− /*
784+ /*
826785 * Determine if Raven is setup and ready to go.
827786 *
828787 * @return {boolean}
829788 */
830− isSetup: function() {
831− if (!this._hasJSON) return false; // needs JSON support
832− if (!this._globalServer) {
833− if (!this.ravenNotConfiguredError) {
834− this.ravenNotConfiguredError = true;
835− this._logDebug('error', 'Error: Raven has not been configured.');
836− }
837− return false;
838− }
839− return true;
840− },
789+ isSetup: function() {
790+ if (!this._hasJSON) return false; // needs JSON support
791+ if (!this._globalServer) {
792+ if (!this.ravenNotConfiguredError) {
793+ this.ravenNotConfiguredError = true;
794+ this._logDebug('error', 'Error: Raven has not been configured.');
795+ }
796+ return false;
797+ }
798+ return true;
799+ },
841800
842− afterLoad: function() {
843− // TODO: remove window dependence?
801+ afterLoad: function() {
802+ // TODO: remove window dependence?
844803
845− // Attempt to initialize Raven on load
846− var RavenConfig = _window.RavenConfig;
847− if (RavenConfig) {
848− this.config(RavenConfig.dsn, RavenConfig.config).install();
849− }
850− },
804+ // Attempt to initialize Raven on load
805+ var RavenConfig = _window.RavenConfig;
806+ if (RavenConfig) {
807+ this.config(RavenConfig.dsn, RavenConfig.config).install();
808+ }
809+ },
851810
852− showReportDialog: function(options) {
853− if (
854− !_document // doesn't work without a document (React native)
855− )
856− return;
811+ showReportDialog: function(options) {
812+ if (
813+ !_document // doesn't work without a document (React native)
814+ )
815+ return;
857816
858− options = options || {};
817+ options = options || {};
859818
860− var lastEventId = options.eventId || this.lastEventId();
861− if (!lastEventId) {
862− throw new RavenConfigError('Missing eventId');
863− }
819+ var lastEventId = options.eventId || this.lastEventId();
820+ if (!lastEventId) {
821+ throw new RavenConfigError('Missing eventId');
822+ }
864823
865− var dsn = options.dsn || this._dsn;
866− if (!dsn) {
867− throw new RavenConfigError('Missing DSN');
868− }
824+ var dsn = options.dsn || this._dsn;
825+ if (!dsn) {
826+ throw new RavenConfigError('Missing DSN');
827+ }
869828
870− var encode = encodeURIComponent;
871− var qs = '';
872− qs += '?eventId=' + encode(lastEventId);
873− qs += '&dsn=' + encode(dsn);
829+ var encode = encodeURIComponent;
830+ var qs = '';
831+ qs += '?eventId=' + encode(lastEventId);
832+ qs += '&dsn=' + encode(dsn);
874833
875− var user = options.user || this._globalContext.user;
876− if (user) {
877− if (user.name) qs += '&name=' + encode(user.name);
878− if (user.email) qs += '&email=' + encode(user.email);
879− }
834+ var user = options.user || this._globalContext.user;
835+ if (user) {
836+ if (user.name) qs += '&name=' + encode(user.name);
837+ if (user.email) qs += '&email=' + encode(user.email);
838+ }
880839
881− var globalServer = this._getGlobalServer(this._parseDSN(dsn));
882−
883− var script = _document.createElement('script');
884− script.async = true;
885− script.src = globalServer + '/api/embed/error-page/' + qs;
886− (_document.head || _document.body).appendChild(script);
887− },
888−
889− /**** Private functions ****/
890− _ignoreNextOnError: function() {
891− var self = this;
892− this._ignoreOnError += 1;
893− setTimeout(function() {
894− // onerror should trigger before setTimeout
895− self._ignoreOnError -= 1;
896− });
897− },
840+ var globalServer = this._getGlobalServer(this._parseDSN(dsn));
898841
899− _triggerEvent: function(eventType, options) {
900− // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
901− var evt, key;
842+ var script = _document.createElement('script');
843+ script.async = true;
844+ script.src = globalServer + '/api/embed/error-page/' + qs;
845+ (_document.head || _document.body).appendChild(script);
846+ },
902847
903− if (!this._hasDocument) return;
848+ /**** Private functions ****/
849+ _ignoreNextOnError: function() {
850+ var self = this;
851+ this._ignoreOnError += 1;
852+ setTimeout(function() {
853+ // onerror should trigger before setTimeout
854+ self._ignoreOnError -= 1;
855+ });
856+ },
904857
905− options = options || {};
858+ _triggerEvent: function(eventType, options) {
859+ // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
860+ var evt, key;
906861
907− eventType =
908− 'raven' + eventType.substr(0, 1).toUpperCase() + eventType.substr(1);
862+ if (!this._hasDocument) return;
909863
910− if (_document.createEvent) {
911− evt = _document.createEvent('HTMLEvents');
912− evt.initEvent(eventType, true, true);
913− } else {
914− evt = _document.createEventObject();
915− evt.eventType = eventType;
916− }
864+ options = options || {};
917865
918− for (key in options)
919− if (hasKey(options, key)) {
920− evt[key] = options[key];
921− }
866+ eventType = 'raven' + eventType.substr(0, 1).toUpperCase() + eventType.substr(1);
922867
923− if (_document.createEvent) {
924− // IE9 if standards
925− _document.dispatchEvent(evt);
926− } else {
927− // IE8 regardless of Quirks or Standards
928− // IE9 if quirks
929− try {
930− _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
931− } catch (e) {
932− // Do nothing
933− }
934− }
935− },
868+ if (_document.createEvent) {
869+ evt = _document.createEvent('HTMLEvents');
870+ evt.initEvent(eventType, true, true);
871+ } else {
872+ evt = _document.createEventObject();
873+ evt.eventType = eventType;
874+ }
875+
876+ for (key in options)
877+ if (hasKey(options, key)) {
878+ evt[key] = options[key];
879+ }
880+
881+ if (_document.createEvent) {
882+ // IE9 if standards
883+ _document.dispatchEvent(evt);
884+ } else {
885+ // IE8 regardless of Quirks or Standards
886+ // IE9 if quirks
887+ try {
888+ _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
889+ } catch (e) {
890+ // Do nothing
891+ }
892+ }
893+ },
936894
937− /**
895+ /**
938896 * Wraps addEventListener to capture UI breadcrumbs
939897 * @param evtName the event name (e.g. "click")
940898 * @returns {Function}
941899 * @private
942900 */
943− _breadcrumbEventHandler: function(evtName) {
944− var self = this;
945− return function(evt) {
946− // reset keypress timeout; e.g. triggering a 'click' after
947− // a 'keypress' will reset the keypress debounce so that a new
948− // set of keypresses can be recorded
949− self._keypressTimeout = null;
950−
951− // It's possible this handler might trigger multiple times for the same
952− // event (e.g. event propagation through node ancestors). Ignore if we've
953− // already captured the event.
954− if (self._lastCapturedEvent === evt) return;
955−
956− self._lastCapturedEvent = evt;
957−
958− // try/catch both:
959− // - accessing evt.target (see getsentry/raven-js#838, #768)
960− // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
961− // can throw an exception in some circumstances.
962− var target;
963− try {
964− target = htmlTreeAsString(evt.target);
965− } catch (e) {
966− target = '<unknown>';
967− }
901+ _breadcrumbEventHandler: function(evtName) {
902+ var self = this;
903+ return function(evt) {
904+ // reset keypress timeout; e.g. triggering a 'click' after
905+ // a 'keypress' will reset the keypress debounce so that a new
906+ // set of keypresses can be recorded
907+ self._keypressTimeout = null;
908+
909+ // It's possible this handler might trigger multiple times for the same
910+ // event (e.g. event propagation through node ancestors). Ignore if we've
911+ // already captured the event.
912+ if (self._lastCapturedEvent === evt) return;
913+
914+ self._lastCapturedEvent = evt;
915+
916+ // try/catch both:
917+ // - accessing evt.target (see getsentry/raven-js#838, #768)
918+ // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
919+ // can throw an exception in some circumstances.
920+ var target;
921+ try {
922+ target = htmlTreeAsString(evt.target);
923+ } catch (e) {
924+ target = '<unknown>';
925+ }
968926
969− self.captureBreadcrumb({
970− category: 'ui.' + evtName, // e.g. ui.click, ui.input
971− message: target
972− });
973− };
974− },
927+ self.captureBreadcrumb({
928+ category: 'ui.' + evtName, // e.g. ui.click, ui.input
929+ message: target
930+ });
931+ };
932+ },
975933
976− /**
934+ /**
977935 * Wraps addEventListener to capture keypress UI events
978936 * @returns {Function}
979937 * @private
980938 */
981− _keypressEventHandler: function() {
982− var self = this,
983− debounceDuration = 1000; // milliseconds
984−
985− // TODO: if somehow user switches keypress target before
986− // debounce timeout is triggered, we will only capture
987− // a single breadcrumb from the FIRST target (acceptable?)
988− return function(evt) {
989− var target;
990− try {
991− target = evt.target;
992− } catch (e) {
993− // just accessing event properties can throw an exception in some rare circumstances
994− // see: https://github.com/getsentry/raven-js/issues/838
995− return;
996− }
997− var tagName = target && target.tagName;
998−
999− // only consider keypress events on actual input elements
1000− // this will disregard keypresses targeting body (e.g. tabbing
1001− // through elements, hotkeys, etc)
1002− if (
1003− !tagName ||
1004− (tagName !== 'INPUT' &&
1005− tagName !== 'TEXTAREA' &&
1006− !target.isContentEditable)
1007− )
1008− return;
1009−
1010− // record first keypress in a series, but ignore subsequent
1011− // keypresses until debounce clears
1012− var timeout = self._keypressTimeout;
1013− if (!timeout) {
1014− self._breadcrumbEventHandler('input')(evt);
1015− }
1016− clearTimeout(timeout);
1017− self._keypressTimeout = setTimeout(function() {
1018− self._keypressTimeout = null;
1019− }, debounceDuration);
1020− };
1021− },
1022−
1023− /**
939+ _keypressEventHandler: function() {
940+ var self = this,
941+ debounceDuration = 1000; // milliseconds
942+
943+ // TODO: if somehow user switches keypress target before
944+ // debounce timeout is triggered, we will only capture
945+ // a single breadcrumb from the FIRST target (acceptable?)
946+ return function(evt) {
947+ var target;
948+ try {
949+ target = evt.target;
950+ } catch (e) {
951+ // just accessing event properties can throw an exception in some rare circumstances
952+ // see: https://github.com/getsentry/raven-js/issues/838
953+ return;
954+ }
955+ var tagName = target && target.tagName;
956+
957+ // only consider keypress events on actual input elements
958+ // this will disregard keypresses targeting body (e.g. tabbing
959+ // through elements, hotkeys, etc)
960+ if (
961+ !tagName ||
962+ (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)
963+ )
964+ return;
965+
966+ // record first keypress in a series, but ignore subsequent
967+ // keypresses until debounce clears
968+ var timeout = self._keypressTimeout;
969+ if (!timeout) {
970+ self._breadcrumbEventHandler('input')(evt);
971+ }
972+ clearTimeout(timeout);
973+ self._keypressTimeout = setTimeout(function() {
974+ self._keypressTimeout = null;
975+ }, debounceDuration);
976+ };
977+ },
978+
979+ /**
1024980 * Captures a breadcrumb of type "navigation", normalizing input URLs
1025981 * @param to the originating URL
1026982 * @param from the target URL
1027983 * @private
1028984 */
1029− _captureUrlChange: function(from, to) {
1030− var parsedLoc = parseUrl(this._location.href);
1031− var parsedTo = parseUrl(to);
1032− var parsedFrom = parseUrl(from);
1033−
1034− // because onpopstate only tells you the "new" (to) value of location.href, and
1035− // not the previous (from) value, we need to track the value of the current URL
1036− // state ourselves
1037− this._lastHref = to;
1038−
1039− // Use only the path component of the URL if the URL matches the current
1040− // document (almost all the time when using pushState)
1041− if (
1042− parsedLoc.protocol === parsedTo.protocol &&
1043− parsedLoc.host === parsedTo.host
1044− )
1045− to = parsedTo.relative;
1046− if (
1047− parsedLoc.protocol === parsedFrom.protocol &&
1048− parsedLoc.host === parsedFrom.host
1049− )
1050− from = parsedFrom.relative;
1051−
1052− this.captureBreadcrumb({
1053− category: 'navigation',
1054− data: {
1055− to: to,
1056− from: from
1057− }
1058− });
1059− },
985+ _captureUrlChange: function(from, to) {
986+ var parsedLoc = parseUrl(this._location.href);
987+ var parsedTo = parseUrl(to);
988+ var parsedFrom = parseUrl(from);
989+
990+ // because onpopstate only tells you the "new" (to) value of location.href, and
991+ // not the previous (from) value, we need to track the value of the current URL
992+ // state ourselves
993+ this._lastHref = to;
994+
995+ // Use only the path component of the URL if the URL matches the current
996+ // document (almost all the time when using pushState)
997+ if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host)
998+ to = parsedTo.relative;
999+ if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host)
1000+ from = parsedFrom.relative;
1001+
1002+ this.captureBreadcrumb({
1003+ category: 'navigation',
1004+ data: {
1005+ to: to,
1006+ from: from
1007+ }
1008+ });
1009+ },
1010+
1011+ _patchFunctionToString: function() {
1012+ var self = this;
1013+ self._originalFunctionToString = Function.prototype.toString;
1014+ // eslint-disable-next-line no-extend-native
1015+ Function.prototype.toString = function() {
1016+ if (typeof this === 'function' && this.__raven__) {
1017+ return self._originalFunctionToString.apply(this.__orig__, arguments);
1018+ }
1019+ return self._originalFunctionToString.apply(this, arguments);
1020+ };
1021+ },
1022+
1023+ _unpatchFunctionToString: function() {
1024+ if (this._originalFunctionToString) {
1025+ // eslint-disable-next-line no-extend-native
1026+ Function.prototype.toString = this._originalFunctionToString;
1027+ }
1028+ },
10601029
1061− /**
1030+ /**
10621031 * Wrap timer functions and event targets to catch errors and provide
10631032 * better metadata.
10641033 */
1065− _instrumentTryCatch: function() {
1066− var self = this;
1067−
1068− var wrappedBuiltIns = self._wrappedBuiltIns;
1069−
1070− function wrapTimeFn(orig) {
1071− return function(fn, t) {
1072− // preserve arity
1073− // Make a copy of the arguments to prevent deoptimization
1074− // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
1075− var args = new Array(arguments.length);
1076− for (var i = 0; i < args.length; ++i) {
1077− args[i] = arguments[i];
1078− }
1079− var originalCallback = args[0];
1080− if (isFunction(originalCallback)) {
1081− args[0] = self.wrap(originalCallback);
1082− }
1083−
1084− // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
1085− // also supports only two arguments and doesn't care what this is, so we
1086− // can just call the original function directly.
1087− if (orig.apply) {
1088− return orig.apply(this, args);
1089− } else {
1090− return orig(args[0], args[1]);
1091− }
1092− };
1093− }
1034+ _instrumentTryCatch: function() {
1035+ var self = this;
1036+
1037+ var wrappedBuiltIns = self._wrappedBuiltIns;
1038+
1039+ function wrapTimeFn(orig) {
1040+ return function(fn, t) {
1041+ // preserve arity
1042+ // Make a copy of the arguments to prevent deoptimization
1043+ // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
1044+ var args = new Array(arguments.length);
1045+ for (var i = 0; i < args.length; ++i) {
1046+ args[i] = arguments[i];
1047+ }
1048+ var originalCallback = args[0];
1049+ if (isFunction(originalCallback)) {
1050+ args[0] = self.wrap(originalCallback);
1051+ }
1052+
1053+ // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
1054+ // also supports only two arguments and doesn't care what this is, so we
1055+ // can just call the original function directly.
1056+ if (orig.apply) {
1057+ return orig.apply(this, args);
1058+ } else {
1059+ return orig(args[0], args[1]);
1060+ }
1061+ };
1062+ }
1063+
1064+ var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
1065+
1066+ function wrapEventTarget(global) {
1067+ var proto = _window[global] && _window[global].prototype;
1068+ if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
1069+ fill(
1070+ proto,
1071+ 'addEventListener',
1072+ function(orig) {
1073+ return function(evtName, fn, capture, secure) {
1074+ // preserve arity
1075+ try {
1076+ if (fn && fn.handleEvent) {
1077+ fn.handleEvent = self.wrap(fn.handleEvent);
1078+ }
1079+ } catch (err) {
1080+ // can sometimes get 'Permission denied to access property "handle Event'
1081+ }
10941082
1095− var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
1096−
1097− function wrapEventTarget(global) {
1098− var proto = _window[global] && _window[global].prototype;
1099− if (
1100− proto &&
1101− proto.hasOwnProperty &&
1102− proto.hasOwnProperty('addEventListener')
1103− ) {
1104− fill(
1105− proto,
1106− 'addEventListener',
1107− function(orig) {
1108− return function(evtName, fn, capture, secure) {
1109− // preserve arity
1110− try {
1111− if (fn && fn.handleEvent) {
1112− fn.handleEvent = self.wrap(fn.handleEvent);
1113− }
1114− } catch (err) {
1115− // can sometimes get 'Permission denied to access property "handle Event'
1116− }
1117−
1118− // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
1119− // so that we don't have more than one wrapper function
1120− var before, clickHandler, keypressHandler;
1121−
1122− if (
1123− autoBreadcrumbs &&
1124− autoBreadcrumbs.dom &&
1125− (global === 'EventTarget' || global === 'Node')
1126− ) {
1127− // NOTE: generating multiple handlers per addEventListener invocation, should
1128− // revisit and verify we can just use one (almost certainly)
1129− clickHandler = self._breadcrumbEventHandler('click');
1130− keypressHandler = self._keypressEventHandler();
1131− before = function(evt) {
1132− // need to intercept every DOM event in `before` argument, in case that
1133− // same wrapped method is re-used for different events (e.g. mousemove THEN click)
1134− // see #724
1135− if (!evt) return;
1136−
1137− var eventType;
1138− try {
1139− eventType = evt.type;
1140− } catch (e) {
1141− // just accessing event properties can throw an exception in some rare circumstances
1142− // see: https://github.com/getsentry/raven-js/issues/838
1143− return;
1144− }
1145− if (eventType === 'click') return clickHandler(evt);
1146− else if (eventType === 'keypress')
1147− return keypressHandler(evt);
1148− };
1149− }
1150− return orig.call(
1151− this,
1152− evtName,
1153− self.wrap(fn, undefined, before),
1154− capture,
1155− secure
1156− );
1157− };
1158− },
1159− wrappedBuiltIns
1160− );
1161− fill(
1162− proto,
1163− 'removeEventListener',
1164− function(orig) {
1165− return function(evt, fn, capture, secure) {
1166− try {
1167− fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn);
1168− } catch (e) {
1169− // ignore, accessing __raven_wrapper__ will throw in some Selenium environments
1170− }
1171− return orig.call(this, evt, fn, capture, secure);
1172− };
1173− },
1174− wrappedBuiltIns
1175− );
1083+ // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
1084+ // so that we don't have more than one wrapper function
1085+ var before, clickHandler, keypressHandler;
1086+
1087+ if (
1088+ autoBreadcrumbs &&
1089+ autoBreadcrumbs.dom &&
1090+ (global === 'EventTarget' || global === 'Node')
1091+ ) {
1092+ // NOTE: generating multiple handlers per addEventListener invocation, should
1093+ // revisit and verify we can just use one (almost certainly)
1094+ clickHandler = self._breadcrumbEventHandler('click');
1095+ keypressHandler = self._keypressEventHandler();
1096+ before = function(evt) {
1097+ // need to intercept every DOM event in `before` argument, in case that
1098+ // same wrapped method is re-used for different events (e.g. mousemove THEN click)
1099+ // see #724
1100+ if (!evt) return;
1101+
1102+ var eventType;
1103+ try {
1104+ eventType = evt.type;
1105+ } catch (e) {
1106+ // just accessing event properties can throw an exception in some rare circumstances
1107+ // see: https://github.com/getsentry/raven-js/issues/838
1108+ return;
11761109 }
1177− }
1110+ if (eventType === 'click') return clickHandler(evt);
1111+ else if (eventType === 'keypress') return keypressHandler(evt);
1112+ };
1113+ }
1114+ return orig.call(
1115+ this,
1116+ evtName,
1117+ self.wrap(fn, undefined, before),
1118+ capture,
1119+ secure
1120+ );
1121+ };
1122+ },
1123+ wrappedBuiltIns
1124+ );
1125+ fill(
1126+ proto,
1127+ 'removeEventListener',
1128+ function(orig) {
1129+ return function(evt, fn, capture, secure) {
1130+ try {
1131+ fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn);
1132+ } catch (e) {
1133+ // ignore, accessing __raven_wrapper__ will throw in some Selenium environments
1134+ }
1135+ return orig.call(this, evt, fn, capture, secure);
1136+ };
1137+ },
1138+ wrappedBuiltIns
1139+ );
1140+ }
1141+ }
11781142
1179− fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
1180− fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
1181− if (_window.requestAnimationFrame) {
1182− fill(
1183− _window,
1184− 'requestAnimationFrame',
1185− function(orig) {
1186− return function(cb) {
1187− return orig(self.wrap(cb));
1188− };
1189− },
1190− wrappedBuiltIns
1191− );
1192− }
1143+ fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
1144+ fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
1145+ if (_window.requestAnimationFrame) {
1146+ fill(
1147+ _window,
1148+ 'requestAnimationFrame',
1149+ function(orig) {
1150+ return function(cb) {
1151+ return orig(self.wrap(cb));
1152+ };
1153+ },
1154+ wrappedBuiltIns
1155+ );
1156+ }
11931157
1194− // event targets borrowed from bugsnag-js:
1195− // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666
1196− var eventTargets = [
1197− 'EventTarget',
1198− 'Window',
1199− 'Node',
1200− 'ApplicationCache',
1201− 'AudioTrackList',
1202− 'ChannelMergerNode',
1203− 'CryptoOperation',
1204− 'EventSource',
1205− 'FileReader',
1206− 'HTMLUnknownElement',
1207− 'IDBDatabase',
1208− 'IDBRequest',
1209− 'IDBTransaction',
1210− 'KeyOperation',
1211− 'MediaController',
1212− 'MessagePort',
1213− 'ModalWindow',
1214− 'Notification',
1215− 'SVGElementInstance',
1216− 'Screen',
1217− 'TextTrack',
1218− 'TextTrackCue',
1219− 'TextTrackList',
1220− 'WebSocket',
1221− 'WebSocketWorker',
1222− 'Worker',
1223− 'XMLHttpRequest',
1224− 'XMLHttpRequestEventTarget',
1225− 'XMLHttpRequestUpload'
1226− ];
1227− for (var i = 0; i < eventTargets.length; i++) {
1228− wrapEventTarget(eventTargets[i]);
1229− }
1230− },
1158+ // event targets borrowed from bugsnag-js:
1159+ // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666
1160+ var eventTargets = [
1161+ 'EventTarget',
1162+ 'Window',
1163+ 'Node',
1164+ 'ApplicationCache',
1165+ 'AudioTrackList',
1166+ 'ChannelMergerNode',
1167+ 'CryptoOperation',
1168+ 'EventSource',
1169+ 'FileReader',
1170+ 'HTMLUnknownElement',
1171+ 'IDBDatabase',
1172+ 'IDBRequest',
1173+ 'IDBTransaction',
1174+ 'KeyOperation',
1175+ 'MediaController',
1176+ 'MessagePort',
1177+ 'ModalWindow',
1178+ 'Notification',
1179+ 'SVGElementInstance',
1180+ 'Screen',
1181+ 'TextTrack',
1182+ 'TextTrackCue',
1183+ 'TextTrackList',
1184+ 'WebSocket',
1185+ 'WebSocketWorker',
1186+ 'Worker',
1187+ 'XMLHttpRequest',
1188+ 'XMLHttpRequestEventTarget',
1189+ 'XMLHttpRequestUpload'
1190+ ];
1191+ for (var i = 0; i < eventTargets.length; i++) {
1192+ wrapEventTarget(eventTargets[i]);
1193+ }
1194+ },
12311195
1232− /**
1196+ /**
12331197 * Instrument browser built-ins w/ breadcrumb capturing
12341198 * - XMLHttpRequests
12351199 * - DOM interactions (click/typing)
@@ -1238,546 +1202,515 @@ · 2 unmodified lines
12381202 *
12391203 * Can be disabled or individually configured via the `autoBreadcrumbs` config option
12401204 */
1241− _instrumentBreadcrumbs: function() {
1242− var self = this;
1243− var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
1205+ _instrumentBreadcrumbs: function() {
1206+ var self = this;
1207+ var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
12441208
1245− var wrappedBuiltIns = self._wrappedBuiltIns;
1209+ var wrappedBuiltIns = self._wrappedBuiltIns;
12461210
1247− function wrapProp(prop, xhr) {
1248− if (prop in xhr && isFunction(xhr[prop])) {
1249− fill(xhr, prop, function(orig) {
1250− return self.wrap(orig);
1251− }); // intentionally don't track filled methods on XHR instances
1252− }
1253− }
1211+ function wrapProp(prop, xhr) {
1212+ if (prop in xhr && isFunction(xhr[prop])) {
1213+ fill(xhr, prop, function(orig) {
1214+ return self.wrap(orig);
1215+ }); // intentionally don't track filled methods on XHR instances
1216+ }
1217+ }
12541218
1255− if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
1256− var xhrproto = XMLHttpRequest.prototype;
1257− fill(
1258− xhrproto,
1259− 'open',
1260− function(origOpen) {
1261− return function(method, url) {
1262− // preserve arity
1263−
1264− // if Sentry key appears in URL, don't capture
1265− if (isString(url) && url.indexOf(self._globalKey) === -1) {
1266− this.__raven_xhr = {
1267− method: method,
1268− url: url,
1269− status_code: null
1270− };
1271− }
1272−
1273− return origOpen.apply(this, arguments);
1274− };
1275− },
1276− wrappedBuiltIns
1277− );
1278−
1279− fill(
1280− xhrproto,
1281− 'send',
1282− function(origSend) {
1283− return function(data) {
1284− // preserve arity
1285− var xhr = this;
1286−
1287− function onreadystatechangeHandler() {
1288− if (xhr.__raven_xhr && xhr.readyState === 4) {
1289− try {
1290− // touching statusCode in some platforms throws
1291− // an exception
1292− xhr.__raven_xhr.status_code = xhr.status;
1293− } catch (e) {
1294− /* do nothing */
1295− }
1296−
1297− self.captureBreadcrumb({
1298− type: 'http',
1299− category: 'xhr',
1300− data: xhr.__raven_xhr
1301− });
1302− }
1303− }
1304−
1305− var props = ['onload', 'onerror', 'onprogress'];
1306− for (var j = 0; j < props.length; j++) {
1307− wrapProp(props[j], xhr);
1308− }
1309−
1310− if (
1311− 'onreadystatechange' in xhr &&
1312− isFunction(xhr.onreadystatechange)
1313− ) {
1314− fill(
1315− xhr,
1316− 'onreadystatechange',
1317− function(orig) {
1318− return self.wrap(
1319− orig,
1320− undefined,
1321− onreadystatechangeHandler
1322− );
1323− } /* intentionally don't track this instrumentation */
1324− );
1325− } else {
1326− // if onreadystatechange wasn't actually set by the page on this xhr, we
1327− // are free to set our own and capture the breadcrumb
1328− xhr.onreadystatechange = onreadystatechangeHandler;
1329− }
1330−
1331− return origSend.apply(this, arguments);
1332− };
1333− },
1334− wrappedBuiltIns
1335− );
1336− }
1219+ if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
1220+ var xhrproto = XMLHttpRequest.prototype;
1221+ fill(
1222+ xhrproto,
1223+ 'open',
1224+ function(origOpen) {
1225+ return function(method, url) {
1226+ // preserve arity
1227+
1228+ // if Sentry key appears in URL, don't capture
1229+ if (isString(url) && url.indexOf(self._globalKey) === -1) {
1230+ this.__raven_xhr = {
1231+ method: method,
1232+ url: url,
1233+ status_code: null
1234+ };
1235+ }
13371236
1338− if (autoBreadcrumbs.xhr && 'fetch' in _window) {
1339− fill(
1340− _window,
1341− 'fetch',
1342− function(origFetch) {
1343− return function(fn, t) {
1344− // preserve arity
1345− // Make a copy of the arguments to prevent deoptimization
1346− // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
1347− var args = new Array(arguments.length);
1348− for (var i = 0; i < args.length; ++i) {
1349− args[i] = arguments[i];
1350− }
1351−
1352− var fetchInput = args[0];
1353− var method = 'GET';
1354− var url;
1355−
1356− if (typeof fetchInput === 'string') {
1357− url = fetchInput;
1358− } else {
1359− url = fetchInput.url;
1360− if (fetchInput.method) {
1361− method = fetchInput.method;
1362− }
1363− }
1364−
1365− if (args[1] && args[1].method) {
1366− method = args[1].method;
1367− }
1368−
1369− var fetchData = {
1370− method: method,
1371− url: url,
1372− status_code: null
1373− };
1374−
1375− self.captureBreadcrumb({
1376− type: 'http',
1377− category: 'fetch',
1378− data: fetchData
1379− });
1380−
1381− return origFetch.apply(this, args).then(function(response) {
1382− fetchData.status_code = response.status;
1383−
1384− return response;
1385− });
1386− };
1387− },
1388− wrappedBuiltIns
1389− );
1237+ return origOpen.apply(this, arguments);
1238+ };
1239+ },
1240+ wrappedBuiltIns
1241+ );
1242+
1243+ fill(
1244+ xhrproto,
1245+ 'send',
1246+ function(origSend) {
1247+ return function(data) {
1248+ // preserve arity
1249+ var xhr = this;
1250+
1251+ function onreadystatechangeHandler() {
1252+ if (xhr.__raven_xhr && xhr.readyState === 4) {
1253+ try {
1254+ // touching statusCode in some platforms throws
1255+ // an exception
1256+ xhr.__raven_xhr.status_code = xhr.status;
1257+ } catch (e) {
1258+ /* do nothing */
13901259 }
13911260
1392− // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
1393− // to the document. Do this before we instrument addEventListener.
1394− if (autoBreadcrumbs.dom && this._hasDocument) {
1395− if (_document.addEventListener) {
1396− _document.addEventListener(
1397− 'click',
1398− self._breadcrumbEventHandler('click'),
1399− false
1400− );
1401− _document.addEventListener(
1402− 'keypress',
1403− self._keypressEventHandler(),
1404− false
1405− );
1406− } else {
1407− // IE8 Compatibility
1408− _document.attachEvent(
1409− 'onclick',
1410− self._breadcrumbEventHandler('click')
1411− );
1412− _document.attachEvent('onkeypress', self._keypressEventHandler());
1413− }
1414− }
1261+ self.captureBreadcrumb({
1262+ type: 'http',
1263+ category: 'xhr',
1264+ data: xhr.__raven_xhr
1265+ });
1266+ }
1267+ }
14151268
1416− // record navigation (URL) changes
1417− // NOTE: in Chrome App environment, touching history.pushState, *even inside
1418− // a try/catch block*, will cause Chrome to output an error to console.error
1419− // borrowed from: https://github.com/angular/angular.js/pull/13945/files
1420− var chrome = _window.chrome;
1421− var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
1422− var hasPushState =
1423− !isChromePackagedApp && _window.history && history.pushState;
1424− if (autoBreadcrumbs.location && hasPushState) {
1425− // TODO: remove onpopstate handler on uninstall()
1426− var oldOnPopState = _window.onpopstate;
1427− _window.onpopstate = function() {
1428− var currentHref = self._location.href;
1429− self._captureUrlChange(self._lastHref, currentHref);
1430−
1431− if (oldOnPopState) {
1432− return oldOnPopState.apply(this, arguments);
1433− }
1434− };
1435−
1436− fill(
1437− history,
1438− 'pushState',
1439− function(origPushState) {
1440− // note history.pushState.length is 0; intentionally not declaring
1441− // params to preserve 0 arity
1442− return function(/* state, title, url */) {
1443− var url = arguments.length > 2 ? arguments[2] : undefined;
1444−
1445− // url argument is optional
1446− if (url) {
1447− // coerce to string (this is what pushState does)
1448− self._captureUrlChange(self._lastHref, url + '');
1449− }
1450−
1451− return origPushState.apply(this, arguments);
1452− };
1453− },
1454− wrappedBuiltIns
1455− );
1456− }
1269+ var props = ['onload', 'onerror', 'onprogress'];
1270+ for (var j = 0; j < props.length; j++) {
1271+ wrapProp(props[j], xhr);
1272+ }
14571273
1458− if (autoBreadcrumbs.console && 'console' in _window && console.log) {
1459− // console
1460− var consoleMethodCallback = function(msg, data) {
1461− self.captureBreadcrumb({
1462− message: msg,
1463− level: data.level,
1464− category: 'console'
1465− });
1466− };
1467−
1468− each(['debug', 'info', 'warn', 'error', 'log'], function(_, level) {
1469− wrapConsoleMethod(console, level, consoleMethodCallback);
1470− });
1471− }
1472− },
1274+ if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) {
1275+ fill(
1276+ xhr,
1277+ 'onreadystatechange',
1278+ function(orig) {
1279+ return self.wrap(orig, undefined, onreadystatechangeHandler);
1280+ } /* intentionally don't track this instrumentation */
1281+ );
1282+ } else {
1283+ // if onreadystatechange wasn't actually set by the page on this xhr, we
1284+ // are free to set our own and capture the breadcrumb
1285+ xhr.onreadystatechange = onreadystatechangeHandler;
1286+ }
1287+
1288+ return origSend.apply(this, arguments);
1289+ };
1290+ },
1291+ wrappedBuiltIns
1292+ );
1293+ }
14731294
1474− _restoreBuiltIns: function() {
1475− // restore any wrapped builtins
1476− var builtin;
1477− while (this._wrappedBuiltIns.length) {
1478− builtin = this._wrappedBuiltIns.shift();
1295+ if (autoBreadcrumbs.xhr && 'fetch' in _window) {
1296+ fill(
1297+ _window,
1298+ 'fetch',
1299+ function(origFetch) {
1300+ return function(fn, t) {
1301+ // preserve arity
1302+ // Make a copy of the arguments to prevent deoptimization
1303+ // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
1304+ var args = new Array(arguments.length);
1305+ for (var i = 0; i < args.length; ++i) {
1306+ args[i] = arguments[i];
1307+ }
14791308
1480− var obj = builtin[0],
1481− name = builtin[1],
1482− orig = builtin[2];
1309+ var fetchInput = args[0];
1310+ var method = 'GET';
1311+ var url;
14831312
1484− obj[name] = orig;
1485− }
1486− },
1313+ if (typeof fetchInput === 'string') {
1314+ url = fetchInput;
1315+ } else if ('Request' in _window && fetchInput instanceof _window.Request) {
1316+ url = fetchInput.url;
1317+ if (fetchInput.method) {
1318+ method = fetchInput.method;
1319+ }
1320+ } else {
1321+ url = '' + fetchInput;
1322+ }
14871323
1488− _drainPlugins: function() {
1489− var self = this;
1324+ if (args[1] && args[1].method) {
1325+ method = args[1].method;
1326+ }
14901327
1491− // FIX ME TODO
1492− each(this._plugins, function(_, plugin) {
1493− var installer = plugin[0];
1494− var args = plugin[1];
1495− installer.apply(self, [self].concat(args));
1496− });
1497− },
1328+ var fetchData = {
1329+ method: method,
1330+ url: url,
1331+ status_code: null
1332+ };
14981333
1499− _parseDSN: function(str) {
1500− var m = dsnPattern.exec(str),
1501− dsn = {},
1502− i = 7;
1334+ self.captureBreadcrumb({
1335+ type: 'http',
1336+ category: 'fetch',
1337+ data: fetchData
1338+ });
15031339
1504− try {
1505− while (i--) dsn[dsnKeys[i]] = m[i] || '';
1506− } catch (e) {
1507− throw new RavenConfigError('Invalid DSN: ' + str);
1508− }
1340+ return origFetch.apply(this, args).then(function(response) {
1341+ fetchData.status_code = response.status;
15091342
1510− if (dsn.pass && !this._globalOptions.allowSecretKey) {
1511− throw new RavenConfigError(
1512− 'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
1513− );
1514− }
1343+ return response;
1344+ });
1345+ };
1346+ },
1347+ wrappedBuiltIns
1348+ );
1349+ }
15151350
1516− return dsn;
1517− },
1351+ // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
1352+ // to the document. Do this before we instrument addEventListener.
1353+ if (autoBreadcrumbs.dom && this._hasDocument) {
1354+ if (_document.addEventListener) {
1355+ _document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
1356+ _document.addEventListener('keypress', self._keypressEventHandler(), false);
1357+ } else {
1358+ // IE8 Compatibility
1359+ _document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
1360+ _document.attachEvent('onkeypress', self._keypressEventHandler());
1361+ }
1362+ }
15181363
1519− _getGlobalServer: function(uri) {
1520− // assemble the endpoint from the uri pieces
1521− var globalServer = '//' + uri.host + (uri.port ? ':' + uri.port : '');
1364+ // record navigation (URL) changes
1365+ // NOTE: in Chrome App environment, touching history.pushState, *even inside
1366+ // a try/catch block*, will cause Chrome to output an error to console.error
1367+ // borrowed from: https://github.com/angular/angular.js/pull/13945/files
1368+ var chrome = _window.chrome;
1369+ var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
1370+ var hasPushAndReplaceState =
1371+ !isChromePackagedApp &&
1372+ _window.history &&
1373+ history.pushState &&
1374+ history.replaceState;
1375+ if (autoBreadcrumbs.location && hasPushAndReplaceState) {
1376+ // TODO: remove onpopstate handler on uninstall()
1377+ var oldOnPopState = _window.onpopstate;
1378+ _window.onpopstate = function() {
1379+ var currentHref = self._location.href;
1380+ self._captureUrlChange(self._lastHref, currentHref);
1381+
1382+ if (oldOnPopState) {
1383+ return oldOnPopState.apply(this, arguments);
1384+ }
1385+ };
1386+
1387+ var historyReplacementFunction = function(origHistFunction) {
1388+ // note history.pushState.length is 0; intentionally not declaring
1389+ // params to preserve 0 arity
1390+ return function(/* state, title, url */) {
1391+ var url = arguments.length > 2 ? arguments[2] : undefined;
1392+
1393+ // url argument is optional
1394+ if (url) {
1395+ // coerce to string (this is what pushState does)
1396+ self._captureUrlChange(self._lastHref, url + '');
1397+ }
15221398
1523− if (uri.protocol) {
1524− globalServer = uri.protocol + ':' + globalServer;
1525− }
1526− return globalServer;
1527− },
1399+ return origHistFunction.apply(this, arguments);
1400+ };
1401+ };
15281402
1529− _handleOnErrorStackInfo: function() {
1530− // if we are intentionally ignoring errors via onerror, bail out
1531− if (!this._ignoreOnError) {
1532− this._handleStackInfo.apply(this, arguments);
1533− }
1534− },
1403+ fill(history, 'pushState', historyReplacementFunction, wrappedBuiltIns);
1404+ fill(history, 'replaceState', historyReplacementFunction, wrappedBuiltIns);
1405+ }
15351406
1536− _handleStackInfo: function(stackInfo, options) {
1537− var frames = this._prepareFrames(stackInfo, options);
1407+ if (autoBreadcrumbs.console && 'console' in _window && console.log) {
1408+ // console
1409+ var consoleMethodCallback = function(msg, data) {
1410+ self.captureBreadcrumb({
1411+ message: msg,
1412+ level: data.level,
1413+ category: 'console'
1414+ });
1415+ };
1416+
1417+ each(['debug', 'info', 'warn', 'error', 'log'], function(_, level) {
1418+ wrapConsoleMethod(console, level, consoleMethodCallback);
1419+ });
1420+ }
1421+ },
15381422
1539− this._triggerEvent('handle', {
1540− stackInfo: stackInfo,
1541− options: options
1542− });
1423+ _restoreBuiltIns: function() {
1424+ // restore any wrapped builtins
1425+ var builtin;
1426+ while (this._wrappedBuiltIns.length) {
1427+ builtin = this._wrappedBuiltIns.shift();
15431428
1544− this._processException(
1545− stackInfo.name,
1546− stackInfo.message,
1547− stackInfo.url,
1548− stackInfo.lineno,
1549− frames,
1550− options
1551− );
1552− },
1553−
1554− _prepareFrames: function(stackInfo, options) {
1555− var self = this;
1556− var frames = [];
1557− if (stackInfo.stack && stackInfo.stack.length) {
1558− each(stackInfo.stack, function(i, stack) {
1559− var frame = self._normalizeFrame(stack, stackInfo.url);
1560− if (frame) {
1561− frames.push(frame);
1562− }
1563− });
1564−
1565− // e.g. frames captured via captureMessage throw
1566− if (options && options.trimHeadFrames) {
1567− for (
1568− var j = 0;
1569− j < options.trimHeadFrames && j < frames.length;
1570− j++
1571− ) {
1572− frames[j].in_app = false;
1573− }
1574− }
1575− }
1576− frames = frames.slice(0, this._globalOptions.stackTraceLimit);
1577− return frames;
1578− },
1579−
1580− _normalizeFrame: function(frame, stackInfoUrl) {
1581− // normalize the frames data
1582− var normalized = {
1583− filename: frame.url,
1584− lineno: frame.line,
1585− colno: frame.column,
1586− function: frame.func || '?'
1587− };
1429+ var obj = builtin[0],
1430+ name = builtin[1],
1431+ orig = builtin[2];
15881432
1589− // Case when we don't have any information about the error
1590− // E.g. throwing a string or raw object, instead of an `Error` in Firefox
1591− // Generating synthetic error doesn't add any value here
1592− //
1593− // We should probably somehow let a user know that they should fix their code
1594− if (!frame.url) {
1595− normalized.filename = stackInfoUrl; // fallback to whole stacks url from onerror handler
1596− }
1433+ obj[name] = orig;
1434+ }
1435+ },
1436+
1437+ _drainPlugins: function() {
1438+ var self = this;
1439+
1440+ // FIX ME TODO
1441+ each(this._plugins, function(_, plugin) {
1442+ var installer = plugin[0];
1443+ var args = plugin[1];
1444+ installer.apply(self, [self].concat(args));
1445+ });
1446+ },
1447+
1448+ _parseDSN: function(str) {
1449+ var m = dsnPattern.exec(str),
1450+ dsn = {},
1451+ i = 7;
1452+
1453+ try {
1454+ while (i--) dsn[dsnKeys[i]] = m[i] || '';
1455+ } catch (e) {
1456+ throw new RavenConfigError('Invalid DSN: ' + str);
1457+ }
15971458
1598− normalized.in_app = !// determine if an exception came from outside of our app
1599− // first we check the global includePaths list.
1600− (
1601− (!!this._globalOptions.includePaths.test &&
1602− !this._globalOptions.includePaths.test(normalized.filename)) ||
1603− // Now we check for fun, if the function name is Raven or TraceKit
1604− /(Raven|TraceKit)\./.test(normalized['function']) ||
1605− // finally, we do a last ditch effort and check for raven.min.js
1606− /raven\.(min\.)?js$/.test(normalized.filename)
1607− );
1608−
1609− return normalized;
1610− },
1611−
1612− _processException: function(
1613− type,
1614− message,
1615− fileurl,
1616− lineno,
1617− frames,
1618− options
1619− ) {
1620− var testString = (type || '') + ': ' + (message || '');
1621−
1622− if (
1623− !!this._globalOptions.ignoreErrors.test &&
1624− this._globalOptions.ignoreErrors.test(testString)
1625− )
1626− return;
1627−
1628− var stacktrace;
1629−
1630− if (frames && frames.length) {
1631− fileurl = frames[0].filename || fileurl;
1632− // Sentry expects frames oldest to newest
1633− // and JS sends them as newest to oldest
1634− frames.reverse();
1635− stacktrace = {frames: frames};
1636− } else if (fileurl) {
1637− stacktrace = {
1638− frames: [
1639− {
1640− filename: fileurl,
1641− lineno: lineno,
1642− in_app: true
1643− }
1644− ]
1645− };
1646− }
1459+ if (dsn.pass && !this._globalOptions.allowSecretKey) {
1460+ throw new RavenConfigError(
1461+ 'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
1462+ );
1463+ }
16471464
1648− if (
1649− !!this._globalOptions.ignoreUrls.test &&
1650− this._globalOptions.ignoreUrls.test(fileurl)
1651− )
1652− return;
1653− if (
1654− !!this._globalOptions.whitelistUrls.test &&
1655− !this._globalOptions.whitelistUrls.test(fileurl)
1656− )
1657− return;
1658−
1659− var data = objectMerge(
1660− {
1661− // sentry.interfaces.Exception
1662− exception: {
1663− values: [
1664− {
1665− type: type,
1666− value: message,
1667− stacktrace: stacktrace
1668− }
1669− ]
1670− },
1671− culprit: fileurl
1672− },
1673− options
1674− );
1675−
1676− // Fire away!
1677− this._send(data);
1678− },
1679−
1680− _trimPacket: function(data) {
1681− // For now, we only want to truncate the two different messages
1682− // but this could/should be expanded to just trim everything
1683− var max = this._globalOptions.maxMessageLength;
1684− if (data.message) {
1685− data.message = truncate(data.message, max);
1686− }
1687− if (data.exception) {
1688− var exception = data.exception.values[0];
1689− exception.value = truncate(exception.value, max);
1690− }
1465+ return dsn;
1466+ },
16911467
1692− var request = data.request;
1693− if (request) {
1694− if (request.url) {
1695− request.url = truncate(request.url, this._globalOptions.maxUrlLength);
1696− }
1697− if (request.Referer) {
1698− request.Referer = truncate(
1699− request.Referer,
1700− this._globalOptions.maxUrlLength
1701− );
1702− }
1703− }
1468+ _getGlobalServer: function(uri) {
1469+ // assemble the endpoint from the uri pieces
1470+ var globalServer = '//' + uri.host + (uri.port ? ':' + uri.port : '');
1471+
1472+ if (uri.protocol) {
1473+ globalServer = uri.protocol + ':' + globalServer;
1474+ }
1475+ return globalServer;
1476+ },
1477+
1478+ _handleOnErrorStackInfo: function() {
1479+ // if we are intentionally ignoring errors via onerror, bail out
1480+ if (!this._ignoreOnError) {
1481+ this._handleStackInfo.apply(this, arguments);
1482+ }
1483+ },
1484+
1485+ _handleStackInfo: function(stackInfo, options) {
1486+ var frames = this._prepareFrames(stackInfo, options);
1487+
1488+ this._triggerEvent('handle', {
1489+ stackInfo: stackInfo,
1490+ options: options
1491+ });
1492+
1493+ this._processException(
1494+ stackInfo.name,
1495+ stackInfo.message,
1496+ stackInfo.url,
1497+ stackInfo.lineno,
1498+ frames,
1499+ options
1500+ );
1501+ },
1502+
1503+ _prepareFrames: function(stackInfo, options) {
1504+ var self = this;
1505+ var frames = [];
1506+ if (stackInfo.stack && stackInfo.stack.length) {
1507+ each(stackInfo.stack, function(i, stack) {
1508+ var frame = self._normalizeFrame(stack, stackInfo.url);
1509+ if (frame) {
1510+ frames.push(frame);
1511+ }
1512+ });
1513+
1514+ // e.g. frames captured via captureMessage throw
1515+ if (options && options.trimHeadFrames) {
1516+ for (var j = 0; j < options.trimHeadFrames && j < frames.length; j++) {
1517+ frames[j].in_app = false;
1518+ }
1519+ }
1520+ }
1521+ frames = frames.slice(0, this._globalOptions.stackTraceLimit);
1522+ return frames;
1523+ },
1524+
1525+ _normalizeFrame: function(frame, stackInfoUrl) {
1526+ // normalize the frames data
1527+ var normalized = {
1528+ filename: frame.url,
1529+ lineno: frame.line,
1530+ colno: frame.column,
1531+ function: frame.func || '?'
1532+ };
1533+
1534+ // Case when we don't have any information about the error
1535+ // E.g. throwing a string or raw object, instead of an `Error` in Firefox
1536+ // Generating synthetic error doesn't add any value here
1537+ //
1538+ // We should probably somehow let a user know that they should fix their code
1539+ if (!frame.url) {
1540+ normalized.filename = stackInfoUrl; // fallback to whole stacks url from onerror handler
1541+ }
1542+
1543+ normalized.in_app = !// determine if an exception came from outside of our app
1544+ // first we check the global includePaths list.
1545+ (
1546+ (!!this._globalOptions.includePaths.test &&
1547+ !this._globalOptions.includePaths.test(normalized.filename)) ||
1548+ // Now we check for fun, if the function name is Raven or TraceKit
1549+ /(Raven|TraceKit)\./.test(normalized['function']) ||
1550+ // finally, we do a last ditch effort and check for raven.min.js
1551+ /raven\.(min\.)?js$/.test(normalized.filename)
1552+ );
1553+
1554+ return normalized;
1555+ },
1556+
1557+ _processException: function(type, message, fileurl, lineno, frames, options) {
1558+ var prefixedMessage = (type ? type + ': ' : '') + (message || '');
1559+ if (
1560+ !!this._globalOptions.ignoreErrors.test &&
1561+ (this._globalOptions.ignoreErrors.test(message) ||
1562+ this._globalOptions.ignoreErrors.test(prefixedMessage))
1563+ ) {
1564+ return;
1565+ }
1566+
1567+ var stacktrace;
1568+
1569+ if (frames && frames.length) {
1570+ fileurl = frames[0].filename || fileurl;
1571+ // Sentry expects frames oldest to newest
1572+ // and JS sends them as newest to oldest
1573+ frames.reverse();
1574+ stacktrace = {frames: frames};
1575+ } else if (fileurl) {
1576+ stacktrace = {
1577+ frames: [
1578+ {
1579+ filename: fileurl,
1580+ lineno: lineno,
1581+ in_app: true
1582+ }
1583+ ]
1584+ };
1585+ }
1586+
1587+ if (
1588+ !!this._globalOptions.ignoreUrls.test &&
1589+ this._globalOptions.ignoreUrls.test(fileurl)
1590+ ) {
1591+ return;
1592+ }
17041593
1705− if (data.breadcrumbs && data.breadcrumbs.values)
1706− this._trimBreadcrumbs(data.breadcrumbs);
1594+ if (
1595+ !!this._globalOptions.whitelistUrls.test &&
1596+ !this._globalOptions.whitelistUrls.test(fileurl)
1597+ ) {
1598+ return;
1599+ }
1600+
1601+ var data = objectMerge(
1602+ {
1603+ // sentry.interfaces.Exception
1604+ exception: {
1605+ values: [
1606+ {
1607+ type: type,
1608+ value: message,
1609+ stacktrace: stacktrace
1610+ }
1611+ ]
1612+ },
1613+ culprit: fileurl
1614+ },
1615+ options
1616+ );
1617+
1618+ // Fire away!
1619+ this._send(data);
1620+ },
1621+
1622+ _trimPacket: function(data) {
1623+ // For now, we only want to truncate the two different messages
1624+ // but this could/should be expanded to just trim everything
1625+ var max = this._globalOptions.maxMessageLength;
1626+ if (data.message) {
1627+ data.message = truncate(data.message, max);
1628+ }
1629+ if (data.exception) {
1630+ var exception = data.exception.values[0];
1631+ exception.value = truncate(exception.value, max);
1632+ }
17071633
1708− return data;
1709− },
1634+ var request = data.request;
1635+ if (request) {
1636+ if (request.url) {
1637+ request.url = truncate(request.url, this._globalOptions.maxUrlLength);
1638+ }
1639+ if (request.Referer) {
1640+ request.Referer = truncate(request.Referer, this._globalOptions.maxUrlLength);
1641+ }
1642+ }
17101643
1711− /**
1644+ if (data.breadcrumbs && data.breadcrumbs.values)
1645+ this._trimBreadcrumbs(data.breadcrumbs);
1646+
1647+ return data;
1648+ },
1649+
1650+ /**
17121651 * Truncate breadcrumb values (right now just URLs)
17131652 */
1714− _trimBreadcrumbs: function(breadcrumbs) {
1715− // known breadcrumb properties with urls
1716− // TODO: also consider arbitrary prop values that start with (https?)?://
1717− var urlProps = ['to', 'from', 'url'],
1718− urlProp,
1719− crumb,
1720− data;
1721−
1722− for (var i = 0; i < breadcrumbs.values.length; ++i) {
1723− crumb = breadcrumbs.values[i];
1724− if (
1725− !crumb.hasOwnProperty('data') ||
1726− !isObject(crumb.data) ||
1727− objectFrozen(crumb.data)
1728− )
1729− continue;
1730−
1731− data = objectMerge({}, crumb.data);
1732− for (var j = 0; j < urlProps.length; ++j) {
1733− urlProp = urlProps[j];
1734− if (data.hasOwnProperty(urlProp) && data[urlProp]) {
1735− data[urlProp] = truncate(
1736− data[urlProp],
1737− this._globalOptions.maxUrlLength
1738− );
1739− }
1740− }
1741− breadcrumbs.values[i].data = data;
1742− }
1743− },
1653+ _trimBreadcrumbs: function(breadcrumbs) {
1654+ // known breadcrumb properties with urls
1655+ // TODO: also consider arbitrary prop values that start with (https?)?://
1656+ var urlProps = ['to', 'from', 'url'],
1657+ urlProp,
1658+ crumb,
1659+ data;
1660+
1661+ for (var i = 0; i < breadcrumbs.values.length; ++i) {
1662+ crumb = breadcrumbs.values[i];
1663+ if (
1664+ !crumb.hasOwnProperty('data') ||
1665+ !isObject(crumb.data) ||
1666+ objectFrozen(crumb.data)
1667+ )
1668+ continue;
1669+
1670+ data = objectMerge({}, crumb.data);
1671+ for (var j = 0; j < urlProps.length; ++j) {
1672+ urlProp = urlProps[j];
1673+ if (data.hasOwnProperty(urlProp) && data[urlProp]) {
1674+ data[urlProp] = truncate(data[urlProp], this._globalOptions.maxUrlLength);
1675+ }
1676+ }
1677+ breadcrumbs.values[i].data = data;
1678+ }
1679+ },
17441680
1745− _getHttpData: function() {
1746− if (!this._hasNavigator && !this._hasDocument) return;
1747− var httpData = {};
1681+ _getHttpData: function() {
1682+ if (!this._hasNavigator && !this._hasDocument) return;
1683+ var httpData = {};
17481684
1749− if (this._hasNavigator && _navigator.userAgent) {
1750− httpData.headers = {
1751− 'User-Agent': navigator.userAgent
1752− };
1753− }
1685+ if (this._hasNavigator && _navigator.userAgent) {
1686+ httpData.headers = {
1687+ 'User-Agent': navigator.userAgent
1688+ };
1689+ }
17541690
1755− if (this._hasDocument) {
1756− if (_document.location && _document.location.href) {
1757− httpData.url = _document.location.href;
1758− }
1759− if (_document.referrer) {
1760− if (!httpData.headers) httpData.headers = {};
1761− httpData.headers.Referer = _document.referrer;
1762− }
1763− }
1691+ if (this._hasDocument) {
1692+ if (_document.location && _document.location.href) {
1693+ httpData.url = _document.location.href;
1694+ }
1695+ if (_document.referrer) {
1696+ if (!httpData.headers) httpData.headers = {};
1697+ httpData.headers.Referer = _document.referrer;
1698+ }
1699+ }
17641700
1765− return httpData;
1766− },
1701+ return httpData;
1702+ },
17671703
1768− _resetBackoff: function() {
1769− this._backoffDuration = 0;
1770− this._backoffStart = null;
1771− },
1704+ _resetBackoff: function() {
1705+ this._backoffDuration = 0;
1706+ this._backoffStart = null;
1707+ },
17721708
1773− _shouldBackoff: function() {
1774− return (
1775− this._backoffDuration &&
1776− now() - this._backoffStart < this._backoffDuration
1777− );
1778− },
1709+ _shouldBackoff: function() {
1710+ return this._backoffDuration && now() - this._backoffStart < this._backoffDuration;
1711+ },
17791712
1780− /**
1713+ /**
17811714 * Returns true if the in-process data payload matches the signature
17821715 * of the previously-sent data
17831716 *
@@ -1786,362 +1719,449 @@ · 2 unmodified lines
17861719 * other old browsers). This can take the form of an "exception"
17871720 * data object with a single frame (derived from the onerror args).
17881721 */
1789− _isRepeatData: function(current) {
1790− var last = this._lastData;
1791−
1792− if (
1793− !last ||
1794− current.message !== last.message || // defined for captureMessage
1795− current.culprit !== last.culprit // defined for captureException/onerror
1796− )
1797− return false;
1798−
1799− // Stacktrace interface (i.e. from captureMessage)
1800− if (current.stacktrace || last.stacktrace) {
1801− return isSameStacktrace(current.stacktrace, last.stacktrace);
1802− } else if (current.exception || last.exception) {
1803− // Exception interface (i.e. from captureException/onerror)
1804− return isSameException(current.exception, last.exception);
1805− }
1722+ _isRepeatData: function(current) {
1723+ var last = this._lastData;
1724+
1725+ if (
1726+ !last ||
1727+ current.message !== last.message || // defined for captureMessage
1728+ current.culprit !== last.culprit // defined for captureException/onerror
1729+ )
1730+ return false;
1731+
1732+ // Stacktrace interface (i.e. from captureMessage)
1733+ if (current.stacktrace || last.stacktrace) {
1734+ return isSameStacktrace(current.stacktrace, last.stacktrace);
1735+ } else if (current.exception || last.exception) {
1736+ // Exception interface (i.e. from captureException/onerror)
1737+ return isSameException(current.exception, last.exception);
1738+ }
18061739
1807− return true;
1808− },
1740+ return true;
1741+ },
18091742
1810− _setBackoffState: function(request) {
1811− // If we are already in a backoff state, don't change anything
1812− if (this._shouldBackoff()) {
1813− return;
1814− }
1743+ _setBackoffState: function(request) {
1744+ // If we are already in a backoff state, don't change anything
1745+ if (this._shouldBackoff()) {
1746+ return;
1747+ }
18151748
1816− var status = request.status;
1749+ var status = request.status;
1750+
1751+ // 400 - project_id doesn't exist or some other fatal
1752+ // 401 - invalid/revoked dsn
1753+ // 429 - too many requests
1754+ if (!(status === 400 || status === 401 || status === 429)) return;
1755+
1756+ var retry;
1757+ try {
1758+ // If Retry-After is not in Access-Control-Expose-Headers, most
1759+ // browsers will throw an exception trying to access it
1760+ retry = request.getResponseHeader('Retry-After');
1761+ retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
1762+ } catch (e) {
1763+ /* eslint no-empty:0 */
1764+ }
18171765
1818− // 400 - project_id doesn't exist or some other fatal
1819− // 401 - invalid/revoked dsn
1820− // 429 - too many requests
1821− if (!(status === 400 || status === 401 || status === 429)) return;
1766+ this._backoffDuration = retry
1767+ ? // If Sentry server returned a Retry-After value, use it
1768+ retry
1769+ : // Otherwise, double the last backoff duration (starts at 1 sec)
1770+ this._backoffDuration * 2 || 1000;
18221771
1823− var retry;
1824− try {
1825− // If Retry-After is not in Access-Control-Expose-Headers, most
1826− // browsers will throw an exception trying to access it
1827− retry = request.getResponseHeader('Retry-After');
1828− retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
1829− } catch (e) {
1830− /* eslint no-empty:0 */
1831− }
1772+ this._backoffStart = now();
1773+ },
18321774
1833− this._backoffDuration = retry
1834− ? // If Sentry server returned a Retry-After value, use it
1835− retry
1836− : // Otherwise, double the last backoff duration (starts at 1 sec)
1837− this._backoffDuration * 2 || 1000;
1775+ _send: function(data) {
1776+ var globalOptions = this._globalOptions;
18381777
1839− this._backoffStart = now();
1840− },
1778+ var baseData = {
1779+ project: this._globalProject,
1780+ logger: globalOptions.logger,
1781+ platform: 'javascript'
1782+ },
1783+ httpData = this._getHttpData();
18411784
1842− _send: function(data) {
1843− var globalOptions = this._globalOptions;
1785+ if (httpData) {
1786+ baseData.request = httpData;
1787+ }
18441788
1845− var baseData = {
1846− project: this._globalProject,
1847− logger: globalOptions.logger,
1848− platform: 'javascript'
1849− },
1850− httpData = this._getHttpData();
1789+ // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
1790+ if (data.trimHeadFrames) delete data.trimHeadFrames;
18511791
1852− if (httpData) {
1853− baseData.request = httpData;
1854− }
1792+ data = objectMerge(baseData, data);
18551793
1856− // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
1857− if (data.trimHeadFrames) delete data.trimHeadFrames;
1858−
1859− data = objectMerge(baseData, data);
1860−
1861− // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
1862− data.tags = objectMerge(
1863− objectMerge({}, this._globalContext.tags),
1864− data.tags
1865− );
1866− data.extra = objectMerge(
1867− objectMerge({}, this._globalContext.extra),
1868− data.extra
1869− );
1870−
1871− // Send along our own collected metadata with extra
1872− data.extra['session:duration'] = now() - this._startTime;
1873−
1874− if (this._breadcrumbs && this._breadcrumbs.length > 0) {
1875− // intentionally make shallow copy so that additions
1876− // to breadcrumbs aren't accidentally sent in this request
1877− data.breadcrumbs = {
1878− values: [].slice.call(this._breadcrumbs, 0)
1879− };
1880− }
1794+ // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
1795+ data.tags = objectMerge(objectMerge({}, this._globalContext.tags), data.tags);
1796+ data.extra = objectMerge(objectMerge({}, this._globalContext.extra), data.extra);
18811797
1882− // If there are no tags/extra, strip the key from the payload alltogther.
1883− if (isEmptyObject(data.tags)) delete data.tags;
1798+ // Send along our own collected metadata with extra
1799+ data.extra['session:duration'] = now() - this._startTime;
18841800
1885− if (this._globalContext.user) {
1886− // sentry.interfaces.User
1887− data.user = this._globalContext.user;
1888− }
1801+ if (this._breadcrumbs && this._breadcrumbs.length > 0) {
1802+ // intentionally make shallow copy so that additions
1803+ // to breadcrumbs aren't accidentally sent in this request
1804+ data.breadcrumbs = {
1805+ values: [].slice.call(this._breadcrumbs, 0)
1806+ };
1807+ }
18891808
1890− // Include the environment if it's defined in globalOptions
1891− if (globalOptions.environment)
1892− data.environment = globalOptions.environment;
1809+ // If there are no tags/extra, strip the key from the payload alltogther.
1810+ if (isEmptyObject(data.tags)) delete data.tags;
18931811
1894− // Include the release if it's defined in globalOptions
1895− if (globalOptions.release) data.release = globalOptions.release;
1812+ if (this._globalContext.user) {
1813+ // sentry.interfaces.User
1814+ data.user = this._globalContext.user;
1815+ }
18961816
1897− // Include server_name if it's defined in globalOptions
1898− if (globalOptions.serverName) data.server_name = globalOptions.serverName;
1817+ // Include the environment if it's defined in globalOptions
1818+ if (globalOptions.environment) data.environment = globalOptions.environment;
18991819
1900− if (isFunction(globalOptions.dataCallback)) {
1901− data = globalOptions.dataCallback(data) || data;
1902− }
1820+ // Include the release if it's defined in globalOptions
1821+ if (globalOptions.release) data.release = globalOptions.release;
19031822
1904− // Why??????????
1905− if (!data || isEmptyObject(data)) {
1906− return;
1907− }
1823+ // Include server_name if it's defined in globalOptions
1824+ if (globalOptions.serverName) data.server_name = globalOptions.serverName;
19081825
1909− // Check if the request should be filtered or not
1910− if (
1911− isFunction(globalOptions.shouldSendCallback) &&
1912− !globalOptions.shouldSendCallback(data)
1913− ) {
1914− return;
1915− }
1826+ if (isFunction(globalOptions.dataCallback)) {
1827+ data = globalOptions.dataCallback(data) || data;
1828+ }
19161829
1917− // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests),
1918− // so drop requests until "cool-off" period has elapsed.
1919− if (this._shouldBackoff()) {
1920− this._logDebug('warn', 'Raven dropped error due to backoff: ', data);
1921− return;
1922− }
1830+ // Why??????????
1831+ if (!data || isEmptyObject(data)) {
1832+ return;
1833+ }
19231834
1924− if (typeof globalOptions.sampleRate === 'number') {
1925− if (Math.random() < globalOptions.sampleRate) {
1926− this._sendProcessedPayload(data);
1927− }
1928− } else {
1929− this._sendProcessedPayload(data);
1930− }
1931− },
1835+ // Check if the request should be filtered or not
1836+ if (
1837+ isFunction(globalOptions.shouldSendCallback) &&
1838+ !globalOptions.shouldSendCallback(data)
1839+ ) {
1840+ return;
1841+ }
1842+
1843+ // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests),
1844+ // so drop requests until "cool-off" period has elapsed.
1845+ if (this._shouldBackoff()) {
1846+ this._logDebug('warn', 'Raven dropped error due to backoff: ', data);
1847+ return;
1848+ }
19321849
1933− _getUuid: function() {
1934− return uuid4();
1935− },
1850+ if (typeof globalOptions.sampleRate === 'number') {
1851+ if (Math.random() < globalOptions.sampleRate) {
1852+ this._sendProcessedPayload(data);
1853+ }
1854+ } else {
1855+ this._sendProcessedPayload(data);
1856+ }
1857+ },
19361858
1937− _sendProcessedPayload: function(data, callback) {
1938− var self = this;
1939− var globalOptions = this._globalOptions;
1859+ _getUuid: function() {
1860+ return uuid4();
1861+ },
19401862
1941− if (!this.isSetup()) return;
1863+ _sendProcessedPayload: function(data, callback) {
1864+ var self = this;
1865+ var globalOptions = this._globalOptions;
19421866
1943− // Try and clean up the packet before sending by truncating long values
1944− data = this._trimPacket(data);
1867+ if (!this.isSetup()) return;
19451868
1946− // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback,
1947− // but this would require copying an un-truncated copy of the data packet, which can be
1948− // arbitrarily deep (extra_data) -- could be worthwhile? will revisit
1949− if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) {
1950− this._logDebug('warn', 'Raven dropped repeat event: ', data);
1951− return;
1952− }
1869+ // Try and clean up the packet before sending by truncating long values
1870+ data = this._trimPacket(data);
19531871
1954− // Send along an event_id if not explicitly passed.
1955− // This event_id can be used to reference the error within Sentry itself.
1956− // Set lastEventId after we know the error should actually be sent
1957− this._lastEventId = data.event_id || (data.event_id = this._getUuid());
1872+ // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback,
1873+ // but this would require copying an un-truncated copy of the data packet, which can be
1874+ // arbitrarily deep (extra_data) -- could be worthwhile? will revisit
1875+ if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) {
1876+ this._logDebug('warn', 'Raven dropped repeat event: ', data);
1877+ return;
1878+ }
19581879
1959− // Store outbound payload after trim
1960− this._lastData = data;
1880+ // Send along an event_id if not explicitly passed.
1881+ // This event_id can be used to reference the error within Sentry itself.
1882+ // Set lastEventId after we know the error should actually be sent
1883+ this._lastEventId = data.event_id || (data.event_id = this._getUuid());
19611884
1962− this._logDebug('debug', 'Raven about to send:', data);
1885+ // Store outbound payload after trim
1886+ this._lastData = data;
19631887
1964− var auth = {
1965− sentry_version: '7',
1966− sentry_client: 'raven-js/' + this.VERSION,
1967− sentry_key: this._globalKey
1968− };
1888+ this._logDebug('debug', 'Raven about to send:', data);
19691889
1970− if (this._globalSecret) {
1971− auth.sentry_secret = this._globalSecret;
1972− }
1890+ var auth = {
1891+ sentry_version: '7',
1892+ sentry_client: 'raven-js/' + this.VERSION,
1893+ sentry_key: this._globalKey
1894+ };
19731895
1974− var exception = data.exception && data.exception.values[0];
1975− this.captureBreadcrumb({
1976− category: 'sentry',
1977− message: exception
1978− ? (exception.type ? exception.type + ': ' : '') + exception.value
1979− : data.message,
1980− event_id: data.event_id,
1981− level: data.level || 'error' // presume error unless specified
1982− });
1896+ if (this._globalSecret) {
1897+ auth.sentry_secret = this._globalSecret;
1898+ }
19831899
1984− var url = this._globalEndpoint;
1985− (globalOptions.transport || this._makeRequest).call(this, {
1986− url: url,
1987− auth: auth,
1988− data: data,
1989− options: globalOptions,
1990− onSuccess: function success() {
1991− self._resetBackoff();
1992−
1993− self._triggerEvent('success', {
1994− data: data,
1995− src: url
1996− });
1997− callback && callback();
1998− },
1999− onError: function failure(error) {
2000− self._logDebug('error', 'Raven transport failed to send: ', error);
2001−
2002− if (error.request) {
2003− self._setBackoffState(error.request);
2004− }
2005−
2006− self._triggerEvent('failure', {
2007− data: data,
2008− src: url
2009− });
2010− error =
2011− error ||
2012− new Error('Raven send failed (no additional details provided)');
2013− callback && callback(error);
2014− }
2015− });
2016− },
2017−
2018− _makeRequest: function(opts) {
2019− var request = _window.XMLHttpRequest && new _window.XMLHttpRequest();
2020− if (!request) return;
2021−
2022− // if browser doesn't support CORS (e.g. IE7), we are out of luck
2023− var hasCORS =
2024− 'withCredentials' in request || typeof XDomainRequest !== 'undefined';
2025−
2026− if (!hasCORS) return;
2027−
2028− var url = opts.url;
2029−
2030− if ('withCredentials' in request) {
2031− request.onreadystatechange = function() {
2032− if (request.readyState !== 4) {
2033− return;
2034− } else if (request.status === 200) {
2035− opts.onSuccess && opts.onSuccess();
2036− } else if (opts.onError) {
2037− var err = new Error('Sentry error code: ' + request.status);
2038− err.request = request;
2039− opts.onError(err);
2040− }
2041− };
2042− } else {
2043− request = new XDomainRequest();
2044− // xdomainrequest cannot go http -> https (or vice versa),
2045− // so always use protocol relative
2046− url = url.replace(/^https?:/, '');
2047−
2048− // onreadystatechange not supported by XDomainRequest
2049− if (opts.onSuccess) {
2050− request.onload = opts.onSuccess;
2051− }
2052− if (opts.onError) {
2053− request.onerror = function() {
2054− var err = new Error('Sentry error code: XDomainRequest');
2055− err.request = request;
2056− opts.onError(err);
2057− };
2058− }
2059− }
1900+ var exception = data.exception && data.exception.values[0];
1901+
1902+ // only capture 'sentry' breadcrumb is autoBreadcrumbs is truthy
1903+ if (
1904+ this._globalOptions.autoBreadcrumbs &&
1905+ this._globalOptions.autoBreadcrumbs.sentry
1906+ ) {
1907+ this.captureBreadcrumb({
1908+ category: 'sentry',
1909+ message: exception
1910+ ? (exception.type ? exception.type + ': ' : '') + exception.value
1911+ : data.message,
1912+ event_id: data.event_id,
1913+ level: data.level || 'error' // presume error unless specified
1914+ });
1915+ }
20601916
2061− // NOTE: auth is intentionally sent as part of query string (NOT as custom
2062− // HTTP header) so as to avoid preflight CORS requests
2063− request.open('POST', url + '?' + urlencode(opts.auth));
2064− request.send(stringify(opts.data));
2065− },
2066−
2067− _logDebug: function(level) {
2068− if (this._originalConsoleMethods[level] && this.debug) {
2069− // In IE<10 console methods do not have their own 'apply' method
2070− Function.prototype.apply.call(
2071− this._originalConsoleMethods[level],
2072− this._originalConsole,
2073− [].slice.call(arguments, 1)
2074− );
2075− }
2076− },
2077−
2078− _mergeContext: function(key, context) {
2079− if (isUndefined(context)) {
2080− delete this._globalContext[key];
2081− } else {
2082− this._globalContext[key] = objectMerge(
2083− this._globalContext[key] || {},
2084− context
2085− );
2086− }
2087− }
2088− };
1917+ var url = this._globalEndpoint;
1918+ (globalOptions.transport || this._makeRequest).call(this, {
1919+ url: url,
1920+ auth: auth,
1921+ data: data,
1922+ options: globalOptions,
1923+ onSuccess: function success() {
1924+ self._resetBackoff();
1925+
1926+ self._triggerEvent('success', {
1927+ data: data,
1928+ src: url
1929+ });
1930+ callback && callback();
1931+ },
1932+ onError: function failure(error) {
1933+ self._logDebug('error', 'Raven transport failed to send: ', error);
1934+
1935+ if (error.request) {
1936+ self._setBackoffState(error.request);
1937+ }
1938+
1939+ self._triggerEvent('failure', {
1940+ data: data,
1941+ src: url
1942+ });
1943+ error = error || new Error('Raven send failed (no additional details provided)');
1944+ callback && callback(error);
1945+ }
1946+ });
1947+ },
1948+
1949+ _makeRequest: function(opts) {
1950+ var request = _window.XMLHttpRequest && new _window.XMLHttpRequest();
1951+ if (!request) return;
1952+
1953+ // if browser doesn't support CORS (e.g. IE7), we are out of luck
1954+ var hasCORS = 'withCredentials' in request || typeof XDomainRequest !== 'undefined';
1955+
1956+ if (!hasCORS) return;
1957+
1958+ var url = opts.url;
1959+
1960+ if ('withCredentials' in request) {
1961+ request.onreadystatechange = function() {
1962+ if (request.readyState !== 4) {
1963+ return;
1964+ } else if (request.status === 200) {
1965+ opts.onSuccess && opts.onSuccess();
1966+ } else if (opts.onError) {
1967+ var err = new Error('Sentry error code: ' + request.status);
1968+ err.request = request;
1969+ opts.onError(err);
1970+ }
1971+ };
1972+ } else {
1973+ request = new XDomainRequest();
1974+ // xdomainrequest cannot go http -> https (or vice versa),
1975+ // so always use protocol relative
1976+ url = url.replace(/^https?:/, '');
1977+
1978+ // onreadystatechange not supported by XDomainRequest
1979+ if (opts.onSuccess) {
1980+ request.onload = opts.onSuccess;
1981+ }
1982+ if (opts.onError) {
1983+ request.onerror = function() {
1984+ var err = new Error('Sentry error code: XDomainRequest');
1985+ err.request = request;
1986+ opts.onError(err);
1987+ };
1988+ }
1989+ }
1990+
1991+ // NOTE: auth is intentionally sent as part of query string (NOT as custom
1992+ // HTTP header) so as to avoid preflight CORS requests
1993+ request.open('POST', url + '?' + urlencode(opts.auth));
1994+ request.send(stringify(opts.data));
1995+ },
1996+
1997+ _logDebug: function(level) {
1998+ if (this._originalConsoleMethods[level] && this.debug) {
1999+ // In IE<10 console methods do not have their own 'apply' method
2000+ Function.prototype.apply.call(
2001+ this._originalConsoleMethods[level],
2002+ this._originalConsole,
2003+ [].slice.call(arguments, 1)
2004+ );
2005+ }
2006+ },
2007+
2008+ _mergeContext: function(key, context) {
2009+ if (isUndefined(context)) {
2010+ delete this._globalContext[key];
2011+ } else {
2012+ this._globalContext[key] = objectMerge(this._globalContext[key] || {}, context);
2013+ }
2014+ }
2015+};
2016+
2017+// Deprecations
2018+Raven.prototype.setUser = Raven.prototype.setUserContext;
2019+Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
2020+
2021+module.exports = Raven;
20892022
2090− /*------------------------------------------------
2091− * utils
2023+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2024+},{"1":1,"2":2,"5":5,"6":6,"7":7}],4:[function(_dereq_,module,exports){
2025+(function (global){
2026+/**
2027+ * Enforces a single instance of the Raven client, and the
2028+ * main entry point for Raven. If you are a consumer of the
2029+ * Raven library, you SHOULD load this file (vs raven.js).
2030+ **/
2031+
2032+var RavenConstructor = _dereq_(3);
2033+
2034+// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2035+var _window =
2036+ typeof window !== 'undefined'
2037+ ? window
2038+ : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
2039+var _Raven = _window.Raven;
2040+
2041+var Raven = new RavenConstructor();
2042+
2043+/*
2044+ * Allow multiple versions of Raven to be installed.
2045+ * Strip Raven from the global context and returns the instance.
20922046 *
2093− * conditionally exported for test via Raven.utils
2094− =================================================
2047+ * @return {Raven}
20952048 */
2096− var objectPrototype = Object.prototype;
2049+Raven.noConflict = function() {
2050+ _window.Raven = _Raven;
2051+ return Raven;
2052+};
2053+
2054+Raven.afterLoad();
2055+
2056+module.exports = Raven;
2057+
2058+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2059+},{"3":3}],5:[function(_dereq_,module,exports){
2060+(function (global){
2061+var _window =
2062+ typeof window !== 'undefined'
2063+ ? window
2064+ : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
2065+
2066+function isObject(what) {
2067+ return typeof what === 'object' && what !== null;
2068+}
2069+
2070+// Yanked from https://git.io/vS8DV re-used under CC0
2071+// with some tiny modifications
2072+function isError(value) {
2073+ switch ({}.toString.call(value)) {
2074+ case '[object Error]':
2075+ return true;
2076+ case '[object Exception]':
2077+ return true;
2078+ case '[object DOMException]':
2079+ return true;
2080+ default:
2081+ return value instanceof Error;
2082+ }
2083+}
20972084
2098− function isUndefined(what) {
2099− return what === void 0;
2100− }
2085+function isErrorEvent(value) {
2086+ return supportsErrorEvent() && {}.toString.call(value) === '[object ErrorEvent]';
2087+}
21012088
2102− function isFunction(what) {
2103− return typeof what === 'function';
2104− }
2089+function isUndefined(what) {
2090+ return what === void 0;
2091+}
21052092
2106− function isString(what) {
2107− return objectPrototype.toString.call(what) === '[object String]';
2108− }
2093+function isFunction(what) {
2094+ return typeof what === 'function';
2095+}
21092096
2110− function isEmptyObject(what) {
2111− for (var _ in what) return false; // eslint-disable-line guard-for-in, no-unused-vars
2112− return true;
2113− }
2097+function isString(what) {
2098+ return Object.prototype.toString.call(what) === '[object String]';
2099+}
21142100
2115− function each(obj, callback) {
2116− var i, j;
2101+function isArray(what) {
2102+ return Object.prototype.toString.call(what) === '[object Array]';
2103+}
21172104
2118− if (isUndefined(obj.length)) {
2119− for (i in obj) {
2120− if (hasKey(obj, i)) {
2121− callback.call(null, i, obj[i]);
2122− }
2123− }
2124− } else {
2125− j = obj.length;
2126− if (j) {
2127− for (i = 0; i < j; i++) {
2128− callback.call(null, i, obj[i]);
2129− }
2130− }
2131− }
2132− }
2105+function isEmptyObject(what) {
2106+ for (var _ in what) {
2107+ if (what.hasOwnProperty(_)) {
2108+ return false;
2109+ }
2110+ }
2111+ return true;
2112+}
2113+
2114+function supportsErrorEvent() {
2115+ try {
2116+ new ErrorEvent(''); // eslint-disable-line no-new
2117+ return true;
2118+ } catch (e) {
2119+ return false;
2120+ }
2121+}
21332122
2134− function objectMerge(obj1, obj2) {
2135− if (!obj2) {
2136− return obj1;
2137− }
2138− each(obj2, function(key, value) {
2139− obj1[key] = value;
2140− });
2141− return obj1;
2142− }
2123+function wrappedCallback(callback) {
2124+ function dataCallback(data, original) {
2125+ var normalizedData = callback(data) || data;
2126+ if (original) {
2127+ return original(normalizedData) || normalizedData;
2128+ }
2129+ return normalizedData;
2130+ }
2131+
2132+ return dataCallback;
2133+}
2134+
2135+function each(obj, callback) {
2136+ var i, j;
2137+
2138+ if (isUndefined(obj.length)) {
2139+ for (i in obj) {
2140+ if (hasKey(obj, i)) {
2141+ callback.call(null, i, obj[i]);
2142+ }
2143+ }
2144+ } else {
2145+ j = obj.length;
2146+ if (j) {
2147+ for (i = 0; i < j; i++) {
2148+ callback.call(null, i, obj[i]);
2149+ }
2150+ }
2151+ }
2152+}
2153+
2154+function objectMerge(obj1, obj2) {
2155+ if (!obj2) {
2156+ return obj1;
2157+ }
2158+ each(obj2, function(key, value) {
2159+ obj1[key] = value;
2160+ });
2161+ return obj1;
2162+}
21432163
2144− /**
2164+/**
21452165 * This function is only used for react-native.
21462166 * react-native freezes object that have already been sent over the
21472167 * js bridge. We need this function in order to check if the object is frozen.
@@ -2149,398 +2169,298 @@ · 1 unmodified line
21492169 * supported because it's not relevant for other "platforms". See related issue:
21502170 * https://github.com/getsentry/react-native-sentry/issues/57
21512171 */
2152− function objectFrozen(obj) {
2153− if (!Object.isFrozen) {
2154− return false;
2155− }
2156− return Object.isFrozen(obj);
2157− }
2172+function objectFrozen(obj) {
2173+ if (!Object.isFrozen) {
2174+ return false;
2175+ }
2176+ return Object.isFrozen(obj);
2177+}
21582178
2159− function truncate(str, max) {
2160− return !max || str.length <= max ? str : str.substr(0, max) + '\u2026';
2161− }
2179+function truncate(str, max) {
2180+ return !max || str.length <= max ? str : str.substr(0, max) + '\u2026';
2181+}
21622182
2163− /**
2183+/**
21642184 * hasKey, a better form of hasOwnProperty
21652185 * Example: hasKey(MainHostObject, property) === true/false
21662186 *
21672187 * @param {Object} host object to check property
21682188 * @param {string} key to check
21692189 */
2170− function hasKey(object, key) {
2171− return objectPrototype.hasOwnProperty.call(object, key);
2172− }
2173−
2174− function joinRegExp(patterns) {
2175− // Combine an array of regular expressions and strings into one large regexp
2176− // Be mad.
2177− var sources = [],
2178− i = 0,
2179− len = patterns.length,
2180− pattern;
2181−
2182− for (; i < len; i++) {
2183− pattern = patterns[i];
2184− if (isString(pattern)) {
2185− // If it's a string, we need to escape it
2186− // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
2187− sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'));
2188− } else if (pattern && pattern.source) {
2189− // If it's a regexp already, we want to extract the source
2190− sources.push(pattern.source);
2191− }
2192− // Intentionally skip other cases
2193− }
2194− return new RegExp(sources.join('|'), 'i');
2195− }
2196−
2197− function urlencode(o) {
2198− var pairs = [];
2199− each(o, function(key, value) {
2200− pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
2201− });
2202− return pairs.join('&');
2203− }
2204−
2205− // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
2206− // intentionally using regex and not <a/> href parsing trick because React Native and other
2207− // environments where DOM might not be available
2208− function parseUrl(url) {
2209− var match = url.match(
2210− /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
2211− );
2212− if (!match) return {};
2213−
2214− // coerce to undefined values to empty string so we don't get 'undefined'
2215− var query = match[6] || '';
2216− var fragment = match[8] || '';
2217− return {
2218− protocol: match[2],
2219− host: match[4],
2220− path: match[5],
2221− relative: match[5] + query + fragment // everything minus origin
2222− };
2223− }
2224− function uuid4() {
2225− var crypto = _window.crypto || _window.msCrypto;
2226−
2227− if (!isUndefined(crypto) && crypto.getRandomValues) {
2228− // Use window.crypto API if available
2229− // eslint-disable-next-line no-undef
2230− var arr = new Uint16Array(8);
2231− crypto.getRandomValues(arr);
2232−
2233− // set 4 in byte 7
2234− arr[3] = (arr[3] & 0xfff) | 0x4000;
2235− // set 2 most significant bits of byte 9 to '10'
2236− arr[4] = (arr[4] & 0x3fff) | 0x8000;
2237−
2238− var pad = function(num) {
2239− var v = num.toString(16);
2240− while (v.length < 4) {
2241− v = '0' + v;
2242− }
2243− return v;
2244− };
2245−
2246− return (
2247− pad(arr[0]) +
2248− pad(arr[1]) +
2249− pad(arr[2]) +
2250− pad(arr[3]) +
2251− pad(arr[4]) +
2252− pad(arr[5]) +
2253− pad(arr[6]) +
2254− pad(arr[7])
2255− );
2256− } else {
2257− // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
2258− return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
2259− var r = (Math.random() * 16) | 0,
2260− v = c === 'x' ? r : (r & 0x3) | 0x8;
2261− return v.toString(16);
2262− });
2263− }
2264− }
2190+function hasKey(object, key) {
2191+ return Object.prototype.hasOwnProperty.call(object, key);
2192+}
2193+
2194+function joinRegExp(patterns) {
2195+ // Combine an array of regular expressions and strings into one large regexp
2196+ // Be mad.
2197+ var sources = [],
2198+ i = 0,
2199+ len = patterns.length,
2200+ pattern;
2201+
2202+ for (; i < len; i++) {
2203+ pattern = patterns[i];
2204+ if (isString(pattern)) {
2205+ // If it's a string, we need to escape it
2206+ // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
2207+ sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'));
2208+ } else if (pattern && pattern.source) {
2209+ // If it's a regexp already, we want to extract the source
2210+ sources.push(pattern.source);
2211+ }
2212+ // Intentionally skip other cases
2213+ }
2214+ return new RegExp(sources.join('|'), 'i');
2215+}
2216+
2217+function urlencode(o) {
2218+ var pairs = [];
2219+ each(o, function(key, value) {
2220+ pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
2221+ });
2222+ return pairs.join('&');
2223+}
2224+
2225+// borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
2226+// intentionally using regex and not <a/> href parsing trick because React Native and other
2227+// environments where DOM might not be available
2228+function parseUrl(url) {
2229+ var match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);
2230+ if (!match) return {};
2231+
2232+ // coerce to undefined values to empty string so we don't get 'undefined'
2233+ var query = match[6] || '';
2234+ var fragment = match[8] || '';
2235+ return {
2236+ protocol: match[2],
2237+ host: match[4],
2238+ path: match[5],
2239+ relative: match[5] + query + fragment // everything minus origin
2240+ };
2241+}
2242+function uuid4() {
2243+ var crypto = _window.crypto || _window.msCrypto;
2244+
2245+ if (!isUndefined(crypto) && crypto.getRandomValues) {
2246+ // Use window.crypto API if available
2247+ // eslint-disable-next-line no-undef
2248+ var arr = new Uint16Array(8);
2249+ crypto.getRandomValues(arr);
2250+
2251+ // set 4 in byte 7
2252+ arr[3] = (arr[3] & 0xfff) | 0x4000;
2253+ // set 2 most significant bits of byte 9 to '10'
2254+ arr[4] = (arr[4] & 0x3fff) | 0x8000;
2255+
2256+ var pad = function(num) {
2257+ var v = num.toString(16);
2258+ while (v.length < 4) {
2259+ v = '0' + v;
2260+ }
2261+ return v;
2262+ };
2263+
2264+ return (
2265+ pad(arr[0]) +
2266+ pad(arr[1]) +
2267+ pad(arr[2]) +
2268+ pad(arr[3]) +
2269+ pad(arr[4]) +
2270+ pad(arr[5]) +
2271+ pad(arr[6]) +
2272+ pad(arr[7])
2273+ );
2274+ } else {
2275+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
2276+ return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
2277+ var r = (Math.random() * 16) | 0,
2278+ v = c === 'x' ? r : (r & 0x3) | 0x8;
2279+ return v.toString(16);
2280+ });
2281+ }
2282+}
22652283
2266− /**
2284+/**
22672285 * Given a child DOM element, returns a query-selector statement describing that
22682286 * and its ancestors
22692287 * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
22702288 * @param elem
22712289 * @returns {string}
22722290 */
2273− function htmlTreeAsString(elem) {
2274− /* eslint no-extra-parens:0*/
2275− var MAX_TRAVERSE_HEIGHT = 5,
2276− MAX_OUTPUT_LEN = 80,
2277− out = [],
2278− height = 0,
2279− len = 0,
2280− separator = ' > ',
2281− sepLength = separator.length,
2282− nextStr;
2283−
2284− while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
2285− nextStr = htmlElementAsString(elem);
2286− // bail out if
2287− // - nextStr is the 'html' element
2288− // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
2289− // (ignore this limit if we are on the first iteration)
2290− if (
2291− nextStr === 'html' ||
2292− (height > 1 &&
2293− len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN)
2294− ) {
2295− break;
2296− }
2291+function htmlTreeAsString(elem) {
2292+ /* eslint no-extra-parens:0*/
2293+ var MAX_TRAVERSE_HEIGHT = 5,
2294+ MAX_OUTPUT_LEN = 80,
2295+ out = [],
2296+ height = 0,
2297+ len = 0,
2298+ separator = ' > ',
2299+ sepLength = separator.length,
2300+ nextStr;
2301+
2302+ while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
2303+ nextStr = htmlElementAsString(elem);
2304+ // bail out if
2305+ // - nextStr is the 'html' element
2306+ // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
2307+ // (ignore this limit if we are on the first iteration)
2308+ if (
2309+ nextStr === 'html' ||
2310+ (height > 1 && len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN)
2311+ ) {
2312+ break;
2313+ }
22972314
2298− out.push(nextStr);
2315+ out.push(nextStr);
22992316
2300− len += nextStr.length;
2301− elem = elem.parentNode;
2302− }
2317+ len += nextStr.length;
2318+ elem = elem.parentNode;
2319+ }
23032320
2304− return out.reverse().join(separator);
2305− }
2321+ return out.reverse().join(separator);
2322+}
23062323
2307− /**
2324+/**
23082325 * Returns a simple, query-selector representation of a DOM element
23092326 * e.g. [HTMLElement] => input#foo.btn[name=baz]
23102327 * @param HTMLElement
23112328 * @returns {string}
23122329 */
2313− function htmlElementAsString(elem) {
2314− var out = [],
2315− className,
2316− classes,
2317− key,
2318− attr,
2319− i;
2320−
2321− if (!elem || !elem.tagName) {
2322− return '';
2323− }
2330+function htmlElementAsString(elem) {
2331+ var out = [],
2332+ className,
2333+ classes,
2334+ key,
2335+ attr,
2336+ i;
2337+
2338+ if (!elem || !elem.tagName) {
2339+ return '';
2340+ }
23242341
2325− out.push(elem.tagName.toLowerCase());
2326− if (elem.id) {
2327− out.push('#' + elem.id);
2328− }
2342+ out.push(elem.tagName.toLowerCase());
2343+ if (elem.id) {
2344+ out.push('#' + elem.id);
2345+ }
23292346
2330− className = elem.className;
2331− if (className && isString(className)) {
2332− classes = className.split(/\s+/);
2333− for (i = 0; i < classes.length; i++) {
2334− out.push('.' + classes[i]);
2335− }
2336− }
2337− var attrWhitelist = ['type', 'name', 'title', 'alt'];
2338− for (i = 0; i < attrWhitelist.length; i++) {
2339− key = attrWhitelist[i];
2340− attr = elem.getAttribute(key);
2341− if (attr) {
2342− out.push('[' + key + '="' + attr + '"]');
2343− }
2344− }
2345− return out.join('');
2346− }
2347+ className = elem.className;
2348+ if (className && isString(className)) {
2349+ classes = className.split(/\s+/);
2350+ for (i = 0; i < classes.length; i++) {
2351+ out.push('.' + classes[i]);
2352+ }
2353+ }
2354+ var attrWhitelist = ['type', 'name', 'title', 'alt'];
2355+ for (i = 0; i < attrWhitelist.length; i++) {
2356+ key = attrWhitelist[i];
2357+ attr = elem.getAttribute(key);
2358+ if (attr) {
2359+ out.push('[' + key + '="' + attr + '"]');
2360+ }
2361+ }
2362+ return out.join('');
2363+}
23472364
2348− /**
2365+/**
23492366 * Returns true if either a OR b is truthy, but not both
23502367 */
2351− function isOnlyOneTruthy(a, b) {
2352− return !!(!!a ^ !!b);
2353− }
2368+function isOnlyOneTruthy(a, b) {
2369+ return !!(!!a ^ !!b);
2370+}
23542371
2355− /**
2372+/**
23562373 * Returns true if the two input exception interfaces have the same content
23572374 */
2358− function isSameException(ex1, ex2) {
2359− if (isOnlyOneTruthy(ex1, ex2)) return false;
2375+function isSameException(ex1, ex2) {
2376+ if (isOnlyOneTruthy(ex1, ex2)) return false;
23602377
2361− ex1 = ex1.values[0];
2362− ex2 = ex2.values[0];
2378+ ex1 = ex1.values[0];
2379+ ex2 = ex2.values[0];
23632380
2364− if (ex1.type !== ex2.type || ex1.value !== ex2.value) return false;
2381+ if (ex1.type !== ex2.type || ex1.value !== ex2.value) return false;
23652382
2366− return isSameStacktrace(ex1.stacktrace, ex2.stacktrace);
2367− }
2383+ return isSameStacktrace(ex1.stacktrace, ex2.stacktrace);
2384+}
23682385
2369− /**
2386+/**
23702387 * Returns true if the two input stack trace interfaces have the same content
23712388 */
2372− function isSameStacktrace(stack1, stack2) {
2373− if (isOnlyOneTruthy(stack1, stack2)) return false;
2374−
2375− var frames1 = stack1.frames;
2376− var frames2 = stack2.frames;
2377−
2378− // Exit early if frame count differs
2379− if (frames1.length !== frames2.length) return false;
2380−
2381− // Iterate through every frame; bail out if anything differs
2382− var a, b;
2383− for (var i = 0; i < frames1.length; i++) {
2384− a = frames1[i];
2385− b = frames2[i];
2386− if (
2387− a.filename !== b.filename ||
2388− a.lineno !== b.lineno ||
2389− a.colno !== b.colno ||
2390− a['function'] !== b['function']
2391− )
2392− return false;
2393− }
2394− return true;
2395− }
2389+function isSameStacktrace(stack1, stack2) {
2390+ if (isOnlyOneTruthy(stack1, stack2)) return false;
2391+
2392+ var frames1 = stack1.frames;
2393+ var frames2 = stack2.frames;
2394+
2395+ // Exit early if frame count differs
2396+ if (frames1.length !== frames2.length) return false;
2397+
2398+ // Iterate through every frame; bail out if anything differs
2399+ var a, b;
2400+ for (var i = 0; i < frames1.length; i++) {
2401+ a = frames1[i];
2402+ b = frames2[i];
2403+ if (
2404+ a.filename !== b.filename ||
2405+ a.lineno !== b.lineno ||
2406+ a.colno !== b.colno ||
2407+ a['function'] !== b['function']
2408+ )
2409+ return false;
2410+ }
2411+ return true;
2412+}
23962413
2397− /**
2414+/**
23982415 * Polyfill a method
23992416 * @param obj object e.g. `document`
24002417 * @param name method name present on object e.g. `addEventListener`
24012418 * @param replacement replacement function
24022419 * @param track {optional} record instrumentation to an array
24032420 */
2404− function fill(obj, name, replacement, track) {
2405− var orig = obj[name];
2406− obj[name] = replacement(orig);
2407− if (track) {
2408− track.push([obj, name, orig]);
2409− }
2410− }
2411−
2412− if (typeof __DEV__ !== 'undefined' && __DEV__) {
2413− Raven.utils = {
2414− isUndefined: isUndefined,
2415− isFunction: isFunction,
2416− isString: isString,
2417− isObject: isObject,
2418− isEmptyObject: isEmptyObject,
2419− isError: isError,
2420− each: each,
2421− objectMerge: objectMerge,
2422− truncate: truncate,
2423− hasKey: hasKey,
2424− joinRegExp: joinRegExp,
2425− urlencode: urlencode,
2426− uuid4: uuid4,
2427− htmlTreeAsString: htmlTreeAsString,
2428− htmlElementAsString: htmlElementAsString,
2429− parseUrl: parseUrl,
2430− fill: fill
2431− };
2432− }
2433−
2434− // Deprecations
2435− Raven.prototype.setUser = Raven.prototype.setUserContext;
2436− Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
2437−
2438− module.exports = Raven;
2439− }.call(
2440− this,
2441− typeof global !== 'undefined'
2442− ? global
2443− : typeof self !== 'undefined'
2444− ? self
2445− : typeof window !== 'undefined' ? window : {}
2446− ));
2447− },
2448− {'1': 1, '2': 2, '5': 5, '6': 6, '7': 7}
2449− ],
2450− 4: [
2451− function(_dereq_, module, exports) {
2452− (function(global) {
2453− /**
2454− * Enforces a single instance of the Raven client, and the
2455− * main entry point for Raven. If you are a consumer of the
2456− * Raven library, you SHOULD load this file (vs raven.js).
2457− **/
2458−
2459− var RavenConstructor = _dereq_(3);
2460−
2461− // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2462− var _window =
2463− typeof window !== 'undefined'
2464− ? window
2465− : typeof global !== 'undefined'
2466− ? global
2467− : typeof self !== 'undefined' ? self : {};
2468− var _Raven = _window.Raven;
2469−
2470− var Raven = new RavenConstructor();
2471−
2472− /*
2473− * Allow multiple versions of Raven to be installed.
2474− * Strip Raven from the global context and returns the instance.
2475− *
2476− * @return {Raven}
2477− */
2478− Raven.noConflict = function() {
2479− _window.Raven = _Raven;
2480− return Raven;
2481− };
2482−
2483− Raven.afterLoad();
2484−
2485− module.exports = Raven;
2486− }.call(
2487− this,
2488− typeof global !== 'undefined'
2489− ? global
2490− : typeof self !== 'undefined'
2491− ? self
2492− : typeof window !== 'undefined' ? window : {}
2493− ));
2494− },
2495− {'3': 3}
2496− ],
2497− 5: [
2498− function(_dereq_, module, exports) {
2499− function isObject(what) {
2500− return typeof what === 'object' && what !== null;
2501− }
2502−
2503− // Yanked from https://git.io/vS8DV re-used under CC0
2504− // with some tiny modifications
2505− function isError(value) {
2506− switch ({}.toString.call(value)) {
2507− case '[object Error]':
2508− return true;
2509− case '[object Exception]':
2510− return true;
2511− case '[object DOMException]':
2512− return true;
2513− default:
2514− return value instanceof Error;
2515− }
2516− }
2517−
2518− function wrappedCallback(callback) {
2519− function dataCallback(data, original) {
2520− var normalizedData = callback(data) || data;
2521− if (original) {
2522− return original(normalizedData) || normalizedData;
2523− }
2524− return normalizedData;
2525− }
2526−
2527− return dataCallback;
2528− }
2421+function fill(obj, name, replacement, track) {
2422+ var orig = obj[name];
2423+ obj[name] = replacement(orig);
2424+ obj[name].__raven__ = true;
2425+ obj[name].__orig__ = orig;
2426+ if (track) {
2427+ track.push([obj, name, orig]);
2428+ }
2429+}
2430+
2431+module.exports = {
2432+ isObject: isObject,
2433+ isError: isError,
2434+ isErrorEvent: isErrorEvent,
2435+ isUndefined: isUndefined,
2436+ isFunction: isFunction,
2437+ isString: isString,
2438+ isArray: isArray,
2439+ isEmptyObject: isEmptyObject,
2440+ supportsErrorEvent: supportsErrorEvent,
2441+ wrappedCallback: wrappedCallback,
2442+ each: each,
2443+ objectMerge: objectMerge,
2444+ truncate: truncate,
2445+ objectFrozen: objectFrozen,
2446+ hasKey: hasKey,
2447+ joinRegExp: joinRegExp,
2448+ urlencode: urlencode,
2449+ uuid4: uuid4,
2450+ htmlTreeAsString: htmlTreeAsString,
2451+ htmlElementAsString: htmlElementAsString,
2452+ isSameException: isSameException,
2453+ isSameStacktrace: isSameStacktrace,
2454+ parseUrl: parseUrl,
2455+ fill: fill
2456+};
2457+
2458+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2459+},{}],6:[function(_dereq_,module,exports){
2460+(function (global){
2461+var utils = _dereq_(5);
25292462
2530− module.exports = {
2531− isObject: isObject,
2532− isError: isError,
2533− wrappedCallback: wrappedCallback
2534− };
2535− },
2536− {}
2537− ],
2538− 6: [
2539− function(_dereq_, module, exports) {
2540− (function(global) {
2541− var utils = _dereq_(5);
2542−
2543− /*
2463+/*
25442464 TraceKit - Cross brower stack traces
25452465
25462466 This was originally forked from github.com/occ/TraceKit, but has since been
@@ -2550,33 +2470,31 @@ · 3 unmodified lines
25502470 MIT license
25512471 */
25522472
2553− var TraceKit = {
2554− collectWindowErrors: true,
2555− debug: false
2556− };
2473+var TraceKit = {
2474+ collectWindowErrors: true,
2475+ debug: false
2476+};
25572477
2558− // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2559− var _window =
2560− typeof window !== 'undefined'
2561− ? window
2562− : typeof global !== 'undefined'
2563− ? global
2564− : typeof self !== 'undefined' ? self : {};
2478+// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2479+var _window =
2480+ typeof window !== 'undefined'
2481+ ? window
2482+ : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
25652483
2566− // global reference to slice
2567− var _slice = [].slice;
2568− var UNKNOWN_FUNCTION = '?';
2484+// global reference to slice
2485+var _slice = [].slice;
2486+var UNKNOWN_FUNCTION = '?';
25692487
2570− // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
2571− var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;
2488+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
2489+var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;
25722490
2573− function getLocationHref() {
2574− if (typeof document === 'undefined' || document.location == null) return '';
2491+function getLocationHref() {
2492+ if (typeof document === 'undefined' || document.location == null) return '';
25752493
2576− return document.location.href;
2577− }
2494+ return document.location.href;
2495+}
25782496
2579− /**
2497+/**
25802498 * TraceKit.report: cross-browser processing of unhandled exceptions
25812499 *
25822500 * Syntax:
@@ -2615,68 +2533,68 @@ · 32 unmodified lines
26152533 * Handlers receive a stackInfo object as described in the
26162534 * TraceKit.computeStackTrace docs.
26172535 */
2618− TraceKit.report = (function reportModuleWrapper() {
2619− var handlers = [],
2620− lastArgs = null,
2621− lastException = null,
2622− lastExceptionStack = null;
2536+TraceKit.report = (function reportModuleWrapper() {
2537+ var handlers = [],
2538+ lastArgs = null,
2539+ lastException = null,
2540+ lastExceptionStack = null;
26232541
2624− /**
2542+ /**
26252543 * Add a crash handler.
26262544 * @param {Function} handler
26272545 */
2628− function subscribe(handler) {
2629− installGlobalHandler();
2630− handlers.push(handler);
2631− }
2546+ function subscribe(handler) {
2547+ installGlobalHandler();
2548+ handlers.push(handler);
2549+ }
26322550
2633− /**
2551+ /**
26342552 * Remove a crash handler.
26352553 * @param {Function} handler
26362554 */
2637− function unsubscribe(handler) {
2638− for (var i = handlers.length - 1; i >= 0; --i) {
2639− if (handlers[i] === handler) {
2640− handlers.splice(i, 1);
2641− }
2642− }
2643− }
2555+ function unsubscribe(handler) {
2556+ for (var i = handlers.length - 1; i >= 0; --i) {
2557+ if (handlers[i] === handler) {
2558+ handlers.splice(i, 1);
2559+ }
2560+ }
2561+ }
26442562
2645− /**
2563+ /**
26462564 * Remove all crash handlers.
26472565 */
2648− function unsubscribeAll() {
2649− uninstallGlobalHandler();
2650− handlers = [];
2651− }
2566+ function unsubscribeAll() {
2567+ uninstallGlobalHandler();
2568+ handlers = [];
2569+ }
26522570
2653− /**
2571+ /**
26542572 * Dispatch stack information to all handlers.
26552573 * @param {Object.<string, *>} stack
26562574 */
2657− function notifyHandlers(stack, isWindowError) {
2658− var exception = null;
2659− if (isWindowError && !TraceKit.collectWindowErrors) {
2660− return;
2661− }
2662− for (var i in handlers) {
2663− if (handlers.hasOwnProperty(i)) {
2664− try {
2665− handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
2666− } catch (inner) {
2667− exception = inner;
2668− }
2669− }
2670− }
2575+ function notifyHandlers(stack, isWindowError) {
2576+ var exception = null;
2577+ if (isWindowError && !TraceKit.collectWindowErrors) {
2578+ return;
2579+ }
2580+ for (var i in handlers) {
2581+ if (handlers.hasOwnProperty(i)) {
2582+ try {
2583+ handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
2584+ } catch (inner) {
2585+ exception = inner;
2586+ }
2587+ }
2588+ }
26712589
2672− if (exception) {
2673− throw exception;
2674− }
2675− }
2590+ if (exception) {
2591+ throw exception;
2592+ }
2593+ }
26762594
2677− var _oldOnerrorHandler, _onErrorHandlerInstalled;
2595+ var _oldOnerrorHandler, _onErrorHandlerInstalled;
26782596
2679− /**
2597+ /**
26802598 * Ensures all global unhandled exceptions are recorded.
26812599 * Supported by Gecko and IE.
26822600 * @param {string} message Error message.
@@ -2687,135 +2605,132 @@ · 4 unmodified lines
26872605 * occurred.
26882606 * @param {?Error} ex The actual Error object.
26892607 */
2690− function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
2691− var stack = null;
2692−
2693− if (lastExceptionStack) {
2694− TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
2695− lastExceptionStack,
2696− url,
2697− lineNo,
2698− message
2699− );
2700− processLastException();
2701− } else if (ex && utils.isError(ex)) {
2702− // non-string `ex` arg; attempt to extract stack trace
2703−
2704− // New chrome and blink send along a real error object
2705− // Let's just report that like a normal error.
2706− // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
2707− stack = TraceKit.computeStackTrace(ex);
2708− notifyHandlers(stack, true);
2709− } else {
2710− var location = {
2711− url: url,
2712− line: lineNo,
2713− column: colNo
2714− };
2715−
2716− var name = undefined;
2717− var msg = message; // must be new var or will modify original `arguments`
2718− var groups;
2719− if ({}.toString.call(message) === '[object String]') {
2720− var groups = message.match(ERROR_TYPES_RE);
2721− if (groups) {
2722− name = groups[1];
2723− msg = groups[2];
2724− }
2725− }
2608+ function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
2609+ var stack = null;
2610+
2611+ if (lastExceptionStack) {
2612+ TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
2613+ lastExceptionStack,
2614+ url,
2615+ lineNo,
2616+ message
2617+ );
2618+ processLastException();
2619+ } else if (ex && utils.isError(ex)) {
2620+ // non-string `ex` arg; attempt to extract stack trace
2621+
2622+ // New chrome and blink send along a real error object
2623+ // Let's just report that like a normal error.
2624+ // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
2625+ stack = TraceKit.computeStackTrace(ex);
2626+ notifyHandlers(stack, true);
2627+ } else {
2628+ var location = {
2629+ url: url,
2630+ line: lineNo,
2631+ column: colNo
2632+ };
2633+
2634+ var name = undefined;
2635+ var msg = message; // must be new var or will modify original `arguments`
2636+ var groups;
2637+ if ({}.toString.call(message) === '[object String]') {
2638+ var groups = message.match(ERROR_TYPES_RE);
2639+ if (groups) {
2640+ name = groups[1];
2641+ msg = groups[2];
2642+ }
2643+ }
27262644
2727− location.func = UNKNOWN_FUNCTION;
2645+ location.func = UNKNOWN_FUNCTION;
27282646
2729− stack = {
2730− name: name,
2731− message: msg,
2732− url: getLocationHref(),
2733− stack: [location]
2734− };
2735− notifyHandlers(stack, true);
2736− }
2647+ stack = {
2648+ name: name,
2649+ message: msg,
2650+ url: getLocationHref(),
2651+ stack: [location]
2652+ };
2653+ notifyHandlers(stack, true);
2654+ }
27372655
2738− if (_oldOnerrorHandler) {
2739− return _oldOnerrorHandler.apply(this, arguments);
2740− }
2656+ if (_oldOnerrorHandler) {
2657+ return _oldOnerrorHandler.apply(this, arguments);
2658+ }
27412659
2742− return false;
2743− }
2660+ return false;
2661+ }
27442662
2745− function installGlobalHandler() {
2746− if (_onErrorHandlerInstalled) {
2747− return;
2748− }
2749− _oldOnerrorHandler = _window.onerror;
2750− _window.onerror = traceKitWindowOnError;
2751− _onErrorHandlerInstalled = true;
2752− }
2663+ function installGlobalHandler() {
2664+ if (_onErrorHandlerInstalled) {
2665+ return;
2666+ }
2667+ _oldOnerrorHandler = _window.onerror;
2668+ _window.onerror = traceKitWindowOnError;
2669+ _onErrorHandlerInstalled = true;
2670+ }
27532671
2754− function uninstallGlobalHandler() {
2755− if (!_onErrorHandlerInstalled) {
2756− return;
2757− }
2758− _window.onerror = _oldOnerrorHandler;
2759− _onErrorHandlerInstalled = false;
2760− _oldOnerrorHandler = undefined;
2761− }
2672+ function uninstallGlobalHandler() {
2673+ if (!_onErrorHandlerInstalled) {
2674+ return;
2675+ }
2676+ _window.onerror = _oldOnerrorHandler;
2677+ _onErrorHandlerInstalled = false;
2678+ _oldOnerrorHandler = undefined;
2679+ }
27622680
2763− function processLastException() {
2764− var _lastExceptionStack = lastExceptionStack,
2765− _lastArgs = lastArgs;
2766− lastArgs = null;
2767− lastExceptionStack = null;
2768− lastException = null;
2769− notifyHandlers.apply(
2770− null,
2771− [_lastExceptionStack, false].concat(_lastArgs)
2772− );
2773− }
2681+ function processLastException() {
2682+ var _lastExceptionStack = lastExceptionStack,
2683+ _lastArgs = lastArgs;
2684+ lastArgs = null;
2685+ lastExceptionStack = null;
2686+ lastException = null;
2687+ notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs));
2688+ }
27742689
2775− /**
2690+ /**
27762691 * Reports an unhandled Error to TraceKit.
27772692 * @param {Error} ex
27782693 * @param {?boolean} rethrow If false, do not re-throw the exception.
27792694 * Only used for window.onerror to not cause an infinite loop of
27802695 * rethrowing.
27812696 */
2782− function report(ex, rethrow) {
2783− var args = _slice.call(arguments, 1);
2784− if (lastExceptionStack) {
2785− if (lastException === ex) {
2786− return; // already caught by an inner catch block, ignore
2787− } else {
2788− processLastException();
2789− }
2790− }
2697+ function report(ex, rethrow) {
2698+ var args = _slice.call(arguments, 1);
2699+ if (lastExceptionStack) {
2700+ if (lastException === ex) {
2701+ return; // already caught by an inner catch block, ignore
2702+ } else {
2703+ processLastException();
2704+ }
2705+ }
27912706
2792− var stack = TraceKit.computeStackTrace(ex);
2793− lastExceptionStack = stack;
2794− lastException = ex;
2795− lastArgs = args;
2796−
2797− // If the stack trace is incomplete, wait for 2 seconds for
2798− // slow slow IE to see if onerror occurs or not before reporting
2799− // this exception; otherwise, we will end up with an incomplete
2800− // stack trace
2801− setTimeout(function() {
2802− if (lastException === ex) {
2803− processLastException();
2804− }
2805− }, stack.incomplete ? 2000 : 0);
2707+ var stack = TraceKit.computeStackTrace(ex);
2708+ lastExceptionStack = stack;
2709+ lastException = ex;
2710+ lastArgs = args;
2711+
2712+ // If the stack trace is incomplete, wait for 2 seconds for
2713+ // slow slow IE to see if onerror occurs or not before reporting
2714+ // this exception; otherwise, we will end up with an incomplete
2715+ // stack trace
2716+ setTimeout(function() {
2717+ if (lastException === ex) {
2718+ processLastException();
2719+ }
2720+ }, stack.incomplete ? 2000 : 0);
28062721
2807− if (rethrow !== false) {
2808− throw ex; // re-throw to propagate to the top level (and cause window.onerror)
2809− }
2810− }
2722+ if (rethrow !== false) {
2723+ throw ex; // re-throw to propagate to the top level (and cause window.onerror)
2724+ }
2725+ }
28112726
2812− report.subscribe = subscribe;
2813− report.unsubscribe = unsubscribe;
2814− report.uninstall = unsubscribeAll;
2815− return report;
2816− })();

724 more lines aren’t shown here.