usehuma 1.0.0

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.mjs ADDED
@@ -0,0 +1,148 @@
1
+ // src/core.ts
2
+ function cv(arr) {
3
+ if (arr.length < 2) return 0;
4
+ const mean = arr.reduce((a, b) => a + b, 0) / arr.length;
5
+ if (mean === 0) return 0;
6
+ const variance = arr.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / arr.length;
7
+ return Math.sqrt(variance) / mean;
8
+ }
9
+ function mouseFeatures(pts) {
10
+ if (pts.length < 5) return { speed_cv: 0, direction_changes: 0, sample_count: 0 };
11
+ const speeds = [];
12
+ const directions = [];
13
+ for (let i = 1; i < pts.length; i++) {
14
+ const dx = pts[i].x - pts[i - 1].x;
15
+ const dy = pts[i].y - pts[i - 1].y;
16
+ const dt = Math.max(pts[i].t - pts[i - 1].t, 1);
17
+ speeds.push(Math.sqrt(dx * dx + dy * dy) / dt);
18
+ directions.push(Math.atan2(dy, dx));
19
+ }
20
+ let dirChanges = 0;
21
+ for (let j = 1; j < directions.length; j++) {
22
+ if (Math.abs(directions[j] - directions[j - 1]) > 0.3) dirChanges++;
23
+ }
24
+ return { speed_cv: cv(speeds), direction_changes: dirChanges, sample_count: pts.length };
25
+ }
26
+ var HumaCollector = class {
27
+ constructor() {
28
+ this.signals = {
29
+ mouse: [],
30
+ keys: [],
31
+ scrolls: [],
32
+ clicks: [],
33
+ focusEvents: [],
34
+ startTime: Date.now(),
35
+ lastKeyTime: null,
36
+ lastScrollTime: null
37
+ };
38
+ this.listening = false;
39
+ this.onMouseMove = (e) => {
40
+ if (this.signals.mouse.length < 200)
41
+ this.signals.mouse.push({ x: e.clientX, y: e.clientY, t: Date.now() });
42
+ };
43
+ this.onKeyDown = () => {
44
+ const now = Date.now();
45
+ if (this.signals.lastKeyTime !== null && this.signals.keys.length < 100)
46
+ this.signals.keys.push({ interval: now - this.signals.lastKeyTime });
47
+ this.signals.lastKeyTime = now;
48
+ };
49
+ this.onScroll = () => {
50
+ const now = Date.now();
51
+ if (this.signals.lastScrollTime !== null && this.signals.scrolls.length < 50)
52
+ this.signals.scrolls.push({ interval: now - this.signals.lastScrollTime });
53
+ this.signals.lastScrollTime = now;
54
+ };
55
+ this.onClick = () => {
56
+ if (this.signals.clicks.length < 50)
57
+ this.signals.clicks.push({ t: Date.now() });
58
+ };
59
+ this.onFocus = () => this.signals.focusEvents.push({ type: "focus", t: Date.now() });
60
+ this.onBlur = () => this.signals.focusEvents.push({ type: "blur", t: Date.now() });
61
+ }
62
+ start() {
63
+ if (this.listening || typeof window === "undefined") return;
64
+ this.listening = true;
65
+ document.addEventListener("mousemove", this.onMouseMove, { passive: true });
66
+ document.addEventListener("keydown", this.onKeyDown, { passive: true });
67
+ document.addEventListener("scroll", this.onScroll, { passive: true });
68
+ document.addEventListener("click", this.onClick, { passive: true });
69
+ window.addEventListener("focus", this.onFocus, { passive: true });
70
+ window.addEventListener("blur", this.onBlur, { passive: true });
71
+ }
72
+ stop() {
73
+ if (!this.listening) return;
74
+ this.listening = false;
75
+ document.removeEventListener("mousemove", this.onMouseMove);
76
+ document.removeEventListener("keydown", this.onKeyDown);
77
+ document.removeEventListener("scroll", this.onScroll);
78
+ document.removeEventListener("click", this.onClick);
79
+ window.removeEventListener("focus", this.onFocus);
80
+ window.removeEventListener("blur", this.onBlur);
81
+ }
82
+ extract() {
83
+ const { keys, scrolls, clicks, focusEvents, startTime, mouse } = this.signals;
84
+ const m = mouseFeatures(mouse);
85
+ const clickIntervals = [];
86
+ for (let i = 1; i < clicks.length; i++)
87
+ clickIntervals.push(clicks[i].t - clicks[i - 1].t);
88
+ return {
89
+ time_on_page_ms: Date.now() - startTime,
90
+ key_interval_cv: cv(keys.map((k) => k.interval)),
91
+ key_count: keys.length,
92
+ scroll_interval_cv: cv(scrolls.map((s) => s.interval)),
93
+ scroll_count: scrolls.length,
94
+ mouse_speed_cv: m.speed_cv,
95
+ mouse_direction_changes: m.direction_changes,
96
+ mouse_sample_count: m.sample_count,
97
+ click_interval_cv: cv(clickIntervals),
98
+ click_count: clicks.length,
99
+ tab_switches: focusEvents.length
100
+ };
101
+ }
102
+ debug() {
103
+ return { signals: this.signals, features: this.extract() };
104
+ }
105
+ };
106
+ async function callHumaApi(opts, sessionData) {
107
+ var _a;
108
+ const endpoint = (_a = opts.endpoint) != null ? _a : "https://humaverify.com/api/v1/verify";
109
+ const res = await fetch(endpoint, {
110
+ method: "POST",
111
+ headers: {
112
+ Authorization: `Bearer ${opts.apiKey}`,
113
+ "Content-Type": "application/json"
114
+ },
115
+ body: JSON.stringify({ userId: opts.userId, sessionData })
116
+ });
117
+ if (!res.ok) {
118
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
119
+ throw err;
120
+ }
121
+ return res.json();
122
+ }
123
+
124
+ // src/index.ts
125
+ var _globalCollector = null;
126
+ function init() {
127
+ if (typeof window === "undefined") return;
128
+ if (_globalCollector) return;
129
+ _globalCollector = new HumaCollector();
130
+ _globalCollector.start();
131
+ }
132
+ async function verify(opts) {
133
+ if (!_globalCollector) init();
134
+ const sessionData = _globalCollector.extract();
135
+ return callHumaApi(opts, sessionData);
136
+ }
137
+ function debug() {
138
+ var _a;
139
+ return (_a = _globalCollector == null ? void 0 : _globalCollector.debug()) != null ? _a : null;
140
+ }
141
+ export {
142
+ HumaCollector,
143
+ callHumaApi,
144
+ debug,
145
+ init,
146
+ verify
147
+ };
148
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts","../src/index.ts"],"sourcesContent":["/**\n * useHUMA — Core Signal Collector\n * Invisible behavioral biometrics — no PII collected.\n */\n\nimport type { SessionData, HumaVerifyResult, HumaError, HumaOptions } from \"./types\";\n\ntype MousePoint = { x: number; y: number; t: number };\ntype KeyEntry = { interval: number };\ntype ScrollEntry = { interval: number };\ntype ClickEntry = { t: number };\ntype FocusEvent = { type: \"focus\" | \"blur\"; t: number };\n\ninterface Signals {\n mouse: MousePoint[];\n keys: KeyEntry[];\n scrolls: ScrollEntry[];\n clicks: ClickEntry[];\n focusEvents: FocusEvent[];\n startTime: number;\n lastKeyTime: number | null;\n lastScrollTime: number | null;\n}\n\nfunction cv(arr: number[]): number {\n if (arr.length < 2) return 0;\n const mean = arr.reduce((a, b) => a + b, 0) / arr.length;\n if (mean === 0) return 0;\n const variance = arr.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / arr.length;\n return Math.sqrt(variance) / mean;\n}\n\nfunction mouseFeatures(pts: MousePoint[]) {\n if (pts.length < 5) return { speed_cv: 0, direction_changes: 0, sample_count: 0 };\n const speeds: number[] = [];\n const directions: number[] = [];\n for (let i = 1; i < pts.length; i++) {\n const dx = pts[i].x - pts[i - 1].x;\n const dy = pts[i].y - pts[i - 1].y;\n const dt = Math.max(pts[i].t - pts[i - 1].t, 1);\n speeds.push(Math.sqrt(dx * dx + dy * dy) / dt);\n directions.push(Math.atan2(dy, dx));\n }\n let dirChanges = 0;\n for (let j = 1; j < directions.length; j++) {\n if (Math.abs(directions[j] - directions[j - 1]) > 0.3) dirChanges++;\n }\n return { speed_cv: cv(speeds), direction_changes: dirChanges, sample_count: pts.length };\n}\n\nexport class HumaCollector {\n private signals: Signals = {\n mouse: [], keys: [], scrolls: [], clicks: [], focusEvents: [],\n startTime: Date.now(), lastKeyTime: null, lastScrollTime: null,\n };\n private listening = false;\n\n private onMouseMove = (e: MouseEvent) => {\n if (this.signals.mouse.length < 200)\n this.signals.mouse.push({ x: e.clientX, y: e.clientY, t: Date.now() });\n };\n private onKeyDown = () => {\n const now = Date.now();\n if (this.signals.lastKeyTime !== null && this.signals.keys.length < 100)\n this.signals.keys.push({ interval: now - this.signals.lastKeyTime });\n this.signals.lastKeyTime = now;\n };\n private onScroll = () => {\n const now = Date.now();\n if (this.signals.lastScrollTime !== null && this.signals.scrolls.length < 50)\n this.signals.scrolls.push({ interval: now - this.signals.lastScrollTime });\n this.signals.lastScrollTime = now;\n };\n private onClick = () => {\n if (this.signals.clicks.length < 50)\n this.signals.clicks.push({ t: Date.now() });\n };\n private onFocus = () => this.signals.focusEvents.push({ type: \"focus\", t: Date.now() });\n private onBlur = () => this.signals.focusEvents.push({ type: \"blur\", t: Date.now() });\n\n start() {\n if (this.listening || typeof window === \"undefined\") return;\n this.listening = true;\n document.addEventListener(\"mousemove\", this.onMouseMove, { passive: true });\n document.addEventListener(\"keydown\", this.onKeyDown, { passive: true });\n document.addEventListener(\"scroll\", this.onScroll, { passive: true });\n document.addEventListener(\"click\", this.onClick, { passive: true });\n window.addEventListener(\"focus\", this.onFocus, { passive: true });\n window.addEventListener(\"blur\", this.onBlur, { passive: true });\n }\n\n stop() {\n if (!this.listening) return;\n this.listening = false;\n document.removeEventListener(\"mousemove\", this.onMouseMove);\n document.removeEventListener(\"keydown\", this.onKeyDown);\n document.removeEventListener(\"scroll\", this.onScroll);\n document.removeEventListener(\"click\", this.onClick);\n window.removeEventListener(\"focus\", this.onFocus);\n window.removeEventListener(\"blur\", this.onBlur);\n }\n\n extract(): SessionData {\n const { keys, scrolls, clicks, focusEvents, startTime, mouse } = this.signals;\n const m = mouseFeatures(mouse);\n const clickIntervals: number[] = [];\n for (let i = 1; i < clicks.length; i++)\n clickIntervals.push(clicks[i].t - clicks[i - 1].t);\n return {\n time_on_page_ms: Date.now() - startTime,\n key_interval_cv: cv(keys.map(k => k.interval)),\n key_count: keys.length,\n scroll_interval_cv: cv(scrolls.map(s => s.interval)),\n scroll_count: scrolls.length,\n mouse_speed_cv: m.speed_cv,\n mouse_direction_changes: m.direction_changes,\n mouse_sample_count: m.sample_count,\n click_interval_cv: cv(clickIntervals),\n click_count: clicks.length,\n tab_switches: focusEvents.length,\n };\n }\n\n debug(): Record<string, unknown> {\n return { signals: this.signals as unknown, features: this.extract() };\n }\n}\n\n/** Send extracted signals to the HUMA API and return a result. */\nexport async function callHumaApi(\n opts: HumaOptions,\n sessionData: SessionData\n): Promise<HumaVerifyResult> {\n const endpoint = opts.endpoint ?? \"https://humaverify.com/api/v1/verify\";\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${opts.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ userId: opts.userId, sessionData }),\n });\n if (!res.ok) {\n const err: HumaError = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw err;\n }\n return res.json() as Promise<HumaVerifyResult>;\n}\n","/**\n * useHUMA JavaScript SDK\n * Privacy-first human verification — no PII, no Cloudflare dependency.\n * https://humaverify.com\n */\n\nexport { HumaCollector, callHumaApi } from \"./core\";\nexport type {\n SessionData,\n HumaVerifyResult,\n HumaError,\n HumaOptions,\n HumaState,\n} from \"./types\";\n\n/**\n * Vanilla JS verify — for non-React apps.\n *\n * @example\n * import { verify } from 'usehuma';\n *\n * const result = await verify({\n * apiKey: 'huma_live_...',\n * userId: 'user_123',\n * });\n * if (result.human) { ... }\n */\nimport { HumaCollector, callHumaApi } from \"./core\";\nimport type { HumaOptions, HumaVerifyResult } from \"./types\";\n\nlet _globalCollector: HumaCollector | null = null;\n\n/** Auto-start signal collection (call once, early in your app). */\nexport function init() {\n if (typeof window === \"undefined\") return;\n if (_globalCollector) return;\n _globalCollector = new HumaCollector();\n _globalCollector.start();\n}\n\n/**\n * Verify the current user as human using collected behavioral signals.\n * Calls init() automatically if not already started.\n */\nexport async function verify(opts: HumaOptions): Promise<HumaVerifyResult> {\n if (!_globalCollector) init();\n const sessionData = _globalCollector!.extract();\n return callHumaApi(opts, sessionData);\n}\n\n/** Get raw collected signals — useful for debugging. */\nexport function debug(): Record<string, unknown> | null {\n return _globalCollector?.debug() as Record<string, unknown> | null ?? null;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,157 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type HumaVerifyResult = {
5
+ human: boolean;
6
+ confidence: number;
7
+ threshold: number;
8
+ token: string;
9
+ pii_stored: false;
10
+ };
11
+ type HumaError = {
12
+ error: string;
13
+ code?: string;
14
+ upgrade_url?: string;
15
+ retry_after?: number;
16
+ };
17
+ type HumaOptions = {
18
+ /** Your HUMA API key (huma_live_...) */
19
+ apiKey: string;
20
+ /** Your internal user ID */
21
+ userId: string;
22
+ /** Override the API endpoint (default: https://humaverify.com/api/v1/verify) */
23
+ endpoint?: string;
24
+ };
25
+ type HumaState = {
26
+ loading: boolean;
27
+ result: HumaVerifyResult | null;
28
+ error: HumaError | null;
29
+ /** true = verified human, false = bot, null = not yet verified */
30
+ isHuman: boolean | null;
31
+ /** 0–100 confidence score */
32
+ score: number | null;
33
+ /** Call manually to trigger verification */
34
+ verify: () => Promise<HumaVerifyResult | null>;
35
+ };
36
+
37
+ /**
38
+ * Collect behavioral signals and verify a user as human.
39
+ *
40
+ * @example
41
+ * const { isHuman, score, loading, verify } = useHuma({
42
+ * apiKey: 'huma_live_...',
43
+ * userId: 'user_123',
44
+ * });
45
+ */
46
+ declare function useHuma(opts: HumaOptions): HumaState;
47
+ type HumaContextValue = HumaState & {
48
+ ready: boolean;
49
+ };
50
+ type HumaProviderProps = {
51
+ apiKey: string;
52
+ userId: string;
53
+ endpoint?: string;
54
+ /** Auto-verify on mount (default: false — call verify() manually) */
55
+ autoVerify?: boolean;
56
+ children: ReactNode;
57
+ };
58
+ /**
59
+ * Wrap your app (or a subtree) with HumaProvider so any child
60
+ * can call useHumaContext() without re-collecting signals.
61
+ *
62
+ * @example
63
+ * <HumaProvider apiKey="huma_live_..." userId={session.userId}>
64
+ * <App />
65
+ * </HumaProvider>
66
+ */
67
+ declare function HumaProvider({ apiKey, userId, endpoint, autoVerify, children }: HumaProviderProps): react_jsx_runtime.JSX.Element;
68
+ /**
69
+ * Access the shared HUMA state inside a HumaProvider.
70
+ */
71
+ declare function useHumaContext(): HumaContextValue;
72
+ type HumaGateProps = {
73
+ apiKey: string;
74
+ userId: string;
75
+ endpoint?: string;
76
+ /** Content to show while verifying */
77
+ fallback?: ReactNode;
78
+ /** Content to show if verification fails (bot detected) */
79
+ blocked?: ReactNode;
80
+ /** Auto-verify on mount (default: true) */
81
+ autoVerify?: boolean;
82
+ children: ReactNode;
83
+ };
84
+ /**
85
+ * Only renders children when the user is verified as human.
86
+ * Shows fallback while loading, blocked if bot detected.
87
+ *
88
+ * @example
89
+ * <HumaGate apiKey="huma_live_..." userId={userId} fallback={<Spinner />}>
90
+ * <SensitiveContent />
91
+ * </HumaGate>
92
+ */
93
+ declare function HumaGate({ apiKey, userId, endpoint, fallback, blocked, autoVerify, children, }: HumaGateProps): react_jsx_runtime.JSX.Element;
94
+ type SessionResult = {
95
+ score: number;
96
+ confidence: number;
97
+ baseline: number;
98
+ delta: number;
99
+ anomaly: boolean;
100
+ action: "allow" | "flag" | "block";
101
+ notes: string[];
102
+ };
103
+ type UseHumaSessionOptions = {
104
+ apiKey: string;
105
+ userId: string;
106
+ /** The token returned by verify() */
107
+ token: string;
108
+ /** Heartbeat interval in ms (default: 30000) */
109
+ intervalMs?: number;
110
+ /** Called when anomaly detected (score dropped or absolute bot) */
111
+ onAnomaly?: (result: SessionResult) => void;
112
+ endpoint?: string;
113
+ };
114
+ /**
115
+ * Continuously monitors an active session for bot behavior / account takeover.
116
+ * Start after a successful verify(). Sends heartbeats every 30s.
117
+ *
118
+ * @example
119
+ * const { lastResult, anomaly, stop } = useHumaSession({
120
+ * apiKey: 'huma_live_...',
121
+ * userId: 'user_123',
122
+ * token: verifyResult.token,
123
+ * onAnomaly: (r) => router.push('/logout'),
124
+ * });
125
+ */
126
+ declare function useHumaSession(opts: UseHumaSessionOptions): {
127
+ lastResult: SessionResult | null;
128
+ anomaly: boolean;
129
+ stop: () => void;
130
+ };
131
+ type HumaVerifyButtonProps = {
132
+ apiKey: string;
133
+ userId: string;
134
+ endpoint?: string;
135
+ onVerified?: (result: HumaVerifyResult) => void;
136
+ onBlocked?: () => void;
137
+ children?: ReactNode;
138
+ className?: string;
139
+ style?: React.CSSProperties;
140
+ };
141
+ /**
142
+ * A button that triggers behavioral verification on click.
143
+ * Useful for form submissions, checkout flows, sensitive actions.
144
+ *
145
+ * @example
146
+ * <HumaVerifyButton
147
+ * apiKey="huma_live_..."
148
+ * userId={userId}
149
+ * onVerified={(r) => console.log('Human!', r.confidence)}
150
+ * onBlocked={() => console.log('Bot detected')}
151
+ * >
152
+ * Submit
153
+ * </HumaVerifyButton>
154
+ */
155
+ declare function HumaVerifyButton({ apiKey, userId, endpoint, onVerified, onBlocked, children, className, style, }: HumaVerifyButtonProps): react_jsx_runtime.JSX.Element;
156
+
157
+ export { HumaGate, HumaProvider, HumaVerifyButton, useHuma, useHumaContext, useHumaSession };
@@ -0,0 +1,157 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type HumaVerifyResult = {
5
+ human: boolean;
6
+ confidence: number;
7
+ threshold: number;
8
+ token: string;
9
+ pii_stored: false;
10
+ };
11
+ type HumaError = {
12
+ error: string;
13
+ code?: string;
14
+ upgrade_url?: string;
15
+ retry_after?: number;
16
+ };
17
+ type HumaOptions = {
18
+ /** Your HUMA API key (huma_live_...) */
19
+ apiKey: string;
20
+ /** Your internal user ID */
21
+ userId: string;
22
+ /** Override the API endpoint (default: https://humaverify.com/api/v1/verify) */
23
+ endpoint?: string;
24
+ };
25
+ type HumaState = {
26
+ loading: boolean;
27
+ result: HumaVerifyResult | null;
28
+ error: HumaError | null;
29
+ /** true = verified human, false = bot, null = not yet verified */
30
+ isHuman: boolean | null;
31
+ /** 0–100 confidence score */
32
+ score: number | null;
33
+ /** Call manually to trigger verification */
34
+ verify: () => Promise<HumaVerifyResult | null>;
35
+ };
36
+
37
+ /**
38
+ * Collect behavioral signals and verify a user as human.
39
+ *
40
+ * @example
41
+ * const { isHuman, score, loading, verify } = useHuma({
42
+ * apiKey: 'huma_live_...',
43
+ * userId: 'user_123',
44
+ * });
45
+ */
46
+ declare function useHuma(opts: HumaOptions): HumaState;
47
+ type HumaContextValue = HumaState & {
48
+ ready: boolean;
49
+ };
50
+ type HumaProviderProps = {
51
+ apiKey: string;
52
+ userId: string;
53
+ endpoint?: string;
54
+ /** Auto-verify on mount (default: false — call verify() manually) */
55
+ autoVerify?: boolean;
56
+ children: ReactNode;
57
+ };
58
+ /**
59
+ * Wrap your app (or a subtree) with HumaProvider so any child
60
+ * can call useHumaContext() without re-collecting signals.
61
+ *
62
+ * @example
63
+ * <HumaProvider apiKey="huma_live_..." userId={session.userId}>
64
+ * <App />
65
+ * </HumaProvider>
66
+ */
67
+ declare function HumaProvider({ apiKey, userId, endpoint, autoVerify, children }: HumaProviderProps): react_jsx_runtime.JSX.Element;
68
+ /**
69
+ * Access the shared HUMA state inside a HumaProvider.
70
+ */
71
+ declare function useHumaContext(): HumaContextValue;
72
+ type HumaGateProps = {
73
+ apiKey: string;
74
+ userId: string;
75
+ endpoint?: string;
76
+ /** Content to show while verifying */
77
+ fallback?: ReactNode;
78
+ /** Content to show if verification fails (bot detected) */
79
+ blocked?: ReactNode;
80
+ /** Auto-verify on mount (default: true) */
81
+ autoVerify?: boolean;
82
+ children: ReactNode;
83
+ };
84
+ /**
85
+ * Only renders children when the user is verified as human.
86
+ * Shows fallback while loading, blocked if bot detected.
87
+ *
88
+ * @example
89
+ * <HumaGate apiKey="huma_live_..." userId={userId} fallback={<Spinner />}>
90
+ * <SensitiveContent />
91
+ * </HumaGate>
92
+ */
93
+ declare function HumaGate({ apiKey, userId, endpoint, fallback, blocked, autoVerify, children, }: HumaGateProps): react_jsx_runtime.JSX.Element;
94
+ type SessionResult = {
95
+ score: number;
96
+ confidence: number;
97
+ baseline: number;
98
+ delta: number;
99
+ anomaly: boolean;
100
+ action: "allow" | "flag" | "block";
101
+ notes: string[];
102
+ };
103
+ type UseHumaSessionOptions = {
104
+ apiKey: string;
105
+ userId: string;
106
+ /** The token returned by verify() */
107
+ token: string;
108
+ /** Heartbeat interval in ms (default: 30000) */
109
+ intervalMs?: number;
110
+ /** Called when anomaly detected (score dropped or absolute bot) */
111
+ onAnomaly?: (result: SessionResult) => void;
112
+ endpoint?: string;
113
+ };
114
+ /**
115
+ * Continuously monitors an active session for bot behavior / account takeover.
116
+ * Start after a successful verify(). Sends heartbeats every 30s.
117
+ *
118
+ * @example
119
+ * const { lastResult, anomaly, stop } = useHumaSession({
120
+ * apiKey: 'huma_live_...',
121
+ * userId: 'user_123',
122
+ * token: verifyResult.token,
123
+ * onAnomaly: (r) => router.push('/logout'),
124
+ * });
125
+ */
126
+ declare function useHumaSession(opts: UseHumaSessionOptions): {
127
+ lastResult: SessionResult | null;
128
+ anomaly: boolean;
129
+ stop: () => void;
130
+ };
131
+ type HumaVerifyButtonProps = {
132
+ apiKey: string;
133
+ userId: string;
134
+ endpoint?: string;
135
+ onVerified?: (result: HumaVerifyResult) => void;
136
+ onBlocked?: () => void;
137
+ children?: ReactNode;
138
+ className?: string;
139
+ style?: React.CSSProperties;
140
+ };
141
+ /**
142
+ * A button that triggers behavioral verification on click.
143
+ * Useful for form submissions, checkout flows, sensitive actions.
144
+ *
145
+ * @example
146
+ * <HumaVerifyButton
147
+ * apiKey="huma_live_..."
148
+ * userId={userId}
149
+ * onVerified={(r) => console.log('Human!', r.confidence)}
150
+ * onBlocked={() => console.log('Bot detected')}
151
+ * >
152
+ * Submit
153
+ * </HumaVerifyButton>
154
+ */
155
+ declare function HumaVerifyButton({ apiKey, userId, endpoint, onVerified, onBlocked, children, className, style, }: HumaVerifyButtonProps): react_jsx_runtime.JSX.Element;
156
+
157
+ export { HumaGate, HumaProvider, HumaVerifyButton, useHuma, useHumaContext, useHumaSession };