1 | import { withScope, captureException } from '@sentry/core';
|
2 | import { GLOBAL_OBJ, getOriginalFunction, markFunctionWrapped, addNonEnumerableProperty, addExceptionTypeValue, addExceptionMechanism } from '@sentry/utils';
|
3 |
|
4 | const WINDOW = GLOBAL_OBJ ;
|
5 |
|
6 | let ignoreOnError = 0;
|
7 |
|
8 | /**
|
9 | * @hidden
|
10 | */
|
11 | function shouldIgnoreOnError() {
|
12 | return ignoreOnError > 0;
|
13 | }
|
14 |
|
15 | /**
|
16 | * @hidden
|
17 | */
|
18 | function ignoreNextOnError() {
|
19 | // onerror should trigger before setTimeout
|
20 | ignoreOnError++;
|
21 | setTimeout(() => {
|
22 | ignoreOnError--;
|
23 | });
|
24 | }
|
25 |
|
26 | /**
|
27 | * Instruments the given function and sends an event to Sentry every time the
|
28 | * function throws an exception.
|
29 | *
|
30 | * @param fn A function to wrap. It is generally safe to pass an unbound function, because the returned wrapper always
|
31 | * has a correct `this` context.
|
32 | * @returns The wrapped function.
|
33 | * @hidden
|
34 | */
|
35 | function wrap(
|
36 | fn,
|
37 | options
|
38 |
|
39 | = {},
|
40 | before,
|
41 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
42 | ) {
|
43 | // for future readers what this does is wrap a function and then create
|
44 | // a bi-directional wrapping between them.
|
45 | //
|
46 | // example: wrapped = wrap(original);
|
47 | // original.__sentry_wrapped__ -> wrapped
|
48 | // wrapped.__sentry_original__ -> original
|
49 |
|
50 | if (typeof fn !== 'function') {
|
51 | return fn;
|
52 | }
|
53 |
|
54 | try {
|
55 | // if we're dealing with a function that was previously wrapped, return
|
56 | // the original wrapper.
|
57 | const wrapper = fn.__sentry_wrapped__;
|
58 | if (wrapper) {
|
59 | return wrapper;
|
60 | }
|
61 |
|
62 | // We don't wanna wrap it twice
|
63 | if (getOriginalFunction(fn)) {
|
64 | return fn;
|
65 | }
|
66 | } catch (e) {
|
67 | // Just accessing custom props in some Selenium environments
|
68 | // can cause a "Permission denied" exception (see raven-js#495).
|
69 | // Bail on wrapping and return the function as-is (defers to window.onerror).
|
70 | return fn;
|
71 | }
|
72 |
|
73 | /* eslint-disable prefer-rest-params */
|
74 | // It is important that `sentryWrapped` is not an arrow function to preserve the context of `this`
|
75 | const sentryWrapped = function () {
|
76 | const args = Array.prototype.slice.call(arguments);
|
77 |
|
78 | try {
|
79 | if (before && typeof before === 'function') {
|
80 | before.apply(this, arguments);
|
81 | }
|
82 |
|
83 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
84 | const wrappedArguments = args.map((arg) => wrap(arg, options));
|
85 |
|
86 | // Attempt to invoke user-land function
|
87 | // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
|
88 | // means the sentry.javascript SDK caught an error invoking your application code. This
|
89 | // is expected behavior and NOT indicative of a bug with sentry.javascript.
|
90 | return fn.apply(this, wrappedArguments);
|
91 | } catch (ex) {
|
92 | ignoreNextOnError();
|
93 |
|
94 | withScope((scope) => {
|
95 | scope.addEventProcessor((event) => {
|
96 | if (options.mechanism) {
|
97 | addExceptionTypeValue(event, undefined, undefined);
|
98 | addExceptionMechanism(event, options.mechanism);
|
99 | }
|
100 |
|
101 | event.extra = {
|
102 | ...event.extra,
|
103 | arguments: args,
|
104 | };
|
105 |
|
106 | return event;
|
107 | });
|
108 |
|
109 | captureException(ex);
|
110 | });
|
111 |
|
112 | throw ex;
|
113 | }
|
114 | };
|
115 | /* eslint-enable prefer-rest-params */
|
116 |
|
117 | // Accessing some objects may throw
|
118 | // ref: https://github.com/getsentry/sentry-javascript/issues/1168
|
119 | try {
|
120 | for (const property in fn) {
|
121 | if (Object.prototype.hasOwnProperty.call(fn, property)) {
|
122 | sentryWrapped[property] = fn[property];
|
123 | }
|
124 | }
|
125 | } catch (_oO) {} // eslint-disable-line no-empty
|
126 |
|
127 | // Signal that this function has been wrapped/filled already
|
128 | // for both debugging and to prevent it to being wrapped/filled twice
|
129 | markFunctionWrapped(sentryWrapped, fn);
|
130 |
|
131 | addNonEnumerableProperty(fn, '__sentry_wrapped__', sentryWrapped);
|
132 |
|
133 | // Restore original function name (not all browsers allow that)
|
134 | try {
|
135 | const descriptor = Object.getOwnPropertyDescriptor(sentryWrapped, 'name') ;
|
136 | if (descriptor.configurable) {
|
137 | Object.defineProperty(sentryWrapped, 'name', {
|
138 | get() {
|
139 | return fn.name;
|
140 | },
|
141 | });
|
142 | }
|
143 | // eslint-disable-next-line no-empty
|
144 | } catch (_oO) {}
|
145 |
|
146 | return sentryWrapped;
|
147 | }
|
148 |
|
149 | /**
|
150 | * All properties the report dialog supports
|
151 | */
|
152 |
|
153 | export { WINDOW, ignoreNextOnError, shouldIgnoreOnError, wrap };
|
154 | //# sourceMappingURL=helpers.js.map
|