-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Expand file tree
/
Copy pathuseDetectOS.ts
More file actions
89 lines (77 loc) · 2.68 KB
/
useDetectOS.ts
File metadata and controls
89 lines (77 loc) · 2.68 KB
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
'use client';
import { useEffect, useState } from 'react';
import type {
Architecture,
Bitness,
OperatingSystem,
} from '#site/types/userAgent';
import { getHighEntropyValues, detectOS } from '#site/util/userAgent';
type UserOSState = {
os: OperatingSystem | 'LOADING';
bitness: Bitness | '';
architecture: Architecture | '';
};
// taken from https://github.com/faisalman/ua-parser-js/issues/732#issue-2348848266
function isAppleSilicon() {
try {
// Best guess if the device uses Apple Silicon: https://stackoverflow.com/a/65412357
const webglContext = document.createElement('canvas').getContext('webgl');
if (webglContext == null) {
return false;
}
const debugInfo = webglContext.getExtension('WEBGL_debug_renderer_info');
const renderer =
(debugInfo &&
webglContext.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)) ||
'';
if (renderer.match(/Apple/) && !renderer.match(/Apple GPU/)) {
return true;
}
if (
webglContext
.getSupportedExtensions()
?.includes('WEBGL_compressed_texture_s3tc_srgb')
) {
return true;
}
} catch {
/**/
}
return false;
}
const useDetectOS = () => {
const [userOSState, setUserOSState] = useState<UserOSState>({
os: 'LOADING',
bitness: '',
architecture: '',
});
useEffect(() => {
// If the navigator User Agent indicates a 64-bit OS, we can assume the bitness is 64.
const uaIndicates64 = /WOW64|Win64|x86_64|x86-64|x64_64|x64;|AMD64/.test(
navigator.userAgent
);
// We immediately set the OS to LOADING, and then we update it with the detected OS.
// This is due to that initial render set within the state will indicate a mismatch from
// the server-side rendering versus what the initial state is from the client-side
setUserOSState(current => ({ ...current, os: detectOS() }));
// We attempt to get the high entropy values from the Browser and set the User OS State
// based from the values we get from the Browser, if it fails we fallback to the User Agent
// to determine the bitness and architecture of the User OS.
getHighEntropyValues(['bitness', 'architecture']).then(
({
// If there is no getHighEntropyValues API on the Browser or it failed to resolve
// we attempt to fallback to what the User Agent indicates
bitness = uaIndicates64 ? '64' : '32',
architecture = isAppleSilicon() ? 'arm' : 'x86',
}) => {
setUserOSState(current => ({
...current,
bitness: bitness as Bitness,
architecture: architecture as Architecture,
}));
}
);
}, []);
return userOSState;
};
export default useDetectOS;