-
-
Notifications
You must be signed in to change notification settings - Fork 344
/
Copy pathmobilereplay.ts
143 lines (123 loc) · 3.83 KB
/
mobilereplay.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import type { Client, DynamicSamplingContext, Event, Integration } from '@sentry/core';
import { logger } from '@sentry/core';
import { isHardCrash } from '../misc';
import { hasHooks } from '../utils/clientutils';
import { isExpoGo, notMobileOs } from '../utils/environment';
import { NATIVE } from '../wrapper';
import { enrichXhrBreadcrumbsForMobileReplay } from './xhrUtils';
export const MOBILE_REPLAY_INTEGRATION_NAME = 'MobileReplay';
export interface MobileReplayOptions {
/**
* Mask all text in recordings
*
* @default true
*/
maskAllText?: boolean;
/**
* Mask all images in recordings
*
* @default true
*/
maskAllImages?: boolean;
/**
* Mask all vector graphics in recordings
* Supports `react-native-svg`
*
* @default true
*/
maskAllVectors?: boolean;
}
const defaultOptions: Required<MobileReplayOptions> = {
maskAllText: true,
maskAllImages: true,
maskAllVectors: true,
};
type MobileReplayIntegration = Integration & {
options: Required<MobileReplayOptions>;
};
/**
* The Mobile Replay Integration, let's you adjust the default mobile replay options.
* To be passed to `Sentry.init` with `replaysOnErrorSampleRate` or `replaysSessionSampleRate`.
*
* ```javascript
* Sentry.init({
* replaysOnErrorSampleRate: 1.0,
* replaysSessionSampleRate: 1.0,
* integrations: [mobileReplayIntegration({
* // Adjust the default options
* })],
* });
* ```
*
* @experimental
*/
export const mobileReplayIntegration = (initOptions: MobileReplayOptions = defaultOptions): MobileReplayIntegration => {
if (isExpoGo()) {
logger.warn(
`[Sentry] ${MOBILE_REPLAY_INTEGRATION_NAME} is not supported in Expo Go. Use EAS Build or \`expo prebuild\` to enable it.`,
);
}
if (notMobileOs()) {
logger.warn(`[Sentry] ${MOBILE_REPLAY_INTEGRATION_NAME} is not supported on this platform.`);
}
if (isExpoGo() || notMobileOs()) {
return mobileReplayIntegrationNoop();
}
const options = { ...defaultOptions, ...initOptions };
async function processEvent(event: Event): Promise<Event> {
const hasException = event.exception?.values?.length > 0;
if (!hasException) {
// Event is not an error, will not capture replay
return event;
}
const recordingReplayId = NATIVE.getCurrentReplayId();
if (recordingReplayId) {
logger.debug(
`[Sentry] ${MOBILE_REPLAY_INTEGRATION_NAME} assign already recording replay ${recordingReplayId} for event ${event.event_id}.`,
);
return event;
}
const replayId = await NATIVE.captureReplay(isHardCrash(event));
if (!replayId) {
logger.debug(`[Sentry] ${MOBILE_REPLAY_INTEGRATION_NAME} not sampled for event ${event.event_id}.`);
return event;
}
return event;
}
function setup(client: Client): void {
if (!hasHooks(client)) {
return;
}
client.on('createDsc', (dsc: DynamicSamplingContext) => {
if (dsc.replay_id) {
return;
}
// TODO: For better performance, we should emit replayId changes on native, and hold the replayId value in JS
const currentReplayId = NATIVE.getCurrentReplayId();
if (currentReplayId) {
dsc.replay_id = currentReplayId;
}
});
client.on('beforeAddBreadcrumb', enrichXhrBreadcrumbsForMobileReplay);
}
// TODO: When adding manual API, ensure overlap with the web replay so users can use the same API interchangeably
// https://github.com/getsentry/sentry-javascript/blob/develop/packages/replay-internal/src/integration.ts#L45
return {
name: MOBILE_REPLAY_INTEGRATION_NAME,
setupOnce() {
/* Noop */
},
setup,
processEvent,
options: options,
};
};
const mobileReplayIntegrationNoop = (): MobileReplayIntegration => {
return {
name: MOBILE_REPLAY_INTEGRATION_NAME,
setupOnce() {
/* Noop */
},
options: defaultOptions,
};
};