raven.js 91 KB

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