Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | 15x 15x 13x 13x 15x 13x 13x 13x 13x 13x 13x 13x 13x 15x 15x 13x 13x 4x 13x 15x 15x 13x 13x 13x 15x 15x 15x 15x 9x 15x | import { PropsWithChildren, useCallback, useEffect, useMemo, useRef } from 'react'
import { FingerprintContext } from '../fingerprint-context'
import { Agent, GetOptions, start, StartOptions, default as Loader } from '@fingerprint/agent'
import * as packageInfo from '../../package.json'
import { isSSR } from '../ssr'
import { WithEnvironment } from './with-environment'
import type { EnvDetails } from '../env.types'
import { usePromiseStore } from '../utils/use-promise-store'
export interface FingerprintProviderOptions extends StartOptions {
/**
* If set to `true`, will force the agent to be rebuilt with the new options. Should be used with caution
* since it can be triggered too often (e.g. on every render) and negatively affect performance of the JS agent.
*/
forceRebuild?: boolean
}
/**
* @example
* ```jsx
* <FingerprintProvider
* apiKey="<your-fpjs-public-api-key>"
* >
* <MyApp />
* </FingerprintProvider>
* ```
*
* Provides the FpContext to its child components.
*
* @privateRemarks
* This is just a wrapper around the actual provider.
* For the implementation, see `ProviderWithEnv` component.
*/
export function FingerprintProvider(props: PropsWithChildren<FingerprintProviderOptions>) {
const propsWithEnv = props as PropsWithChildren<ProviderWithEnvProps>
return (
<WithEnvironment>
<ProviderWithEnv {...propsWithEnv} />
</WithEnvironment>
)
}
interface ProviderWithEnvProps extends FingerprintProviderOptions {
/**
* Contains details about the env we're currently running in (e.g. framework, version)
*/
env: EnvDetails
getOptions?: GetOptions
}
function isLoader(value: unknown): value is Pick<typeof Loader, 'start'> {
return typeof value === 'object' && value !== null && 'start' in value && typeof value.start === 'function'
}
function getCustomLoader(props: Record<string, unknown>) {
Iif ('customAgent' in props && isLoader(props.customAgent)) {
return props.customAgent
}
return undefined
}
function ProviderWithEnv({
children,
forceRebuild,
env,
getOptions,
...agentOptions
}: PropsWithChildren<ProviderWithEnvProps>) {
const createClient = useCallback(() => {
const customLoader = getCustomLoader(agentOptions)
let integrationInfo = `react-sdk/${packageInfo.version}`
Eif (env) {
const envInfo = env.version ? `${env.name}/${env.version}` : env.name
integrationInfo += `/${envInfo}`
}
const mergedIntegrationInfo = [...(agentOptions.integrationInfo || []), integrationInfo]
const startParams = {
...agentOptions,
integrationInfo: mergedIntegrationInfo,
}
return customLoader ? customLoader.start(startParams) : start(startParams)
}, [agentOptions, env])
const clientRef = useRef<Agent>()
const getClient = useCallback(() => {
Iif (isSSR()) {
throw new Error('FingerprintProvider client cannot be used in SSR')
}
if (!clientRef.current) {
clientRef.current = createClient()
}
return clientRef.current
}, [createClient])
const { doRequest } = usePromiseStore()
const getVisitorData = useCallback(
(options?: GetOptions) => {
const client = getClient()
const mergedOptions = {
...getOptions,
...options,
}
return doRequest(async () => client.get(mergedOptions), mergedOptions)
},
[doRequest, getClient, getOptions]
)
const contextValue = useMemo(() => {
return {
getVisitorData,
}
}, [getVisitorData])
useEffect(() => {
// By default, the client is always initialized once during the first render and won't be updated
// if the configuration changes. Use `forceRebuild` flag to disable this behaviour.
if (!clientRef.current || forceRebuild) {
clientRef.current = createClient()
}
}, [forceRebuild, agentOptions, getOptions, createClient])
return <FingerprintContext.Provider value={contextValue}>{children}</FingerprintContext.Provider>
}
|