import type { FieldConfig } from "../types"; import { extractFields } from "../transformers/field-config"; export type FkResolver = (resourceName: string, fkValue: any) => Promise; export async function sanitizePayload( data: any, fields: FieldConfig[], schemas: Record, resolveFk?: FkResolver, ): Promise { if (data == null || typeof data !== "object") return data; if (Array.isArray(data)) { return Promise.all(data.map((item) => { if (item != null && typeof item === "object") { return sanitizePayload(item, fields, schemas, resolveFk); } return item; })); } const result: Record = { ...data }; const fieldMap = new Map(fields.map((f) => [f.name, f])); for (const key of Object.keys(result)) { const field = fieldMap.get(key); if (!field) continue; const val = result[key]; // FK fields whose wire value is a plain target property (fk.value, e.g. // account names) are already in wire format — no id→object resolution. if (field.fk && !field.fk.value) { if (val == null || val === "") { result[key] = null; } else if (resolveFk) { if (field.isArray && Array.isArray(val)) { result[key] = await Promise.all(val.map((v: any) => resolveFk(field.fk!.resource, v))); } else { result[key] = await resolveFk(field.fk!.resource, val); } } continue; } if (field.refSchema && !field.fk) { if (val == null || val === "") { result[key] = field.isArray ? [] : {}; } else if (typeof val === "object") { const refSchemaObj = schemas[field.refSchema!]; const nestedFields = refSchemaObj ? extractFields(field.refSchema!, refSchemaObj, schemas) : []; result[key] = await sanitizePayload(val, nestedFields, schemas, resolveFk); } } else if (field.isArray) { if (val == null || val === "") { result[key] = []; } } else if (field.type === "object") { if (val == null || val === "") { result[key] = {}; } } } return result; }