raven.js 92 KB

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