diff options
| author | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
|---|---|---|
| committer | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
| commit | bce557cc2dc767628bed6aac87301a1be7c5431b (patch) | |
| tree | b51a051228d01fe3306cd7626d4a96768aadb944 /shared/logger/node_modules/@sentry/browser/esm/transports/utils.js | |
init commit
Diffstat (limited to 'shared/logger/node_modules/@sentry/browser/esm/transports/utils.js')
| -rw-r--r-- | shared/logger/node_modules/@sentry/browser/esm/transports/utils.js | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry/browser/esm/transports/utils.js b/shared/logger/node_modules/@sentry/browser/esm/transports/utils.js new file mode 100644 index 0000000..bc50f0c --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/transports/utils.js @@ -0,0 +1,85 @@ +import { isNativeFetch, logger } from '@sentry/utils'; +import { WINDOW } from '../helpers.js'; + +let cachedFetchImpl = undefined; + +/** + * A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers. + * Whenever someone wraps the Fetch API and returns the wrong promise chain, + * this chain becomes orphaned and there is no possible way to capture it's rejections + * other than allowing it bubble up to this very handler. eg. + * + * const f = window.fetch; + * window.fetch = function () { + * const p = f.apply(this, arguments); + * + * p.then(function() { + * console.log('hi.'); + * }); + * + * return p; + * } + * + * `p.then(function () { ... })` is producing a completely separate promise chain, + * however, what's returned is `p` - the result of original `fetch` call. + * + * This mean, that whenever we use the Fetch API to send our own requests, _and_ + * some ad-blocker blocks it, this orphaned chain will _always_ reject, + * effectively causing another event to be captured. + * This makes a whole process become an infinite loop, which we need to somehow + * deal with, and break it in one way or another. + * + * To deal with this issue, we are making sure that we _always_ use the real + * browser Fetch API, instead of relying on what `window.fetch` exposes. + * The only downside to this would be missing our own requests as breadcrumbs, + * but because we are already not doing this, it should be just fine. + * + * Possible failed fetch error messages per-browser: + * + * Chrome: Failed to fetch + * Edge: Failed to Fetch + * Firefox: NetworkError when attempting to fetch resource + * Safari: resource blocked by content blocker + */ +function getNativeFetchImplementation() { + if (cachedFetchImpl) { + return cachedFetchImpl; + } + + /* eslint-disable @typescript-eslint/unbound-method */ + + // Fast path to avoid DOM I/O + if (isNativeFetch(WINDOW.fetch)) { + return (cachedFetchImpl = WINDOW.fetch.bind(WINDOW)); + } + + const document = WINDOW.document; + let fetchImpl = WINDOW.fetch; + // eslint-disable-next-line deprecation/deprecation + if (document && typeof document.createElement === 'function') { + try { + const sandbox = document.createElement('iframe'); + sandbox.hidden = true; + document.head.appendChild(sandbox); + const contentWindow = sandbox.contentWindow; + if (contentWindow && contentWindow.fetch) { + fetchImpl = contentWindow.fetch; + } + document.head.removeChild(sandbox); + } catch (e) { + (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && + logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', e); + } + } + + return (cachedFetchImpl = fetchImpl.bind(WINDOW)); + /* eslint-enable @typescript-eslint/unbound-method */ +} + +/** Clears cached fetch impl */ +function clearCachedFetchImplementation() { + cachedFetchImpl = undefined; +} + +export { clearCachedFetchImplementation, getNativeFetchImplementation }; +//# sourceMappingURL=utils.js.map |
