user-agents 2.0.0-alpha.99 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,13 +17,13 @@
17
17
  alt="NPM Version"></a>
18
18
  <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
19
19
  <a target="_blank" href="https://twitter.com/home?status=User%20Agents%20is%20a%20JavaScript%20module%20for%20generating%20random%20user%20agents%20that's%20updated%20daily%20with%20new%20market%20share%20data.%0A%0Ahttps%3A//github.com/intoli/user-agents">
20
- <img height="26px" src="https://simplesharebuttons.com/images/somacro/twitter.png"
20
+ <img height="26px" src="media/twitter.png"
21
21
  alt="Tweet"></a>
22
22
  <a target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/intoli/user-agents">
23
- <img height="26px" src="https://simplesharebuttons.com/images/somacro/facebook.png"
23
+ <img height="26px" src="media/facebook.png"
24
24
  alt="Share on Facebook"></a>
25
25
  <a target="_blank" href="http://reddit.com/submit?url=https%3A%2F%2Fgithub.com%2Fintoli%2Fuser-agents&title=User%20Agents%20-%20Random%20user%20agent%20generation%20with%20daily-updated%20market%20share%20data">
26
- <img height="26px" src="https://simplesharebuttons.com/images/somacro/reddit.png"
26
+ <img height="26px" src="media/reddit.png"
27
27
  alt="Share on Reddit"></a>
28
28
  <a target="_blank" href="https://news.ycombinator.com/submitlink?u=https://github.com/intoli/user-agents&t=User%20Agents%20-%20Random%20user%20agent%20generation%20with%20daily-updated%20market%20share%20data">
29
29
  <img height="26px" src="media/ycombinator.png"
