UNPKG

10 kBJavaScriptView Raw
1Object.defineProperty(exports, "__esModule", { value: true });
2var tslib_1 = require("tslib");
3var utils_1 = require("@sentry/utils");
4var helpers_1 = require("../helpers");
5var DEFAULT_EVENT_TARGET = [
6 'EventTarget',
7 'Window',
8 'Node',
9 'ApplicationCache',
10 'AudioTrackList',
11 'ChannelMergerNode',
12 'CryptoOperation',
13 'EventSource',
14 'FileReader',
15 'HTMLUnknownElement',
16 'IDBDatabase',
17 'IDBRequest',
18 'IDBTransaction',
19 'KeyOperation',
20 'MediaController',
21 'MessagePort',
22 'ModalWindow',
23 'Notification',
24 'SVGElementInstance',
25 'Screen',
26 'TextTrack',
27 'TextTrackCue',
28 'TextTrackList',
29 'WebSocket',
30 'WebSocketWorker',
31 'Worker',
32 'XMLHttpRequest',
33 'XMLHttpRequestEventTarget',
34 'XMLHttpRequestUpload',
35];
36/** Wrap timer functions and event targets to catch errors and provide better meta data */
37var TryCatch = /** @class */ (function () {
38 /**
39 * @inheritDoc
40 */
41 function TryCatch(options) {
42 /**
43 * @inheritDoc
44 */
45 this.name = TryCatch.id;
46 this._options = tslib_1.__assign({ XMLHttpRequest: true, eventTarget: true, requestAnimationFrame: true, setInterval: true, setTimeout: true }, options);
47 }
48 /**
49 * Wrap timer functions and event targets to catch errors
50 * and provide better metadata.
51 */
52 TryCatch.prototype.setupOnce = function () {
53 var global = utils_1.getGlobalObject();
54 if (this._options.setTimeout) {
55 utils_1.fill(global, 'setTimeout', this._wrapTimeFunction.bind(this));
56 }
57 if (this._options.setInterval) {
58 utils_1.fill(global, 'setInterval', this._wrapTimeFunction.bind(this));
59 }
60 if (this._options.requestAnimationFrame) {
61 utils_1.fill(global, 'requestAnimationFrame', this._wrapRAF.bind(this));
62 }
63 if (this._options.XMLHttpRequest && 'XMLHttpRequest' in global) {
64 utils_1.fill(XMLHttpRequest.prototype, 'send', this._wrapXHR.bind(this));
65 }
66 if (this._options.eventTarget) {
67 var eventTarget = Array.isArray(this._options.eventTarget) ? this._options.eventTarget : DEFAULT_EVENT_TARGET;
68 eventTarget.forEach(this._wrapEventTarget.bind(this));
69 }
70 };
71 /** JSDoc */
72 TryCatch.prototype._wrapTimeFunction = function (original) {
73 // eslint-disable-next-line @typescript-eslint/no-explicit-any
74 return function () {
75 var args = [];
76 for (var _i = 0; _i < arguments.length; _i++) {
77 args[_i] = arguments[_i];
78 }
79 var originalCallback = args[0];
80 args[0] = helpers_1.wrap(originalCallback, {
81 mechanism: {
82 data: { function: utils_1.getFunctionName(original) },
83 handled: true,
84 type: 'instrument',
85 },
86 });
87 return original.apply(this, args);
88 };
89 };
90 /** JSDoc */
91 // eslint-disable-next-line @typescript-eslint/no-explicit-any
92 TryCatch.prototype._wrapRAF = function (original) {
93 // eslint-disable-next-line @typescript-eslint/no-explicit-any
94 return function (callback) {
95 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
96 return original.call(this, helpers_1.wrap(callback, {
97 mechanism: {
98 data: {
99 function: 'requestAnimationFrame',
100 handler: utils_1.getFunctionName(original),
101 },
102 handled: true,
103 type: 'instrument',
104 },
105 }));
106 };
107 };
108 /** JSDoc */
109 TryCatch.prototype._wrapEventTarget = function (target) {
110 // eslint-disable-next-line @typescript-eslint/no-explicit-any
111 var global = utils_1.getGlobalObject();
112 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
113 var proto = global[target] && global[target].prototype;
114 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
115 if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
116 return;
117 }
118 utils_1.fill(proto, 'addEventListener', function (original) {
119 return function (eventName, fn, options) {
120 try {
121 if (typeof fn.handleEvent === 'function') {
122 fn.handleEvent = helpers_1.wrap(fn.handleEvent.bind(fn), {
123 mechanism: {
124 data: {
125 function: 'handleEvent',
126 handler: utils_1.getFunctionName(fn),
127 target: target,
128 },
129 handled: true,
130 type: 'instrument',
131 },
132 });
133 }
134 }
135 catch (err) {
136 // can sometimes get 'Permission denied to access property "handle Event'
137 }
138 return original.call(this, eventName,
139 // eslint-disable-next-line @typescript-eslint/no-explicit-any
140 helpers_1.wrap(fn, {
141 mechanism: {
142 data: {
143 function: 'addEventListener',
144 handler: utils_1.getFunctionName(fn),
145 target: target,
146 },
147 handled: true,
148 type: 'instrument',
149 },
150 }), options);
151 };
152 });
153 utils_1.fill(proto, 'removeEventListener', function (originalRemoveEventListener) {
154 return function (eventName, fn, options) {
155 var _a;
156 /**
157 * There are 2 possible scenarios here:
158 *
159 * 1. Someone passes a callback, which was attached prior to Sentry initialization, or by using unmodified
160 * method, eg. `document.addEventListener.call(el, name, handler). In this case, we treat this function
161 * as a pass-through, and call original `removeEventListener` with it.
162 *
163 * 2. Someone passes a callback, which was attached after Sentry was initialized, which means that it was using
164 * our wrapped version of `addEventListener`, which internally calls `wrap` helper.
165 * This helper "wraps" whole callback inside a try/catch statement, and attached appropriate metadata to it,
166 * in order for us to make a distinction between wrapped/non-wrapped functions possible.
167 * If a function was wrapped, it has additional property of `__sentry_wrapped__`, holding the handler.
168 *
169 * When someone adds a handler prior to initialization, and then do it again, but after,
170 * then we have to detach both of them. Otherwise, if we'd detach only wrapped one, it'd be impossible
171 * to get rid of the initial handler and it'd stick there forever.
172 */
173 var wrappedEventHandler = fn;
174 try {
175 var originalEventHandler = (_a = wrappedEventHandler) === null || _a === void 0 ? void 0 : _a.__sentry_wrapped__;
176 if (originalEventHandler) {
177 originalRemoveEventListener.call(this, eventName, originalEventHandler, options);
178 }
179 }
180 catch (e) {
181 // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments
182 }
183 return originalRemoveEventListener.call(this, eventName, wrappedEventHandler, options);
184 };
185 });
186 };
187 /** JSDoc */
188 TryCatch.prototype._wrapXHR = function (originalSend) {
189 // eslint-disable-next-line @typescript-eslint/no-explicit-any
190 return function () {
191 var args = [];
192 for (var _i = 0; _i < arguments.length; _i++) {
193 args[_i] = arguments[_i];
194 }
195 // eslint-disable-next-line @typescript-eslint/no-this-alias
196 var xhr = this;
197 var xmlHttpRequestProps = ['onload', 'onerror', 'onprogress', 'onreadystatechange'];
198 xmlHttpRequestProps.forEach(function (prop) {
199 if (prop in xhr && typeof xhr[prop] === 'function') {
200 // eslint-disable-next-line @typescript-eslint/no-explicit-any
201 utils_1.fill(xhr, prop, function (original) {
202 var wrapOptions = {
203 mechanism: {
204 data: {
205 function: prop,
206 handler: utils_1.getFunctionName(original),
207 },
208 handled: true,
209 type: 'instrument',
210 },
211 };
212 // If Instrument integration has been called before TryCatch, get the name of original function
213 if (original.__sentry_original__) {
214 wrapOptions.mechanism.data.handler = utils_1.getFunctionName(original.__sentry_original__);
215 }
216 // Otherwise wrap directly
217 return helpers_1.wrap(original, wrapOptions);
218 });
219 }
220 });
221 return originalSend.apply(this, args);
222 };
223 };
224 /**
225 * @inheritDoc
226 */
227 TryCatch.id = 'TryCatch';
228 return TryCatch;
229}());
230exports.TryCatch = TryCatch;
231//# sourceMappingURL=trycatch.js.map
\No newline at end of file