@tracetail/react 2.3.13 → 2.3.15

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/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import type { FC, ReactNode } from 'react';
9
9
  import { FingerprintOptions, FingerprintResult } from '@tracetail/js';
10
+ import type { ComplianceContext } from '@tracetail/js';
10
11
  export interface UseTraceTailOptions extends FingerprintOptions {
11
12
  immediate?: boolean;
12
13
  suspense?: boolean;
@@ -70,8 +71,35 @@ export declare function useVisitorId(options: UseTraceTailOptions & {
70
71
  error: Error | null;
71
72
  refresh: () => Promise<void>;
72
73
  };
73
- export type { FingerprintOptions, FingerprintResult, ComponentData } from '@tracetail/js';
74
- export { TraceTail } from '@tracetail/js';
74
+ /**
75
+ * React hook returning client-side privacy / region compliance signals.
76
+ *
77
+ * The context is computed ONCE on mount (the underlying signals — timezone,
78
+ * locale, GPC, DNT — do not change during a session) and memoized for the
79
+ * lifetime of the component. SSR-safe: during server render it returns the same
80
+ * safe defaults as `getComplianceContext()`.
81
+ *
82
+ * These are CLIENT-SIDE HEURISTICS, not authoritative geolocation, and do NOT
83
+ * gate or alter fingerprint collection. Use `likelyRequiresConsent` together
84
+ * with your own consent state to decide whether to collect a fingerprint —
85
+ * obtaining consent where required (EU ePrivacy/GDPR, UK PECR, etc.) is the
86
+ * merchant's responsibility.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * import { useComplianceContext, useTraceTail } from '@tracetail/react';
91
+ *
92
+ * function Tracker({ hasConsent }: { hasConsent: boolean }) {
93
+ * const compliance = useComplianceContext();
94
+ * const shouldCollect = !compliance.likelyRequiresConsent || hasConsent;
95
+ * const { fingerprint } = useTraceTail({ immediate: shouldCollect });
96
+ * return shouldCollect ? <span>{fingerprint?.visitorId}</span> : null;
97
+ * }
98
+ * ```
99
+ */
100
+ export declare function useComplianceContext(): ComplianceContext;
101
+ export type { FingerprintOptions, FingerprintResult, ComponentData, ComplianceContext, ComplianceRegion } from '@tracetail/js';
102
+ export { TraceTail, getComplianceContext } from '@tracetail/js';
75
103
  interface TraceTailProviderProps {
76
104
  children: ReactNode;
77
105
  apiKey: string;
@@ -85,6 +113,7 @@ export declare const getVersion: () => string;
85
113
  declare const _default: {
86
114
  useTraceTail: typeof useTraceTail;
87
115
  useVisitorId: typeof useVisitorId;
116
+ useComplianceContext: typeof useComplianceContext;
88
117
  TraceTailProvider: FC<TraceTailProviderProps>;
89
118
  getVersion: () => string;
90
119
  };
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, Fragment } from 'react/jsx-runtime';
2
- import { useState, useRef, useEffect, useCallback } from 'react';
3
- import { TraceTail } from '@tracetail/js';
4
- export { TraceTail } from '@tracetail/js';
2
+ import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
3
+ import { TraceTail, getComplianceContext } from '@tracetail/js';
4
+ export { TraceTail, getComplianceContext } from '@tracetail/js';
5
5
 
6
6
  /**
7
7
  * React hook for basic browser fingerprinting
@@ -131,6 +131,38 @@ function useVisitorId(options) {
131
131
  refresh
132
132
  };
133
133
  }
134
+ /**
135
+ * React hook returning client-side privacy / region compliance signals.
136
+ *
137
+ * The context is computed ONCE on mount (the underlying signals — timezone,
138
+ * locale, GPC, DNT — do not change during a session) and memoized for the
139
+ * lifetime of the component. SSR-safe: during server render it returns the same
140
+ * safe defaults as `getComplianceContext()`.
141
+ *
142
+ * These are CLIENT-SIDE HEURISTICS, not authoritative geolocation, and do NOT
143
+ * gate or alter fingerprint collection. Use `likelyRequiresConsent` together
144
+ * with your own consent state to decide whether to collect a fingerprint —
145
+ * obtaining consent where required (EU ePrivacy/GDPR, UK PECR, etc.) is the
146
+ * merchant's responsibility.
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * import { useComplianceContext, useTraceTail } from '@tracetail/react';
151
+ *
152
+ * function Tracker({ hasConsent }: { hasConsent: boolean }) {
153
+ * const compliance = useComplianceContext();
154
+ * const shouldCollect = !compliance.likelyRequiresConsent || hasConsent;
155
+ * const { fingerprint } = useTraceTail({ immediate: shouldCollect });
156
+ * return shouldCollect ? <span>{fingerprint?.visitorId}</span> : null;
157
+ * }
158
+ * ```
159
+ */
160
+ function useComplianceContext() {
161
+ // Empty dependency list: compute once and keep the same reference for the
162
+ // component's lifetime. useMemo (rather than useState/useEffect) keeps the
163
+ // value available on the very first render, including during SSR.
164
+ return useMemo(() => getComplianceContext(), []);
165
+ }
134
166
  const TraceTailProvider = ({ children }) => {
135
167
  // This is a simple provider that could be extended with context
136
168
  // For now, it just renders children since hooks manage their own instances
@@ -144,9 +176,10 @@ const getVersion = () => '2.3.4';
144
176
  var index = {
145
177
  useTraceTail,
146
178
  useVisitorId,
179
+ useComplianceContext,
147
180
  TraceTailProvider,
148
181
  getVersion
149
182
  };
150
183
 
151
- export { TraceTailProvider, index as default, getVersion, useTraceTail, useVisitorId };
184
+ export { TraceTailProvider, index as default, getVersion, useComplianceContext, useTraceTail, useVisitorId };
152
185
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @tracetail/react - React Hooks for Enterprise Browser Fingerprinting\n * Version: 2.3.4\n *\n * Over 99.5% accuracy browser fingerprinting with React hooks and server-side processing.\n * Perfect for fraud detection, user analytics, and security applications.\n */\n\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport type { FC, ReactNode } from 'react';\nimport { TraceTail, FingerprintOptions, FingerprintResult } from '@tracetail/js';\n\nexport interface UseTraceTailOptions extends FingerprintOptions {\n immediate?: boolean;\n suspense?: boolean;\n}\n\nexport interface UseTraceTailReturn {\n fingerprint: FingerprintResult | null;\n loading: boolean;\n error: Error | null;\n generate: () => Promise<FingerprintResult>;\n regenerate: () => Promise<FingerprintResult>;\n}\n\n\n/**\n * React hook for basic browser fingerprinting\n * \n * @example\n * ```typescript\n * import { useTraceTail } from '@tracetail/react';\n * \n * function MyComponent() {\n * const { fingerprint, loading, error } = useTraceTail({\n * apiKey: 'your-api-key',\n * immediate: true\n * });\n * \n * if (loading) return <div>Generating fingerprint...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return <div>Visitor ID: {fingerprint?.visitorId}</div>;\n * }\n * ```\n */\nexport function useTraceTail(options: UseTraceTailOptions): UseTraceTailReturn {\n const [fingerprint, setFingerprint] = useState<FingerprintResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n \n const traceTailRef = useRef<TraceTail | null>(null);\n \n // Initialize TraceTail instance\n useEffect(() => {\n if (!traceTailRef.current) {\n traceTailRef.current = new TraceTail(options);\n }\n }, [options.apiKey, options.endpoint]);\n\n const generate = useCallback(async (): Promise<FingerprintResult> => {\n if (!traceTailRef.current) {\n throw new Error('TraceTail not initialized');\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await traceTailRef.current.generateFingerprint({\n verbose: true\n });\n setFingerprint(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n throw error;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const regenerate = useCallback(async (): Promise<FingerprintResult> => {\n setFingerprint(null);\n return generate();\n }, [generate]);\n\n // Auto-generate on mount if immediate is true\n useEffect(() => {\n if (options.immediate && !fingerprint && !loading) {\n generate().catch(() => {\n // Error is already handled in generate function\n });\n }\n }, [options.immediate, fingerprint, loading, generate]);\n\n return {\n fingerprint,\n loading,\n error,\n generate,\n regenerate\n };\n}\n\n\n/**\n * React hook for visitor identification with persistent storage\n * \n * @example\n * ```typescript\n * import { useVisitorId } from '@tracetail/react';\n * \n * function UserTrackingComponent() {\n * const { visitorId, isReturningVisitor, loading } = useVisitorId({\n * apiKey: 'your-api-key',\n * storageKey: 'app_visitor_id'\n * });\n * \n * return (\n * <div>\n * <p>Visitor: {visitorId}</p>\n * <p>Status: {isReturningVisitor ? 'Returning' : 'New'} visitor</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useVisitorId(options: UseTraceTailOptions & {\n storageKey?: string;\n}): {\n visitorId: string | null;\n isReturningVisitor: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n} {\n const storageKey = options.storageKey || 'tracetail_visitor_id';\n const [visitorId, setVisitorId] = useState<string | null>(null);\n const [isReturningVisitor, setIsReturningVisitor] = useState(false);\n \n const { fingerprint, loading, error, generate } = useTraceTail({\n ...options,\n immediate: true\n });\n\n // Update visitor ID when fingerprint changes\n useEffect(() => {\n if (fingerprint?.visitorId) {\n const storedVisitorId = localStorage.getItem(storageKey);\n \n if (storedVisitorId) {\n setIsReturningVisitor(storedVisitorId === fingerprint.visitorId);\n } else {\n setIsReturningVisitor(false);\n }\n \n setVisitorId(fingerprint.visitorId);\n localStorage.setItem(storageKey, fingerprint.visitorId);\n }\n }, [fingerprint?.visitorId, storageKey]);\n\n const refresh = useCallback(async () => {\n await generate();\n }, [generate]);\n\n return {\n visitorId,\n isReturningVisitor,\n loading,\n error,\n refresh\n };\n}\n\n\n// Re-export types and utilities from the base package\nexport type {\n FingerprintOptions,\n FingerprintResult,\n ComponentData\n} from '@tracetail/js';\n\nexport { TraceTail } from '@tracetail/js';\n\n// React-specific utilities\ninterface TraceTailProviderProps {\n children: ReactNode;\n apiKey: string;\n options?: Partial<FingerprintOptions>;\n}\n\nexport const TraceTailProvider: FC<TraceTailProviderProps> = ({ children }) => {\n // This is a simple provider that could be extended with context\n // For now, it just renders children since hooks manage their own instances\n return <>{children}</>;\n};\n\n/**\n * Get the current React package version\n */\nexport const getVersion = (): string => '2.3.4';\n\n// Default export\nexport default {\n useTraceTail,\n useVisitorId,\n TraceTailProvider,\n getVersion\n};"],"names":["_jsx","_Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @tracetail/react - React Hooks for Enterprise Browser Fingerprinting\n * Version: 2.3.4\n *\n * Over 99.5% accuracy browser fingerprinting with React hooks and server-side processing.\n * Perfect for fraud detection, user analytics, and security applications.\n */\n\nimport { useEffect, useState, useCallback, useRef, useMemo } from 'react';\nimport type { FC, ReactNode } from 'react';\nimport {\n TraceTail,\n FingerprintOptions,\n FingerprintResult,\n getComplianceContext,\n} from '@tracetail/js';\nimport type { ComplianceContext } from '@tracetail/js';\n\nexport interface UseTraceTailOptions extends FingerprintOptions {\n immediate?: boolean;\n suspense?: boolean;\n}\n\nexport interface UseTraceTailReturn {\n fingerprint: FingerprintResult | null;\n loading: boolean;\n error: Error | null;\n generate: () => Promise<FingerprintResult>;\n regenerate: () => Promise<FingerprintResult>;\n}\n\n\n/**\n * React hook for basic browser fingerprinting\n * \n * @example\n * ```typescript\n * import { useTraceTail } from '@tracetail/react';\n * \n * function MyComponent() {\n * const { fingerprint, loading, error } = useTraceTail({\n * apiKey: 'your-api-key',\n * immediate: true\n * });\n * \n * if (loading) return <div>Generating fingerprint...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return <div>Visitor ID: {fingerprint?.visitorId}</div>;\n * }\n * ```\n */\nexport function useTraceTail(options: UseTraceTailOptions): UseTraceTailReturn {\n const [fingerprint, setFingerprint] = useState<FingerprintResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n \n const traceTailRef = useRef<TraceTail | null>(null);\n \n // Initialize TraceTail instance\n useEffect(() => {\n if (!traceTailRef.current) {\n traceTailRef.current = new TraceTail(options);\n }\n }, [options.apiKey, options.endpoint]);\n\n const generate = useCallback(async (): Promise<FingerprintResult> => {\n if (!traceTailRef.current) {\n throw new Error('TraceTail not initialized');\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await traceTailRef.current.generateFingerprint({\n verbose: true\n });\n setFingerprint(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n throw error;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const regenerate = useCallback(async (): Promise<FingerprintResult> => {\n setFingerprint(null);\n return generate();\n }, [generate]);\n\n // Auto-generate on mount if immediate is true\n useEffect(() => {\n if (options.immediate && !fingerprint && !loading) {\n generate().catch(() => {\n // Error is already handled in generate function\n });\n }\n }, [options.immediate, fingerprint, loading, generate]);\n\n return {\n fingerprint,\n loading,\n error,\n generate,\n regenerate\n };\n}\n\n\n/**\n * React hook for visitor identification with persistent storage\n * \n * @example\n * ```typescript\n * import { useVisitorId } from '@tracetail/react';\n * \n * function UserTrackingComponent() {\n * const { visitorId, isReturningVisitor, loading } = useVisitorId({\n * apiKey: 'your-api-key',\n * storageKey: 'app_visitor_id'\n * });\n * \n * return (\n * <div>\n * <p>Visitor: {visitorId}</p>\n * <p>Status: {isReturningVisitor ? 'Returning' : 'New'} visitor</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useVisitorId(options: UseTraceTailOptions & {\n storageKey?: string;\n}): {\n visitorId: string | null;\n isReturningVisitor: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n} {\n const storageKey = options.storageKey || 'tracetail_visitor_id';\n const [visitorId, setVisitorId] = useState<string | null>(null);\n const [isReturningVisitor, setIsReturningVisitor] = useState(false);\n \n const { fingerprint, loading, error, generate } = useTraceTail({\n ...options,\n immediate: true\n });\n\n // Update visitor ID when fingerprint changes\n useEffect(() => {\n if (fingerprint?.visitorId) {\n const storedVisitorId = localStorage.getItem(storageKey);\n \n if (storedVisitorId) {\n setIsReturningVisitor(storedVisitorId === fingerprint.visitorId);\n } else {\n setIsReturningVisitor(false);\n }\n \n setVisitorId(fingerprint.visitorId);\n localStorage.setItem(storageKey, fingerprint.visitorId);\n }\n }, [fingerprint?.visitorId, storageKey]);\n\n const refresh = useCallback(async () => {\n await generate();\n }, [generate]);\n\n return {\n visitorId,\n isReturningVisitor,\n loading,\n error,\n refresh\n };\n}\n\n\n/**\n * React hook returning client-side privacy / region compliance signals.\n *\n * The context is computed ONCE on mount (the underlying signals — timezone,\n * locale, GPC, DNT — do not change during a session) and memoized for the\n * lifetime of the component. SSR-safe: during server render it returns the same\n * safe defaults as `getComplianceContext()`.\n *\n * These are CLIENT-SIDE HEURISTICS, not authoritative geolocation, and do NOT\n * gate or alter fingerprint collection. Use `likelyRequiresConsent` together\n * with your own consent state to decide whether to collect a fingerprint —\n * obtaining consent where required (EU ePrivacy/GDPR, UK PECR, etc.) is the\n * merchant's responsibility.\n *\n * @example\n * ```typescript\n * import { useComplianceContext, useTraceTail } from '@tracetail/react';\n *\n * function Tracker({ hasConsent }: { hasConsent: boolean }) {\n * const compliance = useComplianceContext();\n * const shouldCollect = !compliance.likelyRequiresConsent || hasConsent;\n * const { fingerprint } = useTraceTail({ immediate: shouldCollect });\n * return shouldCollect ? <span>{fingerprint?.visitorId}</span> : null;\n * }\n * ```\n */\nexport function useComplianceContext(): ComplianceContext {\n // Empty dependency list: compute once and keep the same reference for the\n // component's lifetime. useMemo (rather than useState/useEffect) keeps the\n // value available on the very first render, including during SSR.\n return useMemo(() => getComplianceContext(), []);\n}\n\n// Re-export types and utilities from the base package\nexport type {\n FingerprintOptions,\n FingerprintResult,\n ComponentData,\n ComplianceContext,\n ComplianceRegion\n} from '@tracetail/js';\n\nexport { TraceTail, getComplianceContext } from '@tracetail/js';\n\n// React-specific utilities\ninterface TraceTailProviderProps {\n children: ReactNode;\n apiKey: string;\n options?: Partial<FingerprintOptions>;\n}\n\nexport const TraceTailProvider: FC<TraceTailProviderProps> = ({ children }) => {\n // This is a simple provider that could be extended with context\n // For now, it just renders children since hooks manage their own instances\n return <>{children}</>;\n};\n\n/**\n * Get the current React package version\n */\nexport const getVersion = (): string => '2.3.4';\n\n// Default export\nexport default {\n useTraceTail,\n useVisitorId,\n useComplianceContext,\n TraceTailProvider,\n getVersion\n};"],"names":["_jsx","_Fragment"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -134,6 +134,38 @@ function useVisitorId(options) {
134
134
  refresh
135
135
  };
136
136
  }
137
+ /**
138
+ * React hook returning client-side privacy / region compliance signals.
139
+ *
140
+ * The context is computed ONCE on mount (the underlying signals — timezone,
141
+ * locale, GPC, DNT — do not change during a session) and memoized for the
142
+ * lifetime of the component. SSR-safe: during server render it returns the same
143
+ * safe defaults as `getComplianceContext()`.
144
+ *
145
+ * These are CLIENT-SIDE HEURISTICS, not authoritative geolocation, and do NOT
146
+ * gate or alter fingerprint collection. Use `likelyRequiresConsent` together
147
+ * with your own consent state to decide whether to collect a fingerprint —
148
+ * obtaining consent where required (EU ePrivacy/GDPR, UK PECR, etc.) is the
149
+ * merchant's responsibility.
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * import { useComplianceContext, useTraceTail } from '@tracetail/react';
154
+ *
155
+ * function Tracker({ hasConsent }: { hasConsent: boolean }) {
156
+ * const compliance = useComplianceContext();
157
+ * const shouldCollect = !compliance.likelyRequiresConsent || hasConsent;
158
+ * const { fingerprint } = useTraceTail({ immediate: shouldCollect });
159
+ * return shouldCollect ? <span>{fingerprint?.visitorId}</span> : null;
160
+ * }
161
+ * ```
162
+ */
163
+ function useComplianceContext() {
164
+ // Empty dependency list: compute once and keep the same reference for the
165
+ // component's lifetime. useMemo (rather than useState/useEffect) keeps the
166
+ // value available on the very first render, including during SSR.
167
+ return react.useMemo(() => js.getComplianceContext(), []);
168
+ }
137
169
  const TraceTailProvider = ({ children }) => {
138
170
  // This is a simple provider that could be extended with context
139
171
  // For now, it just renders children since hooks manage their own instances
@@ -147,6 +179,7 @@ const getVersion = () => '2.3.4';
147
179
  var index = {
148
180
  useTraceTail,
149
181
  useVisitorId,
182
+ useComplianceContext,
150
183
  TraceTailProvider,
151
184
  getVersion
152
185
  };
@@ -155,9 +188,14 @@ Object.defineProperty(exports, "TraceTail", {
155
188
  enumerable: true,
156
189
  get: function () { return js.TraceTail; }
157
190
  });
191
+ Object.defineProperty(exports, "getComplianceContext", {
192
+ enumerable: true,
193
+ get: function () { return js.getComplianceContext; }
194
+ });
158
195
  exports.TraceTailProvider = TraceTailProvider;
159
196
  exports.default = index;
160
197
  exports.getVersion = getVersion;
198
+ exports.useComplianceContext = useComplianceContext;
161
199
  exports.useTraceTail = useTraceTail;
162
200
  exports.useVisitorId = useVisitorId;
163
201
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @tracetail/react - React Hooks for Enterprise Browser Fingerprinting\n * Version: 2.3.4\n *\n * Over 99.5% accuracy browser fingerprinting with React hooks and server-side processing.\n * Perfect for fraud detection, user analytics, and security applications.\n */\n\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport type { FC, ReactNode } from 'react';\nimport { TraceTail, FingerprintOptions, FingerprintResult } from '@tracetail/js';\n\nexport interface UseTraceTailOptions extends FingerprintOptions {\n immediate?: boolean;\n suspense?: boolean;\n}\n\nexport interface UseTraceTailReturn {\n fingerprint: FingerprintResult | null;\n loading: boolean;\n error: Error | null;\n generate: () => Promise<FingerprintResult>;\n regenerate: () => Promise<FingerprintResult>;\n}\n\n\n/**\n * React hook for basic browser fingerprinting\n * \n * @example\n * ```typescript\n * import { useTraceTail } from '@tracetail/react';\n * \n * function MyComponent() {\n * const { fingerprint, loading, error } = useTraceTail({\n * apiKey: 'your-api-key',\n * immediate: true\n * });\n * \n * if (loading) return <div>Generating fingerprint...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return <div>Visitor ID: {fingerprint?.visitorId}</div>;\n * }\n * ```\n */\nexport function useTraceTail(options: UseTraceTailOptions): UseTraceTailReturn {\n const [fingerprint, setFingerprint] = useState<FingerprintResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n \n const traceTailRef = useRef<TraceTail | null>(null);\n \n // Initialize TraceTail instance\n useEffect(() => {\n if (!traceTailRef.current) {\n traceTailRef.current = new TraceTail(options);\n }\n }, [options.apiKey, options.endpoint]);\n\n const generate = useCallback(async (): Promise<FingerprintResult> => {\n if (!traceTailRef.current) {\n throw new Error('TraceTail not initialized');\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await traceTailRef.current.generateFingerprint({\n verbose: true\n });\n setFingerprint(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n throw error;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const regenerate = useCallback(async (): Promise<FingerprintResult> => {\n setFingerprint(null);\n return generate();\n }, [generate]);\n\n // Auto-generate on mount if immediate is true\n useEffect(() => {\n if (options.immediate && !fingerprint && !loading) {\n generate().catch(() => {\n // Error is already handled in generate function\n });\n }\n }, [options.immediate, fingerprint, loading, generate]);\n\n return {\n fingerprint,\n loading,\n error,\n generate,\n regenerate\n };\n}\n\n\n/**\n * React hook for visitor identification with persistent storage\n * \n * @example\n * ```typescript\n * import { useVisitorId } from '@tracetail/react';\n * \n * function UserTrackingComponent() {\n * const { visitorId, isReturningVisitor, loading } = useVisitorId({\n * apiKey: 'your-api-key',\n * storageKey: 'app_visitor_id'\n * });\n * \n * return (\n * <div>\n * <p>Visitor: {visitorId}</p>\n * <p>Status: {isReturningVisitor ? 'Returning' : 'New'} visitor</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useVisitorId(options: UseTraceTailOptions & {\n storageKey?: string;\n}): {\n visitorId: string | null;\n isReturningVisitor: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n} {\n const storageKey = options.storageKey || 'tracetail_visitor_id';\n const [visitorId, setVisitorId] = useState<string | null>(null);\n const [isReturningVisitor, setIsReturningVisitor] = useState(false);\n \n const { fingerprint, loading, error, generate } = useTraceTail({\n ...options,\n immediate: true\n });\n\n // Update visitor ID when fingerprint changes\n useEffect(() => {\n if (fingerprint?.visitorId) {\n const storedVisitorId = localStorage.getItem(storageKey);\n \n if (storedVisitorId) {\n setIsReturningVisitor(storedVisitorId === fingerprint.visitorId);\n } else {\n setIsReturningVisitor(false);\n }\n \n setVisitorId(fingerprint.visitorId);\n localStorage.setItem(storageKey, fingerprint.visitorId);\n }\n }, [fingerprint?.visitorId, storageKey]);\n\n const refresh = useCallback(async () => {\n await generate();\n }, [generate]);\n\n return {\n visitorId,\n isReturningVisitor,\n loading,\n error,\n refresh\n };\n}\n\n\n// Re-export types and utilities from the base package\nexport type {\n FingerprintOptions,\n FingerprintResult,\n ComponentData\n} from '@tracetail/js';\n\nexport { TraceTail } from '@tracetail/js';\n\n// React-specific utilities\ninterface TraceTailProviderProps {\n children: ReactNode;\n apiKey: string;\n options?: Partial<FingerprintOptions>;\n}\n\nexport const TraceTailProvider: FC<TraceTailProviderProps> = ({ children }) => {\n // This is a simple provider that could be extended with context\n // For now, it just renders children since hooks manage their own instances\n return <>{children}</>;\n};\n\n/**\n * Get the current React package version\n */\nexport const getVersion = (): string => '2.3.4';\n\n// Default export\nexport default {\n useTraceTail,\n useVisitorId,\n TraceTailProvider,\n getVersion\n};"],"names":["useState","useRef","useEffect","TraceTail","useCallback","_jsx","_Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @tracetail/react - React Hooks for Enterprise Browser Fingerprinting\n * Version: 2.3.4\n *\n * Over 99.5% accuracy browser fingerprinting with React hooks and server-side processing.\n * Perfect for fraud detection, user analytics, and security applications.\n */\n\nimport { useEffect, useState, useCallback, useRef, useMemo } from 'react';\nimport type { FC, ReactNode } from 'react';\nimport {\n TraceTail,\n FingerprintOptions,\n FingerprintResult,\n getComplianceContext,\n} from '@tracetail/js';\nimport type { ComplianceContext } from '@tracetail/js';\n\nexport interface UseTraceTailOptions extends FingerprintOptions {\n immediate?: boolean;\n suspense?: boolean;\n}\n\nexport interface UseTraceTailReturn {\n fingerprint: FingerprintResult | null;\n loading: boolean;\n error: Error | null;\n generate: () => Promise<FingerprintResult>;\n regenerate: () => Promise<FingerprintResult>;\n}\n\n\n/**\n * React hook for basic browser fingerprinting\n * \n * @example\n * ```typescript\n * import { useTraceTail } from '@tracetail/react';\n * \n * function MyComponent() {\n * const { fingerprint, loading, error } = useTraceTail({\n * apiKey: 'your-api-key',\n * immediate: true\n * });\n * \n * if (loading) return <div>Generating fingerprint...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return <div>Visitor ID: {fingerprint?.visitorId}</div>;\n * }\n * ```\n */\nexport function useTraceTail(options: UseTraceTailOptions): UseTraceTailReturn {\n const [fingerprint, setFingerprint] = useState<FingerprintResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n \n const traceTailRef = useRef<TraceTail | null>(null);\n \n // Initialize TraceTail instance\n useEffect(() => {\n if (!traceTailRef.current) {\n traceTailRef.current = new TraceTail(options);\n }\n }, [options.apiKey, options.endpoint]);\n\n const generate = useCallback(async (): Promise<FingerprintResult> => {\n if (!traceTailRef.current) {\n throw new Error('TraceTail not initialized');\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await traceTailRef.current.generateFingerprint({\n verbose: true\n });\n setFingerprint(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n throw error;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const regenerate = useCallback(async (): Promise<FingerprintResult> => {\n setFingerprint(null);\n return generate();\n }, [generate]);\n\n // Auto-generate on mount if immediate is true\n useEffect(() => {\n if (options.immediate && !fingerprint && !loading) {\n generate().catch(() => {\n // Error is already handled in generate function\n });\n }\n }, [options.immediate, fingerprint, loading, generate]);\n\n return {\n fingerprint,\n loading,\n error,\n generate,\n regenerate\n };\n}\n\n\n/**\n * React hook for visitor identification with persistent storage\n * \n * @example\n * ```typescript\n * import { useVisitorId } from '@tracetail/react';\n * \n * function UserTrackingComponent() {\n * const { visitorId, isReturningVisitor, loading } = useVisitorId({\n * apiKey: 'your-api-key',\n * storageKey: 'app_visitor_id'\n * });\n * \n * return (\n * <div>\n * <p>Visitor: {visitorId}</p>\n * <p>Status: {isReturningVisitor ? 'Returning' : 'New'} visitor</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useVisitorId(options: UseTraceTailOptions & {\n storageKey?: string;\n}): {\n visitorId: string | null;\n isReturningVisitor: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n} {\n const storageKey = options.storageKey || 'tracetail_visitor_id';\n const [visitorId, setVisitorId] = useState<string | null>(null);\n const [isReturningVisitor, setIsReturningVisitor] = useState(false);\n \n const { fingerprint, loading, error, generate } = useTraceTail({\n ...options,\n immediate: true\n });\n\n // Update visitor ID when fingerprint changes\n useEffect(() => {\n if (fingerprint?.visitorId) {\n const storedVisitorId = localStorage.getItem(storageKey);\n \n if (storedVisitorId) {\n setIsReturningVisitor(storedVisitorId === fingerprint.visitorId);\n } else {\n setIsReturningVisitor(false);\n }\n \n setVisitorId(fingerprint.visitorId);\n localStorage.setItem(storageKey, fingerprint.visitorId);\n }\n }, [fingerprint?.visitorId, storageKey]);\n\n const refresh = useCallback(async () => {\n await generate();\n }, [generate]);\n\n return {\n visitorId,\n isReturningVisitor,\n loading,\n error,\n refresh\n };\n}\n\n\n/**\n * React hook returning client-side privacy / region compliance signals.\n *\n * The context is computed ONCE on mount (the underlying signals — timezone,\n * locale, GPC, DNT — do not change during a session) and memoized for the\n * lifetime of the component. SSR-safe: during server render it returns the same\n * safe defaults as `getComplianceContext()`.\n *\n * These are CLIENT-SIDE HEURISTICS, not authoritative geolocation, and do NOT\n * gate or alter fingerprint collection. Use `likelyRequiresConsent` together\n * with your own consent state to decide whether to collect a fingerprint —\n * obtaining consent where required (EU ePrivacy/GDPR, UK PECR, etc.) is the\n * merchant's responsibility.\n *\n * @example\n * ```typescript\n * import { useComplianceContext, useTraceTail } from '@tracetail/react';\n *\n * function Tracker({ hasConsent }: { hasConsent: boolean }) {\n * const compliance = useComplianceContext();\n * const shouldCollect = !compliance.likelyRequiresConsent || hasConsent;\n * const { fingerprint } = useTraceTail({ immediate: shouldCollect });\n * return shouldCollect ? <span>{fingerprint?.visitorId}</span> : null;\n * }\n * ```\n */\nexport function useComplianceContext(): ComplianceContext {\n // Empty dependency list: compute once and keep the same reference for the\n // component's lifetime. useMemo (rather than useState/useEffect) keeps the\n // value available on the very first render, including during SSR.\n return useMemo(() => getComplianceContext(), []);\n}\n\n// Re-export types and utilities from the base package\nexport type {\n FingerprintOptions,\n FingerprintResult,\n ComponentData,\n ComplianceContext,\n ComplianceRegion\n} from '@tracetail/js';\n\nexport { TraceTail, getComplianceContext } from '@tracetail/js';\n\n// React-specific utilities\ninterface TraceTailProviderProps {\n children: ReactNode;\n apiKey: string;\n options?: Partial<FingerprintOptions>;\n}\n\nexport const TraceTailProvider: FC<TraceTailProviderProps> = ({ children }) => {\n // This is a simple provider that could be extended with context\n // For now, it just renders children since hooks manage their own instances\n return <>{children}</>;\n};\n\n/**\n * Get the current React package version\n */\nexport const getVersion = (): string => '2.3.4';\n\n// Default export\nexport default {\n useTraceTail,\n useVisitorId,\n useComplianceContext,\n TraceTailProvider,\n getVersion\n};"],"names":["useState","useRef","useEffect","TraceTail","useCallback","useMemo","getComplianceContext","_jsx","_Fragment"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tracetail/react",
3
- "version": "2.3.13",
3
+ "version": "2.3.15",
4
4
  "description": "React hooks for TraceTail enterprise browser fingerprinting with over 99.5% accuracy. TypeScript support and React 18 compatibility.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -52,7 +52,7 @@
52
52
  "react": ">=16.8.0"
53
53
  },
54
54
  "dependencies": {
55
- "@tracetail/js": "^2.3.13"
55
+ "@tracetail/js": "^2.3.15"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@rollup/plugin-typescript": "^11.1.6",