@thumbmarkjs/thumbmarkjs 0.20.6 → 1.0.0-rc.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.
Files changed (35) hide show
  1. package/README.md +43 -45
  2. package/dist/thumbmark.cjs.js +1 -1
  3. package/dist/thumbmark.cjs.js.map +1 -1
  4. package/dist/thumbmark.esm.d.ts +107 -16
  5. package/dist/thumbmark.esm.js +1 -1
  6. package/dist/thumbmark.esm.js.map +1 -1
  7. package/dist/thumbmark.umd.js +1 -1
  8. package/dist/thumbmark.umd.js.map +1 -1
  9. package/package.json +7 -2
  10. package/src/components/audio/{audio.ts → index.ts} +11 -8
  11. package/src/components/canvas/{canvas.ts → index.ts} +12 -8
  12. package/src/components/fonts/{fonts.ts → index.ts} +10 -5
  13. package/src/components/hardware/{hardware.ts → index.ts} +3 -5
  14. package/src/components/locales/{locales.ts → index.ts} +2 -4
  15. package/src/components/math/index.ts +28 -0
  16. package/src/components/permissions/{permissions.ts → index.ts} +29 -37
  17. package/src/components/plugins/{plugins.ts → index.ts} +2 -4
  18. package/src/components/screen/{screen.ts → index.ts} +2 -4
  19. package/src/components/system/{system.ts → index.ts} +2 -5
  20. package/src/components/webgl/{webgl.ts → index.ts} +3 -5
  21. package/src/factory.ts +40 -29
  22. package/src/functions/filterComponents.ts +42 -0
  23. package/src/functions/functions.test.ts +39 -0
  24. package/src/functions/index.ts +262 -0
  25. package/src/functions/legacy_functions.ts +54 -0
  26. package/src/index.ts +13 -4
  27. package/src/{fingerprint/options.ts → options.ts} +20 -12
  28. package/src/thumbmark.ts +41 -0
  29. package/src/{declarations.d.ts → types/global.d.ts} +1 -1
  30. package/src/utils/raceAll.ts +0 -2
  31. package/src/components/index.ts +0 -17
  32. package/src/components/math/math.ts +0 -39
  33. package/src/fingerprint/functions.test.ts +0 -34
  34. package/src/fingerprint/functions.ts +0 -118
  35. /package/src/components/canvas/{canvas.test.ts → index.test.ts} +0 -0
package/src/factory.ts CHANGED
@@ -4,21 +4,53 @@
4
4
  *
5
5
  */
6
6
 
7
- import { options, optionsInterface } from './fingerprint/options';
7
+ import { optionsInterface } from './options';
8
+ //import { getComponentPromises } from './fingerprint/tm_functions';
9
+
10
+ // Import all built-in component functions
11
+ import getAudio from "./components/audio";
12
+ import getCanvas from "./components/canvas";
13
+ import getFonts from "./components/fonts";
14
+ import getHardware from "./components/hardware";
15
+ import getLocales from "./components/locales";
16
+ import getMath from "./components/math";
17
+ import getPermissions from "./components/permissions";
18
+ import getPlugins from "./components/plugins";
19
+ import getScreen from "./components/screen";
20
+ import getSystem from "./components/system";
21
+ import getWebGL from "./components/webgl";
22
+
23
+ /**
24
+ * @description key->function map of built-in components. Do not call the function here.
25
+ */
26
+ export const tm_component_promises = {
27
+ 'audio': getAudio,
28
+ 'canvas': getCanvas,
29
+ 'fonts': getFonts,
30
+ 'hardware': getHardware,
31
+ 'locales': getLocales,
32
+ 'math': getMath,
33
+ 'permissions': getPermissions,
34
+ 'plugins': getPlugins,
35
+ 'screen': getScreen,
36
+ 'system': getSystem,
37
+ 'webgl': getWebGL
38
+ };
8
39
 
9
40
  // the component interface is the form of the JSON object the function's promise must return
10
41
  export interface componentInterface {
11
42
  [key: string]: string | string[] | number | boolean | componentInterface;
12
- }
43
+ };
13
44
 
14
45
 
