Skip to content

Commit

Permalink
🕵️‍♂️ Parse client hints headers easily
Browse files Browse the repository at this point in the history
  • Loading branch information
yoavweiss authored and omrilotan committed Oct 9, 2023
1 parent 877ae32 commit 67e55b8
Show file tree
Hide file tree
Showing 27 changed files with 559 additions and 566 deletions.
3 changes: 0 additions & 3 deletions .babelrc

This file was deleted.

8 changes: 0 additions & 8 deletions .eslintrc

This file was deleted.

50 changes: 34 additions & 16 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,38 @@ jobs:
strategy:
matrix:
node-version:
- '17.6'
- "20"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '17.6'
- run: node --version
- run: npm i
- run: npm t
- run: npm run lint
- run: npm run build
- run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
if: github.ref == 'refs/heads/main'
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: npx @lets/publish
if: github.ref == 'refs/heads/main'
- uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v3
with:
node-version: "20"
- run: node --version
- run: npm i
- run: npm t
- run: npm run format
- name: commit auto fixes
env:
USERNAME: ${{ github.actor }}
BRANCH: ${{ github.ref_name }}
REPO: ${{ github.repository }}
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "$(git diff --quiet && echo 0 || echo $?)" -gt 0 ]; then
git config --global user.email "${USERNAME}@users.noreply.github.com" --replace-all
git config --global user.name "$USERNAME" --replace-all
git commit -am "😎 Autofix"
git remote set-url origin https://${TOKEN}@github.com/$REPO.git
git push origin $BRANCH
exit 1
fi
- run: npm run build
- name: Publish package to NPM
if: github.ref == 'refs/heads/main'
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
npx @lets/publish
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
node_modules
*.cjs
*.mjs
*.d.ts

/index.*
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.*
src
scripts
jest.config.cjs
tsconfig.json

2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
17.6
20
2 changes: 2 additions & 0 deletions .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
plugins:
- "@trivago/prettier-plugin-sort-imports"
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Change Log

## 1.0.0

Stable release: No breaking changes
72 changes: 39 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,57 @@
# client-hints
# client-hints [![](https://img.shields.io/npm/v/client-hints.svg?style=flat-square)](https://www.npmjs.com/package/client-hints)

🕵️‍♂️ Parse client hints headers

Use client hints, where available

