Skip to content

Commit b40552c

Browse files
committed
ref(browser): Streamline browser init() checks
1 parent 90cb4d1 commit b40552c

File tree

6 files changed

+76
-68
lines changed

6 files changed

+76
-68
lines changed

dev-packages/browser-integration-tests/suites/manual-client/skip-init-browser-extension/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ sentryTest(
2323
if (hasDebugLogs()) {
2424
expect(errorLogs.length).toEqual(1);
2525
expect(errorLogs[0]).toEqual(
26-
'[Sentry] You cannot run Sentry this way in a browser extension, check: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
26+
'[Sentry] You cannot use Sentry.init() in a browser extension, see: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
2727
);
2828
} else {
2929
expect(errorLogs.length).toEqual(0);

dev-packages/browser-integration-tests/suites/manual-client/skip-init-chrome-extension/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ sentryTest('should not initialize when inside a Chrome browser extension', async
2121
if (hasDebugLogs()) {
2222
expect(errorLogs.length).toEqual(1);
2323
expect(errorLogs[0]).toEqual(
24-
'[Sentry] You cannot run Sentry this way in a browser extension, check: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
24+
'[Sentry] You cannot use Sentry.init() in a browser extension, see: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
2525
);
2626
} else {
2727
expect(errorLogs.length).toEqual(0);

packages/browser/src/sdk.ts

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import {
77
getLocationHref,
88
inboundFiltersIntegration,
99
initAndBind,
10-
logger,
1110
stackParserFromStackParserOptions,
12-
supportsFetch,
1311
} from '@sentry/core';
1412
import type { BrowserClientOptions, BrowserOptions } from './client';
1513
import { BrowserClient } from './client';
@@ -24,6 +22,22 @@ import { linkedErrorsIntegration } from './integrations/linkederrors';
2422
import { defaultStackParser } from './stack-parsers';
2523
import { makeFetchTransport } from './transports/fetch';
2624

25+
type ExtensionProperties = {
26+
chrome?: Runtime;
27+
browser?: Runtime;
28+
nw?: unknown;
29+
};
30+
type Runtime = {
31+
runtime?: {
32+
id?: string;
33+
};
34+
};
35+
36+
/**
37+
* A magic string that build tooling can leverage in order to inject a release value into the SDK.
38+
*/
39+
declare const __SENTRY_RELEASE__: string | undefined;
40+
2741
/** Get the default integrations for the browser SDK. */
2842
export function getDefaultIntegrations(_options: Options): Integration[] {
2943
/**
@@ -79,49 +93,6 @@ function dropTopLevelUndefinedKeys<T extends object>(obj: T): Partial<T> {
7993
return mutatetedObj;
8094
}
8195

82-
type ExtensionProperties = {
83-
chrome?: Runtime;
84-
browser?: Runtime;
85-
nw?: unknown;
86-
};
87-
type Runtime = {
88-
runtime?: {
89-
id?: string;
90-
};
91-
};
92-
93-
function shouldShowBrowserExtensionError(): boolean {
94-
const windowWithMaybeExtension =
95-
typeof WINDOW.window !== 'undefined' && (WINDOW as typeof WINDOW & ExtensionProperties);
96-
if (!windowWithMaybeExtension) {
97-
// No need to show the error if we're not in a browser window environment (e.g. service workers)
98-
return false;
99-
}
100-
101-
const extensionKey = windowWithMaybeExtension.chrome ? 'chrome' : 'browser';
102-
const extensionObject = windowWithMaybeExtension[extensionKey];
103-
104-
const runtimeId = extensionObject?.runtime?.id;
105-
const href = getLocationHref() || '';
106-
107-
const extensionProtocols = ['chrome-extension:', 'moz-extension:', 'ms-browser-extension:', 'safari-web-extension:'];
108-
109-
// Running the SDK in a dedicated extension page and calling Sentry.init is fine; no risk of data leakage
110-
const isDedicatedExtensionPage =
111-
!!runtimeId && WINDOW === WINDOW.top && extensionProtocols.some(protocol => href.startsWith(`${protocol}//`));
112-
113-
// Running the SDK in NW.js, which appears like a browser extension but isn't, is also fine
114-
// see: https://github.com/getsentry/sentry-javascript/issues/12668
115-
const isNWjs = typeof windowWithMaybeExtension.nw !== 'undefined';
116-
117-
return !!runtimeId && !isDedicatedExtensionPage && !isNWjs;
118-
}
119-
120-
/**
121-
* A magic string that build tooling can leverage in order to inject a release value into the SDK.
122-
*/
123-
declare const __SENTRY_RELEASE__: string | undefined;
124-
12596
/**
12697
* The Sentry Browser SDK Client.
12798
*
@@ -169,25 +140,11 @@ declare const __SENTRY_RELEASE__: string | undefined;
169140
* @see {@link BrowserOptions} for documentation on configuration options.
170141
*/
171142
export function init(browserOptions: BrowserOptions = {}): Client | undefined {
172-
const options = applyDefaultOptions(browserOptions);
173-
174-
if (!options.skipBrowserExtensionCheck && shouldShowBrowserExtensionError()) {
175-
if (DEBUG_BUILD) {
176-
consoleSandbox(() => {
177-
// eslint-disable-next-line no-console
178-
console.error(
179-
'[Sentry] You cannot run Sentry this way in a browser extension, check: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
180-
);
181-
});
182-
}
143+
if (!browserOptions.skipBrowserExtensionCheck && _checkForBrowserExtension()) {
183144
return;
184145
}
185146

186-
if (DEBUG_BUILD && !supportsFetch()) {
187-
logger.warn(
188-
'No Fetch API detected. The Sentry SDK requires a Fetch API compatible environment to send events. Please add a Fetch API polyfill.',
189-
);
190-
}
147+
const options = applyDefaultOptions(browserOptions);
191148
const clientOptions: BrowserClientOptions = {
192149
...options,
193150
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
@@ -213,3 +170,48 @@ export function forceLoad(): void {
213170
export function onLoad(callback: () => void): void {
214171
callback();
215172
}
173+
174+
function _isEmbeddedBrowserExtension(): boolean {
175+
if (typeof WINDOW.window === 'undefined') {
176+
// No need to show the error if we're not in a browser window environment (e.g. service workers)
177+
return false;
178+
}
179+
180+
const _window = WINDOW as typeof WINDOW & ExtensionProperties;
181+
182+
// Running the SDK in NW.js, which appears like a browser extension but isn't, is also fine
183+
// see: https://github.com/getsentry/sentry-javascript/issues/12668
184+
if (_window.nw) {
185+
return false;
186+
}
187+
188+
const extensionObject = _window['chrome'] || _window['browser'];
189+
190+
if (!extensionObject?.runtime?.id) {
191+
return false;
192+
}
193+
194+
const href = getLocationHref();
195+
const extensionProtocols = ['chrome-extension', 'moz-extension', 'ms-browser-extension', 'safari-web-extension'];
196+
197+
// Running the SDK in a dedicated extension page and calling Sentry.init is fine; no risk of data leakage
198+
const isDedicatedExtensionPage =
199+
WINDOW === WINDOW.top && extensionProtocols.some(protocol => href.startsWith(`${protocol}://`));
200+
201+
return !isDedicatedExtensionPage;
202+
}
203+
204+
function _checkForBrowserExtension(): true | void {
205+
if (_isEmbeddedBrowserExtension()) {
206+
if (DEBUG_BUILD) {
207+
consoleSandbox(() => {
208+
// eslint-disable-next-line no-console
209+
console.error(
210+
'[Sentry] You cannot use Sentry.init() in a browser extension, see: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
211+
);
212+
});
213+
}
214+
215+
return true;
216+
}
217+
}

packages/browser/test/sdk.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ describe('init', () => {
149149

150150
expect(consoleErrorSpy).toBeCalledTimes(1);
151151
expect(consoleErrorSpy).toHaveBeenCalledWith(
152-
'[Sentry] You cannot run Sentry this way in a browser extension, check: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
152+
'[Sentry] You cannot use Sentry.init() in a browser extension, see: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
153153
);
154154

155155
consoleErrorSpy.mockRestore();
@@ -164,7 +164,7 @@ describe('init', () => {
164164

165165
expect(consoleErrorSpy).toBeCalledTimes(1);
166166
expect(consoleErrorSpy).toHaveBeenCalledWith(
167-
'[Sentry] You cannot run Sentry this way in a browser extension, check: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
167+
'[Sentry] You cannot use Sentry.init() in a browser extension, see: https://docs.sentry.io/platforms/javascript/best-practices/browser-extensions/',
168168
);
169169

170170
consoleErrorSpy.mockRestore();

packages/core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,11 @@ export {
203203
supportsDOMError,
204204
supportsDOMException,
205205
supportsErrorEvent,
206+
// eslint-disable-next-line deprecation/deprecation
206207
supportsFetch,
207208
supportsHistory,
208209
supportsNativeFetch,
210+
// eslint-disable-next-line deprecation/deprecation
209211
supportsReferrerPolicy,
210212
supportsReportingObserver,
211213
} from './utils-hoist/supports';

packages/core/src/utils-hoist/supports.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,11 @@ export function supportsHistory(): boolean {
6969
* {@link supportsFetch}.
7070
*
7171
* @returns Answer to the given question.
72+
* @deprecated This is no longer used and will be removed in a future major version.
7273
*/
73-
export function supportsFetch(): boolean {
74+
export const supportsFetch = _isFetchSupported;
75+
76+
function _isFetchSupported(): boolean {
7477
if (!('fetch' in WINDOW)) {
7578
return false;
7679
}
@@ -104,7 +107,7 @@ export function supportsNativeFetch(): boolean {
104107
return true;
105108
}
106109

107-
if (!supportsFetch()) {
110+
if (!_isFetchSupported()) {
108111
return false;
109112
}
110113

@@ -153,14 +156,15 @@ export function supportsReportingObserver(): boolean {
153156
* {@link supportsReferrerPolicy}.
154157
*
155158
* @returns Answer to the given question.
159+
* @deprecated This is no longer used and will be removed in a future major version.
156160
*/
157161
export function supportsReferrerPolicy(): boolean {
158162
// Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default'
159163
// (see https://caniuse.com/#feat=referrer-policy),
160164
// it doesn't. And it throws an exception instead of ignoring this parameter...
161165
// REF: https://github.com/getsentry/raven-js/issues/1233
162166

163-
if (!supportsFetch()) {
167+
if (!_isFetchSupported()) {
164168
return false;
165169
}
166170

0 commit comments

Comments
 (0)