raven.js 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770
  1. /*! Raven.js 3.13.1 (f55d281) | github.com/getsentry/raven-js */
  2. /*
  3. * Includes TraceKit
  4. * https://github.com/getsentry/TraceKit
  5. *
  6. * Copyright 2017 Matt Robenolt and other contributors
  7. * Released under the BSD license
  8. * https://github.com/getsentry/raven-js/blob/master/LICENSE
  9. *
  10. */
  11. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Raven = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
  12. 'use strict';
  13. function RavenConfigError(message) {
  14. this.name = 'RavenConfigError';
  15. this.message = message;
  16. }
  17. RavenConfigError.prototype = new Error();
  18. RavenConfigError.prototype.constructor = RavenConfigError;
  19. module.exports = RavenConfigError;
  20. },{}],2:[function(_dereq_,module,exports){
  21. 'use strict';
  22. var wrapMethod = function(console, level, callback) {
  23. var originalConsoleLevel = console[level];
  24. var originalConsole = console;
  25. if (!(level in console)) {
  26. return;
  27. }
  28. var sentryLevel = level === 'warn'
  29. ? 'warning'
  30. : level;
  31. console[level] = function () {
  32. var args = [].slice.call(arguments);
  33. var msg = '' + args.join(' ');
  34. var data = {level: sentryLevel, logger: 'console', extra: {'arguments': args}};
  35. callback && callback(msg, data);
  36. // this fails for some browsers. :(
  37. if (originalConsoleLevel) {
  38. // IE9 doesn't allow calling apply on console functions directly
  39. // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193
  40. Function.prototype.apply.call(
  41. originalConsoleLevel,
  42. originalConsole,
  43. args
  44. );
  45. }
  46. };
  47. };
  48. module.exports = {
  49. wrapMethod: wrapMethod
  50. };
  51. },{}],3:[function(_dereq_,module,exports){
  52. (function (global){
  53. /*global XDomainRequest:false, __DEV__:false*/
  54. 'use strict';
  55. var TraceKit = _dereq_(6);
  56. var stringify = _dereq_(7);
  57. var RavenConfigError = _dereq_(1);
  58. var utils = _dereq_(5);
  59. var isError = utils.isError,
  60. isObject = utils.isObject;
  61. var wrapConsoleMethod = _dereq_(2).wrapMethod;
  62. var dsnKeys = 'source protocol user pass host port path'.split(' '),
  63. dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
  64. function now() {
  65. return +new Date();
  66. }
  67. // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
  68. var _window = typeof window !== 'undefined' ? window
  69. : typeof global !== 'undefined' ? global
  70. : typeof self !== 'undefined' ? self
  71. : {};
  72. var _document = _window.document;
  73. var _navigator = _window.navigator;
  74. // First, check for JSON support
  75. // If there is no JSON, we no-op the core features of Raven
  76. // since JSON is required to encode the payload
  77. function Raven() {
  78. this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
  79. // Raven can run in contexts where there's no document (react-native)
  80. this._hasDocument = !isUndefined(_document);
  81. this._hasNavigator = !isUndefined(_navigator);
  82. this._lastCapturedException = null;
  83. this._lastData = null;
  84. this._lastEventId = null;
  85. this._globalServer = null;
  86. this._globalKey = null;
  87. this._globalProject = null;
  88. this._globalContext = {};
  89. this._globalOptions = {
  90. logger: 'javascript',
  91. ignoreErrors: [],
  92. ignoreUrls: [],
  93. whitelistUrls: [],
  94. includePaths: [],
  95. crossOrigin: 'anonymous',
  96. collectWindowErrors: true,
  97. maxMessageLength: 0,
  98. stackTraceLimit: 50,
  99. autoBreadcrumbs: true,
  100. sampleRate: 1
  101. };
  102. this._ignoreOnError = 0;
  103. this._isRavenInstalled = false;
  104. this._originalErrorStackTraceLimit = Error.stackTraceLimit;
  105. // capture references to window.console *and* all its methods first
  106. // before the console plugin has a chance to monkey patch
  107. this._originalConsole = _window.console || {};
  108. this._originalConsoleMethods = {};
  109. this._plugins = [];
  110. this._startTime = now();
  111. this._wrappedBuiltIns = [];
  112. this._breadcrumbs = [];
  113. this._lastCapturedEvent = null;
  114. this._keypressTimeout;
  115. this._location = _window.location;
  116. this._lastHref = this._location && this._location.href;
  117. this._resetBackoff();
  118. for (var method in this._originalConsole) { // eslint-disable-line guard-for-in
  119. this._originalConsoleMethods[method] = this._originalConsole[method];
  120. }
  121. }
  122. /*
  123. * The core Raven singleton
  124. *
  125. * @this {Raven}
  126. */
  127. Raven.prototype = {
  128. // Hardcode version string so that raven source can be loaded directly via
  129. // webpack (using a build step causes webpack #1617). Grunt verifies that
  130. // this value matches package.json during build.
  131. // See: https://github.com/getsentry/raven-js/issues/465
  132. VERSION: '3.13.1',
  133. debug: false,
  134. TraceKit: TraceKit, // alias to TraceKit
  135. /*
  136. * Configure Raven with a DSN and extra options
  137. *
  138. * @param {string} dsn The public Sentry DSN
  139. * @param {object} options Optional set of of global options [optional]
  140. * @return {Raven}
  141. */
  142. config: function(dsn, options) {
  143. var self = this;
  144. if (self._globalServer) {
  145. this._logDebug('error', 'Error: Raven has already been configured');
  146. return self;
  147. }
  148. if (!dsn) return self;
  149. var globalOptions = self._globalOptions;
  150. // merge in options
  151. if (options) {
  152. each(options, function(key, value){
  153. // tags and extra are special and need to be put into context
  154. if (key === 'tags' || key === 'extra' || key === 'user') {
  155. self._globalContext[key] = value;
  156. } else {
  157. globalOptions[key] = value;
  158. }
  159. });
  160. }
  161. self.setDSN(dsn);
  162. // "Script error." is hard coded into browsers for errors that it can't read.
  163. // this is the result of a script being pulled in from an external domain and CORS.
  164. globalOptions.ignoreErrors.push(/^Script error\.?$/);
  165. globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
  166. // join regexp rules into one big rule
  167. globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
  168. globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
  169. globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
  170. globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
  171. globalOptions.maxBreadcrumbs = Math.max(0, Math.min(globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100
  172. var autoBreadcrumbDefaults = {
  173. xhr: true,
  174. console: true,
  175. dom: true,
  176. location: true
  177. };
  178. var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
  179. if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
  180. autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
  181. } else if (autoBreadcrumbs !== false) {
  182. autoBreadcrumbs = autoBreadcrumbDefaults;
  183. }
  184. globalOptions.autoBreadcrumbs = autoBreadcrumbs;
  185. TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
  186. // return for chaining
  187. return self;
  188. },
  189. /*
  190. * Installs a global window.onerror error handler
  191. * to capture and report uncaught exceptions.
  192. * At this point, install() is required to be called due
  193. * to the way TraceKit is set up.
  194. *
  195. * @return {Raven}
  196. */
  197. install: function() {
  198. var self = this;
  199. if (self.isSetup() && !self._isRavenInstalled) {
  200. TraceKit.report.subscribe(function () {
  201. self._handleOnErrorStackInfo.apply(self, arguments);
  202. });
  203. self._instrumentTryCatch();
  204. if (self._globalOptions.autoBreadcrumbs)
  205. self._instrumentBreadcrumbs();
  206. // Install all of the plugins
  207. self._drainPlugins();
  208. self._isRavenInstalled = true;
  209. }
  210. Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
  211. return this;
  212. },
  213. /*
  214. * Set the DSN (can be called multiple time unlike config)
  215. *
  216. * @param {string} dsn The public Sentry DSN
  217. */
  218. setDSN: function(dsn) {
  219. var self = this,
  220. uri = self._parseDSN(dsn),
  221. lastSlash = uri.path.lastIndexOf('/'),
  222. path = uri.path.substr(1, lastSlash);
  223. self._dsn = dsn;
  224. self._globalKey = uri.user;
  225. self._globalSecret = uri.pass && uri.pass.substr(1);
  226. self._globalProject = uri.path.substr(lastSlash + 1);
  227. self._globalServer = self._getGlobalServer(uri);
  228. self._globalEndpoint = self._globalServer +
  229. '/' + path + 'api/' + self._globalProject + '/store/';
  230. // Reset backoff state since we may be pointing at a
  231. // new project/server
  232. this._resetBackoff();
  233. },
  234. /*
  235. * Wrap code within a context so Raven can capture errors
  236. * reliably across domains that is executed immediately.
  237. *
  238. * @param {object} options A specific set of options for this context [optional]
  239. * @param {function} func The callback to be immediately executed within the context
  240. * @param {array} args An array of arguments to be called with the callback [optional]
  241. */
  242. context: function(options, func, args) {
  243. if (isFunction(options)) {
  244. args = func || [];
  245. func = options;
  246. options = undefined;
  247. }
  248. return this.wrap(options, func).apply(this, args);
  249. },
  250. /*
  251. * Wrap code within a context and returns back a new function to be executed
  252. *
  253. * @param {object} options A specific set of options for this context [optional]
  254. * @param {function} func The function to be wrapped in a new context
  255. * @param {function} func A function to call before the try/catch wrapper [optional, private]
  256. * @return {function} The newly wrapped functions with a context
  257. */
  258. wrap: function(options, func, _before) {
  259. var self = this;
  260. // 1 argument has been passed, and it's not a function
  261. // so just return it
  262. if (isUndefined(func) && !isFunction(options)) {
  263. return options;
  264. }
  265. // options is optional
  266. if (isFunction(options)) {
  267. func = options;
  268. options = undefined;
  269. }
  270. // At this point, we've passed along 2 arguments, and the second one
  271. // is not a function either, so we'll just return the second argument.
  272. if (!isFunction(func)) {
  273. return func;
  274. }
  275. // We don't wanna wrap it twice!
  276. try {
  277. if (func.__raven__) {
  278. return func;
  279. }
  280. // If this has already been wrapped in the past, return that
  281. if (func.__raven_wrapper__ ){
  282. return func.__raven_wrapper__ ;
  283. }
  284. } catch (e) {
  285. // Just accessing custom props in some Selenium environments
  286. // can cause a "Permission denied" exception (see raven-js#495).
  287. // Bail on wrapping and return the function as-is (defers to window.onerror).
  288. return func;
  289. }
  290. function wrapped() {
  291. var args = [], i = arguments.length,
  292. deep = !options || options && options.deep !== false;
  293. if (_before && isFunction(_before)) {
  294. _before.apply(this, arguments);
  295. }
  296. // Recursively wrap all of a function's arguments that are
  297. // functions themselves.
  298. while(i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
  299. try {
  300. // Attempt to invoke user-land function
  301. // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
  302. // means Raven caught an error invoking your application code. This is
  303. // expected behavior and NOT indicative of a bug with Raven.js.
  304. return func.apply(this, args);
  305. } catch(e) {
  306. self._ignoreNextOnError();
  307. self.captureException(e, options);
  308. throw e;
  309. }
  310. }
  311. // copy over properties of the old function
  312. for (var property in func) {
  313. if (hasKey(func, property)) {
  314. wrapped[property] = func[property];
  315. }
  316. }
  317. wrapped.prototype = func.prototype;
  318. func.__raven_wrapper__ = wrapped;
  319. // Signal that this function has been wrapped already
  320. // for both debugging and to prevent it to being wrapped twice
  321. wrapped.__raven__ = true;
  322. wrapped.__inner__ = func;
  323. return wrapped;
  324. },
  325. /*
  326. * Uninstalls the global error handler.
  327. *
  328. * @return {Raven}
  329. */
  330. uninstall: function() {
  331. TraceKit.report.uninstall();
  332. this._restoreBuiltIns();
  333. Error.stackTraceLimit = this._originalErrorStackTraceLimit;
  334. this._isRavenInstalled = false;
  335. return this;
  336. },
  337. /*
  338. * Manually capture an exception and send it over to Sentry
  339. *
  340. * @param {error} ex An exception to be logged
  341. * @param {object} options A specific set of options for this error [optional]
  342. * @return {Raven}
  343. */
  344. captureException: function(ex, options) {
  345. // If not an Error is passed through, recall as a message instead
  346. if (!isError(ex)) {
  347. return this.captureMessage(ex, objectMerge({
  348. trimHeadFrames: 1,
  349. stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
  350. }, options));
  351. }
  352. // Store the raw exception object for potential debugging and introspection
  353. this._lastCapturedException = ex;
  354. // TraceKit.report will re-raise any exception passed to it,
  355. // which means you have to wrap it in try/catch. Instead, we
  356. // can wrap it here and only re-raise if TraceKit.report
  357. // raises an exception different from the one we asked to
  358. // report on.
  359. try {
  360. var stack = TraceKit.computeStackTrace(ex);
  361. this._handleStackInfo(stack, options);
  362. } catch(ex1) {
  363. if(ex !== ex1) {
  364. throw ex1;
  365. }
  366. }
  367. return this;
  368. },
  369. /*
  370. * Manually send a message to Sentry
  371. *
  372. * @param {string} msg A plain message to be captured in Sentry
  373. * @param {object} options A specific set of options for this message [optional]
  374. * @return {Raven}
  375. */
  376. captureMessage: function(msg, options) {
  377. // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an
  378. // early call; we'll error on the side of logging anything called before configuration since it's
  379. // probably something you should see:
  380. if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(msg)) {
  381. return;
  382. }
  383. options = options || {};
  384. var data = objectMerge({
  385. message: msg + '' // Make sure it's actually a string
  386. }, options);
  387. if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
  388. var ex;
  389. // create a stack trace from this point; just trim
  390. // off extra frames so they don't include this function call (or
  391. // earlier Raven.js library fn calls)
  392. try {
  393. throw new Error(msg);
  394. } catch (ex1) {
  395. ex = ex1;
  396. }
  397. // null exception name so `Error` isn't prefixed to msg
  398. ex.name = null;
  399. options = objectMerge({
  400. // fingerprint on msg, not stack trace (legacy behavior, could be
  401. // revisited)
  402. fingerprint: msg,
  403. trimHeadFrames: (options.trimHeadFrames || 0) + 1
  404. }, options);
  405. var stack = TraceKit.computeStackTrace(ex);
  406. var frames = this._prepareFrames(stack, options);
  407. data.stacktrace = {
  408. // Sentry expects frames oldest to newest
  409. frames: frames.reverse()
  410. }
  411. }
  412. // Fire away!
  413. this._send(data);
  414. return this;
  415. },
  416. captureBreadcrumb: function (obj) {
  417. var crumb = objectMerge({
  418. timestamp: now() / 1000
  419. }, obj);
  420. if (isFunction(this._globalOptions.breadcrumbCallback)) {
  421. var result = this._globalOptions.breadcrumbCallback(crumb);
  422. if (isObject(result) && !isEmptyObject(result)) {
  423. crumb = result;
  424. } else if (result === false) {
  425. return this;
  426. }
  427. }
  428. this._breadcrumbs.push(crumb);
  429. if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
  430. this._breadcrumbs.shift();
  431. }
  432. return this;
  433. },
  434. addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
  435. var pluginArgs = [].slice.call(arguments, 1);
  436. this._plugins.push([plugin, pluginArgs]);
  437. if (this._isRavenInstalled) {
  438. this._drainPlugins();
  439. }
  440. return this;
  441. },
  442. /*
  443. * Set/clear a user to be sent along with the payload.
  444. *
  445. * @param {object} user An object representing user data [optional]
  446. * @return {Raven}
  447. */
  448. setUserContext: function(user) {
  449. // Intentionally do not merge here since that's an unexpected behavior.
  450. this._globalContext.user = user;
  451. return this;
  452. },
  453. /*
  454. * Merge extra attributes to be sent along with the payload.
  455. *
  456. * @param {object} extra An object representing extra data [optional]
  457. * @return {Raven}
  458. */
  459. setExtraContext: function(extra) {
  460. this._mergeContext('extra', extra);
  461. return this;
  462. },
  463. /*
  464. * Merge tags to be sent along with the payload.
  465. *
  466. * @param {object} tags An object representing tags [optional]
  467. * @return {Raven}
  468. */
  469. setTagsContext: function(tags) {
  470. this._mergeContext('tags', tags);
  471. return this;
  472. },
  473. /*
  474. * Clear all of the context.
  475. *
  476. * @return {Raven}
  477. */
  478. clearContext: function() {
  479. this._globalContext = {};
  480. return this;
  481. },
  482. /*
  483. * Get a copy of the current context. This cannot be mutated.
  484. *
  485. * @return {object} copy of context
  486. */
  487. getContext: function() {
  488. // lol javascript
  489. return JSON.parse(stringify(this._globalContext));
  490. },
  491. /*
  492. * Set environment of application
  493. *
  494. * @param {string} environment Typically something like 'production'.
  495. * @return {Raven}
  496. */
  497. setEnvironment: function(environment) {
  498. this._globalOptions.environment = environment;
  499. return this;
  500. },
  501. /*
  502. * Set release version of application
  503. *
  504. * @param {string} release Typically something like a git SHA to identify version
  505. * @return {Raven}
  506. */
  507. setRelease: function(release) {
  508. this._globalOptions.release = release;
  509. return this;
  510. },
  511. /*
  512. * Set the dataCallback option
  513. *
  514. * @param {function} callback The callback to run which allows the
  515. * data blob to be mutated before sending
  516. * @return {Raven}
  517. */
  518. setDataCallback: function(callback) {
  519. var original = this._globalOptions.dataCallback;
  520. this._globalOptions.dataCallback = isFunction(callback)
  521. ? function (data) { return callback(data, original); }
  522. : callback;
  523. return this;
  524. },
  525. /*
  526. * Set the breadcrumbCallback option
  527. *
  528. * @param {function} callback The callback to run which allows filtering
  529. * or mutating breadcrumbs
  530. * @return {Raven}
  531. */
  532. setBreadcrumbCallback: function(callback) {
  533. var original = this._globalOptions.breadcrumbCallback;
  534. this._globalOptions.breadcrumbCallback = isFunction(callback)
  535. ? function (data) { return callback(data, original); }
  536. : callback;
  537. return this;
  538. },
  539. /*
  540. * Set the shouldSendCallback option
  541. *
  542. * @param {function} callback The callback to run which allows
  543. * introspecting the blob before sending
  544. * @return {Raven}
  545. */
  546. setShouldSendCallback: function(callback) {
  547. var original = this._globalOptions.shouldSendCallback;
  548. this._globalOptions.shouldSendCallback = isFunction(callback)
  549. ? function (data) { return callback(data, original); }
  550. : callback;
  551. return this;
  552. },
  553. /**
  554. * Override the default HTTP transport mechanism that transmits data
  555. * to the Sentry server.
  556. *
  557. * @param {function} transport Function invoked instead of the default
  558. * `makeRequest` handler.
  559. *
  560. * @return {Raven}
  561. */
  562. setTransport: function(transport) {
  563. this._globalOptions.transport = transport;
  564. return this;
  565. },
  566. /*
  567. * Get the latest raw exception that was captured by Raven.
  568. *
  569. * @return {error}
  570. */
  571. lastException: function() {
  572. return this._lastCapturedException;
  573. },
  574. /*
  575. * Get the last event id
  576. *
  577. * @return {string}
  578. */
  579. lastEventId: function() {
  580. return this._lastEventId;
  581. },
  582. /*
  583. * Determine if Raven is setup and ready to go.
  584. *
  585. * @return {boolean}
  586. */
  587. isSetup: function() {
  588. if (!this._hasJSON) return false; // needs JSON support
  589. if (!this._globalServer) {
  590. if (!this.ravenNotConfiguredError) {
  591. this.ravenNotConfiguredError = true;
  592. this._logDebug('error', 'Error: Raven has not been configured.');
  593. }
  594. return false;
  595. }
  596. return true;
  597. },
  598. afterLoad: function () {
  599. // TODO: remove window dependence?
  600. // Attempt to initialize Raven on load
  601. var RavenConfig = _window.RavenConfig;
  602. if (RavenConfig) {
  603. this.config(RavenConfig.dsn, RavenConfig.config).install();
  604. }
  605. },
  606. showReportDialog: function (options) {
  607. if (!_document) // doesn't work without a document (React native)
  608. return;
  609. options = options || {};
  610. var lastEventId = options.eventId || this.lastEventId();
  611. if (!lastEventId) {
  612. throw new RavenConfigError('Missing eventId');
  613. }
  614. var dsn = options.dsn || this._dsn;
  615. if (!dsn) {
  616. throw new RavenConfigError('Missing DSN');
  617. }
  618. var encode = encodeURIComponent;
  619. var qs = '';
  620. qs += '?eventId=' + encode(lastEventId);
  621. qs += '&dsn=' + encode(dsn);
  622. var user = options.user || this._globalContext.user;
  623. if (user) {
  624. if (user.name) qs += '&name=' + encode(user.name);
  625. if (user.email) qs += '&email=' + encode(user.email);
  626. }
  627. var globalServer = this._getGlobalServer(this._parseDSN(dsn));
  628. var script = _document.createElement('script');
  629. script.async = true;
  630. script.src = globalServer + '/api/embed/error-page/' + qs;
  631. (_document.head || _document.body).appendChild(script);
  632. },
  633. /**** Private functions ****/
  634. _ignoreNextOnError: function () {
  635. var self = this;
  636. this._ignoreOnError += 1;
  637. setTimeout(function () {
  638. // onerror should trigger before setTimeout
  639. self._ignoreOnError -= 1;
  640. });
  641. },
  642. _triggerEvent: function(eventType, options) {
  643. // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
  644. var evt, key;
  645. if (!this._hasDocument)
  646. return;
  647. options = options || {};
  648. eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
  649. if (_document.createEvent) {
  650. evt = _document.createEvent('HTMLEvents');
  651. evt.initEvent(eventType, true, true);
  652. } else {
  653. evt = _document.createEventObject();
  654. evt.eventType = eventType;
  655. }
  656. for (key in options) if (hasKey(options, key)) {
  657. evt[key] = options[key];
  658. }
  659. if (_document.createEvent) {
  660. // IE9 if standards
  661. _document.dispatchEvent(evt);
  662. } else {
  663. // IE8 regardless of Quirks or Standards
  664. // IE9 if quirks
  665. try {
  666. _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
  667. } catch(e) {
  668. // Do nothing
  669. }
  670. }
  671. },
  672. /**
  673. * Wraps addEventListener to capture UI breadcrumbs
  674. * @param evtName the event name (e.g. "click")
  675. * @returns {Function}
  676. * @private
  677. */
  678. _breadcrumbEventHandler: function(evtName) {
  679. var self = this;
  680. return function (evt) {
  681. // reset keypress timeout; e.g. triggering a 'click' after
  682. // a 'keypress' will reset the keypress debounce so that a new
  683. // set of keypresses can be recorded
  684. self._keypressTimeout = null;
  685. // It's possible this handler might trigger multiple times for the same
  686. // event (e.g. event propagation through node ancestors). Ignore if we've
  687. // already captured the event.
  688. if (self._lastCapturedEvent === evt)
  689. return;
  690. self._lastCapturedEvent = evt;
  691. // try/catch both:
  692. // - accessing evt.target (see getsentry/raven-js#838, #768)
  693. // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
  694. // can throw an exception in some circumstances.
  695. var target;
  696. try {
  697. target = htmlTreeAsString(evt.target);
  698. } catch (e) {
  699. target = '<unknown>';
  700. }
  701. self.captureBreadcrumb({
  702. category: 'ui.' + evtName, // e.g. ui.click, ui.input
  703. message: target
  704. });
  705. };
  706. },
  707. /**
  708. * Wraps addEventListener to capture keypress UI events
  709. * @returns {Function}
  710. * @private
  711. */
  712. _keypressEventHandler: function() {
  713. var self = this,
  714. debounceDuration = 1000; // milliseconds
  715. // TODO: if somehow user switches keypress target before
  716. // debounce timeout is triggered, we will only capture
  717. // a single breadcrumb from the FIRST target (acceptable?)
  718. return function (evt) {
  719. var target;
  720. try {
  721. target = evt.target;
  722. } catch (e) {
  723. // just accessing event properties can throw an exception in some rare circumstances
  724. // see: https://github.com/getsentry/raven-js/issues/838
  725. return;
  726. }
  727. var tagName = target && target.tagName;
  728. // only consider keypress events on actual input elements
  729. // this will disregard keypresses targeting body (e.g. tabbing
  730. // through elements, hotkeys, etc)
  731. if (!tagName || tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)
  732. return;
  733. // record first keypress in a series, but ignore subsequent
  734. // keypresses until debounce clears
  735. var timeout = self._keypressTimeout;
  736. if (!timeout) {
  737. self._breadcrumbEventHandler('input')(evt);
  738. }
  739. clearTimeout(timeout);
  740. self._keypressTimeout = setTimeout(function () {
  741. self._keypressTimeout = null;
  742. }, debounceDuration);
  743. };
  744. },
  745. /**
  746. * Captures a breadcrumb of type "navigation", normalizing input URLs
  747. * @param to the originating URL
  748. * @param from the target URL
  749. * @private
  750. */
  751. _captureUrlChange: function(from, to) {
  752. var parsedLoc = parseUrl(this._location.href);
  753. var parsedTo = parseUrl(to);
  754. var parsedFrom = parseUrl(from);
  755. // because onpopstate only tells you the "new" (to) value of location.href, and
  756. // not the previous (from) value, we need to track the value of the current URL
  757. // state ourselves
  758. this._lastHref = to;
  759. // Use only the path component of the URL if the URL matches the current
  760. // document (almost all the time when using pushState)
  761. if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host)
  762. to = parsedTo.relative;
  763. if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host)
  764. from = parsedFrom.relative;
  765. this.captureBreadcrumb({
  766. category: 'navigation',
  767. data: {
  768. to: to,
  769. from: from
  770. }
  771. });
  772. },
  773. /**
  774. * Install any queued plugins
  775. */
  776. _instrumentTryCatch: function() {
  777. var self = this;
  778. var wrappedBuiltIns = self._wrappedBuiltIns;
  779. function wrapTimeFn(orig) {
  780. return function (fn, t) { // preserve arity
  781. // Make a copy of the arguments to prevent deoptimization
  782. // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
  783. var args = new Array(arguments.length);
  784. for(var i = 0; i < args.length; ++i) {
  785. args[i] = arguments[i];
  786. }
  787. var originalCallback = args[0];
  788. if (isFunction(originalCallback)) {
  789. args[0] = self.wrap(originalCallback);
  790. }
  791. // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
  792. // also supports only two arguments and doesn't care what this is, so we
  793. // can just call the original function directly.
  794. if (orig.apply) {
  795. return orig.apply(this, args);
  796. } else {
  797. return orig(args[0], args[1]);
  798. }
  799. };
  800. }
  801. var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
  802. function wrapEventTarget(global) {
  803. var proto = _window[global] && _window[global].prototype;
  804. if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
  805. fill(proto, 'addEventListener', function(orig) {
  806. return function (evtName, fn, capture, secure) { // preserve arity
  807. try {
  808. if (fn && fn.handleEvent) {
  809. fn.handleEvent = self.wrap(fn.handleEvent);
  810. }
  811. } catch (err) {
  812. // can sometimes get 'Permission denied to access property "handle Event'
  813. }
  814. // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
  815. // so that we don't have more than one wrapper function
  816. var before,
  817. clickHandler,
  818. keypressHandler;
  819. if (autoBreadcrumbs && autoBreadcrumbs.dom && (global === 'EventTarget' || global === 'Node')) {
  820. // NOTE: generating multiple handlers per addEventListener invocation, should
  821. // revisit and verify we can just use one (almost certainly)
  822. clickHandler = self._breadcrumbEventHandler('click');
  823. keypressHandler = self._keypressEventHandler();
  824. before = function (evt) {
  825. // need to intercept every DOM event in `before` argument, in case that
  826. // same wrapped method is re-used for different events (e.g. mousemove THEN click)
  827. // see #724
  828. if (!evt) return;
  829. var eventType;
  830. try {
  831. eventType = evt.type
  832. } catch (e) {
  833. // just accessing event properties can throw an exception in some rare circumstances
  834. // see: https://github.com/getsentry/raven-js/issues/838
  835. return;
  836. }
  837. if (eventType === 'click')
  838. return clickHandler(evt);
  839. else if (eventType === 'keypress')
  840. return keypressHandler(evt);
  841. };
  842. }
  843. return orig.call(this, evtName, self.wrap(fn, undefined, before), capture, secure);
  844. };
  845. }, wrappedBuiltIns);
  846. fill(proto, 'removeEventListener', function (orig) {
  847. return function (evt, fn, capture, secure) {
  848. try {
  849. fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn);
  850. } catch (e) {
  851. // ignore, accessing __raven_wrapper__ will throw in some Selenium environments
  852. }
  853. return orig.call(this, evt, fn, capture, secure);
  854. };
  855. }, wrappedBuiltIns);
  856. }
  857. }
  858. fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
  859. fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
  860. if (_window.requestAnimationFrame) {
  861. fill(_window, 'requestAnimationFrame', function (orig) {
  862. return function (cb) {
  863. return orig(self.wrap(cb));
  864. };
  865. }, wrappedBuiltIns);
  866. }
  867. // event targets borrowed from bugsnag-js:
  868. // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666
  869. var eventTargets = ['EventTarget', 'Window', 'Node', 'ApplicationCache', 'AudioTrackList', 'ChannelMergerNode', 'CryptoOperation', 'EventSource', 'FileReader', 'HTMLUnknownElement', 'IDBDatabase', 'IDBRequest', 'IDBTransaction', 'KeyOperation', 'MediaController', 'MessagePort', 'ModalWindow', 'Notification', 'SVGElementInstance', 'Screen', 'TextTrack', 'TextTrackCue', 'TextTrackList', 'WebSocket', 'WebSocketWorker', 'Worker', 'XMLHttpRequest', 'XMLHttpRequestEventTarget', 'XMLHttpRequestUpload'];
  870. for (var i = 0; i < eventTargets.length; i++) {
  871. wrapEventTarget(eventTargets[i]);
  872. }
  873. },
  874. /**
  875. * Instrument browser built-ins w/ breadcrumb capturing
  876. * - XMLHttpRequests
  877. * - DOM interactions (click/typing)
  878. * - window.location changes
  879. * - console
  880. *
  881. * Can be disabled or individually configured via the `autoBreadcrumbs` config option
  882. */
  883. _instrumentBreadcrumbs: function () {
  884. var self = this;
  885. var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
  886. var wrappedBuiltIns = self._wrappedBuiltIns;
  887. function wrapProp(prop, xhr) {
  888. if (prop in xhr && isFunction(xhr[prop])) {
  889. fill(xhr, prop, function (orig) {
  890. return self.wrap(orig);
  891. }); // intentionally don't track filled methods on XHR instances
  892. }
  893. }
  894. if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
  895. var xhrproto = XMLHttpRequest.prototype;
  896. fill(xhrproto, 'open', function(origOpen) {
  897. return function (method, url) { // preserve arity
  898. // if Sentry key appears in URL, don't capture
  899. if (isString(url) && url.indexOf(self._globalKey) === -1) {
  900. this.__raven_xhr = {
  901. method: method,
  902. url: url,
  903. status_code: null
  904. };
  905. }
  906. return origOpen.apply(this, arguments);
  907. };
  908. }, wrappedBuiltIns);
  909. fill(xhrproto, 'send', function(origSend) {
  910. return function (data) { // preserve arity
  911. var xhr = this;
  912. function onreadystatechangeHandler() {
  913. if (xhr.__raven_xhr && (xhr.readyState === 1 || xhr.readyState === 4)) {
  914. try {
  915. // touching statusCode in some platforms throws
  916. // an exception
  917. xhr.__raven_xhr.status_code = xhr.status;
  918. } catch (e) { /* do nothing */ }
  919. self.captureBreadcrumb({
  920. type: 'http',
  921. category: 'xhr',
  922. data: xhr.__raven_xhr
  923. });
  924. }
  925. }
  926. var props = ['onload', 'onerror', 'onprogress'];
  927. for (var j = 0; j < props.length; j++) {
  928. wrapProp(props[j], xhr);
  929. }
  930. if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) {
  931. fill(xhr, 'onreadystatechange', function (orig) {
  932. return self.wrap(orig, undefined, onreadystatechangeHandler);
  933. } /* intentionally don't track this instrumentation */);
  934. } else {
  935. // if onreadystatechange wasn't actually set by the page on this xhr, we
  936. // are free to set our own and capture the breadcrumb
  937. xhr.onreadystatechange = onreadystatechangeHandler;
  938. }
  939. return origSend.apply(this, arguments);
  940. };
  941. }, wrappedBuiltIns);
  942. }
  943. if (autoBreadcrumbs.xhr && 'fetch' in _window) {
  944. fill(_window, 'fetch', function(origFetch) {
  945. return function (fn, t) { // preserve arity
  946. // Make a copy of the arguments to prevent deoptimization
  947. // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
  948. var args = new Array(arguments.length);
  949. for(var i = 0; i < args.length; ++i) {
  950. args[i] = arguments[i];
  951. }
  952. var method = 'GET';
  953. if (args[1] && args[1].method) {
  954. method = args[1].method;
  955. }
  956. var fetchData = {
  957. method: method,
  958. url: args[0],
  959. status_code: null
  960. };
  961. self.captureBreadcrumb({
  962. type: 'http',
  963. category: 'fetch',
  964. data: fetchData
  965. });
  966. return origFetch.apply(this, args).then(function (response) {
  967. fetchData.status_code = response.status;
  968. return response;
  969. });
  970. };
  971. }, wrappedBuiltIns);
  972. }
  973. // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
  974. // to the document. Do this before we instrument addEventListener.
  975. if (autoBreadcrumbs.dom && this._hasDocument) {
  976. if (_document.addEventListener) {
  977. _document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
  978. _document.addEventListener('keypress', self._keypressEventHandler(), false);
  979. }
  980. else {
  981. // IE8 Compatibility
  982. _document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
  983. _document.attachEvent('onkeypress', self._keypressEventHandler());
  984. }
  985. }
  986. // record navigation (URL) changes
  987. // NOTE: in Chrome App environment, touching history.pushState, *even inside
  988. // a try/catch block*, will cause Chrome to output an error to console.error
  989. // borrowed from: https://github.com/angular/angular.js/pull/13945/files
  990. var chrome = _window.chrome;
  991. var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
  992. var hasPushState = !isChromePackagedApp && _window.history && history.pushState;
  993. if (autoBreadcrumbs.location && hasPushState) {
  994. // TODO: remove onpopstate handler on uninstall()
  995. var oldOnPopState = _window.onpopstate;
  996. _window.onpopstate = function () {
  997. var currentHref = self._location.href;
  998. self._captureUrlChange(self._lastHref, currentHref);
  999. if (oldOnPopState) {
  1000. return oldOnPopState.apply(this, arguments);
  1001. }
  1002. };
  1003. fill(history, 'pushState', function (origPushState) {
  1004. // note history.pushState.length is 0; intentionally not declaring
  1005. // params to preserve 0 arity
  1006. return function (/* state, title, url */) {
  1007. var url = arguments.length > 2 ? arguments[2] : undefined;
  1008. // url argument is optional
  1009. if (url) {
  1010. // coerce to string (this is what pushState does)
  1011. self._captureUrlChange(self._lastHref, url + '');
  1012. }
  1013. return origPushState.apply(this, arguments);
  1014. };
  1015. }, wrappedBuiltIns);
  1016. }
  1017. if (autoBreadcrumbs.console && 'console' in _window && console.log) {
  1018. // console
  1019. var consoleMethodCallback = function (msg, data) {
  1020. self.captureBreadcrumb({
  1021. message: msg,
  1022. level: data.level,
  1023. category: 'console'
  1024. });
  1025. };
  1026. each(['debug', 'info', 'warn', 'error', 'log'], function (_, level) {
  1027. wrapConsoleMethod(console, level, consoleMethodCallback);
  1028. });
  1029. }
  1030. },
  1031. _restoreBuiltIns: function () {
  1032. // restore any wrapped builtins
  1033. var builtin;
  1034. while (this._wrappedBuiltIns.length) {
  1035. builtin = this._wrappedBuiltIns.shift();
  1036. var obj = builtin[0],
  1037. name = builtin[1],
  1038. orig = builtin[2];
  1039. obj[name] = orig;
  1040. }
  1041. },
  1042. _drainPlugins: function() {
  1043. var self = this;
  1044. // FIX ME TODO
  1045. each(this._plugins, function(_, plugin) {
  1046. var installer = plugin[0];
  1047. var args = plugin[1];
  1048. installer.apply(self, [self].concat(args));
  1049. });
  1050. },
  1051. _parseDSN: function(str) {
  1052. var m = dsnPattern.exec(str),
  1053. dsn = {},
  1054. i = 7;
  1055. try {
  1056. while (i--) dsn[dsnKeys[i]] = m[i] || '';
  1057. } catch(e) {
  1058. throw new RavenConfigError('Invalid DSN: ' + str);
  1059. }
  1060. if (dsn.pass && !this._globalOptions.allowSecretKey) {
  1061. throw new RavenConfigError('Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key');
  1062. }
  1063. return dsn;
  1064. },
  1065. _getGlobalServer: function(uri) {
  1066. // assemble the endpoint from the uri pieces
  1067. var globalServer = '//' + uri.host +
  1068. (uri.port ? ':' + uri.port : '');
  1069. if (uri.protocol) {
  1070. globalServer = uri.protocol + ':' + globalServer;
  1071. }
  1072. return globalServer;
  1073. },
  1074. _handleOnErrorStackInfo: function() {
  1075. // if we are intentionally ignoring errors via onerror, bail out
  1076. if (!this._ignoreOnError) {
  1077. this._handleStackInfo.apply(this, arguments);
  1078. }
  1079. },
  1080. _handleStackInfo: function(stackInfo, options) {
  1081. var frames = this._prepareFrames(stackInfo, options);
  1082. this._triggerEvent('handle', {
  1083. stackInfo: stackInfo,
  1084. options: options
  1085. });
  1086. this._processException(
  1087. stackInfo.name,
  1088. stackInfo.message,
  1089. stackInfo.url,
  1090. stackInfo.lineno,
  1091. frames,
  1092. options
  1093. );
  1094. },
  1095. _prepareFrames: function(stackInfo, options) {
  1096. var self = this;
  1097. var frames = [];
  1098. if (stackInfo.stack && stackInfo.stack.length) {
  1099. each(stackInfo.stack, function(i, stack) {
  1100. var frame = self._normalizeFrame(stack);
  1101. if (frame) {
  1102. frames.push(frame);
  1103. }
  1104. });
  1105. // e.g. frames captured via captureMessage throw
  1106. if (options && options.trimHeadFrames) {
  1107. for (var j = 0; j < options.trimHeadFrames && j < frames.length; j++) {
  1108. frames[j].in_app = false;
  1109. }
  1110. }
  1111. }
  1112. frames = frames.slice(0, this._globalOptions.stackTraceLimit);
  1113. return frames;
  1114. },
  1115. _normalizeFrame: function(frame) {
  1116. if (!frame.url) return;
  1117. // normalize the frames data
  1118. var normalized = {
  1119. filename: frame.url,
  1120. lineno: frame.line,
  1121. colno: frame.column,
  1122. 'function': frame.func || '?'
  1123. };
  1124. normalized.in_app = !( // determine if an exception came from outside of our app
  1125. // first we check the global includePaths list.
  1126. !!this._globalOptions.includePaths.test && !this._globalOptions.includePaths.test(normalized.filename) ||
  1127. // Now we check for fun, if the function name is Raven or TraceKit
  1128. /(Raven|TraceKit)\./.test(normalized['function']) ||
  1129. // finally, we do a last ditch effort and check for raven.min.js
  1130. /raven\.(min\.)?js$/.test(normalized.filename)
  1131. );
  1132. return normalized;
  1133. },
  1134. _processException: function(type, message, fileurl, lineno, frames, options) {
  1135. var stacktrace;
  1136. if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;
  1137. message += '';
  1138. if (frames && frames.length) {
  1139. fileurl = frames[0].filename || fileurl;
  1140. // Sentry expects frames oldest to newest
  1141. // and JS sends them as newest to oldest
  1142. frames.reverse();
  1143. stacktrace = {frames: frames};
  1144. } else if (fileurl) {
  1145. stacktrace = {
  1146. frames: [{
  1147. filename: fileurl,
  1148. lineno: lineno,
  1149. in_app: true
  1150. }]
  1151. };
  1152. }
  1153. if (!!this._globalOptions.ignoreUrls.test && this._globalOptions.ignoreUrls.test(fileurl)) return;
  1154. if (!!this._globalOptions.whitelistUrls.test && !this._globalOptions.whitelistUrls.test(fileurl)) return;
  1155. var data = objectMerge({
  1156. // sentry.interfaces.Exception
  1157. exception: {
  1158. values: [{
  1159. type: type,
  1160. value: message,
  1161. stacktrace: stacktrace
  1162. }]
  1163. },
  1164. culprit: fileurl
  1165. }, options);
  1166. // Fire away!
  1167. this._send(data);
  1168. },
  1169. _trimPacket: function(data) {
  1170. // For now, we only want to truncate the two different messages
  1171. // but this could/should be expanded to just trim everything
  1172. var max = this._globalOptions.maxMessageLength;
  1173. if (data.message) {
  1174. data.message = truncate(data.message, max);
  1175. }
  1176. if (data.exception) {
  1177. var exception = data.exception.values[0];
  1178. exception.value = truncate(exception.value, max);
  1179. }
  1180. return data;
  1181. },
  1182. _getHttpData: function() {
  1183. if (!this._hasNavigator && !this._hasDocument) return;
  1184. var httpData = {};
  1185. if (this._hasNavigator && _navigator.userAgent) {
  1186. httpData.headers = {
  1187. 'User-Agent': navigator.userAgent
  1188. };
  1189. }
  1190. if (this._hasDocument) {
  1191. if (_document.location && _document.location.href) {
  1192. httpData.url = _document.location.href;
  1193. }
  1194. if (_document.referrer) {
  1195. if (!httpData.headers) httpData.headers = {};
  1196. httpData.headers.Referer = _document.referrer;
  1197. }
  1198. }
  1199. return httpData;
  1200. },
  1201. _resetBackoff: function() {
  1202. this._backoffDuration = 0;
  1203. this._backoffStart = null;
  1204. },
  1205. _shouldBackoff: function() {
  1206. return this._backoffDuration && now() - this._backoffStart < this._backoffDuration;
  1207. },
  1208. /**
  1209. * Returns true if the in-process data payload matches the signature
  1210. * of the previously-sent data
  1211. *
  1212. * NOTE: This has to be done at this level because TraceKit can generate
  1213. * data from window.onerror WITHOUT an exception object (IE8, IE9,
  1214. * other old browsers). This can take the form of an "exception"
  1215. * data object with a single frame (derived from the onerror args).
  1216. */
  1217. _isRepeatData: function (current) {
  1218. var last = this._lastData;
  1219. if (!last ||
  1220. current.message !== last.message || // defined for captureMessage
  1221. current.culprit !== last.culprit) // defined for captureException/onerror
  1222. return false;
  1223. // Stacktrace interface (i.e. from captureMessage)
  1224. if (current.stacktrace || last.stacktrace) {
  1225. return isSameStacktrace(current.stacktrace, last.stacktrace);
  1226. }
  1227. // Exception interface (i.e. from captureException/onerror)
  1228. else if (current.exception || last.exception) {
  1229. return isSameException(current.exception, last.exception);
  1230. }
  1231. return true;
  1232. },
  1233. _setBackoffState: function(request) {
  1234. // If we are already in a backoff state, don't change anything
  1235. if (this._shouldBackoff()) {
  1236. return;
  1237. }
  1238. var status = request.status;
  1239. // 400 - project_id doesn't exist or some other fatal
  1240. // 401 - invalid/revoked dsn
  1241. // 429 - too many requests
  1242. if (!(status === 400 || status === 401 || status === 429))
  1243. return;
  1244. var retry;
  1245. try {
  1246. // If Retry-After is not in Access-Control-Expose-Headers, most
  1247. // browsers will throw an exception trying to access it
  1248. retry = request.getResponseHeader('Retry-After');
  1249. retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
  1250. } catch (e) {
  1251. /* eslint no-empty:0 */
  1252. }
  1253. this._backoffDuration = retry
  1254. // If Sentry server returned a Retry-After value, use it
  1255. ? retry
  1256. // Otherwise, double the last backoff duration (starts at 1 sec)
  1257. : this._backoffDuration * 2 || 1000;
  1258. this._backoffStart = now();
  1259. },
  1260. _send: function(data) {
  1261. var globalOptions = this._globalOptions;
  1262. var baseData = {
  1263. project: this._globalProject,
  1264. logger: globalOptions.logger,
  1265. platform: 'javascript'
  1266. }, httpData = this._getHttpData();
  1267. if (httpData) {
  1268. baseData.request = httpData;
  1269. }
  1270. // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
  1271. if (data.trimHeadFrames) delete data.trimHeadFrames;
  1272. data = objectMerge(baseData, data);
  1273. // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
  1274. data.tags = objectMerge(objectMerge({}, this._globalContext.tags), data.tags);
  1275. data.extra = objectMerge(objectMerge({}, this._globalContext.extra), data.extra);
  1276. // Send along our own collected metadata with extra
  1277. data.extra['session:duration'] = now() - this._startTime;
  1278. if (this._breadcrumbs && this._breadcrumbs.length > 0) {
  1279. // intentionally make shallow copy so that additions
  1280. // to breadcrumbs aren't accidentally sent in this request
  1281. data.breadcrumbs = {
  1282. values: [].slice.call(this._breadcrumbs, 0)
  1283. };
  1284. }
  1285. // If there are no tags/extra, strip the key from the payload alltogther.
  1286. if (isEmptyObject(data.tags)) delete data.tags;
  1287. if (this._globalContext.user) {
  1288. // sentry.interfaces.User
  1289. data.user = this._globalContext.user;
  1290. }
  1291. // Include the environment if it's defined in globalOptions
  1292. if (globalOptions.environment) data.environment = globalOptions.environment;
  1293. // Include the release if it's defined in globalOptions
  1294. if (globalOptions.release) data.release = globalOptions.release;
  1295. // Include server_name if it's defined in globalOptions
  1296. if (globalOptions.serverName) data.server_name = globalOptions.serverName;
  1297. if (isFunction(globalOptions.dataCallback)) {
  1298. data = globalOptions.dataCallback(data) || data;
  1299. }
  1300. // Why??????????
  1301. if (!data || isEmptyObject(data)) {
  1302. return;
  1303. }
  1304. // Check if the request should be filtered or not
  1305. if (isFunction(globalOptions.shouldSendCallback) && !globalOptions.shouldSendCallback(data)) {
  1306. return;
  1307. }
  1308. // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests),
  1309. // so drop requests until "cool-off" period has elapsed.
  1310. if (this._shouldBackoff()) {
  1311. this._logDebug('warn', 'Raven dropped error due to backoff: ', data);
  1312. return;
  1313. }
  1314. if (typeof globalOptions.sampleRate === 'number') {
  1315. if (Math.random() < globalOptions.sampleRate) {
  1316. this._sendProcessedPayload(data);
  1317. }
  1318. } else {
  1319. this._sendProcessedPayload(data);
  1320. }
  1321. },
  1322. _getUuid: function () {
  1323. return uuid4();
  1324. },
  1325. _sendProcessedPayload: function(data, callback) {
  1326. var self = this;
  1327. var globalOptions = this._globalOptions;
  1328. if (!this.isSetup()) return;
  1329. // Send along an event_id if not explicitly passed.
  1330. // This event_id can be used to reference the error within Sentry itself.
  1331. // Set lastEventId after we know the error should actually be sent
  1332. this._lastEventId = data.event_id || (data.event_id = this._getUuid());
  1333. // Try and clean up the packet before sending by truncating long values
  1334. data = this._trimPacket(data);
  1335. // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback,
  1336. // but this would require copying an un-truncated copy of the data packet, which can be
  1337. // arbitrarily deep (extra_data) -- could be worthwhile? will revisit
  1338. if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) {
  1339. this._logDebug('warn', 'Raven dropped repeat event: ', data);
  1340. return;
  1341. }
  1342. // Store outbound payload after trim
  1343. this._lastData = data;
  1344. this._logDebug('debug', 'Raven about to send:', data);
  1345. var auth = {
  1346. sentry_version: '7',
  1347. sentry_client: 'raven-js/' + this.VERSION,
  1348. sentry_key: this._globalKey
  1349. };
  1350. if (this._globalSecret) {
  1351. auth.sentry_secret = this._globalSecret;
  1352. }
  1353. var exception = data.exception && data.exception.values[0];
  1354. this.captureBreadcrumb({
  1355. category: 'sentry',
  1356. message: exception
  1357. ? (exception.type ? exception.type + ': ' : '') + exception.value
  1358. : data.message,
  1359. event_id: data.event_id,
  1360. level: data.level || 'error' // presume error unless specified
  1361. });
  1362. var url = this._globalEndpoint;
  1363. (globalOptions.transport || this._makeRequest).call(this, {
  1364. url: url,
  1365. auth: auth,
  1366. data: data,
  1367. options: globalOptions,
  1368. onSuccess: function success() {
  1369. self._resetBackoff();
  1370. self._triggerEvent('success', {
  1371. data: data,
  1372. src: url
  1373. });
  1374. callback && callback();
  1375. },
  1376. onError: function failure(error) {
  1377. self._logDebug('error', 'Raven transport failed to send: ', error);
  1378. if (error.request) {
  1379. self._setBackoffState(error.request);
  1380. }
  1381. self._triggerEvent('failure', {
  1382. data: data,
  1383. src: url
  1384. });
  1385. error = error || new Error('Raven send failed (no additional details provided)');
  1386. callback && callback(error);
  1387. }
  1388. });
  1389. },
  1390. _makeRequest: function(opts) {
  1391. var request = new XMLHttpRequest();
  1392. // if browser doesn't support CORS (e.g. IE7), we are out of luck
  1393. var hasCORS =
  1394. 'withCredentials' in request ||
  1395. typeof XDomainRequest !== 'undefined';
  1396. if (!hasCORS) return;
  1397. var url = opts.url;
  1398. if ('withCredentials' in request) {
  1399. request.onreadystatechange = function () {
  1400. if (request.readyState !== 4) {
  1401. return;
  1402. } else if (request.status === 200) {
  1403. opts.onSuccess && opts.onSuccess();
  1404. } else if (opts.onError) {
  1405. var err = new Error('Sentry error code: ' + request.status);
  1406. err.request = request;
  1407. opts.onError(err);
  1408. }
  1409. };
  1410. } else {
  1411. request = new XDomainRequest();
  1412. // xdomainrequest cannot go http -> https (or vice versa),
  1413. // so always use protocol relative
  1414. url = url.replace(/^https?:/, '');
  1415. // onreadystatechange not supported by XDomainRequest
  1416. if (opts.onSuccess) {
  1417. request.onload = opts.onSuccess;
  1418. }
  1419. if (opts.onError) {
  1420. request.onerror = function () {
  1421. var err = new Error('Sentry error code: XDomainRequest');
  1422. err.request = request;
  1423. opts.onError(err);
  1424. }
  1425. }
  1426. }
  1427. // NOTE: auth is intentionally sent as part of query string (NOT as custom
  1428. // HTTP header) so as to avoid preflight CORS requests
  1429. request.open('POST', url + '?' + urlencode(opts.auth));
  1430. request.send(stringify(opts.data));
  1431. },
  1432. _logDebug: function(level) {
  1433. if (this._originalConsoleMethods[level] && this.debug) {
  1434. // In IE<10 console methods do not have their own 'apply' method
  1435. Function.prototype.apply.call(
  1436. this._originalConsoleMethods[level],
  1437. this._originalConsole,
  1438. [].slice.call(arguments, 1)
  1439. );
  1440. }
  1441. },
  1442. _mergeContext: function(key, context) {
  1443. if (isUndefined(context)) {
  1444. delete this._globalContext[key];
  1445. } else {
  1446. this._globalContext[key] = objectMerge(this._globalContext[key] || {}, context);
  1447. }
  1448. }
  1449. };
  1450. /*------------------------------------------------
  1451. * utils
  1452. *
  1453. * conditionally exported for test via Raven.utils
  1454. =================================================
  1455. */
  1456. var objectPrototype = Object.prototype;
  1457. function isUndefined(what) {
  1458. return what === void 0;
  1459. }
  1460. function isFunction(what) {
  1461. return typeof what === 'function';
  1462. }
  1463. function isString(what) {
  1464. return objectPrototype.toString.call(what) === '[object String]';
  1465. }
  1466. function isEmptyObject(what) {
  1467. for (var _ in what) return false; // eslint-disable-line guard-for-in, no-unused-vars
  1468. return true;
  1469. }
  1470. function each(obj, callback) {
  1471. var i, j;
  1472. if (isUndefined(obj.length)) {
  1473. for (i in obj) {
  1474. if (hasKey(obj, i)) {
  1475. callback.call(null, i, obj[i]);
  1476. }
  1477. }
  1478. } else {
  1479. j = obj.length;
  1480. if (j) {
  1481. for (i = 0; i < j; i++) {
  1482. callback.call(null, i, obj[i]);
  1483. }
  1484. }
  1485. }
  1486. }
  1487. function objectMerge(obj1, obj2) {
  1488. if (!obj2) {
  1489. return obj1;
  1490. }
  1491. each(obj2, function(key, value){
  1492. obj1[key] = value;
  1493. });
  1494. return obj1;
  1495. }
  1496. function truncate(str, max) {
  1497. return !max || str.length <= max ? str : str.substr(0, max) + '\u2026';
  1498. }
  1499. /**
  1500. * hasKey, a better form of hasOwnProperty
  1501. * Example: hasKey(MainHostObject, property) === true/false
  1502. *
  1503. * @param {Object} host object to check property
  1504. * @param {string} key to check
  1505. */
  1506. function hasKey(object, key) {
  1507. return objectPrototype.hasOwnProperty.call(object, key);
  1508. }
  1509. function joinRegExp(patterns) {
  1510. // Combine an array of regular expressions and strings into one large regexp
  1511. // Be mad.
  1512. var sources = [],
  1513. i = 0, len = patterns.length,
  1514. pattern;
  1515. for (; i < len; i++) {
  1516. pattern = patterns[i];
  1517. if (isString(pattern)) {
  1518. // If it's a string, we need to escape it
  1519. // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
  1520. sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'));
  1521. } else if (pattern && pattern.source) {
  1522. // If it's a regexp already, we want to extract the source
  1523. sources.push(pattern.source);
  1524. }
  1525. // Intentionally skip other cases
  1526. }
  1527. return new RegExp(sources.join('|'), 'i');
  1528. }
  1529. function urlencode(o) {
  1530. var pairs = [];
  1531. each(o, function(key, value) {
  1532. pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
  1533. });
  1534. return pairs.join('&');
  1535. }
  1536. // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
  1537. // intentionally using regex and not <a/> href parsing trick because React Native and other
  1538. // environments where DOM might not be available
  1539. function parseUrl(url) {
  1540. var match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);
  1541. if (!match) return {};
  1542. // coerce to undefined values to empty string so we don't get 'undefined'
  1543. var query = match[6] || '';
  1544. var fragment = match[8] || '';
  1545. return {
  1546. protocol: match[2],
  1547. host: match[4],
  1548. path: match[5],
  1549. relative: match[5] + query + fragment // everything minus origin
  1550. };
  1551. }
  1552. function uuid4() {
  1553. var crypto = _window.crypto || _window.msCrypto;
  1554. if (!isUndefined(crypto) && crypto.getRandomValues) {
  1555. // Use window.crypto API if available
  1556. var arr = new Uint16Array(8);
  1557. crypto.getRandomValues(arr);
  1558. // set 4 in byte 7
  1559. arr[3] = arr[3] & 0xFFF | 0x4000;
  1560. // set 2 most significant bits of byte 9 to '10'
  1561. arr[4] = arr[4] & 0x3FFF | 0x8000;
  1562. var pad = function(num) {
  1563. var v = num.toString(16);
  1564. while (v.length < 4) {
  1565. v = '0' + v;
  1566. }
  1567. return v;
  1568. };
  1569. return pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) +
  1570. pad(arr[5]) + pad(arr[6]) + pad(arr[7]);
  1571. } else {
  1572. // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
  1573. return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  1574. var r = Math.random()*16|0,
  1575. v = c === 'x' ? r : r&0x3|0x8;
  1576. return v.toString(16);
  1577. });
  1578. }
  1579. }
  1580. /**
  1581. * Given a child DOM element, returns a query-selector statement describing that
  1582. * and its ancestors
  1583. * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
  1584. * @param elem
  1585. * @returns {string}
  1586. */
  1587. function htmlTreeAsString(elem) {
  1588. /* eslint no-extra-parens:0*/
  1589. var MAX_TRAVERSE_HEIGHT = 5,
  1590. MAX_OUTPUT_LEN = 80,
  1591. out = [],
  1592. height = 0,
  1593. len = 0,
  1594. separator = ' > ',
  1595. sepLength = separator.length,
  1596. nextStr;
  1597. while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
  1598. nextStr = htmlElementAsString(elem);
  1599. // bail out if
  1600. // - nextStr is the 'html' element
  1601. // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
  1602. // (ignore this limit if we are on the first iteration)
  1603. if (nextStr === 'html' || height > 1 && len + (out.length * sepLength) + nextStr.length >= MAX_OUTPUT_LEN) {
  1604. break;
  1605. }
  1606. out.push(nextStr);
  1607. len += nextStr.length;
  1608. elem = elem.parentNode;
  1609. }
  1610. return out.reverse().join(separator);
  1611. }
  1612. /**
  1613. * Returns a simple, query-selector representation of a DOM element
  1614. * e.g. [HTMLElement] => input#foo.btn[name=baz]
  1615. * @param HTMLElement
  1616. * @returns {string}
  1617. */
  1618. function htmlElementAsString(elem) {
  1619. var out = [],
  1620. className,
  1621. classes,
  1622. key,
  1623. attr,
  1624. i;
  1625. if (!elem || !elem.tagName) {
  1626. return '';
  1627. }
  1628. out.push(elem.tagName.toLowerCase());
  1629. if (elem.id) {
  1630. out.push('#' + elem.id);
  1631. }
  1632. className = elem.className;
  1633. if (className && isString(className)) {
  1634. classes = className.split(/\s+/);
  1635. for (i = 0; i < classes.length; i++) {
  1636. out.push('.' + classes[i]);
  1637. }
  1638. }
  1639. var attrWhitelist = ['type', 'name', 'title', 'alt'];
  1640. for (i = 0; i < attrWhitelist.length; i++) {
  1641. key = attrWhitelist[i];
  1642. attr = elem.getAttribute(key);
  1643. if (attr) {
  1644. out.push('[' + key + '="' + attr + '"]');
  1645. }
  1646. }
  1647. return out.join('');
  1648. }
  1649. /**
  1650. * Returns true if either a OR b is truthy, but not both
  1651. */
  1652. function isOnlyOneTruthy(a, b) {
  1653. return !!(!!a ^ !!b);
  1654. }
  1655. /**
  1656. * Returns true if the two input exception interfaces have the same content
  1657. */
  1658. function isSameException(ex1, ex2) {
  1659. if (isOnlyOneTruthy(ex1, ex2))
  1660. return false;
  1661. ex1 = ex1.values[0];
  1662. ex2 = ex2.values[0];
  1663. if (ex1.type !== ex2.type ||
  1664. ex1.value !== ex2.value)
  1665. return false;
  1666. return isSameStacktrace(ex1.stacktrace, ex2.stacktrace);
  1667. }
  1668. /**
  1669. * Returns true if the two input stack trace interfaces have the same content
  1670. */
  1671. function isSameStacktrace(stack1, stack2) {
  1672. if (isOnlyOneTruthy(stack1, stack2))
  1673. return false;
  1674. var frames1 = stack1.frames;
  1675. var frames2 = stack2.frames;
  1676. // Exit early if frame count differs
  1677. if (frames1.length !== frames2.length)
  1678. return false;
  1679. // Iterate through every frame; bail out if anything differs
  1680. var a, b;
  1681. for (var i = 0; i < frames1.length; i++) {
  1682. a = frames1[i];
  1683. b = frames2[i];
  1684. if (a.filename !== b.filename ||
  1685. a.lineno !== b.lineno ||
  1686. a.colno !== b.colno ||
  1687. a['function'] !== b['function'])
  1688. return false;
  1689. }
  1690. return true;
  1691. }
  1692. /**
  1693. * Polyfill a method
  1694. * @param obj object e.g. `document`
  1695. * @param name method name present on object e.g. `addEventListener`
  1696. * @param replacement replacement function
  1697. * @param track {optional} record instrumentation to an array
  1698. */
  1699. function fill(obj, name, replacement, track) {
  1700. var orig = obj[name];
  1701. obj[name] = replacement(orig);
  1702. if (track) {
  1703. track.push([obj, name, orig]);
  1704. }
  1705. }
  1706. if (typeof __DEV__ !== 'undefined' && __DEV__) {
  1707. Raven.utils = {
  1708. isUndefined: isUndefined,
  1709. isFunction: isFunction,
  1710. isString: isString,
  1711. isObject: isObject,
  1712. isEmptyObject: isEmptyObject,
  1713. isError: isError,
  1714. each: each,
  1715. objectMerge: objectMerge,
  1716. truncate: truncate,
  1717. hasKey: hasKey,
  1718. joinRegExp: joinRegExp,
  1719. urlencode: urlencode,
  1720. uuid4: uuid4,
  1721. htmlTreeAsString: htmlTreeAsString,
  1722. htmlElementAsString: htmlElementAsString,
  1723. parseUrl: parseUrl,
  1724. fill: fill
  1725. };
  1726. };
  1727. // Deprecations
  1728. Raven.prototype.setUser = Raven.prototype.setUserContext;
  1729. Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
  1730. module.exports = Raven;
  1731. }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  1732. },{"1":1,"2":2,"5":5,"6":6,"7":7}],4:[function(_dereq_,module,exports){
  1733. (function (global){
  1734. /**
  1735. * Enforces a single instance of the Raven client, and the
  1736. * main entry point for Raven. If you are a consumer of the
  1737. * Raven library, you SHOULD load this file (vs raven.js).
  1738. **/
  1739. 'use strict';
  1740. var RavenConstructor = _dereq_(3);
  1741. // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
  1742. var _window = typeof window !== 'undefined' ? window
  1743. : typeof global !== 'undefined' ? global
  1744. : typeof self !== 'undefined' ? self
  1745. : {};
  1746. var _Raven = _window.Raven;
  1747. var Raven = new RavenConstructor();
  1748. /*
  1749. * Allow multiple versions of Raven to be installed.
  1750. * Strip Raven from the global context and returns the instance.
  1751. *
  1752. * @return {Raven}
  1753. */
  1754. Raven.noConflict = function () {
  1755. _window.Raven = _Raven;
  1756. return Raven;
  1757. };
  1758. Raven.afterLoad();
  1759. module.exports = Raven;
  1760. }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  1761. },{"3":3}],5:[function(_dereq_,module,exports){
  1762. 'use strict';
  1763. function isObject(what) {
  1764. return typeof what === 'object' && what !== null;
  1765. }
  1766. // Sorta yanked from https://github.com/joyent/node/blob/aa3b4b4/lib/util.js#L560
  1767. // with some tiny modifications
  1768. function isError(what) {
  1769. var toString = {}.toString.call(what);
  1770. return isObject(what) &&
  1771. toString === '[object Error]' ||
  1772. toString === '[object Exception]' || // Firefox NS_ERROR_FAILURE Exceptions
  1773. what instanceof Error;
  1774. }
  1775. module.exports = {
  1776. isObject: isObject,
  1777. isError: isError
  1778. };
  1779. },{}],6:[function(_dereq_,module,exports){
  1780. (function (global){
  1781. 'use strict';
  1782. var utils = _dereq_(5);
  1783. /*
  1784. TraceKit - Cross brower stack traces
  1785. This was originally forked from github.com/occ/TraceKit, but has since been
  1786. largely re-written and is now maintained as part of raven-js. Tests for
  1787. this are in test/vendor.
  1788. MIT license
  1789. */
  1790. var TraceKit = {
  1791. collectWindowErrors: true,
  1792. debug: false
  1793. };
  1794. // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
  1795. var _window = typeof window !== 'undefined' ? window
  1796. : typeof global !== 'undefined' ? global
  1797. : typeof self !== 'undefined' ? self
  1798. : {};
  1799. // global reference to slice
  1800. var _slice = [].slice;
  1801. var UNKNOWN_FUNCTION = '?';
  1802. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
  1803. var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;
  1804. function getLocationHref() {
  1805. if (typeof document === 'undefined' || typeof document.location === 'undefined')
  1806. return '';
  1807. return document.location.href;
  1808. }
  1809. /**
  1810. * TraceKit.report: cross-browser processing of unhandled exceptions
  1811. *
  1812. * Syntax:
  1813. * TraceKit.report.subscribe(function(stackInfo) { ... })
  1814. * TraceKit.report.unsubscribe(function(stackInfo) { ... })
  1815. * TraceKit.report(exception)
  1816. * try { ...code... } catch(ex) { TraceKit.report(ex); }
  1817. *
  1818. * Supports:
  1819. * - Firefox: full stack trace with line numbers, plus column number
  1820. * on top frame; column number is not guaranteed
  1821. * - Opera: full stack trace with line and column numbers
  1822. * - Chrome: full stack trace with line and column numbers
  1823. * - Safari: line and column number for the top frame only; some frames
  1824. * may be missing, and column number is not guaranteed
  1825. * - IE: line and column number for the top frame only; some frames
  1826. * may be missing, and column number is not guaranteed
  1827. *
  1828. * In theory, TraceKit should work on all of the following versions:
  1829. * - IE5.5+ (only 8.0 tested)
  1830. * - Firefox 0.9+ (only 3.5+ tested)
  1831. * - Opera 7+ (only 10.50 tested; versions 9 and earlier may require
  1832. * Exceptions Have Stacktrace to be enabled in opera:config)
  1833. * - Safari 3+ (only 4+ tested)
  1834. * - Chrome 1+ (only 5+ tested)
  1835. * - Konqueror 3.5+ (untested)
  1836. *
  1837. * Requires TraceKit.computeStackTrace.
  1838. *
  1839. * Tries to catch all unhandled exceptions and report them to the
  1840. * subscribed handlers. Please note that TraceKit.report will rethrow the
  1841. * exception. This is REQUIRED in order to get a useful stack trace in IE.
  1842. * If the exception does not reach the top of the browser, you will only
  1843. * get a stack trace from the point where TraceKit.report was called.
  1844. *
  1845. * Handlers receive a stackInfo object as described in the
  1846. * TraceKit.computeStackTrace docs.
  1847. */
  1848. TraceKit.report = (function reportModuleWrapper() {
  1849. var handlers = [],
  1850. lastArgs = null,
  1851. lastException = null,
  1852. lastExceptionStack = null;
  1853. /**
  1854. * Add a crash handler.
  1855. * @param {Function} handler
  1856. */
  1857. function subscribe(handler) {
  1858. installGlobalHandler();
  1859. handlers.push(handler);
  1860. }
  1861. /**
  1862. * Remove a crash handler.
  1863. * @param {Function} handler
  1864. */
  1865. function unsubscribe(handler) {
  1866. for (var i = handlers.length - 1; i >= 0; --i) {
  1867. if (handlers[i] === handler) {
  1868. handlers.splice(i, 1);
  1869. }
  1870. }
  1871. }
  1872. /**
  1873. * Remove all crash handlers.
  1874. */
  1875. function unsubscribeAll() {
  1876. uninstallGlobalHandler();
  1877. handlers = [];
  1878. }
  1879. /**
  1880. * Dispatch stack information to all handlers.
  1881. * @param {Object.<string, *>} stack
  1882. */
  1883. function notifyHandlers(stack, isWindowError) {
  1884. var exception = null;
  1885. if (isWindowError && !TraceKit.collectWindowErrors) {
  1886. return;
  1887. }
  1888. for (var i in handlers) {
  1889. if (handlers.hasOwnProperty(i)) {
  1890. try {
  1891. handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
  1892. } catch (inner) {
  1893. exception = inner;
  1894. }
  1895. }
  1896. }
  1897. if (exception) {
  1898. throw exception;
  1899. }
  1900. }
  1901. var _oldOnerrorHandler, _onErrorHandlerInstalled;
  1902. /**
  1903. * Ensures all global unhandled exceptions are recorded.
  1904. * Supported by Gecko and IE.
  1905. * @param {string} message Error message.
  1906. * @param {string} url URL of script that generated the exception.
  1907. * @param {(number|string)} lineNo The line number at which the error
  1908. * occurred.
  1909. * @param {?(number|string)} colNo The column number at which the error
  1910. * occurred.
  1911. * @param {?Error} ex The actual Error object.
  1912. */
  1913. function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
  1914. var stack = null;
  1915. if (lastExceptionStack) {
  1916. TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, message);
  1917. processLastException();
  1918. } else if (ex && utils.isError(ex)) {
  1919. // non-string `ex` arg; attempt to extract stack trace
  1920. // New chrome and blink send along a real error object
  1921. // Let's just report that like a normal error.
  1922. // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
  1923. stack = TraceKit.computeStackTrace(ex);
  1924. notifyHandlers(stack, true);
  1925. } else {
  1926. var location = {
  1927. 'url': url,
  1928. 'line': lineNo,
  1929. 'column': colNo
  1930. };
  1931. var name = undefined;
  1932. var msg = message; // must be new var or will modify original `arguments`
  1933. var groups;
  1934. if ({}.toString.call(message) === '[object String]') {
  1935. var groups = message.match(ERROR_TYPES_RE);
  1936. if (groups) {
  1937. name = groups[1];
  1938. msg = groups[2];
  1939. }
  1940. }
  1941. location.func = UNKNOWN_FUNCTION;
  1942. stack = {
  1943. 'name': name,
  1944. 'message': msg,
  1945. 'url': getLocationHref(),
  1946. 'stack': [location]
  1947. };
  1948. notifyHandlers(stack, true);
  1949. }
  1950. if (_oldOnerrorHandler) {
  1951. return _oldOnerrorHandler.apply(this, arguments);
  1952. }
  1953. return false;
  1954. }
  1955. function installGlobalHandler ()
  1956. {
  1957. if (_onErrorHandlerInstalled) {
  1958. return;
  1959. }
  1960. _oldOnerrorHandler = _window.onerror;
  1961. _window.onerror = traceKitWindowOnError;
  1962. _onErrorHandlerInstalled = true;
  1963. }
  1964. function uninstallGlobalHandler ()
  1965. {
  1966. if (!_onErrorHandlerInstalled) {
  1967. return;
  1968. }
  1969. _window.onerror = _oldOnerrorHandler;
  1970. _onErrorHandlerInstalled = false;
  1971. _oldOnerrorHandler = undefined;
  1972. }
  1973. function processLastException() {
  1974. var _lastExceptionStack = lastExceptionStack,
  1975. _lastArgs = lastArgs;
  1976. lastArgs = null;
  1977. lastExceptionStack = null;
  1978. lastException = null;
  1979. notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs));
  1980. }
  1981. /**
  1982. * Reports an unhandled Error to TraceKit.
  1983. * @param {Error} ex
  1984. * @param {?boolean} rethrow If false, do not re-throw the exception.
  1985. * Only used for window.onerror to not cause an infinite loop of
  1986. * rethrowing.
  1987. */
  1988. function report(ex, rethrow) {
  1989. var args = _slice.call(arguments, 1);
  1990. if (lastExceptionStack) {
  1991. if (lastException === ex) {
  1992. return; // already caught by an inner catch block, ignore
  1993. } else {
  1994. processLastException();
  1995. }
  1996. }
  1997. var stack = TraceKit.computeStackTrace(ex);
  1998. lastExceptionStack = stack;
  1999. lastException = ex;
  2000. lastArgs = args;
  2001. // If the stack trace is incomplete, wait for 2 seconds for
  2002. // slow slow IE to see if onerror occurs or not before reporting
  2003. // this exception; otherwise, we will end up with an incomplete
  2004. // stack trace
  2005. setTimeout(function () {
  2006. if (lastException === ex) {
  2007. processLastException();
  2008. }
  2009. }, (stack.incomplete ? 2000 : 0));
  2010. if (rethrow !== false) {
  2011. throw ex; // re-throw to propagate to the top level (and cause window.onerror)
  2012. }
  2013. }
  2014. report.subscribe = subscribe;
  2015. report.unsubscribe = unsubscribe;
  2016. report.uninstall = unsubscribeAll;
  2017. return report;
  2018. }());
  2019. /**
  2020. * TraceKit.computeStackTrace: cross-browser stack traces in JavaScript
  2021. *
  2022. * Syntax:
  2023. * s = TraceKit.computeStackTrace(exception) // consider using TraceKit.report instead (see below)
  2024. * Returns:
  2025. * s.name - exception name
  2026. * s.message - exception message
  2027. * s.stack[i].url - JavaScript or HTML file URL
  2028. * s.stack[i].func - function name, or empty for anonymous functions (if guessing did not work)
  2029. * s.stack[i].args - arguments passed to the function, if known
  2030. * s.stack[i].line - line number, if known
  2031. * s.stack[i].column - column number, if known
  2032. *
  2033. * Supports:
  2034. * - Firefox: full stack trace with line numbers and unreliable column
  2035. * number on top frame
  2036. * - Opera 10: full stack trace with line and column numbers
  2037. * - Opera 9-: full stack trace with line numbers
  2038. * - Chrome: full stack trace with line and column numbers
  2039. * - Safari: line and column number for the topmost stacktrace element
  2040. * only
  2041. * - IE: no line numbers whatsoever
  2042. *
  2043. * Tries to guess names of anonymous functions by looking for assignments
  2044. * in the source code. In IE and Safari, we have to guess source file names
  2045. * by searching for function bodies inside all page scripts. This will not
  2046. * work for scripts that are loaded cross-domain.
  2047. * Here be dragons: some function names may be guessed incorrectly, and
  2048. * duplicate functions may be mismatched.
  2049. *
  2050. * TraceKit.computeStackTrace should only be used for tracing purposes.
  2051. * Logging of unhandled exceptions should be done with TraceKit.report,
  2052. * which builds on top of TraceKit.computeStackTrace and provides better
  2053. * IE support by utilizing the window.onerror event to retrieve information
  2054. * about the top of the stack.
  2055. *
  2056. * Note: In IE and Safari, no stack trace is recorded on the Error object,
  2057. * so computeStackTrace instead walks its *own* chain of callers.
  2058. * This means that:
  2059. * * in Safari, some methods may be missing from the stack trace;
  2060. * * in IE, the topmost function in the stack trace will always be the
  2061. * caller of computeStackTrace.
  2062. *
  2063. * This is okay for tracing (because you are likely to be calling
  2064. * computeStackTrace from the function you want to be the topmost element
  2065. * of the stack trace anyway), but not okay for logging unhandled
  2066. * exceptions (because your catch block will likely be far away from the
  2067. * inner function that actually caused the exception).
  2068. *
  2069. */
  2070. TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
  2071. /**
  2072. * Escapes special characters, except for whitespace, in a string to be
  2073. * used inside a regular expression as a string literal.
  2074. * @param {string} text The string.
  2075. * @return {string} The escaped string literal.
  2076. */
  2077. function escapeRegExp(text) {
  2078. return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&');
  2079. }
  2080. /**
  2081. * Escapes special characters in a string to be used inside a regular
  2082. * expression as a string literal. Also ensures that HTML entities will
  2083. * be matched the same as their literal friends.
  2084. * @param {string} body The string.
  2085. * @return {string} The escaped string.
  2086. */
  2087. function escapeCodeAsRegExpForMatchingInsideHTML(body) {
  2088. return escapeRegExp(body).replace('<', '(?:<|&lt;)').replace('>', '(?:>|&gt;)').replace('&', '(?:&|&amp;)').replace('"', '(?:"|&quot;)').replace(/\s+/g, '\\s+');
  2089. }
  2090. // Contents of Exception in various browsers.
  2091. //
  2092. // SAFARI:
  2093. // ex.message = Can't find variable: qq
  2094. // ex.line = 59
  2095. // ex.sourceId = 580238192
  2096. // ex.sourceURL = http://...
  2097. // ex.expressionBeginOffset = 96
  2098. // ex.expressionCaretOffset = 98
  2099. // ex.expressionEndOffset = 98
  2100. // ex.name = ReferenceError
  2101. //
  2102. // FIREFOX:
  2103. // ex.message = qq is not defined
  2104. // ex.fileName = http://...
  2105. // ex.lineNumber = 59
  2106. // ex.columnNumber = 69
  2107. // ex.stack = ...stack trace... (see the example below)
  2108. // ex.name = ReferenceError
  2109. //
  2110. // CHROME:
  2111. // ex.message = qq is not defined
  2112. // ex.name = ReferenceError
  2113. // ex.type = not_defined
  2114. // ex.arguments = ['aa']
  2115. // ex.stack = ...stack trace...
  2116. //
  2117. // INTERNET EXPLORER:
  2118. // ex.message = ...
  2119. // ex.name = ReferenceError
  2120. //
  2121. // OPERA:
  2122. // ex.message = ...message... (see the example below)
  2123. // ex.name = ReferenceError
  2124. // ex.opera#sourceloc = 11 (pretty much useless, duplicates the info in ex.message)
  2125. // ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
  2126. /**
  2127. * Computes stack trace information from the stack property.
  2128. * Chrome and Gecko use this property.
  2129. * @param {Error} ex
  2130. * @return {?Object.<string, *>} Stack trace information.
  2131. */
  2132. function computeStackTraceFromStackProp(ex) {
  2133. if (typeof ex.stack === 'undefined' || !ex.stack) return;
  2134. var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|<anonymous>).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
  2135. gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|resource|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i,
  2136. winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
  2137. lines = ex.stack.split('\n'),
  2138. stack = [],
  2139. parts,
  2140. element,
  2141. reference = /^(.*) is undefined$/.exec(ex.message);
  2142. for (var i = 0, j = lines.length; i < j; ++i) {
  2143. if ((parts = chrome.exec(lines[i]))) {
  2144. var isNative = parts[2] && parts[2].indexOf('native') !== -1;
  2145. element = {
  2146. 'url': !isNative ? parts[2] : null,
  2147. 'func': parts[1] || UNKNOWN_FUNCTION,
  2148. 'args': isNative ? [parts[2]] : [],
  2149. 'line': parts[3] ? +parts[3] : null,
  2150. 'column': parts[4] ? +parts[4] : null
  2151. };
  2152. } else if ( parts = winjs.exec(lines[i]) ) {
  2153. element = {
  2154. 'url': parts[2],
  2155. 'func': parts[1] || UNKNOWN_FUNCTION,
  2156. 'args': [],
  2157. 'line': +parts[3],
  2158. 'column': parts[4] ? +parts[4] : null
  2159. };
  2160. } else if ((parts = gecko.exec(lines[i]))) {
  2161. element = {
  2162. 'url': parts[3],
  2163. 'func': parts[1] || UNKNOWN_FUNCTION,
  2164. 'args': parts[2] ? parts[2].split(',') : [],
  2165. 'line': parts[4] ? +parts[4] : null,
  2166. 'column': parts[5] ? +parts[5] : null
  2167. };
  2168. } else {
  2169. continue;
  2170. }
  2171. if (!element.func && element.line) {
  2172. element.func = UNKNOWN_FUNCTION;
  2173. }
  2174. stack.push(element);
  2175. }
  2176. if (!stack.length) {
  2177. return null;
  2178. }
  2179. if (!stack[0].column && typeof ex.columnNumber !== 'undefined') {
  2180. // FireFox uses this awesome columnNumber property for its top frame
  2181. // Also note, Firefox's column number is 0-based and everything else expects 1-based,
  2182. // so adding 1
  2183. stack[0].column = ex.columnNumber + 1;
  2184. }
  2185. return {
  2186. 'name': ex.name,
  2187. 'message': ex.message,
  2188. 'url': getLocationHref(),
  2189. 'stack': stack
  2190. };
  2191. }
  2192. /**
  2193. * Adds information about the first frame to incomplete stack traces.
  2194. * Safari and IE require this to get complete data on the first frame.
  2195. * @param {Object.<string, *>} stackInfo Stack trace information from
  2196. * one of the compute* methods.
  2197. * @param {string} url The URL of the script that caused an error.
  2198. * @param {(number|string)} lineNo The line number of the script that
  2199. * caused an error.
  2200. * @param {string=} message The error generated by the browser, which
  2201. * hopefully contains the name of the object that caused the error.
  2202. * @return {boolean} Whether or not the stack information was
  2203. * augmented.
  2204. */
  2205. function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, message) {
  2206. var initial = {
  2207. 'url': url,
  2208. 'line': lineNo
  2209. };
  2210. if (initial.url && initial.line) {
  2211. stackInfo.incomplete = false;
  2212. if (!initial.func) {
  2213. initial.func = UNKNOWN_FUNCTION;
  2214. }
  2215. if (stackInfo.stack.length > 0) {
  2216. if (stackInfo.stack[0].url === initial.url) {
  2217. if (stackInfo.stack[0].line === initial.line) {
  2218. return false; // already in stack trace
  2219. } else if (!stackInfo.stack[0].line && stackInfo.stack[0].func === initial.func) {
  2220. stackInfo.stack[0].line = initial.line;
  2221. return false;
  2222. }
  2223. }
  2224. }
  2225. stackInfo.stack.unshift(initial);
  2226. stackInfo.partial = true;
  2227. return true;
  2228. } else {
  2229. stackInfo.incomplete = true;
  2230. }
  2231. return false;
  2232. }
  2233. /**
  2234. * Computes stack trace information by walking the arguments.caller
  2235. * chain at the time the exception occurred. This will cause earlier
  2236. * frames to be missed but is the only way to get any stack trace in
  2237. * Safari and IE. The top frame is restored by
  2238. * {@link augmentStackTraceWithInitialElement}.
  2239. * @param {Error} ex
  2240. * @return {?Object.<string, *>} Stack trace information.
  2241. */
  2242. function computeStackTraceByWalkingCallerChain(ex, depth) {
  2243. var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
  2244. stack = [],
  2245. funcs = {},
  2246. recursion = false,
  2247. parts,
  2248. item,
  2249. source;
  2250. for (var curr = computeStackTraceByWalkingCallerChain.caller; curr && !recursion; curr = curr.caller) {
  2251. if (curr === computeStackTrace || curr === TraceKit.report) {
  2252. // console.log('skipping internal function');
  2253. continue;
  2254. }
  2255. item = {
  2256. 'url': null,
  2257. 'func': UNKNOWN_FUNCTION,
  2258. 'line': null,
  2259. 'column': null
  2260. };
  2261. if (curr.name) {
  2262. item.func = curr.name;
  2263. } else if ((parts = functionName.exec(curr.toString()))) {
  2264. item.func = parts[1];
  2265. }
  2266. if (typeof item.func === 'undefined') {
  2267. try {
  2268. item.func = parts.input.substring(0, parts.input.indexOf('{'));
  2269. } catch (e) { }
  2270. }
  2271. if (funcs['' + curr]) {
  2272. recursion = true;
  2273. }else{
  2274. funcs['' + curr] = true;
  2275. }
  2276. stack.push(item);
  2277. }
  2278. if (depth) {
  2279. // console.log('depth is ' + depth);
  2280. // console.log('stack is ' + stack.length);
  2281. stack.splice(0, depth);
  2282. }
  2283. var result = {
  2284. 'name': ex.name,
  2285. 'message': ex.message,
  2286. 'url': getLocationHref(),
  2287. 'stack': stack
  2288. };
  2289. augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
  2290. return result;
  2291. }
  2292. /**
  2293. * Computes a stack trace for an exception.
  2294. * @param {Error} ex
  2295. * @param {(string|number)=} depth
  2296. */
  2297. function computeStackTrace(ex, depth) {
  2298. var stack = null;
  2299. depth = (depth == null ? 0 : +depth);
  2300. try {
  2301. stack = computeStackTraceFromStackProp(ex);
  2302. if (stack) {
  2303. return stack;
  2304. }
  2305. } catch (e) {
  2306. if (TraceKit.debug) {
  2307. throw e;
  2308. }
  2309. }
  2310. try {
  2311. stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
  2312. if (stack) {
  2313. return stack;
  2314. }
  2315. } catch (e) {
  2316. if (TraceKit.debug) {
  2317. throw e;
  2318. }
  2319. }
  2320. return {
  2321. 'name': ex.name,
  2322. 'message': ex.message,
  2323. 'url': getLocationHref()
  2324. };
  2325. }
  2326. computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
  2327. computeStackTrace.computeStackTraceFromStackProp = computeStackTraceFromStackProp;
  2328. return computeStackTrace;
  2329. }());
  2330. module.exports = TraceKit;
  2331. }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  2332. },{"5":5}],7:[function(_dereq_,module,exports){
  2333. 'use strict';
  2334. /*
  2335. json-stringify-safe
  2336. Like JSON.stringify, but doesn't throw on circular references.
  2337. Originally forked from https://github.com/isaacs/json-stringify-safe
  2338. version 5.0.1 on 3/8/2017 and modified for IE8 compatibility.
  2339. Tests for this are in test/vendor.
  2340. ISC license: https://github.com/isaacs/json-stringify-safe/blob/master/LICENSE
  2341. */
  2342. exports = module.exports = stringify
  2343. exports.getSerialize = serializer
  2344. function indexOf(haystack, needle) {
  2345. for (var i = 0; i < haystack.length; ++i) {
  2346. if (haystack[i] === needle) return i;
  2347. }
  2348. return -1;
  2349. }
  2350. function stringify(obj, replacer, spaces, cycleReplacer) {
  2351. return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces)
  2352. }
  2353. function serializer(replacer, cycleReplacer) {
  2354. var stack = [], keys = []
  2355. if (cycleReplacer == null) cycleReplacer = function(key, value) {
  2356. if (stack[0] === value) return '[Circular ~]'
  2357. return '[Circular ~.' + keys.slice(0, indexOf(stack, value)).join('.') + ']'
  2358. }
  2359. return function(key, value) {
  2360. if (stack.length > 0) {
  2361. var thisPos = indexOf(stack, this);
  2362. ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
  2363. ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
  2364. if (~indexOf(stack, value)) value = cycleReplacer.call(this, key, value)
  2365. }
  2366. else stack.push(value)
  2367. return replacer == null ? value : replacer.call(this, key, value)
  2368. }
  2369. }
  2370. },{}]},{},[4])(4)
  2371. });