From 5d356671364305b590447da577602b3cc55b7179 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Sat, 18 Apr 2026 23:23:25 -0500 Subject: adjust for ai output structures --- src/lib/sanitize.ts | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'src/lib') diff --git a/src/lib/sanitize.ts b/src/lib/sanitize.ts index d63eb19..b77893e 100644 --- a/src/lib/sanitize.ts +++ b/src/lib/sanitize.ts @@ -48,30 +48,47 @@ function normalizeHex(hex: string): string { * Recursively coerce every field of a brand output object to its expected type. * Returns `null` if the input is clearly not a valid brand output at all. */ +const DEFAULT_SWATCHES = [ + { id: 's0', name: 'Background', hex: '#ffffff', role: 'background' }, + { id: 's1', name: 'Surface', hex: '#f5f5f5', role: 'neutral' }, + { id: 's2', name: 'Primary', hex: '#2563eb', role: 'primary' }, + { id: 's3', name: 'Accent', hex: '#7c3aed', role: 'accent' }, + { id: 's4', name: 'Text', hex: '#111111', role: 'text' }, +]; + export function sanitizeOutputs(raw: unknown): BrandOutputs | null { if (!raw || typeof raw !== 'object') return null; - const r = raw as Record; + let r = raw as Record; + + // Unwrap single-key envelopes: {"brand_package": {...}} → {...} + const keys = Object.keys(r); + if (keys.length === 1 && r[keys[0]] && typeof r[keys[0]] === 'object') { + r = r[keys[0]] as Record; + } - // Must have at least the core keys to be worth keeping - if (!r.overview && !r.positioning && !r.tone) return null; + // Must have at least one recognisable content field + if (!r.overview && !r.positioning && !r.tone && !r.titles && !r.palette) return null; const tone = (r.tone && typeof r.tone === 'object' ? r.tone : {}) as Record; const typo = (r.typography && typeof r.typography === 'object' ? r.typography : {}) as Record; const palette = (r.palette && typeof r.palette === 'object' ? r.palette : {}) as Record; - const swatches = Array.isArray(palette.swatches) - ? palette.swatches.map((s: unknown, i: number) => { + // Accept swatches under palette.swatches or palette.colors + const rawSwatches = Array.isArray(palette.swatches) ? palette.swatches + : Array.isArray(palette.colors) ? palette.colors + : []; + + const swatches = rawSwatches.length + ? rawSwatches.map((s: unknown, i: number) => { const sw = (s && typeof s === 'object' ? s : {}) as Record; return { id: str(sw.id, `s${i}`), name: str(sw.name, 'Color'), - hex: normalizeHex(str(sw.hex, '#888888')), - role: str(sw.role, 'accent'), + hex: normalizeHex(str(sw.hex ?? sw.color ?? sw.value, '#888888')), + role: str(sw.role ?? sw.type, 'accent'), }; }) - : []; - - if (!swatches.length) return null; + : DEFAULT_SWATCHES; const visualDirections = Array.isArray(r.visualDirections) ? r.visualDirections.map((v: unknown, i: number) => { -- cgit v1.2.3