diff --git a/packages/browser-utils/src/getNativeImplementation.ts b/packages/browser-utils/src/getNativeImplementation.ts index 410d2abf4de0..70a0baa11e59 100644 --- a/packages/browser-utils/src/getNativeImplementation.ts +++ b/packages/browser-utils/src/getNativeImplementation.ts @@ -1,5 +1,4 @@ -import { debug, isNativeFunction } from '@sentry/core'; -import { DEBUG_BUILD } from './debug-build'; +import { getNativeImplementationFromIframe, isNativeFunction } from '@sentry/core'; import { WINDOW } from './types'; /** @@ -39,31 +38,14 @@ export function getNativeImplementation(name: T) { + let impl = undefined; + const document = WINDOW.document; + // 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?.[name]) { + impl = contentWindow[name] as CacheableImplementations[T]; + } + document.head.removeChild(sandbox); + } catch (e) { + // Could not create sandbox iframe, just use window.xxx + DEBUG_BUILD && debug.warn(`Could not create sandbox iframe for ${name} check, bailing to window.${name}: `, e); + } + } + return impl; +} diff --git a/packages/core/src/utils/is.ts b/packages/core/src/utils/is.ts index 4c8589934800..eb0bbe628cbf 100644 --- a/packages/core/src/utils/is.ts +++ b/packages/core/src/utils/is.ts @@ -214,3 +214,11 @@ export function isVueViewModel(wat: unknown): wat is VueViewModel | VNode { export function isRequest(request: unknown): request is Request { return typeof Request !== 'undefined' && isInstanceOf(request, Request); } + +/** + * isNative checks if the given function is a native implementation + */ +// eslint-disable-next-line @typescript-eslint/ban-types +export function isNativeFunction(func: Function): boolean { + return func && /^function\s+\w+\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString()); +} diff --git a/packages/core/src/utils/supports.ts b/packages/core/src/utils/supports.ts index 7ac3b4789765..ceb752b4a7fa 100644 --- a/packages/core/src/utils/supports.ts +++ b/packages/core/src/utils/supports.ts @@ -1,5 +1,5 @@ -import { DEBUG_BUILD } from '../debug-build'; -import { debug } from './debug-logger'; +import { getNativeImplementationFromIframe } from './getNativeImplementationFromIframe'; +import { isNativeFunction } from './is'; import { GLOBAL_OBJ } from './worldwide'; const WINDOW = GLOBAL_OBJ as unknown as Window; @@ -89,14 +89,6 @@ function _isFetchSupported(): boolean { } } -/** - * isNative checks if the given function is a native implementation - */ -// eslint-disable-next-line @typescript-eslint/ban-types -export function isNativeFunction(func: Function): boolean { - return func && /^function\s+\w+\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString()); -} - /** * Tells whether current environment supports Fetch API natively * {@link supportsNativeFetch}. @@ -118,27 +110,9 @@ export function supportsNativeFetch(): boolean { return true; } - // window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension) - // so create a "pure" iframe to see if that has native fetch - let result = false; - const doc = WINDOW.document; - // eslint-disable-next-line deprecation/deprecation - if (doc && typeof (doc.createElement as unknown) === 'function') { - try { - const sandbox = doc.createElement('iframe'); - sandbox.hidden = true; - doc.head.appendChild(sandbox); - if (sandbox.contentWindow?.fetch) { - // eslint-disable-next-line @typescript-eslint/unbound-method - result = isNativeFunction(sandbox.contentWindow.fetch); - } - doc.head.removeChild(sandbox); - } catch (err) { - DEBUG_BUILD && debug.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err); - } - } + const nativeImpl = getNativeImplementationFromIframe('fetch'); - return result; + return nativeImpl ? isNativeFunction(nativeImpl) : false; } /**