-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathsupports.ts
167 lines (149 loc) · 4.26 KB
/
supports.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import { DEBUG_BUILD } from './debug-build';
import { logger } from './logger';
import { GLOBAL_OBJ } from './worldwide';
const WINDOW = GLOBAL_OBJ as unknown as Window;
declare const EdgeRuntime: string | undefined;
export { supportsHistory } from './vendor/supportsHistory';
/**
* Tells whether current environment supports ErrorEvent objects
* {@link supportsErrorEvent}.
*
* @returns Answer to the given question.
*/
export function supportsErrorEvent(): boolean {
try {
new ErrorEvent('');
return true;
} catch (e) {
return false;
}
}
/**
* Tells whether current environment supports DOMError objects
* {@link supportsDOMError}.
*
* @returns Answer to the given question.
*/
export function supportsDOMError(): boolean {
try {
// Chrome: VM89:1 Uncaught TypeError: Failed to construct 'DOMError':
// 1 argument required, but only 0 present.
// @ts-expect-error It really needs 1 argument, not 0.
new DOMError('');
return true;
} catch (e) {
return false;
}
}
/**
* Tells whether current environment supports DOMException objects
* {@link supportsDOMException}.
*
* @returns Answer to the given question.
*/
export function supportsDOMException(): boolean {
try {
new DOMException('');
return true;
} catch (e) {
return false;
}
}
/**
* Tells whether current environment supports Fetch API
* {@link supportsFetch}.
*
* @returns Answer to the given question.
*/
export function supportsFetch(): boolean {
if (!('fetch' in WINDOW)) {
return false;
}
try {
new Headers();
new Request('http://www.example.com');
new Response();
return true;
} catch (e) {
return false;
}
}
/**
* isNative checks if the given function is a native implementation
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export function isNativeFunction(func: Function): boolean {
return func && /^function\s+\w+\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString());
}
/**
* Tells whether current environment supports Fetch API natively
* {@link supportsNativeFetch}.
*
* @returns true if `window.fetch` is natively implemented, false otherwise
*/
export function supportsNativeFetch(): boolean {
if (typeof EdgeRuntime === 'string') {
return true;
}
if (!supportsFetch()) {
return false;
}
// Fast path to avoid DOM I/O
// eslint-disable-next-line @typescript-eslint/unbound-method
if (isNativeFunction(WINDOW.fetch)) {
return true;
}
// window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension)
// so create a "pure" iframe to see if that has native fetch
let result = false;
const doc = WINDOW.document;
// eslint-disable-next-line deprecation/deprecation
if (doc && typeof (doc.createElement as unknown) === 'function') {
try {
const sandbox = doc.createElement('iframe');
sandbox.hidden = true;
doc.head.appendChild(sandbox);
if (sandbox.contentWindow && sandbox.contentWindow.fetch) {
// eslint-disable-next-line @typescript-eslint/unbound-method
result = isNativeFunction(sandbox.contentWindow.fetch);
}
doc.head.removeChild(sandbox);
} catch (err) {
DEBUG_BUILD &&
logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err);
}
}
return result;
}
/**
* Tells whether current environment supports ReportingObserver API
* {@link supportsReportingObserver}.
*
* @returns Answer to the given question.
*/
export function supportsReportingObserver(): boolean {
return 'ReportingObserver' in WINDOW;
}
/**
* Tells whether current environment supports Referrer Policy API
* {@link supportsReferrerPolicy}.
*
* @returns Answer to the given question.
*/
export function supportsReferrerPolicy(): boolean {
// Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default'
// (see https://caniuse.com/#feat=referrer-policy),
// it doesn't. And it throws an exception instead of ignoring this parameter...
// REF: https://github.com/getsentry/raven-js/issues/1233
if (!supportsFetch()) {
return false;
}
try {
new Request('_', {
referrerPolicy: 'origin' as ReferrerPolicy,
});
return true;
} catch (e) {
return false;
}
}