/**
 * Freshness of stored registrar facts.
 *
 * A date in the `domains` table is an assertion made at the moment of the last
 * registrar sync, not a current fact. Nothing in the row said when that moment
 * was: `updated_at` moves when ANY column is edited and does NOT move when a
 * sync re-confirms an unchanged value, so it cannot answer "how fresh is this
 * expiry date". `expiry_synced_at` answers exactly that and nothing else.
 *
 * This is the same pattern `domain_reputation.last_checked_at` already uses for
 * reputation checks; the domains table never got it.
 */
/** Beyond this, a stored registrar fact is reported as stale. */
export declare const DEFAULT_STALE_AFTER_DAYS = 7;
export type FreshnessState = "fresh" | "stale" | "never";
export interface Freshness {
    state: FreshnessState;
    /** Whole days since the last sync; null when never synced. */
    age_days: number | null;
    /** The value read, echoed back so a caller can show its provenance. */
    synced_at: string | null;
}
/**
 * Classify how fresh a stored registrar fact is.
 *
 * An unparseable or absent timestamp is "never" — deliberately the pessimistic
 * reading, because the failure this guards against is a stale value being read
 * as current. Treating an unreadable timestamp as fresh would reintroduce it.
 */
export declare function freshness(syncedAt: string | null | undefined, options?: {
    now?: Date;
    staleAfterDays?: number;
}): Freshness;
/** True when a stored expiry date is already behind us. */
export declare function isLapsed(expiresAt: string | null | undefined, now?: Date): boolean;
export interface LapsedSplit {
    /** Lapsed rows within the displayed page. */
    lapsedShown: number;
    /** Lapsed rows across the WHOLE result — never the page. */
    lapsedTotal: number;
    /** Rendered count: bare when complete, "N total, showing M" when bounded. */
    label: string;
    /** True when the page cannot show every lapsed row. */
    bounded: boolean;
}
/**
 * Split a paged listing into its lapsed count and its displayed count.
 *
 * The counts MUST come from the full result and the display from the page.
 * Counting the page and printing that number as a heading would publish a
 * bounded read as a population — the same defect class the two-sided expiry fix
 * exists to remove, which makes it exactly the mistake worth guarding here.
 */
export declare function lapsedSplit<T extends {
    expires_at: string | null;
}>(all: T[], page: T[], now?: Date): LapsedSplit;
/**
 * A short suffix to render next to any stored registrar date, so a reader
 * cannot mistake a months-old snapshot for a current fact.
 */
export declare function freshnessSuffix(syncedAt: string | null | undefined, options?: {
    now?: Date;
    staleAfterDays?: number;
}): string;
//# sourceMappingURL=freshness.d.ts.map