import { z } from "zod" import { logEntrySchema, logPageSchema, logSettingsSchema, logSettingsPatchSchema, logSummarySchema } from "@mmapp/contracts" import { requestBlob, requestJson } from "./http-client" const timedSignal = (signal?: AbortSignal, ms = 30000) => AbortSignal.any([...(signal ? [signal] : []), AbortSignal.timeout(ms)]) function confirmed(schema: z.ZodType, raw: unknown): T { const parsed = schema.safeParse(raw) if (!parsed.success) throw new Error("Ответ сервера журнала не подтверждён: некорректные данные") return parsed.data } export async function getLogs(base: string, params: URLSearchParams, signal?: AbortSignal) { const result = confirmed(logPageSchema, await requestJson(base, "/api/logs?" + params, { signal: timedSignal(signal) })) const server = params.get("serverId") if (server && result.entries.some(row => String(row.serverId) !== server)) throw new Error("Журнал относится к другому устройству") return result } export async function getLogSummary(base: string, params: URLSearchParams, signal?: AbortSignal) { return confirmed(logSummarySchema, await requestJson(base, "/api/logs/summary?" + params, { signal: timedSignal(signal) })) } export async function getLogContext(base: string, id: string, signal?: AbortSignal) { return confirmed(z.object({ entry: logEntrySchema, before: z.array(logEntrySchema), after: z.array(logEntrySchema) }), await requestJson(base, `/api/logs/${encodeURIComponent(id)}/context`, { signal: timedSignal(signal) })) } export async function getLogSettings(base: string, signal?: AbortSignal) { return confirmed(logSettingsSchema, await requestJson(base, "/api/logs/settings", { signal: timedSignal(signal) })) } export async function putLogSettings(base: string, patch: z.infer, signal?: AbortSignal) { const input = logSettingsPatchSchema.parse(patch) const result = confirmed(z.object({ ok: z.literal(true), settings: logSettingsSchema }), await requestJson(base, "/api/logs/settings", { method: "PUT", body: JSON.stringify(input), signal: timedSignal(signal) })) if (Object.entries(input).some(([key, value]) => result.settings[key as keyof typeof result.settings] !== value)) throw new Error("Сервер подтвердил другие настройки; обновите данные") return result.settings } export async function exportLogs(base: string, params: URLSearchParams, format: "csv" | "json", signal?: AbortSignal) { const query = new URLSearchParams(params); query.set("format", format) const res = await requestBlob(base, "/api/logs/export?" + query, { signal: timedSignal(signal, 60000) }) const blob = await res.blob(), url = URL.createObjectURL(blob), anchor = document.createElement("a") anchor.href = url; anchor.download = `router-logs.${format}`; anchor.click(); setTimeout(() => URL.revokeObjectURL(url), 1000) }