/** * Humanity signals — invisible bot-protection primitives shared by the lib's * public forms (client) and the hub's per-route `verifyHuman` gate (server). * * PURE + React-free on purpose: this module is a tsup SERVER entry (no * "use client" banner) so the hub can import it server-side without pulling a * client-reference boundary — same pattern as `schemas/contact-schema` and * `components/features/mux-origins`. * * Two origin-independent signals travel in the POST body: a honeypot (a hidden * field real users never fill) and timing (ms from form mount to submit). * `evaluateHumanitySignals` is the SINGLE source of truth for the block/allow * decision — the hub imports + calls it rather than re-implementing the rules. */ /** Hidden honeypot field name. Innocuous + autofill-resistant (deliberately NOT name/email). */ export declare const HONEYPOT_FIELD = "contact_url_confirm"; /** Client-measured ms between form mount and submit. */ export declare const ELAPSED_MS_FIELD = "form_elapsed_ms"; /** Default minimum fill time (ms). A submit faster than this is treated as a bot. */ export declare const DEFAULT_MIN_FILL_MS = 700; /** * Every humanity-signal key that rides in a public form's POST body. * Server-side handlers that forward form payloads upstream (HubSpot booking, * CRM pushes, …) MUST strip by THIS array — never hand-typed strings — so a * field rename here propagates everywhere and the honeypot value can never * silently leak into an upstream record. */ export declare const HUMANITY_SIGNAL_KEYS: readonly ["contact_url_confirm", "form_elapsed_ms"]; /** Keyed wire object produced by `useHumanitySignals().getSignals()` and spread into the POST body. */ export type HumanitySignals = Record; /** Result of {@link evaluateHumanitySignals}. */ export type HumanityVerdict = { ok: true; } | { ok: false; reason: 'honeypot' | 'too_fast'; }; /** Tolerant reader — never throws; missing/garbage timing → null. */ export declare function extractHumanitySignals(body: unknown): { honeypot: string; elapsedMs: number | null; }; /** * SINGLE decision fn for honeypot + timing (the hub's `verifyHuman` imports + calls this): * - honeypot non-empty → bot (real users never fill the off-screen field) * - elapsed below `minFillMs` → bot (humans take time; a MISSING timing value never blocks) */ export declare function evaluateHumanitySignals(body: unknown, opts: { minFillMs: number; }): HumanityVerdict; /** Parse a comma-separated env string → trimmed, non-empty entries (undefined → []). */ export declare const splitCsvEnv: (s?: string) => string[]; //# sourceMappingURL=humanity-signals.d.ts.map