Skip to content

Commit cfa5e7b

Browse files
mydeabillyvg
andcommitted
ref(replay): Add jsdoc to all replay modules
This is one more step of #6323. Note that this also renames/moves a few things to make more sense. wip Apply suggestions from code review Co-authored-by: Billy Vong <[email protected]>
1 parent 8291249 commit cfa5e7b

24 files changed

+175
-100
lines changed

docs/event-sending.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ This document gives an outline for how event sending works, and which which plac
7777
## Replay (WIP)
7878

7979
* `replay.sendReplayRequest()`
80-
* `createPayload()`
81-
* `getReplayEvent()`
80+
* `createRecordingData()`
81+
* `prepareReplayEvent()`
8282
* `client._prepareEvent()` (see baseclient)
8383
* `baseclient._applyClientOptions()`
8484
* `baseclient._applyIntegrationsMetadata()`

packages/replay/.eslintrc.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@ module.exports = {
2525
rules: {
2626
// TODO (high-prio): Re-enable this after migration
2727
'@typescript-eslint/explicit-member-accessibility': 'off',
28-
// TODO (high-prio): Re-enable this after migration
28+
// Since we target only es6 here, we can leave this off
2929
'@sentry-internal/sdk/no-async-await': 'off',
30-
// TODO (medium-prio): Re-enable this after migration
31-
'jsdoc/require-jsdoc': 'off',
3230
},
3331
},
3432
{

packages/replay/src/coreHandlers/breadcrumbHandler.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import type { InstrumentationTypeBreadcrumb } from '../types';
44
import { DomHandlerData, handleDom } from './handleDom';
55
import { handleScope } from './handleScope';
66

7+
/**
8+
* An event handler to react to breadcrumbs.
9+
*/
710
export function breadcrumbHandler(type: InstrumentationTypeBreadcrumb, handlerData: unknown): Breadcrumb | null {
811
if (type === 'scope') {
912
return handleScope(handlerData as Scope);

packages/replay/src/coreHandlers/handleDom.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export interface DomHandlerData {
99
event: Node | { target: Node };
1010
}
1111

12+
/**
13+
* An event handler to react to DOM events.
14+
*/
1215
export function handleDom(handlerData: DomHandlerData): Breadcrumb | null {
1316
// Taken from https://github.com/getsentry/sentry-javascript/blob/master/packages/browser/src/integrations/breadcrumbs.ts#L112
1417
let target;

packages/replay/src/coreHandlers/handleFetch.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import type { ReplayPerformanceEntry } from '../createPerformanceEntry';
2-
import type { ReplayContainer } from '../types';
1+
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
32
import { createPerformanceSpans } from '../util/createPerformanceSpans';
43
import { shouldFilterRequest } from '../util/shouldFilterRequest';
54

packages/replay/src/coreHandlers/handleHistory.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { ReplayPerformanceEntry } from '../createPerformanceEntry';
2-
import type { ReplayContainer } from '../types';
1+
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
32
import { createPerformanceSpans } from '../util/createPerformanceSpans';
43

54
interface HistoryHandlerData {

packages/replay/src/coreHandlers/handleScope.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { createBreadcrumb } from '../util/createBreadcrumb';
44

55
let _LAST_BREADCRUMB: null | Breadcrumb = null;
66

7+
/**
8+
* An event handler to handle scope changes.
9+
*/
710
export function handleScope(scope: Scope): Breadcrumb | null {
811
const newBreadcrumb = scope.getLastBreadcrumb();
912

packages/replay/src/coreHandlers/handleXhr.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { ReplayPerformanceEntry } from '../createPerformanceEntry';
2-
import type { ReplayContainer } from '../types';
1+
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
32
import { createPerformanceSpans } from '../util/createPerformanceSpans';
43
import { shouldFilterRequest } from '../util/shouldFilterRequest';
54

packages/replay/src/createPerformanceEntry.ts

Lines changed: 16 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,12 @@ import { browserPerformanceTimeOrigin } from '@sentry/utils';
22
import { record } from 'rrweb';
33

44
import { WINDOW } from './constants';
5-
import type { AllPerformanceEntry, PerformanceNavigationTiming, PerformancePaintTiming } from './types';
6-
7-
export interface ReplayPerformanceEntry {
8-
/**
9-
* One of these types https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry/entryType
10-
*/
11-
type: string;
12-
13-
/**
14-
* A more specific description of the performance entry
15-
*/
16-
name: string;
17-
18-
/**
19-
* The start timestamp in seconds
20-
*/
21-
start: number;
22-
23-
/**
24-
* The end timestamp in seconds
25-
*/
26-
end: number;
27-
28-
/**
29-
* Additional unstructured data to be included
30-
*/
31-
data?: Record<string, unknown>;
32-
}
33-
34-
interface MemoryInfo {
35-
jsHeapSizeLimit: number;
36-
totalJSHeapSize: number;
37-
usedJSHeapSize: number;
38-
}
5+
import type {
6+
AllPerformanceEntry,
7+
PerformanceNavigationTiming,
8+
PerformancePaintTiming,
9+
ReplayPerformanceEntry,
10+
} from './types';
3911

4012
// Map entryType -> function to normalize data for event
4113
// @ts-ignore TODO: entry type does not fit the create* functions entry type
@@ -46,9 +18,12 @@ const ENTRY_TYPES: Record<string, (entry: AllPerformanceEntry) => null | ReplayP
4618
// @ts-ignore TODO: entry type does not fit the create* functions entry type
4719
navigation: createNavigationEntry,
4820
// @ts-ignore TODO: entry type does not fit the create* functions entry type
49-
['largest-contentful-paint']: createLargestContentfulPaint,
21+
'largest-contentful-paint': createLargestContentfulPaint,
5022
};
5123

24+
/**
25+
* Create replay performance entries from the browser performance entries.
26+
*/
5227
export function createPerformanceEntries(entries: AllPerformanceEntry[]): ReplayPerformanceEntry[] {
5328
return entries.map(createPerformanceEntry).filter(Boolean) as ReplayPerformanceEntry[];
5429
}
@@ -67,9 +42,7 @@ function getAbsoluteTime(time: number): number {
6742
return ((browserPerformanceTimeOrigin || WINDOW.performance.timeOrigin) + time) / 1000;
6843
}
6944

70-
// TODO: type definition!
71-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
72-
function createPaintEntry(entry: PerformancePaintTiming) {
45+
function createPaintEntry(entry: PerformancePaintTiming): ReplayPerformanceEntry {
7346
const { duration, entryType, name, startTime } = entry;
7447

7548
const start = getAbsoluteTime(startTime);
@@ -81,9 +54,7 @@ function createPaintEntry(entry: PerformancePaintTiming) {
8154
};
8255
}
8356

84-
// TODO: type definition!
85-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
86-
function createNavigationEntry(entry: PerformanceNavigationTiming) {
57+
function createNavigationEntry(entry: PerformanceNavigationTiming): ReplayPerformanceEntry | null {
8758
// TODO: There looks to be some more interesting bits in here (domComplete, domContentLoaded)
8859
const { entryType, name, duration, domComplete, startTime, transferSize, type } = entry;
8960

@@ -104,9 +75,7 @@ function createNavigationEntry(entry: PerformanceNavigationTiming) {
10475
};
10576
}
10677

107-
// TODO: type definition!
108-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
109-
function createResourceEntry(entry: PerformanceResourceTiming) {
78+
function createResourceEntry(entry: PerformanceResourceTiming): ReplayPerformanceEntry | null {
11079
const { entryType, initiatorType, name, responseEnd, startTime, encodedBodySize, transferSize } = entry;
11180

11281
// Core SDK handles these
@@ -126,9 +95,9 @@ function createResourceEntry(entry: PerformanceResourceTiming) {
12695
};
12796
}
12897

129-
// TODO: type definition!
130-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
131-
function createLargestContentfulPaint(entry: PerformanceEntry & { size: number; element: Node }) {
98+
function createLargestContentfulPaint(
99+
entry: PerformanceEntry & { size: number; element: Node },
100+
): ReplayPerformanceEntry {
132101
const { duration, entryType, startTime, size } = entry;
133102

134103
const start = getAbsoluteTime(startTime);
@@ -147,25 +116,3 @@ function createLargestContentfulPaint(entry: PerformanceEntry & { size: number;
147116
},
148117
};
149118
}
150-
151-
type ReplayMemoryEntry = ReplayPerformanceEntry & { data: { memory: MemoryInfo } };
152-
153-
export function createMemoryEntry(memoryEntry: MemoryInfo): ReplayMemoryEntry {
154-
const { jsHeapSizeLimit, totalJSHeapSize, usedJSHeapSize } = memoryEntry;
155-
// we don't want to use `getAbsoluteTime` because it adds the event time to the
156-
// time origin, so we get the current timestamp instead
157-
const time = new Date().getTime() / 1000;
158-
return {
159-
type: 'memory',
160-
name: 'memory',
161-
start: time,
162-
end: time,
163-
data: {
164-
memory: {
165-
jsHeapSizeLimit,
166-
totalJSHeapSize,
167-
usedJSHeapSize,
168-
},
169-
},
170-
};
171-
}

packages/replay/src/eventBuffer.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ interface CreateEventBufferParams {
1212
useCompression: boolean;
1313
}
1414

15+
/**
16+
* Create an event buffer for replays.
17+
*/
1518
export function createEventBuffer({ useCompression }: CreateEventBufferParams): EventBuffer {
1619
// eslint-disable-next-line no-restricted-globals
1720
if (useCompression && window.Worker) {
@@ -72,7 +75,10 @@ class EventBufferArray implements EventBuffer {
7275
}
7376
}
7477

75-
// exporting for testing
78+
/**
79+
* Event buffer that uses a web worker to compress events.
80+
* Exported only for testing.
81+
*/
7682
export class EventBufferCompressionWorker implements EventBuffer {
7783
private _worker: null | Worker;
7884
private _eventBufferItemLength: number = 0;
@@ -83,19 +89,25 @@ export class EventBufferCompressionWorker implements EventBuffer {
8389
}
8490

8591
/**
86-
* Note that this may not reflect what is actually in the event buffer. This
87-
* is only a local count of the buffer size since `addEvent` is async.
92+
* Destroy the event buffer.
8893
*/
89-
public get length(): number {
90-
return this._eventBufferItemLength;
91-
}
92-
9394
public destroy(): void {
9495
__DEBUG_BUILD__ && logger.log('[Replay] Destroying compression worker');
9596
this._worker?.terminate();
9697
this._worker = null;
9798
}
9899

100+
/**
101+
* Note that this may not reflect what is actually in the event buffer. This
102+
* is only a local count of the buffer size since `addEvent` is async.
103+
*/
104+
public get length(): number {
105+
return this._eventBufferItemLength;
106+
}
107+
108+
/**
109+
* Add an event to the event buffer.
110+
*/
99111
public async addEvent(event: RecordingEvent, isCheckout?: boolean): Promise<ReplayRecordingData> {
100112
if (isCheckout) {
101113
// This event is a checkout, make sure worker buffer is cleared before
@@ -110,6 +122,9 @@ export class EventBufferCompressionWorker implements EventBuffer {
110122
return this._sendEventToWorker(event);
111123
}
112124

125+
/**
126+
* Finish the event buffer and return the compressed data.
127+
*/
113128
public finish(): Promise<Uint8Array> {
114129
return this._finishRequest(this._getAndIncrementId());
115130
}
@@ -160,6 +175,9 @@ export class EventBufferCompressionWorker implements EventBuffer {
160175
});
161176
}
162177

178+
/**
179+
* Send the event to the worker.
180+
*/
163181
private _sendEventToWorker(event: RecordingEvent): Promise<ReplayRecordingData> {
164182
const promise = this._postMessage({
165183
id: this._getAndIncrementId(),
@@ -173,6 +191,9 @@ export class EventBufferCompressionWorker implements EventBuffer {
173191
return promise;
174192
}
175193

194+
/**
195+
* Finish the request and return the compressed data from the worker.
196+
*/
176197
private async _finishRequest(id: number): Promise<Uint8Array> {
177198
const promise = this._postMessage({ id, method: 'finish', args: [] });
178199

@@ -182,6 +203,7 @@ export class EventBufferCompressionWorker implements EventBuffer {
182203
return promise as Promise<Uint8Array>;
183204
}
184205

206+
/** Get the current ID and increment it for the next call. */
185207
private _getAndIncrementId(): number {
186208
return this._id++;
187209
}

packages/replay/src/integration.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ const MEDIA_SELECTORS = 'img,image,svg,path,rect,area,video,object,picture,embed
1818

1919
let _initialized = false;
2020

21+
/**
22+
* The main replay integration class, to be passed to `init({ integrations: [] })`.
23+
*/
2124
export class Replay implements Integration {
2225
/**
2326
* @inheritDoc
@@ -36,6 +39,16 @@ export class Replay implements Integration {
3639

3740
readonly options: ReplayPluginOptions;
3841

42+
/** If replay has already been initialized */
43+
protected get _isInitialized(): boolean {
44+
return _initialized;
45+
}
46+
47+
/** Update _isInitialized */
48+
protected set _isInitialized(value: boolean) {
49+
_initialized = value;
50+
}
51+
3952
private _replay?: ReplayContainer;
4053

4154
constructor({
@@ -181,6 +194,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
181194
this._replay.stop();
182195
}
183196

197+
/** Setup the integration. */
184198
private _setup(): void {
185199
// Client is not available in constructor, so we need to wait until setupOnce
186200
this._loadReplayOptionsFromClient();

packages/replay/src/replay.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ import type {
4141
import { addEvent } from './util/addEvent';
4242
import { addMemoryEntry } from './util/addMemoryEntry';
4343
import { createBreadcrumb } from './util/createBreadcrumb';
44-
import { createPayload } from './util/createPayload';
4544
import { createPerformanceSpans } from './util/createPerformanceSpans';
45+
import { createRecordingData } from './util/createRecordingData';
4646
import { createReplayEnvelope } from './util/createReplayEnvelope';
4747
import { debounce } from './util/debounce';
48-
import { getReplayEvent } from './util/getReplayEvent';
4948
import { isExpired } from './util/isExpired';
5049
import { isSessionExpired } from './util/isSessionExpired';
5150
import { overwriteRecordDroppedEvent, restoreRecordDroppedEvent } from './util/monkeyPatchRecordDroppedEvent';
51+
import { prepareReplayEvent } from './util/prepareReplayEvent';
5252

5353
/**
5454
* Returns true to return control to calling function, otherwise continue with normal batching
@@ -57,6 +57,9 @@ import { overwriteRecordDroppedEvent, restoreRecordDroppedEvent } from './util/m
5757
const BASE_RETRY_INTERVAL = 5000;
5858
const MAX_RETRY_COUNT = 3;
5959

60+
/**
61+
* The main replay container class, which holds all the state and methods for recording and sending replays.
62+
*/
6063
export class ReplayContainer implements ReplayContainerInterface {
6164
public eventBuffer: EventBuffer | null = null;
6265

@@ -905,7 +908,7 @@ export class ReplayContainer implements ReplayContainerInterface {
905908
includeReplayStartTimestamp,
906909
eventContext,
907910
}: SendReplay): Promise<void | TransportMakeRequestResponse> {
908-
const payloadWithSequence = createPayload({
911+
const recordingData = createRecordingData({
909912
events,
910913
headers: {
911914
segment_id,
@@ -938,7 +941,7 @@ export class ReplayContainer implements ReplayContainerInterface {
938941
segment_id,
939942
};
940943

941-
const replayEvent = await getReplayEvent({ scope, client, event: baseEvent });
944+
const replayEvent = await prepareReplayEvent({ scope, client, event: baseEvent });
942945

943946
if (!replayEvent) {
944947
// Taken from baseclient's `_processEvent` method, where this is handled for errors/transactions
@@ -990,7 +993,7 @@ export class ReplayContainer implements ReplayContainerInterface {
990993
}
991994
*/
992995

993-
const envelope = createReplayEnvelope(replayEvent, payloadWithSequence, dsn, client.getOptions().tunnel);
996+
const envelope = createReplayEnvelope(replayEvent, recordingData, dsn, client.getOptions().tunnel);
994997

995998
try {
996999
return await transport.send(envelope);
@@ -999,6 +1002,9 @@ export class ReplayContainer implements ReplayContainerInterface {
9991002
}
10001003
}
10011004

1005+
/**
1006+
* Reset the counter of retries for sending replays.
1007+
*/
10021008
resetRetries(): void {
10031009
this._retryCount = 0;
10041010
this._retryInterval = BASE_RETRY_INTERVAL;

0 commit comments

Comments
 (0)