Skip to content

Commit a1d1dac

Browse files
authored
ref(replay): Use WINDOW instead of window (#6316)
1 parent 2972c53 commit a1d1dac

21 files changed

+108
-85
lines changed

packages/replay/.eslintrc.js

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ module.exports = {
3939
rules: {
4040
// TODO (high-prio): Go through console logs and figure out which ones should be replaced with the SDK logger
4141
'no-console': 'off',
42-
// TODO (high-pio): Re-enable this after migration
43-
'no-restricted-globals': 'off',
4442
// TODO (high-prio): Re-enable this after migration
4543
'@typescript-eslint/explicit-member-accessibility': 'off',
4644
// TODO (high-prio): Remove this exception from naming convention after migration

packages/replay/config/rollup.config.core.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const config = defineConfig({
1919
format: 'esm',
2020
},
2121
],
22-
external: [...Object.keys(pkg.dependencies || {})],
22+
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})],
2323
plugins: [
2424
typescript({
2525
tsconfig: IS_PRODUCTION ? './config/tsconfig.core.json' : './tsconfig.json',

packages/replay/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
"lodash.debounce": "^4.0.8",
6161
"rrweb": "^1.1.3"
6262
},
63+
"peerDependencies": {
64+
"@sentry/browser": "7.22.0"
65+
},
6366
"engines": {
6467
"node": ">=12"
6568
},

packages/replay/src/createPerformanceEntry.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { WINDOW } from '@sentry/browser';
12
import { browserPerformanceTimeOrigin } from '@sentry/utils';
23
import { record } from 'rrweb';
34

@@ -60,7 +61,7 @@ function createPerformanceEntry(entry: AllPerformanceEntry): ReplayPerformanceEn
6061
function getAbsoluteTime(time: number): number {
6162
// browserPerformanceTimeOrigin can be undefined if `performance` or
6263
// `performance.now` doesn't exist, but this is already checked by this integration
63-
return ((browserPerformanceTimeOrigin || window.performance.timeOrigin) + time) / 1000;
64+
return ((browserPerformanceTimeOrigin || WINDOW.performance.timeOrigin) + time) / 1000;
6465
}
6566

6667
// TODO: type definition!

packages/replay/src/eventBuffer.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface CreateEventBufferParams {
1212
}
1313

1414
export function createEventBuffer({ useCompression }: CreateEventBufferParams): IEventBuffer {
15+
// eslint-disable-next-line no-restricted-globals
1516
if (useCompression && window.Worker) {
1617
const workerBlob = new Blob([workerString]);
1718
const workerUrl = URL.createObjectURL(workerBlob);

packages/replay/src/index.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable max-lines */ // TODO: We might want to split this file up
2+
import { WINDOW } from '@sentry/browser';
23
import { addGlobalEventProcessor, getCurrentHub, Scope, setContext } from '@sentry/core';
34
import { Breadcrumb, Client, Event, Integration } from '@sentry/types';
45
import { addInstrumentationHandler, createEnvelope, logger } from '@sentry/utils';
@@ -232,7 +233,7 @@ export class Replay implements Integration {
232233
return;
233234
}
234235
// XXX: See method comments above
235-
window.setTimeout(() => this.start());
236+
setTimeout(() => this.start());
236237
}
237238

238239
/**
@@ -396,8 +397,8 @@ export class Replay implements Integration {
396397
* first flush.
397398
*/
398399
setInitialState(): void {
399-
const urlPath = `${window.location.pathname}${window.location.hash}${window.location.search}`;
400-
const url = `${window.location.origin}${urlPath}`;
400+
const urlPath = `${WINDOW.location.pathname}${WINDOW.location.hash}${WINDOW.location.search}`;
401+
const url = `${WINDOW.location.origin}${urlPath}`;
401402

402403
this.performanceEvents = [];
403404

@@ -414,9 +415,9 @@ export class Replay implements Integration {
414415
*/
415416
addListeners(): void {
416417
try {
417-
document.addEventListener('visibilitychange', this.handleVisibilityChange);
418-
window.addEventListener('blur', this.handleWindowBlur);
419-
window.addEventListener('focus', this.handleWindowFocus);
418+
WINDOW.document.addEventListener('visibilitychange', this.handleVisibilityChange);
419+
WINDOW.addEventListener('blur', this.handleWindowBlur);
420+
WINDOW.addEventListener('focus', this.handleWindowFocus);
420421

421422
// There is no way to remove these listeners, so ensure they are only added once
422423
if (!this.hasInitializedCoreListeners) {
@@ -440,7 +441,7 @@ export class Replay implements Integration {
440441
}
441442

442443
// PerformanceObserver //
443-
if (!('PerformanceObserver' in window)) {
444+
if (!('PerformanceObserver' in WINDOW)) {
444445
return;
445446
}
446447

@@ -475,10 +476,10 @@ export class Replay implements Integration {
475476
*/
476477
removeListeners(): void {
477478
try {
478-
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
479+
WINDOW.document.removeEventListener('visibilitychange', this.handleVisibilityChange);
479480

480-
window.removeEventListener('blur', this.handleWindowBlur);
481-
window.removeEventListener('focus', this.handleWindowFocus);
481+
WINDOW.removeEventListener('blur', this.handleWindowBlur);
482+
WINDOW.removeEventListener('focus', this.handleWindowFocus);
482483

483484
if (this.performanceObserver) {
484485
this.performanceObserver.disconnect();
@@ -665,7 +666,7 @@ export class Replay implements Integration {
665666
* page will also trigger a change to a hidden state.
666667
*/
667668
handleVisibilityChange: () => void = () => {
668-
if (document.visibilityState === 'visible') {
669+
if (WINDOW.document.visibilityState === 'visible') {
669670
this.doChangeToForegroundTasks();
670671
} else {
671672
this.doChangeToBackgroundTasks();
@@ -980,13 +981,13 @@ export class Replay implements Integration {
980981
addMemoryEntry(): Promise<void[]> | undefined {
981982
// window.performance.memory is a non-standard API and doesn't work on all browsers
982983
// so we check before creating the event.
983-
if (!('memory' in window.performance)) {
984+
if (!('memory' in WINDOW.performance)) {
984985
return;
985986
}
986987

987988
return this.createPerformanceSpans([
988989
// @ts-ignore memory doesn't exist on type Performance as the API is non-standard (we check that it exists above)
989-
createMemoryEntry(window.performance.memory),
990+
createMemoryEntry(WINDOW.performance.memory),
990991
]);
991992
}
992993

packages/replay/src/session/deleteSession.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1+
import { WINDOW } from '@sentry/browser';
2+
13
import { REPLAY_SESSION_KEY } from './constants';
24

35
/**
46
* Deletes a session from storage
57
*/
68
export function deleteSession(): void {
7-
const hasSessionStorage = 'sessionStorage' in window;
9+
const hasSessionStorage = 'sessionStorage' in WINDOW;
810

911
if (!hasSessionStorage) {
1012
return;
1113
}
1214

1315
try {
14-
window.sessionStorage.removeItem(REPLAY_SESSION_KEY);
16+
WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
1517
} catch {
1618
// Ignore potential SecurityError exceptions
1719
}

packages/replay/src/session/fetchSession.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { WINDOW } from '@sentry/browser';
2+
13
import { SampleRates } from '../types';
24
import { REPLAY_SESSION_KEY } from './constants';
35
import { Session } from './Session';
@@ -6,15 +8,15 @@ import { Session } from './Session';
68
* Fetches a session from storage
79
*/
810
export function fetchSession({ sessionSampleRate, errorSampleRate }: SampleRates): Session | null {
9-
const hasSessionStorage = 'sessionStorage' in window;
11+
const hasSessionStorage = 'sessionStorage' in WINDOW;
1012

1113
if (!hasSessionStorage) {
1214
return null;
1315
}
1416

1517
try {
1618
// This can throw if cookies are disabled
17-
const sessionStringFromStorage = window.sessionStorage.getItem(REPLAY_SESSION_KEY);
19+
const sessionStringFromStorage = WINDOW.sessionStorage.getItem(REPLAY_SESSION_KEY);
1820

1921
if (!sessionStringFromStorage) {
2022
return null;

packages/replay/src/session/saveSession.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
import { WINDOW } from '@sentry/browser';
2+
13
import { REPLAY_SESSION_KEY } from './constants';
24
import { Session } from './Session';
35

46
export function saveSession(session: Session): void {
5-
const hasSessionStorage = 'sessionStorage' in window;
7+
const hasSessionStorage = 'sessionStorage' in WINDOW;
68
if (!hasSessionStorage) {
79
return;
810
}
911

1012
try {
11-
window.sessionStorage.setItem(REPLAY_SESSION_KEY, JSON.stringify(session));
13+
WINDOW.sessionStorage.setItem(REPLAY_SESSION_KEY, JSON.stringify(session));
1214
} catch {
1315
// Ignore potential SecurityError exceptions
1416
}

packages/replay/src/util/isBrowser.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isNodeEnv } from '@sentry/utils';
22

33
export function isBrowser(): boolean {
4+
// eslint-disable-next-line no-restricted-globals
45
return typeof window !== 'undefined' && !isNodeEnv();
56
}
+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { WINDOW } from '@sentry/browser';
2+
13
import { isBrowser } from './isBrowser';
24

35
/**
46
* Returns true if we are currently recording an internal to Sentry replay
57
* (e.g. on https://sentry.io )
68
*/
79
export function isInternal(): boolean {
8-
return isBrowser() && ['sentry.io', 'dev.getsentry.net'].includes(window.location.host);
10+
return isBrowser() && ['sentry.io', 'dev.getsentry.net'].includes(WINDOW.location.host);
911
}

packages/replay/test/unit/flush.test.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { WINDOW } from '@sentry/browser';
12
import * as SentryUtils from '@sentry/utils';
23
import { BASE_TIMESTAMP, mockRrweb, mockSdk } from '@test';
34

@@ -20,7 +21,7 @@ type MockEventBufferFinish = jest.MockedFunction<Exclude<typeof Replay.prototype
2021
type MockFlush = jest.MockedFunction<typeof Replay.prototype.flush>;
2122
type MockRunFlush = jest.MockedFunction<typeof Replay.prototype.runFlush>;
2223

23-
const prevLocation = window.location;
24+
const prevLocation = WINDOW.location;
2425
let domHandler: (args: any) => any;
2526

2627
const { record: mockRecord } = mockRrweb();
@@ -91,9 +92,7 @@ afterEach(async () => {
9192
replay.clearSession();
9293
replay.loadSession({ expiry: SESSION_IDLE_DURATION });
9394
mockRecord.takeFullSnapshot.mockClear();
94-
// @ts-ignore: The operand of a 'delete' operator must be optional.ts(2790)
95-
delete window.location;
96-
Object.defineProperty(window, 'location', {
95+
Object.defineProperty(WINDOW, 'location', {
9796
value: prevLocation,
9897
writable: true,
9998
});
@@ -109,10 +108,10 @@ it('flushes twice after multiple flush() calls)', async () => {
109108
// the following blur events will all call a debounced flush function, which
110109
// should end up queueing a second flush
111110

112-
window.dispatchEvent(new Event('blur'));
113-
window.dispatchEvent(new Event('blur'));
114-
window.dispatchEvent(new Event('blur'));
115-
window.dispatchEvent(new Event('blur'));
111+
WINDOW.dispatchEvent(new Event('blur'));
112+
WINDOW.dispatchEvent(new Event('blur'));
113+
WINDOW.dispatchEvent(new Event('blur'));
114+
WINDOW.dispatchEvent(new Event('blur'));
116115

117116
expect(replay.flush).toHaveBeenCalledTimes(4);
118117

@@ -138,7 +137,7 @@ it('long first flush enqueues following events', async () => {
138137
expect(mockAddPerformanceEntries).not.toHaveBeenCalled();
139138

140139
// flush #1 @ t=0s - due to blur
141-
window.dispatchEvent(new Event('blur'));
140+
WINDOW.dispatchEvent(new Event('blur'));
142141
expect(replay.flush).toHaveBeenCalledTimes(1);
143142
expect(replay.runFlush).toHaveBeenCalledTimes(1);
144143

@@ -152,7 +151,7 @@ it('long first flush enqueues following events', async () => {
152151

153152
await advanceTimers(1000);
154153
// flush #3 @ t=6s - due to blur
155-
window.dispatchEvent(new Event('blur'));
154+
WINDOW.dispatchEvent(new Event('blur'));
156155
expect(replay.flush).toHaveBeenCalledTimes(3);
157156

158157
// NOTE: Blur also adds a breadcrumb which calls `addUpdate`, meaning it will
@@ -161,7 +160,7 @@ it('long first flush enqueues following events', async () => {
161160
expect(replay.flush).toHaveBeenCalledTimes(3);
162161

163162
// flush #4 @ t=14s - due to blur
164-
window.dispatchEvent(new Event('blur'));
163+
WINDOW.dispatchEvent(new Event('blur'));
165164
expect(replay.flush).toHaveBeenCalledTimes(4);
166165

167166
expect(replay.runFlush).toHaveBeenCalledTimes(1);

packages/replay/test/unit/index-errorSampleRate.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
jest.unmock('@sentry/browser');
22

3-
import { captureException } from '@sentry/browser';
3+
import { captureException, WINDOW } from '@sentry/browser';
44
import { BASE_TIMESTAMP, RecordMock } from '@test';
55
import { PerformanceEntryResource } from '@test/fixtures/performanceEntry/resource';
66
import { resetSdkMock } from '@test/mocks';
@@ -317,7 +317,7 @@ describe('Replay (errorSampleRate)', () => {
317317
*/
318318
it('sends a replay after loading the session multiple times', async () => {
319319
// Pretend that a session is already saved before loading replay
320-
window.sessionStorage.setItem(
320+
WINDOW.sessionStorage.setItem(
321321
REPLAY_SESSION_KEY,
322322
`{"segmentId":0,"id":"fd09adfc4117477abc8de643e5a5798a","sampled":"error","started":${BASE_TIMESTAMP},"lastActivity":${BASE_TIMESTAMP}}`,
323323
);

0 commit comments

Comments
 (0)