/**
 * AI-crawler activity logging for the admin "AI crawler activity" panel.
 *
 * Hits are aggregated per (bot token, surface) via upsert, so storage stays
 * bounded (~known bots × surfaces) and never needs pruning. Recording is always
 * best-effort: a logging failure — or a database that predates the
 * `actuate_ai_crawler_hits` table — must never break a public surface.
 */
import { hasModel } from '../api/route-helpers.js';
import { detectAiBot } from './ai-bots.js';
const MAX_BOT_LEN = 128;
/** Upsert one aggregated hit. Safe to await on any public route. */
export async function recordAiCrawlerHit(db, entry) {
    if (!db || !hasModel(db, 'aiCrawlerHit'))
        return;
    const bot = String(entry.bot ?? '')
        .slice(0, MAX_BOT_LEN)
        .trim();
    if (!bot)
        return;
    const category = entry.category ?? 'other';
    try {
        await db.aiCrawlerHit.upsert({
            where: { bot_surface: { bot, surface: entry.surface } },
            update: { hits: { increment: 1 }, lastSeenAt: new Date(), category },
            create: { bot, surface: entry.surface, category, hits: 1 },
        });
    }
    catch {
        // best-effort — swallow so logging can never break the response
    }
}
/**
 * Detect a known AI crawler from the request's User-Agent and, if found, record
 * a hit on the given surface. No-op for humans and unknown bots, so the only
 * cost on a normal page request is a header read + taxonomy scan.
 */
export async function recordAiCrawlerFromRequest(db, request, surface) {
    const detected = detectAiBot(request.headers.get('user-agent'));
    if (!detected)
        return;
    await recordAiCrawlerHit(db, {
        bot: detected.token,
        surface,
        category: detected.category,
    });
}
//# sourceMappingURL=ai-crawler-log.js.map