import { CorrectiveCommandRegistry } from "./corrective-command-registry"; import { CorrectiveCaseRunnerError, MainMutationCommand } from "./corrective-case-runner"; import { InMemoryMainStore, runAtomicMutation } from "./corrective-main-transaction"; export interface MeshVertexState { id: string; x: number; y: number; z: number; } export interface MeshMain { vertices: MeshVertexState[]; } const VERTEX_ID = /^[A-Za-z0-9._:-]{1,128}$/u; const COORDINATE_LIMIT = 1_000_000; function coordinate(value: unknown, label: string): number { if (typeof value !== "number" || !Number.isFinite(value) || Math.abs(value) > COORDINATE_LIMIT) { throw new CorrectiveCaseRunnerError("COMMAND_MALFORMED", `${label} must be a finite coordinate within bounds`); } return value; } function meshPayload(command: MainMutationCommand): { vertexId: string; delta: { x: number; y: number; z: number } } { const input = command.payload; if (!input || typeof input !== "object" || Array.isArray(input) || typeof input.vertexId !== "string" || !VERTEX_ID.test(input.vertexId) || !input.delta || typeof input.delta !== "object" || Array.isArray(input.delta) || Object.keys(input).some((key) => !["vertexId", "delta"].includes(key))) { throw new CorrectiveCaseRunnerError("COMMAND_MALFORMED", "mesh payload must contain only vertexId and delta"); } const delta = input.delta as Record; if (Object.keys(delta).some((key) => !["x", "y", "z"].includes(key)) || !Object.prototype.hasOwnProperty.call(delta, "x") || !Object.prototype.hasOwnProperty.call(delta, "y") || !Object.prototype.hasOwnProperty.call(delta, "z")) { throw new CorrectiveCaseRunnerError("COMMAND_MALFORMED", "mesh delta must contain only x, y, and z"); } return { vertexId: input.vertexId, delta: { x: coordinate(delta.x, "delta.x"), y: coordinate(delta.y, "delta.y"), z: coordinate(delta.z, "delta.z") } }; } function cloneMeshMain(value: MeshMain): MeshMain { return { vertices: value.vertices.map((vertex) => ({ ...vertex })) }; } export function createMeshRegistry(main: InMemoryMainStore): CorrectiveCommandRegistry { return new CorrectiveCommandRegistry().register({ commandType: "meshTranslateVertex", targetKinds: ["MESH"], authorizations: ["USER_EDIT", "SYSTEM"], execute: async (command) => { const change = meshPayload(command); return runAtomicMutation(main, command, (draft) => { const vertex = draft.vertices.find((candidate) => candidate.id === change.vertexId); if (!vertex) throw new CorrectiveCaseRunnerError("COMMAND_UNSUPPORTED", `vertex ${change.vertexId} does not exist`); const before = { x: vertex.x, y: vertex.y, z: vertex.z }; const after = { x: before.x + change.delta.x, y: before.y + change.delta.y, z: before.z + change.delta.z }; if ([after.x, after.y, after.z].some((value) => !Number.isFinite(value) || Math.abs(value) > COORDINATE_LIMIT)) { throw new CorrectiveCaseRunnerError("COMMAND_MALFORMED", "mesh translation exceeds coordinate bounds"); } vertex.x = after.x; vertex.y = after.y; vertex.z = after.z; return { delta: { vertexId: vertex.id, before, after }, persistence: { dirty: true } }; }); }, }); } export function createMeshMain(vertices: readonly MeshVertexState[], revision = 0, dirty = false): InMemoryMainStore { return new InMemoryMainStore({ vertices: vertices.map((vertex) => ({ ...vertex })) }, revision, dirty, cloneMeshMain); }