History

Bump Raven.js

Thibaut Courouble committed 9 years ago

Commit 2db57fd1 parent c1ebb7a1 file · +557 −401Browse files

Unified · Split

assets/javascripts/vendor/raven.js+557−401
@@ -1,10 +1,10 @@
1−/*! Raven.js 3.5.1 (bef9fa7) | github.com/getsentry/raven-js */
1+/*! Raven.js 3.11.0 (cb87941) | github.com/getsentry/raven-js */
22
33 /*
44 * Includes TraceKit
55 * https://github.com/getsentry/TraceKit
66 *
7− * Copyright 2016 Matt Robenolt and other contributors
7+ * Copyright 2017 Matt Robenolt and other contributors
88 * Released under the BSD license
99 * https://github.com/getsentry/raven-js/blob/master/LICENSE
1010 *
@@ -91,30 +91,14 @@ module.exports = { · 80 unmodified lines
9191 };
9292
9393 },{}],4:[function(_dereq_,module,exports){
94−/*global XDomainRequest:false*/
94+(function (global){
95+/*global XDomainRequest:false, __DEV__:false*/
9596 'use strict';
9697
97−var TraceKit = _dereq_(7);
98+var TraceKit = _dereq_(6);
9899 var RavenConfigError = _dereq_(2);
99−var utils = _dereq_(6);
100100 var stringify = _dereq_(1);
101101
102−var isFunction = utils.isFunction;
103−var isUndefined = utils.isUndefined;
104−var isError = utils.isError;
105−var isEmptyObject = utils.isEmptyObject;
106−var hasKey = utils.hasKey;
107−var joinRegExp = utils.joinRegExp;
108−var each = utils.each;
109−var objectMerge = utils.objectMerge;
110−var truncate = utils.truncate;
111−var urlencode = utils.urlencode;
112−var uuid4 = utils.uuid4;
113−var htmlTreeAsString = utils.htmlTreeAsString;
114−var parseUrl = utils.parseUrl;
115−var isString = utils.isString;
116−var fill = utils.fill;
117−
118102 var wrapConsoleMethod = _dereq_(3).wrapMethod;
119103
120104 var dsnKeys = 'source protocol user pass host port path'.split(' '),
@@ -124,6 +108,13 @@ function now() { · 3 unmodified lines
124108 return +new Date();
125109 }
126110
111+// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
112+var _window = typeof window !== 'undefined' ? window
113+ : typeof global !== 'undefined' ? global
114+ : typeof self !== 'undefined' ? self
115+ : {};
116+var _document = _window.document;
117+var _navigator = _window.navigator;
127118
128119 // First, check for JSON support
129120 // If there is no JSON, we no-op the core features of Raven
@@ -131,8 +122,10 @@ function now() { · 1 unmodified line
131122 function Raven() {
132123 this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
133124 // Raven can run in contexts where there's no document (react-native)
134− this._hasDocument = typeof document !== 'undefined';
125+ this._hasDocument = !isUndefined(_document);
126+ this._hasNavigator = !isUndefined(_navigator);
135127 this._lastCapturedException = null;
128+ this._lastData = null;
136129 this._lastEventId = null;
137130 this._globalServer = null;
138131 this._globalKey = null;
@@ -155,7 +148,7 @@ function Raven() { · 16 unmodified lines
155148 this._originalErrorStackTraceLimit = Error.stackTraceLimit;
156149 // capture references to window.console *and* all its methods first
157150 // before the console plugin has a chance to monkey patch
158− this._originalConsole = window.console || {};
151+ this._originalConsole = _window.console || {};
159152 this._originalConsoleMethods = {};
160153 this._plugins = [];
161154 this._startTime = now();
@@ -163,8 +156,9 @@ function Raven() { · 1 unmodified line
163156 this._breadcrumbs = [];
164157 this._lastCapturedEvent = null;
165158 this._keypressTimeout;
166− this._location = window.location;
159+ this._location = _window.location;
167160 this._lastHref = this._location && this._location.href;
161+ this._resetBackoff();
168162
169163 for (var method in this._originalConsole) { // eslint-disable-line guard-for-in
170164 this._originalConsoleMethods[method] = this._originalConsole[method];
@@ -182,7 +176,7 @@ Raven.prototype = { · 11 unmodified lines
182176 // webpack (using a build step causes webpack #1617). Grunt verifies that
183177 // this value matches package.json during build.
184178 // See: https://github.com/getsentry/raven-js/issues/465
185− VERSION: '3.5.1',
179+ VERSION: '3.11.0',
186180
187181 debug: false,
188182
@@ -198,41 +192,39 @@ Raven.prototype = { · 9 unmodified lines
198192 config: function(dsn, options) {
199193 var self = this;
200194
201− if (this._globalServer) {
195+ if (self._globalServer) {
202196 this._logDebug('error', 'Error: Raven has already been configured');
203− return this;
197+ return self;
204198 }
205− if (!dsn) return this;
199+ if (!dsn) return self;
200+
201+ var globalOptions = self._globalOptions;
206202
207203 // merge in options
208204 if (options) {
209205 each(options, function(key, value){
210206 // tags and extra are special and need to be put into context
211− if (key === 'tags' || key === 'extra') {
207+ if (key === 'tags' || key === 'extra' || key === 'user') {
212208 self._globalContext[key] = value;
213209 } else {
214− self._globalOptions[key] = value;
210+ globalOptions[key] = value;
215211 }
216212 });
217213 }
218214
219− var uri = this._parseDSN(dsn),
220− lastSlash = uri.path.lastIndexOf('/'),
221− path = uri.path.substr(1, lastSlash);
222−
223− this._dsn = dsn;
215+ self.setDSN(dsn);
224216
225217 // "Script error." is hard coded into browsers for errors that it can't read.
226218 // this is the result of a script being pulled in from an external domain and CORS.
227− this._globalOptions.ignoreErrors.push(/^Script error\.?$/);
228− this._globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
219+ globalOptions.ignoreErrors.push(/^Script error\.?$/);
220+ globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
229221
230222 // join regexp rules into one big rule
231− this._globalOptions.ignoreErrors = joinRegExp(this._globalOptions.ignoreErrors);
232− this._globalOptions.ignoreUrls = this._globalOptions.ignoreUrls.length ? joinRegExp(this._globalOptions.ignoreUrls) : false;
233− this._globalOptions.whitelistUrls = this._globalOptions.whitelistUrls.length ? joinRegExp(this._globalOptions.whitelistUrls) : false;
234− this._globalOptions.includePaths = joinRegExp(this._globalOptions.includePaths);
235− this._globalOptions.maxBreadcrumbs = Math.max(0, Math.min(this._globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100
223+ globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
224+ globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
225+ globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
226+ globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
227+ globalOptions.maxBreadcrumbs = Math.max(0, Math.min(globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100
236228
237229 var autoBreadcrumbDefaults = {
238230 xhr: true,
@@ -241,27 +233,18 @@ Raven.prototype = { · 2 unmodified lines
241233 location: true
242234 };
243235
244− var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
236+ var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
245237 if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
246238 autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
247239 } else if (autoBreadcrumbs !== false) {
248240 autoBreadcrumbs = autoBreadcrumbDefaults;
249241 }
250− this._globalOptions.autoBreadcrumbs = autoBreadcrumbs;
251−
252− this._globalKey = uri.user;
253− this._globalSecret = uri.pass && uri.pass.substr(1);
254− this._globalProject = uri.path.substr(lastSlash + 1);
255−
256− this._globalServer = this._getGlobalServer(uri);
242+ globalOptions.autoBreadcrumbs = autoBreadcrumbs;
257243
258− this._globalEndpoint = this._globalServer +
259− '/' + path + 'api/' + this._globalProject + '/store/';
260−
261− TraceKit.collectWindowErrors = !!this._globalOptions.collectWindowErrors;
244+ TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
262245
263246 // return for chaining
264− return this;
247+ return self;
265248 },
266249
267250 /*
@@ -274,24 +257,50 @@ Raven.prototype = { · 6 unmodified lines
274257 */
275258 install: function() {
276259 var self = this;
277− if (this.isSetup() && !this._isRavenInstalled) {
260+ if (self.isSetup() && !self._isRavenInstalled) {
278261 TraceKit.report.subscribe(function () {
279262 self._handleOnErrorStackInfo.apply(self, arguments);
280263 });
281− this._instrumentTryCatch();
264+ self._instrumentTryCatch();
282265 if (self._globalOptions.autoBreadcrumbs)
283− this._instrumentBreadcrumbs();
266+ self._instrumentBreadcrumbs();
284267
285268 // Install all of the plugins
286− this._drainPlugins();
269+ self._drainPlugins();
287270
288− this._isRavenInstalled = true;
271+ self._isRavenInstalled = true;
289272 }
290273
291− Error.stackTraceLimit = this._globalOptions.stackTraceLimit;
274+ Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
292275 return this;
293276 },
294277
278+ /*
279+ * Set the DSN (can be called multiple time unlike config)
280+ *
281+ * @param {string} dsn The public Sentry DSN
282+ */
283+ setDSN: function(dsn) {
284+ var self = this,
285+ uri = self._parseDSN(dsn),
286+ lastSlash = uri.path.lastIndexOf('/'),
287+ path = uri.path.substr(1, lastSlash);
288+
289+ self._dsn = dsn;
290+ self._globalKey = uri.user;
291+ self._globalSecret = uri.pass && uri.pass.substr(1);
292+ self._globalProject = uri.path.substr(lastSlash + 1);
293+
294+ self._globalServer = self._getGlobalServer(uri);
295+
296+ self._globalEndpoint = self._globalServer +
297+ '/' + path + 'api/' + self._globalProject + '/store/';
298+
299+ // Reset backoff state since we may be pointing at a
300+ // new project/server
301+ this._resetBackoff();
302+ },
303+
295304 /*
296305 * Wrap code within a context so Raven can capture errors
297306 * reliably across domains that is executed immediately.
@@ -343,18 +352,18 @@ Raven.prototype = { · 45 unmodified lines
343352 if (func.__raven__) {
344353 return func;
345354 }
355+
356+ // If this has already been wrapped in the past, return that
357+ if (func.__raven_wrapper__ ){
358+ return func.__raven_wrapper__ ;
359+ }
346360 } catch (e) {
347− // Just accessing the __raven__ prop in some Selenium environments
361+ // Just accessing custom props in some Selenium environments
348362 // can cause a "Permission denied" exception (see raven-js#495).
349363 // Bail on wrapping and return the function as-is (defers to window.onerror).
350364 return func;
351365 }
352366
353− // If this has already been wrapped in the past, return that
354− if (func.__raven_wrapper__ ){
355− return func.__raven_wrapper__ ;
356− }
357−
358367 function wrapped() {
359368 var args = [], i = arguments.length,
360369 deep = !options || options && options.deep !== false;
@@ -368,6 +377,10 @@ Raven.prototype = { · 7 unmodified lines
368377 while(i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
369378
370379 try {
380+ // Attempt to invoke user-land function
381+ // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
382+ // means Raven caught an error invoking your application code. This is
383+ // expected behavior and NOT indicative of a bug with Raven.js.
371384 return func.apply(this, args);
372385 } catch(e) {
373386 self._ignoreNextOnError();
@@ -418,7 +431,12 @@ Raven.prototype = { · 44 unmodified lines
418431 */
419432 captureException: function(ex, options) {
420433 // If not an Error is passed through, recall as a message instead
421− if (!isError(ex)) return this.captureMessage(ex, options);
434+ if (!isError(ex)) {
435+ return this.captureMessage(ex, objectMerge({
436+ trimHeadFrames: 1,
437+ stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
438+ }, options));
439+ }
422440
423441 // Store the raw exception object for potential debugging and introspection
424442 this._lastCapturedException = ex;
@@ -455,12 +473,43 @@ Raven.prototype = { · 30 unmodified lines
455473 return;
456474 }
457475
476+ options = options || {};
477+
478+ var data = objectMerge({
479+ message: msg + '' // Make sure it's actually a string
480+ }, options);
481+
482+ if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
483+ var ex;
484+ // create a stack trace from this point; just trim
485+ // off extra frames so they don't include this function call (or
486+ // earlier Raven.js library fn calls)
487+ try {
488+ throw new Error(msg);
489+ } catch (ex1) {
490+ ex = ex1;
491+ }
492+
493+ // null exception name so `Error` isn't prefixed to msg
494+ ex.name = null;
495+
496+ options = objectMerge({
497+ // fingerprint on msg, not stack trace (legacy behavior, could be
498+ // revisited)
499+ fingerprint: msg,
500+ trimHeadFrames: (options.trimHeadFrames || 0) + 1
501+ }, options);
502+
503+ var stack = TraceKit.computeStackTrace(ex);
504+ var frames = this._prepareFrames(stack, options);
505+ data.stacktrace = {
506+ // Sentry expects frames oldest to newest
507+ frames: frames.reverse()
508+ }
509+ }
510+
458511 // Fire away!
459− this._send(
460− objectMerge({
461− message: msg + '' // Make sure it's actually a string
462− }, options)
463− );
512+ this._send(data);
464513
465514 return this;
466515 },
@@ -470,14 +519,25 @@ Raven.prototype = { · 3 unmodified lines
470519 timestamp: now() / 1000
471520 }, obj);
472521
522+ if (isFunction(this._globalOptions.breadcrumbCallback)) {
523+ var result = this._globalOptions.breadcrumbCallback(crumb);
524+
525+ if (isObject(result) && !isEmptyObject(result)) {
526+ crumb = result;
527+ } else if (result === false) {
528+ return this;
529+ }
530+ }
531+
473532 this._breadcrumbs.push(crumb);
474533 if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
475534 this._breadcrumbs.shift();
476535 }
536+ return this;
477537 },
478538
479539 addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
480− var pluginArgs = Array.prototype.slice.call(arguments, 1);
540+ var pluginArgs = [].slice.call(arguments, 1);
481541
482542 this._plugins.push([plugin, pluginArgs]);
483543 if (this._isRavenInstalled) {
@@ -586,6 +646,22 @@ Raven.prototype = { · 102 unmodified lines
586646 return this;
587647 },
588648
649+ /*
650+ * Set the breadcrumbCallback option
651+ *
652+ * @param {function} callback The callback to run which allows filtering
653+ * or mutating breadcrumbs
654+ * @return {Raven}
655+ */
656+ setBreadcrumbCallback: function(callback) {
657+ var original = this._globalOptions.breadcrumbCallback;
658+ this._globalOptions.breadcrumbCallback = isFunction(callback)
659+ ? function (data) { return callback(data, original); }
660+ : callback;
661+
662+ return this;
663+ },
664+
589665 /*
590666 * Set the shouldSendCallback option
591667 *
@@ -656,14 +732,14 @@ Raven.prototype = { · 64 unmodified lines
656732 // TODO: remove window dependence?
657733
658734 // Attempt to initialize Raven on load
659− var RavenConfig = window.RavenConfig;
735+ var RavenConfig = _window.RavenConfig;
660736 if (RavenConfig) {
661737 this.config(RavenConfig.dsn, RavenConfig.config).install();
662738 }
663739 },
664740
665741 showReportDialog: function (options) {
666− if (!window.document) // doesn't work without a document (React native)
742+ if (!_document) // doesn't work without a document (React native)
667743 return;
668744
669745 options = options || {};
@@ -691,10 +767,10 @@ Raven.prototype = { · 21 unmodified lines
691767
692768 var globalServer = this._getGlobalServer(this._parseDSN(dsn));
693769
694− var script = document.createElement('script');
770+ var script = _document.createElement('script');
695771 script.async = true;
696772 script.src = globalServer + '/api/embed/error-page/' + qs;
697− (document.head || document.body).appendChild(script);
773+ (_document.head || _document.body).appendChild(script);
698774 },
699775
700776 /**** Private functions ****/
@@ -718,11 +794,11 @@ Raven.prototype = { · 17 unmodified lines
718794
719795 eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
720796
721− if (document.createEvent) {
722− evt = document.createEvent('HTMLEvents');
797+ if (_document.createEvent) {
798+ evt = _document.createEvent('HTMLEvents');
723799 evt.initEvent(eventType, true, true);
724800 } else {
725− evt = document.createEventObject();
801+ evt = _document.createEventObject();
726802 evt.eventType = eventType;
727803 }
728804
@@ -730,14 +806,14 @@ Raven.prototype = { · 1 unmodified line
730806 evt[key] = options[key];
731807 }
732808
733− if (document.createEvent) {
809+ if (_document.createEvent) {
734810 // IE9 if standards
735− document.dispatchEvent(evt);
811+ _document.dispatchEvent(evt);
736812 } else {
737813 // IE8 regardless of Quirks or Standards
738814 // IE9 if quirks
739815 try {
740− document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
816+ _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
741817 } catch(e) {
742818 // Do nothing
743819 }
@@ -765,14 +841,14 @@ Raven.prototype = { · 21 unmodified lines
765841 return;
766842
767843 self._lastCapturedEvent = evt;
768− var elem = evt.target;
769844
845+ // try/catch both:
846+ // - accessing evt.target (see getsentry/raven-js#838, #768)
847+ // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
848+ // can throw an exception in some circumstances.
770849 var target;
771−
772− // try/catch htmlTreeAsString because it's particularly complicated, and
773− // just accessing the DOM incorrectly can throw an exception in some circumstances.
774850 try {
775− target = htmlTreeAsString(elem);
851+ target = htmlTreeAsString(evt.target);
776852 } catch (e) {
777853 target = '<unknown>';
778854 }
@@ -796,15 +872,21 @@ Raven.prototype = { · 17 unmodified lines
796872 // TODO: if somehow user switches keypress target before
797873 // debounce timeout is triggered, we will only capture
798874 // a single breadcrumb from the FIRST target (acceptable?)
799−
800875 return function (evt) {
801− var target = evt.target,
802− tagName = target && target.tagName;
876+ var target;
877+ try {
878+ target = evt.target;
879+ } catch (e) {
880+ // just accessing event properties can throw an exception in some rare circumstances
881+ // see: https://github.com/getsentry/raven-js/issues/838
882+ return;
883+ }
884+ var tagName = target && target.tagName;
803885
804886 // only consider keypress events on actual input elements
805887 // this will disregard keypresses targeting body (e.g. tabbing
806888 // through elements, hotkeys, etc)
807− if (!tagName || tagName !== 'INPUT' && tagName !== 'TEXTAREA')
889+ if (!tagName || tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)
808890 return;
809891
810892 // record first keypress in a series, but ignore subsequent
@@ -815,7 +897,7 @@ Raven.prototype = { · 4 unmodified lines
815897 }
816898 clearTimeout(timeout);
817899 self._keypressTimeout = setTimeout(function () {
818− self._keypressTimeout = null;
900+ self._keypressTimeout = null;
819901 }, debounceDuration);
820902 };
821903 },
@@ -887,7 +969,7 @@ Raven.prototype = { · 65 unmodified lines
887969 var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
888970
889971 function wrapEventTarget(global) {
890− var proto = window[global] && window[global].prototype;
972+ var proto = _window[global] && _window[global].prototype;
891973 if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
892974 fill(proto, 'addEventListener', function(orig) {
893975 return function (evtName, fn, capture, secure) { // preserve arity
@@ -901,30 +983,55 @@ Raven.prototype = { · 7 unmodified lines
901983
902984 // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
903985 // so that we don't have more than one wrapper function
904− var before;
986+ var before,
987+ clickHandler,
988+ keypressHandler;
989+
905990 if (autoBreadcrumbs && autoBreadcrumbs.dom && (global === 'EventTarget' || global === 'Node')) {
906− if (evtName === 'click'){
907− before = self._breadcrumbEventHandler(evtName);
908− } else if (evtName === 'keypress') {
909− before = self._keypressEventHandler();
910− }
991+ // NOTE: generating multiple handlers per addEventListener invocation, should
992+ // revisit and verify we can just use one (almost certainly)
993+ clickHandler = self._breadcrumbEventHandler('click');
994+ keypressHandler = self._keypressEventHandler();
995+ before = function (evt) {
996+ // need to intercept every DOM event in `before` argument, in case that
997+ // same wrapped method is re-used for different events (e.g. mousemove THEN click)
998+ // see #724
999+ if (!evt) return;
1000+
1001+ var eventType;
1002+ try {
1003+ eventType = evt.type
1004+ } catch (e) {
1005+ // just accessing event properties can throw an exception in some rare circumstances
1006+ // see: https://github.com/getsentry/raven-js/issues/838
1007+ return;
1008+ }
1009+ if (eventType === 'click')
1010+ return clickHandler(evt);
1011+ else if (eventType === 'keypress')
1012+ return keypressHandler(evt);
1013+ };
9111014 }
9121015 return orig.call(this, evtName, self.wrap(fn, undefined, before), capture, secure);
9131016 };
9141017 }, wrappedBuiltIns);
9151018 fill(proto, 'removeEventListener', function (orig) {
9161019 return function (evt, fn, capture, secure) {
917− fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn);
1020+ try {
1021+ fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn);
1022+ } catch (e) {
1023+ // ignore, accessing __raven_wrapper__ will throw in some Selenium environments
1024+ }
9181025 return orig.call(this, evt, fn, capture, secure);
9191026 };
9201027 }, wrappedBuiltIns);
9211028 }
9221029 }
9231030
924− fill(window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
925− fill(window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
926− if (window.requestAnimationFrame) {
927− fill(window, 'requestAnimationFrame', function (orig) {
1031+ fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
1032+ fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
1033+ if (_window.requestAnimationFrame) {
1034+ fill(_window, 'requestAnimationFrame', function (orig) {
9281035 return function (cb) {
9291036 return orig(self.wrap(cb));
9301037 };
@@ -937,15 +1044,6 @@ Raven.prototype = { · 6 unmodified lines
9371044 for (var i = 0; i < eventTargets.length; i++) {
9381045 wrapEventTarget(eventTargets[i]);
9391046 }
940−
941− var $ = window.jQuery || window.$;
942− if ($ && $.fn && $.fn.ready) {
943− fill($.fn, 'ready', function (orig) {
944− return function (fn) {
945− return orig.call(this, self.wrap(fn));
946− };
947− }, wrappedBuiltIns);
948− }
9491047 },
9501048
9511049
@@ -972,7 +1070,7 @@ Raven.prototype = { · 20 unmodified lines
9721070 }
9731071 }
9741072
975− if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in window) {
1073+ if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
9761074 var xhrproto = XMLHttpRequest.prototype;
9771075 fill(xhrproto, 'open', function(origOpen) {
9781076 return function (method, url) { // preserve arity
@@ -1029,17 +1127,54 @@ Raven.prototype = { · 50 unmodified lines
10291127 }, wrappedBuiltIns);
10301128 }
10311129
1130+ if (autoBreadcrumbs.xhr && 'fetch' in _window) {
1131+ fill(_window, 'fetch', function(origFetch) {
1132+ return function (fn, t) { // preserve arity
1133+ // Make a copy of the arguments to prevent deoptimization
1134+ // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
1135+ var args = new Array(arguments.length);
1136+ for(var i = 0; i < args.length; ++i) {
1137+ args[i] = arguments[i];
1138+ }
1139+
1140+ var method = 'GET';
1141+
1142+ if (args[1] && args[1].method) {
1143+ method = args[1].method;
1144+ }
1145+
1146+ var fetchData = {
1147+ method: method,
1148+ url: args[0],
1149+ status_code: null
1150+ };
1151+
1152+ self.captureBreadcrumb({
1153+ type: 'http',
1154+ category: 'fetch',
1155+ data: fetchData
1156+ });
1157+
1158+ return origFetch.apply(this, args).then(function (response) {
1159+ fetchData.status_code = response.status;
1160+
1161+ return response;
1162+ });
1163+ };
1164+ }, wrappedBuiltIns);
1165+ }
1166+
10321167 // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
10331168 // to the document. Do this before we instrument addEventListener.
10341169 if (autoBreadcrumbs.dom && this._hasDocument) {
1035− if (document.addEventListener) {
1036− document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
1037− document.addEventListener('keypress', self._keypressEventHandler(), false);
1170+ if (_document.addEventListener) {
1171+ _document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
1172+ _document.addEventListener('keypress', self._keypressEventHandler(), false);
10381173 }
10391174 else {
10401175 // IE8 Compatibility
1041− document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
1042− document.attachEvent('onkeypress', self._keypressEventHandler());
1176+ _document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
1177+ _document.attachEvent('onkeypress', self._keypressEventHandler());
10431178 }
10441179 }
10451180
@@ -1047,13 +1182,13 @@ Raven.prototype = { · 1 unmodified line
10471182 // NOTE: in Chrome App environment, touching history.pushState, *even inside
10481183 // a try/catch block*, will cause Chrome to output an error to console.error
10491184 // borrowed from: https://github.com/angular/angular.js/pull/13945/files
1050− var chrome = window.chrome;
1185+ var chrome = _window.chrome;
10511186 var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
1052− var hasPushState = !isChromePackagedApp && window.history && history.pushState;
1187+ var hasPushState = !isChromePackagedApp && _window.history && history.pushState;
10531188 if (autoBreadcrumbs.location && hasPushState) {
10541189 // TODO: remove onpopstate handler on uninstall()
1055− var oldOnPopState = window.onpopstate;
1056− window.onpopstate = function () {
1190+ var oldOnPopState = _window.onpopstate;
1191+ _window.onpopstate = function () {
10571192 var currentHref = self._location.href;
10581193 self._captureUrlChange(self._lastHref, currentHref);
10591194
@@ -1079,7 +1214,7 @@ Raven.prototype = { · 19 unmodified lines
10791214 }, wrappedBuiltIns);
10801215 }
10811216
1082− if (autoBreadcrumbs.console && 'console' in window && console.log) {
1217+ if (autoBreadcrumbs.console && 'console' in _window && console.log) {
10831218 // console
10841219 var consoleMethodCallback = function (msg, data) {
10851220 self.captureBreadcrumb({
@@ -1158,17 +1293,7 @@ Raven.prototype = { · 72 unmodified lines
11581293 },
11591294
11601295 _handleStackInfo: function(stackInfo, options) {
1161− var self = this;
1162− var frames = [];
1163−
1164− if (stackInfo.stack && stackInfo.stack.length) {
1165− each(stackInfo.stack, function(i, stack) {
1166− var frame = self._normalizeFrame(stack);
1167− if (frame) {
1168− frames.push(frame);
1169− }
1170− });
1171− }
1296+ var frames = this._prepareFrames(stackInfo, options);
11721297
11731298 this._triggerEvent('handle', {
11741299 stackInfo: stackInfo,
@@ -1180,11 +1305,34 @@ Raven.prototype = { · 5 unmodified lines
11801305 stackInfo.message,
11811306 stackInfo.url,
11821307 stackInfo.lineno,
1183− frames.slice(0, this._globalOptions.stackTraceLimit),
1308+ frames,
11841309 options
11851310 );
11861311 },
11871312
1313+ _prepareFrames: function(stackInfo, options) {
1314+ var self = this;
1315+ var frames = [];
1316+ if (stackInfo.stack && stackInfo.stack.length) {
1317+ each(stackInfo.stack, function(i, stack) {
1318+ var frame = self._normalizeFrame(stack);
1319+ if (frame) {
1320+ frames.push(frame);
1321+ }
1322+ });
1323+
1324+ // e.g. frames captured via captureMessage throw
1325+ if (options && options.trimHeadFrames) {
1326+ for (var j = 0; j < options.trimHeadFrames && j < frames.length; j++) {
1327+ frames[j].in_app = false;
1328+ }
1329+ }
1330+ }
1331+ frames = frames.slice(0, this._globalOptions.stackTraceLimit);
1332+ return frames;
1333+ },
1334+
1335+
11881336 _normalizeFrame: function(frame) {
11891337 if (!frame.url) return;
11901338
@@ -1210,7 +1358,6 @@ Raven.prototype = { · 19 unmodified lines
12101358
12111359 _processException: function(type, message, fileurl, lineno, frames, options) {
12121360 var stacktrace;
1213−
12141361 if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;
12151362
12161363 message += '';
@@ -1266,25 +1413,99 @@ Raven.prototype = { · 49 unmodified lines
12661413 },
12671414
12681415 _getHttpData: function() {
1269− if (!this._hasDocument || !document.location || !document.location.href) {
1270− return;
1416+ if (!this._hasNavigator && !this._hasDocument) return;
1417+ var httpData = {};
1418+
1419+ if (this._hasNavigator && _navigator.userAgent) {
1420+ httpData.headers = {
1421+ 'User-Agent': navigator.userAgent
1422+ };
12711423 }
12721424
1273− var httpData = {
1274− headers: {
1275− 'User-Agent': navigator.userAgent
1425+ if (this._hasDocument) {
1426+ if (_document.location && _document.location.href) {
1427+ httpData.url = _document.location.href;
12761428 }
1277− };
1429+ if (_document.referrer) {
1430+ if (!httpData.headers) httpData.headers = {};
1431+ httpData.headers.Referer = _document.referrer;
1432+ }
1433+ }
12781434
1279− httpData.url = document.location.href;
1435+ return httpData;
1436+ },
1437+
1438+ _resetBackoff: function() {
1439+ this._backoffDuration = 0;
1440+ this._backoffStart = null;
1441+ },
1442+
1443+ _shouldBackoff: function() {
1444+ return this._backoffDuration && now() - this._backoffStart < this._backoffDuration;
1445+ },
1446+
1447+ /**
1448+ * Returns true if the in-process data payload matches the signature
1449+ * of the previously-sent data
1450+ *
1451+ * NOTE: This has to be done at this level because TraceKit can generate
1452+ * data from window.onerror WITHOUT an exception object (IE8, IE9,
1453+ * other old browsers). This can take the form of an "exception"
1454+ * data object with a single frame (derived from the onerror args).
1455+ */
1456+ _isRepeatData: function (current) {
1457+ var last = this._lastData;
12801458
1281− if (document.referrer) {
1282− httpData.headers.Referer = document.referrer;
1459+ if (!last ||
1460+ current.message !== last.message || // defined for captureMessage
1461+ current.culprit !== last.culprit) // defined for captureException/onerror
1462+ return false;
1463+
1464+ // Stacktrace interface (i.e. from captureMessage)
1465+ if (current.stacktrace || last.stacktrace) {
1466+ return isSameStacktrace(current.stacktrace, last.stacktrace);
1467+ }
1468+ // Exception interface (i.e. from captureException/onerror)
1469+ else if (current.exception || last.exception) {
1470+ return isSameException(current.exception, last.exception);
12831471 }
12841472
1285− return httpData;
1473+ return true;
12861474 },
12871475
1476+ _setBackoffState: function(request) {
1477+ // If we are already in a backoff state, don't change anything
1478+ if (this._shouldBackoff()) {
1479+ return;
1480+ }
1481+
1482+ var status = request.status;
1483+
1484+ // 400 - project_id doesn't exist or some other fatal
1485+ // 401 - invalid/revoked dsn
1486+ // 429 - too many requests
1487+ if (!(status === 400 || status === 401 || status === 429))
1488+ return;
1489+
1490+ var retry;
1491+ try {
1492+ // If Retry-After is not in Access-Control-Expose-Headers, most
1493+ // browsers will throw an exception trying to access it
1494+ retry = request.getResponseHeader('Retry-After');
1495+ retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
1496+ } catch (e) {
1497+ /* eslint no-empty:0 */
1498+ }
1499+
1500+
1501+ this._backoffDuration = retry
1502+ // If Sentry server returned a Retry-After value, use it
1503+ ? retry
1504+ // Otherwise, double the last backoff duration (starts at 1 sec)
1505+ : this._backoffDuration * 2 || 1000;
1506+
1507+ this._backoffStart = now();
1508+ },
12881509
12891510 _send: function(data) {
12901511 var globalOptions = this._globalOptions;
@@ -1299,6 +1520,9 @@ Raven.prototype = { · 8 unmodified lines
12991520 baseData.request = httpData;
13001521 }
13011522
1523+ // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
1524+ if (data.trimHeadFrames) delete data.trimHeadFrames;
1525+
13021526 data = objectMerge(baseData, data);
13031527
13041528 // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
@@ -1347,24 +1571,46 @@ Raven.prototype = { · 42 unmodified lines
13471571 return;
13481572 }
13491573
1574+ // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests),
1575+ // so drop requests until "cool-off" period has elapsed.
1576+ if (this._shouldBackoff()) {
1577+ this._logDebug('warn', 'Raven dropped error due to backoff: ', data);
1578+ return;
1579+ }
1580+
13501581 this._sendProcessedPayload(data);
13511582 },
13521583
1584+ _getUuid: function () {
1585+ return uuid4();
1586+ },
1587+
13531588 _sendProcessedPayload: function(data, callback) {
13541589 var self = this;
13551590 var globalOptions = this._globalOptions;
13561591
1592+ if (!this.isSetup()) return;
1593+
13571594 // Send along an event_id if not explicitly passed.
13581595 // This event_id can be used to reference the error within Sentry itself.
13591596 // Set lastEventId after we know the error should actually be sent
1360− this._lastEventId = data.event_id || (data.event_id = uuid4());
1597+ this._lastEventId = data.event_id || (data.event_id = this._getUuid());
13611598
13621599 // Try and clean up the packet before sending by truncating long values
13631600 data = this._trimPacket(data);
13641601
1365− this._logDebug('debug', 'Raven about to send:', data);
1602+ // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback,
1603+ // but this would require copying an un-truncated copy of the data packet, which can be
1604+ // arbitrarily deep (extra_data) -- could be worthwhile? will revisit
1605+ if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) {
1606+ this._logDebug('warn', 'Raven dropped repeat event: ', data);
1607+ return;
1608+ }
13661609
1367− if (!this.isSetup()) return;
1610+ // Store outbound payload after trim
1611+ this._lastData = data;
1612+
1613+ this._logDebug('debug', 'Raven about to send:', data);
13681614
13691615 var auth = {
13701616 sentry_version: '7',
@@ -1392,6 +1638,8 @@ Raven.prototype = { · 21 unmodified lines
13921638 data: data,
13931639 options: globalOptions,
13941640 onSuccess: function success() {
1641+ self._resetBackoff();
1642+
13951643 self._triggerEvent('success', {
13961644 data: data,
13971645 src: url
@@ -1399,6 +1647,12 @@ Raven.prototype = { · 1 unmodified line
13991647 callback && callback();
14001648 },
14011649 onError: function failure(error) {
1650+ self._logDebug('error', 'Raven transport failed to send: ', error);
1651+
1652+ if (error.request) {
1653+ self._setBackoffState(error.request);
1654+ }
1655+
14021656 self._triggerEvent('failure', {
14031657 data: data,
14041658 src: url
@@ -1426,7 +1680,9 @@ Raven.prototype = { · 21 unmodified lines
14261680 opts.onSuccess();
14271681 }
14281682 } else if (opts.onError) {
1429− opts.onError(new Error('Sentry error code: ' + request.status));
1683+ var err = new Error('Sentry error code: ' + request.status);
1684+ err.request = request;
1685+ opts.onError(err);
14301686 }
14311687 }
14321688
@@ -1473,46 +1729,12 @@ Raven.prototype = { · 40 unmodified lines
14731729 }
14741730 };
14751731
1476−// Deprecations
1477−Raven.prototype.setUser = Raven.prototype.setUserContext;
1478−Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
1479−
1480−module.exports = Raven;
1481−
1482−},{"1":1,"2":2,"3":3,"6":6,"7":7}],5:[function(_dereq_,module,exports){
1483−/**
1484− * Enforces a single instance of the Raven client, and the
1485− * main entry point for Raven. If you are a consumer of the
1486− * Raven library, you SHOULD load this file (vs raven.js).
1487− **/
1488−
1489−'use strict';
1490−
1491−var RavenConstructor = _dereq_(4);
1492−
1493−var _Raven = window.Raven;
1494−
1495−var Raven = new RavenConstructor();
1496−
1497−/*
1498− * Allow multiple versions of Raven to be installed.
1499− * Strip Raven from the global context and returns the instance.
1732+/*------------------------------------------------
1733+ * utils
15001734 *
1501− * @return {Raven}
1735+ * conditionally exported for test via Raven.utils
1736+ =================================================
15021737 */
1503−Raven.noConflict = function () {
1504− window.Raven = _Raven;
1505− return Raven;
1506−};
1507−
1508−Raven.afterLoad();
1509−
1510−module.exports = Raven;
1511−
1512−},{"4":4}],6:[function(_dereq_,module,exports){
1513−/*eslint no-extra-parens:0*/
1514−'use strict';
1515−
15161738 var objectPrototype = Object.prototype;
15171739
15181740 function isUndefined(what) {
@@ -1638,7 +1860,7 @@ function parseUrl(url) { · 119 unmodified lines
16381860 };
16391861 }
16401862 function uuid4() {
1641− var crypto = window.crypto || window.msCrypto;
1863+ var crypto = _window.crypto || _window.msCrypto;
16421864
16431865 if (!isUndefined(crypto) && crypto.getRandomValues) {
16441866 // Use window.crypto API if available
@@ -1678,6 +1900,7 @@ function uuid4() { · 33 unmodified lines
16781900 * @returns {string}
16791901 */
16801902 function htmlTreeAsString(elem) {
1903+ /* eslint no-extra-parens:0*/
16811904 var MAX_TRAVERSE_HEIGHT = 5,
16821905 MAX_OUTPUT_LEN = 80,
16831906 out = [],
@@ -1732,7 +1955,7 @@ function htmlElementAsString(elem) { · 48 unmodified lines
17321955
17331956 className = elem.className;
17341957 if (className && isString(className)) {
1735− classes = className.split(' ');
1958+ classes = className.split(/\s+/);
17361959 for (i = 0; i < classes.length; i++) {
17371960 out.push('.' + classes[i]);
17381961 }
@@ -1748,6 +1971,58 @@ function htmlElementAsString(elem) { · 9 unmodified lines
17481971 return out.join('');
17491972 }
17501973
1974+/**
1975+ * Returns true if either a OR b is truthy, but not both
1976+ */
1977+function isOnlyOneTruthy(a, b) {
1978+ return !!(!!a ^ !!b);
1979+}
1980+
1981+/**
1982+ * Returns true if the two input exception interfaces have the same content
1983+ */
1984+function isSameException(ex1, ex2) {
1985+ if (isOnlyOneTruthy(ex1, ex2))
1986+ return false;
1987+
1988+ ex1 = ex1.values[0];
1989+ ex2 = ex2.values[0];
1990+
1991+ if (ex1.type !== ex2.type ||
1992+ ex1.value !== ex2.value)
1993+ return false;
1994+
1995+ return isSameStacktrace(ex1.stacktrace, ex2.stacktrace);
1996+}
1997+
1998+/**
1999+ * Returns true if the two input stack trace interfaces have the same content
2000+ */
2001+function isSameStacktrace(stack1, stack2) {
2002+ if (isOnlyOneTruthy(stack1, stack2))
2003+ return false;
2004+
2005+ var frames1 = stack1.frames;
2006+ var frames2 = stack2.frames;
2007+
2008+ // Exit early if frame count differs
2009+ if (frames1.length !== frames2.length)
2010+ return false;
2011+
2012+ // Iterate through every frame; bail out if anything differs
2013+ var a, b;
2014+ for (var i = 0; i < frames1.length; i++) {
2015+ a = frames1[i];
2016+ b = frames2[i];
2017+ if (a.filename !== b.filename ||
2018+ a.lineno !== b.lineno ||
2019+ a.colno !== b.colno ||
2020+ a['function'] !== b['function'])
2021+ return false;
2022+ }
2023+ return true;
2024+}
2025+
17512026 /**
17522027 * Polyfill a method
17532028 * @param obj object e.g. `document`
@@ -1763,37 +2038,83 @@ function fill(obj, name, replacement, track) { · 9 unmodified lines
17632038 }
17642039 }
17652040
1766−module.exports = {
1767− isUndefined: isUndefined,
1768− isFunction: isFunction,
1769− isString: isString,
1770− isObject: isObject,
1771− isEmptyObject: isEmptyObject,
1772− isError: isError,
1773− each: each,
1774− objectMerge: objectMerge,
1775− truncate: truncate,
1776− hasKey: hasKey,
1777− joinRegExp: joinRegExp,
1778− urlencode: urlencode,
1779− uuid4: uuid4,
1780− htmlTreeAsString: htmlTreeAsString,
1781− htmlElementAsString: htmlElementAsString,
1782− parseUrl: parseUrl,
1783− fill: fill
2041+if (typeof __DEV__ !== 'undefined' && __DEV__) {
2042+ Raven.utils = {
2043+ isUndefined: isUndefined,
2044+ isFunction: isFunction,
2045+ isString: isString,
2046+ isObject: isObject,
2047+ isEmptyObject: isEmptyObject,
2048+ isError: isError,
2049+ each: each,
2050+ objectMerge: objectMerge,
2051+ truncate: truncate,
2052+ hasKey: hasKey,
2053+ joinRegExp: joinRegExp,
2054+ urlencode: urlencode,
2055+ uuid4: uuid4,
2056+ htmlTreeAsString: htmlTreeAsString,
2057+ htmlElementAsString: htmlElementAsString,
2058+ parseUrl: parseUrl,
2059+ fill: fill
2060+ };
17842061 };
17852062
1786−},{}],7:[function(_dereq_,module,exports){
2063+// Deprecations
2064+Raven.prototype.setUser = Raven.prototype.setUserContext;
2065+Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
2066+
2067+module.exports = Raven;
2068+
2069+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2070+},{"1":1,"2":2,"3":3,"6":6}],5:[function(_dereq_,module,exports){
2071+(function (global){
2072+/**
2073+ * Enforces a single instance of the Raven client, and the
2074+ * main entry point for Raven. If you are a consumer of the
2075+ * Raven library, you SHOULD load this file (vs raven.js).
2076+ **/
2077+
17872078 'use strict';
17882079
1789−var utils = _dereq_(6);
2080+var RavenConstructor = _dereq_(4);
2081+
2082+// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2083+var _window = typeof window !== 'undefined' ? window
2084+ : typeof global !== 'undefined' ? global
2085+ : typeof self !== 'undefined' ? self
2086+ : {};
2087+var _Raven = _window.Raven;
2088+
2089+var Raven = new RavenConstructor();
17902090
1791−var hasKey = utils.hasKey;
1792−var isString = utils.isString;
1793−var isUndefined = utils.isUndefined;
2091+/*
2092+ * Allow multiple versions of Raven to be installed.
2093+ * Strip Raven from the global context and returns the instance.
2094+ *
2095+ * @return {Raven}
2096+ */
2097+Raven.noConflict = function () {
2098+ _window.Raven = _Raven;
2099+ return Raven;
2100+};
2101+
2102+Raven.afterLoad();
2103+
2104+module.exports = Raven;
2105+
2106+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2107+},{"4":4}],6:[function(_dereq_,module,exports){
2108+(function (global){
2109+'use strict';
17942110
17952111 /*
1796− TraceKit - Cross brower stack traces - github.com/occ/TraceKit
2112+ TraceKit - Cross brower stack traces
2113+
2114+ This was originally forked from github.com/occ/TraceKit, but has since been
2115+ largely re-written and is now maintained as part of raven-js. Tests for
2116+ this are in test/vendor.
2117+
17972118 MIT license
17982119 */
17992120
@@ -1802,6 +2123,12 @@ var TraceKit = { · 2 unmodified lines
18022123 debug: false
18032124 };
18042125
2126+// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2127+var _window = typeof window !== 'undefined' ? window
2128+ : typeof global !== 'undefined' ? global
2129+ : typeof self !== 'undefined' ? self
2130+ : {};
2131+
18052132 // global reference to slice
18062133 var _slice = [].slice;
18072134 var UNKNOWN_FUNCTION = '?';
@@ -1810,7 +2137,7 @@ var UNKNOWN_FUNCTION = '?'; · 2 unmodified lines
18102137 var ERROR_TYPES_RE = /^(?:Uncaught (?:exception: )?)?((?:Eval|Internal|Range|Reference|Syntax|Type|URI)Error): ?(.*)$/;
18112138
18122139 function getLocationHref() {
1813− if (typeof document === 'undefined')
2140+ if (typeof document === 'undefined' || typeof document.location === 'undefined')
18142141 return '';
18152142
18162143 return document.location.href;
@@ -1900,7 +2227,7 @@ TraceKit.report = (function reportModuleWrapper() { · 83 unmodified lines
19002227 return;
19012228 }
19022229 for (var i in handlers) {
1903− if (hasKey(handlers, i)) {
2230+ if (handlers.hasOwnProperty(i)) {
19042231 try {
19052232 handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
19062233 } catch (inner) {
@@ -1949,7 +2276,7 @@ TraceKit.report = (function reportModuleWrapper() { · 42 unmodified lines
19492276 var name = undefined;
19502277 var msg = message; // must be new var or will modify original `arguments`
19512278 var groups;
1952− if (isString(message)) {
2279+ if ({}.toString.call(message) === '[object String]') {
19532280 var groups = message.match(ERROR_TYPES_RE);
19542281 if (groups) {
19552282 name = groups[1];
@@ -1980,8 +2307,8 @@ TraceKit.report = (function reportModuleWrapper() { · 24 unmodified lines
19802307 if (_onErrorHandlerInstalled) {
19812308 return;
19822309 }
1983− _oldOnerrorHandler = window.onerror;
1984− window.onerror = traceKitWindowOnError;
2310+ _oldOnerrorHandler = _window.onerror;
2311+ _window.onerror = traceKitWindowOnError;
19852312 _onErrorHandlerInstalled = true;
19862313 }
19872314
@@ -1990,7 +2317,7 @@ TraceKit.report = (function reportModuleWrapper() { · 2 unmodified lines
19902317 if (!_onErrorHandlerInstalled) {
19912318 return;
19922319 }
1993− window.onerror = _oldOnerrorHandler;
2320+ _window.onerror = _oldOnerrorHandler;
19942321 _onErrorHandlerInstalled = false;
19952322 _oldOnerrorHandler = undefined;
19962323 }
@@ -2030,7 +2357,7 @@ TraceKit.report = (function reportModuleWrapper() { · 33 unmodified lines
20302357 // slow slow IE to see if onerror occurs or not before reporting
20312358 // this exception; otherwise, we will end up with an incomplete
20322359 // stack trace
2033− window.setTimeout(function () {
2360+ setTimeout(function () {
20342361 if (lastException === ex) {
20352362 processLastException();
20362363 }
@@ -2164,10 +2491,10 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 127 unmodified lines
21642491 * @return {?Object.<string, *>} Stack trace information.
21652492 */
21662493 function computeStackTraceFromStackProp(ex) {
2167− if (isUndefined(ex.stack) || !ex.stack) return;
2494+ if (typeof ex.stack === 'undefined' || !ex.stack) return;
21682495
21692496 var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|<anonymous>).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
2170− gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i,
2497+ gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|resource|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i,
21712498 winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
21722499 lines = ex.stack.split('\n'),
21732500 stack = [],
@@ -2216,7 +2543,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 42 unmodified lines
22162543 return null;
22172544 }
22182545
2219− if (!stack[0].column && !isUndefined(ex.columnNumber)) {
2546+ if (!stack[0].column && typeof ex.columnNumber !== 'undefined') {
22202547 // FireFox uses this awesome columnNumber property for its top frame
22212548 // Also note, Firefox's column number is 0-based and everything else expects 1-based,
22222549 // so adding 1
@@ -2231,153 +2558,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 8 unmodified lines
22312558 };
22322559 }
22332560
2234− /**
2235− * Computes stack trace information from the stacktrace property.
2236− * Opera 10 uses this property.
2237− * @param {Error} ex
2238− * @return {?Object.<string, *>} Stack trace information.
2239− */
2240− function computeStackTraceFromStacktraceProp(ex) {
2241− // Access and store the stacktrace property before doing ANYTHING
2242− // else to it because Opera is not very good at providing it
2243− // reliably in other circumstances.
2244− var stacktrace = ex.stacktrace;
2245− if (isUndefined(ex.stacktrace) || !ex.stacktrace) return;
2246−
2247− var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i,
2248− opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\))? in (.*):\s*$/i,
2249− lines = stacktrace.split('\n'),
2250− stack = [],
2251− parts;
2252−
2253− for (var line = 0; line < lines.length; line += 2) {
2254− var element = null;
2255− if ((parts = opera10Regex.exec(lines[line]))) {
2256− element = {
2257− 'url': parts[2],
2258− 'line': +parts[1],
2259− 'column': null,
2260− 'func': parts[3],
2261− 'args':[]
2262− };
2263− } else if ((parts = opera11Regex.exec(lines[line]))) {
2264− element = {
2265− 'url': parts[6],
2266− 'line': +parts[1],
2267− 'column': +parts[2],
2268− 'func': parts[3] || parts[4],
2269− 'args': parts[5] ? parts[5].split(',') : []
2270− };
2271− }
2272−
2273− if (element) {
2274− if (!element.func && element.line) {
2275− element.func = UNKNOWN_FUNCTION;
2276− }
2277−
2278− stack.push(element);
2279− }
2280− }
2281−
2282− if (!stack.length) {
2283− return null;
2284− }
2285−
2286− return {
2287− 'name': ex.name,
2288− 'message': ex.message,
2289− 'url': getLocationHref(),
2290− 'stack': stack
2291− };
2292− }
2293−
2294− /**
2295− * NOT TESTED.
2296− * Computes stack trace information from an error message that includes
2297− * the stack trace.
2298− * Opera 9 and earlier use this method if the option to show stack
2299− * traces is turned on in opera:config.
2300− * @param {Error} ex
2301− * @return {?Object.<string, *>} Stack information.
2302− */
2303− function computeStackTraceFromOperaMultiLineMessage(ex) {
2304− // Opera includes a stack trace into the exception message. An example is:
2305− //
2306− // Statement on line 3: Undefined variable: undefinedFunc
2307− // Backtrace:
2308− // Line 3 of linked script file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.js: In function zzz
2309− // undefinedFunc(a);
2310− // Line 7 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function yyy
2311− // zzz(x, y, z);
2312− // Line 3 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function xxx
2313− // yyy(a, a, a);
2314− // Line 1 of function script
2315− // try { xxx('hi'); return false; } catch(ex) { TraceKit.report(ex); }
2316− // ...
2317−
2318− var lines = ex.message.split('\n');
2319− if (lines.length < 4) {
2320− return null;
2321− }
2322−
2323− var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|https?|blob)\S+)(?:: in function (\S+))?\s*$/i,
2324− lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|https?|blob)\S+)(?:: in function (\S+))?\s*$/i,
2325− lineRE3 = /^\s*Line (\d+) of function script\s*$/i,
2326− stack = [],
2327− scripts = document.getElementsByTagName('script'),
2328− parts;
2329−
2330− for (var line = 2; line < lines.length; line += 2) {
2331− var item = null;
2332− if ((parts = lineRE1.exec(lines[line]))) {
2333− item = {
2334− 'url': parts[2],
2335− 'func': parts[3],
2336− 'args': [],
2337− 'line': +parts[1],
2338− 'column': null
2339− };
2340− } else if ((parts = lineRE2.exec(lines[line]))) {
2341− item = {
2342− 'url': parts[3],
2343− 'func': parts[4],
2344− 'args': [],
2345− 'line': +parts[1],
2346− 'column': null // TODO: Check to see if inline#1 (+parts[2]) points to the script number or column number.
2347− };
2348− var relativeLine = (+parts[1]); // relative to the start of the <SCRIPT> block
2349− } else if ((parts = lineRE3.exec(lines[line]))) {
2350− var url = window.location.href.replace(/#.*$/, '');
2351− item = {
2352− 'url': url,
2353− 'func': '',
2354− 'args': [],
2355− 'line': parts[1],
2356− 'column': null
2357− };
2358− }
2359−
2360− if (item) {
2361− if (!item.func) {
2362− item.func = UNKNOWN_FUNCTION;
2363− }
2364−
2365− stack.push(item);
2366− }
2367− }
2368−
2369− if (!stack.length) {
2370− return null; // could not parse multiline exception message as Opera stack trace
2371− }
2372−
2373− return {
2374− 'name': ex.name,
2375− 'message': lines[0],
2376− 'url': getLocationHref(),
2377− 'stack': stack
2378− };
2379− }
2380−
23812561 /**
23822562 * Adds information about the first frame to incomplete stack traces.
23832563 * Safari and IE require this to get complete data on the first frame.
@@ -2502,20 +2682,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 118 unmodified lines
25022682 var stack = null;
25032683 depth = (depth == null ? 0 : +depth);
25042684
2505− try {
2506− // This must be tried first because Opera 10 *destroys*
2507− // its stacktrace property if you try to access the stack
2508− // property first!!
2509− stack = computeStackTraceFromStacktraceProp(ex);
2510− if (stack) {
2511− return stack;
2512− }
2513− } catch (e) {
2514− if (TraceKit.debug) {
2515− throw e;
2516− }
2517− }
2518−
25192685 try {
25202686 stack = computeStackTraceFromStackProp(ex);
25212687 if (stack) {
@@ -2527,17 +2693,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 5 unmodified lines
25272693 }
25282694 }
25292695
2530− try {
2531− stack = computeStackTraceFromOperaMultiLineMessage(ex);
2532− if (stack) {
2533− return stack;
2534− }
2535− } catch (e) {
2536− if (TraceKit.debug) {
2537− throw e;
2538− }
2539− }
2540−
25412696 try {
25422697 stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
25432698 if (stack) {
@@ -2564,5 +2719,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 20 unmodified lines
25642719
25652720 module.exports = TraceKit;
25662721
2567−},{"6":6}]},{},[5])(5)
2568−});
2722+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2723+},{}]},{},[5])(5)
2724+});