(
fn: T | NonFunction,
options: {
mechanism?: Mechanism;
} = {},
)
| 58 | * @hidden |
| 59 | */ |
| 60 | export function wrap<T extends WrappableFunction, NonFunction>( |
| 61 | fn: T | NonFunction, |
| 62 | options: { |
| 63 | mechanism?: Mechanism; |
| 64 | } = {}, |
| 65 | ): NonFunction | WrappedFunction<T> { |
| 66 | // for future readers what this does is wrap a function and then create |
| 67 | // a bi-directional wrapping between them. |
| 68 | // |
| 69 | // example: wrapped = wrap(original); |
| 70 | // original.__sentry_wrapped__ -> wrapped |
| 71 | // wrapped.__sentry_original__ -> original |
| 72 | |
| 73 | function isFunction(fn: T | NonFunction): fn is T { |
| 74 | return typeof fn === 'function'; |
| 75 | } |
| 76 | |
| 77 | if (!isFunction(fn)) { |
| 78 | return fn; |
| 79 | } |
| 80 | |
| 81 | try { |
| 82 | // If we're dealing with a function that was previously wrapped, return the original wrapper. |
| 83 | // Check via hasOwnProperty so a `__sentry_wrapped__` inherited from a wrapped `Function.prototype` |
| 84 | // is not mistaken for a real wrapper. |
| 85 | const hasOwnWrapper = Object.prototype.hasOwnProperty.call(fn, '__sentry_wrapped__'); |
| 86 | if (hasOwnWrapper) { |
| 87 | const wrapper = (fn as WrappedFunction<T>).__sentry_wrapped__; |
| 88 | if (typeof wrapper === 'function') { |
| 89 | return wrapper; |
| 90 | } else { |
| 91 | // If we find that the `__sentry_wrapped__` function is not a function at the time of accessing it, it means |
| 92 | // that something messed with it. In that case we want to return the originally passed function. |
| 93 | return fn; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | // We don't wanna wrap it twice |
| 98 | if (getOriginalFunction(fn)) { |
| 99 | return fn; |
| 100 | } |
| 101 | } catch { |
| 102 | // Just accessing custom props in some Selenium environments |
| 103 | // can cause a "Permission denied" exception (see raven-js#495). |
| 104 | // Bail on wrapping and return the function as-is (defers to window.onerror). |
| 105 | return fn; |
| 106 | } |
| 107 | |
| 108 | // Wrap the function itself |
| 109 | // It is important that `sentryWrapped` is not an arrow function to preserve the context of `this` |
| 110 | const sentryWrapped = function (this: unknown, ...args: unknown[]): unknown { |
| 111 | // Track depth on GLOBAL_OBJ so the thirdPartyErrorFilterIntegration (in @sentry/core) can detect |
| 112 | // that processEvent is running inside a sentryWrapped call, even with minified/bundled code. |
| 113 | GLOBAL_OBJ._sentryWrappedDepth = (GLOBAL_OBJ._sentryWrappedDepth || 0) + 1; |
| 114 | try { |
| 115 | // Also wrap arguments that are themselves functions |
| 116 | const wrappedArguments = args.map(arg => wrap(arg, options)); |
| 117 |
no test coverage detected