summaryrefslogtreecommitdiff
path: root/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js
diff options
context:
space:
mode:
authorrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
committerrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
commitbce557cc2dc767628bed6aac87301a1be7c5431b (patch)
treeb51a051228d01fe3306cd7626d4a96768aadb944 /shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js
init commit
Diffstat (limited to 'shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js')
-rw-r--r--shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js281
1 files changed, 281 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js
new file mode 100644
index 0000000..69e112f
--- /dev/null
+++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js
@@ -0,0 +1,281 @@
+import { fill, getFunctionName, getOriginalFunction } from '@sentry/utils';
+import { WINDOW, wrap } from '../helpers.js';
+
+const DEFAULT_EVENT_TARGET = [
+ 'EventTarget',
+ 'Window',
+ 'Node',
+ 'ApplicationCache',
+ 'AudioTrackList',
+ 'ChannelMergerNode',
+ 'CryptoOperation',
+ 'EventSource',
+ 'FileReader',
+ 'HTMLUnknownElement',
+ 'IDBDatabase',
+ 'IDBRequest',
+ 'IDBTransaction',
+ 'KeyOperation',
+ 'MediaController',
+ 'MessagePort',
+ 'ModalWindow',
+ 'Notification',
+ 'SVGElementInstance',
+ 'Screen',
+ 'TextTrack',
+ 'TextTrackCue',
+ 'TextTrackList',
+ 'WebSocket',
+ 'WebSocketWorker',
+ 'Worker',
+ 'XMLHttpRequest',
+ 'XMLHttpRequestEventTarget',
+ 'XMLHttpRequestUpload',
+];
+
+/** Wrap timer functions and event targets to catch errors and provide better meta data */
+class TryCatch {
+ /**
+ * @inheritDoc
+ */
+ static __initStatic() {this.id = 'TryCatch';}
+
+ /**
+ * @inheritDoc
+ */
+ __init() {this.name = TryCatch.id;}
+
+ /** JSDoc */
+
+ /**
+ * @inheritDoc
+ */
+ constructor(options) {TryCatch.prototype.__init.call(this);
+ this._options = {
+ XMLHttpRequest: true,
+ eventTarget: true,
+ requestAnimationFrame: true,
+ setInterval: true,
+ setTimeout: true,
+ ...options,
+ };
+ }
+
+ /**
+ * Wrap timer functions and event targets to catch errors
+ * and provide better metadata.
+ */
+ setupOnce() {
+ if (this._options.setTimeout) {
+ fill(WINDOW, 'setTimeout', _wrapTimeFunction);
+ }
+
+ if (this._options.setInterval) {
+ fill(WINDOW, 'setInterval', _wrapTimeFunction);
+ }
+
+ if (this._options.requestAnimationFrame) {
+ fill(WINDOW, 'requestAnimationFrame', _wrapRAF);
+ }
+
+ if (this._options.XMLHttpRequest && 'XMLHttpRequest' in WINDOW) {
+ fill(XMLHttpRequest.prototype, 'send', _wrapXHR);
+ }
+
+ const eventTargetOption = this._options.eventTarget;
+ if (eventTargetOption) {
+ const eventTarget = Array.isArray(eventTargetOption) ? eventTargetOption : DEFAULT_EVENT_TARGET;
+ eventTarget.forEach(_wrapEventTarget);
+ }
+ }
+} TryCatch.__initStatic();
+
+/** JSDoc */
+function _wrapTimeFunction(original) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return function ( ...args) {
+ const originalCallback = args[0];
+ args[0] = wrap(originalCallback, {
+ mechanism: {
+ data: { function: getFunctionName(original) },
+ handled: true,
+ type: 'instrument',
+ },
+ });
+ return original.apply(this, args);
+ };
+}
+
+/** JSDoc */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function _wrapRAF(original) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return function ( callback) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return original.apply(this, [
+ wrap(callback, {
+ mechanism: {
+ data: {
+ function: 'requestAnimationFrame',
+ handler: getFunctionName(original),
+ },
+ handled: true,
+ type: 'instrument',
+ },
+ }),
+ ]);
+ };
+}
+
+/** JSDoc */
+function _wrapXHR(originalSend) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return function ( ...args) {
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
+ const xhr = this;
+ const xmlHttpRequestProps = ['onload', 'onerror', 'onprogress', 'onreadystatechange'];
+
+ xmlHttpRequestProps.forEach(prop => {
+ if (prop in xhr && typeof xhr[prop] === 'function') {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ fill(xhr, prop, function (original) {
+ const wrapOptions = {
+ mechanism: {
+ data: {
+ function: prop,
+ handler: getFunctionName(original),
+ },
+ handled: true,
+ type: 'instrument',
+ },
+ };
+
+ // If Instrument integration has been called before TryCatch, get the name of original function
+ const originalFunction = getOriginalFunction(original);
+ if (originalFunction) {
+ wrapOptions.mechanism.data.handler = getFunctionName(originalFunction);
+ }
+
+ // Otherwise wrap directly
+ return wrap(original, wrapOptions);
+ });
+ }
+ });
+
+ return originalSend.apply(this, args);
+ };
+}
+
+/** JSDoc */
+function _wrapEventTarget(target) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const globalObject = WINDOW ;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ const proto = globalObject[target] && globalObject[target].prototype;
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins
+ if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
+ return;
+ }
+
+ fill(proto, 'addEventListener', function (original)
+
+ {
+ return function (
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+
+ eventName,
+ fn,
+ options,
+ ) {
+ try {
+ if (typeof fn.handleEvent === 'function') {
+ // ESlint disable explanation:
+ // First, it is generally safe to call `wrap` with an unbound function. Furthermore, using `.bind()` would
+ // introduce a bug here, because bind returns a new function that doesn't have our
+ // flags(like __sentry_original__) attached. `wrap` checks for those flags to avoid unnecessary wrapping.
+ // Without those flags, every call to addEventListener wraps the function again, causing a memory leak.
+ // eslint-disable-next-line @typescript-eslint/unbound-method
+ fn.handleEvent = wrap(fn.handleEvent, {
+ mechanism: {
+ data: {
+ function: 'handleEvent',
+ handler: getFunctionName(fn),
+ target,
+ },
+ handled: true,
+ type: 'instrument',
+ },
+ });
+ }
+ } catch (err) {
+ // can sometimes get 'Permission denied to access property "handle Event'
+ }
+
+ return original.apply(this, [
+ eventName,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ wrap(fn , {
+ mechanism: {
+ data: {
+ function: 'addEventListener',
+ handler: getFunctionName(fn),
+ target,
+ },
+ handled: true,
+ type: 'instrument',
+ },
+ }),
+ options,
+ ]);
+ };
+ });
+
+ fill(
+ proto,
+ 'removeEventListener',
+ function (
+ originalRemoveEventListener,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ) {
+ return function (
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+
+ eventName,
+ fn,
+ options,
+ ) {
+ /**
+ * There are 2 possible scenarios here:
+ *
+ * 1. Someone passes a callback, which was attached prior to Sentry initialization, or by using unmodified
+ * method, eg. `document.addEventListener.call(el, name, handler). In this case, we treat this function
+ * as a pass-through, and call original `removeEventListener` with it.
+ *
+ * 2. Someone passes a callback, which was attached after Sentry was initialized, which means that it was using
+ * our wrapped version of `addEventListener`, which internally calls `wrap` helper.
+ * This helper "wraps" whole callback inside a try/catch statement, and attached appropriate metadata to it,
+ * in order for us to make a distinction between wrapped/non-wrapped functions possible.
+ * If a function was wrapped, it has additional property of `__sentry_wrapped__`, holding the handler.
+ *
+ * When someone adds a handler prior to initialization, and then do it again, but after,
+ * then we have to detach both of them. Otherwise, if we'd detach only wrapped one, it'd be impossible
+ * to get rid of the initial handler and it'd stick there forever.
+ */
+ const wrappedEventHandler = fn ;
+ try {
+ const originalEventHandler = wrappedEventHandler && wrappedEventHandler.__sentry_wrapped__;
+ if (originalEventHandler) {
+ originalRemoveEventListener.call(this, eventName, originalEventHandler, options);
+ }
+ } catch (e) {
+ // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments
+ }
+ return originalRemoveEventListener.call(this, eventName, wrappedEventHandler, options);
+ };
+ },
+ );
+}
+
+export { TryCatch };
+//# sourceMappingURL=trycatch.js.map