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 */
2 2
3/*3/*
4 * Includes TraceKit4 * Includes TraceKit
5 * https://github.com/getsentry/TraceKit5 * https://github.com/getsentry/TraceKit
6 *6 *
7 * Copyright 2016 Matt Robenolt and other contributors7 * Copyright 2017 Matt Robenolt and other contributors
8 * Released under the BSD license8 * Released under the BSD license
9 * https://github.com/getsentry/raven-js/blob/master/LICENSE9 * https://github.com/getsentry/raven-js/blob/master/LICENSE
10 *10 *
@@ -91,30 +91,14 @@ module.exports = { · 80 unmodified lines
91};91};
92 92
93},{}],4:[function(_dereq_,module,exports){93},{}],4:[function(_dereq_,module,exports){
94/*global XDomainRequest:false*/94(function (global){
95/*global XDomainRequest:false, __DEV__:false*/
95'use strict';96'use strict';
96 97
97var TraceKit = _dereq_(7);98var TraceKit = _dereq_(6);
98var RavenConfigError = _dereq_(2);99var RavenConfigError = _dereq_(2);
99var utils = _dereq_(6);
100var stringify = _dereq_(1);100var stringify = _dereq_(1);
101 101
102var isFunction = utils.isFunction;
103var isUndefined = utils.isUndefined;
104var isError = utils.isError;
105var isEmptyObject = utils.isEmptyObject;
106var hasKey = utils.hasKey;
107var joinRegExp = utils.joinRegExp;
108var each = utils.each;
109var objectMerge = utils.objectMerge;
110var truncate = utils.truncate;
111var urlencode = utils.urlencode;
112var uuid4 = utils.uuid4;
113var htmlTreeAsString = utils.htmlTreeAsString;
114var parseUrl = utils.parseUrl;
115var isString = utils.isString;
116var fill = utils.fill;
117
118var wrapConsoleMethod = _dereq_(3).wrapMethod;102var wrapConsoleMethod = _dereq_(3).wrapMethod;
119 103
120var dsnKeys = 'source protocol user pass host port path'.split(' '),104var dsnKeys = 'source protocol user pass host port path'.split(' '),
@@ -124,6 +108,13 @@ function now() { · 3 unmodified lines
124 return +new Date();108 return +new Date();
125}109}
126 110
111// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
112var _window = typeof window !== 'undefined' ? window
113 : typeof global !== 'undefined' ? global
114 : typeof self !== 'undefined' ? self
115 : {};
116var _document = _window.document;
117var _navigator = _window.navigator;
127 118
128// First, check for JSON support119// First, check for JSON support
129// If there is no JSON, we no-op the core features of Raven120// If there is no JSON, we no-op the core features of Raven
@@ -131,8 +122,10 @@ function now() { · 1 unmodified line
131function Raven() {122function Raven() {
132 this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);123 this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
133 // Raven can run in contexts where there's no document (react-native)124 // 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);
135 this._lastCapturedException = null;127 this._lastCapturedException = null;
128 this._lastData = null;
136 this._lastEventId = null;129 this._lastEventId = null;
137 this._globalServer = null;130 this._globalServer = null;
138 this._globalKey = null;131 this._globalKey = null;
@@ -155,7 +148,7 @@ function Raven() { · 16 unmodified lines
155 this._originalErrorStackTraceLimit = Error.stackTraceLimit;148 this._originalErrorStackTraceLimit = Error.stackTraceLimit;
156 // capture references to window.console *and* all its methods first149 // capture references to window.console *and* all its methods first
157 // before the console plugin has a chance to monkey patch150 // before the console plugin has a chance to monkey patch
158 this._originalConsole = window.console || {};151 this._originalConsole = _window.console || {};
159 this._originalConsoleMethods = {};152 this._originalConsoleMethods = {};
160 this._plugins = [];153 this._plugins = [];
161 this._startTime = now();154 this._startTime = now();
@@ -163,8 +156,9 @@ function Raven() { · 1 unmodified line
163 this._breadcrumbs = [];156 this._breadcrumbs = [];
164 this._lastCapturedEvent = null;157 this._lastCapturedEvent = null;
165 this._keypressTimeout;158 this._keypressTimeout;
166 this._location = window.location;159 this._location = _window.location;
167 this._lastHref = this._location && this._location.href;160 this._lastHref = this._location && this._location.href;
161 this._resetBackoff();
168 162
169 for (var method in this._originalConsole) { // eslint-disable-line guard-for-in163 for (var method in this._originalConsole) { // eslint-disable-line guard-for-in
170 this._originalConsoleMethods[method] = this._originalConsole[method];164 this._originalConsoleMethods[method] = this._originalConsole[method];
@@ -182,7 +176,7 @@ Raven.prototype = { · 11 unmodified lines
182 // webpack (using a build step causes webpack #1617). Grunt verifies that176 // webpack (using a build step causes webpack #1617). Grunt verifies that
183 // this value matches package.json during build.177 // this value matches package.json during build.
184 // See: https://github.com/getsentry/raven-js/issues/465178 // See: https://github.com/getsentry/raven-js/issues/465
185 VERSION: '3.5.1',179 VERSION: '3.11.0',
186 180
187 debug: false,181 debug: false,
188 182
@@ -198,41 +192,39 @@ Raven.prototype = { · 9 unmodified lines
198 config: function(dsn, options) {192 config: function(dsn, options) {
199 var self = this;193 var self = this;
200 194
201 if (this._globalServer) {195 if (self._globalServer) {
202 this._logDebug('error', 'Error: Raven has already been configured');196 this._logDebug('error', 'Error: Raven has already been configured');
203 return this;197 return self;
204 }198 }
205 if (!dsn) return this;199 if (!dsn) return self;
200
201 var globalOptions = self._globalOptions;
206 202
207 // merge in options203 // merge in options
208 if (options) {204 if (options) {
209 each(options, function(key, value){205 each(options, function(key, value){
210 // tags and extra are special and need to be put into context206 // 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') {
212 self._globalContext[key] = value;208 self._globalContext[key] = value;
213 } else {209 } else {
214 self._globalOptions[key] = value;210 globalOptions[key] = value;
215 }211 }
216 });212 });
217 }213 }
218 214
219 var uri = this._parseDSN(dsn),215 self.setDSN(dsn);
220 lastSlash = uri.path.lastIndexOf('/'),
221 path = uri.path.substr(1, lastSlash);
222
223 this._dsn = dsn;
224 216
225 // "Script error." is hard coded into browsers for errors that it can't read.217 // "Script error." is hard coded into browsers for errors that it can't read.
226 // this is the result of a script being pulled in from an external domain and CORS.218 // this is the result of a script being pulled in from an external domain and CORS.
227 this._globalOptions.ignoreErrors.push(/^Script error\.?$/);219 globalOptions.ignoreErrors.push(/^Script error\.?$/);
228 this._globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);220 globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
229 221
230 // join regexp rules into one big rule222 // join regexp rules into one big rule
231 this._globalOptions.ignoreErrors = joinRegExp(this._globalOptions.ignoreErrors);223 globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
232 this._globalOptions.ignoreUrls = this._globalOptions.ignoreUrls.length ? joinRegExp(this._globalOptions.ignoreUrls) : false;224 globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
233 this._globalOptions.whitelistUrls = this._globalOptions.whitelistUrls.length ? joinRegExp(this._globalOptions.whitelistUrls) : false;225 globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
234 this._globalOptions.includePaths = joinRegExp(this._globalOptions.includePaths);226 globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
235 this._globalOptions.maxBreadcrumbs = Math.max(0, Math.min(this._globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100227 globalOptions.maxBreadcrumbs = Math.max(0, Math.min(globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100
236 228
237 var autoBreadcrumbDefaults = {229 var autoBreadcrumbDefaults = {
238 xhr: true,230 xhr: true,
@@ -241,27 +233,18 @@ Raven.prototype = { · 2 unmodified lines
241 location: true233 location: true
242 };234 };
243 235
244 var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;236 var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
245 if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {237 if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
246 autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);238 autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
247 } else if (autoBreadcrumbs !== false) {239 } else if (autoBreadcrumbs !== false) {
248 autoBreadcrumbs = autoBreadcrumbDefaults;240 autoBreadcrumbs = autoBreadcrumbDefaults;
249 }241 }
250 this._globalOptions.autoBreadcrumbs = autoBreadcrumbs;242 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);
257 243
258 this._globalEndpoint = this._globalServer +244 TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
259 '/' + path + 'api/' + this._globalProject + '/store/';
260
261 TraceKit.collectWindowErrors = !!this._globalOptions.collectWindowErrors;
262 245
263 // return for chaining246 // return for chaining
264 return this;247 return self;
265 },248 },
266 249
267 /*250 /*
@@ -274,24 +257,50 @@ Raven.prototype = { · 6 unmodified lines
274 */257 */
275 install: function() {258 install: function() {
276 var self = this;259 var self = this;
277 if (this.isSetup() && !this._isRavenInstalled) {260 if (self.isSetup() && !self._isRavenInstalled) {
278 TraceKit.report.subscribe(function () {261 TraceKit.report.subscribe(function () {
279 self._handleOnErrorStackInfo.apply(self, arguments);262 self._handleOnErrorStackInfo.apply(self, arguments);
280 });263 });
281 this._instrumentTryCatch();264 self._instrumentTryCatch();
282 if (self._globalOptions.autoBreadcrumbs)265 if (self._globalOptions.autoBreadcrumbs)
283 this._instrumentBreadcrumbs();266 self._instrumentBreadcrumbs();
284 267
285 // Install all of the plugins268 // Install all of the plugins
286 this._drainPlugins();269 self._drainPlugins();
287 270
288 this._isRavenInstalled = true;271 self._isRavenInstalled = true;
289 }272 }
290 273
291 Error.stackTraceLimit = this._globalOptions.stackTraceLimit;274 Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
292 return this;275 return this;
293 },276 },
294 277
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
295 /*304 /*
296 * Wrap code within a context so Raven can capture errors305 * Wrap code within a context so Raven can capture errors
297 * reliably across domains that is executed immediately.306 * reliably across domains that is executed immediately.
@@ -343,18 +352,18 @@ Raven.prototype = { · 45 unmodified lines
343 if (func.__raven__) {352 if (func.__raven__) {
344 return func;353 return func;
345 }354 }
355
356 // If this has already been wrapped in the past, return that
357 if (func.__raven_wrapper__ ){
358 return func.__raven_wrapper__ ;
359 }
346 } catch (e) {360 } catch (e) {
347 // Just accessing the __raven__ prop in some Selenium environments361 // Just accessing custom props in some Selenium environments
348 // can cause a "Permission denied" exception (see raven-js#495).362 // can cause a "Permission denied" exception (see raven-js#495).
349 // Bail on wrapping and return the function as-is (defers to window.onerror).363 // Bail on wrapping and return the function as-is (defers to window.onerror).
350 return func;364 return func;
351 }365 }
352 366
353 // If this has already been wrapped in the past, return that
354 if (func.__raven_wrapper__ ){
355 return func.__raven_wrapper__ ;
356 }
357
358 function wrapped() {367 function wrapped() {
359 var args = [], i = arguments.length,368 var args = [], i = arguments.length,
360 deep = !options || options && options.deep !== false;369 deep = !options || options && options.deep !== false;
@@ -368,6 +377,10 @@ Raven.prototype = { · 7 unmodified lines
368 while(i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];377 while(i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
369 378
370 try {379 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.
371 return func.apply(this, args);384 return func.apply(this, args);
372 } catch(e) {385 } catch(e) {
373 self._ignoreNextOnError();386 self._ignoreNextOnError();
@@ -418,7 +431,12 @@ Raven.prototype = { · 44 unmodified lines
418 */431 */
419 captureException: function(ex, options) {432 captureException: function(ex, options) {
420 // If not an Error is passed through, recall as a message instead433 // 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 }
422 440
423 // Store the raw exception object for potential debugging and introspection441 // Store the raw exception object for potential debugging and introspection
424 this._lastCapturedException = ex;442 this._lastCapturedException = ex;
@@ -455,12 +473,43 @@ Raven.prototype = { · 30 unmodified lines
455 return;473 return;
456 }474 }
457 475
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
458 // Fire away!511 // Fire away!
459 this._send(512 this._send(data);
460 objectMerge({
461 message: msg + '' // Make sure it's actually a string
462 }, options)
463 );
464 513
465 return this;514 return this;
466 },515 },
@@ -470,14 +519,25 @@ Raven.prototype = { · 3 unmodified lines
470 timestamp: now() / 1000519 timestamp: now() / 1000
471 }, obj);520 }, obj);
472 521
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
473 this._breadcrumbs.push(crumb);532 this._breadcrumbs.push(crumb);
474 if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {533 if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
475 this._breadcrumbs.shift();534 this._breadcrumbs.shift();
476 }535 }
536 return this;
477 },537 },
478 538
479 addPlugin: function(plugin /*arg1, arg2, ... argN*/) {539 addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
480 var pluginArgs = Array.prototype.slice.call(arguments, 1);540 var pluginArgs = [].slice.call(arguments, 1);
481 541
482 this._plugins.push([plugin, pluginArgs]);542 this._plugins.push([plugin, pluginArgs]);
483 if (this._isRavenInstalled) {543 if (this._isRavenInstalled) {
@@ -586,6 +646,22 @@ Raven.prototype = { · 102 unmodified lines
586 return this;646 return this;
587 },647 },
588 648
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
589 /*665 /*
590 * Set the shouldSendCallback option666 * Set the shouldSendCallback option
591 *667 *
@@ -656,14 +732,14 @@ Raven.prototype = { · 64 unmodified lines
656 // TODO: remove window dependence?732 // TODO: remove window dependence?
657 733
658 // Attempt to initialize Raven on load734 // Attempt to initialize Raven on load
659 var RavenConfig = window.RavenConfig;735 var RavenConfig = _window.RavenConfig;
660 if (RavenConfig) {736 if (RavenConfig) {
661 this.config(RavenConfig.dsn, RavenConfig.config).install();737 this.config(RavenConfig.dsn, RavenConfig.config).install();
662 }738 }
663 },739 },
664 740
665 showReportDialog: function (options) {741 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)
667 return;743 return;
668 744
669 options = options || {};745 options = options || {};
@@ -691,10 +767,10 @@ Raven.prototype = { · 21 unmodified lines
691 767
692 var globalServer = this._getGlobalServer(this._parseDSN(dsn));768 var globalServer = this._getGlobalServer(this._parseDSN(dsn));
693 769
694 var script = document.createElement('script');770 var script = _document.createElement('script');
695 script.async = true;771 script.async = true;
696 script.src = globalServer + '/api/embed/error-page/' + qs;772 script.src = globalServer + '/api/embed/error-page/' + qs;
697 (document.head || document.body).appendChild(script);773 (_document.head || _document.body).appendChild(script);
698 },774 },
699 775
700 /**** Private functions ****/776 /**** Private functions ****/
@@ -718,11 +794,11 @@ Raven.prototype = { · 17 unmodified lines
718 794
719 eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);795 eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
720 796
721 if (document.createEvent) {797 if (_document.createEvent) {
722 evt = document.createEvent('HTMLEvents');798 evt = _document.createEvent('HTMLEvents');
723 evt.initEvent(eventType, true, true);799 evt.initEvent(eventType, true, true);
724 } else {800 } else {
725 evt = document.createEventObject();801 evt = _document.createEventObject();
726 evt.eventType = eventType;802 evt.eventType = eventType;
727 }803 }
728 804
@@ -730,14 +806,14 @@ Raven.prototype = { · 1 unmodified line
730 evt[key] = options[key];806 evt[key] = options[key];
731 }807 }
732 808
733 if (document.createEvent) {809 if (_document.createEvent) {
734 // IE9 if standards810 // IE9 if standards
735 document.dispatchEvent(evt);811 _document.dispatchEvent(evt);
736 } else {812 } else {
737 // IE8 regardless of Quirks or Standards813 // IE8 regardless of Quirks or Standards
738 // IE9 if quirks814 // IE9 if quirks
739 try {815 try {
740 document.fireEvent('on' + evt.eventType.toLowerCase(), evt);816 _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
741 } catch(e) {817 } catch(e) {
742 // Do nothing818 // Do nothing
743 }819 }
@@ -765,14 +841,14 @@ Raven.prototype = { · 21 unmodified lines
765 return;841 return;
766 842
767 self._lastCapturedEvent = evt;843 self._lastCapturedEvent = evt;
768 var elem = evt.target;
769 844
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.
770 var target;849 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.
774 try {850 try {
775 target = htmlTreeAsString(elem);851 target = htmlTreeAsString(evt.target);
776 } catch (e) {852 } catch (e) {
777 target = '<unknown>';853 target = '<unknown>';
778 }854 }
@@ -796,15 +872,21 @@ Raven.prototype = { · 17 unmodified lines
796 // TODO: if somehow user switches keypress target before872 // TODO: if somehow user switches keypress target before
797 // debounce timeout is triggered, we will only capture873 // debounce timeout is triggered, we will only capture
798 // a single breadcrumb from the FIRST target (acceptable?)874 // a single breadcrumb from the FIRST target (acceptable?)
799
800 return function (evt) {875 return function (evt) {
801 var target = evt.target,876 var target;
802 tagName = target && target.tagName;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;
803 885
804 // only consider keypress events on actual input elements886 // only consider keypress events on actual input elements
805 // this will disregard keypresses targeting body (e.g. tabbing887 // this will disregard keypresses targeting body (e.g. tabbing
806 // through elements, hotkeys, etc)888 // through elements, hotkeys, etc)
807 if (!tagName || tagName !== 'INPUT' && tagName !== 'TEXTAREA')889 if (!tagName || tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)
808 return;890 return;
809 891
810 // record first keypress in a series, but ignore subsequent892 // record first keypress in a series, but ignore subsequent
@@ -815,7 +897,7 @@ Raven.prototype = { · 4 unmodified lines
815 }897 }
816 clearTimeout(timeout);898 clearTimeout(timeout);
817 self._keypressTimeout = setTimeout(function () {899 self._keypressTimeout = setTimeout(function () {
818 self._keypressTimeout = null;900 self._keypressTimeout = null;
819 }, debounceDuration);901 }, debounceDuration);
820 };902 };
821 },903 },
@@ -887,7 +969,7 @@ Raven.prototype = { · 65 unmodified lines
887 var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;969 var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
888 970
889 function wrapEventTarget(global) {971 function wrapEventTarget(global) {
890 var proto = window[global] && window[global].prototype;972 var proto = _window[global] && _window[global].prototype;
891 if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {973 if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
892 fill(proto, 'addEventListener', function(orig) {974 fill(proto, 'addEventListener', function(orig) {
893 return function (evtName, fn, capture, secure) { // preserve arity975 return function (evtName, fn, capture, secure) { // preserve arity
@@ -901,30 +983,55 @@ Raven.prototype = { · 7 unmodified lines
901 983
902 // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`984 // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
903 // so that we don't have more than one wrapper function985 // so that we don't have more than one wrapper function
904 var before;986 var before,
987 clickHandler,
988 keypressHandler;
989
905 if (autoBreadcrumbs && autoBreadcrumbs.dom && (global === 'EventTarget' || global === 'Node')) {990 if (autoBreadcrumbs && autoBreadcrumbs.dom && (global === 'EventTarget' || global === 'Node')) {
906 if (evtName === 'click'){991 // NOTE: generating multiple handlers per addEventListener invocation, should
907 before = self._breadcrumbEventHandler(evtName);992 // revisit and verify we can just use one (almost certainly)
908 } else if (evtName === 'keypress') {993 clickHandler = self._breadcrumbEventHandler('click');
909 before = self._keypressEventHandler();994 keypressHandler = self._keypressEventHandler();
910 }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 };
911 }1014 }
912 return orig.call(this, evtName, self.wrap(fn, undefined, before), capture, secure);1015 return orig.call(this, evtName, self.wrap(fn, undefined, before), capture, secure);
913 };1016 };
914 }, wrappedBuiltIns);1017 }, wrappedBuiltIns);
915 fill(proto, 'removeEventListener', function (orig) {1018 fill(proto, 'removeEventListener', function (orig) {
916 return function (evt, fn, capture, secure) {1019 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 }
918 return orig.call(this, evt, fn, capture, secure);1025 return orig.call(this, evt, fn, capture, secure);
919 };1026 };
920 }, wrappedBuiltIns);1027 }, wrappedBuiltIns);
921 }1028 }
922 }1029 }
923 1030
924 fill(window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);1031 fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
925 fill(window, 'setInterval', wrapTimeFn, wrappedBuiltIns);1032 fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
926 if (window.requestAnimationFrame) {1033 if (_window.requestAnimationFrame) {
927 fill(window, 'requestAnimationFrame', function (orig) {1034 fill(_window, 'requestAnimationFrame', function (orig) {
928 return function (cb) {1035 return function (cb) {
929 return orig(self.wrap(cb));1036 return orig(self.wrap(cb));
930 };1037 };
@@ -937,15 +1044,6 @@ Raven.prototype = { · 6 unmodified lines
937 for (var i = 0; i < eventTargets.length; i++) {1044 for (var i = 0; i < eventTargets.length; i++) {
938 wrapEventTarget(eventTargets[i]);1045 wrapEventTarget(eventTargets[i]);
939 }1046 }
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 }
949 },1047 },
950 1048
951 1049
@@ -972,7 +1070,7 @@ Raven.prototype = { · 20 unmodified lines
972 }1070 }
973 }1071 }
974 1072
975 if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in window) {1073 if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
976 var xhrproto = XMLHttpRequest.prototype;1074 var xhrproto = XMLHttpRequest.prototype;
977 fill(xhrproto, 'open', function(origOpen) {1075 fill(xhrproto, 'open', function(origOpen) {
978 return function (method, url) { // preserve arity1076 return function (method, url) { // preserve arity
@@ -1029,17 +1127,54 @@ Raven.prototype = { · 50 unmodified lines
1029 }, wrappedBuiltIns);1127 }, wrappedBuiltIns);
1030 }1128 }
1031 1129
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
1032 // Capture breadcrumbs from any click that is unhandled / bubbled up all the way1167 // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
1033 // to the document. Do this before we instrument addEventListener.1168 // to the document. Do this before we instrument addEventListener.
1034 if (autoBreadcrumbs.dom && this._hasDocument) {1169 if (autoBreadcrumbs.dom && this._hasDocument) {
1035 if (document.addEventListener) {1170 if (_document.addEventListener) {
1036 document.addEventListener('click', self._breadcrumbEventHandler('click'), false);1171 _document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
1037 document.addEventListener('keypress', self._keypressEventHandler(), false);1172 _document.addEventListener('keypress', self._keypressEventHandler(), false);
1038 }1173 }
1039 else {1174 else {
1040 // IE8 Compatibility1175 // IE8 Compatibility
1041 document.attachEvent('onclick', self._breadcrumbEventHandler('click'));1176 _document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
1042 document.attachEvent('onkeypress', self._keypressEventHandler());1177 _document.attachEvent('onkeypress', self._keypressEventHandler());
1043 }1178 }
1044 }1179 }
1045 1180
@@ -1047,13 +1182,13 @@ Raven.prototype = { · 1 unmodified line
1047 // NOTE: in Chrome App environment, touching history.pushState, *even inside1182 // NOTE: in Chrome App environment, touching history.pushState, *even inside
1048 // a try/catch block*, will cause Chrome to output an error to console.error1183 // a try/catch block*, will cause Chrome to output an error to console.error
1049 // borrowed from: https://github.com/angular/angular.js/pull/13945/files1184 // borrowed from: https://github.com/angular/angular.js/pull/13945/files
1050 var chrome = window.chrome;1185 var chrome = _window.chrome;
1051 var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;1186 var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
1052 var hasPushState = !isChromePackagedApp && window.history && history.pushState;1187 var hasPushState = !isChromePackagedApp && _window.history && history.pushState;
1053 if (autoBreadcrumbs.location && hasPushState) {1188 if (autoBreadcrumbs.location && hasPushState) {
1054 // TODO: remove onpopstate handler on uninstall()1189 // TODO: remove onpopstate handler on uninstall()
1055 var oldOnPopState = window.onpopstate;1190 var oldOnPopState = _window.onpopstate;
1056 window.onpopstate = function () {1191 _window.onpopstate = function () {
1057 var currentHref = self._location.href;1192 var currentHref = self._location.href;
1058 self._captureUrlChange(self._lastHref, currentHref);1193 self._captureUrlChange(self._lastHref, currentHref);
1059 1194
@@ -1079,7 +1214,7 @@ Raven.prototype = { · 19 unmodified lines
1079 }, wrappedBuiltIns);1214 }, wrappedBuiltIns);
1080 }1215 }
1081 1216
1082 if (autoBreadcrumbs.console && 'console' in window && console.log) {1217 if (autoBreadcrumbs.console && 'console' in _window && console.log) {
1083 // console1218 // console
1084 var consoleMethodCallback = function (msg, data) {1219 var consoleMethodCallback = function (msg, data) {
1085 self.captureBreadcrumb({1220 self.captureBreadcrumb({
@@ -1158,17 +1293,7 @@ Raven.prototype = { · 72 unmodified lines
1158 },1293 },
1159 1294
1160 _handleStackInfo: function(stackInfo, options) {1295 _handleStackInfo: function(stackInfo, options) {
1161 var self = this;1296 var frames = this._prepareFrames(stackInfo, options);
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 }
1172 1297
1173 this._triggerEvent('handle', {1298 this._triggerEvent('handle', {
1174 stackInfo: stackInfo,1299 stackInfo: stackInfo,
@@ -1180,11 +1305,34 @@ Raven.prototype = { · 5 unmodified lines
1180 stackInfo.message,1305 stackInfo.message,
1181 stackInfo.url,1306 stackInfo.url,
1182 stackInfo.lineno,1307 stackInfo.lineno,
1183 frames.slice(0, this._globalOptions.stackTraceLimit),1308 frames,
1184 options1309 options
1185 );1310 );
1186 },1311 },
1187 1312
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
1188 _normalizeFrame: function(frame) {1336 _normalizeFrame: function(frame) {
1189 if (!frame.url) return;1337 if (!frame.url) return;
1190 1338
@@ -1210,7 +1358,6 @@ Raven.prototype = { · 19 unmodified lines
1210 1358
1211 _processException: function(type, message, fileurl, lineno, frames, options) {1359 _processException: function(type, message, fileurl, lineno, frames, options) {
1212 var stacktrace;1360 var stacktrace;
1213
1214 if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;1361 if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;
1215 1362
1216 message += '';1363 message += '';
@@ -1266,25 +1413,99 @@ Raven.prototype = { · 49 unmodified lines
1266 },1413 },
1267 1414
1268 _getHttpData: function() {1415 _getHttpData: function() {
1269 if (!this._hasDocument || !document.location || !document.location.href) {1416 if (!this._hasNavigator && !this._hasDocument) return;
1270 return;1417 var httpData = {};
1418
1419 if (this._hasNavigator && _navigator.userAgent) {
1420 httpData.headers = {
1421 'User-Agent': navigator.userAgent
1422 };
1271 }1423 }
1272 1424
1273 var httpData = {1425 if (this._hasDocument) {
1274 headers: {1426 if (_document.location && _document.location.href) {
1275 'User-Agent': navigator.userAgent1427 httpData.url = _document.location.href;
1276 }1428 }
1277 };1429 if (_document.referrer) {
1430 if (!httpData.headers) httpData.headers = {};
1431 httpData.headers.Referer = _document.referrer;
1432 }
1433 }
1278 1434
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;
1280 1458
1281 if (document.referrer) {1459 if (!last ||
1282 httpData.headers.Referer = document.referrer;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);
1283 }1471 }
1284 1472
1285 return httpData;1473 return true;
1286 },1474 },
1287 1475
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 },
1288 1509
1289 _send: function(data) {1510 _send: function(data) {
1290 var globalOptions = this._globalOptions;1511 var globalOptions = this._globalOptions;
@@ -1299,6 +1520,9 @@ Raven.prototype = { · 8 unmodified lines
1299 baseData.request = httpData;1520 baseData.request = httpData;
1300 }1521 }
1301 1522
1523 // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
1524 if (data.trimHeadFrames) delete data.trimHeadFrames;
1525
1302 data = objectMerge(baseData, data);1526 data = objectMerge(baseData, data);
1303 1527
1304 // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge1528 // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
@@ -1347,24 +1571,46 @@ Raven.prototype = { · 42 unmodified lines
1347 return;1571 return;
1348 }1572 }
1349 1573
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
1350 this._sendProcessedPayload(data);1581 this._sendProcessedPayload(data);
1351 },1582 },
1352 1583
1584 _getUuid: function () {
1585 return uuid4();
1586 },
1587
1353 _sendProcessedPayload: function(data, callback) {1588 _sendProcessedPayload: function(data, callback) {
1354 var self = this;1589 var self = this;
1355 var globalOptions = this._globalOptions;1590 var globalOptions = this._globalOptions;
1356 1591
1592 if (!this.isSetup()) return;
1593
1357 // Send along an event_id if not explicitly passed.1594 // Send along an event_id if not explicitly passed.
1358 // This event_id can be used to reference the error within Sentry itself.1595 // This event_id can be used to reference the error within Sentry itself.
1359 // Set lastEventId after we know the error should actually be sent1596 // 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());
1361 1598
1362 // Try and clean up the packet before sending by truncating long values1599 // Try and clean up the packet before sending by truncating long values
1363 data = this._trimPacket(data);1600 data = this._trimPacket(data);
1364 1601
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 }
1366 1609
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);
1368 1614
1369 var auth = {1615 var auth = {
1370 sentry_version: '7',1616 sentry_version: '7',
@@ -1392,6 +1638,8 @@ Raven.prototype = { · 21 unmodified lines
1392 data: data,1638 data: data,
1393 options: globalOptions,1639 options: globalOptions,
1394 onSuccess: function success() {1640 onSuccess: function success() {
1641 self._resetBackoff();
1642
1395 self._triggerEvent('success', {1643 self._triggerEvent('success', {
1396 data: data,1644 data: data,
1397 src: url1645 src: url
@@ -1399,6 +1647,12 @@ Raven.prototype = { · 1 unmodified line
1399 callback && callback();1647 callback && callback();
1400 },1648 },
1401 onError: function failure(error) {1649 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
1402 self._triggerEvent('failure', {1656 self._triggerEvent('failure', {
1403 data: data,1657 data: data,
1404 src: url1658 src: url
@@ -1426,7 +1680,9 @@ Raven.prototype = { · 21 unmodified lines
1426 opts.onSuccess();1680 opts.onSuccess();
1427 }1681 }
1428 } else if (opts.onError) {1682 } 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);
1430 }1686 }
1431 }1687 }
1432 1688
@@ -1473,46 +1729,12 @@ Raven.prototype = { · 40 unmodified lines
1473 }1729 }
1474};1730};
1475 1731
1476// Deprecations1732/*------------------------------------------------
1477Raven.prototype.setUser = Raven.prototype.setUserContext;1733 * utils
1478Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
1479
1480module.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
1491var RavenConstructor = _dereq_(4);
1492
1493var _Raven = window.Raven;
1494
1495var 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.
1500 *1734 *
1501 * @return {Raven}1735 * conditionally exported for test via Raven.utils
1736 =================================================
1502 */1737 */
1503Raven.noConflict = function () {
1504 window.Raven = _Raven;
1505 return Raven;
1506};
1507
1508Raven.afterLoad();
1509
1510module.exports = Raven;
1511
1512},{"4":4}],6:[function(_dereq_,module,exports){
1513/*eslint no-extra-parens:0*/
1514'use strict';
1515
1516var objectPrototype = Object.prototype;1738var objectPrototype = Object.prototype;
1517 1739
1518function isUndefined(what) {1740function isUndefined(what) {
@@ -1638,7 +1860,7 @@ function parseUrl(url) { · 119 unmodified lines
1638 };1860 };
1639}1861}
1640function uuid4() {1862function uuid4() {
1641 var crypto = window.crypto || window.msCrypto;1863 var crypto = _window.crypto || _window.msCrypto;
1642 1864
1643 if (!isUndefined(crypto) && crypto.getRandomValues) {1865 if (!isUndefined(crypto) && crypto.getRandomValues) {
1644 // Use window.crypto API if available1866 // Use window.crypto API if available
@@ -1678,6 +1900,7 @@ function uuid4() { · 33 unmodified lines
1678 * @returns {string}1900 * @returns {string}
1679 */1901 */
1680function htmlTreeAsString(elem) {1902function htmlTreeAsString(elem) {
1903 /* eslint no-extra-parens:0*/
1681 var MAX_TRAVERSE_HEIGHT = 5,1904 var MAX_TRAVERSE_HEIGHT = 5,
1682 MAX_OUTPUT_LEN = 80,1905 MAX_OUTPUT_LEN = 80,
1683 out = [],1906 out = [],
@@ -1732,7 +1955,7 @@ function htmlElementAsString(elem) { · 48 unmodified lines
1732 1955
1733 className = elem.className;1956 className = elem.className;
1734 if (className && isString(className)) {1957 if (className && isString(className)) {
1735 classes = className.split(' ');1958 classes = className.split(/\s+/);
1736 for (i = 0; i < classes.length; i++) {1959 for (i = 0; i < classes.length; i++) {
1737 out.push('.' + classes[i]);1960 out.push('.' + classes[i]);
1738 }1961 }
@@ -1748,6 +1971,58 @@ function htmlElementAsString(elem) { · 9 unmodified lines
1748 return out.join('');1971 return out.join('');
1749}1972}
1750 1973
1974/**
1975 * Returns true if either a OR b is truthy, but not both
1976 */
1977function isOnlyOneTruthy(a, b) {
1978 return !!(!!a ^ !!b);
1979}
1980
1981/**
1982 * Returns true if the two input exception interfaces have the same content
1983 */
1984function 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 */
2001function 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
1751/**2026/**
1752 * Polyfill a method2027 * Polyfill a method
1753 * @param obj object e.g. `document`2028 * @param obj object e.g. `document`
@@ -1763,37 +2038,83 @@ function fill(obj, name, replacement, track) { · 9 unmodified lines
1763 }2038 }
1764}2039}
1765 2040
1766module.exports = {2041if (typeof __DEV__ !== 'undefined' && __DEV__) {
1767 isUndefined: isUndefined,2042 Raven.utils = {
1768 isFunction: isFunction,2043 isUndefined: isUndefined,
1769 isString: isString,2044 isFunction: isFunction,
1770 isObject: isObject,2045 isString: isString,
1771 isEmptyObject: isEmptyObject,2046 isObject: isObject,
1772 isError: isError,2047 isEmptyObject: isEmptyObject,
1773 each: each,2048 isError: isError,
1774 objectMerge: objectMerge,2049 each: each,
1775 truncate: truncate,2050 objectMerge: objectMerge,
1776 hasKey: hasKey,2051 truncate: truncate,
1777 joinRegExp: joinRegExp,2052 hasKey: hasKey,
1778 urlencode: urlencode,2053 joinRegExp: joinRegExp,
1779 uuid4: uuid4,2054 urlencode: urlencode,
1780 htmlTreeAsString: htmlTreeAsString,2055 uuid4: uuid4,
1781 htmlElementAsString: htmlElementAsString,2056 htmlTreeAsString: htmlTreeAsString,
1782 parseUrl: parseUrl,2057 htmlElementAsString: htmlElementAsString,
1783 fill: fill2058 parseUrl: parseUrl,
2059 fill: fill
2060 };
1784};2061};
1785 2062
1786},{}],7:[function(_dereq_,module,exports){2063// Deprecations
2064Raven.prototype.setUser = Raven.prototype.setUserContext;
2065Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
2066
2067module.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
1787'use strict';2078'use strict';
1788 2079
1789var utils = _dereq_(6);2080var 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)
2083var _window = typeof window !== 'undefined' ? window
2084 : typeof global !== 'undefined' ? global
2085 : typeof self !== 'undefined' ? self
2086 : {};
2087var _Raven = _window.Raven;
2088
2089var Raven = new RavenConstructor();
1790 2090
1791var hasKey = utils.hasKey;2091/*
1792var isString = utils.isString;2092 * Allow multiple versions of Raven to be installed.
1793var isUndefined = utils.isUndefined;2093 * Strip Raven from the global context and returns the instance.
2094 *
2095 * @return {Raven}
2096 */
2097Raven.noConflict = function () {
2098 _window.Raven = _Raven;
2099 return Raven;
2100};
2101
2102Raven.afterLoad();
2103
2104module.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';
1794 2110
1795/*2111/*
1796 TraceKit - Cross brower stack traces - github.com/occ/TraceKit2112 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
1797 MIT license2118 MIT license
1798*/2119*/
1799 2120
@@ -1802,6 +2123,12 @@ var TraceKit = { · 2 unmodified lines
1802 debug: false2123 debug: false
1803};2124};
1804 2125
2126// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
2127var _window = typeof window !== 'undefined' ? window
2128 : typeof global !== 'undefined' ? global
2129 : typeof self !== 'undefined' ? self
2130 : {};
2131
1805// global reference to slice2132// global reference to slice
1806var _slice = [].slice;2133var _slice = [].slice;
1807var UNKNOWN_FUNCTION = '?';2134var UNKNOWN_FUNCTION = '?';
@@ -1810,7 +2137,7 @@ var UNKNOWN_FUNCTION = '?'; · 2 unmodified lines
1810var ERROR_TYPES_RE = /^(?:Uncaught (?:exception: )?)?((?:Eval|Internal|Range|Reference|Syntax|Type|URI)Error): ?(.*)$/;2137var ERROR_TYPES_RE = /^(?:Uncaught (?:exception: )?)?((?:Eval|Internal|Range|Reference|Syntax|Type|URI)Error): ?(.*)$/;
1811 2138
1812function getLocationHref() {2139function getLocationHref() {
1813 if (typeof document === 'undefined')2140 if (typeof document === 'undefined' || typeof document.location === 'undefined')
1814 return '';2141 return '';
1815 2142
1816 return document.location.href;2143 return document.location.href;
@@ -1900,7 +2227,7 @@ TraceKit.report = (function reportModuleWrapper() { · 83 unmodified lines
1900 return;2227 return;
1901 }2228 }
1902 for (var i in handlers) {2229 for (var i in handlers) {
1903 if (hasKey(handlers, i)) {2230 if (handlers.hasOwnProperty(i)) {
1904 try {2231 try {
1905 handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));2232 handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
1906 } catch (inner) {2233 } catch (inner) {
@@ -1949,7 +2276,7 @@ TraceKit.report = (function reportModuleWrapper() { · 42 unmodified lines
1949 var name = undefined;2276 var name = undefined;
1950 var msg = message; // must be new var or will modify original `arguments`2277 var msg = message; // must be new var or will modify original `arguments`
1951 var groups;2278 var groups;
1952 if (isString(message)) {2279 if ({}.toString.call(message) === '[object String]') {
1953 var groups = message.match(ERROR_TYPES_RE);2280 var groups = message.match(ERROR_TYPES_RE);
1954 if (groups) {2281 if (groups) {
1955 name = groups[1];2282 name = groups[1];
@@ -1980,8 +2307,8 @@ TraceKit.report = (function reportModuleWrapper() { · 24 unmodified lines
1980 if (_onErrorHandlerInstalled) {2307 if (_onErrorHandlerInstalled) {
1981 return;2308 return;
1982 }2309 }
1983 _oldOnerrorHandler = window.onerror;2310 _oldOnerrorHandler = _window.onerror;
1984 window.onerror = traceKitWindowOnError;2311 _window.onerror = traceKitWindowOnError;
1985 _onErrorHandlerInstalled = true;2312 _onErrorHandlerInstalled = true;
1986 }2313 }
1987 2314
@@ -1990,7 +2317,7 @@ TraceKit.report = (function reportModuleWrapper() { · 2 unmodified lines
1990 if (!_onErrorHandlerInstalled) {2317 if (!_onErrorHandlerInstalled) {
1991 return;2318 return;
1992 }2319 }
1993 window.onerror = _oldOnerrorHandler;2320 _window.onerror = _oldOnerrorHandler;
1994 _onErrorHandlerInstalled = false;2321 _onErrorHandlerInstalled = false;
1995 _oldOnerrorHandler = undefined;2322 _oldOnerrorHandler = undefined;
1996 }2323 }
@@ -2030,7 +2357,7 @@ TraceKit.report = (function reportModuleWrapper() { · 33 unmodified lines
2030 // slow slow IE to see if onerror occurs or not before reporting2357 // slow slow IE to see if onerror occurs or not before reporting
2031 // this exception; otherwise, we will end up with an incomplete2358 // this exception; otherwise, we will end up with an incomplete
2032 // stack trace2359 // stack trace
2033 window.setTimeout(function () {2360 setTimeout(function () {
2034 if (lastException === ex) {2361 if (lastException === ex) {
2035 processLastException();2362 processLastException();
2036 }2363 }
@@ -2164,10 +2491,10 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 127 unmodified lines
2164 * @return {?Object.<string, *>} Stack trace information.2491 * @return {?Object.<string, *>} Stack trace information.
2165 */2492 */
2166 function computeStackTraceFromStackProp(ex) {2493 function computeStackTraceFromStackProp(ex) {
2167 if (isUndefined(ex.stack) || !ex.stack) return;2494 if (typeof ex.stack === 'undefined' || !ex.stack) return;
2168 2495
2169 var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|<anonymous>).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,2496 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,
2171 winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,2498 winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
2172 lines = ex.stack.split('\n'),2499 lines = ex.stack.split('\n'),
2173 stack = [],2500 stack = [],
@@ -2216,7 +2543,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 42 unmodified lines
2216 return null;2543 return null;
2217 }2544 }
2218 2545
2219 if (!stack[0].column && !isUndefined(ex.columnNumber)) {2546 if (!stack[0].column && typeof ex.columnNumber !== 'undefined') {
2220 // FireFox uses this awesome columnNumber property for its top frame2547 // FireFox uses this awesome columnNumber property for its top frame
2221 // Also note, Firefox's column number is 0-based and everything else expects 1-based,2548 // Also note, Firefox's column number is 0-based and everything else expects 1-based,
2222 // so adding 12549 // so adding 1
@@ -2231,153 +2558,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 8 unmodified lines
2231 };2558 };
2232 }2559 }
2233 2560
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
2381 /**2561 /**
2382 * Adds information about the first frame to incomplete stack traces.2562 * Adds information about the first frame to incomplete stack traces.
2383 * Safari and IE require this to get complete data on the first frame.2563 * Safari and IE require this to get complete data on the first frame.
@@ -2502,20 +2682,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 118 unmodified lines
2502 var stack = null;2682 var stack = null;
2503 depth = (depth == null ? 0 : +depth);2683 depth = (depth == null ? 0 : +depth);
2504 2684
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
2519 try {2685 try {
2520 stack = computeStackTraceFromStackProp(ex);2686 stack = computeStackTraceFromStackProp(ex);
2521 if (stack) {2687 if (stack) {
@@ -2527,17 +2693,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 5 unmodified lines
2527 }2693 }
2528 }2694 }
2529 2695
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
2541 try {2696 try {
2542 stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);2697 stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
2543 if (stack) {2698 if (stack) {
@@ -2564,5 +2719,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 20 unmodified lines
2564 2719
2565module.exports = TraceKit;2720module.exports = TraceKit;
2566 2721
2567},{"6":6}]},{},[5])(5)2722}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2568});2723},{}]},{},[5])(5)
2724});