// c31 — model: validation for an admin edit submission. Pure: no I/O. // The DB no longer stores edits (admin POST goes directly to Forgejo // + filesystem), so this file holds only the body sanity checks that // were previously bundled with the SQLite proposal flow. export const MAX_EDIT_BODY_BYTES = 256 * 1024; // 256 KB export class EditValidationError extends Error { constructor(message: string) { super(message); this.name = "EditValidationError"; } } // Throws EditValidationError when the body is empty, too large, or // otherwise unfit to commit. Returns the trimmed-but-otherwise-untouched // body string on success. export const validateEditBody = (raw: unknown): string => { if (typeof raw !== "string") { throw new EditValidationError("body must be a string"); } if (raw.trim().length === 0) { throw new EditValidationError("body cannot be empty"); } const bytes = new TextEncoder().encode(raw).length; if (bytes > MAX_EDIT_BODY_BYTES) { throw new EditValidationError( `body exceeds the ${MAX_EDIT_BODY_BYTES / 1024} KB limit (got ${Math.round(bytes / 1024)} KB)`, ); } return raw; }; // Byte-identical check between current page content and the proposed // new content. Used to skip a Forgejo round-trip when the user // accidentally submitted without changes. export const isNoOpEdit = (currentBody: string, newBody: string): boolean => currentBody === newBody;