UNPKG

@tracetail/react

Version:

React hooks for TraceTail enterprise browser fingerprinting with over 99.5% accuracy. TypeScript support and React 18 compatibility.

153 lines (150 loc) 4.67 kB
import { jsx, Fragment } from 'react/jsx-runtime'; import { useState, useRef, useEffect, useCallback } from 'react'; import { TraceTail } from '@tracetail/js'; export { TraceTail } from '@tracetail/js'; /** * React hook for basic browser fingerprinting * * @example * ```typescript * import { useTraceTail } from '@tracetail/react'; * * function MyComponent() { * const { fingerprint, loading, error } = useTraceTail({ * apiKey: 'your-api-key', * immediate: true * }); * * if (loading) return <div>Generating fingerprint...</div>; * if (error) return <div>Error: {error.message}</div>; * * return <div>Visitor ID: {fingerprint?.visitorId}</div>; * } * ``` */ function useTraceTail(options) { const [fingerprint, setFingerprint] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const traceTailRef = useRef(null); // Initialize TraceTail instance useEffect(() => { if (!traceTailRef.current) { traceTailRef.current = new TraceTail(options); } }, [options.apiKey, options.endpoint]); const generate = useCallback(async () => { if (!traceTailRef.current) { throw new Error('TraceTail not initialized'); } setLoading(true); setError(null); try { const result = await traceTailRef.current.generateFingerprint({ verbose: true }); setFingerprint(result); return result; } catch (err) { const error = err instanceof Error ? err : new Error('Unknown error'); setError(error); throw error; } finally { setLoading(false); } }, []); const regenerate = useCallback(async () => { setFingerprint(null); return generate(); }, [generate]); // Auto-generate on mount if immediate is true useEffect(() => { if (options.immediate && !fingerprint && !loading) { generate().catch(() => { // Error is already handled in generate function }); } }, [options.immediate, fingerprint, loading, generate]); return { fingerprint, loading, error, generate, regenerate }; } /** * React hook for visitor identification with persistent storage * * @example * ```typescript * import { useVisitorId } from '@tracetail/react'; * * function UserTrackingComponent() { * const { visitorId, isReturningVisitor, loading } = useVisitorId({ * apiKey: 'your-api-key', * storageKey: 'app_visitor_id' * }); * * return ( * <div> * <p>Visitor: {visitorId}</p> * <p>Status: {isReturningVisitor ? 'Returning' : 'New'} visitor</p> * </div> * ); * } * ``` */ function useVisitorId(options) { const storageKey = options.storageKey || 'tracetail_visitor_id'; const [visitorId, setVisitorId] = useState(null); const [isReturningVisitor, setIsReturningVisitor] = useState(false); const { fingerprint, loading, error, generate } = useTraceTail({ ...options, immediate: true }); // Update visitor ID when fingerprint changes useEffect(() => { if (fingerprint === null || fingerprint === void 0 ? void 0 : fingerprint.visitorId) { const storedVisitorId = localStorage.getItem(storageKey); if (storedVisitorId) { setIsReturningVisitor(storedVisitorId === fingerprint.visitorId); } else { setIsReturningVisitor(false); } setVisitorId(fingerprint.visitorId); localStorage.setItem(storageKey, fingerprint.visitorId); } }, [fingerprint === null || fingerprint === void 0 ? void 0 : fingerprint.visitorId, storageKey]); const refresh = useCallback(async () => { await generate(); }, [generate]); return { visitorId, isReturningVisitor, loading, error, refresh }; } const TraceTailProvider = ({ children }) => { // This is a simple provider that could be extended with context // For now, it just renders children since hooks manage their own instances return jsx(Fragment, { children: children }); }; /** * Get the current React package version */ const getVersion = () => '2.3.4'; // Default export var index = { useTraceTail, useVisitorId, TraceTailProvider, getVersion }; export { TraceTailProvider, index as default, getVersion, useTraceTail, useVisitorId }; //# sourceMappingURL=index.esm.js.map