15
46
  // The component function's interface is simply the promise of the above
16
47
  export interface componentFunctionInterface {
17
- (): Promise<componentInterface>;
48
+ (options?: optionsInterface): Promise<componentInterface | null>;
18
49
  }
19
50
 
20
51
  // components include a dictionary of name: function.
21
- export const components: {[name: string]: componentFunctionInterface} = {};
52
+ // Renamed to customComponents for clarity; this is for user-registered components.
53
+ export const customComponents: {[name: string]: componentFunctionInterface | null} = {};
22
54
 
23
55
  //In case a promise time-outs, this is what we use as the value in place
24
56
  export const timeoutInstance: componentInterface = {
@@ -30,29 +62,8 @@ export const timeoutInstance: componentInterface = {
30
62
  * in the fingerprint.
31
63
  * @param {string} name - the name identifier of the component
32
64
  * @param {componentFunctionInterface} creationFunction - the function that implements the component
33
- * @returns
65
+ * @returns nothing
34
66
  */
35
- export const includeComponent = (name:string, creationFunction: componentFunctionInterface) => {
36
- if (typeof window !== 'undefined')
37
- components[name] = creationFunction;
38
- }
39
-
40
- /**
41
- * The function turns the map of component functions to a map of Promises when called
42
- * @returns {[name: string]: <Promise>componentInterface}
43
- */
44
- export const getComponentPromises = () => {
45
- return Object.fromEntries(
46
- Object.entries(components)
47
- .filter(([key]) => {
48
- return !options?.exclude?.includes(key)}
49
- )
50
- .filter(([key]) => {
51
- return options?.include?.some(e => e.includes('.'))
52
- ? options?.include?.some(e => e.startsWith(key))
53
- : options?.include?.length === 0 || options?.include?.includes(key)
54
- }
55
- )
56
- .map(([key, value]) => [key, value()])
57
- );
58
- }
67
+ export const includeComponent = (name:string, creationFunction: componentFunctionInterface, options?: optionsInterface) => {
68
+ customComponents[name] = creationFunction;
69
+ };
@@ -0,0 +1,42 @@
1
+ import { componentInterface } from "../factory";
2
+ import { optionsInterface } from "../options";
3
+
4
+ // ===================== Data Filtering =====================
5
+
6
+ /**
7
+ * Recursively filters a componentInterface object by include/exclude options.
8
+ *
9
+ * @param obj - The object to filter
10
+ * @param options - Filtering options
11
+ * @param path - Current path (for recursion)
12
+ * @returns Filtered object
13
+ */
14
+ export function filterThumbmarkData(
15
+ obj: componentInterface,
16
+ options?: optionsInterface,
17
+ path: string = ""
18
+ ): componentInterface {
19
+ const result: componentInterface = {};
20
+ const excludeList = options?.exclude || [];
21
+ const includeList = options?.include || [];
22
+
23
+ for (const [key, value] of Object.entries(obj)) {
24
+ const currentPath = path + key + ".";
25
+
26
+ if (typeof value === "object" && !Array.isArray(value)) {
27
+ const filtered = filterThumbmarkData(value, options, currentPath);
28
+ if (Object.keys(filtered).length > 0) {
29
+ result[key] = filtered;
30
+ }
31
+ } else {
32
+ const isExcluded = excludeList.some(exclusion => currentPath.startsWith(exclusion));
33
+ const isIncluded = includeList.some(inclusion => currentPath.startsWith(inclusion));
34
+
35
+ if (!isExcluded || isIncluded) {
36
+ result[key] = value;
37
+ }
38
+ }
39
+ }
40
+
41
+ return result;
42
+ }
@@ -0,0 +1,39 @@
1
+ import { componentInterface } from '../factory'
2
+ import { filterThumbmarkData } from '../utils/filterComponents'
3
+ import { defaultOptions } from '../options';
4
+
5
+ const test_components: componentInterface = {
6
+ 'one': '1',
7
+ 'two': 2,
8
+ 'three': {'a': true, 'b': false}
9
+ }
10
+
11
+ describe('component filtering tests', () => {
12
+ test("excluding top level works", () => {
13
+ expect(filterThumbmarkData(test_components,
14
+ { ...defaultOptions, ...{ exclude: ['one']} }
15
+ )).toMatchObject({
16
+ 'two': 2, 'three': {'a': true, 'b': false}
17
+ })
18
+ });
19
+ test("including top level works", () => {
20
+ expect(filterThumbmarkData(test_components, { ...defaultOptions, ...{ include: ['one', 'two']} })).toMatchObject({
21
+ 'one': '1', 'two': 2
22
+ })
23
+ });
24
+ test("excluding low-level works", () => {
25
+ expect(filterThumbmarkData(test_components,
26
+ { ...defaultOptions, ...{ exclude: ['two', 'three.a']} }
27
+ )).toMatchObject({
28
+ 'one': '1',
29
+ 'three': {'b': false}
30
+ })
31
+ });
32
+ test("including low-level works", () => {
33
+ expect(filterThumbmarkData(test_components,
34
+ { ...defaultOptions, ...{ include: ['one', 'three.b']} })).toMatchObject({
35
+ 'one': '1',
36
+ 'three': {'b': false}
37
+ })
38
+ });
39
+ });
@@ -0,0 +1,262 @@
1
+ /**
2
+ * ThumbmarkJS: Main fingerprinting and API logic
3
+ *
4
+ * This module handles component collection, API calls, uniqueness scoring, and data filtering
5
+ * for the ThumbmarkJS browser fingerprinting library.
6
+ *
7
+ * Exports:
8
+ * - getThumbmark
9
+ * - getThumbmarkDataFromPromiseMap
10
+ * - resolveClientComponents
11
+ * - getVersion
12
+ * - filterThumbmarkData
13
+ *
14
+ * Internal helpers and types are also defined here.
15
+ */
16
+
17
+ // ===================== Imports =====================
18
+ import { defaultOptions, optionsInterface } from "../options";
19
+ import {
20
+ timeoutInstance,
21
+ componentInterface,
22
+ tm_component_promises,
23
+ customComponents,
24
+ includeComponent as globalIncludeComponent
25
+ } from "../factory";
26
+ import { hash } from "../utils/hash";
27
+ import { raceAllPerformance } from "../utils/raceAll";
28
+ import * as packageJson from '../../package.json';
29
+ import { filterThumbmarkData } from './filterComponents'
30
+
31
+ // ===================== Types & Interfaces =====================
32
+
33
+ /**
34
+ * Info returned from the API (IP, classification, uniqueness, etc)
35
+ */
36
+ interface infoInterface {
37
+ ip_address?: {
38
+ ip_address: string,
39
+ ip_identifier: string,
40
+ autonomous_system_number: number,
41
+ ip_version: 'v6' | 'v4',
42
+ },
43
+ classification?: {
44
+ tor: boolean,
45
+ proxy: boolean, // i.e. vpn and
46
+ datacenter: boolean,
47
+ danger_level: number, // 5 is highest and should be blocked. 0 is no danger.
48
+ },
49
+ uniqueness?: {
50
+ score: number | string
51
+ },
52
+ timed_out?: boolean; // added for timeout handling
53
+ }
54
+
55
+ /**
56
+ * API response structure
57
+ */
58
+ interface apiResponse {
59
+ thumbmark?: string;
60
+ info?: infoInterface;
61
+ version?: string;
62
+ }
63
+
64
+ /**
65
+ * Final thumbmark response structure
66
+ */
67
+ interface thumbmarkResponse {
68
+ components: componentInterface,
69
+ info: { [key: string]: any },
70
+ version: string,
71
+ thumbmark: string,
72
+ /**
73
+ * Only present if options.performance is true.
74
+ */
75
+ elapsed?: any;
76
+ }
77
+
78
+ // ===================== Version =====================
79
+
80
+ /**
81
+ * Returns the current package version
82
+ */
83
+ export function getVersion(): string {
84
+ return packageJson.version;
85
+ }
86
+
87
+ // ===================== API Call Logic =====================
88
+
89
+ let currentApiPromise: Promise<apiResponse> | null = null;
90
+ let apiPromiseResult: apiResponse | null = null;
91
+
92
+ /**
93
+ * Calls the Thumbmark API with the given components, using caching and deduplication.
94
+ * Returns a promise for the API response or null on error.
95
+ */
96
+ export const getApiPromise = (
97
+ options: optionsInterface,
98
+ components: componentInterface
99
+ ): Promise<apiResponse | null> => {
100
+ // 1. If a result is already cached and caching is enabled, return it.
101
+ if (options.cache_api_call && apiPromiseResult) {
102
+ return Promise.resolve(apiPromiseResult);
103
+ }
104
+
105
+ // 2. If a request is already in flight, return that promise to prevent duplicate calls.
106
+ if (currentApiPromise) {
107
+ return currentApiPromise;
108
+ }
109
+
110
+ // 3. Otherwise, initiate a new API call with timeout.
111
+ const endpoint = 'https://api-dev.thumbmarkjs.com/thumbmark';
112
+ const fetchPromise = fetch(endpoint, {
113
+ method: 'POST',
114
+ headers: {
115
+ 'x-api-key': options.api_key!,
116
+ 'Authorization': 'custom-authorized',
117
+ },
118
+ body: JSON.stringify({ components: components, clientHash: hash(JSON.stringify(components)) }),
119
+ })
120
+ .then(response => {
121
+ // Handle HTTP errors that aren't network errors
122
+ if (!response.ok) {
123
+ throw new Error(`HTTP error! status: ${response.status}`);
124
+ }
125
+ return response.json();
126
+ })
127
+ .then(data => {
128
+ apiPromiseResult = data; // Cache the successful result
129
+ currentApiPromise = null; // Clear the in-flight promise
130
+ return data;
131
+ })
132
+ .catch(error => {
133
+ console.error('Error fetching pro data', error);
134
+ currentApiPromise = null; // Also clear the in-flight promise on error
135
+ // Return null instead of a string to prevent downstream crashes
136
+ return null;
137
+ });
138
+
139
+ // Timeout logic
140
+ const timeoutMs = options.timeout || 5000;
141
+ const timeoutPromise = new Promise<apiResponse>((resolve) => {
142
+ setTimeout(() => {
143
+ resolve({
144
+ thumbmark: hash(JSON.stringify(components)),
145
+ info: { timed_out: true },
146
+ version: packageJson.version,
147
+ });
148
+ }, timeoutMs);
149
+ });
150
+
151
+ currentApiPromise = Promise.race([fetchPromise, timeoutPromise]);
152
+ return currentApiPromise;
153
+ };
154
+
155
+ // ===================== Main Thumbmark Logic =====================
156
+
157
+ /**
158
+ * Main entry point: collects all components, optionally calls API, and returns thumbmark data.
159
+ *
160
+ * @param options - Options for fingerprinting and API
161
+ * @returns thumbmarkResponse (elapsed is present only if options.performance is true)
162
+ */
163
+ export async function getThumbmark(options?: optionsInterface): Promise<thumbmarkResponse> {
164
+ const _options = { ...defaultOptions, ...options };
165
+ // Merge built-in and user-registered components
166
+ const allComponents = { ...tm_component_promises, ...customComponents };
167
+ const { elapsed, resolvedComponents: clientComponentsResult } = await resolveClientComponents(allComponents, _options);
168
+
169
+ const apiPromise = _options.api_key ? getApiPromise(_options, clientComponentsResult) : null;
170
+ const apiResult = apiPromise ? await apiPromise : null;
171
+
172
+ // Only add 'elapsed' if performance is true
173
+ const maybeElapsed = _options.performance ? { elapsed } : {};
174
+
175
+ if (apiResult) {
176
+ const info: infoInterface = apiResult.info || {};
177
+ return {
178
+ components: clientComponentsResult,
179
+ info,
180
+ version: getVersion(),
181
+ thumbmark: apiResult.thumbmark || 'undefined',
182
+ ...maybeElapsed,
183
+ };
184
+ }
185
+ return {
186
+ thumbmark: hash(JSON.stringify(clientComponentsResult)),
187
+ components: clientComponentsResult,
188
+ info: {
189
+ uniqueness: 'api only'
190
+ },
191
+ version: getVersion(),
192
+ ...maybeElapsed,
193
+ };
194
+ }
195
+
196
+ // ===================== Component Resolution & Performance =====================
197
+
198
+ /**
199
+ * Resolves and times all filtered component promises from a component function map.
200
+ *
201
+ * @param comps - Map of component functions
202
+ * @param options - Options for filtering and timing
203
+ * @returns Object with elapsed times and filtered resolved components
204
+ */
205
+ export async function resolveClientComponents(
206
+ comps: { [key: string]: (options?: optionsInterface) => Promise<componentInterface | null> },
207
+ options?: optionsInterface
208
+ ): Promise<{ elapsed: Record<string, number>, resolvedComponents: componentInterface }> {
209
+ const opts = { ...defaultOptions, ...options };
210
+ const filtered = Object.entries(comps)
211
+ .filter(([key]) => !opts?.exclude?.includes(key))
212
+ .filter(([key]) =>
213
+ opts?.include?.some(e => e.includes('.'))
214
+ ? opts?.include?.some(e => e.startsWith(key))
215
+ : opts?.include?.length === 0 || opts?.include?.includes(key)
216
+ );
217
+ const keys = filtered.map(([key]) => key);
218
+ const promises = filtered.map(([_, fn]) => fn(options));
219
+ const resolvedValues = await raceAllPerformance(promises, opts?.timeout || 5000, timeoutInstance);
220
+
221
+ const elapsed: Record<string, number> = {};
222
+ const resolvedComponentsRaw: Record<string, componentInterface> = {};
223
+
224
+ resolvedValues.forEach((value, index) => {
225
+ if (value.value != null) {
226
+ resolvedComponentsRaw[keys[index]] = value.value;
227
+ elapsed[keys[index]] = value.elapsed ?? 0;
228
+ }
229
+ });
230
+
231
+ const resolvedComponents = filterThumbmarkData(resolvedComponentsRaw, opts, "");
232
+ return { elapsed, resolvedComponents };
233
+ }
234
+
235
+ // ===================== Logging (Internal) =====================
236
+
237
+ /**
238
+ * Logs thumbmark data to remote logging endpoint (only once per session)
239
+ * @internal
240
+ */
241
+ async function logThumbmarkData(thisHash: string, thumbmarkData: componentInterface) {
242
+ const url = 'https://logging.thumbmarkjs.com/v1/log';
243
+ const payload = {
244
+ thumbmark: thisHash,
245
+ components: thumbmarkData,
246
+ version: getVersion()
247
+ };
248
+ if (!sessionStorage.getItem("_tmjs_l")) {
249
+ sessionStorage.setItem("_tmjs_l", "1");
250
+ try {
251
+ await fetch(url, {
252
+ method: 'POST',
253
+ headers: {
254
+ 'Content-Type': 'application/json'
255
+ },
256
+ body: JSON.stringify(payload)
257
+ });
258
+ } catch { /* do nothing */ }
259
+ }
260
+ }
261
+
262
+ export { globalIncludeComponent as includeComponent };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * This file is here to support legacy implementations.
3
+ * Eventually, these functions will be removed to keep the library small.
4
+ */
5
+
6
+ import { componentInterface } from '../factory'
7
+ import { options} from '../options'
8
+ import { resolveClientComponents, getThumbmark } from '.';
9
+ import { tm_component_promises } from "../factory";
10
+
11
+ /**
12
+ *
13
+ * @deprecated
14
+ */
15
+ export async function getFingerprintData() {
16
+ const thumbmarkData = await getThumbmark(options);
17
+ return thumbmarkData.components;
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param includeData boolean
23
+ * @deprecated this function is going to be removed. use getThumbmark or Thumbmark class instead.
24
+ */
25
+ export async function getFingerprint(includeData?: false): Promise<string>
26
+ export async function getFingerprint(includeData: true): Promise<{ hash: string, data: componentInterface }>
27
+ export async function getFingerprint(includeData?: boolean): Promise<string | { hash: string, data: componentInterface }> {
28
+ try {
29
+ const thumbmarkData = await getThumbmark(options);
30
+ if (includeData) {
31
+ return { hash: thumbmarkData.thumbmark.toString(), data: thumbmarkData.components}
32
+ } else {
33
+ return thumbmarkData.thumbmark.toString()
34
+ }
35
+ } catch (error) {
36
+ throw error
37
+ }
38
+ }
39
+ /**
40
+ *
41
+ * @deprecated use Thumbmark or getThumbmark instead with options
42
+ */
43
+ export async function getFingerprintPerformance() {
44
+ try {
45
+ const { elapsed, resolvedComponents } = await resolveClientComponents(tm_component_promises, options);
46
+ // Legacy format: merge resolvedComponents and elapsed into one object
47
+ return {
48
+ ...resolvedComponents,
49
+ elapsed
50
+ };
51
+ } catch (error) {
52
+ throw error;
53
+ }
54
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,15 @@
1
- import { getFingerprint, getFingerprintData, getFingerprintPerformance, getVersion } from './fingerprint/functions'
2
- import { setOption } from './fingerprint/options'
1
+ import {
2
+ getFingerprint,
3
+ getFingerprintData,
4
+ getFingerprintPerformance
5
+ } from './functions/legacy_functions'
6
+ import { getThumbmark, getVersion } from './functions'
7
+ import { setOption } from './options'
3
8
  import { includeComponent } from './factory'
4
- import './components'
9
+ import { Thumbmark } from './thumbmark'
5
10
 
6
- export { setOption, getVersion, getFingerprint, getFingerprintData, getFingerprintPerformance, includeComponent }
11
+ export { Thumbmark, getThumbmark, getVersion,
12
+
13
+ // deprecated functions. Don't use anymore.
14
+ setOption, getFingerprint, getFingerprintData, getFingerprintPerformance, includeComponent
15
+ }
@@ -1,23 +1,31 @@
1
1
  export interface optionsInterface {
2
- exclude: string[],
3
- include: string[],
4
- webgl_runs?: number,
5
- canvas_runs?: number,
6
- permissions_to_check?: PermissionName[], // new option
7
- retries?: number, // new option
8
- timeout: number, // new option
9
- logging: boolean
2
+ exclude?: string[],
3
+ include?: string[],
4
+ permissions_to_check?: PermissionName[],
5
+ timeout?: number,
6
+ logging?: boolean,
7
+ api_key?: string,
8
+ cache_api_call?: boolean,
9
+ performance?: boolean, // re-added
10
10
  }
11
11
 
12
- export let options: optionsInterface = {
12
+ export const defaultOptions: optionsInterface = {
13
13
  exclude: [],
14
14
  include: [],
15
15
  logging: true,
16
- timeout: 1000
17
- }
16
+ timeout: 5000,
17
+ cache_api_call: true,
18
+ performance: false // re-added
19
+ };
18
20
 
21
+ export let options = {...defaultOptions};
22
+ /**
23
+ *
24
+ * @param key @deprecated this function will be removed
25
+ * @param value
26
+ */
19
27
  export function setOption<K extends keyof optionsInterface>(key: K, value: optionsInterface[K]) {
20
- if (!['include', 'exclude', 'permissions_to_check', 'retries', 'timeout', 'logging'].includes(key))
28
+ if (!['include', 'exclude', 'permissions_to_check', 'retries', 'timeout', 'logging', 'api_key', 'cache_api_call'].includes(key))
21
29
  throw new Error('Unknown option ' + key)
22
30
  if (['include', 'exclude', 'permissions_to_check'].includes(key) && !(Array.isArray(value) && value.every(item => typeof item === 'string')) )
23
31
  throw new Error('The value of the include, exclude and permissions_to_check must be an array of strings');
@@ -0,0 +1,41 @@
1
+ import { optionsInterface } from "./options";
2
+ import { getThumbmark, getVersion, includeComponent as globalIncludeComponent } from './functions';
3
+ import { defaultOptions } from "./options";
4
+ import { componentInterface } from "./factory";
5
+
6
+ /**
7
+ * A client for generating thumbmarks with a persistent configuration.
8
+ */
9
+
10
+ export class Thumbmark {
11
+ private options: optionsInterface;
12
+
13
+ /**
14
+ * Creates a new Thumbmarker client instance.
15
+ * @param options - Default configuration options for this instance.
16
+ */
17
+ constructor(options?: optionsInterface) {
18
+ this.options = { ...defaultOptions, ...options };
19
+ }
20
+
21
+ /**
22
+ * Generates a thumbmark using the instance's configuration.
23
+ * @param overrideOptions - Options to override for this specific call.
24
+ * @returns The thumbmark result.
25
+ */
26
+ public async get(overrideOptions?: optionsInterface): Promise<any> {
27
+ const finalOptions = { ...this.options, ...overrideOptions };
28
+ return getThumbmark(finalOptions);
29
+ }
30
+ public getVersion(): string {
31
+ return getVersion()
32
+ }
33
+ /**
34
+ * Register a custom component to be included in the fingerprint.
35
+ * @param key - The component name
36
+ * @param fn - The component function
37
+ */
38
+ public includeComponent(key: string, fn: (options?: optionsInterface) => Promise<componentInterface | null>) {
39
+ globalIncludeComponent(key, fn);
40
+ }
41
+ }
@@ -5,8 +5,8 @@ interface ApplePaySession {
5
5
  }
6
6
 
7
7
  interface Window {
8
- webkitAudioContext: typeof AudioContext
9
8
  webkitOfflineAudioContext: typeof OfflineAudioContext
9
+ webkitAudioContext: typeof AudioContext
10
10
  ApplePaySession: typeof ApplePaySession
11
11
  }
12
12
 
@@ -1,5 +1,3 @@
1
- import { componentInterface } from '../factory'
2
-
3
1
  type DelayedPromise<T> = Promise<T>;
4
2
 
5
3
  export function delay<T>(t: number, val: T): DelayedPromise<T> {
@@ -1,17 +0,0 @@
1
- /**
2
- * Does anyone have a cleaner way of doing this?
3
- * I want to import all the components in this folder
4
- * Feels a little dumb I'm doing this manually.
5
- */
6
-
7
- import './audio/audio'
8
- import './canvas/canvas'
9
- import './fonts/fonts'
10
- import './hardware/hardware'
11
- import './locales/locales'
12
- import './permissions/permissions'
13
- import './plugins/plugins'
14
- import './screen/screen'
15
- import './system/system'
16
- import './webgl/webgl'
17
- import './math/math'
@@ -1,39 +0,0 @@
1
- import { componentInterface, includeComponent } from '../../factory'
2
-
3
- const getMathInfo = async (): Promise<componentInterface> => {
4
- return {
5
- acos: Math.acos(0.5),
6
- asin: integrate(Math.asin, -1, 1, 97),
7
- atan: integrate(Math.atan, -1, 1, 97),
8
- cos: integrate(Math.cos, 0, Math.PI, 97),
9
- cosh: Math.cosh(9/7),
10
- e: Math.E,
11
- largeCos: Math.cos(1e20),
12
- largeSin: Math.sin(1e20),
13
- largeTan: Math.tan(1e20),
14
- log: Math.log(1000),
15
- pi: Math.PI,
16
- sin: integrate(Math.sin, -Math.PI, Math.PI, 97),
17
- sinh: integrate(Math.sinh, -9/7, 7/9, 97),
18
- sqrt: Math.sqrt(2),
19
- tan: integrate(Math.tan, 0, 2 * Math.PI, 97),
20
- tanh: integrate(Math.tanh, -9/7, 7/9, 97),
21
- }
22
- }
23
-
24
- /** This might be a little excessive, but I wasn't sure what number to pick for some of the
25
- * trigonometric functions. Using an integral here, so a few numbers are calculated. However,
26
- * I do this mainly for those integrals that sum up to a small value, otherwise there's no point.
27
- */
28
-
29
- const integrate = (f: (x: number) => number, a: number, b: number, n: number): number => {
30
- const h = (b - a) / n;
31
- let sum = 0;
32
- for (let i = 0; i < n; i++) {
33
- const x = a + (i + 0.5) * h;
34
- sum += f(x);
35
- }
36
- return sum * h;
37
- };
38
-
39
- includeComponent('math', getMathInfo);