import { validateCustomFields } from "@capakraken/engine"; import { BlueprintTarget, type BlueprintFieldDefinition } from "@capakraken/shared"; import { TRPCError } from "@trpc/server"; import { findUniqueOrThrow } from "../db/helpers.js"; interface BlueprintLookup { blueprint: { findUnique: (args: { where: { id: string }; select: { fieldDefs: true; target: true }; }) => Promise<{ fieldDefs: unknown; target: string } | null>; }; } interface AssertBlueprintDynamicFieldsInput { db: BlueprintLookup; blueprintId: string | undefined; dynamicFields: Record; target: BlueprintTarget; } export async function assertBlueprintDynamicFields({ db, blueprintId, dynamicFields, target, }: AssertBlueprintDynamicFieldsInput): Promise { if (!blueprintId) return; const blueprint = await findUniqueOrThrow( db.blueprint.findUnique({ where: { id: blueprintId }, select: { fieldDefs: true, target: true }, }), "Blueprint", ); if (blueprint.target !== target) { throw new TRPCError({ code: "BAD_REQUEST", message: `${target} entities require a ${target.toLowerCase()} blueprint`, }); } const fieldDefs = blueprint.fieldDefs as BlueprintFieldDefinition[]; const errors = validateCustomFields(fieldDefs, dynamicFields); if (errors.length > 0) { throw new TRPCError({ code: "UNPROCESSABLE_CONTENT", message: errors.map((error) => error.message).join("; "), }); } }