-
-
Notifications
You must be signed in to change notification settings - Fork 342
/
Copy pathspotlight.ts
109 lines (92 loc) · 3.22 KB
/
spotlight.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
import type { BaseTransportOptions, Client, ClientOptions, Envelope, Integration } from '@sentry/types';
import { logger, serializeEnvelope } from '@sentry/utils';
import { ReactNativeLibraries } from '../utils/rnlibraries';
import { createStealthXhr, XHR_READYSTATE_DONE } from '../utils/xhr';
type SpotlightReactNativeIntegrationOptions = {
/**
* The URL of the Sidecar instance to connect and forward events to.
* If not set, Spotlight will try to connect to the Sidecar running on localhost:8969.
*
* @default "http://localhost:8969/stream"
*/
sidecarUrl?: string;
};
/**
* Use this integration to send errors and transactions to Spotlight.
*
* Learn more about spotlight at https://spotlightjs.com
*/
export function spotlightIntegration({
sidecarUrl = getDefaultSidecarUrl(),
}: SpotlightReactNativeIntegrationOptions = {}): Integration {
logger.info('[Spotlight] Using Sidecar URL', sidecarUrl);
return {
name: 'Spotlight',
setupOnce(): void {
// nothing to do here
},
setup(client: Client<ClientOptions<BaseTransportOptions>>): void {
setup(client, sidecarUrl);
},
};
}
function setup(client: Client, sidecarUrl: string): void {
sendEnvelopesToSidecar(client, sidecarUrl);
}
function sendEnvelopesToSidecar(client: Client, sidecarUrl: string): void {
if (!client.on) {
return;
}
client.on('beforeEnvelope', (originalEnvelope: Envelope) => {
// TODO: This is a workaround for spotlight/sidecar not supporting images
const spotlightEnvelope: Envelope = [...originalEnvelope];
const envelopeItems = [...originalEnvelope[1]].filter(
item => typeof item[0].content_type !== 'string' || !item[0].content_type.startsWith('image'),
);
spotlightEnvelope[1] = envelopeItems as Envelope[1];
const xhr = createStealthXhr();
if (!xhr) {
logger.error('[Spotlight] Sentry SDK can not create XHR object');
return;
}
xhr.open('POST', sidecarUrl, true);
xhr.setRequestHeader('Content-Type', 'application/x-sentry-envelope');
xhr.onreadystatechange = function () {
if (xhr.readyState === XHR_READYSTATE_DONE) {
const status = xhr.status;
if (status === 0 || (status >= 200 && status < 400)) {
// The request has been completed successfully
} else {
// Handle the error
logger.error(
"[Spotlight] Sentry SDK can't connect to Spotlight is it running? See https://spotlightjs.com to download it.",
new Error(xhr.statusText),
);
}
}
};
xhr.send(serializeEnvelope(spotlightEnvelope));
});
}
function getDefaultSidecarUrl(): string {
try {
const { url } = ReactNativeLibraries.Devtools?.getDevServer();
return `http://${getHostnameFromString(url)}:8969/stream`;
} catch (_oO) {
// We can't load devserver URL
}
return 'http://localhost:8969/stream';
}
/**
* React Native implementation of the URL class is missing the `hostname` property.
*/
function getHostnameFromString(urlString: string): string | null {
const regex = /^(?:\w+:)?\/\/([^/:]+)(:\d+)?(.*)$/;
const matches = urlString.match(regex);
if (matches && matches[1]) {
return matches[1];
} else {
// Invalid URL format
return null;
}
}