```js
import { ClientHints } from 'client-hints'
import { userAgentParser } from 'some-user-agent-parser-library'
import { ClientHints } from "client-hints";
import { userAgentParser } from "some-user-agent-parser-library";

app.get('/api-endpoint', (req, res) => {
const hints = new ClientHints(req.headers)
app.get("/api-endpoint", (req, res) => {
const hints = new ClientHints(req.headers);

const isMobile = hints.mobile ?? (userAgentParser(req.get('user-agent')).device?.type === 'mobile')
// ↑ cheap ↑ more expensive
const isMobile =
hints.mobile ?? // cheap
userAgentParser(req.get("user-agent")).device?.type === "mobile"; // more expensive

res.send( isMobile ? 'Mobile page' : 'Desktop page' )
})
res.send(isMobile ? "Mobile page" : "Desktop page");
});
```
# Available detections
## Available detections
All detections return `undefined` if the relevant header is not available.
| Feature | Type | Header | Meaning | Adoption level
| - | - | - | - | -
| `vendorName` | _string_ | Sec-CH-UA / Sec-CH-UA-Full-Version-List | User Agent vendor version list | Experimental
| `vendorVersion` | _string_ | Sec-CH-UA-Full-Version | User agent vendor version | Experimental
| `mobile` | _boolean_ | Sec-CH-UA-Mobile | Boolean: Is this a mobile device | Experimental
| `platform` | _string_ | Sec-CH-UA-Platform | Operating system name | Experimental
| `platformVersion` | _string_ | Sec-CH-UA-Platform-Version | Operating system version | Experimental
| `arch` | _string_ | Sec-CH-UA-Arch | CPU architecture | Experimental
| `model` | _string_ | Sec-CH-UA-Model | Device model | Experimental
| `fetchMode` | _string_ | Sec-Fetch-Mode | Navigation type |
| `fetchDest`, `fetchDestination` | _string_ | Sec-Fetch-Dest | Resource type |
| `fetchUser` | _boolean_ | Sec-Fetch-User | Was the request triggered by user action |
| `fetchSite` | _string_ | Sec-Fetch-Site | Relationship to origin |
| `dpr`, `devicePixelRatio` | _string_ | Content-DPR | Image device to pixel ratio | Experimental
| `deviceMemory` | _number_ | Device-Memory | Appr. available RAM | Experimental
| `dpr`, `devicePixelRatio` | _number_ | DPR | Device pixel ratio | Deprecated
| `contentDpr`, `contentDevicePixelRatio` | _number_ | Content-DPR | Image device pixel ratio | Deprecated
| `ect`, `effectiveConnectionType` | _string_ | ECT | Network profile (G) | Experimental
| `downlink` | _number_ | Downlink | Network speed (Mbps) | Experimental
| `viewportWidth` | _number_ | Viewport-Width | Layout viewport width | Deprecated
| `width` | _number_ | Width | Resource desired width | Deprecated
| Feature | Type | Header | Meaning | Adoption level |
| --------------------------------------- | --------- | --------------------------------------- | ---------------------------------------- | -------------- |
| `arch`, `architecture` | _string_ | Sec-CH-UA-Arch | CPU architecture | Experimental |
| `contentDpr`, `contentDevicePixelRatio` | _number_ | Content-DPR | Image device pixel ratio | Deprecated |
| `deviceMemory` | _number_ | Device-Memory | Appr. available RAM | Experimental |
| `downlink` | _number_ | Downlink | Network speed (Mbps) | Experimental |
| `dpr`, `devicePixelRatio` | _number_ | DPR | Device pixel ratio | Deprecated |
| `dpr`, `devicePixelRatio` | _string_ | Content-DPR | Image device to pixel ratio | Experimental |
| `ect`, `effectiveConnectionType` | _string_ | ECT | Network profile (G) | Experimental |
| `fetchDest`, `fetchDestination` | _string_ | Sec-Fetch-Dest | Resource type |
| `fetchMode` | _string_ | Sec-Fetch-Mode | Navigation type |
| `fetchSite` | _string_ | Sec-Fetch-Site | Relationship to origin |
| `fetchUser` | _boolean_ | Sec-Fetch-User | Was the request triggered by user action |
| `mobile` | _boolean_ | Sec-CH-UA-Mobile | Boolean: Is this a mobile device | Experimental |
| `model` | _string_ | Sec-CH-UA-Model | Device model | Experimental |
| `platform` | _string_ | Sec-CH-UA-Platform | Operating system name | Experimental |
| `platformVersion` | _string_ | Sec-CH-UA-Platform-Version | Operating system version | Experimental |
| `purpose` | _string_ | Sec-Purpose | Resource purpose (prefetch) | Experimental |
| `vendorName` | _string_ | Sec-CH-UA / Sec-CH-UA-Full-Version-List | User Agent vendor version list | Experimental |
| `vendorVersion` | _string_ | Sec-CH-UA-Full-Version | User agent vendor version | Experimental |
| `viewportWidth` | _number_ | Viewport-Width | Layout viewport width | Deprecated |
| `width` | _number_ | Width | Resource desired width | Deprecated |
## Client Hints Intruction Response Header
Set the value of `Accept-CH` header to include the headers you want the browse to send.
Example:
```
Accept-CH: Sec-CH-UA-Mobile,Sec-CH-UA-Full-Version,Sec-CH-UA-Full-Version-List,Sec-CH-UA-Model,Sec-CH-UA-Platform,Sec-CH-UA-Platform-Version,ECT
```plaintext
Accept-CH: *
```
4 changes: 4 additions & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: "ts-jest",
};
20 changes: 11 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "client-hints",
"version": "0.2.2",
"version": "1.0.0",
"description": "🕵️‍♂️ Parse client hints headers",
"keywords": [
"client-hints",
Expand Down Expand Up @@ -29,16 +29,18 @@
"scripts": {
"prepublishOnly": "npm run build",
"build": "scripts/build.sh",
"test": "node --experimental-fetch ./node_modules/mocha/bin/mocha src --recursive",
"lint": "eslint src/** --plugin log"
"test": "jest",
"format": "prettier --write .",
"lint": "prettier --check ."
},
"devDependencies": {
"@babel/eslint-parser": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"esbuild": "^0.14.25",
"eslint": "^7.18.0",
"eslint-plugin-log": "^1.2.7",
"mocha": "^9.2.1",
"typescript": "^4.6.2"
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@types/jest": "^29.5.5",
"esbuild": "^0.19.4",
"jest": "^29.7.0",
"prettier": "^3.0.3",
"ts-jest": "^29.1.1",
"typescript": "^5.2.2"
}
}
19 changes: 16 additions & 3 deletions scripts/build.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
#!/usr/bin/env bash

esbuild src/index.js --outfile=index.cjs --format=cjs --bundle --target=node16
esbuild src/index.js --outfile=index.mjs --format=esm --bundle --target=node16
tsc src/index.js --declaration --allowJs --emitDeclarationOnly --outDir .
failures=0

esbuild src/index.ts --outfile=index.cjs --format=cjs --bundle --sourcemap
failures=$((failures + $?))

esbuild src/index.ts --outfile=index.mjs --format=esm --bundle --sourcemap
failures=$((failures + $?))

tsc src/index.ts --declaration --emitDeclarationOnly --declarationMap --outDir types --target esnext --moduleResolution node
failures=$((failures + $?))

mv types/index.d.ts .
mv types/index.d.ts.map .
rm -rf types

exit $failures
Loading

0 comments on commit 67e55b8

Please sign in to comment.