import JSZip from 'jszip'; import type { OfferPreparation } from './iva-offer-preparations.ts'; import { recordOfferWorkflow, offerAttachmentValid, offerWrittenRequest, } from './iva-offer-workflow.ts'; export async function buildOfferPackage( row: OfferPreparation, load: (url: string) => Promise, ) { const item = recordOfferWorkflow(row, 'form'), w = item.workflow!, zip = new JSZip(); for (const [folder, attachment] of [ ['despacho', w.decisionAttachment], ['formulario', w.formAttachment], ] as const) { if (!attachment) continue; if (!offerAttachmentValid(attachment)) throw Error('Referência de anexo inválida.'); const bytes = await load(attachment.url), hash = Array.from( new Uint8Array(await crypto.subtle.digest('SHA-256', bytes)), ) .map((b) => b.toString(16).padStart(2, '0')) .join(''); if (hash !== attachment.sha256) throw Error( 'O anexo diverge do hash registado;conjunto não emitido.', ); zip.file( folder + '/' + attachment.name.replace(/[^\p{L}\p{N}._-]/gu, '_'), bytes, ); } zip.file('pedido.txt', offerWrittenRequest(item, w)); zip.file( 'preparacao-formulario.txt', `${w.formName}\nFonte/aplicabilidade:${w.formSource}\n${w.formContent}\nDespacho:${item.request?.decisionRef};SHA256:${w.decisionAttachment!.sha256}\nApresentação fora do InvesteMoz.`, ); zip.file( 'manifesto.json', JSON.stringify( { branch: item.branch, request: item.request, workflow: w, scope: 'Submissão externa;conteúdo de preparação e anexos,não recibo de entrega à autoridade.', }, null, 2, ), ); return { row: item, bytes: await zip.generateAsync({ type: 'uint8array' }), }; }