var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { ClientHints: () => ClientHints }); module.exports = __toCommonJS(src_exports); // src/parse/index.ts function parse(input) { try { if (!input) return void 0; return JSON.parse(input)?.trim(); } catch (error) { return input ?? void 0; } } // src/toNumber/index.ts var NULLABLES = [null, void 0, ""]; function toNumber(input) { if (NULLABLES.includes(input)) { return void 0; } const result = Number(input); if (Number.isNaN(result)) { return void 0; } return result; } // src/uaVendorsList/index.ts var pairs = (array) => array.reduce( (accumulator, value, index, array2) => index % 2 === 0 ? [...accumulator, array2.slice(index, index + 2)] : accumulator, [] ); var extractTokens = (string, tokens) => string.replace( /__TOKEN\[(\d*)]__/g, (input, match) => match ? tokens[match] : input ); function getIndexes(string, substring) { const indexes = []; let index = -1; while (true) { index = string.indexOf(substring, index + 1); if (index === -1) { break; } else { indexes.push(index); } } return indexes; } function getEntries(string) { const tokens = pairs(getIndexes(string, '"')).map(([start, end]) => string.slice(start, end + 1)).map((token, index) => { string = string.replace(token, `__TOKEN[${index}]__`); return token; }); return string.split(",").map((cell) => extractTokens(cell, tokens).trim()); } var uaVendorsList = (string) => getEntries(string).map((entry) => { const tokens = pairs(getIndexes(entry, '"')).map(([start, end]) => entry.substring(start, end + 1)).map((token, index) => { entry = entry.replace(token, `__TOKEN[${index}]__`); return parse(token); }); return Object.fromEntries( entry.split(";").map((cell) => { const parts = cell.split("="); return parts.length > 1 ? [extractTokens(parts[0], tokens), extractTokens(parts[1], tokens)] : ["name", extractTokens(parts[0], tokens)]; }) ); }); // src/index.ts var vendors = [ "Chrome", "Google Chrome", "Microsoft Edge", "Brave", "HeadlessChrome", "YaBrowser" ]; var HEADERS = { BITNESS: "sec-ch-ua-bitness", CONTENT_DPR: "content-dpr", DEVICE_MEMORY: "device-memory", DOWNLINK: "downlink", DPR: "dpr", ECT: "ect", FETCH_DEST: "sec-fetch-dest", FETCH_MODE: "sec-fetch-mode", FETCH_SITE: "sec-fetch-site", FETCH_USER: "sec-fetch-user", GPC: "sec-gpc", MOBILE: "sec-ch-ua-mobile", PREFERS_COLOR_SCHEME: "sec-ch-prefers-color-scheme", PREFERS_REDUCED_MOTION: "sec-ch-prefers-reduced-motion", PREFERS_REDUCED_TRANSPARENCY: "sec-ch-prefers-reduced-transparency", PURPOSE: "sec-purpose", USER_AGENT_ARCH: "sec-ch-ua-arch", USER_AGENT_MODEL: "sec-ch-ua-model", USER_AGENT_PLATFORM_VERSION: "sec-ch-ua-platform-version", USER_AGENT_PLATFORM: "sec-ch-ua-platform", USER_AGENT_VERSION_LIST: "sec-ch-ua-full-version-list", USER_AGENT_VERSION: "sec-ch-ua-full-version", USER_AGENT: "sec-ch-ua", VIEWPORT_WIDTH: "viewport-width", WIDTH: "width" }; var ClientHints = class { entries; constructor(input) { const headers = input instanceof Request ? input.headers : input; const entries = headers instanceof Headers ? Array.from(headers.entries()) : Object.entries(headers); this.entries = entries.map(([key, value]) => [key.toLowerCase(), value]); } #store = /* @__PURE__ */ new Map(); /** * @param name: header name * @returns comma separted list of header values */ #get(name) { const list = this.entries.filter(([key]) => key === name).map(([, value]) => value); return list.length ? list.join(", ") : void 0; } get #uaVendorsList() { if (!this.#store.has("uaVendorsList")) { const header = this.#get(HEADERS.USER_AGENT_VERSION_LIST) || this.#get(HEADERS.USER_AGENT); if (header) { this.#store.set("uaVendorsList", uaVendorsList(header)); } else { this.#store.set("uaVendorsList", []); } } return this.#store.get("uaVendorsList"); } /** * Convert to a JSONable object. Also used in the implementation of JSON.stringify * @example * console.log(new ClientHints(request)) // {"mobile":true,"vendorName":"Chrome","vendorVersion":"91",...} */ toJSON() { return Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter((name) => name !== "constructor").reduce( (acc, name) => this[name] !== "" ? Object.assign(acc, { [name]: this[name] }) : acc, {} ); } /** * The browser is on a mobile device */ get mobile() { const value = this.#get(HEADERS.MOBILE); return value ? value.includes("?1") : void 0; } /** * Browser brand name */ get vendorName() { const names = this.#uaVendorsList.map(({ name }) => name).filter((name) => !/^[\W]*not/i.test(name)); return vendors.find((vendor) => names.includes(vendor)) ?? names.at(0); } /** * Browser version */ get vendorVersion() { const header = this.#get(HEADERS.USER_AGENT_VERSION); if (header) { return parse(header); } const entry = this.#uaVendorsList.find( ({ name }) => name === this.vendorName ); return entry?.v || entry?.version || void 0; } /** * Operating system name */ get platform() { return parse(this.#get(HEADERS.USER_AGENT_PLATFORM)); } /** * Operating system version */ get platformVersion() { return parse(this.#get(HEADERS.USER_AGENT_PLATFORM_VERSION)); } /** * Relationship to origin */ get fetchSite() { return parse(this.#get(HEADERS.FETCH_SITE)); } /** * Navigation type (navigate, nested-navigate, same-origin, cross-origin, ...) */ get fetchMode() { return parse(this.#get(HEADERS.FETCH_MODE)); } /** * Resource type (document, iframe, script, image, ...) */ get fetchDest() { return parse(this.#get(HEADERS.FETCH_DEST)); } /** * Resource type (document, iframe, script, image, ...) */ get fetchDestination() { return parse(this.#get(HEADERS.FETCH_DEST)); } /** * User activation */ get fetchUser() { const value = this.#get(HEADERS.FETCH_USER); return value ? value.includes("?1") : void 0; } /** * CPU architecture (ARM, x86) */ get arch() { return parse(this.#get(HEADERS.USER_AGENT_ARCH)); } /** * CPU architecture (ARM, x86) */ get architecture() { return parse(this.#get(HEADERS.USER_AGENT_ARCH)); } /** * CPU bitness (32, 64) */ get bitness() { return toNumber(parse(this.#get(HEADERS.BITNESS))); } /** * Device model name */ get model() { return parse(this.#get(HEADERS.USER_AGENT_MODEL)); } /** * Device amount of RAM (approximate) */ get deviceMemory() { return toNumber(parse(this.#get(HEADERS.DEVICE_MEMORY))); } /** * [Deprecated] Image density suitable for the screen */ get contentDevicePixelRatio() { return toNumber(parse(this.#get(HEADERS.CONTENT_DPR))); } /** * [Deprecated] Image density suitable for the screen */ get contentDpr() { return toNumber(parse(this.#get(HEADERS.CONTENT_DPR))); } /** * [Deprecated] Screen pixel density */ get devicePixelRatio() { return toNumber(parse(this.#get(HEADERS.DPR))); } /** * [Deprecated] Screen pixel density */ get dpr() { return toNumber(parse(this.#get(HEADERS.DPR))); } /** * Connection type name (slow-2g, 2g, 3g, 4g, ...) */ get effectiveConnectionType() { return parse(this.#get(HEADERS.ECT)); } /** * Connection type name (slow-2g, 2g, 3g, 4g, ...) */ get ect() { return parse(this.#get(HEADERS.ECT)); } /** * Approximate bandwidth of the connection */ get downlink() { return toNumber(parse(this.#get(HEADERS.DOWNLINK))); } /** * [Deprecated] Screen width in pixels */ get width() { return toNumber(parse(this.#get(HEADERS.WIDTH))); } /** * [Deprecated] Viewport width in pixels */ get viewportWidth() { return toNumber(parse(this.#get(HEADERS.VIEWPORT_WIDTH))); } /** * Accesibility; Preferred color scheme (light, dark) */ get prefersColorScheme() { return parse(this.#get(HEADERS.PREFERS_COLOR_SCHEME)); } /** * Accesibility; Preferred reduced motion setting */ get prefersReducedMotion() { switch (this.#get(HEADERS.PREFERS_REDUCED_MOTION)) { case "no-preference": return false; case "reduce": return true; default: return void 0; } } /** * Accesibility; Preferred reduced transparency setting */ get prefersReducedTransparency() { switch (this.#get(HEADERS.PREFERS_REDUCED_TRANSPARENCY)) { case "no-preference": return false; case "reduce": return true; default: return void 0; } } /** * Purpose of the request (prefetch, ...) */ get purpose() { return parse(this.#get(HEADERS.PURPOSE)); } /** * [Non-standard] Global privacy control (GPC) setting */ get gpc() { const value = this.#get(HEADERS.GPC); return value ? value === "1" : void 0; } }; //# sourceMappingURL=index.cjs.map