25 lines
2.6 KiB
TypeScript
25 lines
2.6 KiB
TypeScript
import {alertsConfigRevision} from "./alerts-revision.js"
|
|
import {normalizeAlertsConfig,alertsRulesReceiptSchema,type PutRulesBody} from "@mmapp/contracts/alerts"
|
|
type Receipt=ReturnType<typeof alertsRulesReceiptSchema.parse>
|
|
type Normalized=ReturnType<typeof normalizeAlertsConfig>&{groups:NonNullable<ReturnType<typeof normalizeAlertsConfig>["groups"]>}
|
|
interface Dependencies<C>{transaction:(work:(context:C)=>Promise<Receipt>)=>Promise<Receipt>;lock:(context:C)=>Promise<boolean|undefined>;revision:(context:C)=>Promise<string>;groups:(context:C)=>Promise<Normalized["groups"]>;write:(context:C,value:Normalized)=>Promise<void>;read:(context:C)=>Promise<unknown>}
|
|
export async function executeAlertsConfigReplacement<C>(input:PutRulesBody&{expectedRevision?:string},deps:Dependencies<C>):Promise<Receipt>{
|
|
const {expectedRevision,...body}=input
|
|
normalizeAlertsConfig(body)
|
|
return deps.transaction(async context=>{
|
|
const locked=await deps.lock(context)
|
|
if(locked===false)throw Error("Сохранение правил уже выполняется")
|
|
if(locked!==true)throw Error("Блокировка правил не подтверждена")
|
|
if(expectedRevision!==undefined&&await deps.revision(context)!==expectedRevision)throw Error("Правила изменились на сервере. Обновите снимок и сравните его с черновиком перед сохранением.")
|
|
const normalized=normalizeAlertsConfig({...body,groups:body.groups??await deps.groups(context)}) as Normalized
|
|
await deps.write(context,normalized)
|
|
const parsed=alertsRulesReceiptSchema.safeParse(await deps.read(context))
|
|
if(!parsed.success)throw Error("Сохранённая конфигурация оповещений не подтверждена")
|
|
const receipt=parsed.data
|
|
if(receipt.revision!==alertsConfigRevision(receipt))throw Error("Ревизия сохранённой конфигурации не подтверждена")
|
|
const match=(expected:Record<string,unknown>,actual:Record<string,unknown>|undefined)=>actual!==undefined&&Object.entries(expected).every(([key,value])=>JSON.stringify(actual[key])===JSON.stringify(value))
|
|
if(receipt.rules.length!==normalized.rules.length||receipt.groups.length!==normalized.groups.length||normalized.rules.some(rule=>!match(rule,receipt.rules.find(row=>row.id===rule.id)))||normalized.groups.some(group=>!match(group,receipt.groups.find(row=>row.id===group.id))))throw Error("Сохранённые правила или группы не совпадают с отправленными")
|
|
return receipt
|
|
})
|
|
}
|