@@ -194,6 +194,30 @@ const userAgent = new UserAgent([
194
194
  This example also shows that you can specify both multiple and nested properties on object filters.
195
195
 
196
196
 
197
+ ### Filtering for Modern Browsers
198
+
199
+ If you want to restrict the generated user agents to only modern browsers, you can combine User-Agents with the [browserslist](https://www.npmjs.com/package/browserslist) and [browserslist-useragent](https://www.npmjs.com/package/browserslist-useragent) packages.
200
+ The `browserslist` package lets you define what "modern" means using flexible queries like `"last 2 versions and not dead"`, and `browserslist-useragent` handles matching user agent strings against those queries.
201
+
202
+ ```javascript
203
+ import browserslist from 'browserslist';
204
+ import { matchesUA } from 'browserslist-useragent';
205
+ import UserAgent from 'user-agents';
206
+
207
+ const browsers = browserslist('last 2 versions and not dead');
208
+
209
+ function isModernBrowser(data) {
210
+ return matchesUA(data.userAgent, { browsers, allowHigherVersions: true });
211
+ }
212
+
213
+ const userAgent = new UserAgent(isModernBrowser);
214
+ ```
215
+
216
+ The `allowHigherVersions` option ensures that browser versions newer than those in the browserslist database are still accepted.
217
+ Keep in mind that the User-Agents data is already updated daily from real-world traffic, so the generated user agents are naturally skewed toward modern browsers even without explicit filtering.
218
+ You can find the full list of supported browserslist queries in the [browserslist documentation](https://github.com/browserslist/browserslist#full-list).
219
+
220
+
197
221
  ## API
198
222
 
199
223
  ### class: UserAgent([filters])
@@ -212,24 +236,39 @@ Other properties can be accessed as outlined below.
212
236
  - returns: <`UserAgent`>
213
237
 
214
238
  This method generates a new `UserAgent` instance using the same filters that were used to construct `userAgent`.
215
- The following examples both generate two user agents based on the same filters.
216
-
217
- ```javascript
218
- // Explicitly use the constructor twice.
219
- const firstUserAgent = new UserAgent(filters);
220
- const secondUserAgent = new UserAgent(filters);
221
- ```
239
+ You can also call `UserAgent.random(filters)` as a static method, which is equivalent to `new UserAgent(filters)` but returns `null` instead of throwing if the filters match no user agents.
222
240
 
223
241
  ```javascript
224
- // Use the `random()` method to construct a second user agent.
242
+ // Use the instance method to reuse filter processing.
225
243
  const firstUserAgent = new UserAgent(filters);
226
244
  const secondUserAgent = firstUserAgent.random();
245
+
246
+ // Or use the static method directly.
247
+ const otherUserAgent = UserAgent.random(filters);
227
248
  ```
228
249
 
229
- The reason to prefer the second pattern is that it reuses the filter processing and preparation of the data for random selection.
250
+ The reason to prefer the instance method is that it reuses the filter processing and preparation of the data for random selection.
230
251
  Subsequent random generations can easily be over 100x faster than the initial construction.
231
252
 
232
253
 
254
+ #### userAgent.top()
255
+
256
+ - `count` <`Number`> - The number of top entries to return. If omitted, all matching entries are returned.
257
+ - returns: <`UserAgentData[]`>
258
+
259
+ Returns the most common user agents from the filtered dataset, ordered by descending frequency.
260
+ Like `random()`, this is available both as an instance method and as a static method.
261
+
262
+ ```javascript
263
+ // Use the instance method with pre-configured filters.
264
+ const mobileAgents = new UserAgent({ deviceCategory: 'mobile' });
265
+ const topMobile = mobileAgents.top(5);
266
+
267
+ // Or use the static method directly.
268
+ const topDesktop = UserAgent.top(5, { deviceCategory: 'desktop' });
269
+ ```
270
+
271
+
233
272
  #### userAgent()
234
273
 
235
274
  - returns: <`UserAgent`>
@@ -272,14 +311,30 @@ Note that each property of `data` is also accessible directly on `userAgent`.
272
311
  For example, `userAgent.appName` is equivalent to `userAgent.data.appName`.
273
312
 
274
313
 
314
+ ## Data
315
+
316
+ The dataset is built from a snapshot of the last 24 hours of real-world browser traffic, and a new version of the package is published daily with a fully refreshed dataset.
317
+ This means that the data is not accumulated over time; older browser versions are naturally phased out as they disappear from the traffic, and each release reflects a current view of the browser landscape.
318
+
319
+ User agents are not selected with uniform probability.
320
+ Each profile in the dataset is weighted according to its real-world usage frequency, so commonly seen browsers like Chrome on Windows will appear far more often than niche configurations.
321
+ The result is a random distribution that closely mirrors actual web traffic.
322
+
323
+
275
324
  ## Versioning
276
325
 
277
326
  The project follows [the Semantic Versioning guidelines](https://semver.org/).
278
327
  The automated deployments will always correspond to patch versions, and minor versions should not introduce breaking changes.
279
- It's likely that the structure of user agent data will change in the future, and this will correspond to a new major version.
280
328
 
281
- Please keep in mind that older major versions will cease to be updated after a new major version is released.
282
- You can continue to use older versions of the software, but you'll need to upgrade to get access to the latest data.
329
+ The current `latest` release on npm is v1, which is built with JavaScript and Webpack and outputs a UMD bundle.
330
+ The upcoming v2 release is available under the `next` tag (`npm install user-agents@next`) and includes several improvements:
331
+
332
+ - Rewritten in TypeScript with exported type definitions for `UserAgentData` and `Filter`.
333
+ - Built with tsup, producing native ESM and CJS entry points instead of a UMD bundle.
334
+ - Removed the `Function` class inheritance, which resolves Content Security Policy errors in browser extensions and other restricted environments.
335
+
336
+ The v1 line is deprecated and will stop receiving daily data updates once v2 is promoted to `latest`.
337
+ Both versions receive the same daily data and share an identical API surface, so upgrading should be straightforward.
283
338
 
284
339
 
285
340
  ## Acknowledgements
package/dist/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _lodashclonedeep = require('lodash.clonedeep'); var _lodashclonedeep2 = _interopRequireDefault(_lodashclonedeep);var _useragentsjson = require('./user-agents.json'); var _useragentsjson2 = _interopRequireDefault(_useragentsjson);var o=_useragentsjson2.default,d=t=>{let a=t.reduce((e,[n])=>e+n,0),r=0;return t.map(([e,n])=>(r+=e/a,[r,n]))},f=o.map(({weight:t},a)=>[t,a]),p=d(f),u=(t,a=r=>r)=>{let r;return typeof t=="function"?r=[t]:t instanceof RegExp?r=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?t.test(e.userAgent):t.test(e)]:t instanceof Array?r=t.map(e=>u(e)):typeof t=="object"?r=Object.entries(t).map(([e,n])=>u(n,s=>s[e])):r=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?t===e.userAgent:t===e],e=>{try{let n=a(e);return r.every(s=>s(n))}catch (e2){return!1}}},A=t=>{if(!t)return p;let a=u(t),r=[];return o.forEach((e,n)=>{a(e)&&r.push([e.weight,n])}),d(r)},c=(t,a)=>{Object.defineProperty(t,"cumulativeWeightIndexPairs",{configurable:!0,enumerable:!1,writable:!1,value:a})},b,i=class t extends Function{constructor(r){super();this[b]=()=>this.data.userAgent;this.toString=()=>this.data.userAgent;this.random=()=>{let r=new t;return c(r,this.cumulativeWeightIndexPairs),r.randomize(),r};this.randomize=()=>{let r=Math.random(),[,e]=_nullishCoalesce(this.cumulativeWeightIndexPairs.find(([s])=>s>r), () => ([]));if(e==null)throw new Error("Error finding a random user agent.");let n=o[e];this.data=_lodashclonedeep2.default.call(void 0, n)};if(c(this,A(r)),this.cumulativeWeightIndexPairs.length===0)throw new Error("No user agents matched your filters.");return this.randomize(),new Proxy(this,{apply:()=>this.random(),get:(e,n,s)=>{if(e.data&&typeof n=="string"&&Object.prototype.hasOwnProperty.call(e.data,n)&&Object.prototype.propertyIsEnumerable.call(e.data,n)){let l=e.data[n];if(l!==void 0)return l}return Reflect.get(e,n,s)}})}static{b=Symbol.toPrimitive}static{this.random=r=>{try{return new t(r)}catch (e3){return null}}}};var P=i;exports.default = P;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _useragentsjson = require('./user-agents.json'); var _useragentsjson2 = _interopRequireDefault(_useragentsjson);var o=_useragentsjson2.default,p=r=>{let t=r.reduce((e,[s])=>e+s,0),a=0;return r.map(([e,s])=>(a+=e/t,[a,s]))},y=o.map(({weight:r},t)=>[r,t]),b=p(y),c=(r,t=a=>a)=>{let a;return typeof r=="function"?a=[r]:r instanceof RegExp?a=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?r.test(e.userAgent):r.test(e)]:r instanceof Array?a=r.map(e=>c(e)):typeof r=="object"?a=Object.entries(r).map(([e,s])=>c(s,n=>n[e])):a=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?r===e.userAgent:r===e],e=>{try{let s=t(e);return a.every(n=>n(s))}catch (e2){return!1}}},A=r=>{if(!r)return b;let t=c(r),a=[];return o.forEach((e,s)=>{t(e)&&a.push([e.weight,s])}),p(a)},g=(r,t)=>{Object.defineProperty(r,"cumulativeWeightIndexPairs",{configurable:!0,enumerable:!1,writable:!1,value:t})},d=new WeakSet,m,h,u=class r{constructor(t){this[m]=()=>this.data.userAgent;this.toString=()=>this.data.userAgent;this.random=()=>{let t=new r;return g(t,this.cumulativeWeightIndexPairs),t.randomize(),t};this.top=t=>{let a=this.cumulativeWeightIndexPairs,e=a.map(([n,i],l)=>({weight:l>0?n-a[l-1][0]:n,index:i}));e.sort((n,i)=>i.weight-n.weight);let s=t!=null?Math.min(t,e.length):e.length;return e.slice(0,s).map(({index:n})=>structuredClone(o[n]))};this.randomize=()=>{let t=Math.random(),[,a]=_nullishCoalesce(this.cumulativeWeightIndexPairs.find(([e])=>e>t), () => ([]));if(a==null)throw new Error("Error finding a random user agent.");this.data=structuredClone(o[a])};if(g(this,A(t)),this.cumulativeWeightIndexPairs.length===0)throw new Error("No user agents matched your filters.");this.randomize();let a=()=>{},e=new Proxy(a,{apply:()=>this.random(),get:(s,n)=>{if(this.data&&typeof n=="string"&&Object.prototype.hasOwnProperty.call(this.data,n)&&Object.prototype.propertyIsEnumerable.call(this.data,n)){let i=this.data[n];if(i!==void 0)return i}return Reflect.get(this,n)},set:(s,n,i)=>Reflect.set(this,n,i),defineProperty:(s,n,i)=>Reflect.defineProperty(this,n,i),getOwnPropertyDescriptor:(s,n)=>Reflect.getOwnPropertyDescriptor(this,n),has:(s,n)=>Reflect.has(this,n),deleteProperty:(s,n)=>Reflect.deleteProperty(this,n),ownKeys:()=>Reflect.ownKeys(this),getPrototypeOf:()=>r.prototype});return d.add(e),e}static[(h=Symbol.hasInstance,m=Symbol.toPrimitive,h)](t){return t instanceof Object&&d.has(t)}static{this.random=t=>{try{return new r(t)}catch (e3){return null}}}static{this.top=(t,a)=>{try{return new r(a).top(t)}catch (e4){return[]}}}};var U=u;exports.default = U;
2
2
 
3
- module.exports = exports.default//# sourceMappingURL=index.cjs.map
3
+ module.exports = exports.default;
4
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/user-agent.ts","../src/index.ts"],"names":["cloneDeep","untypedUserAgents","userAgents","makeCumulativeWeightIndexPairs","weightIndexPairs","totalWeight","sum","weight","index","defaultWeightIndexPairs","defaultCumulativeWeightIndexPairs","constructFilter","filters","accessor","parentObject","childFilters","value","childFilter","key","valueFilter","constructCumulativeWeightIndexPairsFromFilters","filter","rawUserAgent","setCumulativeWeightIndexPairs","userAgent","cumulativeWeightIndexPairs","_a","UserAgent","_UserAgent","randomNumber","cumulativeWeight","target","property","receiver","src_default"],"mappings":"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","sourcesContent":["import cloneDeep from 'lodash.clonedeep';\n\nimport untypedUserAgents from './user-agents.json' assert { 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 (error) {\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\nexport class UserAgent extends Function {\n constructor(filters?: Filter) {\n super();\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 // eslint-disable-next-line no-constructor-return\n return new Proxy(this, {\n apply: () => this.random(),\n get: (target, property, receiver) => {\n const dataCandidate =\n target.data &&\n typeof property === 'string' &&\n Object.prototype.hasOwnProperty.call(target.data, property) &&\n Object.prototype.propertyIsEnumerable.call(target.data, property);\n if (dataCandidate) {\n const value = target.data[property as keyof UserAgentData];\n if (value !== undefined) {\n return value;\n }\n }\n\n return Reflect.get(target, property, receiver);\n },\n });\n }\n\n static random = (filters: Filter) => {\n try {\n return new UserAgent(filters);\n } catch (error) {\n return null;\n }\n };\n\n //\n // Standard Object Methods\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 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 const rawUserAgent = userAgents[index];\n\n (this as { data: UserAgentData }).data = cloneDeep(rawUserAgent);\n };\n}\n","import { Filter, UserAgent, UserAgentData } from './user-agent';\n\nexport default UserAgent;\nexport type { Filter, UserAgentData };\n"]}
1
+ {"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":"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","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"]}
package/dist/index.d.cts CHANGED
@@ -28,13 +28,19 @@ declare module './user-agent' {
28
28
  (): UserAgent;
29
29
  }
30
30
  }
31
- declare class UserAgent extends Function {
32
- constructor(filters?: Filter);
31
+ declare class UserAgent {
32
+ static [Symbol.hasInstance](instance: unknown): boolean;
33
33
  static random: (filters: Filter) => UserAgent | null;
34
+ static top: (count?: number, filters?: Filter) => UserAgentData[];
35
+ readonly data: UserAgentData;
36
+ constructor(filters?: Filter);
34
37
  [Symbol.toPrimitive]: () => string;
35
38
  toString: () => string;
36
39
  random: () => UserAgent;
40
+ top: (count?: number) => UserAgentData[];
37
41
  randomize: () => void;
38
42
  }
39
43
 
40
- export { Filter, UserAgentData, UserAgent as default };
44
+ // @ts-ignore
45
+ export = UserAgent;
46
+ export type { Filter, UserAgentData };
package/dist/index.d.ts CHANGED
@@ -28,13 +28,17 @@ declare module './user-agent' {
28
28
  (): UserAgent;
29
29
  }
30
30
  }
31
- declare class UserAgent extends Function {
32
- constructor(filters?: Filter);
31
+ declare class UserAgent {
32
+ static [Symbol.hasInstance](instance: unknown): boolean;
33
33
  static random: (filters: Filter) => UserAgent | null;
34
+ static top: (count?: number, filters?: Filter) => UserAgentData[];
35
+ readonly data: UserAgentData;
36
+ constructor(filters?: Filter);
34
37
  [Symbol.toPrimitive]: () => string;
35
38
  toString: () => string;
36
39
  random: () => UserAgent;
40
+ top: (count?: number) => UserAgentData[];
37
41
  randomize: () => void;
38
42
  }
39
43
 
40
- export { Filter, UserAgentData, UserAgent as default };
44
+ export { type Filter, type UserAgentData, UserAgent as default };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import g from"lodash.clonedeep";import m from"./user-agents.json"assert{type:"json"};var o=m,d=t=>{let a=t.reduce((e,[n])=>e+n,0),r=0;return t.map(([e,n])=>(r+=e/a,[r,n]))},f=o.map(({weight:t},a)=>[t,a]),p=d(f),u=(t,a=r=>r)=>{let r;return typeof t=="function"?r=[t]:t instanceof RegExp?r=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?t.test(e.userAgent):t.test(e)]:t instanceof Array?r=t.map(e=>u(e)):typeof t=="object"?r=Object.entries(t).map(([e,n])=>u(n,s=>s[e])):r=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?t===e.userAgent:t===e],e=>{try{let n=a(e);return r.every(s=>s(n))}catch{return!1}}},A=t=>{if(!t)return p;let a=u(t),r=[];return o.forEach((e,n)=>{a(e)&&r.push([e.weight,n])}),d(r)},c=(t,a)=>{Object.defineProperty(t,"cumulativeWeightIndexPairs",{configurable:!0,enumerable:!1,writable:!1,value:a})},b,i=class t extends Function{constructor(r){super();this[b]=()=>this.data.userAgent;this.toString=()=>this.data.userAgent;this.random=()=>{let r=new t;return c(r,this.cumulativeWeightIndexPairs),r.randomize(),r};this.randomize=()=>{let r=Math.random(),[,e]=this.cumulativeWeightIndexPairs.find(([s])=>s>r)??[];if(e==null)throw new Error("Error finding a random user agent.");let n=o[e];this.data=g(n)};if(c(this,A(r)),this.cumulativeWeightIndexPairs.length===0)throw new Error("No user agents matched your filters.");return this.randomize(),new Proxy(this,{apply:()=>this.random(),get:(e,n,s)=>{if(e.data&&typeof n=="string"&&Object.prototype.hasOwnProperty.call(e.data,n)&&Object.prototype.propertyIsEnumerable.call(e.data,n)){let l=e.data[n];if(l!==void 0)return l}return Reflect.get(e,n,s)}})}static{b=Symbol.toPrimitive}static{this.random=r=>{try{return new t(r)}catch{return null}}}};var P=i;export{P as default};
1
+ import f from"./user-agents.json"with{type:"json"};var o=f,p=r=>{let t=r.reduce((e,[s])=>e+s,0),a=0;return r.map(([e,s])=>(a+=e/t,[a,s]))},y=o.map(({weight:r},t)=>[r,t]),b=p(y),c=(r,t=a=>a)=>{let a;return typeof r=="function"?a=[r]:r instanceof RegExp?a=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?r.test(e.userAgent):r.test(e)]:r instanceof Array?a=r.map(e=>c(e)):typeof r=="object"?a=Object.entries(r).map(([e,s])=>c(s,n=>n[e])):a=[e=>typeof e=="object"&&e&&"userAgent"in e&&e.userAgent?r===e.userAgent:r===e],e=>{try{let s=t(e);return a.every(n=>n(s))}catch{return!1}}},A=r=>{if(!r)return b;let t=c(r),a=[];return o.forEach((e,s)=>{t(e)&&a.push([e.weight,s])}),p(a)},g=(r,t)=>{Object.defineProperty(r,"cumulativeWeightIndexPairs",{configurable:!0,enumerable:!1,writable:!1,value:t})},d=new WeakSet,m,h,u=class r{constructor(t){this[m]=()=>this.data.userAgent;this.toString=()=>this.data.userAgent;this.random=()=>{let t=new r;return g(t,this.cumulativeWeightIndexPairs),t.randomize(),t};this.top=t=>{let a=this.cumulativeWeightIndexPairs,e=a.map(([n,i],l)=>({weight:l>0?n-a[l-1][0]:n,index:i}));e.sort((n,i)=>i.weight-n.weight);let s=t!=null?Math.min(t,e.length):e.length;return e.slice(0,s).map(({index:n})=>structuredClone(o[n]))};this.randomize=()=>{let t=Math.random(),[,a]=this.cumulativeWeightIndexPairs.find(([e])=>e>t)??[];if(a==null)throw new Error("Error finding a random user agent.");this.data=structuredClone(o[a])};if(g(this,A(t)),this.cumulativeWeightIndexPairs.length===0)throw new Error("No user agents matched your filters.");this.randomize();let a=()=>{},e=new Proxy(a,{apply:()=>this.random(),get:(s,n)=>{if(this.data&&typeof n=="string"&&Object.prototype.hasOwnProperty.call(this.data,n)&&Object.prototype.propertyIsEnumerable.call(this.data,n)){let i=this.data[n];if(i!==void 0)return i}return Reflect.get(this,n)},set:(s,n,i)=>Reflect.set(this,n,i),defineProperty:(s,n,i)=>Reflect.defineProperty(this,n,i),getOwnPropertyDescriptor:(s,n)=>Reflect.getOwnPropertyDescriptor(this,n),has:(s,n)=>Reflect.has(this,n),deleteProperty:(s,n)=>Reflect.deleteProperty(this,n),ownKeys:()=>Reflect.ownKeys(this),getPrototypeOf:()=>r.prototype});return d.add(e),e}static[(h=Symbol.hasInstance,m=Symbol.toPrimitive,h)](t){return t instanceof Object&&d.has(t)}static{this.random=t=>{try{return new r(t)}catch{return null}}}static{this.top=(t,a)=>{try{return new r(a).top(t)}catch{return[]}}}};var U=u;export{U as default};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/user-agent.ts","../src/index.ts"],"sourcesContent":["import cloneDeep from 'lodash.clonedeep';\n\nimport untypedUserAgents from './user-agents.json' assert { 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 (error) {\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\nexport class UserAgent extends Function {\n constructor(filters?: Filter) {\n super();\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 // eslint-disable-next-line no-constructor-return\n return new Proxy(this, {\n apply: () => this.random(),\n get: (target, property, receiver) => {\n const dataCandidate =\n target.data &&\n typeof property === 'string' &&\n Object.prototype.hasOwnProperty.call(target.data, property) &&\n Object.prototype.propertyIsEnumerable.call(target.data, property);\n if (dataCandidate) {\n const value = target.data[property as keyof UserAgentData];\n if (value !== undefined) {\n return value;\n }\n }\n\n return Reflect.get(target, property, receiver);\n },\n });\n }\n\n static random = (filters: Filter) => {\n try {\n return new UserAgent(filters);\n } catch (error) {\n return null;\n }\n };\n\n //\n // Standard Object Methods\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 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 const rawUserAgent = userAgents[index];\n\n (this as { data: UserAgentData }).data = cloneDeep(rawUserAgent);\n };\n}\n","import { Filter, UserAgent, UserAgentData } from './user-agent';\n\nexport default UserAgent;\nexport type { Filter, UserAgentData };\n"],"mappings":"AAAA,OAAOA,MAAe,mBAEtB,OAAOC,MAAuB,oBAAqB,MAAO,CAAE,KAAM,MAAO,EAEzE,IAAMC,EAA8BD,EAgD9BE,EACJC,GAC4B,CAC5B,IAAMC,EAAcD,EAAiB,OAAO,CAACE,EAAK,CAACC,CAAM,IAAMD,EAAMC,EAAQ,CAAC,EAC1ED,EAAM,EACV,OAAOF,EAAiB,IAAI,CAAC,CAACG,EAAQC,CAAK,KACzCF,GAAOC,EAASF,EACT,CAACC,EAAKE,CAAK,EACnB,CACH,EAGMC,EAAmDP,EAAW,IAAI,CAAC,CAAE,OAAAK,CAAO,EAAGC,IAAU,CAC7FD,EACAC,CACF,CAAC,EACKE,EAAoCP,EAA+BM,CAAuB,EAG1FE,EAAkB,CACtBC,EACAC,EAAuDC,GAAuBA,IAChD,CAG9B,IAAIC,EACJ,OAAI,OAAOH,GAAY,WACrBG,EAAe,CAACH,CAAO,EACdA,aAAmB,OAC5BG,EAAe,CACZC,GACC,OAAOA,GAAU,UAAYA,GAAS,cAAeA,GAASA,EAAM,UAChEJ,EAAQ,KAAKI,EAAM,SAAS,EAC5BJ,EAAQ,KAAKI,CAAe,CACpC,EACSJ,aAAmB,MAC5BG,EAAeH,EAAQ,IAAKK,GAAgBN,EAAgBM,CAAW,CAAC,EAC/D,OAAOL,GAAY,SAC5BG,EAAe,OAAO,QAAQH,CAAO,EAAE,IAAI,CAAC,CAACM,EAAKC,CAAW,IAC3DR,EACEQ,EACCL,GACEA,EAAgEI,CAAG,CACxE,CACF,EAEAH,EAAe,CACZC,GACC,OAAOA,GAAU,UAAYA,GAAS,cAAeA,GAASA,EAAM,UAChEJ,IAAYI,EAAM,UAClBJ,IAAYI,CACpB,EAGMF,GAAoB,CAC1B,GAAI,CACF,IAAME,EAAQH,EAASC,CAAY,EACnC,OAAOC,EAAa,MAAOE,GAAgBA,EAAYD,CAAU,CAAC,CACpE,MAAgB,CAEd,MAAO,EACT,CACF,CACF,EAGMI,EACJR,GAC4B,CAC5B,GAAI,CAACA,EACH,OAAOF,EAGT,IAAMW,EAASV,EAAgBC,CAAO,EAEhCR,EAA4C,CAAC,EACnD,OAAAF,EAAW,QAAQ,CAACoB,EAAcd,IAAU,CACtCa,EAAOC,CAAY,GACrBlB,EAAiB,KAAK,CAACkB,EAAa,OAAQd,CAAK,CAAC,CAEtD,CAAC,EACML,EAA+BC,CAAgB,CACxD,EAEMmB,EAAgC,CACpCC,EACAC,IACG,CACH,OAAO,eAAeD,EAAW,6BAA8B,CAC7D,aAAc,GACd,WAAY,GACZ,SAAU,GACV,MAAOC,CACT,CAAC,CACH,EAlJAC,EAoJaC,EAAN,MAAMC,UAAkB,QAAS,CACtC,YAAYhB,EAAkB,CAC5B,MAAM,EAyCR,KAACc,GAAsB,IAAc,KAAK,KAAK,UAE/C,cAAW,IAAc,KAAK,KAAK,UAEnC,YAAS,IAAiB,CACxB,IAAMF,EAAY,IAAII,EACtB,OAAAL,EAA8BC,EAAW,KAAK,0BAA0B,EACxEA,EAAU,UAAU,EACbA,CACT,EAEA,eAAY,IAAY,CAEtB,IAAMK,EAAe,KAAK,OAAO,EAC3B,CAAC,CAAErB,CAAK,EACZ,KAAK,2BAA2B,KAC9B,CAAC,CAACsB,CAAgB,IAAMA,EAAmBD,CAC7C,GAAK,CAAC,EACR,GAAIrB,GAAS,KACX,MAAM,IAAI,MAAM,oCAAoC,EAEtD,IAAMc,EAAepB,EAAWM,CAAK,EAEpC,KAAiC,KAAOR,EAAUsB,CAAY,CACjE,EAhEE,GAAAC,EAA8B,KAAMH,EAA+CR,CAAO,CAAC,EACvF,KAAK,2BAA2B,SAAW,EAC7C,MAAM,IAAI,MAAM,sCAAsC,EAGxD,YAAK,UAAU,EAGR,IAAI,MAAM,KAAM,CACrB,MAAO,IAAM,KAAK,OAAO,EACzB,IAAK,CAACmB,EAAQC,EAAUC,IAAa,CAMnC,GAJEF,EAAO,MACP,OAAOC,GAAa,UACpB,OAAO,UAAU,eAAe,KAAKD,EAAO,KAAMC,CAAQ,GAC1D,OAAO,UAAU,qBAAqB,KAAKD,EAAO,KAAMC,CAAQ,EAC/C,CACjB,IAAMhB,EAAQe,EAAO,KAAKC,CAA+B,EACzD,GAAIhB,IAAU,OACZ,OAAOA,CAEX,CAEA,OAAO,QAAQ,IAAIe,EAAQC,EAAUC,CAAQ,CAC/C,CACF,CAAC,CACH,CAcC,OAAAP,EAAA,OAAO,YAZR,YAAO,OAAUd,GAAoB,CACnC,GAAI,CACF,OAAO,IAAIgB,EAAUhB,CAAO,CAC9B,MAAgB,CACd,OAAO,IACT,CACF,EA+BF,ECtNA,IAAOsB,EAAQC","names":["cloneDeep","untypedUserAgents","userAgents","makeCumulativeWeightIndexPairs","weightIndexPairs","totalWeight","sum","weight","index","defaultWeightIndexPairs","defaultCumulativeWeightIndexPairs","constructFilter","filters","accessor","parentObject","childFilters","value","childFilter","key","valueFilter","constructCumulativeWeightIndexPairsFromFilters","filter","rawUserAgent","setCumulativeWeightIndexPairs","userAgent","cumulativeWeightIndexPairs","_a","UserAgent","_UserAgent","randomNumber","cumulativeWeight","target","property","receiver","src_default","UserAgent"]}
1
+ {"version":3,"sources":["../src/user-agent.ts","../src/index.ts"],"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"],"mappings":"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","names":["untypedUserAgents","userAgents","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","UserAgent"]}