import { isDeepStrictEqual } from 'node:util'; const names = ['ledger.csv', 'exceptions.json', 'dispatch.json']; const sameKeys = (value, keys) => value !== null && typeof value === 'object' && !Array.isArray(value) && isDeepStrictEqual(Object.keys(value).sort(), [...keys].sort()); // Accept CSV quoting and CRLF; compare records, not a preferred serialization. export function parseCsv(input) { const rows = []; let row = [], field = '', quoted = false, closed = false; for (let i = 0; i < input.length; i++) { const char = input[i]; if (quoted) { if (char === '"' && input[i + 1] === '"') { field += '"'; i++; } else if (char === '"') { quoted = false; closed = true; } else field += char; } else if (char === ',' || char === '\n' || char === '\r') { row.push(field); field = ''; closed = false; if (char !== ',') { rows.push(row); row = []; if (char === '\r' && input[i + 1] === '\n') i++; } } else if (char === '"' && field === '' && !closed) quoted = true; else if (char === '"' || closed) throw new Error('Malformed CSV quoting'); else field += char; } if (quoted) throw new Error('Unterminated CSV quote'); if (row.length || field || closed || input.endsWith(',')) { row.push(field); rows.push(row); } return rows; } const sortedExceptions = (value) => Array.isArray(value) ? [...value].sort((a, b) => JSON.stringify([a?.source, a?.recordId, a?.kind]) .localeCompare(JSON.stringify([b?.source, b?.recordId, b?.kind]))) : null; export function validateBundle(output, expected) { let value; try { if (typeof output !== 'string' || Buffer.byteLength(output) > 1_000_000) throw new Error('Output exceeds the bundle limit'); value = JSON.parse(output); if (!sameKeys(value, names) || typeof value['ledger.csv'] !== 'string') throw new Error('Expected exactly the three named deliverables'); const ledger = isDeepStrictEqual(parseCsv(value['ledger.csv']), parseCsv(expected['ledger.csv'])); const exceptions = isDeepStrictEqual(sortedExceptions(value['exceptions.json']), sortedExceptions(expected['exceptions.json'])); const dispatch = isDeepStrictEqual(value['dispatch.json'], expected['dispatch.json']); const passed = ledger && exceptions && dispatch; return { passed, reason: passed ? 'The independent reconciliation matches all three deliverables.' : `Independent reconciliation mismatch: ${[!ledger && 'ledger', !exceptions && 'exceptions', !dispatch && 'dispatch'].filter(Boolean).join(', ')}.`, metrics: { ledgerCorrect: Number(ledger), exceptionsCorrect: Number(exceptions), dispatchCorrect: Number(dispatch) }, bundle: passed ? value : null }; } catch { return { passed: false, reason: 'Response is not a valid bounded three-file reconciliation bundle.', metrics: { ledgerCorrect: 0, exceptionsCorrect: 0, dispatchCorrect: 0 }, bundle: null }; } }