import type {Crumb} from 'sentry/types/breadcrumbs'; import type {Event, EventTransaction} from 'sentry/types/event'; import { breadcrumbFactory, replayTimestamps, rrwebEventListFactory, spansFactory, } from 'sentry/utils/replays/replayDataUtils'; import type { MemorySpanType, RecordingEvent, ReplayCrumb, ReplayError, ReplaySpan, } from 'sentry/views/replays/types'; interface ReplayReaderParams { breadcrumbs: ReplayCrumb[] | undefined; errors: ReplayError[] | undefined; /** * The root Replay event, created at the start of the browser session. */ event: Event | undefined; /** * The captured data from rrweb. * Saved as N attachments that belong to the root Replay event. */ rrwebEvents: RecordingEvent[] | undefined; spans: ReplaySpan[] | undefined; } type RequiredNotNull = { [P in keyof T]: NonNullable; }; export default class ReplayReader { static factory({breadcrumbs, event, errors, rrwebEvents, spans}: ReplayReaderParams) { if (!breadcrumbs || !event || !rrwebEvents || !spans || !errors) { return null; } return new ReplayReader({breadcrumbs, event, errors, rrwebEvents, spans}); } private constructor({ breadcrumbs, event, errors, rrwebEvents, spans, }: RequiredNotNull) { const {startTimestampMS, endTimestampMS} = replayTimestamps( rrwebEvents, breadcrumbs, spans ); this.spans = spansFactory(spans); this.breadcrumbs = breadcrumbFactory( startTimestampMS, event, errors, breadcrumbs, this.spans ); this.rrwebEvents = rrwebEventListFactory( startTimestampMS, endTimestampMS, rrwebEvents ); this.event = { ...event, startTimestamp: startTimestampMS / 1000, endTimestamp: endTimestampMS / 1000, } as EventTransaction; } private event: EventTransaction; private rrwebEvents: RecordingEvent[]; private breadcrumbs: Crumb[]; private spans: ReplaySpan[]; getEvent = () => { return this.event; }; getRRWebEvents = () => { return this.rrwebEvents; }; getRawCrumbs = () => { return this.breadcrumbs; }; getRawSpans = () => { return this.spans; }; isMemorySpan = (span: ReplaySpan): span is MemorySpanType => { return span.op === 'memory'; }; isNotMemorySpan = (span: ReplaySpan) => { return !this.isMemorySpan(span); }; }