UNPKG

@stafyniaksacha/facturx

Version:

Factur-X and Order-X generation library for European e-invoicing standard

94 lines (90 loc) 3 kB
import { Buffer } from 'node:buffer'; import { r as resolvePdf, F as FACTURX_FILENAME, O as ORDERX_FILENAME, Z as ZUGFERD_FILENAMES, a as resolveXml, c as check } from './facturx.Cloc1W3i.mjs'; import { PDFName, PDFDict, PDFStream, decodePDFRawStream, PDFArray } from 'pdf-lib'; function extractAttachments(pdfDoc) { const rawAttachments = extractRawAttachments(pdfDoc); return rawAttachments.map(({ fileName, fileSpec }) => { const stream = fileSpec.lookup(PDFName.of("EF"), PDFDict).lookup(PDFName.of("F"), PDFStream); return { name: fileName.decodeText(), data: decodePDFRawStream(stream).decode() }; }); } function extractRawAttachments(pdfDoc) { if (!pdfDoc.catalog.has(PDFName.of("Names"))) return []; const Names = pdfDoc.catalog.lookup(PDFName.of("Names"), PDFDict); if (!Names.has(PDFName.of("EmbeddedFiles"))) return []; const EmbeddedFiles = Names.lookup(PDFName.of("EmbeddedFiles"), PDFDict); if (!EmbeddedFiles.has(PDFName.of("Names"))) return []; const EFNames = EmbeddedFiles.lookup(PDFName.of("Names"), PDFArray); const rawAttachments = []; for (let idx = 0, len = EFNames.size(); idx < len; idx += 2) { const fileName = EFNames.lookup(idx); const fileSpec = EFNames.lookup(idx + 1, PDFDict); rawAttachments.push({ fileName, fileSpec }); } return rawAttachments; } async function extract(options) { let file = null; const pdf = await resolvePdf(options.pdf); let flavor = options.flavor; const level = options.level; const attachments = extractAttachments(pdf); if (attachments?.length) { for (const attachment of attachments) { if (attachment.name === FACTURX_FILENAME) { if (!options.flavor || options.flavor === "facturx") { flavor = "facturx"; } else { throw new Error(`Invalid flavor, expected ${options.flavor} but found facturx`); } file = attachment; break; } if (attachment.name === ORDERX_FILENAME) { if (!options.flavor || options.flavor === "orderx") { flavor = "orderx"; } else { throw new Error(`Invalid flavor, expected ${options.flavor} but found orderx`); } file = attachment; break; } if (ZUGFERD_FILENAMES.includes(attachment.name)) { if (!options.flavor || options.flavor === "zugferd") { flavor = "zugferd"; } else { throw new Error(`Invalid flavor, expected ${options.flavor} but found zugferd`); } file = attachment; break; } } } if (!file) { throw new Error("No attachment found"); } const xml = await resolveXml(Buffer.from(file.data)); if (options.check === true) { const result = await check({ xml, flavor, level }); if (!result.valid) { throw new Error("Invalid XML"); } } return { filename: file.name, xml: xml.toString(), flavor, level }; } export { extract as e };