27 lines
1.3 KiB
TypeScript
27 lines
1.3 KiB
TypeScript
import { McpError } from "./security.js"
|
|
|
|
type IdentityStep = { action: string; id?: unknown }
|
|
type IdentityRow = Record<string, unknown>
|
|
|
|
/** Old sealed plans must obey the same identity rule as new public requests. */
|
|
export function assertNoCallerCreateId(step: IdentityStep): void {
|
|
if (step.action === "create" && step.id !== undefined) throw new McpError("INVALID_INPUT", "ID создаваемого объекта назначает RouterOS", 400)
|
|
}
|
|
|
|
function validId(value: unknown): value is string {
|
|
return typeof value === "string" && value.length > 0 && value.length <= 200 && value.trim() === value
|
|
}
|
|
|
|
export function acknowledgedCreateId(result: unknown): string | undefined {
|
|
const id = result && typeof result === "object" && !Array.isArray(result) ? (result as IdentityRow)[".id"] : undefined
|
|
return validId(id) ? id : undefined
|
|
}
|
|
|
|
/** Recovery may remove only the one new identity proven by the checkpoints. */
|
|
export function recoveryRosStepId(step: IdentityStep, before: IdentityRow[], after: IdentityRow[]): string | undefined {
|
|
assertNoCallerCreateId(step)
|
|
if (step.action !== "create") return validId(step.id) ? step.id : undefined
|
|
const added = after.filter(row => !before.some(previous => previous[".id"] === row[".id"]))
|
|
return added.length === 1 && validId(added[0][".id"]) ? added[0][".id"] : undefined
|
|
}
|