/** * First-touch referral attribution — server side. * * The browser captures an anonymous visitor's *first* landing context (referral * source, UTM params, referring host, landing path) and persists it across the * signup boundary in a first-party cookie named `an_ft` (see * `client/analytics.ts`). On signup, the auth hook reads that cookie off the * request and enriches the canonical server-side `signup` event so we can * measure where new users came from and how apps spread (virality). * * This module is intentionally pure and dependency-free so it is trivially * unit-testable and can never throw into the signup path. The single hard rule: * parsing untrusted cookie input must NEVER throw — every accessor is defensive. */ /** * The decoded first-touch attribution object. Mirrors the compact JSON the * client writes into the `an_ft` cookie / `an_attribution` localStorage key. * Every field is optional — the client omits empty fields to keep the cookie * small, and a malformed/absent cookie yields `null`. */ export interface FirstTouchAttribution { /** Referral source bucket, e.g. "clip_share", "plan_share". */ ref?: string; /** Referrer's stable user id (the clip/plan owner who shared the link). */ via?: string; utm_source?: string; utm_medium?: string; utm_campaign?: string; utm_content?: string; utm_term?: string; /** `window.location.pathname` of the first page the visitor landed on. */ landing_path?: string; /** Host of `document.referrer` (scrubbed; host only, never a full URL). */ landing_referrer?: string; /** ISO timestamp of when the visitor first landed. */ landed_at?: string; } /** Cookie name written by the client (non-HttpOnly; non-sensitive). */ export declare const FIRST_TOUCH_COOKIE_NAME = "an_ft"; /** * Parse a raw `Cookie:` header into a flat name→value map. Tolerates missing * input, extra whitespace, `=` inside values, and malformed pairs. Never throws. */ export declare function parseCookieHeader(cookieHeader: string | null | undefined): Record; /** * Decode a single cookie value into a `FirstTouchAttribution`. The value is the * URL-encoded compact JSON written by the client. Returns `null` for empty, * malformed, or non-object input. Only known string fields are copied through, * each clamped to a sane max length as a defense against an oversized cookie. */ export declare function decodeFirstTouchValue(value: string | null | undefined): FirstTouchAttribution | null; /** * Read the `an_ft` first-touch attribution out of a raw `Cookie:` header. * Returns `null` when the cookie is absent or unparseable. Never throws. */ export declare function readFirstTouchAttribution(cookieHeader: string | null | undefined): FirstTouchAttribution | null; /** * Derive the `referral_source` bucket from first-touch attribution per the * contract: * 1. explicit `ref` wins; * 2. landing path under `/share/` => "clip_share"; * 3. landing path that looks like a public plan page * (`/p/`, `/plan/`, `/plans/`, `/recaps/`, or `/share-plan/`) => * "plan_share"; * 4. a non-empty external referring host => "external"; * 5. otherwise => "direct". */ export declare function deriveReferralSource(ft: FirstTouchAttribution | null): string; /** * Compute the snake_case signup-event properties from first-touch attribution. * Returns a clean object with `undefined` values omitted, ready to merge into * the `signup` track call. Always sets `referral_source` (defaults to "direct"). * * Pure and total — given any (or no) input it returns a well-formed object and * never throws. */ export declare function deriveSignupAttribution(ft: FirstTouchAttribution | null): Record; /** * Convenience: read the cookie header and derive signup attribution in one * call. Never throws; falls back to `{ referral_source: "direct" }` on any * error. */ export declare function signupAttributionFromCookieHeader(cookieHeader: string | null | undefined): Record; //# sourceMappingURL=attribution.d.ts.map