/** * Fan-out archive query and merge replies until timeout. * @module aggregate */ /** * @param {object} opts * @param {string} opts.sha256 * @param {string} opts.tenantId * @param {string[]} [opts.kinds] * @param {Array<{ archiveId: string, query: (sha: string) => object[]|null }>} opts.archives * @param {number} [opts.timeoutMs=50] unused in in-process mock (archives are sync) * @returns {{ archivesQueried: boolean, archiveReplies: number, records: object[], silent: string[] }} */ export function aggregateAttached({ sha256, tenantId, kinds = ['publicMeta', 'privateMeta', 'file'], archives }) { const records = []; const silent = []; for (const arch of archives) { const hit = arch.query(sha256); if (hit == null) { silent.push(arch.archiveId); continue; } for (const rec of hit) { if (!kinds.length || kinds.includes(rec.kind)) records.push(rec); } } return { sha256, tenantId, archivesQueried: true, archiveReplies: archives.length - silent.length, silent, records, }; } /** * Merge chain receipts with archive records. * @param {object[]} chainReceipts * @param {object[]} archiveRecords */ export function mergeReceipts(chainReceipts, archiveRecords) { const extra = archiveRecords.map((r) => { if (r.kind === 'tree') { return { kind: 'tree-leaf', archiveId: r.archiveId, attachedAt: r.storedAt, itemizedOnMainChain: false, merkleRoot: r.record?.merkleRoot, proof: r.record?.proof, leafIndex: r.record?.leafIndex, chainSealJobId: r.record?.chainSealJobId, ...r.record, }; } return { kind: r.kind === 'file' ? 'file-attach' : 'metadata-attach', archiveId: r.archiveId, attachedAt: r.storedAt, ...r.record, }; }); return [...chainReceipts, ...extra]; }