Files
MikrotikManager/shared/api/alerts.ts

34 lines
4.4 KiB
TypeScript

import {z} from "zod"
import {normalizeAlertsConfig,alertsResponseSchema,alertsRulesReceiptSchema,telegramSettingsReceiptSchema,telegramTestReceiptSchema,putTelegramSchema,testTelegramSchema,type PutRulesBody,type PutTelegramBody,type TestTelegramBody} from "@mmapp/contracts/alerts"
import {requestJson} from "./http-client"
type Options={signal?:AbortSignal;expectedRevision?:string}
const signal=(options?:Options)=>{const active=options?.signal?AbortSignal.any([options.signal,AbortSignal.timeout(30_000)]):AbortSignal.timeout(30_000);active.throwIfAborted();return active}
function parse<S extends z.ZodType>(schema:S,raw:unknown,message:string):z.output<S>{const result=schema.safeParse(raw);if(!result.success)throw Error(message);return result.data}
export async function getAlerts(baseUrl:string,options?:Options){return parse(alertsResponseSchema,await requestJson<unknown>(baseUrl,"/api/alerts",{signal:signal(options),cache:"no-store"}),"Данные оповещений не подтверждены сервером")}
export async function saveAlertRules(baseUrl:string,payload:PutRulesBody,options?:Options){
const body=normalizeAlertsConfig(payload)
if(!options?.expectedRevision||!/^[a-f0-9]{64}$/.test(options.expectedRevision))throw Error("Обновите снимок правил перед сохранением")
const receipt=parse(alertsRulesReceiptSchema,await requestJson<unknown>(baseUrl,"/api/alerts/rules",{method:"PUT",headers:{"If-Match":'"'+options.expectedRevision+'"'},body:JSON.stringify(body),signal:signal(options)}),"Сохранение правил не подтверждено сервером")
const same=(a:unknown,b:unknown)=>JSON.stringify(a)===JSON.stringify(b)
if(receipt.rules.length!==body.rules.length||body.rules.some(rule=>{
const saved=receipt.rules.find(row=>row.id===rule.id)
if(!saved)return true
const targets=(rule.targets?.length?rule.targets:[rule.target??""]).map(value=>value.trim()).filter(Boolean)
const conditions=(rule.conditions?.length?rule.conditions:[rule.condition??""]).map(value=>value.trim()).filter(Boolean)
const expected={name:rule.name,type:rule.type,targets,conditions,groupId:rule.groupId?.trim()||null,severity:rule.severity,enabled:rule.enabled,cooldown:rule.cooldown,confirmStabilitySec:rule.confirmStabilitySec||null,recoveryMode:rule.recoveryMode??"always",recoveryStabilitySec:rule.recoveryStabilitySec||null,chatId:rule.chatId}
return Object.entries(expected).some(([key,value])=>!same(saved[key as keyof typeof saved],value))
})||body.groups!==undefined&&(receipt.groups.length!==body.groups.length||body.groups.some(group=>{const saved=receipt.groups.find(row=>row.id===group.id);return !saved||Object.entries({...group,name:group.name.trim()||group.id}).some(([key,value])=>!same(saved[key as keyof typeof saved],value))})))throw Error("Сохранённые правила или группы не совпадают с отправленными")
return receipt
}
export async function saveAlertsTelegram(baseUrl:string,payload:PutTelegramBody,options?:Options){
const body=parse(putTelegramSchema,payload,"Проверьте параметры Telegram")
if(Object.keys(body).length===0)throw Error("Нет изменённых параметров Telegram")
const receipt=parse(telegramSettingsReceiptSchema,await requestJson<unknown>(baseUrl,"/api/alerts/telegram",{method:"PUT",body:JSON.stringify(body),signal:signal(options)}),"Сохранение параметров Telegram не подтверждено сервером")
if(body.chatId!==undefined&&receipt.telegram.chatId!==body.chatId.trim()||body.messageThreadId!==undefined&&receipt.telegram.messageThreadId!==body.messageThreadId||body.token!==undefined&&receipt.telegram.tokenConfigured!==Boolean(body.token?.trim()))throw Error("Сохранённые параметры Telegram не совпадают с отправленными")
return receipt
}
export async function testAlertsTelegram(baseUrl:string,payload:TestTelegramBody={},options?:Options){
const body=parse(testTelegramSchema,payload,"Проверьте параметры тестового сообщения Telegram")
return parse(telegramTestReceiptSchema,await requestJson<unknown>(baseUrl,"/api/alerts/telegram/test",{method:"POST",body:JSON.stringify(body),signal:signal(options)}),"Отправка тестового сообщения не подтверждена сервером")
}