raven.js 94 KB

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