react-user-agent-client-hints
Advanced tools
Comparing version 0.2.1 to 0.2.2
@@ -1,14 +0,4 @@ | ||
import { UADataValues, UALowEntropyJSON } from "../types"; | ||
export declare type Hint = "architecture" | "model" | "bitness" | "platformVersion" | "fullVersionList"; | ||
declare type HighEntropy = "high"; | ||
declare type LowEntropy = "low"; | ||
export declare function useUserAgentData(params: { | ||
entropy: HighEntropy; | ||
hints: Hint[]; | ||
}): UADataValues; | ||
export declare function useUserAgentData(params: { | ||
entropy: LowEntropy; | ||
}): UALowEntropyJSON; | ||
export declare function useUserAgentData(): UALowEntropyJSON; | ||
declare type Hint = "brand" | "model" | "version" | "architecture" | "platform" | "mobile" | "platformVersion" | "uaFullVersion" | "bitness" | "wow64" | "fullVersionList"; | ||
export declare function useUserAgentData(hints: Hint[]): [UADataValues | null, Error | null]; | ||
export {}; | ||
//# sourceMappingURL=useUserAgentData.d.ts.map |
@@ -14,92 +14,37 @@ "use strict"; | ||
const react_1 = require("react"); | ||
const HIGH_ENTROPY = "high"; | ||
const LOW_ENTROPY = "low"; | ||
/** | ||
* Type-safe hook for accessing the current browser and operating system information. | ||
* @param entropy Amount of information this hook reveals about the browser. | ||
* @param hints Collection of strongly typed strings hinting to the returned user-agent data. | ||
* @returns User agent data mapped from the hints argument or an error. | ||
* @throws | ||
*/ | ||
function useUserAgentData(params) { | ||
function useUserAgentData(hints) { | ||
const [userAgentData, setUserAgentData] = (0, react_1.useState)(null); | ||
const [error, setError] = (0, react_1.useState)(null); | ||
const [state, dispatch] = (0, react_1.useReducer)(userAgentReducer, initState); | ||
(0, react_1.useEffect)(() => { | ||
function getUserAgentData() { | ||
function getHighEntropyUAData() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
switch (params === null || params === void 0 ? void 0 : params.entropy) { | ||
case HIGH_ENTROPY: { | ||
if (params.hints === undefined) { | ||
setError(new Error("Cannot have high entropy and no hints.")); | ||
return; | ||
} | ||
const data = yield getHighEntropyUserAgentData(params.hints); | ||
if (data instanceof Error) { | ||
setError(data); | ||
break; | ||
} | ||
dispatch({ type: HIGH_ENTROPY, payload: data }); | ||
break; | ||
try { | ||
// check if the `navigator.userAgentData` object is available | ||
if (navigator.userAgentData === undefined) { | ||
setError(new Error("User-agent client hints API is undefined.")); | ||
return; | ||
} | ||
case LOW_ENTROPY: { | ||
const data = getLowEntropyUserAgentData(); | ||
dispatch({ type: LOW_ENTROPY, payload: data }); | ||
break; | ||
// check if the user has granted permission for the client hints | ||
if (navigator.userAgentData.getHighEntropyValues === undefined) { | ||
setError(new Error("Permission denied accessing user-agent data")); | ||
return; | ||
} | ||
case undefined: { | ||
const data = getLowEntropyUserAgentData(); | ||
dispatch({ type: LOW_ENTROPY, payload: data }); | ||
break; | ||
} | ||
default: { | ||
setError(new Error("An unexpected case has been encountered.")); | ||
break; | ||
} | ||
// request the high entropy values | ||
const agentData = yield navigator.userAgentData.getHighEntropyValues(hints); | ||
setUserAgentData(agentData); | ||
} | ||
catch (err) { | ||
setError(new Error("Failed to get user-agent data")); | ||
} | ||
}); | ||
} | ||
void getUserAgentData(); | ||
}, [params === null || params === void 0 ? void 0 : params.entropy, params === null || params === void 0 ? void 0 : params.hints]); | ||
if (error instanceof Error) | ||
throw error; | ||
return state; | ||
getHighEntropyUAData(); | ||
}, [hints]); | ||
return [userAgentData, error]; | ||
} | ||
exports.useUserAgentData = useUserAgentData; | ||
function getHighEntropyUserAgentData(hints) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const agentData = yield ((_a = navigator.userAgentData) === null || _a === void 0 ? void 0 : _a.getHighEntropyValues(hints)); | ||
if (agentData === undefined) { | ||
return new Error("Could not return user-agent data."); | ||
} | ||
return agentData; | ||
} | ||
catch (err) { | ||
if (!(err instanceof Error)) | ||
throw new Error("An unexpected error has occurred."); | ||
if (err.name === "NotAllowedError") { | ||
return new Error("Permission denied accessing user-agent data."); | ||
} | ||
return err; | ||
} | ||
}); | ||
} | ||
function getLowEntropyUserAgentData() { | ||
if (navigator.userAgentData === undefined) | ||
throw new Error("Client does not have user-agent data."); | ||
return; | ||
return navigator.userAgentData.toJSON(); | ||
} | ||
const initState = {}; | ||
function userAgentReducer(state, action) { | ||
switch (action.type) { | ||
case HIGH_ENTROPY: { | ||
return Object.assign(Object.assign({}, state), action.payload); | ||
} | ||
case LOW_ENTROPY: { | ||
return Object.assign(Object.assign({}, state), action.payload); | ||
} | ||
default: | ||
throw new Error("An unexpected case has been reached."); | ||
} | ||
} |
@@ -1,3 +0,2 @@ | ||
export { useUserAgentClientHints } from "./hooks/useUserAgentClientHints"; | ||
export { UADataValues, UALowEntropyJSON, Hint } from "./types"; | ||
export { useUserAgentData } from "./hooks/useUserAgentData"; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useUserAgentClientHints = void 0; | ||
var useUserAgentClientHints_1 = require("./hooks/useUserAgentClientHints"); | ||
Object.defineProperty(exports, "useUserAgentClientHints", { enumerable: true, get: function () { return useUserAgentClientHints_1.useUserAgentClientHints; } }); | ||
exports.useUserAgentData = void 0; | ||
var useUserAgentData_1 = require("./hooks/useUserAgentData"); | ||
Object.defineProperty(exports, "useUserAgentData", { enumerable: true, get: function () { return useUserAgentData_1.useUserAgentData; } }); |
{ | ||
"name": "react-user-agent-client-hints", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "", | ||
@@ -21,4 +21,5 @@ "main": "./dist/index.js", | ||
"@jest/types": "^28.1.0", | ||
"@playwright/test": "^1.29.2", | ||
"@testing-library/jest-dom": "^5.16.4", | ||
"@testing-library/react": "^13.3.0", | ||
"@testing-library/react": "^13.4.0", | ||
"@types/jest": "^27.5.1", | ||
@@ -25,0 +26,0 @@ "@types/node": "^17.0.34", |
110
README.md
@@ -7,4 +7,67 @@ # React User Agent Client Hints | ||
![workflow](https://github.com/zakarynichols/react-user-agent-client-hints/actions/workflows/ci-cd.yml/badge.svg?branch=develop) | ||
![example workflow](https://github.com/zakarynichols/react-user-agent-client-hints/actions/workflows/ci-cd.yml/badge.svg?branch=develop) | ||
The useUserAgentData hook allows you to fetch high entropy user-agent data from the browser. It returns an object with the user-agent data, or an error if something went wrong. | ||
## Usage | ||
To use the useUserAgentData hook, you must pass an array of hints as an argument. These hints are used to request specific user-agent data. | ||
```tsx | ||
import { useUserAgentData } from "path/to/hook" | ||
function MyComponent() { | ||
const [userAgentData, error] = useUserAgentData(["brand", "version"]) | ||
if (error) { | ||
return <div>{error.message}</div> | ||
} | ||
if (!userAgentData) { | ||
return <div>Loading...</div> | ||
} | ||
return ( | ||
<div> | ||
<p>Brands: {userAgentData.brands.map(brand => brand.brand).join(", ")}</p> | ||
<p>Mobile: {userAgentData.mobile ? "Yes" : "No"}</p> | ||
<p>Architecture: {userAgentData.architecture}</p> | ||
<p>Bitness: {userAgentData.bitness}</p> | ||
<p>Model: {userAgentData.model}</p> | ||
<p>Platform: {userAgentData.platform}</p> | ||
<p>Platform Version: {userAgentData.platformVersion}</p> | ||
<p>UA Full Version: {userAgentData.uaFullVersion}</p> | ||
<p>Wow64: {userAgentData.wow64 ? "Yes" : "No"}</p> | ||
<p> | ||
Full Version List:{" "} | ||
{userAgentData.fullVersionList.map(brand => brand.brand).join(", ")} | ||
</p> | ||
</div> | ||
) | ||
} | ||
``` | ||
```ts | ||
interface UADataValues { | ||
brands: NavigatorUABrandVersion[] | ||
mobile: boolean | ||
architecture: string | ||
bitness: string | ||
model: string | ||
platform: string | ||
platformVersion: string | ||
uaFullVersion: string | ||
wow64: boolean | ||
fullVersionList: NavigatorUABrandVersion[] | ||
} | ||
``` | ||
## Error handling | ||
If there is an error while fetching the user-agent data, useUserAgentData will return an error object with a message. The possible error messages are: | ||
- User-agent client hints API is undefined.: The navigator.userAgentData object is not defined in the browser. | ||
- Permission denied accessing user-agent data: The user has not granted permission for the client hints. | ||
- Failed to get user-agent data: An unexpected error occurred. | ||
### Potential Use Cases | ||
@@ -21,40 +84,13 @@ | ||
### Installation | ||
## Possible Hints | ||
```sh | ||
$ npm install react-user-agent-client-hints | ||
``` | ||
- "brand": The brand of the user agent, such as "Google", "Apple", "Mozilla", etc. | ||
- "model": The model of the device, such as "iPhone", "Pixel", "Galaxy", etc. | ||
- "version": The version of the user agent, such as "13.0", "11.0", "78.0", etc. | ||
- "architecture": The architecture of the device, such as "arm", "x86", "x86_64", etc. | ||
- "platform": The platform the user agent is running on, such as "Windows", "macOS", "iOS", "Android", etc. | ||
- "mobile": A boolean indicating whether the device is a mobile device or not. | ||
- "fullVersionList": A list of objects representing the full version of the user agent and the brand | ||
- "wow64": A boolean indicating whether the user agent is running on a 32-bit version of Windows on a 64-bit system. | ||
### Examples | ||
```ts | ||
import { useUserAgentClientHints, Hint } from "react-user-agent-client-hints" | ||
/** Declare in module scope or use `useMemo` if you need derived state. */ | ||
const hints = [ | ||
"architecture", | ||
"model", | ||
"bitness", | ||
"platformVersion", | ||
"fullVersionList" | ||
] | ||
/* | ||
* High entropy potentially reveals more info about the operating | ||
* system and browser. Under the hood is async allowing time for the | ||
* browser to request user permission, or make other checks. | ||
*/ | ||
const highEntropyUAData = useUserAgentClientHints({ entropy: "high", hints }) | ||
/* | ||
* Low entropy runs sync, but potentially does not reveal enough information | ||
* able to identify a user. | ||
*/ | ||
const lowEntropyUAData = useUserAgentClientHints({ entropy: "low" }) | ||
/* | ||
* Can call without parameters too. | ||
*/ | ||
const UADataNoParams = useUserAgentClientHint() | ||
``` | ||
### References | ||
@@ -61,0 +97,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
98
13922
33
11
140
1