@fingerprintjs/fingerprintjs-pro-react-native
Version:
Official React Native client for Fingerprint PRO. Best identification solution for React Native.
543 lines (534 loc) • 16.6 kB
JavaScript
/**
* FingerprintJS Pro React Native v3.3.1 - Copyright (c) FingerprintJS, Inc, 2025 (https://fingerprint.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
import { NativeModules } from 'react-native';
import React, { createContext, useState, useCallback, useRef, useEffect, useMemo, useContext } from 'react';
/**
* Something was wrong while building URL for identification request
*
* @group Errors
*/
class InvalidUrlError extends Error {
constructor(message) {
super(message);
this.name = 'InvalidURL';
}
}
/**
* Something was wrong with params while building URL for identification request
*
* @group Errors
*/
class InvalidURLParamsError extends Error {
constructor(message) {
super(message);
this.name = 'InvalidURLParams';
}
}
/**
* Unknown API error
*
* @group Errors
*/
class ApiError extends Error {
constructor(message) {
super(message);
this.name = 'ApiError';
}
}
/**
* Token is missing in the request
*
* @group Errors
*/
class ApiKeyRequiredError extends Error {
constructor(message) {
super(message);
this.name = 'ApiKeyRequiredError';
}
}
/**
* Wrong token
*
* @group Errors
*/
class ApiKeyNotFoundError extends Error {
constructor(message) {
super(message);
this.name = 'ApiKeyNotFoundError';
}
}
/**
* API token is outdated
*
* @group Errors
*/
class ApiKeyExpiredError extends Error {
constructor(message) {
super(message);
this.name = 'ApiKeyExpiredError';
}
}
/**
* Wrong request format (content, parameters)
*
* @group Errors
*/
class RequestCannotBeParsedError extends Error {
constructor(message) {
super(message);
this.name = 'RequestCannotBeParsedError';
}
}
/**
* Request failed
*
* @group Errors
*/
class FailedError extends Error {
constructor(message) {
super(message);
this.name = 'FailedError';
}
}
/**
* Server timeout
*
* @group Errors
*/
class RequestTimeoutError extends Error {
constructor(message) {
super(message);
this.name = 'RequestTimeoutError';
}
}
/**
* Request limit for token reached
*
* @group Errors
*/
class TooManyRequestError extends Error {
constructor(message) {
super(message);
this.name = 'TooManyRequestError';
}
}
/**
* Request Filtering deny origin
*
* @group Errors
*/
class OriginNotAvailableError extends Error {
constructor(message) {
super(message);
this.name = 'OriginNotAvailableError';
}
}
/**
* Request Filtering deny some headers
*
* @group Errors
*/
class HeaderRestrictedError extends Error {
constructor(message) {
super(message);
this.name = 'HeaderRestrictedError';
}
}
/**
* Request Filtering deny this hostname
*
* @group Errors
*/
class HostnameRestrictedError extends Error {
constructor(message) {
super(message);
this.name = 'HostnameRestrictedError';
}
}
/**
* Request Filtering deny crawlers
*
* @group Errors
*/
class NotAvailableForCrawlBotsError extends Error {
constructor(message) {
super(message);
this.name = 'NotAvailableForCrawlBotsError';
}
}
/**
* Request Filtering deny empty UA
*
* @group Errors
*/
class NotAvailableWithoutUAError extends Error {
constructor(message) {
super(message);
this.name = 'NotAvailableWithoutUAError';
}
}
/**
* API key does not match the selected region
*
* @group Errors
*/
class WrongRegionError extends Error {
constructor(message) {
super(message);
this.name = 'WrongRegionError';
}
}
/**
* Subscription is not active for the provided API key
*
* @group Errors
*/
class SubscriptionNotActiveError extends Error {
constructor(message) {
super(message);
this.name = 'SubscriptionNotActiveError';
}
}
/**
* Something wrong with used API version
*
* @group Errors
*/
class UnsupportedVersionError extends Error {
constructor(message) {
super(message);
this.name = 'UnsupportedVersionError';
}
}
/**
*
*
* @group Errors
*/
class InstallationMethodRestrictedError extends Error {
constructor(message) {
super(message);
this.name = 'InstallationMethodRestrictedError';
}
}
/**
* Error while parsing the response
*
* @group Errors
*/
class ResponseCannotBeParsedError extends Error {
constructor(message) {
super(message);
this.name = 'ResponseCannotBeParsedError';
}
}
/**
* Something wrong with network
*
* @group Errors
*/
class NetworkError extends Error {
constructor(message) {
super(message);
this.name = 'NetworkError';
}
}
/**
* Error while parsing JSON response
*
* @group Errors
*/
class JsonParsingError extends Error {
constructor(message) {
super(message);
this.name = 'JsonParsingError';
}
}
/**
* Bad response type
*
* @group Errors
*/
class InvalidResponseTypeError extends Error {
constructor(message) {
super(message);
this.name = 'InvalidResponseType';
}
}
/**
* Client-side timeout error
*
* @group Errors
*/
class ClientTimeoutError extends Error {
constructor(message) {
super(message);
this.name = 'ClientTimeoutError';
}
}
/**
* Other error
*
* @group Errors
*/
class UnknownError extends Error {
constructor(message) {
super(message);
this.name = 'UnknownError';
}
}
function unwrapError(error) {
const [errorType, ...errorMessageParts] = error.message.split(':');
const errorMessage = errorMessageParts.join(':');
switch (errorType) {
case 'InvalidURL':
return new InvalidUrlError(errorMessage);
case 'InvalidURLParams':
return new InvalidURLParamsError(errorMessage);
case 'ApiError':
return new ApiError(errorMessage);
// Api Errors block
case 'ApiKeyRequired':
case 'TokenRequired':
return new ApiKeyRequiredError(errorMessage);
case 'ApiKeyNotFound':
case 'TokenNotFound':
return new ApiKeyNotFoundError(errorMessage);
case 'ApiKeyExpired':
case 'TokenExpired':
return new ApiKeyExpiredError(errorMessage);
case 'RequestCannotBeParsed':
return new RequestCannotBeParsedError(errorMessage);
case 'Failed':
return new FailedError(errorMessage);
case 'RequestTimeout':
return new RequestTimeoutError(errorMessage);
case 'TooManyRequest':
return new TooManyRequestError(errorMessage);
case 'OriginNotAvailable':
return new OriginNotAvailableError(errorMessage);
case 'HeaderRestricted':
return new HeaderRestrictedError(errorMessage);
case 'HostnameRestricted':
return new HostnameRestrictedError(errorMessage);
case 'NotAvailableForCrawlBots':
return new NotAvailableForCrawlBotsError(errorMessage);
case 'NotAvailableWithoutUA':
return new NotAvailableWithoutUAError(errorMessage);
case 'WrongRegion':
return new WrongRegionError(errorMessage);
case 'SubscriptionNotActive':
return new SubscriptionNotActiveError(errorMessage);
case 'UnsupportedVersion':
return new UnsupportedVersionError(errorMessage);
case 'InstallationMethodRestricted':
return new InstallationMethodRestrictedError(errorMessage);
case 'ResponseCannotBeParsed':
return new ResponseCannotBeParsedError(errorMessage);
// end of API Errors block
case 'ClientTimeout':
return new ClientTimeoutError(errorMessage);
case 'NetworkError':
return new NetworkError(errorMessage);
case 'JsonParsingError':
return new JsonParsingError(errorMessage);
case 'InvalidResponseType':
return new InvalidResponseTypeError(errorMessage);
default:
return new UnknownError(error.message);
}
}
var version = "3.3.1";
/**
*
* @group API Client approach
*/
class FingerprintJsProAgent {
constructor({ apiKey, region, endpointUrl, fallbackEndpointUrls = [], extendedResponseFormat = false, requestOptions = {}, }) {
/**
* Initialises FingerprintJS Pro Agent with certain settings
*
* @param params
*/
this.requestOptions = {};
try {
NativeModules.RNFingerprintjsPro.configure(apiKey, region, endpointUrl, fallbackEndpointUrls, extendedResponseFormat, version);
this.requestOptions = requestOptions;
}
catch (e) {
console.error('RNFingerprintjsPro configure error: ', e);
}
}
/**
* Returns visitor identifier based on the request options {@link https://dev.fingerprint.com/docs/native-android-integration#get-the-visitor-identifier | more info in the documentation page}
*
* @param tags is a customer-provided value or an object that will be saved together with the analysis event and will be returned back to you in a webhook message or when you search for the visit in the server API. {@link https://dev.fingerprint.com/docs/js-agent#tag | more info in the documentation page}
* @param linkedId is a way of linking current analysis event with a custom identifier. This will allow you to filter visit information when using the Server API {@link https://dev.fingerprint.com/docs/js-agent#linkedid | more info in the documentation page}
* @param options is used to configure requests with different settings
*/
async getVisitorId(tags, linkedId, options) {
var _a;
try {
const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : this.requestOptions.timeout;
if (timeout != null) {
return await NativeModules.RNFingerprintjsPro.getVisitorIdWithTimeout(tags, linkedId, timeout);
}
return await NativeModules.RNFingerprintjsPro.getVisitorId(tags, linkedId);
}
catch (error) {
if (error instanceof Error) {
throw unwrapError(error);
}
else {
throw new UnknownError(String(error));
}
}
}
/**
* Returns visitor identification data based on the request options {@link https://dev.fingerprint.com/docs/native-android-integration#get-the-visitor-identifier | more info in the documentation page}
*
* Provide `extendedResponseFormat` option in the {@link constructor} to get response in the {@link https://dev.fingerprint.com/docs/native-android-integration#response-format | extended format}
*
* @param tags is a customer-provided value or an object that will be saved together with the analysis event and will be returned back to you in a webhook message or when you search for the visit in the server API. {@link https://dev.fingerprint.com/docs/js-agent#tag | more info in the documentation page}
* @param linkedId is a way of linking current analysis event with a custom identifier. This will allow you to filter visit information when using the Server API {@link https://dev.fingerprint.com/docs/js-agent#linkedid | more info in the documentation page}
* @param options is used to configure requests with different settings
*/
async getVisitorData(tags, linkedId, options) {
var _a;
try {
const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : this.requestOptions.timeout;
let visitorData;
if (timeout != null) {
visitorData = await NativeModules.RNFingerprintjsPro.getVisitorDataWithTimeout(tags, linkedId, timeout);
}
else {
visitorData = await NativeModules.RNFingerprintjsPro.getVisitorData(tags, linkedId);
}
const [requestId, confidenceScore, visitorDataJsonString, sealedResult] = visitorData;
const result = {
...JSON.parse(visitorDataJsonString),
requestId,
confidence: {
score: confidenceScore,
},
};
if (sealedResult) {
result['sealedResult'] = sealedResult;
}
return result;
}
catch (error) {
if (error instanceof Error) {
throw unwrapError(error);
}
else {
throw new UnknownError(String(error));
}
}
}
}
const stub = () => {
throw new Error('You forgot to wrap your component in <FingerprintJsProProvider>.');
};
const initialContext = {
visitorId: '',
getVisitorData: stub,
};
const FingerprintJsProContext = createContext(initialContext);
/**
* Provides the FingerprintJsProContext to its child components.
*
* @example
* ```jsx
* <FingerprintJsProProvider
* apiKey: 'your-fpjs-public-api-key'
* requestOptions: { timeout: 5000 } // Optional: Set a custom timeout in milliseconds
* >
* <MyApp />
* </FingerprintJsProProvider>
* ```
* @group Hooks approach
*/
function FingerprintJsProProvider({ children, ...fingerprintJsProAgentParams }) {
const [client, setClient] = useState(() => new FingerprintJsProAgent(fingerprintJsProAgentParams));
const [visitorId, updateVisitorId] = useState('');
const getVisitorData = useCallback(async (tags, linkedId, requestOptions) => {
const result = await client.getVisitorData(tags, linkedId, requestOptions);
updateVisitorId(result.visitorId);
return result;
}, [client]);
const firstRender = useRef(true);
useEffect(() => {
if (firstRender) {
firstRender.current = false;
}
else {
setClient(new FingerprintJsProAgent(fingerprintJsProAgentParams));
}
}, [fingerprintJsProAgentParams]);
const contextValue = useMemo(() => {
return {
visitorId,
getVisitorData,
};
}, [visitorId, getVisitorData]);
return React.createElement(FingerprintJsProContext.Provider, { value: contextValue }, children);
}
/**
* Use the `useVisitorData` hook in your components to perform identification requests with the FingerprintJS API.
*
* @example
* ```jsx
* const {
* // Request state
* isLoading,
* // Error info
* error,
* // Visitor info
* data,
* // A method to be called to initiate request
* getData,
* } = useVisitorData();
* ```
*
* @group Hooks approach
*/
function useVisitorData() {
const { getVisitorData } = useContext(FingerprintJsProContext);
const [state, setState] = useState({});
const getData = useCallback(async (tags, linkedId, options) => {
let result = null;
try {
setState((state) => ({ ...state, isLoading: true }));
result = await getVisitorData(tags, linkedId, options);
setState((state) => ({
...state,
data: result,
isLoading: false,
error: undefined,
}));
}
catch (error) {
setState((state) => ({
...state,
data: undefined,
error: error,
}));
}
finally {
setState((state) => (state.isLoading ? { ...state, isLoading: false } : state));
}
return result;
}, [getVisitorData]);
const { isLoading, data, error } = state;
return {
isLoading,
data,
error,
getData,
};
}
export { ApiError, ApiKeyExpiredError, ApiKeyNotFoundError, ApiKeyRequiredError, ClientTimeoutError, FailedError, FingerprintJsProAgent, FingerprintJsProProvider, HeaderRestrictedError, InstallationMethodRestrictedError, InvalidResponseTypeError, InvalidURLParamsError, InvalidUrlError, JsonParsingError, NetworkError, NotAvailableForCrawlBotsError, NotAvailableWithoutUAError, OriginNotAvailableError, RequestCannotBeParsedError, RequestTimeoutError, ResponseCannotBeParsedError, SubscriptionNotActiveError, TooManyRequestError, UnknownError, UnsupportedVersionError, WrongRegionError, useVisitorData };
//# sourceMappingURL=fpjs-pro-react-native.esm.js.map