UNPKG

user-agents

Version:

A JavaScript library for generating random user agents.

1 lines 15.6 kB
{"version":3,"sources":["../src/user-agent.ts","../src/index.ts"],"names":["userAgents","untypedUserAgents","makeCumulativeWeightIndexPairs","weightIndexPairs","totalWeight","sum","weight","index","defaultWeightIndexPairs","defaultCumulativeWeightIndexPairs","constructFilter","filters","accessor","parentObject","childFilters","value","childFilter","key","valueFilter","constructCumulativeWeightIndexPairsFromFilters","filter","rawUserAgent","setCumulativeWeightIndexPairs","userAgent","cumulativeWeightIndexPairs","userAgentInstances","_a","_b","UserAgent","_UserAgent","count","pairs","entries","cumWeight","i","a","b","n","randomNumber","cumulativeWeight","target","proxy","_target","property","descriptor","instance","index_default"],"mappings":"AAAA,iYAAmD,IAE7CA,CAAAA,CAA8BC,wBAAAA,CAgD9BC,CAAAA,CACJC,CAAAA,EAC4B,CAC5B,IAAMC,CAAAA,CAAcD,CAAAA,CAAiB,MAAA,CAAO,CAACE,CAAAA,CAAK,CAACC,CAAM,CAAA,CAAA,EAAMD,CAAAA,CAAMC,CAAAA,CAAQ,CAAC,CAAA,CAC1ED,CAAAA,CAAM,CAAA,CACV,OAAOF,CAAAA,CAAiB,GAAA,CAAI,CAAC,CAACG,CAAAA,CAAQC,CAAK,CAAA,CAAA,EAAA,CACzCF,CAAAA,EAAOC,CAAAA,CAASF,CAAAA,CACT,CAACC,CAAAA,CAAKE,CAAK,CAAA,CACnB,CACH,CAAA,CAGMC,CAAAA,CAAmDR,CAAAA,CAAW,GAAA,CAAI,CAAC,CAAE,MAAA,CAAAM,CAAO,CAAA,CAAGC,CAAAA,CAAAA,EAAU,CAC7FD,CAAAA,CACAC,CACF,CAAC,CAAA,CACKE,CAAAA,CAAoCP,CAAAA,CAA+BM,CAAuB,CAAA,CAG1FE,CAAAA,CAAkB,CACtBC,CAAAA,CACAC,CAAAA,CAAuDC,CAAAA,EAAuBA,CAAAA,CAAAA,EAChD,CAG9B,IAAIC,CAAAA,CACJ,OAAI,OAAOH,CAAAA,EAAY,UAAA,CACrBG,CAAAA,CAAe,CAACH,CAAO,CAAA,CACdA,EAAAA,WAAmB,MAAA,CAC5BG,CAAAA,CAAe,CACZC,CAAAA,EACC,OAAOA,CAAAA,EAAU,QAAA,EAAYA,CAAAA,EAAS,WAAA,GAAeA,CAAAA,EAASA,CAAAA,CAAM,SAAA,CAChEJ,CAAAA,CAAQ,IAAA,CAAKI,CAAAA,CAAM,SAAS,CAAA,CAC5BJ,CAAAA,CAAQ,IAAA,CAAKI,CAAe,CACpC,CAAA,CACSJ,EAAAA,WAAmB,KAAA,CAC5BG,CAAAA,CAAeH,CAAAA,CAAQ,GAAA,CAAKK,CAAAA,EAAgBN,CAAAA,CAAgBM,CAAW,CAAC,CAAA,CAC/D,OAAOL,CAAAA,EAAY,QAAA,CAC5BG,CAAAA,CAAe,MAAA,CAAO,OAAA,CAAQH,CAAO,CAAA,CAAE,GAAA,CAAI,CAAC,CAACM,CAAAA,CAAKC,CAAW,CAAA,CAAA,EAC3DR,CAAAA,CACEQ,CAAAA,CACCL,CAAAA,EACEA,CAAAA,CAAgEI,CAAG,CACxE,CACF,CAAA,CAEAH,CAAAA,CAAe,CACZC,CAAAA,EACC,OAAOA,CAAAA,EAAU,QAAA,EAAYA,CAAAA,EAAS,WAAA,GAAeA,CAAAA,EAASA,CAAAA,CAAM,SAAA,CAChEJ,CAAAA,GAAYI,CAAAA,CAAM,SAAA,CAClBJ,CAAAA,GAAYI,CACpB,CAAA,CAGMF,CAAAA,EAAoB,CAC1B,GAAI,CACF,IAAME,CAAAA,CAAQH,CAAAA,CAASC,CAAY,CAAA,CACnC,OAAOC,CAAAA,CAAa,KAAA,CAAOE,CAAAA,EAAgBA,CAAAA,CAAYD,CAAU,CAAC,CACpE,CAAA,UAAQ,CAEN,MAAO,CAAA,CACT,CACF,CACF,CAAA,CAGMI,CAAAA,CACJR,CAAAA,EAC4B,CAC5B,EAAA,CAAI,CAACA,CAAAA,CACH,OAAOF,CAAAA,CAGT,IAAMW,CAAAA,CAASV,CAAAA,CAAgBC,CAAO,CAAA,CAEhCR,CAAAA,CAA4C,CAAC,CAAA,CACnD,OAAAH,CAAAA,CAAW,OAAA,CAAQ,CAACqB,CAAAA,CAAcd,CAAAA,CAAAA,EAAU,CACtCa,CAAAA,CAAOC,CAAY,CAAA,EACrBlB,CAAAA,CAAiB,IAAA,CAAK,CAACkB,CAAAA,CAAa,MAAA,CAAQd,CAAK,CAAC,CAEtD,CAAC,CAAA,CACML,CAAAA,CAA+BC,CAAgB,CACxD,CAAA,CAEMmB,CAAAA,CAAgC,CACpCC,CAAAA,CACAC,CAAAA,CAAAA,EACG,CACH,MAAA,CAAO,cAAA,CAAeD,CAAAA,CAAW,4BAAA,CAA8B,CAC7D,YAAA,CAAc,CAAA,CAAA,CACd,UAAA,CAAY,CAAA,CAAA,CACZ,QAAA,CAAU,CAAA,CAAA,CACV,KAAA,CAAOC,CACT,CAAC,CACH,CAAA,CAGMC,CAAAA,CAAqB,IAAI,OAAA,CAnJ/BC,CAAAA,CAAAC,CAAAA,CAqJaC,CAAAA,CAAN,MAAMC,CAAU,CAwBrB,WAAA,CAAYlB,CAAAA,CAAkB,CA2C9B,IAAA,CAACe,CAAAA,CAAAA,CAAsB,CAAA,CAAA,EAAc,IAAA,CAAK,IAAA,CAAK,SAAA,CAE/C,IAAA,CAAA,QAAA,CAAW,CAAA,CAAA,EAAc,IAAA,CAAK,IAAA,CAAK,SAAA,CAEnC,IAAA,CAAA,MAAA,CAAS,CAAA,CAAA,EAAiB,CACxB,IAAMH,CAAAA,CAAY,IAAIM,CAAAA,CACtB,OAAAP,CAAAA,CAA8BC,CAAAA,CAAW,IAAA,CAAK,0BAA0B,CAAA,CACxEA,CAAAA,CAAU,SAAA,CAAU,CAAA,CACbA,CACT,CAAA,CAEA,IAAA,CAAA,GAAA,CAAOO,CAAAA,EAAoC,CAEzC,IAAMC,CAAAA,CAAQ,IAAA,CAAK,0BAAA,CACbC,CAAAA,CAAUD,CAAAA,CAAM,GAAA,CAAI,CAAC,CAACE,CAAAA,CAAW1B,CAAK,CAAA,CAAG2B,CAAAA,CAAAA,EAAAA,CAAO,CACpD,MAAA,CAAQA,CAAAA,CAAI,CAAA,CAAID,CAAAA,CAAYF,CAAAA,CAAMG,CAAAA,CAAI,CAAC,CAAA,CAAE,CAAC,CAAA,CAAID,CAAAA,CAC9C,KAAA,CAAA1B,CACF,CAAA,CAAE,CAAA,CACFyB,CAAAA,CAAQ,IAAA,CAAK,CAACG,CAAAA,CAAGC,CAAAA,CAAAA,EAAMA,CAAAA,CAAE,MAAA,CAASD,CAAAA,CAAE,MAAM,CAAA,CAC1C,IAAME,CAAAA,CAAIP,CAAAA,EAAS,IAAA,CAAO,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAOE,CAAAA,CAAQ,MAAM,CAAA,CAAIA,CAAAA,CAAQ,MAAA,CACpE,OAAOA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAGK,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAE,KAAA,CAAA9B,CAAM,CAAA,CAAA,EAAM,eAAA,CAAgBP,CAAAA,CAAWO,CAAK,CAAC,CAAC,CAClF,CAAA,CAEA,IAAA,CAAA,SAAA,CAAY,CAAA,CAAA,EAAY,CAEtB,IAAM+B,CAAAA,CAAe,IAAA,CAAK,MAAA,CAAO,CAAA,CAC3B,CAAC,CAAE/B,CAAK,CAAA,kBACZ,IAAA,CAAK,0BAAA,CAA2B,IAAA,CAC9B,CAAC,CAACgC,CAAgB,CAAA,CAAA,EAAMA,CAAAA,CAAmBD,CAC7C,CAAA,SAAK,CAAC,GAAA,CACR,EAAA,CAAI/B,CAAAA,EAAS,IAAA,CACX,MAAM,IAAI,KAAA,CAAM,oCAAoC,CAAA,CAGrD,IAAA,CAAiC,IAAA,CAAO,eAAA,CAAgBP,CAAAA,CAAWO,CAAK,CAAC,CAC5E,CAAA,CA5EE,EAAA,CADAe,CAAAA,CAA8B,IAAA,CAAMH,CAAAA,CAA+CR,CAAO,CAAC,CAAA,CACvF,IAAA,CAAK,0BAAA,CAA2B,MAAA,GAAW,CAAA,CAC7C,MAAM,IAAI,KAAA,CAAM,sCAAsC,CAAA,CAGxD,IAAA,CAAK,SAAA,CAAU,CAAA,CAKf,IAAM6B,CAAAA,CAAS,CAAA,CAAA,EAAM,CAAC,CAAA,CAChBC,CAAAA,CAAQ,IAAI,KAAA,CAAMD,CAAAA,CAA2B,CACjD,KAAA,CAAO,CAAA,CAAA,EAAM,IAAA,CAAK,MAAA,CAAO,CAAA,CACzB,GAAA,CAAK,CAACE,CAAAA,CAASC,CAAAA,CAAAA,EAAa,CAC1B,EAAA,CACE,IAAA,CAAK,IAAA,EACL,OAAOA,CAAAA,EAAa,QAAA,EACpB,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,IAAA,CAAK,IAAA,CAAMA,CAAQ,CAAA,EACxD,MAAA,CAAO,SAAA,CAAU,oBAAA,CAAqB,IAAA,CAAK,IAAA,CAAK,IAAA,CAAMA,CAAQ,CAAA,CAC9D,CACA,IAAM5B,CAAAA,CAAQ,IAAA,CAAK,IAAA,CAAK4B,CAA+B,CAAA,CACvD,EAAA,CAAI5B,CAAAA,GAAU,KAAA,CAAA,CACZ,OAAOA,CAEX,CAEA,OAAO,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAM4B,CAAQ,CACnC,CAAA,CACA,GAAA,CAAK,CAACD,CAAAA,CAASC,CAAAA,CAAU5B,CAAAA,CAAAA,EAAU,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAM4B,CAAAA,CAAU5B,CAAK,CAAA,CACpE,cAAA,CAAgB,CAAC2B,CAAAA,CAASC,CAAAA,CAAUC,CAAAA,CAAAA,EAClC,OAAA,CAAQ,cAAA,CAAe,IAAA,CAAMD,CAAAA,CAAUC,CAAU,CAAA,CACnD,wBAAA,CAA0B,CAACF,CAAAA,CAASC,CAAAA,CAAAA,EAClC,OAAA,CAAQ,wBAAA,CAAyB,IAAA,CAAMA,CAAQ,CAAA,CACjD,GAAA,CAAK,CAACD,CAAAA,CAASC,CAAAA,CAAAA,EAAa,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAMA,CAAQ,CAAA,CACtD,cAAA,CAAgB,CAACD,CAAAA,CAASC,CAAAA,CAAAA,EAAa,OAAA,CAAQ,cAAA,CAAe,IAAA,CAAMA,CAAQ,CAAA,CAC5E,OAAA,CAAS,CAAA,CAAA,EAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA,CACnC,cAAA,CAAgB,CAAA,CAAA,EAAMd,CAAAA,CAAU,SAClC,CAAC,CAAA,CACD,OAAAJ,CAAAA,CAAmB,GAAA,CAAIgB,CAAK,CAAA,CACrBA,CACT,CAhEA,MAAA,CAAA,CAAQd,CAAAA,CAAA,MAAA,CAAO,WAAA,CAkEdD,CAAAA,CAAA,MAAA,CAAO,WAAA,CAlEAC,CAAAA,CAAkB,CAAA,CAAEkB,CAAAA,CAA4B,CACtD,OAAOA,EAAAA,WAAoB,MAAA,EAAUpB,CAAAA,CAAmB,GAAA,CAAIoB,CAAkB,CAChF,CAEA,MAAA,CAAA,IAAA,CAAO,MAAA,CAAUlC,CAAAA,EAAoB,CACnC,GAAI,CACF,OAAO,IAAIkB,CAAAA,CAAUlB,CAAO,CAC9B,CAAA,UAAQ,CACN,OAAO,IACT,CACF,CAAA,CAGA,MAAA,CAAA,IAAA,CAAO,GAAA,CAAM,CAACmB,CAAAA,CAAgBnB,CAAAA,CAAAA,EAAsC,CAClE,GAAI,CACF,OAAO,IAAIkB,CAAAA,CAAUlB,CAAO,CAAA,CAAE,GAAA,CAAImB,CAAK,CACzC,CAAA,UAAQ,CACN,MAAO,CAAC,CACV,CACF,CAAA,CAmFF,CAAA,CC1PA,IAAOgB,CAAAA,CAAQlB,CAAAA,CAAAA,oBAAAA","file":"/home/circleci/user-agents/dist/index.cjs","sourcesContent":["import untypedUserAgents from './user-agents.json' with { type: 'json' };\n\nconst userAgents: UserAgentData[] = untypedUserAgents as UserAgentData[];\n\ntype NestedValueOf<T> = T extends object ? T[keyof T] | NestedValueOf<T[keyof T]> : T;\n\nexport type Filter<T extends UserAgentData | NestedValueOf<UserAgentData> = UserAgentData> =\n | ((parentObject: T) => boolean)\n | RegExp\n | Array<Filter<T>>\n | { [key: string]: Filter<T> }\n | string;\n\nexport interface UserAgentData {\n appName: 'Netscape';\n connection: {\n downlink: number;\n effectiveType: '3g' | '4g';\n rtt: number;\n downlinkMax?: number | null;\n type?: 'cellular' | 'wifi';\n };\n language?: string | null;\n oscpu?: string | null;\n platform:\n | 'iPad'\n | 'iPhone'\n | 'Linux aarch64'\n | 'Linux armv81'\n | 'Linux armv8l'\n | 'Linux x86_64'\n | 'MacIntel'\n | 'Win32';\n pluginsLength: number;\n screenHeight: number;\n screenWidth: number;\n userAgent: string;\n vendor: 'Apple Computer, Inc.' | 'Google Inc.' | '';\n weight: number;\n}\n\ndeclare module './user-agent' {\n export interface UserAgent extends Readonly<UserAgentData> {\n readonly cumulativeWeightIndexPairs: Array<[number, number]>;\n readonly data: UserAgentData;\n (): UserAgent;\n }\n}\n\n// Normalizes the total weight to 1 and constructs a cumulative distribution.\nconst makeCumulativeWeightIndexPairs = (\n weightIndexPairs: Array<[number, number]>,\n): Array<[number, number]> => {\n const totalWeight = weightIndexPairs.reduce((sum, [weight]) => sum + weight, 0);\n let sum = 0;\n return weightIndexPairs.map(([weight, index]) => {\n sum += weight / totalWeight;\n return [sum, index];\n });\n};\n\n// Precompute these so that we can quickly generate unfiltered user agents.\nconst defaultWeightIndexPairs: Array<[number, number]> = userAgents.map(({ weight }, index) => [\n weight,\n index,\n]);\nconst defaultCumulativeWeightIndexPairs = makeCumulativeWeightIndexPairs(defaultWeightIndexPairs);\n\n// Turn the various filter formats into a single filter function that acts on raw user agents.\nconst constructFilter = <T extends UserAgentData | NestedValueOf<UserAgentData>>(\n filters: Filter<T>,\n accessor: (parentObject: T) => T | NestedValueOf<T> = (parentObject: T): T => parentObject,\n): ((profile: T) => boolean) => {\n // WARNING: This type and a lot of the types in here are wrong, but I can't get TypeScript to\n // resolve things correctly so this will have to do for now.\n let childFilters: Array<(parentObject: T) => boolean>;\n if (typeof filters === 'function') {\n childFilters = [filters];\n } else if (filters instanceof RegExp) {\n childFilters = [\n (value: T | NestedValueOf<T>) =>\n typeof value === 'object' && value && 'userAgent' in value && value.userAgent\n ? filters.test(value.userAgent)\n : filters.test(value as string),\n ];\n } else if (filters instanceof Array) {\n childFilters = filters.map((childFilter) => constructFilter(childFilter));\n } else if (typeof filters === 'object') {\n childFilters = Object.entries(filters).map(([key, valueFilter]) =>\n constructFilter(\n valueFilter as Filter<T>,\n (parentObject: T): T | NestedValueOf<T> =>\n (parentObject as unknown as { [key: string]: NestedValueOf<T> })[key] as NestedValueOf<T>,\n ),\n );\n } else {\n childFilters = [\n (value: T | NestedValueOf<T>) =>\n typeof value === 'object' && value && 'userAgent' in value && value.userAgent\n ? filters === value.userAgent\n : filters === value,\n ];\n }\n\n return (parentObject: T) => {\n try {\n const value = accessor(parentObject);\n return childFilters.every((childFilter) => childFilter(value as T));\n } catch {\n // This happens when a user-agent lacks a nested property.\n return false;\n }\n };\n};\n\n// Construct normalized cumulative weight index pairs given the filters.\nconst constructCumulativeWeightIndexPairsFromFilters = (\n filters?: Filter<UserAgentData>,\n): Array<[number, number]> => {\n if (!filters) {\n return defaultCumulativeWeightIndexPairs;\n }\n\n const filter = constructFilter(filters);\n\n const weightIndexPairs: Array<[number, number]> = [];\n userAgents.forEach((rawUserAgent, index) => {\n if (filter(rawUserAgent)) {\n weightIndexPairs.push([rawUserAgent.weight, index]);\n }\n });\n return makeCumulativeWeightIndexPairs(weightIndexPairs);\n};\n\nconst setCumulativeWeightIndexPairs = (\n userAgent: UserAgent,\n cumulativeWeightIndexPairs: Array<[number, number]>,\n) => {\n Object.defineProperty(userAgent, 'cumulativeWeightIndexPairs', {\n configurable: true,\n enumerable: false,\n writable: false,\n value: cumulativeWeightIndexPairs,\n });\n};\n\n// WeakSet tracking all UserAgent instances for `instanceof` support through proxies.\nconst userAgentInstances = new WeakSet<object>();\n\nexport class UserAgent {\n static [Symbol.hasInstance](instance: unknown): boolean {\n return instance instanceof Object && userAgentInstances.has(instance as object);\n }\n\n static random = (filters: Filter) => {\n try {\n return new UserAgent(filters);\n } catch {\n return null;\n }\n };\n\n // Static version that creates a temporary instance with the given filters and returns the top entries.\n static top = (count?: number, filters?: Filter): UserAgentData[] => {\n try {\n return new UserAgent(filters).top(count);\n } catch {\n return [];\n }\n };\n\n readonly data!: UserAgentData;\n\n constructor(filters?: Filter) {\n setCumulativeWeightIndexPairs(this, constructCumulativeWeightIndexPairsFromFilters(filters));\n if (this.cumulativeWeightIndexPairs.length === 0) {\n throw new Error('No user agents matched your filters.');\n }\n\n this.randomize();\n\n // Use a plain function as the proxy target so the `apply` trap works without\n // extending `Function`, which requires `eval` and violates CSP in browser extensions.\n // All property access is forwarded to the real UserAgent instance via the traps.\n const target = () => {};\n const proxy = new Proxy(target as unknown as this, {\n apply: () => this.random(),\n get: (_target, property) => {\n if (\n this.data &&\n typeof property === 'string' &&\n Object.prototype.hasOwnProperty.call(this.data, property) &&\n Object.prototype.propertyIsEnumerable.call(this.data, property)\n ) {\n const value = this.data[property as keyof UserAgentData];\n if (value !== undefined) {\n return value;\n }\n }\n\n return Reflect.get(this, property);\n },\n set: (_target, property, value) => Reflect.set(this, property, value),\n defineProperty: (_target, property, descriptor) =>\n Reflect.defineProperty(this, property, descriptor),\n getOwnPropertyDescriptor: (_target, property) =>\n Reflect.getOwnPropertyDescriptor(this, property),\n has: (_target, property) => Reflect.has(this, property),\n deleteProperty: (_target, property) => Reflect.deleteProperty(this, property),\n ownKeys: () => Reflect.ownKeys(this),\n getPrototypeOf: () => UserAgent.prototype,\n });\n userAgentInstances.add(proxy);\n return proxy;\n }\n\n [Symbol.toPrimitive] = (): string => this.data.userAgent;\n\n toString = (): string => this.data.userAgent;\n\n random = (): UserAgent => {\n const userAgent = new UserAgent();\n setCumulativeWeightIndexPairs(userAgent, this.cumulativeWeightIndexPairs);\n userAgent.randomize();\n return userAgent;\n };\n\n top = (count?: number): UserAgentData[] => {\n // Recover individual weights from the cumulative distribution and sort by descending weight.\n const pairs = this.cumulativeWeightIndexPairs;\n const entries = pairs.map(([cumWeight, index], i) => ({\n weight: i > 0 ? cumWeight - pairs[i - 1][0] : cumWeight,\n index,\n }));\n entries.sort((a, b) => b.weight - a.weight);\n const n = count != null ? Math.min(count, entries.length) : entries.length;\n return entries.slice(0, n).map(({ index }) => structuredClone(userAgents[index]));\n };\n\n randomize = (): void => {\n // Find a random raw random user agent.\n const randomNumber = Math.random();\n const [, index] =\n this.cumulativeWeightIndexPairs.find(\n ([cumulativeWeight]) => cumulativeWeight > randomNumber,\n ) ?? [];\n if (index == null) {\n throw new Error('Error finding a random user agent.');\n }\n\n (this as { data: UserAgentData }).data = structuredClone(userAgents[index]);\n };\n}\n","import { Filter, UserAgent, UserAgentData } from './user-agent';\n\nexport default UserAgent;\nexport type { Filter, UserAgentData };\n"]}