File size: 3,127 Bytes
27497f4
 
78120e2
27497f4
 
 
 
78120e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6572963
78120e2
 
 
27497f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78120e2
 
27497f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78120e2
 
 
 
 
 
27497f4
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { NextRequest } from "next/server";
import { promises as fs } from "fs";
import os from "os";
import path from "path";

export const runtime = "nodejs";

async function resolveLogFilePath() {
    if (process.env.CHAT_LOG_PATH) return process.env.CHAT_LOG_PATH;

    const candidates = [
        process.env.DATA_DIR,
        process.env.HF_HOME,
        process.env.HOME,
        "/tmp",
        os.tmpdir(),
        process.cwd(),
    ].filter(Boolean) as string[];

    for (const dir of candidates) {
        const candidate = path.join(dir, "chat-logs.jsonl");
        try {
            await fs.access(candidate);
            return candidate;
        } catch {
            // try next
        }
    }

    // Default location if not present yet
    return path.join(os.tmpdir(), "chat-logs.jsonl");
}
const ADMIN_TOKEN = process.env.ADMIN_TOKEN || "";

function isAuthorized(req: NextRequest) {
    if (!ADMIN_TOKEN) return true;

    const tokenFromHeader = req.headers.get("x-admin-token") || "";
    const auth = req.headers.get("authorization") || "";
    const tokenFromBearer = auth.toLowerCase().startsWith("bearer ") ? auth.slice(7) : "";
    const tokenFromQuery = req.nextUrl.searchParams.get("token") || "";

    return tokenFromHeader === ADMIN_TOKEN || tokenFromBearer === ADMIN_TOKEN || tokenFromQuery === ADMIN_TOKEN;
}

function clampInt(v: number, min: number, max: number) {
    return Math.max(min, Math.min(max, v));
}

export async function GET(req: NextRequest) {
    if (!isAuthorized(req)) {
        return new Response(JSON.stringify({ error: "Unauthorized" }), {
            status: 401,
            headers: { "Content-Type": "application/json" },
        });
    }

    const tailParam = req.nextUrl.searchParams.get("tail");
    const rawParam = req.nextUrl.searchParams.get("raw");

    const tail = clampInt(Number(tailParam ?? "100"), 1, 2000);
    const raw = rawParam === "1" || rawParam === "true";

    try {
        const logFile = await resolveLogFilePath();
        const file = await fs.readFile(logFile, "utf8");
        const lines = file.split(/\r?\n/).filter(Boolean);
        const sliced = lines.slice(Math.max(0, lines.length - tail));

        if (raw) {
            return new Response(sliced.join("\n"), {
                headers: { "Content-Type": "text/plain; charset=utf-8" },
            });
        }

        const parsed = sliced
            .map((l) => {
                try {
                    return JSON.parse(l);
                } catch {
                    return null;
                }
            })
            .filter(Boolean);

        return new Response(JSON.stringify({ count: parsed.length, logs: parsed }), {
            headers: { "Content-Type": "application/json" },
        });
    } catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        const status = message.includes("ENOENT") ? 404 : 500;
        return new Response(JSON.stringify({ error: "Failed to read logs", message }), {
            status,
            headers: { "Content-Type": "application/json" },
        });
    }
}