/**
 * Loki access-log field names (Traefik JSON access log, flattened by Loki's
 * `| json`). Overridable via env in case the shipped field names differ — the
 * exact names are validated against real logs during rollout.
 */
export interface LokiFields {
    host: string;
    path: string;
    userAgent: string;
}
export declare const DEFAULT_LOKI_FIELDS: LokiFields;
/** Regex (anchored) matching automation request paths from the shared denylist. */
export declare function automationPathRegex(): string;
/** Case-insensitive regex matching automation user-agents from the shared denylist. */
export declare function automationUaRegex(): string;
/**
 * LogQL instant query counting *proper* requests to `host` over the trailing
 * window — requests whose path and user-agent are NOT on the automation denylist.
 */
export declare function buildProperRequestCountQuery(selector: string, host: string, windowSeconds: number, fields?: LokiFields): string;
/** LogQL counting ALL requests to `host` (incl. automation) over the window. */
export declare function buildTotalRequestCountQuery(selector: string, host: string, windowSeconds: number, fields?: LokiFields): string;
/**
 * Grouped variant of {@link buildProperRequestCountQuery} — one query counting
 * *proper* (non-automation) requests for every host in `hosts`, grouped by host.
 */
export declare function buildGroupedProperRequestCountQuery(selector: string, hosts: string[], windowSeconds: number, fields?: LokiFields): string;
/** Grouped variant of {@link buildTotalRequestCountQuery} — all requests per host. */
export declare function buildGroupedTotalRequestCountQuery(selector: string, hosts: string[], windowSeconds: number, fields?: LokiFields): string;
/**
 * Activity classification for a studio host:
 *  - ACTIVE  — at least one proper (non-automation) request in the window.
 *  - IDLE    — access logs exist for the host but NONE are proper requests.
 *  - UNKNOWN — no access logs at all (signal unavailable) or the query failed.
 *
 * The UNKNOWN vs IDLE distinction is critical: a host with zero total log lines
 * means we can't measure (Traefik access logs off / not reaching Loki), NOT that
 * the studio is idle. Every live studio is polled by the observability worker
 * every 15s, so once access logs work total-requests is always > 0 — making
 * `total == 0` a reliable "can't measure" signal. The keeper sleeps only on IDLE.
 */
export type HostActivity = "ACTIVE" | "IDLE" | "UNKNOWN";
/**
 * Verdict for one host from its request counts + whether the log pipeline is
 * proven live this scan (a canary host known to always receive traffic had
 * requests in the window).
 *
 *  - proper > 0            → ACTIVE  (real user traffic)
 *  - total  > 0, proper 0  → IDLE    (logs exist, all automation)
 *  - total == 0, healthy   → IDLE    (pipeline proven live ⇒ zero requests is
 *                                     genuine idleness, not a missing signal)
 *  - total == 0, !healthy  → UNKNOWN (can't tell idle from a broken pipeline —
 *                                     fail safe, never slept; the dev.140 guard)
 *
 * The `pipelineHealthy` canary is what lets us reclaim genuinely-silent studios
 * (the common case) without risking a fleet-wide sleep when Traefik→Loki breaks.
 */
export declare function classifyActivity(proper: number, total: number, pipelineHealthy: boolean): HostActivity;
export interface LokiClient {
    /**
     * Classify a batch of hosts in as few Loki queries as possible (two grouped
     * queries per chunk). Returns a verdict for every input host. Preferred over
     * per-host calls: 40 studios was 80 separate queries that saturated Loki's
     * query queue (queueTime ≫ execTime) and timed out to all-UNKNOWN.
     */
    classifyHosts(hosts: string[], windowSeconds: number): Promise<Map<string, HostActivity>>;
    /** Single-host convenience wrapper over {@link classifyHosts} (optional; the
     * keeper only uses the batched form). */
    classifyHostActivity?(host: string, windowSeconds: number): Promise<HostActivity>;
}
export declare function createLokiClient(opts: {
    lokiUrl: string;
    selector: string;
    fields?: LokiFields;
    fetchTimeoutMs?: number;
    /**
     * A host known to ALWAYS receive Traefik traffic (e.g. the switchboard apex).
     * Each scan we check it has requests in the window; if so the Traefik→Loki
     * pipeline is proven live and a studio's `total == 0` is trusted as idle. If
     * unset (or the canary is silent), we fall back to the conservative
     * `total == 0 ⇒ UNKNOWN` (never sleep) behaviour.
     */
    canaryHost?: string;
    logger?: {
        warn: (m: string) => void;
    };
}): LokiClient;
//# sourceMappingURL=loki.d.ts.map