@getpeppr/cli 0.7.1 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils/file.ts","../src/utils/errors.ts","../src/formatters/validation.ts","../../sdk/src/core/ubl-builder.ts","../../sdk/src/core/checksums/luhn.ts","../../sdk/src/core/country-rules.ts","../../sdk/src/core/code-lists.ts","../../sdk/src/core/validator.ts","../../sdk/src/core/status-precedence.ts","../../sdk/src/version.ts","../../sdk/src/core/client.ts","../../sdk/src/core/schematron.ts","../src/commands/validate.ts","../src/commands/init.ts","../src/templates/invoice.ts","../src/templates/credit-note.ts","../src/commands/convert.ts","../src/commands/lookup.ts","../src/lib/peppol-directory.ts","../src/commands/send.ts","../src/lib/credentials-store.ts","../src/lib/auth.ts","../src/lib/send-payload.ts","../src/templates/send-default.ts","../src/lib/confirm.ts","../src/lib/watch.ts","../src/formatters/send-result.ts","../src/commands/login.ts","../src/commands/logout.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { registerValidateCommand } from \"./commands/validate.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerConvertCommand } from \"./commands/convert.js\";\nimport { registerLookupCommand } from \"./commands/lookup.js\";\nimport { registerSendCommand } from \"./commands/send.js\";\nimport { registerLoginCommand } from \"./commands/login.js\";\nimport { registerLogoutCommand } from \"./commands/logout.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"getpeppr\")\n .description(\"CLI tool for Peppol e-invoice validation and development\")\n .version(version);\n\nregisterValidateCommand(program);\nregisterInitCommand(program);\nregisterConvertCommand(program);\nregisterLookupCommand(program);\nregisterSendCommand(program);\nregisterLoginCommand(program);\nregisterLogoutCommand(program);\n\nprogram.parse();\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { InvoiceInput } from \"@getpeppr/sdk\";\nimport { exitWithError } from \"./errors.js\";\n\nexport type FileReadResult =\n | { ok: true; data: unknown }\n | { ok: false; error: string };\n\nexport function readJsonFile(filePath: string): FileReadResult {\n const resolved = resolve(filePath);\n\n if (!existsSync(resolved)) {\n return { ok: false, error: `Error: file not found — ${resolved}` };\n }\n\n let content: string;\n try {\n content = readFileSync(resolved, \"utf-8\");\n } catch {\n return { ok: false, error: `Error: could not read file — ${resolved}` };\n }\n\n try {\n const data: unknown = JSON.parse(content);\n return { ok: true, data };\n } catch {\n return { ok: false, error: `Error: invalid JSON in file — ${resolved}` };\n }\n}\n\nexport function readAndValidateInvoiceJson(filePath: string): InvoiceInput {\n const parseResult = readJsonFile(filePath);\n if (!parseResult.ok) {\n exitWithError(parseResult.error);\n }\n\n if (\n typeof parseResult.data !== \"object\" ||\n parseResult.data === null ||\n Array.isArray(parseResult.data)\n ) {\n exitWithError(\n \"Error: JSON file must contain an object, not an array or primitive\",\n );\n }\n\n return parseResult.data as InvoiceInput;\n}\n","export function exitWithError(message: string, code = 2): never {\n process.stderr.write(message + \"\\n\");\n process.exit(code);\n}\n","import pc from \"picocolors\";\nimport type { MergedValidationResult } from \"../commands/validate.js\";\nimport type { ValidationError, ValidationWarning, SchematronViolation } from \"@getpeppr/sdk\";\n\nfunction sectionHeader(title: string): string {\n const pad = 45 - title.length - 4;\n return pc.dim(`── ${title} ${\"─\".repeat(Math.max(pad, 3))}`);\n}\n\nfunction formatError(item: ValidationError | SchematronViolation): string {\n const ruleId = \"ruleId\" in item && item.ruleId ? pc.dim(` (${item.ruleId})`) : \"\";\n const field = \"field\" in item && item.field ? `${item.field} — ` : \"\";\n return ` ${pc.red(\"✗\")} ${field}${item.message}${ruleId}`;\n}\n\nfunction formatWarning(item: ValidationWarning | SchematronViolation): string {\n const ruleId = \"ruleId\" in item && item.ruleId ? pc.dim(` (${item.ruleId})`) : \"\";\n const field = \"field\" in item && item.field ? `${item.field} — ` : \"\";\n return ` ${pc.yellow(\"⚠\")} ${field}${item.message}${ruleId}`;\n}\n\nfunction formatSection(\n title: string,\n errors: (ValidationError | SchematronViolation)[],\n warnings: (ValidationWarning | SchematronViolation)[],\n): string {\n const lines: string[] = [sectionHeader(title)];\n\n if (errors.length === 0 && warnings.length === 0) {\n lines.push(` ${pc.green(\"✓\")} All rules passed`);\n return lines.join(\"\\n\");\n }\n\n if (errors.length === 0) {\n lines.push(` ${pc.green(\"✓\")} No errors`);\n }\n\n for (const err of errors) {\n lines.push(formatError(err));\n }\n\n for (const warn of warnings) {\n lines.push(formatWarning(warn));\n }\n\n return lines.join(\"\\n\");\n}\n\nexport function formatValidationResult(\n filename: string,\n result: MergedValidationResult,\n): string {\n const lines: string[] = [];\n\n lines.push(`\\nValidating: ${pc.bold(filename)}\\n`);\n\n lines.push(\n formatSection(\n \"Structure\",\n result.structure.errors,\n result.structure.warnings,\n ),\n );\n lines.push(\"\");\n\n lines.push(\n formatSection(\n \"Business Rules (Peppol BIS 3.0)\",\n result.schematron.errors,\n result.schematron.warnings,\n ),\n );\n lines.push(\"\");\n\n lines.push(\n formatSection(\n \"Country Rules\",\n result.countryRules.errors,\n result.countryRules.warnings,\n ),\n );\n lines.push(\"\");\n\n // Summary\n lines.push(sectionHeader(\"Summary\"));\n const { totalErrors, totalWarnings, valid } = result;\n\n if (valid && totalWarnings === 0) {\n lines.push(` ${pc.green(pc.bold(\"✓ Invoice is valid\"))}`);\n } else if (valid) {\n lines.push(\n ` ${pc.green(pc.bold(\"✓ Invoice is valid\"))} ${pc.dim(`(${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"})`)}`,\n );\n } else {\n const parts: string[] = [];\n parts.push(`${totalErrors} error${totalErrors === 1 ? \"\" : \"s\"}`);\n if (totalWarnings > 0) {\n parts.push(`${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"}`);\n }\n lines.push(\n ` ${pc.red(pc.bold(`✗ ${parts.join(\", \")}`))} — invoice non-compliant`,\n );\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n","/**\n * UBL XML Builder\n *\n * Converts our clean JSON invoice format to Peppol BIS 3.0 compliant UBL 2.1 XML.\n * This is the core abstraction that hides XML complexity from developers.\n *\n * Reference: https://docs.peppol.eu/poacc/billing/3.0/\n */\n\nimport type { InvoiceInput, CreditNoteInput, InvoiceLine, Party, Delivery, AllowanceCharge, Attachment, InvoicePeriod } from \"../types/invoice.js\";\n\nconst UBL_NS = \"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\";\nconst CAC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\";\nconst CBC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\";\nconst CREDIT_NOTE_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2\";\n\n// Peppol BIS 3.0 customization and profile IDs\nconst PEPPOL_CUSTOMIZATION_ID =\n \"urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\";\nconst PEPPOL_PROFILE_ID = \"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\";\n\n/** Default unit of measure */\nconst DEFAULT_UNIT = \"EA\";\n\n/** Default payment means code (30 = credit transfer) */\nconst DEFAULT_PAYMENT_MEANS = 30;\n\n/** Map human-readable unit names to UN/ECE Recommendation 20 codes */\nconst UNIT_CODE_MAP: Record<string, string> = {\n each: \"EA\", piece: \"EA\", pieces: \"EA\",\n hour: \"HUR\", hours: \"HUR\",\n day: \"DAY\", days: \"DAY\",\n week: \"WEE\", weeks: \"WEE\",\n month: \"MON\", months: \"MON\",\n year: \"ANN\", years: \"ANN\",\n kilogram: \"KGM\", kg: \"KGM\",\n meter: \"MTR\", metre: \"MTR\",\n liter: \"LTR\", litre: \"LTR\",\n unit: \"C62\", units: \"C62\",\n set: \"SET\", sets: \"SET\",\n pack: \"PK\", packs: \"PK\",\n};\n\n/**\n * Resolve a human-readable unit name to its UN/ECE Recommendation 20 code.\n * If already a valid UBL code (2-3 uppercase chars) or unknown, passes through unchanged.\n */\nfunction resolveUnitCode(unit: string): string {\n return UNIT_CODE_MAP[unit.toLowerCase()] ?? unit;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\nfunction formatDate(dateStr?: string): string {\n if (!dateStr) {\n return new Date().toISOString().split(\"T\")[0]!;\n }\n // Accept ISO 8601 date or datetime\n return dateStr.split(\"T\")[0]!;\n}\n\nfunction formatAmount(amount: number): string {\n return amount.toFixed(2);\n}\n\n/** Round to 2 decimal places to prevent IEEE 754 accumulation errors */\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nfunction parsePeppolId(peppolId: string): { scheme: string; id: string } {\n const scheme = peppolId.split(\":\")[0]!;\n const id = peppolId.split(\":\").slice(1).join(\":\");\n return { scheme, id };\n}\n\nfunction buildPartyXml(party: Party, role: \"AccountingSupplierParty\" | \"AccountingCustomerParty\"): string {\n const { scheme: endpointScheme, id: endpointId } = parsePeppolId(party.peppolId);\n\n return `\n <cac:${role}>\n <cac:Party>\n <cbc:EndpointID schemeID=\"${escapeXml(endpointScheme)}\">${escapeXml(endpointId)}</cbc:EndpointID>\n <cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(endpointScheme)}\">${escapeXml(endpointId)}</cbc:ID>\n </cac:PartyIdentification>\n <cac:PartyName>\n <cbc:Name>${escapeXml(party.name)}</cbc:Name>\n </cac:PartyName>\n <cac:PostalAddress>\n ${party.street ? `<cbc:StreetName>${escapeXml(party.street)}</cbc:StreetName>` : \"\"}\n ${party.city ? `<cbc:CityName>${escapeXml(party.city)}</cbc:CityName>` : \"\"}\n ${party.postalCode ? `<cbc:PostalZone>${escapeXml(party.postalCode)}</cbc:PostalZone>` : \"\"}\n <cac:Country>\n <cbc:IdentificationCode>${escapeXml(party.country)}</cbc:IdentificationCode>\n </cac:Country>\n </cac:PostalAddress>\n ${\n party.vatNumber\n ? `<cac:PartyTaxScheme>\n <cbc:CompanyID>${escapeXml(party.vatNumber)}</cbc:CompanyID>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:PartyTaxScheme>`\n : \"\"\n }\n <cac:PartyLegalEntity>\n <cbc:RegistrationName>${escapeXml(party.name)}</cbc:RegistrationName>\n ${party.companyId ? `<cbc:CompanyID>${escapeXml(party.companyId)}</cbc:CompanyID>` : \"\"}\n </cac:PartyLegalEntity>\n ${(party.contactName || party.phone || party.email)\n ? `<cac:Contact>\n ${party.contactName ? `<cbc:Name>${escapeXml(party.contactName)}</cbc:Name>` : \"\"}\n ${party.phone ? `<cbc:Telephone>${escapeXml(party.phone)}</cbc:Telephone>` : \"\"}\n ${party.email ? `<cbc:ElectronicMail>${escapeXml(party.email)}</cbc:ElectronicMail>` : \"\"}\n </cac:Contact>`\n : \"\"\n }\n </cac:Party>\n </cac:${role}>`;\n}\n\nfunction buildPayeePartyXml(party: Party): string {\n const { scheme, id } = parsePeppolId(party.peppolId);\n\n return `\n <cac:PayeeParty>\n <cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(scheme)}\">${escapeXml(id)}</cbc:ID>\n </cac:PartyIdentification>\n <cac:PartyName>\n <cbc:Name>${escapeXml(party.name)}</cbc:Name>\n </cac:PartyName>\n ${party.companyId\n ? `<cac:PartyLegalEntity>\n <cbc:RegistrationName>${escapeXml(party.name)}</cbc:RegistrationName>\n <cbc:CompanyID>${escapeXml(party.companyId)}</cbc:CompanyID>\n </cac:PartyLegalEntity>`\n : \"\"\n }\n </cac:PayeeParty>`;\n}\n\nfunction buildTaxRepresentativePartyXml(party: Party): string {\n const parts: string[] = [\n \" <cac:TaxRepresentativeParty>\",\n \" <cac:PartyName>\",\n ` <cbc:Name>${escapeXml(party.name)}</cbc:Name>`,\n \" </cac:PartyName>\",\n ];\n\n // PostalAddress\n parts.push(\" <cac:PostalAddress>\");\n if (party.street) {\n parts.push(` <cbc:StreetName>${escapeXml(party.street)}</cbc:StreetName>`);\n }\n if (party.city) {\n parts.push(` <cbc:CityName>${escapeXml(party.city)}</cbc:CityName>`);\n }\n if (party.postalCode) {\n parts.push(` <cbc:PostalZone>${escapeXml(party.postalCode)}</cbc:PostalZone>`);\n }\n parts.push(\" <cac:Country>\");\n parts.push(` <cbc:IdentificationCode>${escapeXml(party.country)}</cbc:IdentificationCode>`);\n parts.push(\" </cac:Country>\");\n parts.push(\" </cac:PostalAddress>\");\n\n // PartyTaxScheme (vatNumber → CompanyID)\n if (party.vatNumber) {\n parts.push(\" <cac:PartyTaxScheme>\");\n parts.push(` <cbc:CompanyID>${escapeXml(party.vatNumber)}</cbc:CompanyID>`);\n parts.push(\" <cac:TaxScheme>\");\n parts.push(\" <cbc:ID>VAT</cbc:ID>\");\n parts.push(\" </cac:TaxScheme>\");\n parts.push(\" </cac:PartyTaxScheme>\");\n }\n\n parts.push(\" </cac:TaxRepresentativeParty>\");\n return parts.join(\"\\n\");\n}\n\nfunction buildAttachmentXml(attachment: Attachment): string {\n const parts: string[] = [\n \"<cac:AdditionalDocumentReference>\",\n ` <cbc:ID>${escapeXml(attachment.id)}</cbc:ID>`,\n ];\n\n if (attachment.description) {\n parts.push(` <cbc:DocumentDescription>${escapeXml(attachment.description)}</cbc:DocumentDescription>`);\n }\n\n if (attachment.content || attachment.url) {\n parts.push(\" <cac:Attachment>\");\n if (attachment.content && attachment.mimeType && attachment.filename) {\n parts.push(\n ` <cbc:EmbeddedDocumentBinaryObject mimeCode=\"${escapeXml(attachment.mimeType)}\" filename=\"${escapeXml(attachment.filename)}\">${attachment.content}</cbc:EmbeddedDocumentBinaryObject>`,\n );\n } else if (attachment.url) {\n parts.push(\n ` <cac:ExternalReference>\\n <cbc:URI>${escapeXml(attachment.url)}</cbc:URI>\\n </cac:ExternalReference>`,\n );\n }\n parts.push(\" </cac:Attachment>\");\n }\n\n parts.push(\"</cac:AdditionalDocumentReference>\");\n return parts.join(\"\\n \");\n}\n\nfunction buildInvoicePeriodXml(period: InvoicePeriod): string {\n const parts: string[] = [\"<cac:InvoicePeriod>\"];\n if (period.startDate) {\n parts.push(` <cbc:StartDate>${formatDate(period.startDate)}</cbc:StartDate>`);\n }\n if (period.endDate) {\n parts.push(` <cbc:EndDate>${formatDate(period.endDate)}</cbc:EndDate>`);\n }\n parts.push(\"</cac:InvoicePeriod>\");\n return parts.join(\"\\n \");\n}\n\nfunction buildDeliveryXml(delivery: Delivery): string {\n const parts: string[] = [\"<cac:Delivery>\"];\n\n if (delivery.date) {\n parts.push(` <cbc:ActualDeliveryDate>${formatDate(delivery.date)}</cbc:ActualDeliveryDate>`);\n }\n\n if (delivery.locationId || delivery.address) {\n parts.push(\" <cac:DeliveryLocation>\");\n if (delivery.locationId) {\n parts.push(` <cbc:ID>${escapeXml(delivery.locationId)}</cbc:ID>`);\n }\n if (delivery.address) {\n parts.push(\" <cac:Address>\");\n if (delivery.address.street) {\n parts.push(` <cbc:StreetName>${escapeXml(delivery.address.street)}</cbc:StreetName>`);\n }\n if (delivery.address.city) {\n parts.push(` <cbc:CityName>${escapeXml(delivery.address.city)}</cbc:CityName>`);\n }\n if (delivery.address.postalCode) {\n parts.push(` <cbc:PostalZone>${escapeXml(delivery.address.postalCode)}</cbc:PostalZone>`);\n }\n parts.push(` <cac:Country>\\n <cbc:IdentificationCode>${escapeXml(delivery.address.country)}</cbc:IdentificationCode>\\n </cac:Country>`);\n parts.push(\" </cac:Address>\");\n }\n parts.push(\" </cac:DeliveryLocation>\");\n }\n\n parts.push(\"</cac:Delivery>\");\n return parts.join(\"\\n \");\n}\n\nfunction buildDocumentAllowanceChargeXml(\n item: AllowanceCharge,\n isCharge: boolean,\n currency: string,\n): string {\n const vatCategory = item.vatCategory ?? \"S\";\n return `\n <cac:AllowanceCharge>\n <cbc:ChargeIndicator>${isCharge}</cbc:ChargeIndicator>\n <cbc:AllowanceChargeReason>${escapeXml(item.reason)}</cbc:AllowanceChargeReason>\n <cbc:Amount currencyID=\"${escapeXml(currency)}\">${formatAmount(item.amount)}</cbc:Amount>\n <cac:TaxCategory>\n <cbc:ID>${vatCategory}</cbc:ID>\n <cbc:Percent>${item.vatRate}</cbc:Percent>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:TaxCategory>\n </cac:AllowanceCharge>`;\n}\n\nfunction buildLineAllowanceChargeXml(\n reason: string,\n amount: number,\n isCharge: boolean,\n currency: string,\n): string {\n return `\n <cac:AllowanceCharge>\n <cbc:ChargeIndicator>${isCharge}</cbc:ChargeIndicator>\n <cbc:AllowanceChargeReason>${escapeXml(reason)}</cbc:AllowanceChargeReason>\n <cbc:Amount currencyID=\"${escapeXml(currency)}\">${formatAmount(amount)}</cbc:Amount>\n </cac:AllowanceCharge>`;\n}\n\nfunction calculateLineExtensionAmount(line: InvoiceLine): number {\n const base = line.quantity * line.unitPrice;\n const lineAllowances = (line.allowances ?? []).reduce((sum, a) => sum + a.amount, 0);\n const lineCharges = (line.charges ?? []).reduce((sum, c) => sum + c.amount, 0);\n return base - lineAllowances + lineCharges;\n}\n\ntype LineType = \"InvoiceLine\" | \"CreditNoteLine\";\ntype QuantityType = \"InvoicedQuantity\" | \"CreditedQuantity\";\n\nfunction buildDocumentLineXml(\n line: InvoiceLine,\n index: number,\n currency: string,\n lineTag: LineType,\n qtyTag: QuantityType,\n): string {\n const lineTotal = calculateLineExtensionAmount(line);\n const unit = resolveUnitCode(line.unit ?? DEFAULT_UNIT);\n const vatCategory = line.vatCategory ?? \"S\";\n\n const lineAllowancesXml = (line.allowances ?? [])\n .map((a) => buildLineAllowanceChargeXml(a.reason, a.amount, false, currency))\n .join(\"\");\n const lineChargesXml = (line.charges ?? [])\n .map((c) => buildLineAllowanceChargeXml(c.reason, c.amount, true, currency))\n .join(\"\");\n\n return `\n <cac:${lineTag}>\n <cbc:ID>${index + 1}</cbc:ID>\n ${line.accountingCost ? `<cbc:AccountingCost>${escapeXml(line.accountingCost)}</cbc:AccountingCost>` : \"\"}\n <cbc:${qtyTag} unitCode=\"${escapeXml(unit)}\">${Number(line.quantity.toFixed(6))}</cbc:${qtyTag}>\n <cbc:LineExtensionAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(lineTotal)}</cbc:LineExtensionAmount>\n ${lineAllowancesXml}${lineChargesXml}\n <cac:Item>\n <cbc:Name>${escapeXml(line.description)}</cbc:Name>\n ${\n line.itemId\n ? `<cac:SellersItemIdentification>\n <cbc:ID>${escapeXml(line.itemId)}</cbc:ID>\n </cac:SellersItemIdentification>`\n : \"\"\n }\n <cac:ClassifiedTaxCategory>\n <cbc:ID>${vatCategory}</cbc:ID>\n <cbc:Percent>${line.vatRate}</cbc:Percent>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:ClassifiedTaxCategory>\n ${\n line.standardItemId\n ? `<cac:StandardItemIdentification>\n <cbc:ID schemeID=\"${escapeXml(line.standardItemScheme ?? \"0160\")}\">${escapeXml(line.standardItemId)}</cbc:ID>\n </cac:StandardItemIdentification>`\n : \"\"\n }\n ${\n line.commodityCode && line.commodityScheme\n ? `<cac:CommodityClassification>\n <cbc:ItemClassificationCode listID=\"${escapeXml(line.commodityScheme)}\">${escapeXml(line.commodityCode)}</cbc:ItemClassificationCode>\n </cac:CommodityClassification>`\n : \"\"\n }\n ${(line.properties ?? []).map(\n (p) => `<cac:AdditionalItemProperty>\n <cbc:Name>${escapeXml(p.name)}</cbc:Name>\n <cbc:Value>${escapeXml(p.value)}</cbc:Value>\n </cac:AdditionalItemProperty>`\n ).join(\"\\n \")}\n </cac:Item>\n <cac:Price>\n <cbc:PriceAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(line.unitPrice)}</cbc:PriceAmount>\n ${line.baseQuantity != null ? `<cbc:BaseQuantity unitCode=\"${escapeXml(resolveUnitCode(line.baseQuantityUnit ?? line.unit ?? DEFAULT_UNIT))}\">${line.baseQuantity}</cbc:BaseQuantity>` : \"\"}\n </cac:Price>\n </cac:${lineTag}>`;\n}\n\nfunction buildInvoiceLineXml(line: InvoiceLine, index: number, currency: string): string {\n return buildDocumentLineXml(line, index, currency, \"InvoiceLine\", \"InvoicedQuantity\");\n}\n\ninterface TaxSubtotal {\n vatRate: number;\n vatCategory: string;\n taxableAmount: number;\n taxAmount: number;\n}\n\nfunction calculateTaxSubtotals(\n lines: InvoiceLine[],\n allowances?: AllowanceCharge[],\n charges?: AllowanceCharge[],\n): TaxSubtotal[] {\n const groups = new Map<string, TaxSubtotal>();\n\n function addToGroup(vatCategory: string, vatRate: number, amount: number) {\n const key = `${vatCategory}-${vatRate}`;\n const existing = groups.get(key);\n if (existing) {\n existing.taxableAmount = round2(existing.taxableAmount + amount);\n } else {\n groups.set(key, {\n vatRate,\n vatCategory,\n taxableAmount: amount,\n taxAmount: 0, // computed once per group below (BR-CO-17)\n });\n }\n }\n\n for (const line of lines) {\n addToGroup(line.vatCategory ?? \"S\", line.vatRate, calculateLineExtensionAmount(line));\n }\n\n for (const a of allowances ?? []) {\n addToGroup(a.vatCategory ?? \"S\", a.vatRate, -a.amount);\n }\n\n for (const c of charges ?? []) {\n addToGroup(c.vatCategory ?? \"S\", c.vatRate, c.amount);\n }\n\n // BR-CO-17: BT-117 = round2(group taxable base × rate), rounded ONCE per group —\n // accumulating per-line rounded taxes drifts a cent on sub-cent line amounts\n // (2 × €0.03 @21% → 0.02 instead of the compliant 0.01) and diverges from the\n // grouped figure the getpeppr gateway sends to the provider (GPR-833).\n return Array.from(groups.values()).map((subtotal) => ({\n ...subtotal,\n taxAmount: round2(subtotal.taxableAmount * (subtotal.vatRate / 100)),\n }));\n}\n\n// ─── Shared document-level XML fragments ───────────────────\n\ninterface DocumentTotals {\n lineExtensionAmount: number;\n allowanceTotalAmount: number;\n chargeTotalAmount: number;\n taxExclusiveAmount: number;\n totalTax: number;\n taxInclusiveAmount: number;\n payableAmount: number;\n taxSubtotals: TaxSubtotal[];\n}\n\nfunction calculateDocumentTotals(\n lines: InvoiceLine[],\n allowances?: AllowanceCharge[],\n charges?: AllowanceCharge[],\n): DocumentTotals {\n const taxSubtotals = calculateTaxSubtotals(lines, allowances, charges);\n const lineExtensionAmount = lines.reduce(\n (sum, line) => sum + calculateLineExtensionAmount(line),\n 0,\n );\n const allowanceTotalAmount = (allowances ?? []).reduce((sum, a) => sum + a.amount, 0);\n const chargeTotalAmount = (charges ?? []).reduce((sum, c) => sum + c.amount, 0);\n const taxExclusiveAmount = round2(lineExtensionAmount - allowanceTotalAmount + chargeTotalAmount);\n const totalTax = round2(taxSubtotals.reduce((sum, st) => sum + st.taxAmount, 0));\n const taxInclusiveAmount = round2(taxExclusiveAmount + totalTax);\n return {\n lineExtensionAmount,\n allowanceTotalAmount,\n chargeTotalAmount,\n taxExclusiveAmount,\n totalTax,\n taxInclusiveAmount,\n payableAmount: taxInclusiveAmount,\n taxSubtotals,\n };\n}\n\nfunction buildTaxTotalXml(taxSubtotals: TaxSubtotal[], totalTax: number, currency: string): string {\n const subtotalsXml = taxSubtotals\n .map(\n (st) => `\n <cac:TaxSubtotal>\n <cbc:TaxableAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(st.taxableAmount)}</cbc:TaxableAmount>\n <cbc:TaxAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(st.taxAmount)}</cbc:TaxAmount>\n <cac:TaxCategory>\n <cbc:ID>${st.vatCategory}</cbc:ID>\n <cbc:Percent>${st.vatRate}</cbc:Percent>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:TaxCategory>\n </cac:TaxSubtotal>`,\n )\n .join(\"\");\n\n return `<cac:TaxTotal>\n <cbc:TaxAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totalTax)}</cbc:TaxAmount>\n ${subtotalsXml}\n </cac:TaxTotal>`;\n}\n\nfunction buildTaxCurrencyTotalXml(totalTax: number, taxCurrency: string, rate: number): string {\n const convertedAmount = Math.round(totalTax * rate * 100) / 100;\n return `<cac:TaxTotal>\n <cbc:TaxAmount currencyID=\"${escapeXml(taxCurrency)}\">${formatAmount(convertedAmount)}</cbc:TaxAmount>\n </cac:TaxTotal>`;\n}\n\ninterface LegalMonetaryTotalOptions {\n prepaidAmount?: number;\n roundingAmount?: number;\n}\n\n/** BT-115 arithmetic — the single formula behind both the rendered\n * cbc:PayableAmount and computeUblPayableAmount. Rounded via toFixed to be\n * EXACTLY the figure formatAmount renders (Math.round-based round2 drifts a\n * cent from the historic rendering on float dust, e.g. roundingAmount −0.325). */\nfunction payableFromTaxInclusive(\n taxInclusiveAmount: number,\n prepaidAmount?: number,\n roundingAmount?: number,\n): number {\n return Number((taxInclusiveAmount - (prepaidAmount ?? 0) + (roundingAmount ?? 0)).toFixed(2));\n}\n\n/** Monetary-only projection of an invoice / credit note — the fields that\n * determine the legal amount due. Party and routing data are irrelevant here. */\nexport interface UblMonetaryInput {\n lines: InvoiceLine[];\n allowances?: AllowanceCharge[];\n charges?: AllowanceCharge[];\n prepaidAmount?: number;\n roundingAmount?: number;\n}\n\n/**\n * BT-115 PayableAmount of the document — the legal amount due, integrating\n * line- and document-level allowances/charges, VAT, prepaid and rounding.\n * This is the SAME computation buildInvoiceXml/buildCreditNoteXml render into\n * cac:LegalMonetaryTotal, exposed so consumers (e.g. the getpeppr gateway's\n * settlement ledger, GPR-833) never re-derive the amount from a parallel\n * formula that would drift from the UBL on the network.\n */\nexport function computeUblPayableAmount(input: UblMonetaryInput): number {\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n return payableFromTaxInclusive(totals.taxInclusiveAmount, input.prepaidAmount, input.roundingAmount);\n}\n\nfunction buildLegalMonetaryTotalXml(totals: DocumentTotals, currency: string, options?: LegalMonetaryTotalOptions): string {\n const prepaid = options?.prepaidAmount;\n const rounding = options?.roundingAmount;\n const payableAmount = payableFromTaxInclusive(totals.taxInclusiveAmount, prepaid, rounding);\n\n return `<cac:LegalMonetaryTotal>\n <cbc:LineExtensionAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.lineExtensionAmount)}</cbc:LineExtensionAmount>\n <cbc:TaxExclusiveAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.taxExclusiveAmount)}</cbc:TaxExclusiveAmount>\n <cbc:TaxInclusiveAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.taxInclusiveAmount)}</cbc:TaxInclusiveAmount>\n ${totals.allowanceTotalAmount > 0 ? `<cbc:AllowanceTotalAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.allowanceTotalAmount)}</cbc:AllowanceTotalAmount>` : \"\"}\n ${totals.chargeTotalAmount > 0 ? `<cbc:ChargeTotalAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.chargeTotalAmount)}</cbc:ChargeTotalAmount>` : \"\"}\n ${prepaid != null ? `<cbc:PrepaidAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(prepaid)}</cbc:PrepaidAmount>` : \"\"}\n ${rounding != null ? `<cbc:PayableRoundingAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(rounding)}</cbc:PayableRoundingAmount>` : \"\"}\n <cbc:PayableAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(payableAmount)}</cbc:PayableAmount>\n </cac:LegalMonetaryTotal>`;\n}\n\nfunction buildPaymentMeansXml(input: InvoiceInput | CreditNoteInput): string {\n const paymentMeans = input.paymentMeans ?? DEFAULT_PAYMENT_MEANS;\n return `<cac:PaymentMeans>\n <cbc:PaymentMeansCode>${paymentMeans}</cbc:PaymentMeansCode>\n ${input.paymentReference ? `<cbc:PaymentID>${escapeXml(input.paymentReference)}</cbc:PaymentID>` : \"\"}\n ${\n input.paymentIban\n ? `<cac:PayeeFinancialAccount>\n <cbc:ID>${escapeXml(input.paymentIban)}</cbc:ID>\n ${\n input.paymentBic\n ? `<cac:FinancialInstitutionBranch>\n <cbc:ID>${escapeXml(input.paymentBic)}</cbc:ID>\n </cac:FinancialInstitutionBranch>`\n : \"\"\n }\n </cac:PayeeFinancialAccount>`\n : \"\"\n }\n </cac:PaymentMeans>`;\n}\n\nfunction buildCreditNoteLineXml(line: InvoiceLine, index: number, currency: string): string {\n return buildDocumentLineXml(line, index, currency, \"CreditNoteLine\", \"CreditedQuantity\");\n}\n\nfunction buildOrderReferenceXml(orderReference?: string, salesOrderReference?: string): string {\n if (!orderReference && !salesOrderReference) return \"\";\n const parts: string[] = [\"<cac:OrderReference>\"];\n if (orderReference) {\n parts.push(`<cbc:ID>${escapeXml(orderReference)}</cbc:ID>`);\n }\n if (salesOrderReference) {\n parts.push(`<cbc:SalesOrderID>${escapeXml(salesOrderReference)}</cbc:SalesOrderID>`);\n }\n parts.push(\"</cac:OrderReference>\");\n return parts.join(\"\");\n}\n\n/**\n * Build a Peppol BIS 3.0 compliant UBL 2.1 Invoice XML from a simple JSON input.\n */\nexport function buildInvoiceXml(input: InvoiceInput): string {\n const currency = input.currency ?? \"EUR\";\n const date = formatDate(input.date);\n const dueDate = input.dueDate ? formatDate(input.dueDate) : undefined;\n const hasTaxCurrency = input.taxCurrency && input.taxCurrency !== currency;\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n\n const linesXml = input.lines\n .map((line, i) => buildInvoiceLineXml(line, i, currency))\n .join(\"\");\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"${UBL_NS}\"\n xmlns:cac=\"${CAC_NS}\"\n xmlns:cbc=\"${CBC_NS}\">\n <cbc:CustomizationID>${PEPPOL_CUSTOMIZATION_ID}</cbc:CustomizationID>\n <cbc:ProfileID>${PEPPOL_PROFILE_ID}</cbc:ProfileID>\n <cbc:ID>${escapeXml(input.number)}</cbc:ID>\n <cbc:IssueDate>${date}</cbc:IssueDate>\n ${dueDate ? `<cbc:DueDate>${dueDate}</cbc:DueDate>` : \"\"}\n ${input.taxPointDate ? `<cbc:TaxPointDate>${formatDate(input.taxPointDate)}</cbc:TaxPointDate>` : \"\"}\n <cbc:InvoiceTypeCode>${input.invoiceTypeCode ?? (input.isCreditNote ? 381 : 380)}</cbc:InvoiceTypeCode>\n ${input.note ? `<cbc:Note>${escapeXml(input.note)}</cbc:Note>` : \"\"}\n ${input.accountingCost ? `<cbc:AccountingCost>${escapeXml(input.accountingCost)}</cbc:AccountingCost>` : \"\"}\n <cbc:DocumentCurrencyCode>${escapeXml(currency)}</cbc:DocumentCurrencyCode>\n ${hasTaxCurrency ? `<cbc:TaxCurrencyCode>${escapeXml(input.taxCurrency!)}</cbc:TaxCurrencyCode>` : \"\"}\n ${input.buyerReference ? `<cbc:BuyerReference>${escapeXml(input.buyerReference)}</cbc:BuyerReference>` : \"\"}\n ${input.invoicePeriod ? buildInvoicePeriodXml(input.invoicePeriod) : \"\"}\n ${buildOrderReferenceXml(input.orderReference, input.salesOrderReference)}\n ${input.despatchReference ? `<cac:DespatchDocumentReference><cbc:ID>${escapeXml(input.despatchReference)}</cbc:ID></cac:DespatchDocumentReference>` : \"\"}\n ${input.receiptReference ? `<cac:ReceiptDocumentReference><cbc:ID>${escapeXml(input.receiptReference)}</cbc:ID></cac:ReceiptDocumentReference>` : \"\"}\n ${input.contractReference ? `<cac:ContractDocumentReference><cbc:ID>${escapeXml(input.contractReference)}</cbc:ID></cac:ContractDocumentReference>` : \"\"}\n ${(input.attachments ?? []).map((a) => buildAttachmentXml(a)).join(\"\\n \")}\n ${input.projectReference ? `<cac:ProjectReference><cbc:ID>${escapeXml(input.projectReference)}</cbc:ID></cac:ProjectReference>` : \"\"}\n ${input.from ? buildPartyXml(input.from, \"AccountingSupplierParty\") : \"\"}\n ${buildPartyXml(input.to, \"AccountingCustomerParty\")}\n ${input.payeeParty ? buildPayeePartyXml(input.payeeParty) : \"\"}\n ${input.taxRepresentative ? buildTaxRepresentativePartyXml(input.taxRepresentative) : \"\"}\n ${input.delivery ? buildDeliveryXml(input.delivery) : \"\"}\n ${buildPaymentMeansXml(input)}\n ${input.paymentTerms ? `<cac:PaymentTerms>\\n <cbc:Note>${escapeXml(input.paymentTerms)}</cbc:Note>\\n </cac:PaymentTerms>` : \"\"}\n ${(input.allowances ?? []).map((a) => buildDocumentAllowanceChargeXml(a, false, currency)).join(\"\")}\n ${(input.charges ?? []).map((c) => buildDocumentAllowanceChargeXml(c, true, currency)).join(\"\")}\n ${hasTaxCurrency && input.taxCurrencyRate ? buildTaxCurrencyTotalXml(totals.totalTax, input.taxCurrency!, input.taxCurrencyRate) : \"\"}\n ${buildTaxTotalXml(totals.taxSubtotals, totals.totalTax, currency)}\n ${buildLegalMonetaryTotalXml(totals, currency, { prepaidAmount: input.prepaidAmount, roundingAmount: input.roundingAmount })}\n ${linesXml}\n</Invoice>`;\n}\n\n/**\n * Build a Peppol BIS 3.0 compliant UBL 2.1 Credit Note XML.\n *\n * Generates XML directly with correct CreditNote elements — no string replacement.\n */\nexport function buildCreditNoteXml(input: CreditNoteInput): string {\n const currency = input.currency ?? \"EUR\";\n const date = formatDate(input.date);\n const dueDate = input.dueDate ? formatDate(input.dueDate) : undefined;\n const hasTaxCurrency = input.taxCurrency && input.taxCurrency !== currency;\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n\n const linesXml = input.lines\n .map((line, i) => buildCreditNoteLineXml(line, i, currency))\n .join(\"\");\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CreditNote xmlns=\"${CREDIT_NOTE_NS}\"\n xmlns:cac=\"${CAC_NS}\"\n xmlns:cbc=\"${CBC_NS}\">\n <cbc:CustomizationID>${PEPPOL_CUSTOMIZATION_ID}</cbc:CustomizationID>\n <cbc:ProfileID>${PEPPOL_PROFILE_ID}</cbc:ProfileID>\n <cbc:ID>${escapeXml(input.number)}</cbc:ID>\n <cbc:IssueDate>${date}</cbc:IssueDate>\n ${dueDate ? `<cbc:DueDate>${dueDate}</cbc:DueDate>` : \"\"}\n ${input.taxPointDate ? `<cbc:TaxPointDate>${formatDate(input.taxPointDate)}</cbc:TaxPointDate>` : \"\"}\n <cbc:CreditNoteTypeCode>${input.invoiceTypeCode ?? 381}</cbc:CreditNoteTypeCode>\n ${input.note ? `<cbc:Note>${escapeXml(input.note)}</cbc:Note>` : \"\"}\n ${input.accountingCost ? `<cbc:AccountingCost>${escapeXml(input.accountingCost)}</cbc:AccountingCost>` : \"\"}\n <cbc:DocumentCurrencyCode>${escapeXml(currency)}</cbc:DocumentCurrencyCode>\n ${hasTaxCurrency ? `<cbc:TaxCurrencyCode>${escapeXml(input.taxCurrency!)}</cbc:TaxCurrencyCode>` : \"\"}\n ${input.buyerReference ? `<cbc:BuyerReference>${escapeXml(input.buyerReference)}</cbc:BuyerReference>` : \"\"}\n ${input.invoicePeriod ? buildInvoicePeriodXml(input.invoicePeriod) : \"\"}\n ${buildOrderReferenceXml(input.orderReference, input.salesOrderReference)}\n <cac:BillingReference><cac:InvoiceDocumentReference><cbc:ID>${escapeXml(input.invoiceReference)}</cbc:ID></cac:InvoiceDocumentReference></cac:BillingReference>\n ${input.despatchReference ? `<cac:DespatchDocumentReference><cbc:ID>${escapeXml(input.despatchReference)}</cbc:ID></cac:DespatchDocumentReference>` : \"\"}\n ${input.receiptReference ? `<cac:ReceiptDocumentReference><cbc:ID>${escapeXml(input.receiptReference)}</cbc:ID></cac:ReceiptDocumentReference>` : \"\"}\n ${input.contractReference ? `<cac:ContractDocumentReference><cbc:ID>${escapeXml(input.contractReference)}</cbc:ID></cac:ContractDocumentReference>` : \"\"}\n ${(input.attachments ?? []).map((a) => buildAttachmentXml(a)).join(\"\\n \")}\n ${input.projectReference ? `<cac:ProjectReference><cbc:ID>${escapeXml(input.projectReference)}</cbc:ID></cac:ProjectReference>` : \"\"}\n ${input.from ? buildPartyXml(input.from, \"AccountingSupplierParty\") : \"\"}\n ${buildPartyXml(input.to, \"AccountingCustomerParty\")}\n ${input.payeeParty ? buildPayeePartyXml(input.payeeParty) : \"\"}\n ${input.taxRepresentative ? buildTaxRepresentativePartyXml(input.taxRepresentative) : \"\"}\n ${input.delivery ? buildDeliveryXml(input.delivery) : \"\"}\n ${buildPaymentMeansXml(input)}\n ${input.paymentTerms ? `<cac:PaymentTerms>\\n <cbc:Note>${escapeXml(input.paymentTerms)}</cbc:Note>\\n </cac:PaymentTerms>` : \"\"}\n ${(input.allowances ?? []).map((a) => buildDocumentAllowanceChargeXml(a, false, currency)).join(\"\")}\n ${(input.charges ?? []).map((c) => buildDocumentAllowanceChargeXml(c, true, currency)).join(\"\")}\n ${hasTaxCurrency && input.taxCurrencyRate ? buildTaxCurrencyTotalXml(totals.totalTax, input.taxCurrency!, input.taxCurrencyRate) : \"\"}\n ${buildTaxTotalXml(totals.taxSubtotals, totals.totalTax, currency)}\n ${buildLegalMonetaryTotalXml(totals, currency, { prepaidAmount: input.prepaidAmount, roundingAmount: input.roundingAmount })}\n ${linesXml}\n</CreditNote>`;\n}\n","/**\n * Luhn mod-10 checksum used by French SIREN/SIRET identifiers.\n * Input is checked digits-only: callers must `.trim()` and ensure length.\n */\n\nexport function isValidLuhn(input: string): boolean {\n // Runtime guard for untyped (plain JS) callers: RegExp.test() coerces\n // numbers, but the digit loop below silently misbehaves on non-strings.\n if (typeof input !== \"string\") return false;\n if (!/^\\d+$/.test(input)) return false;\n let sum = 0;\n let alt = false;\n for (let i = input.length - 1; i >= 0; i--) {\n let n = input.charCodeAt(i) - 48;\n if (alt) {\n n *= 2;\n if (n > 9) n -= 9;\n }\n sum += n;\n alt = !alt;\n }\n return sum % 10 === 0;\n}\n\n/** SIREN of La Poste — the only unit whose SIRETs may fail Luhn (INSEE-documented). */\nconst LA_POSTE_SIREN = \"356000000\";\n\n/**\n * SIRET checksum per the INSEE validation contract:\n * - the embedded SIREN (first 9 digits) must itself be Luhn-valid;\n * - the full 14 digits must be Luhn-valid, EXCEPT for La Poste\n * (SIREN 356000000 exactly): its establishment SIRETs may fail Luhn and are\n * then valid when the sum of the 14 digits is a multiple of 5. The head\n * office (…00048) satisfies standard Luhn — the digit-sum rule is a\n * fallback, not a replacement.\n */\nexport function isValidLuhnSiret(input: string): boolean {\n if (typeof input !== \"string\") return false;\n if (!/^\\d{14}$/.test(input)) return false;\n\n const siren = input.slice(0, 9);\n if (!isValidLuhn(siren)) return false;\n\n if (isValidLuhn(input)) return true;\n\n if (siren === LA_POSTE_SIREN) {\n let sum = 0;\n for (let i = 0; i < input.length; i++) {\n sum += input.charCodeAt(i) - 48;\n }\n return sum % 5 === 0;\n }\n\n return false;\n}\n","/**\n * Country-Specific Validation Rules\n *\n * Produces warnings (not blocking errors) for country-specific invoice requirements.\n * Invoices can still be sent, but developers get helpful feedback about\n * local compliance expectations.\n *\n * Each rule has a unique ID: {CC}-{NN} (e.g., BE-01, FR-02).\n */\n\nimport type {\n InvoiceInput,\n ValidationError,\n ValidationWarning,\n} from \"../types/invoice.js\";\nimport { isValidLuhn, isValidLuhnSiret } from \"./checksums/index.js\";\n\n// ─── Result Type ─────────────────────────────────────────────\n\nexport interface CountryValidationResult {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nfunction warn(field: string, message: string, ruleId: string): ValidationWarning {\n return { field, message, ruleId };\n}\n\n// ─── Belgium (BE) ────────────────────────────────────────────\n\n/**\n * Belgian structured communication format: +++NNN/NNNN/NNNNN+++\n * The last 2 of the 12 digits are a mod-97 check digit.\n * If base mod 97 === 0, the check digit is 97.\n */\nconst BE_STRUCTURED_RE = /^\\+{3}\\d{3}\\/\\d{4}\\/\\d{5}\\+{3}$/;\n\nfunction validateBelgianCheckDigit(reference: string): boolean {\n // Extract the 12 digits from +++NNN/NNNN/NNNNN+++\n const digits = reference.replace(/[^0-9]/g, \"\");\n if (digits.length !== 12) return false;\n\n const base = parseInt(digits.slice(0, 10), 10);\n const check = parseInt(digits.slice(10, 12), 10);\n const expected = base % 97 === 0 ? 97 : base % 97;\n\n return check === expected;\n}\n\nfunction validateBelgium(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const ref = input.paymentReference;\n\n if (ref && BE_STRUCTURED_RE.test(ref)) {\n // It's in structured format — verify the checksum\n if (!validateBelgianCheckDigit(ref)) {\n warnings.push(\n warn(\n \"paymentReference\",\n `Belgian structured communication \"${ref}\" has an invalid mod-97 checksum. Verify the reference.`,\n \"BE-01\",\n ),\n );\n }\n } else if (!ref) {\n warnings.push(\n warn(\n \"paymentReference\",\n \"Belgian recipients typically expect a structured communication reference (+++NNN/NNNN/NNNNN+++ format).\",\n \"BE-02\",\n ),\n );\n }\n}\n\n/**\n * Seller-direction Belgian rules: only payment reference validation.\n * Separated from validateBelgium() to prevent buyer-focused rules\n * from accidentally firing with buyer data in a seller context.\n */\nfunction validateBelgiumSeller(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const ref = input.paymentReference;\n\n if (ref && BE_STRUCTURED_RE.test(ref)) {\n if (!validateBelgianCheckDigit(ref)) {\n warnings.push(\n warn(\n \"paymentReference\",\n `Belgian structured communication \"${ref}\" has an invalid mod-97 checksum. Verify the reference.`,\n \"BE-01\",\n ),\n );\n }\n } else if (!ref) {\n warnings.push(\n warn(\n \"paymentReference\",\n \"Belgian sellers typically include a structured communication reference (+++NNN/NNNN/NNNNN+++ format).\",\n \"BE-02\",\n ),\n );\n }\n}\n\n// ─── France (FR) ─────────────────────────────────────────────\n\nconst FR_SIREN_RE = /^\\d{9}$/;\nconst FR_SIRET_RE = /^\\d{14}$/;\n// The 2-character key may be alphanumeric, but letters I and O are excluded\n// from the key alphabet (confusable with 1 and 0).\nconst FR_VAT_RE = /^FR[0-9A-HJ-NP-Z]{2}\\d{9}$/;\n// Numeric-key form only — alphanumeric keys exist (rare but legitimate) and\n// the DGFiP key formula does not apply to them.\nconst FR_VAT_NUMERIC_KEY_RE = /^FR(\\d{2})(\\d{9})$/;\n\n/** Peppol schemes whose value is a SIREN or SIRET (SIRENE 0002, SIRET 0009, FR:CTC 0225). */\nconst FR_SIREN_BASED_SCHEMES = [\"0002\", \"0009\", \"0225\"];\n\n/**\n * DGFiP key formula for numeric-key French VAT numbers.\n * Deliberately the only VAT-content check: no Luhn on the embedded SIREN\n * (exotic but legitimate registrations, e.g. Monaco, may not carry an\n * INSEE Luhn-valid SIREN) and no cross-check against companyId (VAT-group\n * members — assujetti unique — legitimately use the group VAT number,\n * whose SIREN differs from their own).\n */\nfunction frVatKey(siren: string): number {\n return (12 + 3 * (Number(siren) % 97)) % 97;\n}\n\nfunction isValidSirenOrSiret(id: string): boolean {\n if (FR_SIREN_RE.test(id)) return isValidLuhn(id);\n if (FR_SIRET_RE.test(id)) return isValidLuhnSiret(id);\n return false;\n}\n\n/**\n * Buyer-side French identifier checks. Seller-side rules are deliberately\n * absent: `InvoiceInput.from` is deprecated/ignored (the seller is the API\n * key's Legal Entity, whose SIREN and VAT number the gateway verifies against\n * INSEE/VIES at onboarding), and VAT-rate policing is not possible offline\n * (rates depend on the place of supply, not on party countries).\n */\nfunction validateFrance(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const { companyId, companyIdScheme, vatNumber } = input.to ?? {};\n\n // companyId is only a SIREN/SIRET when no scheme is set or the scheme is\n // SIREN-based — a French company may legitimately use e.g. a GLN (0088).\n const companyIdIsSiren =\n !companyIdScheme || FR_SIREN_BASED_SCHEMES.includes(companyIdScheme);\n\n // \"Provided\" means anything but null/undefined/empty string — falsy garbage\n // like 0 or NaN from untyped JS callers must warn, not silently pass.\n if (companyId != null && companyId !== \"\" && companyIdIsSiren) {\n if (typeof companyId !== \"string\") {\n // No raw interpolation: String(Symbol) in a template literal throws.\n warnings.push(\n warn(\n \"to.companyId\",\n \"French company ID should be a string of 9 (SIREN) or 14 (SIRET) digits.\",\n \"FR-01\",\n ),\n );\n } else if (!FR_SIREN_RE.test(companyId) && !FR_SIRET_RE.test(companyId)) {\n warnings.push(\n warn(\n \"to.companyId\",\n `French company ID should be a 9-digit SIREN or 14-digit SIRET, got \"${companyId}\".`,\n \"FR-01\",\n ),\n );\n } else if (!isValidSirenOrSiret(companyId)) {\n warnings.push(\n warn(\n \"to.companyId\",\n `French company ID \"${companyId}\" has an invalid checksum. Verify the SIREN/SIRET.`,\n \"FR-01\",\n ),\n );\n }\n }\n\n if (vatNumber != null && vatNumber !== \"\") {\n if (typeof vatNumber !== \"string\") {\n warnings.push(\n warn(\n \"to.vatNumber\",\n \"French VAT number should be a string matching FR + 2 characters + 9 digits (SIREN).\",\n \"FR-02\",\n ),\n );\n } else if (!FR_VAT_RE.test(vatNumber)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `French VAT number should match format FR + 2 characters + 9 digits (SIREN), got \"${vatNumber}\".`,\n \"FR-02\",\n ),\n );\n } else {\n const numericKey = FR_VAT_NUMERIC_KEY_RE.exec(vatNumber);\n if (numericKey) {\n const [, key, siren] = numericKey;\n if (Number(key) !== frVatKey(siren)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `French VAT number \"${vatNumber}\" has an invalid verification key — expected FR${String(frVatKey(siren)).padStart(2, \"0\")}${siren}. Likely a typo.`,\n \"FR-03\",\n ),\n );\n }\n }\n }\n }\n}\n\n// ─── Italy (IT) ──────────────────────────────────────────────\n\nfunction validateItaly(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n if (!input.buyerReference) {\n warnings.push(\n warn(\n \"buyerReference\",\n \"Italian recipients (SDI) typically require a buyer reference (CIG/CUP code). Consider setting buyerReference.\",\n \"IT-01\",\n ),\n );\n }\n\n const peppolId = input.to?.peppolId;\n if (peppolId?.startsWith(\"0201:\")) {\n const fiscalCode = peppolId.slice(5);\n if (fiscalCode.length !== 11 && fiscalCode.length !== 16) {\n warnings.push(\n warn(\n \"to.peppolId\",\n `Italian fiscal code (after 0201:) should be 11 digits (partita IVA) or 16 characters (codice fiscale), got ${fiscalCode.length} characters.`,\n \"IT-02\",\n ),\n );\n }\n }\n}\n\n// ─── Netherlands (NL) ───────────────────────────────────────\n\nconst NL_KVK_RE = /^\\d{8}$/;\nconst NL_VAT_RE = /^NL\\d{9}B\\d{2}$/;\n\nfunction validateNetherlands(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const { companyId, vatNumber } = input.to ?? {};\n\n if (companyId && !NL_KVK_RE.test(companyId)) {\n warnings.push(\n warn(\n \"to.companyId\",\n `Dutch KVK number should be exactly 8 digits, got \"${companyId}\".`,\n \"NL-01\",\n ),\n );\n }\n\n if (vatNumber && !NL_VAT_RE.test(vatNumber)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `Dutch VAT number should match format NL + 9 digits + B + 2 digits, got \"${vatNumber}\".`,\n \"NL-02\",\n ),\n );\n }\n}\n\n// ─── Germany (DE) ────────────────────────────────────────────\n\nconst DE_VAT_RE = /^DE\\d{9}$/;\n\nfunction validateGermany(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const { vatNumber } = input.to ?? {};\n\n if (vatNumber && !DE_VAT_RE.test(vatNumber)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `German VAT number should match format DE + 9 digits, got \"${vatNumber}\".`,\n \"DE-01\",\n ),\n );\n }\n}\n\n// ─── Main Entry Point ───────────────────────────────────────\n\n/**\n * Validate country-specific rules for an invoice.\n *\n * Returns warnings for common compliance issues specific to the\n * recipient's country. These are advisory — the invoice can still be sent.\n *\n * @example\n * ```ts\n * const result = validateCountryRules(invoice);\n * for (const w of result.warnings) {\n * console.warn(`[${w.ruleId}] ${w.field}: ${w.message}`);\n * }\n * ```\n */\nexport function validateCountryRules(input: InvoiceInput): CountryValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n const buyerCountry = input.to?.country;\n const sellerCountry = input.from?.country;\n\n // Buyer-country rules\n if (buyerCountry) {\n switch (buyerCountry) {\n case \"BE\": validateBelgium(input, errors, warnings); break;\n case \"FR\": validateFrance(input, errors, warnings); break;\n case \"IT\": validateItaly(input, errors, warnings); break;\n case \"NL\": validateNetherlands(input, errors, warnings); break;\n case \"DE\": validateGermany(input, errors, warnings); break;\n }\n }\n\n // Seller-country rules (skip if same as buyer to avoid duplicates)\n if (sellerCountry && sellerCountry !== buyerCountry) {\n switch (sellerCountry) {\n case \"BE\": validateBelgiumSeller(input, errors, warnings); break;\n }\n }\n\n return { errors, warnings };\n}\n","/**\n * Peppol Code Lists — Static lookup utilities\n *\n * Provides tree-shakeable helper functions for common Peppol-related code lists:\n * countries, EAS schemes, unit codes, VAT categories, and payment means.\n *\n * All data is static — no API calls, no side effects.\n */\n\n// ─── Countries (ISO 3166-1 alpha-2) ───────────────────────────────────────────\n\n/** EU + EEA + common Peppol trading partners (~50 most used) */\nconst COUNTRIES: ReadonlyMap<string, string> = new Map([\n // EU member states\n [\"AT\", \"Austria\"],\n [\"BE\", \"Belgium\"],\n [\"BG\", \"Bulgaria\"],\n [\"HR\", \"Croatia\"],\n [\"CY\", \"Cyprus\"],\n [\"CZ\", \"Czechia\"],\n [\"DK\", \"Denmark\"],\n [\"EE\", \"Estonia\"],\n [\"FI\", \"Finland\"],\n [\"FR\", \"France\"],\n [\"DE\", \"Germany\"],\n [\"GR\", \"Greece\"],\n [\"HU\", \"Hungary\"],\n [\"IE\", \"Ireland\"],\n [\"IT\", \"Italy\"],\n [\"LV\", \"Latvia\"],\n [\"LT\", \"Lithuania\"],\n [\"LU\", \"Luxembourg\"],\n [\"MT\", \"Malta\"],\n [\"NL\", \"Netherlands\"],\n [\"PL\", \"Poland\"],\n [\"PT\", \"Portugal\"],\n [\"RO\", \"Romania\"],\n [\"SK\", \"Slovakia\"],\n [\"SI\", \"Slovenia\"],\n [\"ES\", \"Spain\"],\n [\"SE\", \"Sweden\"],\n // EEA (non-EU)\n [\"IS\", \"Iceland\"],\n [\"LI\", \"Liechtenstein\"],\n [\"NO\", \"Norway\"],\n // Common Peppol trading partners\n [\"GB\", \"United Kingdom\"],\n [\"CH\", \"Switzerland\"],\n [\"US\", \"United States\"],\n [\"CA\", \"Canada\"],\n [\"AU\", \"Australia\"],\n [\"NZ\", \"New Zealand\"],\n [\"SG\", \"Singapore\"],\n [\"JP\", \"Japan\"],\n [\"KR\", \"South Korea\"],\n [\"IN\", \"India\"],\n [\"TR\", \"Turkey\"],\n [\"SA\", \"Saudi Arabia\"],\n [\"AE\", \"United Arab Emirates\"],\n [\"IL\", \"Israel\"],\n [\"ZA\", \"South Africa\"],\n [\"BR\", \"Brazil\"],\n [\"MX\", \"Mexico\"],\n [\"MY\", \"Malaysia\"],\n [\"TH\", \"Thailand\"],\n [\"ID\", \"Indonesia\"],\n]);\n\n/**\n * Get the country name for an ISO 3166-1 alpha-2 code.\n *\n * @param code - Two-letter country code (case-insensitive)\n * @returns Country name or `undefined` if not found\n *\n * @example\n * ```ts\n * getCountryName(\"FR\") // \"France\"\n * getCountryName(\"XX\") // undefined\n * ```\n */\nexport function getCountryName(code: string): string | undefined {\n return COUNTRIES.get(code.toUpperCase());\n}\n\n/**\n * Get all supported countries.\n *\n * @returns Array of `{ code, name }` objects sorted by name\n */\nexport function getAllCountries(): Array<{ code: string; name: string }> {\n return Array.from(COUNTRIES.entries())\n .map(([code, name]) => ({ code, name }))\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\n// ─── Currencies (ISO 4217) ────────────────────────────────────────────────────\n\n/**\n * A currency entry per ISO 4217.\n */\nexport interface Currency {\n /** Three-letter ISO 4217 code (uppercase) */\n code: string;\n /** Currency name */\n name: string;\n /** Standard minor unit count (e.g., 2 for EUR, 0 for JPY, 3 for BHD) */\n minorUnits: number;\n}\n\n/** Common Peppol/EU trade currencies (~30 most used) */\nconst CURRENCIES: ReadonlyMap<string, Currency> = new Map([\n [\"EUR\", { code: \"EUR\", name: \"Euro\", minorUnits: 2 }],\n [\"USD\", { code: \"USD\", name: \"US Dollar\", minorUnits: 2 }],\n [\"GBP\", { code: \"GBP\", name: \"Pound Sterling\", minorUnits: 2 }],\n [\"CHF\", { code: \"CHF\", name: \"Swiss Franc\", minorUnits: 2 }],\n [\"DKK\", { code: \"DKK\", name: \"Danish Krone\", minorUnits: 2 }],\n [\"NOK\", { code: \"NOK\", name: \"Norwegian Krone\", minorUnits: 2 }],\n [\"SEK\", { code: \"SEK\", name: \"Swedish Krona\", minorUnits: 2 }],\n [\"PLN\", { code: \"PLN\", name: \"Polish Zloty\", minorUnits: 2 }],\n [\"CZK\", { code: \"CZK\", name: \"Czech Koruna\", minorUnits: 2 }],\n [\"HUF\", { code: \"HUF\", name: \"Hungarian Forint\", minorUnits: 2 }],\n [\"RON\", { code: \"RON\", name: \"Romanian Leu\", minorUnits: 2 }],\n [\"BGN\", { code: \"BGN\", name: \"Bulgarian Lev\", minorUnits: 2 }],\n [\"HRK\", { code: \"HRK\", name: \"Croatian Kuna\", minorUnits: 2 }],\n [\"ISK\", { code: \"ISK\", name: \"Icelandic Krona\", minorUnits: 0 }],\n [\"TRY\", { code: \"TRY\", name: \"Turkish Lira\", minorUnits: 2 }],\n [\"JPY\", { code: \"JPY\", name: \"Japanese Yen\", minorUnits: 0 }],\n [\"CNY\", { code: \"CNY\", name: \"Chinese Yuan\", minorUnits: 2 }],\n [\"KRW\", { code: \"KRW\", name: \"South Korean Won\", minorUnits: 0 }],\n [\"INR\", { code: \"INR\", name: \"Indian Rupee\", minorUnits: 2 }],\n [\"SGD\", { code: \"SGD\", name: \"Singapore Dollar\", minorUnits: 2 }],\n [\"AUD\", { code: \"AUD\", name: \"Australian Dollar\", minorUnits: 2 }],\n [\"NZD\", { code: \"NZD\", name: \"New Zealand Dollar\", minorUnits: 2 }],\n [\"CAD\", { code: \"CAD\", name: \"Canadian Dollar\", minorUnits: 2 }],\n [\"BRL\", { code: \"BRL\", name: \"Brazilian Real\", minorUnits: 2 }],\n [\"MXN\", { code: \"MXN\", name: \"Mexican Peso\", minorUnits: 2 }],\n [\"ZAR\", { code: \"ZAR\", name: \"South African Rand\", minorUnits: 2 }],\n [\"AED\", { code: \"AED\", name: \"UAE Dirham\", minorUnits: 2 }],\n [\"SAR\", { code: \"SAR\", name: \"Saudi Riyal\", minorUnits: 2 }],\n [\"ILS\", { code: \"ILS\", name: \"Israeli Shekel\", minorUnits: 2 }],\n [\"HKD\", { code: \"HKD\", name: \"Hong Kong Dollar\", minorUnits: 2 }],\n [\"TWD\", { code: \"TWD\", name: \"Taiwan Dollar\", minorUnits: 2 }],\n]);\n\n/**\n * Look up a currency by ISO 4217 code.\n *\n * @param code - Three-letter currency code (case-insensitive)\n * @returns The currency entry or `undefined` if not found\n *\n * @example\n * ```ts\n * getCurrency(\"EUR\") // { code: \"EUR\", name: \"Euro\", minorUnits: 2 }\n * getCurrency(\"eu\") // undefined\n * ```\n */\nexport function getCurrency(code: string): Currency | undefined {\n return CURRENCIES.get(code.toUpperCase());\n}\n\n/**\n * Get all supported currencies.\n *\n * @returns Array sorted by ISO code ascending\n */\nexport function getAllCurrencies(): Currency[] {\n return Array.from(CURRENCIES.values()).sort((a, b) => a.code.localeCompare(b.code));\n}\n\n// ─── EAS Schemes (Peppol participant identifier schemes) ──────────────────────\n\n/**\n * A Peppol Electronic Address Scheme (EAS) entry.\n */\nexport interface EasScheme {\n /** Numeric EAS code (e.g. \"0088\") */\n code: string;\n /** Human-readable scheme name */\n name: string;\n /** ISO country code if scheme is country-specific */\n country?: string;\n}\n\nconst EAS_SCHEMES: readonly EasScheme[] = [\n { code: \"0002\", name: \"System Information et Repertoire des Entreprises et des Etablissements (SIRENE)\", country: \"FR\" },\n { code: \"0007\", name: \"Organisationsnummer\", country: \"SE\" },\n { code: \"0009\", name: \"SIRET-CODE\", country: \"FR\" },\n { code: \"0088\", name: \"EAN Location Code (GLN)\" },\n { code: \"0096\", name: \"Danish Chamber of Commerce (P-nummer)\", country: \"DK\" },\n { code: \"0184\", name: \"Danish Central Business Register (CVR)\", country: \"DK\" },\n { code: \"0190\", name: \"Dutch Chamber of Commerce (KVK)\", country: \"NL\" },\n { code: \"0191\", name: \"Organisatie Identificatie Nummer (OIN)\", country: \"NL\" },\n { code: \"0192\", name: \"Danish SE-number (Erhvervsstyrelsen)\", country: \"DK\" },\n { code: \"0195\", name: \"Singapore Unique Entity Number (UEN)\", country: \"SG\" },\n { code: \"0196\", name: \"Icelandic Kennitala\", country: \"IS\" },\n { code: \"0198\", name: \"Danish ERST id (Erhvervsstyrelsen)\", country: \"DK\" },\n { code: \"0200\", name: \"Lithuanian Legal Entity Register (GRIS)\", country: \"LT\" },\n { code: \"0201\", name: \"Italian Codice Destinatario\", country: \"IT\" },\n { code: \"0202\", name: \"Italian Fiscal Code (Codice Fiscale)\", country: \"IT\" },\n { code: \"0204\", name: \"German Leitweg-ID\", country: \"DE\" },\n { code: \"0208\", name: \"Belgian Enterprise Number (KBO/BCE)\", country: \"BE\" },\n { code: \"0209\", name: \"German Creditor Identifier (GS1)\", country: \"DE\" },\n { code: \"0210\", name: \"Italian Codice Fiscale (per IPA)\", country: \"IT\" },\n { code: \"0211\", name: \"Italian Partita IVA (VAT number)\", country: \"IT\" },\n { code: \"0212\", name: \"Finnish OVT code\", country: \"FI\" },\n { code: \"0213\", name: \"Finnish OP identifier\", country: \"FI\" },\n { code: \"0225\", name: \"FRCTC Electronic Address\", country: \"FR\" },\n { code: \"9957\", name: \"French VAT number\", country: \"FR\" },\n] as const;\n\n/** Lookup index: EAS code → scheme */\nconst EAS_BY_CODE: ReadonlyMap<string, EasScheme> = new Map(\n EAS_SCHEMES.map((s) => [s.code, s]),\n);\n\n/**\n * Look up an EAS scheme by its numeric code.\n *\n * @param code - EAS code (e.g. \"0088\", \"0208\")\n * @returns The scheme or `undefined` if not found\n *\n * @example\n * ```ts\n * getEasScheme(\"0208\") // { code: \"0208\", name: \"Belgian Enterprise Number (KBO/BCE)\", country: \"BE\" }\n * getEasScheme(\"9999\") // undefined\n * ```\n */\nexport function getEasScheme(code: string): EasScheme | undefined {\n return EAS_BY_CODE.get(code);\n}\n\n/**\n * Get all known EAS schemes.\n *\n * @returns Array of EAS schemes sorted by code\n */\nexport function getAllEasSchemes(): EasScheme[] {\n return [...EAS_SCHEMES];\n}\n\n// ─── Unit Codes (UN/ECE Recommendation 20) ────────────────────────────────────\n\n/** Human-readable aliases → UN/ECE unit codes */\nconst UNIT_ALIAS_MAP: Record<string, string> = {\n each: \"EA\", piece: \"EA\", pieces: \"EA\",\n hour: \"HUR\", hours: \"HUR\",\n day: \"DAY\", days: \"DAY\",\n week: \"WEE\", weeks: \"WEE\",\n month: \"MON\", months: \"MON\",\n year: \"ANN\", years: \"ANN\",\n kilogram: \"KGM\", kg: \"KGM\",\n meter: \"MTR\", metre: \"MTR\",\n liter: \"LTR\", litre: \"LTR\",\n unit: \"C62\", units: \"C62\",\n set: \"SET\", sets: \"SET\",\n pack: \"PK\", packs: \"PK\",\n minute: \"MIN\", minutes: \"MIN\",\n second: \"SEC\", seconds: \"SEC\",\n tonne: \"TNE\", ton: \"TNE\",\n \"square metre\": \"MTK\", \"square meter\": \"MTK\", sqm: \"MTK\",\n};\n\n/** Canonical unit codes with human-readable names */\nconst UNIT_CODES: ReadonlyMap<string, string> = new Map([\n [\"EA\", \"Each\"],\n [\"HUR\", \"Hour\"],\n [\"DAY\", \"Day\"],\n [\"WEE\", \"Week\"],\n [\"MON\", \"Month\"],\n [\"ANN\", \"Year\"],\n [\"MIN\", \"Minute\"],\n [\"SEC\", \"Second\"],\n [\"KGM\", \"Kilogram\"],\n [\"MTR\", \"Metre\"],\n [\"LTR\", \"Litre\"],\n [\"MTK\", \"Square metre\"],\n [\"TNE\", \"Tonne\"],\n [\"C62\", \"One (unit)\"],\n [\"SET\", \"Set\"],\n [\"PK\", \"Pack\"],\n]);\n\n/**\n * Resolve a human-readable unit name or alias to its UN/ECE Recommendation 20 code.\n *\n * Accepts both aliases (\"hours\", \"kg\") and canonical codes (\"HUR\", \"KGM\").\n * Unknown values pass through unchanged.\n *\n * @param input - Unit name or code\n * @returns Resolved UN/ECE code\n *\n * @example\n * ```ts\n * resolveUnit(\"hours\") // \"HUR\"\n * resolveUnit(\"HUR\") // \"HUR\"\n * resolveUnit(\"kg\") // \"KGM\"\n * resolveUnit(\"XYZ\") // \"XYZ\" (passthrough)\n * ```\n */\nexport function resolveUnit(input: string): string {\n return UNIT_ALIAS_MAP[input.toLowerCase()] ?? input;\n}\n\n/**\n * Get all supported unit codes with human-readable names.\n *\n * @returns Array of `{ code, name }` objects sorted by code\n */\nexport function getAllUnits(): Array<{ code: string; name: string }> {\n return Array.from(UNIT_CODES.entries())\n .map(([code, name]) => ({ code, name }))\n .sort((a, b) => a.code.localeCompare(b.code));\n}\n\n// ─── VAT Categories (UNCL 5305) ──────────────────────────────────────────────\n\n/**\n * A Peppol VAT category entry.\n */\nexport interface VatCategory {\n /** Category code (e.g. \"S\", \"Z\", \"AE\") */\n code: string;\n /** Short name */\n name: string;\n /** Longer description */\n description: string;\n /**\n * Whether getpeppr can actually put this category on the wire (GPR-1012).\n *\n * `false` means the code is valid under EN 16931 but our provider has no\n * vocabulary for it, so a send carrying it is refused with a 422\n * (`unsupported_vat_category`). Listing such a code without saying so is what\n * let `L` and `M` be advertised for months as usable regimes.\n */\n sendable: boolean;\n}\n\n/**\n * The ten codes `BR-CL-17` allows, verbatim: `' AE L M E S Z G O K B '`.\n *\n * ⚠️ This list held NINE until GPR-1012 — `B` (Italian split payment) was\n * missing, so a developer reading it concluded the network refuses a code it\n * accepts. And `L`/`M` were listed with no hint that they cannot be delivered.\n * Both halves of the same defect: a catalogue that describes the network must\n * describe it exactly, and a catalogue that implies capability must be honest\n * about ours.\n */\nconst VAT_CATEGORIES: readonly VatCategory[] = [\n { code: \"S\", name: \"Standard rate\", description: \"Standard VAT rate applies\", sendable: true },\n { code: \"Z\", name: \"Zero rated\", description: \"Zero-rated goods — VAT at 0% but right to deduct input VAT\", sendable: true },\n { code: \"E\", name: \"Exempt\", description: \"Exempt from VAT — no right to deduct input VAT\", sendable: true },\n { code: \"AE\", name: \"Reverse charge\", description: \"VAT reverse charge — customer accounts for VAT\", sendable: true },\n { code: \"K\", name: \"Intra-community supply\", description: \"Intra-community supply of goods — exempt with right to deduct\", sendable: true },\n { code: \"G\", name: \"Export outside the EU\", description: \"Free export item — tax not charged\", sendable: true },\n { code: \"O\", name: \"Outside scope of VAT\", description: \"Services outside scope of VAT\", sendable: true },\n { code: \"B\", name: \"Split payment\", description: \"Italian split payment — NOT sendable via getpeppr (no provider vocabulary)\", sendable: false },\n { code: \"L\", name: \"Canary Islands IGIC\", description: \"Canary Islands general indirect tax (IGIC) — NOT sendable via getpeppr (no provider vocabulary)\", sendable: false },\n { code: \"M\", name: \"Ceuta and Melilla IPSI\", description: \"Tax for production, services and importation in Ceuta and Melilla (IPSI) — NOT sendable via getpeppr (no provider vocabulary)\", sendable: false },\n] as const;\n\n/**\n * Get all Peppol VAT category codes, sendable or not.\n *\n * Filter on `sendable` to get only the ones getpeppr can deliver — the others\n * are listed so the catalogue matches EN 16931, not because they can be used.\n *\n * @returns Array of VAT categories\n */\nexport function getVatCategories(): VatCategory[] {\n return [...VAT_CATEGORIES];\n}\n\n// ─── Payment Means (UNCL 4461) ───────────────────────────────────────────────\n\n/**\n * A payment means code entry.\n */\nexport interface PaymentMeansCode {\n /** Numeric code */\n code: number;\n /** Human-readable description */\n name: string;\n}\n\nconst PAYMENT_MEANS_CODES: readonly PaymentMeansCode[] = [\n { code: 10, name: \"Cash\" },\n { code: 20, name: \"Cheque\" },\n { code: 30, name: \"Credit transfer\" },\n { code: 42, name: \"Payment to bank account\" },\n { code: 48, name: \"Bank card\" },\n { code: 49, name: \"Direct debit\" },\n { code: 57, name: \"Standing agreement\" },\n { code: 58, name: \"SEPA credit transfer\" },\n { code: 59, name: \"SEPA direct debit\" },\n] as const;\n\n/**\n * Get all supported payment means codes.\n *\n * @returns Array of payment means codes sorted by code\n */\nexport function getPaymentMeansCodes(): PaymentMeansCode[] {\n return [...PAYMENT_MEANS_CODES];\n}\n","/**\n * Invoice Validator\n *\n * Validates invoice data BEFORE conversion to XML.\n * Implements key Peppol BIS 3.0 business rules with human-readable error messages.\n *\n * Design principle: Errors tell you WHAT's wrong, WHERE it is, and HOW to fix it.\n * No developer should need to Google a Peppol rule ID.\n */\n\nimport type {\n InvoiceInput,\n InvoiceLine,\n Party,\n ValidationResult,\n ValidationError,\n ValidationWarning,\n} from \"../types/invoice.js\";\nimport { validateCountryRules } from \"./country-rules.js\";\nimport { getCurrency } from \"./code-lists.js\";\n\nfunction error(field: string, message: string, ruleId?: string, suggestion?: string): ValidationError {\n return { field, message, ruleId, suggestion };\n}\n\nfunction warning(field: string, message: string, ruleId?: string): ValidationWarning {\n return { field, message, ruleId };\n}\n\n/**\n * Type-guard that pushes a clean ValidationError when value is not a string.\n * Returns false to signal that downstream string-only checks should be skipped.\n * Prevents raw TypeError bubbling out of the SDK on malformed input (GPR-414 #3).\n */\nfunction assertString(\n value: unknown,\n fieldPath: string,\n errors: ValidationError[],\n): value is string {\n if (typeof value !== \"string\") {\n errors.push(error(\n fieldPath,\n `Expected string, received ${value === null ? \"null\" : typeof value}`,\n undefined,\n \"Check your payload — this field must be a text value\",\n ));\n return false;\n }\n return true;\n}\n\nconst ISO_DATE_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction validateParty(party: Party, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (party.name === undefined || party.name === null || party.name === \"\") {\n errors.push(error(`${path}.name`, \"Business name is required\", \"BR-06\"));\n } else if (!assertString(party.name, `${path}.name`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.name.trim()) {\n errors.push(error(`${path}.name`, \"Business name is required\", \"BR-06\"));\n }\n\n if (party.peppolId === undefined || party.peppolId === null || (party.peppolId as string) === \"\") {\n errors.push(\n error(\n `${path}.peppolId`,\n \"Peppol participant ID is required\",\n undefined,\n 'Format: \"scheme:id\", e.g. \"0208:0685660237\" for Belgian companies'\n )\n );\n } else if (!assertString(party.peppolId, `${path}.peppolId`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.peppolId.includes(\":\")) {\n errors.push(\n error(\n `${path}.peppolId`,\n `Invalid Peppol ID format: \"${party.peppolId}\"`,\n undefined,\n 'Must be \"scheme:id\" format. Common schemes: 0208 (Belgium), 0009 (France SIRET), 0204 (Germany Leitweg)'\n )\n );\n }\n\n if (party.country === undefined || party.country === null || party.country === \"\") {\n errors.push(error(`${path}.country`, \"Country code is required\", \"BR-11\"));\n } else if (!assertString(party.country, `${path}.country`, errors)) {\n // skip — assertString already pushed the type error\n } else if (party.country.length !== 2) {\n errors.push(\n error(\n `${path}.country`,\n `Invalid country code: \"${party.country}\"`,\n undefined,\n \"Must be ISO 3166-1 alpha-2 (e.g., BE, FR, DE, NL)\"\n )\n );\n }\n\n return errors;\n}\n\n/** Validate buyer postal address — required by Peppol BIS 3.0 (BG-8) and Storecove */\nfunction validateBuyerAddress(party: Party, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (party.street === undefined || party.street === null || party.street === \"\") {\n errors.push(error(`${path}.street`, \"Street address is required for the buyer\", \"BR-50\",\n 'e.g. \"123 Business Street\"'));\n } else if (!assertString(party.street, `${path}.street`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.street.trim()) {\n errors.push(error(`${path}.street`, \"Street address is required for the buyer\", \"BR-50\",\n 'e.g. \"123 Business Street\"'));\n }\n\n if (party.city === undefined || party.city === null || party.city === \"\") {\n errors.push(error(`${path}.city`, \"City is required for the buyer\", \"BR-51\",\n 'e.g. \"Brussels\"'));\n } else if (!assertString(party.city, `${path}.city`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.city.trim()) {\n errors.push(error(`${path}.city`, \"City is required for the buyer\", \"BR-51\",\n 'e.g. \"Brussels\"'));\n }\n\n if (party.postalCode === undefined || party.postalCode === null || party.postalCode === \"\") {\n errors.push(error(`${path}.postalCode`, \"Postal code is required for the buyer\", \"BR-53\",\n 'e.g. \"1000\"'));\n } else if (!assertString(party.postalCode, `${path}.postalCode`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.postalCode.trim()) {\n errors.push(error(`${path}.postalCode`, \"Postal code is required for the buyer\", \"BR-53\",\n 'e.g. \"1000\"'));\n }\n\n return errors;\n}\n\nfunction validateLine(line: InvoiceLine, index: number, isCreditNote = false): ValidationError[] {\n const errors: ValidationError[] = [];\n const path = `lines[${index}]`;\n\n if (line.description === undefined || line.description === null || line.description === \"\") {\n errors.push(error(`${path}.description`, \"Line item description is required\", \"BR-25\"));\n } else if (!assertString(line.description, `${path}.description`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!line.description.trim()) {\n errors.push(error(`${path}.description`, \"Line item description is required\", \"BR-25\"));\n }\n\n if (line.quantity === undefined || line.quantity === null) {\n errors.push(error(`${path}.quantity`, \"Quantity is required\", \"BR-22\"));\n } else if (line.quantity <= 0 && !isCreditNote) {\n errors.push(\n error(\n `${path}.quantity`,\n `Quantity must be positive, got ${line.quantity}`,\n undefined,\n \"For returns/credits, use a credit note instead\"\n )\n );\n }\n\n if (line.unitPrice === undefined || line.unitPrice === null) {\n errors.push(error(`${path}.unitPrice`, \"Unit price is required\", \"BR-26\"));\n } else if (line.unitPrice < 0) {\n errors.push(\n error(\n `${path}.unitPrice`,\n `Unit price cannot be negative, got ${line.unitPrice}`,\n undefined,\n \"For discounts, use a negative quantity or a separate discount line\"\n )\n );\n }\n\n if (line.vatRate === undefined || line.vatRate === null) {\n errors.push(error(`${path}.vatRate`, \"VAT rate is required\", \"BR-CO-17\"));\n } else if (line.vatRate < 0 || line.vatRate > 100) {\n errors.push(\n error(\n `${path}.vatRate`,\n `VAT rate must be between 0 and 100, got ${line.vatRate}`,\n undefined,\n \"Use 0 for zero-rated, 21 for standard Belgian VAT, etc.\"\n )\n );\n }\n\n return errors;\n}\n\n/**\n * Validate an invoice input before sending.\n * Returns human-readable errors with suggestions for fixes.\n */\nexport function validateInvoice(input: InvoiceInput): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n // ── Invoice-level validation ──\n\n if (input.number === undefined || input.number === null || input.number === \"\") {\n errors.push(\n error(\"number\", \"Invoice number is required\", \"BR-02\", \"Must be unique per supplier\")\n );\n } else if (!assertString(input.number, \"number\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!input.number.trim()) {\n errors.push(\n error(\"number\", \"Invoice number is required\", \"BR-02\", \"Must be unique per supplier\")\n );\n }\n\n // ── Invoice type code validation ──\n\n const VALID_TYPE_CODES = [380, 381, 383, 384, 386, 389, 751];\n if (input.invoiceTypeCode != null && !VALID_TYPE_CODES.includes(input.invoiceTypeCode)) {\n errors.push(\n error(\n \"invoiceTypeCode\",\n `Invalid invoice type code: ${input.invoiceTypeCode}`,\n undefined,\n \"Valid codes: 380, 381, 383, 384, 386, 389, 751\"\n )\n );\n }\n\n // ── Credit note validation ──\n\n if (input.isCreditNote) {\n const ref = input.invoiceReference;\n if (ref === undefined || ref === null || ref === \"\") {\n errors.push(error(\n \"invoiceReference\",\n \"Reference to the original invoice is required for credit notes\",\n undefined,\n 'Set invoiceReference to the original invoice number (e.g., \"INV-001\")'\n ));\n } else if (!assertString(ref, \"invoiceReference\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!ref.trim()) {\n errors.push(error(\n \"invoiceReference\",\n \"Reference to the original invoice is required for credit notes\",\n undefined,\n 'Set invoiceReference to the original invoice number (e.g., \"INV-001\")'\n ));\n }\n }\n\n if (input.from) {\n warnings.push(\n warning(\n \"from\",\n \"Seller info is determined by your API key. The 'from' field is deprecated and ignored.\",\n )\n );\n }\n\n if (!input.to) {\n errors.push(error(\"to\", \"Buyer (to) is required\", \"BR-07\"));\n } else {\n errors.push(...validateParty(input.to, \"to\"));\n errors.push(...validateBuyerAddress(input.to, \"to\"));\n }\n\n if (input.payeeParty) {\n const ppName = input.payeeParty.name;\n if (ppName === undefined || ppName === null || ppName === \"\") {\n errors.push(error(\"payeeParty.name\", \"Payee party name is required\", \"BR-17\"));\n } else if (!assertString(ppName, \"payeeParty.name\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!ppName.trim()) {\n errors.push(error(\"payeeParty.name\", \"Payee party name is required\", \"BR-17\"));\n }\n\n const ppId = input.payeeParty.peppolId;\n if (ppId === undefined || ppId === null || (ppId as string) === \"\") {\n errors.push(\n error(\n \"payeeParty.peppolId\",\n \"Payee party Peppol ID is required\",\n undefined,\n 'Format: \"scheme:id\", e.g. \"0208:0685660237\"'\n )\n );\n } else if (!assertString(ppId, \"payeeParty.peppolId\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!ppId.includes(\":\")) {\n errors.push(\n error(\n \"payeeParty.peppolId\",\n `Invalid Peppol ID format: \"${ppId}\"`,\n undefined,\n 'Must be \"scheme:id\" format'\n )\n );\n }\n }\n\n if (!input.lines || input.lines.length === 0) {\n errors.push(\n error(\"lines\", \"At least one line item is required\", \"BR-16\", \"Add items to the lines array\")\n );\n } else {\n for (let i = 0; i < input.lines.length; i++) {\n errors.push(...validateLine(input.lines[i]!, i, input.isCreditNote));\n }\n }\n\n // ── Date validation ──\n\n if (input.date) {\n if (!ISO_DATE_RE.test(input.date)) {\n errors.push(\n error(\"date\", `Invalid date format: \"${input.date}\"`, undefined, \"Use ISO 8601: YYYY-MM-DD\")\n );\n }\n }\n\n if (input.dueDate) {\n if (!ISO_DATE_RE.test(input.dueDate)) {\n errors.push(\n error(\n \"dueDate\",\n `Invalid due date format: \"${input.dueDate}\"`,\n undefined,\n \"Use ISO 8601: YYYY-MM-DD\"\n )\n );\n }\n }\n\n // ── TaxPointDate validation (BT-7) ──\n\n if (input.taxPointDate) {\n if (!ISO_DATE_RE.test(input.taxPointDate)) {\n errors.push(\n error(\n \"taxPointDate\",\n `Invalid tax point date format: \"${input.taxPointDate}\"`,\n undefined,\n \"Use ISO 8601: YYYY-MM-DD\"\n )\n );\n }\n }\n\n // ── RoundingAmount validation (BT-114) ──\n\n if (input.roundingAmount !== undefined && input.roundingAmount !== null) {\n if (input.roundingAmount < -0.99 || input.roundingAmount > 0.99) {\n errors.push(\n error(\n \"roundingAmount\",\n `Rounding amount must be between -0.99 and 0.99, got ${input.roundingAmount}`,\n undefined,\n \"Rounding is stored as integer cents (±99). Use values like 0.50 or -0.25.\"\n )\n );\n }\n }\n\n // ── BuyerReference / OrderReference (BT-10) ──\n\n if (!input.buyerReference && !input.orderReference) {\n warnings.push(\n warning(\n \"buyerReference\",\n \"Either buyerReference or orderReference is required by Peppol BIS 3.0 (BT-10).\",\n \"BR-10\"\n )\n );\n }\n\n // ── TaxCurrencyCode validation ──\n\n if (input.taxCurrency && input.taxCurrency !== (input.currency ?? \"EUR\") && !input.taxCurrencyRate) {\n errors.push(\n error(\n \"taxCurrencyRate\",\n \"Tax currency rate is required when taxCurrency differs from document currency\",\n \"BR-53\",\n \"Set taxCurrencyRate to the exchange rate from document currency to tax currency\"\n )\n );\n }\n\n if (input.taxCurrency && input.taxCurrency === (input.currency ?? \"EUR\")) {\n warnings.push(\n warning(\"taxCurrency\", \"Tax currency is the same as document currency — TaxCurrencyCode will be omitted\")\n );\n }\n\n if (input.taxCurrencyRate !== undefined && input.taxCurrencyRate <= 0) {\n errors.push(\n error(\n \"taxCurrencyRate\",\n `Tax currency rate must be positive, got ${input.taxCurrencyRate}`,\n undefined,\n \"Set to the exchange rate from document currency to tax currency\"\n )\n );\n }\n\n // ── Currency code validation (ISO 4217) ──\n\n if (input.currency && !getCurrency(input.currency)) {\n errors.push(\n error(\n \"currency\",\n `Invalid currency code: \"${input.currency}\"`,\n undefined,\n 'Use ISO 4217 (e.g., \"EUR\", \"USD\", \"GBP\", \"JPY\"). See https://getpeppr.dev/docs/types/#currency'\n )\n );\n }\n\n if (input.taxCurrency && !getCurrency(input.taxCurrency)) {\n errors.push(\n error(\n \"taxCurrency\",\n `Invalid tax currency code: \"${input.taxCurrency}\"`,\n undefined,\n 'Use ISO 4217 (e.g., \"EUR\", \"USD\")'\n )\n );\n }\n\n // ── Warnings (non-blocking) ──\n\n if (!input.dueDate) {\n warnings.push(warning(\"dueDate\", \"No due date specified. Recommended for payment terms.\", \"BR-09\"));\n }\n\n if (!input.to?.vatNumber) {\n warnings.push(warning(\"to.vatNumber\", \"Buyer VAT number not provided. May be required for B2B.\"));\n }\n\n if (input.paymentMeans === 30 && !input.paymentIban) {\n warnings.push(\n warning(\n \"paymentIban\",\n \"Payment means is credit transfer but no IBAN provided. Buyer won't know where to pay.\"\n )\n );\n }\n\n // ── Cross-field validation ──\n\n if (input.from?.peppolId && input.to?.peppolId && input.from.peppolId === input.to.peppolId) {\n errors.push(\n error(\n \"to.peppolId\",\n \"Buyer and seller cannot have the same Peppol ID\",\n undefined,\n \"Check that 'from' and 'to' are different parties\"\n )\n );\n }\n\n // ── Country-specific rules (advisory warnings) ──\n\n const countryResult = validateCountryRules(input);\n warnings.push(...countryResult.warnings);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","import type { DocumentStatus } from \"../types/invoice\";\n\n/** Wait-semantics family of a status (spec parente §3.12 — orthogonal to its §8.1 position). */\nexport type StatusFamily = \"progress\" | \"terminal-success\" | \"terminal-failure\" | \"fallback\";\n\nexport interface StatusPrecedenceEntry {\n status: DocumentStatus;\n family: StatusFamily;\n}\n\n/**\n * The §8.1 synthesis precedence as DATA — index 0 = most final. `waitFor()`\n * derives its terminal sets from the `family` column instead of a hard-coded\n * list (§8.7). The console locks this table against its own `synthesize()`\n * branch order, so a drift between packages fails CI, not production.\n */\nexport const STATUS_PRECEDENCE: readonly StatusPrecedenceEntry[] = [\n { status: \"failed\", family: \"terminal-failure\" },\n { status: \"rejected\", family: \"terminal-failure\" },\n { status: \"paid\", family: \"terminal-success\" },\n { status: \"partially_paid\", family: \"progress\" },\n { status: \"accepted\", family: \"progress\" },\n { status: \"conditionally_accepted\", family: \"progress\" },\n { status: \"under_query\", family: \"progress\" },\n { status: \"in_process\", family: \"progress\" },\n { status: \"cleared\", family: \"progress\" },\n { status: \"delivered\", family: \"progress\" },\n { status: \"acknowledged\", family: \"progress\" },\n // Terminal for developer wait semantics only — stays rank 40 (non-terminal)\n // in the projection guard (§3.12 two-level terminality).\n { status: \"no_action\", family: \"terminal-failure\" },\n { status: \"submitted\", family: \"progress\" },\n { status: \"unknown\", family: \"fallback\" },\n];\n\nexport function statusFamily(status: DocumentStatus): StatusFamily {\n return STATUS_PRECEDENCE.find((e) => e.status === status)?.family ?? \"fallback\";\n}\n\n/** Derived — never hard-code this list again (§8.7). */\nexport const TERMINAL_FAILURE_STATUSES: readonly DocumentStatus[] = STATUS_PRECEDENCE\n .filter((e) => e.family === \"terminal-failure\")\n .map((e) => e.status);\n","/** SDK version — keep in sync with package.json on each release. */\nexport const SDK_VERSION = \"4.1.1\";\n","/**\n * getpeppr SDK Client\n *\n * The main entry point. Designed to feel like Stripe's SDK:\n *\n * const peppol = new Peppol({ apiKey: \"sk_live_...\" });\n * const result = await peppol.invoices.send({ from, to, lines });\n *\n * All requests go through the getpeppr API gateway (api.getpeppr.dev),\n * which handles Peppol delivery, billing, and usage tracking.\n * Use `baseUrl` to point to a custom instance or localhost.\n */\n\nimport type {\n PeppolConfig,\n InvoiceInput,\n CreditNoteInput,\n SendResult,\n StatusDetail,\n StatusDetailEntry,\n ValidationResult,\n WebhookEvent,\n RetryConfig,\n DocumentStatus,\n WaitForOptions,\n PaginatedResult,\n InvoiceSummary,\n GetStatusOptions,\n ListInvoicesOptions,\n DirectoryEntry,\n DirectorySearchOptions,\n DirectorySearchResult,\n PeppolId,\n DocumentFormat,\n ServerValidationResult,\n EventEntry,\n ListEventsOptions,\n BatchSendOptions,\n BatchSendResult,\n InvoiceOperationOptions,\n RequestLogEntry,\n ResponseLogEntry,\n Contact,\n ContactInput,\n ListContactsOptions,\n BankAccount,\n BankAccountInput,\n ListBankAccountsOptions,\n ImportInvoiceOptions,\n TransportType,\n Transport,\n TransportInput,\n TransportUpdateInput,\n MarkAsState,\n MarkAsOptions,\n InvoiceUpdateInput,\n LegalEntityInput,\n LegalEntity,\n LegalEntityStatus,\n ListLegalEntitiesOptions,\n ArchiveLegalEntityResult,\n AttestationInput,\n AttestationResult,\n LegalEntityRequestOptions,\n} from \"../types/invoice.js\";\nimport { buildInvoiceXml, buildCreditNoteXml } from \"./ubl-builder.js\";\nimport { validateInvoice } from \"./validator.js\";\nimport { statusFamily, TERMINAL_FAILURE_STATUSES } from \"./status-precedence.js\";\nimport { SDK_VERSION } from \"../version.js\";\n\n// ─── Backend Adapter Interface ──────────────────────────────\n\n/**\n * Backend adapter interface for the SDK's transport layer.\n * The default implementation hits the getpeppr API gateway.\n *\n * @internal transport contract. This interface is NOT meant to be implemented by\n * consumers — `PeppolConfig` exposes no adapter injection point, so the only\n * implementer is the built-in `GetpepprAdapter`. New gateway features add methods\n * here as minor releases (as contacts/bank-accounts/transports did); external\n * `implements BackendAdapter` is unsupported and may break across minor versions.\n */\nexport interface BackendAdapter {\n /** Provider name (for logging) */\n readonly name: string;\n /** Send an invoice as structured JSON (gateway handles UBL generation) */\n sendInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult>;\n /** Create a draft invoice without sending (POST /invoices, no send_after_import) */\n createInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult>;\n /** Send an existing draft invoice by ID (POST /invoices/send/{id}, returns 204) */\n sendInvoiceById(id: string): Promise<void>;\n /** @deprecated Credit notes now route through sendInvoice with isCreditNote: true */\n sendCreditNote(input: CreditNoteInput): Promise<SendResult>;\n /** Validate an invoice server-side (free, no metering) */\n validateDocument(input: InvoiceInput): Promise<{ valid: boolean; errors: string[] }>;\n /** List invoices with pagination and filtering */\n listInvoices(options?: ListInvoicesOptions): Promise<PaginatedResult<InvoiceSummary>>;\n /** Get document status by ID */\n getStatus(documentId: string, options?: GetStatusOptions): Promise<SendResult>;\n /** Look up a Peppol participant in the directory */\n lookupDirectory(scheme: string, id: string): Promise<DirectoryEntry>;\n /** Search the Peppol Directory for participants */\n searchDirectory?(params: Record<string, string>): Promise<DirectorySearchResult>;\n /** Export an invoice in a specific format (e.g., PDF) — returns raw binary */\n getInvoiceAs(id: string, format: DocumentFormat): Promise<ArrayBuffer>;\n /** Validate an invoice server-side through the getpeppr gateway's offline SDK-backed checks. */\n validateDocumentServer(input: InvoiceInput): Promise<ServerValidationResult>;\n /** List events with optional filtering and pagination */\n listEvents(options?: ListEventsOptions): Promise<PaginatedResult<EventEntry>>;\n /** Acknowledge a received invoice (POST /invoices/{id}/ack) */\n acknowledgeInvoice(id: string): Promise<SendResult>;\n /** List contacts with optional filtering and pagination */\n listContacts(options?: ListContactsOptions): Promise<PaginatedResult<Contact>>;\n /** Get a single contact by ID */\n getContact(id: string): Promise<Contact>;\n /** Create a new contact */\n createContact(input: ContactInput): Promise<Contact>;\n /** Update an existing contact */\n updateContact(id: string, input: Partial<ContactInput>): Promise<Contact>;\n /** Delete a contact */\n deleteContact(id: string): Promise<void>;\n /** List bank accounts with optional pagination */\n listBankAccounts(options?: ListBankAccountsOptions): Promise<PaginatedResult<BankAccount>>;\n /** Get a single bank account by ID */\n getBankAccount(id: string): Promise<BankAccount>;\n /** Create a new bank account */\n createBankAccount(input: BankAccountInput): Promise<BankAccount>;\n /** Update an existing bank account */\n updateBankAccount(id: string, input: Partial<BankAccountInput>): Promise<BankAccount>;\n /** Delete a bank account */\n deleteBankAccount(id: string): Promise<void>;\n /** Import an invoice from a file (XML, PDF, etc.) */\n importInvoice(options: ImportInvoiceOptions): Promise<SendResult>;\n /** List all available transport types (global, not account-scoped) */\n listTransportTypes(): Promise<TransportType[]>;\n /** List configured transports for this account */\n listTransports(): Promise<Transport[]>;\n /** Get a single transport by code */\n getTransport(code: string): Promise<Transport>;\n /** Create a new transport */\n createTransport(input: TransportInput): Promise<Transport>;\n /** Update an existing transport */\n updateTransport(code: string, input: TransportUpdateInput): Promise<Transport>;\n /** Delete a transport */\n deleteTransport(code: string): Promise<void>;\n /** Update an existing invoice */\n updateInvoice(id: string, input: InvoiceUpdateInput): Promise<SendResult>;\n /** Delete an invoice */\n deleteInvoice(id: string): Promise<SendResult>;\n /** Transition an invoice to a new state */\n markInvoiceAs(id: string, state: MarkAsState, options?: MarkAsOptions): Promise<SendResult>;\n /** Create a sub-tenant Legal Entity (master key). */\n createLegalEntity(input: LegalEntityInput, options?: LegalEntityRequestOptions): Promise<LegalEntity>;\n /** Fetch a single sub-tenant Legal Entity by id (master key). */\n getLegalEntity(id: string): Promise<LegalEntity>;\n /** List sub-tenant Legal Entities (master key), paginated. */\n listLegalEntities(options?: ListLegalEntitiesOptions): Promise<PaginatedResult<LegalEntity>>;\n /** Archive (soft-delete) a sub-tenant Legal Entity (master key). */\n archiveLegalEntity(id: string): Promise<ArchiveLegalEntityResult>;\n /** Request (or resend) a sub-tenant attestation — production only (master key). */\n requestLegalEntityAttestation(id: string, input: AttestationInput, options?: LegalEntityRequestOptions): Promise<AttestationResult>;\n}\n\n// ─── Retry & Header Utilities ────────────────────────────────────────\n\n/**\n * Case-insensitive header lookup. Per RFC 7230 §3.2, HTTP header names are\n * case-insensitive. Some adapters (axios default, Cloudflare Workers, proxies) lowercase\n * header keys, which made the strict bracket lookup miss user-supplied lowercase\n * keys and silently disabled retry safety on POST requests with idempotency keys.\n *\n * When multiple headers match (e.g. \"Idempotency-Key\" and \"idempotency-key\" both present),\n * returns the value of the first matching key in insertion order.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function findHeaderCaseInsensitive(\n headers: Record<string, string> | undefined,\n name: string,\n): string | undefined {\n if (!headers) return undefined;\n const target = name.toLowerCase();\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === target) return value;\n }\n return undefined;\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction calculateRetryDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n retryAfterMs?: number,\n): number {\n if (retryAfterMs !== undefined) return Math.min(retryAfterMs, maxDelayMs);\n const exponentialDelay = initialDelayMs * Math.pow(2, attempt);\n const jitter = Math.random() * initialDelayMs;\n return Math.min(exponentialDelay + jitter, maxDelayMs);\n}\n\n/**\n * Parse the Retry-After header value into milliseconds.\n * Supports integer seconds (e.g., \"1\", \"60\") and HTTP-date format.\n * Returns undefined if the header is missing or unparseable.\n */\nfunction parseRetryAfter(headerValue: string | null): number | undefined {\n if (!headerValue) return undefined;\n\n // Try integer seconds first (most common for rate limiters)\n const seconds = Number(headerValue);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n // Try HTTP-date format (e.g., \"Wed, 21 Oct 2025 07:28:00 GMT\")\n const dateMs = Date.parse(headerValue);\n if (!Number.isNaN(dateMs)) {\n const delayMs = dateMs - Date.now();\n return delayMs > 0 ? delayMs : 0;\n }\n\n return undefined;\n}\n\n/**\n * C0 controls, DEL, and C1 (U+0080–U+009F).\n *\n * ⛔ These matter ONLY on the parsed path, and that is the whole point. JSON\n * forbids raw C0 inside a string, so they always travel the wire escaped and\n * the old verbatim format kept them inert. `JSON.parse` decodes them into real\n * bytes, and a terminal ACTS on them: `ESC [ 2K` clears the line, so a third\n * party's text overwrites what was just printed, and a newline forges a log\n * line (CWE-117/150). The CLI writes `e.message` straight to stderr.\n *\n * C1 is included because U+009B is a single-character CSI — some terminals\n * treat it exactly like `ESC [`.\n */\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001F\\u007F-\\u009F]/g;\n\n/**\n * Accept a `docs` value only if it is an absolute http(s) URL, and return the\n * PARSED form.\n *\n * Two distinct reasons, both measured. `new URL` normalises control characters\n * out of the href — most are percent-encoded (`ESC` becomes `%1B`) while TAB,\n * LF and CR are STRIPPED outright per the WHATWG parser — so the link cannot\n * smuggle an escape sequence either way. And it happily accepts\n * `javascript:`: parsing alone is not validation, the protocol has to be\n * checked.\n */\n/** Replace every control character with a space. */\nfunction stripControls(value: string): string {\n return value.replace(CONTROL_CHARACTERS, \" \");\n}\n\n/**\n * Own-property read. `Object.hasOwn`, never a bare index: this object comes off\n * the wire, so an inherited value from a host that polluted `Object.prototype`\n * would otherwise be preferred over the fallback.\n */\nfunction readOwn(source: object, key: string): unknown {\n return Object.hasOwn(source, key) ? (source as Record<string, unknown>)[key] : undefined;\n}\n\n/**\n * Read a field as a displayable sentence, or `null` if it cannot be one.\n *\n * ⛔ Sanitises BEFORE the emptiness check, never after: control characters are\n * not whitespace, so trimming first would accept a value that is technically\n * non-empty and says nothing.\n */\nfunction readSentence(source: object, key: string): string | null {\n const value = readOwn(source, key);\n if (typeof value !== \"string\") return null;\n const cleaned = stripControls(value).trim();\n return cleaned === \"\" ? null : cleaned;\n}\n\nfunction safeDocsUrl(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n let parsed: URL;\n try {\n parsed = new URL(value);\n } catch {\n return null;\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") return null;\n return parsed.href;\n}\n\n/**\n * Build the human-readable message for a failed response.\n *\n * The gateway answers 4xx with `{ error, code, docs }`. Pasting that JSON into\n * `Error.message` leaks braces to humans — the CLI prints `e.message` straight\n * to the terminal — so when the envelope is recognisable we show the sentence\n * and, when present, the docs link.\n *\n * Deliberately general rather than keyed on any one `code`: every gateway 4xx\n * shares this envelope, and a special case would leave the rest printing JSON.\n *\n * Falls back to the verbatim body for anything unrecognised — a proxy's HTML, a\n * bare JSON scalar, an envelope with no usable sentence. The fallback must stay\n * byte-identical to the old format: it is what non-gateway failures still show.\n *\n * ⚠️ This shapes the MESSAGE only. `PeppolApiError.responseBody` keeps the raw\n * body because `.code` reparses it.\n */\nfunction formatApiErrorMessage(status: number, rawBody: string): string {\n // ⛔ The fallback is sanitised TOO, and that is not belt-and-braces.\n //\n // JSON forbids only C0 (U+0000–U+001F); DEL and C1 travel the wire RAW. So a\n // body whose sentence is nothing but those characters cleans to empty, falls\n // through to here, and the raw body carries them straight into the message —\n // the exact injection the sanitiser exists to stop, through its own back door\n // (found by gate, second pass).\n //\n // This gives up \"the fallback is byte-identical to the old format\". That\n // promise was never worth a live injection path: an unrecognised body is\n // still shown verbatim, minus characters a terminal would ACT on.\n const verbatim = `getpeppr API error (${status}): ${stripControls(rawBody)}`;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawBody);\n } catch {\n return verbatim;\n }\n\n // A bare string, array or null parses fine but is not an envelope.\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return verbatim;\n }\n\n // ⛔ `message` FIRST, then `error`. Several routes under `app/api/v1/` —\n // `invoices/route.ts`, `invoices/send/[id]`, `onboarding/legal-entity` —\n // emit `{ error: <machine code>, message: <human sentence> }`. Reading\n // `error` there prints \"unsupported_vat_category\" and drops the sentence\n // explaining what to do, which is strictly worse than the raw JSON this\n // replaced. Most other routes put the sentence in `error`, so both shapes\n // have to work.\n //\n // ⚠️ No count here on purpose: this comment first said \"nine sites\", the real\n // figure was eleven, and it moves whenever a route is added. Name the files,\n // not the tally (the GPR-1019 lesson).\n const sentence = readSentence(parsed, \"message\") ?? readSentence(parsed, \"error\");\n if (sentence === null) return verbatim;\n\n const link = safeDocsUrl(readOwn(parsed, \"docs\"));\n return `getpeppr API error (${status}): ${sentence}${link ? ` See ${link}` : \"\"}`;\n}\n\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof PeppolApiError) {\n return RETRYABLE_STATUS_CODES.has(error.statusCode);\n }\n // Retry on timeout/abort errors\n if (error instanceof Error && error.name === \"AbortError\") {\n return true;\n }\n // Retry on transient network errors (DNS failure, connection refused, reset, timeout, etc.)\n if (error instanceof TypeError && /fetch failed|network|ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT/i.test(error.message)) {\n return true;\n }\n return false;\n}\n\n// ─── getpeppr API Adapter ───────────────────────────────────\n\nconst DEFAULT_BASE_URL = \"https://api.getpeppr.dev/v1\";\n\nclass GetpepprAdapter implements BackendAdapter {\n readonly name = \"getpeppr\";\n private baseUrl: string;\n private apiKey: string;\n private timeout: number;\n private retryConfig: Required<RetryConfig>;\n private onRequest?: (entry: RequestLogEntry) => void;\n private onResponse?: (entry: ResponseLogEntry) => void;\n\n constructor(config: PeppolConfig) {\n this.apiKey = config.apiKey;\n this.timeout = config.timeout ?? 30_000;\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.retryConfig = {\n maxRetries: config.retry?.maxRetries ?? 3,\n initialDelayMs: config.retry?.initialDelayMs ?? 500,\n maxDelayMs: config.retry?.maxDelayMs ?? 30_000,\n };\n this.onRequest = config.onRequest;\n this.onResponse = config.onResponse;\n }\n\n private async request<T>(method: string, path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<T> {\n const { maxRetries, initialDelayMs, maxDelayMs } = this.retryConfig;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await this.doRequest<T>(method, path, body, extraHeaders);\n } catch (err) {\n lastError = err;\n // 429 (rate limit) is always safe to retry — the request was never processed.\n // For other retryable errors (500, 502, 503, 504, network failures),\n // only retry non-idempotent methods (POST, PUT, PATCH) if an Idempotency-Key was\n // provided, to prevent duplicate side effects (e.g., sending the same invoice twice).\n const is429 = err instanceof PeppolApiError && err.statusCode === 429;\n const isSafeMethod = /^(GET|DELETE|HEAD)$/i.test(method);\n const hasIdempotencyKey = !!findHeaderCaseInsensitive(extraHeaders, \"Idempotency-Key\");\n const canRetry = is429 || isSafeMethod || hasIdempotencyKey;\n if (attempt < maxRetries && canRetry && isRetryableError(err)) {\n const retryAfterMs = err instanceof PeppolApiError ? err.retryAfterMs : undefined;\n await sleep(calculateRetryDelay(attempt, initialDelayMs, maxDelayMs, retryAfterMs));\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private async doRequest<T>(method: string, path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const requestHeaders: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"User-Agent\": `getpeppr-sdk/${SDK_VERSION}`,\n ...extraHeaders,\n };\n\n const startTime = Date.now();\n if (this.onRequest) {\n try {\n this.onRequest({\n method,\n url,\n headers: { ...requestHeaders },\n body,\n timestamp: startTime,\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers: requestHeaders,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => \"Unknown error\");\n const retryAfterMs = response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined;\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: errorBody,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n throw new PeppolApiError(\n formatApiErrorMessage(response.status, errorBody),\n response.status,\n errorBody,\n retryAfterMs,\n );\n }\n\n // 204 No Content — no body to parse (e.g., sendInvoiceById)\n if (response.status === 204) {\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: undefined,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n return undefined as T;\n }\n\n let responseBody: T;\n try {\n responseBody = (await response.json()) as T;\n } catch {\n throw new PeppolApiError(\n `getpeppr API error: unexpected response format (status ${response.status})`,\n response.status,\n \"Response body is not valid JSON\",\n );\n }\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n // GPR-1061 — a COPY, not the live object. The hook used to receive\n // the very body the parsers then read: a hook that redacts fields\n // before logging them (an entirely reasonable hook) could delete\n // `status` and make the SDK blame the gateway for the omission.\n //\n // The clone is not guaranteed: structuredClone throws RangeError\n // past roughly 3000 levels of nesting. Falling back to the live\n // object would reopen the mutation above, and letting the throw\n // escape would silently drop the log — the surrounding catch\n // swallows everything — so the hook fires with a marker instead.\n body: cloneForHook(responseBody),\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n return responseBody;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // NOTE: sendInvoice and createInvoice hit the same SDK endpoint (POST /invoices).\n // The gateway (Tasks 9-10) differentiates them: sendInvoice wraps with\n // { invoice: {...}, send_after_import: true }, createInvoice omits the flag.\n async sendInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) {\n headers[\"Idempotency-Key\"] = options.idempotencyKey;\n }\n if (options?.validateRecipient) {\n headers[\"X-Validate-Recipient\"] = options.validateRecipient === true ? \"warn\" : String(options.validateRecipient);\n }\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices\", input, headers);\n return parseSendResult(result);\n }\n\n async createInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) {\n headers[\"Idempotency-Key\"] = options.idempotencyKey;\n }\n if (options?.validateRecipient) {\n headers[\"X-Validate-Recipient\"] = options.validateRecipient === true ? \"warn\" : String(options.validateRecipient);\n }\n // Signal to the gateway that this is a draft (no auto-send).\n // The gateway reads `_draft` and strips it before forwarding to the provider.\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices\", { ...input, _draft: true }, headers);\n return parseSendResult(result);\n }\n\n async sendInvoiceById(id: string): Promise<void> {\n await this.request<void>(\"POST\", `/invoices/send/${id}`);\n }\n\n async sendCreditNote(input: CreditNoteInput): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/credit-notes\", input);\n return parseSendResult(result);\n }\n\n async validateDocument(input: InvoiceInput): Promise<{ valid: boolean; errors: string[] }> {\n return this.request<{ valid: boolean; errors: string[] }>(\"POST\", \"/validate\", input);\n }\n\n async listInvoices(options?: ListInvoicesOptions): Promise<PaginatedResult<InvoiceSummary>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n if (options?.includeLines) params.set(\"include\", \"lines\");\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/invoices${query}`);\n\n // Gateway returns { invoices: [...], meta: {...} }\n //\n // GPR-1061 — guarded, because `body.invoices ?? body.data ?? []` reads an\n // empty page out of anything that is not an object: `200 \"ok\"` or `200 42`\n // returned a successful, empty, fabricated result, and `200 null` threw a\n // TypeError. An empty page a caller believes is real is the same class of\n // defect as an invented status.\n const envelope = requireRecordBody(result, \"the invoice list\");\n const rows = envelope.invoices ?? envelope.data ?? [];\n if (!Array.isArray(rows)) {\n throw new PeppolProtocolError(\n \"The getpeppr API answered the invoice list without an array of invoices. \" +\n \"Please report this response to support@getpeppr.dev.\",\n \"invoices\",\n boundedBody(envelope),\n );\n }\n const invoices = rows as Record<string, unknown>[];\n const meta = envelope.meta as Record<string, unknown> | undefined;\n\n return {\n data: invoices.map(parseInvoiceSummary),\n meta: {\n totalCount: Number(meta?.total_count ?? invoices.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n hasMore: meta ? Number(meta.total_count) > Number(meta.offset) + Number(meta.limit) : false,\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async getStatus(documentId: string, options?: GetStatusOptions): Promise<SendResult> {\n // GPR-1061 — `?include=evidence` makes the gateway read the sending evidence\n // from the network so it can return `peppolMessageId`. It is opt-in because\n // it costs a provider round trip, and it degrades silently: an in-flight\n // document simply comes back without the field.\n const query = options?.includeEvidence ? \"?include=evidence\" : \"\";\n const result = await this.request<Record<string, unknown>>(\n \"GET\",\n `/invoices/${documentId}${query}`,\n );\n return parseSendResult(result);\n }\n\n async lookupDirectory(scheme: string, id: string): Promise<DirectoryEntry> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/directory/${scheme}/${id}`);\n return parseDirectoryEntry(result);\n }\n\n async searchDirectory(params: Record<string, string>): Promise<DirectorySearchResult> {\n const query = new URLSearchParams(params).toString();\n const result = await this.request<Record<string, unknown>>(\"GET\", `/directory/search?${query}`);\n\n // Gateway returns { data: [...], meta: {...} } — entries are already in SDK\n // shape, but the pagination meta is snake_case (total_count, has_more) —\n // same split as listEvents (GPR-868).\n const data = (result.data ?? []) as DirectoryEntry[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data,\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? data.length),\n offset: Number(meta?.offset ?? params.offset ?? 0),\n limit: Number(meta?.limit ?? params.limit ?? 20),\n hasMore:\n meta?.has_more != null || meta?.hasMore != null\n ? Boolean(meta.has_more ?? meta.hasMore)\n : Number(meta?.total_count ?? meta?.totalCount ?? 0) >\n Number(meta?.offset ?? 0) + Number(meta?.limit ?? 0),\n },\n };\n }\n\n async getInvoiceAs(id: string, format: DocumentFormat): Promise<ArrayBuffer> {\n const { maxRetries, initialDelayMs, maxDelayMs } = this.retryConfig;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await this.doRequestBinary(`/invoices/${id}/as/${format}`);\n } catch (err) {\n lastError = err;\n if (attempt < maxRetries && isRetryableError(err)) {\n const retryAfterMs = err instanceof PeppolApiError ? err.retryAfterMs : undefined;\n await sleep(calculateRetryDelay(attempt, initialDelayMs, maxDelayMs, retryAfterMs));\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private async doRequestBinary(path: string): Promise<ArrayBuffer> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const requestHeaders = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n\n const startTime = Date.now();\n if (this.onRequest) {\n try {\n this.onRequest({\n method: \"GET\",\n url,\n headers: { ...requestHeaders },\n timestamp: startTime,\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: requestHeaders,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => \"Unknown error\");\n const retryAfterMs = response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined;\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: errorBody,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n throw new PeppolApiError(\n formatApiErrorMessage(response.status, errorBody),\n response.status,\n errorBody,\n retryAfterMs,\n );\n }\n\n const responseBody = await response.arrayBuffer();\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: `[ArrayBuffer: ${responseBody.byteLength} bytes]`,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n return responseBody;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async validateDocumentServer(input: InvoiceInput): Promise<ServerValidationResult> {\n return this.request<ServerValidationResult>(\"POST\", \"/validate/server\", input);\n }\n\n async listEvents(options?: ListEventsOptions): Promise<PaginatedResult<EventEntry>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n if (options?.invoiceId) params.set(\"invoiceId\", options.invoiceId);\n if (options?.dateFrom) params.set(\"dateFrom\", options.dateFrom);\n if (options?.dateTo) params.set(\"dateTo\", options.dateTo);\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/events${query}`);\n\n // Rows are camelCase (id, eventType, documentId, metadata, createdAt);\n // pagination meta is snake_case (total_count, has_more) — same split as\n // invoices.list (GPR-738). Read both forms defensively.\n const events = (result.data ?? []) as Record<string, unknown>[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data: events.map((evt) => ({\n id: String(evt.id ?? \"\"),\n eventType: String(evt.eventType ?? evt.event_type ?? \"\"),\n documentId: (evt.documentId ?? evt.document_id ?? null) as string | null,\n metadata: (evt.metadata ?? null) as Record<string, unknown> | null,\n createdAt: String(evt.createdAt ?? evt.created_at ?? \"\"),\n })),\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? events.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n // Prefer the gateway's authoritative has_more; fall back to computing it\n // from total_count/offset/limit so listAll() paginates correctly even if\n // a response omits the flag.\n hasMore:\n meta?.has_more != null || meta?.hasMore != null\n ? Boolean(meta.has_more ?? meta.hasMore)\n : Number(meta?.total_count ?? meta?.totalCount ?? 0) >\n Number(meta?.offset ?? options?.offset ?? 0) +\n Number(meta?.limit ?? options?.limit ?? 0),\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async acknowledgeInvoice(id: string): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"POST\", `/invoices/${id}/ack`);\n return parseSendResult(result);\n }\n\n async updateInvoice(id: string, input: InvoiceUpdateInput): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/invoices/${id}`, input);\n return parseSendResult(result);\n }\n\n async deleteInvoice(id: string): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"DELETE\", `/invoices/${id}`);\n return parseSendResult(result);\n }\n\n async markInvoiceAs(id: string, state: MarkAsState, options?: MarkAsOptions): Promise<SendResult> {\n const body: Record<string, unknown> = { state };\n if (options?.commit) body.commit = options.commit;\n if (options?.reason) body.reason = options.reason;\n const result = await this.request<Record<string, unknown>>(\"POST\", `/invoices/${id}/mark-as`, body);\n return parseSendResult(result);\n }\n\n async listContacts(options?: ListContactsOptions): Promise<PaginatedResult<Contact>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n if (options?.name) params.set(\"name\", options.name);\n if (options?.isClient != null) params.set(\"isClient\", String(options.isClient));\n if (options?.isProvider != null) params.set(\"isProvider\", String(options.isProvider));\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/contacts${query}`);\n\n const contacts = (result.contacts ?? result.data ?? []) as Record<string, unknown>[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data: contacts.map(parseContact),\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? contacts.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n hasMore: meta\n ? Number(meta.total_count ?? meta.totalCount) > Number(meta.offset) + Number(meta.limit)\n : false,\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async getContact(id: string): Promise<Contact> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/contacts/${id}`);\n return parseContact(result);\n }\n\n async createContact(input: ContactInput): Promise<Contact> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/contacts\", input);\n return parseContact(result);\n }\n\n async updateContact(id: string, input: Partial<ContactInput>): Promise<Contact> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/contacts/${id}`, input);\n return parseContact(result);\n }\n\n async deleteContact(id: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/contacts/${id}`);\n }\n\n async createLegalEntity(input: LegalEntityInput, options?: LegalEntityRequestOptions): Promise<LegalEntity> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) headers[\"Idempotency-Key\"] = options.idempotencyKey;\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/legal-entities\", input, headers);\n return parseLegalEntity(result);\n }\n\n async getLegalEntity(id: string): Promise<LegalEntity> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/legal-entities/${id}`);\n return parseLegalEntity(result);\n }\n\n async listLegalEntities(options?: ListLegalEntitiesOptions): Promise<PaginatedResult<LegalEntity>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/legal-entities${query}`);\n\n // The route returns { data, pagination: { total_count, offset, limit, has_more } }.\n const rows = (result.data ?? []) as Record<string, unknown>[];\n const pagination = result.pagination as Record<string, unknown> | undefined;\n\n return {\n data: rows.map(parseLegalEntity),\n meta: {\n totalCount: Number(pagination?.total_count ?? rows.length),\n offset: Number(pagination?.offset ?? options?.offset ?? 0),\n limit: Number(pagination?.limit ?? options?.limit ?? 50),\n hasMore: Boolean(pagination?.has_more ?? false),\n truncated: false,\n },\n };\n }\n\n async archiveLegalEntity(id: string): Promise<ArchiveLegalEntityResult> {\n const result = await this.request<Record<string, unknown>>(\"DELETE\", `/legal-entities/${id}`);\n return {\n id: String(result.id ?? id),\n externalId: result.externalId != null ? String(result.externalId) : null,\n status: \"archived\",\n };\n }\n\n async requestLegalEntityAttestation(id: string, input: AttestationInput, options?: LegalEntityRequestOptions): Promise<AttestationResult> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) headers[\"Idempotency-Key\"] = options.idempotencyKey;\n const result = await this.request<Record<string, unknown>>(\n \"POST\",\n `/legal-entities/${id}/attestation`,\n input,\n headers,\n );\n return {\n id: String(result.id ?? id),\n externalId: result.externalId != null ? String(result.externalId) : null,\n status: String(result.status ?? \"\") as LegalEntityStatus,\n expiresAt: String(result.expiresAt ?? \"\"),\n };\n }\n\n async listBankAccounts(options?: ListBankAccountsOptions): Promise<PaginatedResult<BankAccount>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/bank-accounts${query}`);\n\n const bankAccounts = (result.bankAccounts ?? result.data ?? []) as Record<string, unknown>[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data: bankAccounts.map(parseBankAccount),\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? bankAccounts.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n hasMore: meta\n ? Number(meta.total_count ?? meta.totalCount) > Number(meta.offset) + Number(meta.limit)\n : false,\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async getBankAccount(id: string): Promise<BankAccount> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/bank-accounts/${id}`);\n return parseBankAccount(result);\n }\n\n async createBankAccount(input: BankAccountInput): Promise<BankAccount> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/bank-accounts\", input);\n return parseBankAccount(result);\n }\n\n async updateBankAccount(id: string, input: Partial<BankAccountInput>): Promise<BankAccount> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/bank-accounts/${id}`, input);\n return parseBankAccount(result);\n }\n\n async deleteBankAccount(id: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/bank-accounts/${id}`);\n }\n\n async importInvoice(options: ImportInvoiceOptions): Promise<SendResult> {\n const body = {\n file: arrayBufferToBase64(options.file),\n filename: options.filename,\n mimeType: options.mimeType ?? detectMimeType(options.filename),\n // Declared, never derived from the document: routing decides delivery, and\n // parsing a caller's XML for a destination would put a parse error on the\n // \"whose invoice goes where\" path.\n to: options.to,\n };\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices/import\", body);\n return parseSendResult(result);\n }\n\n async listTransportTypes(): Promise<TransportType[]> {\n const result = await this.request<Record<string, unknown>>(\"GET\", \"/transports/types\");\n const types = (result.transportTypes ?? result.data ?? []) as Record<string, unknown>[];\n return types.map((t) => ({\n code: String(t.code ?? \"\"),\n name: String(t.name ?? \"\"),\n }));\n }\n\n async listTransports(): Promise<Transport[]> {\n const result = await this.request<Record<string, unknown>>(\"GET\", \"/transports\");\n const transports = (result.transports ?? result.data ?? []) as Record<string, unknown>[];\n return transports.map(parseTransport);\n }\n\n async getTransport(code: string): Promise<Transport> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/transports/${code}`);\n return parseTransport(result);\n }\n\n async createTransport(input: TransportInput): Promise<Transport> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/transports\", input);\n return parseTransport(result);\n }\n\n async updateTransport(code: string, input: TransportUpdateInput): Promise<Transport> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/transports/${code}`, input);\n return parseTransport(result);\n }\n\n async deleteTransport(code: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/transports/${code}`);\n }\n}\n\n// ─── Import Helpers ──────────────────────────────────────────\n\n/** Convert ArrayBuffer or Uint8Array to base64 string (works in all runtimes). */\nexport function arrayBufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n}\n\n/** Detect MIME type from a filename's extension. */\nexport function detectMimeType(filename: string): string {\n const ext = filename.split(\".\").pop()?.toLowerCase();\n switch (ext) {\n case \"xml\": return \"application/xml\";\n case \"pdf\": return \"application/pdf\";\n case \"json\": return \"application/json\";\n default: return \"application/octet-stream\";\n }\n}\n\n/**\n * Read the wire status, or refuse (GPR-1061).\n *\n * The SDK used to fall back to `\"submitted\"` here. That value is not a terminal\n * state, so unless `submitted` was itself the status being waited for — and\n * `waitFor()` does check its targets first — `waitFor()` and `getpeppr send\n * --watch` could only time out on it, on a document that had in fact been\n * delivered. A plausible substitute is worse than a missing one: a consumer\n * reading `status` has no way to tell it apart from a measurement.\n */\n/** Upper bound on the serialised body carried by a PeppolProtocolError. */\nconst PROTOCOL_ERROR_BODY_LIMIT = 2000;\n\n/**\n * Deep-copy a response body for a logging hook, or hand it a marker.\n *\n * The hook must never receive the object the parsers go on to read (GPR-1061),\n * and it must never be skipped in silence either: the call site swallows hook\n * errors by design, so a `structuredClone` that throws would delete the log\n * entry without a trace.\n */\nfunction cloneForHook(body: unknown): unknown {\n try {\n return structuredClone(body);\n } catch {\n return \"[response body could not be copied for logging]\";\n }\n}\n\n/**\n * Serialise the offending body for a protocol error, bounded.\n *\n * An invoice payload has no natural size limit — 400 lines is an ordinary\n * document — and this string ends up on an exception a consumer may log. Cap\n * it: the point is to identify the shape that broke, not to archive the body.\n */\nfunction boundedBody(raw: unknown): string {\n let serialised: string;\n try {\n serialised = JSON.stringify(raw) ?? String(raw);\n } catch {\n serialised = \"[unserialisable response body]\";\n }\n if (serialised.length <= PROTOCOL_ERROR_BODY_LIMIT) return serialised;\n let head = serialised.slice(0, PROTOCOL_ERROR_BODY_LIMIT);\n // Never end on a lone high surrogate: the cut would split a character in two\n // and the payload kept for a support report would stop being what the gateway\n // sent, replaced by U+FFFD the moment it is encoded.\n if (/[\\uD800-\\uDBFF]$/.test(head)) head = head.slice(0, -1);\n return `${head}… [truncated, ${serialised.length} chars]`;\n}\n\n/**\n * Refuse a 2xx body the SDK cannot parse honestly (GPR-1061).\n *\n * `raw` is typed `Record<string, unknown>` by a cast, not by validation, so a\n * body that is not an object at all reaches here — `200 null` from a proxy in\n * front of the gateway is enough. Left unguarded that surfaces as a TypeError,\n * losing the type, the field and the body a support report needs.\n */\nfunction requireRecordBody(raw: unknown, surface: string): Record<string, unknown> {\n if (isRecord(raw)) return raw;\n throw new PeppolProtocolError(\n `The getpeppr API answered ${surface} with a body that is not an object. ` +\n `Please report this response to support@getpeppr.dev.`,\n \"body\",\n boundedBody(raw),\n );\n}\n\nfunction requireWireStatus(candidate: unknown, raw: Record<string, unknown>, surface: string): string {\n // A TYPE check, not a truthiness check. Everything here came off the wire and\n // TypeScript constrains none of it: `String(false)` is `\"false\"` and\n // `String({})` is `\"[object Object]\"`, both of which mapStatus would coerce\n // to \"unknown\" — and a polling loop starts over on \"unknown\".\n if (typeof candidate === \"string\" && candidate.trim() !== \"\") return candidate;\n // The body stays on `responseBody`, never in `message`: the message is what\n // the CLI prints and what most consumers log by reflex.\n throw new PeppolProtocolError(\n `The getpeppr API answered ${surface} without a status. The SDK will not ` +\n `invent one — please report this response to support@getpeppr.dev.`,\n \"status\",\n boundedBody(raw),\n );\n}\n\n/**\n * An identifier the gateway MAY send, kept only if it is really a string.\n *\n * A TYPE guard, never a coercion: `String(42)` is `\"42\"` and `String({})` is\n * `\"[object Object]\"` — both look like identifiers and resolve to nothing on\n * the next call. Nothing here is constrained by TypeScript; the response body\n * is a cast over parsed JSON. Same doctrine as `requireWireStatus`: the SDK\n * does not invent a value it was not given (GPR-1061).\n */\nfunction optionalWireId(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() !== \"\" ? value : undefined;\n}\n\nfunction parseSendResult(body: Record<string, unknown>): SendResult {\n const result = requireRecordBody(body, \"this request\");\n const rawStatus = requireWireStatus(result.status, result, \"this request\");\n const sendResult: SendResult = {\n id: String(result.id ?? \"\"),\n status: mapStatus(rawStatus),\n rawStatus,\n // A TYPE guard like the identifiers below, not a cast. This line used to\n // read `as string | undefined`, which types a number as a string and hands\n // a consumer an AS4 id that never existed.\n peppolMessageId: optionalWireId(result.peppolMessageId ?? result.peppol_message_id),\n ublXml: result.ublXml as string | undefined,\n warnings: Array.isArray(result.warnings) ? result.warnings : undefined,\n };\n // GPR-1061 — this used to fall back to `new Date().toISOString()`. A timestamp\n // stamped at the moment of the call is indistinguishable from one the gateway\n // measured, and no consumer can tell them apart. Absent stays absent.\n //\n // `updatedAt` was in this chain too and is gone: it is a different\n // measurement, and serving it under `createdAt` is the same fiction wearing\n // a plausible value. `created_at` stays — it is the snake_case spelling of\n // the same field, not another field.\n const createdAt = result.createdAt ?? result.created_at;\n if (createdAt != null) sendResult.createdAt = String(createdAt);\n const detail = parseStatusDetail(result.detail);\n if (detail) sendResult.detail = detail;\n // ⛔ GPR-1069 — `parseSendResult` est une LISTE BLANCHE : tout champ non\n // recopié ici est SUPPRIMÉ silencieusement pour l'utilisateur du SDK. Le\n // gateway et l'OpenAPI exposaient déjà `rulebook` sur le 201 d'import que\n // cette liste jetait — la promesse « nous vous disons contre quelle version\n // nous avons validé » était donc tenue en HTTP brut et fausse via le SDK.\n //\n // ⚠️ Garde de FORME, pas cast : les deux champs doivent être des chaînes.\n // Un objet partiel venu du réseau n'entre pas — mieux vaut absent que\n // `verifiedAt: undefined` sous un type qui le déclare requis.\n const rulebook = result.rulebook;\n if (\n typeof rulebook === \"object\" && rulebook !== null &&\n typeof (rulebook as Record<string, unknown>).peppol === \"string\" &&\n typeof (rulebook as Record<string, unknown>).verifiedAt === \"string\"\n ) {\n sendResult.rulebook = rulebook as { peppol: string; verifiedAt: string };\n }\n // GPR-1061 — `id` keeps whatever meaning its surface gives it; these two say\n // which identifier you are actually holding.\n const submissionId = optionalWireId(result.submissionId);\n if (submissionId) sendResult.submissionId = submissionId;\n const providerDocumentId = optionalWireId(result.providerDocumentId);\n if (providerDocumentId) sendResult.providerDocumentId = providerDocumentId;\n return sendResult;\n}\n\nfunction parseDirectoryEntry(result: Record<string, unknown>): DirectoryEntry {\n const participant = isRecord(result.participant) ? result.participant : result;\n const scheme = participant.scheme == null ? undefined : String(participant.scheme);\n const id = participant.id == null ? undefined : String(participant.id);\n const peppolId =\n participant.peppolId == null\n ? formatPeppolId(scheme, id)\n : String(participant.peppolId);\n\n return {\n name: String(participant.name ?? \"\"),\n peppolId: peppolId as PeppolId,\n country: String(participant.country ?? \"\"),\n capabilities: Array.isArray(participant.capabilities)\n ? participant.capabilities.map(String)\n : [],\n registrationDate: participant.registrationDate == null ? undefined : String(participant.registrationDate),\n vatNumber: participant.vatNumber == null ? undefined : String(participant.vatNumber),\n additionalIds: Array.isArray(participant.additionalIds)\n ? participant.additionalIds.filter(isRecord).map((entry) => ({\n scheme: String(entry.scheme ?? \"\"),\n value: String(entry.value ?? \"\"),\n }))\n : undefined,\n contactInfo: isRecord(participant.contactInfo)\n ? {\n name: participant.contactInfo.name == null ? undefined : String(participant.contactInfo.name),\n email: participant.contactInfo.email == null ? undefined : String(participant.contactInfo.email),\n phone: participant.contactInfo.phone == null ? undefined : String(participant.contactInfo.phone),\n }\n : undefined,\n website: participant.website == null ? undefined : String(participant.website),\n };\n}\n\nfunction formatPeppolId(scheme: string | undefined, id: string | undefined): string {\n if (!id) return scheme ? `${scheme}:` : \"\";\n if (id.includes(\":\")) return id;\n return scheme ? `${scheme}:${id}` : id;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nconst STATUS_DETAIL_AXES = [\"platformFiscal\", \"delivery\", \"businessDisposition\", \"settlement\"] as const;\n\n/** Rebuild one axis entry by ALLOWLIST — the public type has no `message` field\n * and parsing must not smuggle one (or any unknown key) in at runtime. Returns\n * undefined when the required identifying fields are missing. */\nfunction parseStatusDetailEntry(raw: unknown): StatusDetailEntry | undefined {\n if (\n !isRecord(raw) ||\n typeof raw.axis !== \"string\" ||\n typeof raw.jurisdiction !== \"string\" ||\n typeof raw.code !== \"string\" ||\n typeof raw.label !== \"string\" ||\n typeof raw.codeSystem !== \"string\" ||\n typeof raw.codeVersion !== \"string\"\n ) {\n return undefined;\n }\n const entry: StatusDetailEntry = {\n axis: raw.axis as StatusDetailEntry[\"axis\"],\n jurisdiction: raw.jurisdiction,\n code: raw.code,\n label: raw.label,\n codeSystem: raw.codeSystem,\n codeVersion: raw.codeVersion,\n };\n if (isRecord(raw.standardCode) && typeof raw.standardCode.system === \"string\" && typeof raw.standardCode.code === \"string\") {\n entry.standardCode = { system: raw.standardCode.system, code: raw.standardCode.code };\n }\n if (typeof raw.reason === \"string\") entry.reason = raw.reason;\n if (Array.isArray(raw.warnings) && raw.warnings.every((w) => typeof w === \"string\")) {\n entry.warnings = [...raw.warnings];\n }\n if (typeof raw.failureCategory === \"string\") {\n entry.failureCategory = raw.failureCategory as StatusDetailEntry[\"failureCategory\"];\n }\n if (\n isRecord(raw.payment) &&\n typeof raw.payment.amount === \"number\" &&\n typeof raw.payment.currency === \"string\" &&\n typeof raw.payment.date === \"string\"\n ) {\n entry.payment = { amount: raw.payment.amount, currency: raw.payment.currency, date: raw.payment.date };\n }\n if (typeof raw.paymentSemantics === \"string\") {\n entry.paymentSemantics = raw.paymentSemantics as StatusDetailEntry[\"paymentSemantics\"];\n }\n if (typeof raw.actor === \"string\") entry.actor = raw.actor as StatusDetailEntry[\"actor\"];\n return entry;\n}\n\n/** Tolerant client-side pick of the per-axis detail map — never throws on gateway JSON. */\nfunction parseStatusDetail(raw: unknown): StatusDetail | undefined {\n if (!isRecord(raw)) return undefined;\n const detail: StatusDetail = {};\n for (const axis of STATUS_DETAIL_AXES) {\n const entry = parseStatusDetailEntry(raw[axis]);\n if (entry) detail[axis] = entry;\n }\n return Object.keys(detail).length > 0 ? detail : undefined;\n}\n\nfunction parseContact(raw: Record<string, unknown>): Contact {\n const contact: Contact = {\n id: String(raw.id ?? \"\"),\n name: String(raw.name ?? \"\"),\n };\n\n if (raw.peppolId != null) contact.peppolId = String(raw.peppolId);\n if (raw.vatNumber != null) contact.vatNumber = String(raw.vatNumber);\n if (raw.companyId != null) contact.companyId = String(raw.companyId);\n if (raw.street != null) contact.street = String(raw.street);\n if (raw.city != null) contact.city = String(raw.city);\n if (raw.postalCode != null) contact.postalCode = String(raw.postalCode);\n if (raw.country != null) contact.country = String(raw.country);\n if (raw.email != null) contact.email = String(raw.email);\n if (raw.phone != null) contact.phone = String(raw.phone);\n if (raw.isClient != null) contact.isClient = Boolean(raw.isClient);\n if (raw.isProvider != null) contact.isProvider = Boolean(raw.isProvider);\n if (raw.createdAt != null) contact.createdAt = String(raw.createdAt);\n if (raw.updatedAt != null) contact.updatedAt = String(raw.updatedAt);\n if (raw.directoryVerified != null) contact.directoryVerified = Boolean(raw.directoryVerified);\n if (raw.directoryLastChecked != null) contact.directoryLastChecked = String(raw.directoryLastChecked);\n\n return contact;\n}\n\nfunction parseLegalEntity(raw: Record<string, unknown>): LegalEntity {\n const idObj = raw.identifier as Record<string, unknown> | null | undefined;\n const le: LegalEntity = {\n id: String(raw.id ?? \"\"),\n externalId: raw.externalId != null ? String(raw.externalId) : null,\n companyName: raw.companyName != null ? String(raw.companyName) : null,\n country: raw.country != null ? String(raw.country) : null,\n identifier:\n idObj && idObj.scheme != null && idObj.value != null\n ? { scheme: String(idObj.scheme), value: String(idObj.value) }\n : null,\n status: String(raw.status ?? \"pending\") as LegalEntityStatus,\n environment: String(raw.environment ?? \"\"),\n createdAt: String(raw.createdAt ?? \"\"),\n };\n if (raw.verificationDetail != null) {\n le.verificationDetail = raw.verificationDetail as LegalEntity[\"verificationDetail\"];\n }\n return le;\n}\n\nfunction parseInvoiceSummary(row: Record<string, unknown>): InvoiceSummary {\n // The gateway returns camelCase rows (`invoiceNumber`, `createdAt`, …);\n // `number` is accepted as a legacy fallback for back-compat (GPR-738).\n const raw = requireRecordBody(row, \"this invoice row\");\n const rawStatus = requireWireStatus(raw.state ?? raw.status, raw, \"this invoice row\");\n const summary: InvoiceSummary = {\n id: String(raw.id ?? \"\"),\n number: String(raw.invoiceNumber ?? raw.number ?? \"\"),\n status: mapStatus(rawStatus),\n rawStatus,\n };\n const detail = parseStatusDetail(raw.detail);\n if (detail) summary.detail = detail;\n // GPR-1062 — the gateway has always sent `providerDocumentId` here and this\n // parser dropped it, so `list()` and `getStatus()` did not compose.\n const submissionId = optionalWireId(raw.submissionId);\n if (submissionId) summary.submissionId = submissionId;\n const providerDocumentId = optionalWireId(raw.providerDocumentId);\n if (providerDocumentId) summary.providerDocumentId = providerDocumentId;\n if (raw.createdAt != null) summary.createdAt = String(raw.createdAt);\n if (typeof raw.isCreditNote === \"boolean\") summary.isCreditNote = raw.isCreditNote;\n if (raw.recipientName != null) summary.recipientName = String(raw.recipientName);\n if (raw.totalAmount != null && Number.isFinite(Number(raw.totalAmount))) {\n summary.totalAmount = Number(raw.totalAmount);\n }\n if (raw.currency != null) summary.currency = String(raw.currency);\n if (raw.environment != null) summary.environment = String(raw.environment);\n return summary;\n}\n\nfunction parseBankAccount(raw: Record<string, unknown>): BankAccount {\n const account: BankAccount = {\n id: String(raw.id ?? \"\"),\n name: String(raw.name ?? \"\"),\n type: (raw.type === \"number\" ? \"number\" : \"iban\") as \"iban\" | \"number\",\n };\n\n if (raw.iban != null) account.iban = String(raw.iban);\n if (raw.number != null) account.number = String(raw.number);\n if (raw.bic != null) account.bic = String(raw.bic);\n if (raw.country != null) account.country = String(raw.country);\n if (raw.createdAt != null) account.createdAt = String(raw.createdAt);\n if (raw.updatedAt != null) account.updatedAt = String(raw.updatedAt);\n\n return account;\n}\n\nfunction parseTransport(raw: Record<string, unknown>): Transport {\n return {\n id: String(raw.id ?? \"\"),\n transportTypeCode: String(raw.transportTypeCode ?? \"\"),\n name: String(raw.name ?? \"\"),\n status: raw.status ? String(raw.status) : undefined,\n };\n}\n\n// getpeppr gateway document lifecycle states.\n// Mapped from Storecove webhook events. See: Storecove API v2 §3.3.4\nconst VALID_STATUSES = new Set<DocumentStatus>([\n \"submitted\", \"delivered\", \"accepted\", \"rejected\", \"paid\", \"failed\",\n \"cleared\", \"acknowledged\", \"in_process\", \"under_query\",\n \"conditionally_accepted\", \"partially_paid\", \"no_action\",\n \"unknown\", // explicitly known: gateway may emit this when it can't map a Storecove status\n]);\n\n// Note: each call to mapStatus that hits the unknown fallback emits its own console.warn.\n// No dedup is intentional — callers see the warning proportionally to how often the\n// unknown status appears (matches Stripe/AWS SDK convention).\n/** @internal — exported for testing only; not part of the public SDK surface. */\nexport function mapStatus(raw: string): DocumentStatus {\n const s = raw.toLowerCase() as DocumentStatus;\n if (VALID_STATUSES.has(s)) return s;\n console.warn(\n `[getpeppr] Unknown gateway status received: \"${raw}\" — ` +\n `please report to support@getpeppr.dev. Coercing to \"unknown\".`,\n );\n return \"unknown\";\n}\n\n// ─── Error Classes ──────────────────────────────────────────\n\nexport class PeppolError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PeppolError\";\n }\n}\n\nexport class PeppolValidationError extends PeppolError {\n constructor(\n message: string,\n public readonly validation: ValidationResult\n ) {\n super(message);\n this.name = \"PeppolValidationError\";\n }\n}\n\n/**\n * The gateway answered 2xx with a body the SDK cannot honestly parse — a field\n * the contract makes mandatory is missing.\n *\n * The SDK raises this instead of substituting a plausible value: a fabricated\n * status is indistinguishable from a measured one for anyone reading `status`\n * (GPR-1061). Nothing you sent causes it and retrying will not clear it — it is\n * worth reporting, with the caveat on `responseBody` below.\n */\nexport class PeppolProtocolError extends PeppolError {\n constructor(\n message: string,\n /** The field the response lacked, or `\"body\"` when it is not an object. */\n public readonly field: string,\n /**\n * The offending response body, serialised and capped at 2000 characters.\n *\n * This is your own document data as the gateway returned it. It is here so\n * you can see the shape that broke — treat it like any other payload before\n * putting it somewhere it will be retained.\n */\n public readonly responseBody: string,\n ) {\n super(message);\n this.name = \"PeppolProtocolError\";\n }\n}\n\nexport class PeppolApiError extends PeppolError {\n /** Parsed Retry-After delay in milliseconds (present on 429 responses) */\n public readonly retryAfterMs?: number;\n\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly responseBody: string,\n retryAfterMs?: number,\n ) {\n super(message);\n this.name = \"PeppolApiError\";\n this.retryAfterMs = retryAfterMs;\n }\n\n /**\n * The gateway's machine-readable error code, parsed from the JSON response body\n * (e.g. \"le_cap_exceeded\", \"identifier_immutable\", \"legal_entity_locked\", \"forbidden\").\n * Returns undefined when the body is not JSON or carries no string `code`.\n */\n get code(): string | undefined {\n try {\n const parsed = JSON.parse(this.responseBody) as { code?: unknown };\n return typeof parsed?.code === \"string\" ? parsed.code : undefined;\n } catch {\n return undefined;\n }\n }\n}\n\n// ─── Main SDK Client ────────────────────────────────────────\n\nexport class Peppol {\n private adapter: BackendAdapter;\n public readonly invoices: InvoiceOperations;\n public readonly creditNotes: CreditNoteOperations;\n public readonly directory: DirectoryOperations;\n public readonly events: EventOperations;\n public readonly contacts: ContactOperations;\n public readonly bankAccounts: BankAccountOperations;\n public readonly transports: TransportOperations;\n /**\n * Sub-tenant Legal Entities — **platform accounts only**.\n *\n * Requires a platform account and a **master API key**. With a standard key\n * every call here fails with 403 `master_key_required`.\n *\n * Onboarding your OWN company is not done through this API: your legal entity\n * is managed in the console, on the Peppol identity page. This surface is for\n * platforms that onboard their customers as sub-tenants.\n *\n * **Getting access:** platform mode is enabled by getpeppr on your account —\n * email hello@getpeppr.dev to have it switched on. Once it is, you create the\n * master key yourself at https://console.getpeppr.dev/api-keys.\n *\n * @see https://getpeppr.dev/docs/platform/legal-entities/\n */\n public readonly legalEntities: LegalEntityOperations;\n\n constructor(config: PeppolConfig) {\n if (!config.apiKey) {\n throw new PeppolError(\n 'API key is required. Sign up at https://console.getpeppr.dev to get your sandbox key.'\n );\n }\n\n this.adapter = new GetpepprAdapter(config);\n this.invoices = new InvoiceOperations(this.adapter);\n this.creditNotes = new CreditNoteOperations(this.adapter);\n this.directory = new DirectoryOperations(this.adapter);\n this.events = new EventOperations(this.adapter);\n this.contacts = new ContactOperations(this.adapter);\n this.bankAccounts = new BankAccountOperations(this.adapter);\n this.transports = new TransportOperations(this.adapter);\n this.legalEntities = new LegalEntityOperations(this.adapter);\n }\n\n /**\n * Validate an invoice without sending it.\n * Useful for pre-flight checks in your UI.\n */\n validate(input: InvoiceInput): ValidationResult {\n return validateInvoice(input);\n }\n\n /**\n * Generate UBL XML without sending.\n * Useful for debugging or manual submission.\n */\n toXml(input: InvoiceInput): string {\n const validation = validateInvoice(input);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n validation\n );\n }\n if (input.isCreditNote) {\n return buildCreditNoteXml(input as unknown as CreditNoteInput);\n }\n return buildInvoiceXml(input);\n }\n}\n\n/** @internal — exported for testing only; not part of the public SDK surface. */\nexport async function* paginate<T>(\n fetchPage: (offset: number, limit: number) => Promise<PaginatedResult<T>>,\n options?: { limit?: number },\n): AsyncGenerator<T> {\n const pageSize = options?.limit ?? 25;\n let offset = 0;\n\n while (true) {\n const page = await fetchPage(offset, pageSize);\n if (page.data.length === 0) break; // safety: empty page (even with hasMore=true) ends iteration\n for (const item of page.data) {\n yield item;\n }\n if (!page.meta.hasMore) break;\n offset += page.data.length; // FIX (GPR-414 #6): was += pageSize, which silently skipped records on partial pages\n }\n}\n\nclass InvoiceOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Create a draft invoice without sending it.\n * Validates input client-side, then creates the invoice via the gateway.\n * Use `sendById()` to send the draft when ready.\n *\n * @example\n * ```ts\n * const draft = await peppol.invoices.create({ number: \"INV-001\", to, lines });\n * // Later, when ready:\n * await peppol.invoices.sendById(draft.id);\n * ```\n */\n async create(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const validation = validateInvoice(input);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed:\\n${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : \"\"}`).join(\"\\n\")}`,\n validation\n );\n }\n\n const result = await this.adapter.createInvoice(input, options);\n\n if (validation.warnings.length > 0) {\n result.warnings = validation.warnings;\n }\n\n return result;\n }\n\n /**\n * Send an existing draft invoice by ID.\n * The invoice must have been previously created with `create()`.\n *\n * @example\n * ```ts\n * await peppol.invoices.sendById(\"inv-1\");\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support draft sending\n */\n async sendById(id: string): Promise<void> {\n return this.adapter.sendInvoiceById(id);\n }\n\n /**\n * Send an invoice via Peppol.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.send({\n * number: \"INV-001\",\n * from: { name: \"My Company\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * to: { name: \"Client Co\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * lines: [\n * { description: \"Consulting\", quantity: 10, unitPrice: 150, vatRate: 21 }\n * ]\n * });\n * ```\n */\n async send(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n // Client-side validation for fast feedback\n const validation = validateInvoice(input);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed:\\n${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : \"\"}`).join(\"\\n\")}`,\n validation\n );\n }\n\n // Send structured JSON — gateway handles UBL generation\n const result = await this.adapter.sendInvoice(input, options);\n\n if (validation.warnings.length > 0) {\n result.warnings = validation.warnings;\n }\n\n return result;\n }\n\n /** List invoices with pagination, filtering, and proper metadata */\n async list(options?: ListInvoicesOptions): Promise<PaginatedResult<InvoiceSummary>> {\n return this.adapter.listInvoices(options);\n }\n\n /**\n * Async iterator over all invoices, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const invoice of peppol.invoices.listAll()) {\n * console.log(invoice.id, invoice.status);\n * }\n * ```\n */\n listAll(options?: Omit<ListInvoicesOptions, \"offset\">): AsyncIterable<InvoiceSummary> {\n return paginate(\n (offset, limit) => this.adapter.listInvoices({ ...options, offset, limit }),\n options,\n );\n }\n\n /**\n * Get the status of a sent invoice.\n *\n * @param options.includeEvidence Ask the gateway to read the sending evidence\n * from the Peppol network so the result carries `peppolMessageId`. Costs one\n * provider round trip, so it is off by default; if the document has not gone\n * out yet, or the read fails, the field is simply absent and everything else\n * is unaffected.\n *\n * @example\n * ```ts\n * const status = await peppol.invoices.getStatus(id);\n * const proof = await peppol.invoices.getStatus(id, { includeEvidence: true });\n * ```\n */\n async getStatus(documentId: string, options?: GetStatusOptions): Promise<SendResult> {\n return this.adapter.getStatus(documentId, options);\n }\n\n /**\n * Export an invoice in a specific format (e.g., PDF, UBL XML).\n * Returns raw binary data as an ArrayBuffer.\n *\n * @example\n * ```ts\n * const pdf = await peppol.invoices.getAs(\"inv-123\", \"pdf\");\n * fs.writeFileSync(\"invoice.pdf\", Buffer.from(pdf));\n * ```\n */\n async getAs(id: string, format: DocumentFormat): Promise<ArrayBuffer> {\n return this.adapter.getInvoiceAs(id, format);\n }\n\n /**\n * Validate an invoice server-side using the getpeppr gateway's offline SDK-backed checks.\n * The gateway runs SDK validation, verifies UBL XML generation, and evaluates offline\n * Peppol business rules without sending the invoice to Storecove.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.validateServer({\n * number: \"INV-001\",\n * to: { name: \"Acme\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * lines: [{ description: \"Item\", quantity: 1, unitPrice: 100, vatRate: 21 }]\n * });\n * console.log(result.valid, result.schematron.errors);\n * ```\n * Validation findings return a structured result with valid=false. Transport, auth,\n * malformed request, and unexpected gateway failures still throw PeppolApiError.\n */\n async validateServer(input: InvoiceInput): Promise<ServerValidationResult> {\n return this.adapter.validateDocumentServer(input);\n }\n\n /**\n * Send a UBL Invoice or CreditNote you built yourself.\n *\n * getpeppr does not regenerate, normalise, or repair the document — we\n * forward the bytes you supplied, unchanged, to the network. Only UBL Invoice\n * and CreditNote are accepted — a PDF, a CII document, or an XML that is\n * neither is refused. The file is base64-encoded into a JSON body; there is\n * no multipart upload.\n *\n * ⚠️ Byte-for-byte equality is NOT guaranteed, because the network\n * re-serialises the document in transit. Measured 2026-08-18 on a test\n * document: namespace declarations come back reordered, numeric character\n * references are resolved (`&#65;` → `A`), whitespace inside tags is dropped,\n * and no element was added, removed or altered. That is one document and four\n * kinds of difference — indicative, not a warranty of what is preserved.\n * **If you seal your documents, hash a canonical form (C14N) rather than the\n * raw bytes.**\n *\n * `to` is required and is never read from the document. Routing decides\n * delivery, the document travels as payload, and getpeppr will not guess a\n * destination by parsing your XML.\n *\n * Before transmission the document is validated against the complete official\n * OpenPeppol rulebooks. A document violating a `fatal` rule is refused and is\n * NOT sent; the error names the rule.\n *\n * @example\n * ```ts\n * const xmlBytes = fs.readFileSync(\"invoice.xml\");\n * const result = await peppol.invoices.importFile({\n * file: xmlBytes,\n * filename: \"invoice.xml\",\n * to: { peppolId: \"0208:0685660237\" },\n * });\n * console.log(result.id, result.status);\n * ```\n *\n * @throws {PeppolApiError} 400 — `invalid_base64`, or a missing `file` /\n * `filename`. `missing_recipient` when `to.peppolId` is absent.\n * @throws {PeppolApiError} 422 — the document was refused and NOT sent. Two\n * families, and they do NOT retry the same way:\n *\n * - **The document was rejected** (`validation_failed`, `not_ubl_document`,\n * `document_too_complex`, `undecodable_document`, `unsupported_encoding`).\n * Terminal: the same bytes fail identically forever. Fix the document —\n * retrying is pure waste, and `validation_failed` names the rule.\n * - **The account may not send right now** (`peppol_identity_incomplete`,\n * `peppol_identity_not_verified`, `platform_billing_not_active`,\n * `production_access_expired`). ⛔ NOT terminal: these describe account\n * state, and account state changes — a verification completes, a contract\n * is activated. The identical document will go through once it does.\n *\n * Treating the second family as terminal costs a customer a real invoice;\n * treating the first as retryable costs an infinite loop. See the API\n * reference for the full list.\n */\n async importFile(options: ImportInvoiceOptions): Promise<SendResult> {\n return this.adapter.importInvoice(options);\n }\n\n /**\n * Acknowledge a received invoice.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.acknowledge(\"inv-123\");\n * console.log(result.status); // \"accepted\"\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support acknowledgement\n */\n async acknowledge(id: string): Promise<SendResult> {\n return this.adapter.acknowledgeInvoice(id);\n }\n\n /**\n * Update an existing invoice (draft only).\n * Only include the fields you want to change — partial updates are supported.\n *\n * @example\n * ```ts\n * const updated = await peppol.invoices.update(\"inv-123\", {\n * dueDate: \"2026-04-01\",\n * lines: [\n * { id: \"line-1\", quantity: 5 },\n * { id: \"line-2\", _destroy: true },\n * ],\n * });\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support invoice updates\n */\n async update(id: string, input: InvoiceUpdateInput): Promise<SendResult> {\n return this.adapter.updateInvoice(id, input);\n }\n\n /**\n * Delete an invoice.\n *\n * @example\n * ```ts\n * const deleted = await peppol.invoices.delete(\"inv-123\");\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support invoice deletion\n */\n async delete(id: string): Promise<SendResult> {\n return this.adapter.deleteInvoice(id);\n }\n\n /**\n * Transition an invoice to a new state.\n * The gateway validates the state machine — invalid transitions return an error.\n *\n * `\"paid\"` on a French CTC invoice reports the payment collection\n * (« signalement d'encaissement ») to the tax authority via the gateway —\n * a legal obligation of the French mandate for service invoices. The full\n * amount is reported from the invoice's stored tax breakdown (no amount to\n * pass), at most once per invoice: replays return the same report (200),\n * a concurrent report returns 409, a non-French invoice returns 422.\n * The invoice's own status becomes `paid` later, when the network confirms\n * (webhook / polling), not synchronously with this call.\n *\n * @example\n * ```ts\n * // France: report that the customer paid this invoice\n * await peppol.invoices.markAs(\"inv-123\", \"paid\");\n * ```\n * @throws {PeppolApiError} 422 for \"paid\" on a non-French-CTC invoice; 501 for states the provider does not support\n */\n async markAs(id: string, state: MarkAsState, options?: MarkAsOptions): Promise<SendResult> {\n return this.adapter.markInvoiceAs(id, state, options);\n }\n\n /**\n * Send multiple invoices in parallel with controlled concurrency.\n * Each invoice is validated and sent individually — failures don't affect other invoices\n * unless `stopOnError: true` is set.\n *\n * The SDK's built-in retry logic (including 429 Retry-After) provides automatic\n * rate-limit handling at the request level.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.sendBatch([invoice1, invoice2, invoice3], {\n * concurrency: 3,\n * });\n * console.log(`${result.succeeded.length} sent, ${result.failed.length} failed`);\n * ```\n */\n async sendBatch(\n inputs: InvoiceInput[],\n options?: BatchSendOptions,\n ): Promise<BatchSendResult> {\n const concurrency = options?.concurrency ?? 5;\n const stopOnError = options?.stopOnError ?? false;\n\n const succeeded: BatchSendResult[\"succeeded\"] = [];\n const failed: BatchSendResult[\"failed\"] = [];\n let stopped = false;\n\n // Process in chunks of `concurrency` size\n for (let i = 0; i < inputs.length; i += concurrency) {\n if (stopped) break;\n\n const chunk = inputs.slice(i, i + concurrency);\n const promises = chunk.map(async (input, j) => {\n const index = i + j;\n if (stopped) return;\n try {\n const result = await this.send(input);\n succeeded.push({ index, result });\n } catch (error) {\n failed.push({ index, input, error: error as Error });\n if (stopOnError) {\n stopped = true;\n }\n }\n });\n\n await Promise.all(promises);\n }\n\n return { succeeded, failed, total: inputs.length };\n }\n\n /**\n * Poll until an invoice reaches a target status.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.waitFor(id, \"accepted\", { timeout: 60000 });\n * ```\n */\n async waitFor(\n documentId: string,\n targetStatus: DocumentStatus | DocumentStatus[],\n options?: WaitForOptions,\n ): Promise<SendResult> {\n const timeout = options?.timeout ?? 120_000;\n const interval = options?.interval ?? 5_000;\n const targets = Array.isArray(targetStatus) ? targetStatus : [targetStatus];\n // §8.7 — terminal sets DERIVED from the precedence table, never hard-coded.\n // Targets are checked first, so explicitly waiting for a terminal still resolves.\n const startTime = Date.now();\n\n while (true) {\n const result = await this.getStatus(documentId);\n\n if (targets.includes(result.status)) {\n return result;\n }\n\n if (TERMINAL_FAILURE_STATUSES.includes(result.status)) {\n throw new PeppolError(\n `Document ${documentId} reached terminal status \"${result.status}\" while waiting for \"${targets.join('\" or \"')}\"`\n );\n }\n\n if (statusFamily(result.status) === \"terminal-success\") {\n // The document reached a terminal success (paid) that outranks every\n // progress target in the §8.1 precedence: the target was PASSED, not\n // missed — resolve with the real result instead of timing out (GPR-825).\n if (targets.every((t) => statusFamily(t) === \"progress\")) {\n return result;\n }\n // A failure/unknown target can never be reached anymore — fail fast.\n throw new PeppolError(\n `Document ${documentId} reached terminal status \"${result.status}\" while waiting for \"${targets.join('\" or \"')}\"`\n );\n }\n\n if (Date.now() - startTime >= timeout) {\n throw new PeppolError(\n `Timed out waiting for document ${documentId} to reach status \"${targets.join('\" or \"')}\" (last: \"${result.status}\")`\n );\n }\n\n await sleep(interval);\n }\n }\n}\n\n/** @deprecated Use peppol.invoices.send() with isCreditNote: true instead */\nclass CreditNoteOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Send a credit note via Peppol.\n * @deprecated Use peppol.invoices.send({ ...input, isCreditNote: true }) instead.\n */\n async send(input: CreditNoteInput): Promise<SendResult> {\n // Convert to InvoiceInput with isCreditNote flag and delegate to sendInvoice\n const invoiceInput: InvoiceInput = {\n ...input,\n isCreditNote: true,\n invoiceReference: input.invoiceReference,\n };\n\n const validation = validateInvoice(invoiceInput);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Credit note validation failed:\\n${validation.errors.map((e) => ` - ${e.field}: ${e.message}`).join(\"\\n\")}`,\n validation\n );\n }\n\n // Route through sendInvoice — the provider has no separate credit-notes endpoint\n return this.adapter.sendInvoice(invoiceInput);\n }\n}\n\n// ─── Directory Operations ───────────────────────────────────\n\nclass DirectoryOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Look up a Peppol participant in the directory.\n *\n * @example\n * ```ts\n * const entry = await peppol.directory.lookup(\"0208:0685660237\");\n * console.log(entry.name, entry.capabilities);\n * ```\n */\n async lookup(peppolId: PeppolId): Promise<DirectoryEntry> {\n const colonIndex = peppolId.indexOf(\":\");\n if (colonIndex === -1) {\n throw new PeppolError(\n 'Invalid Peppol ID format. Expected \"scheme:id\" (e.g., \"0208:0685660237\")',\n );\n }\n const scheme = peppolId.slice(0, colonIndex);\n const id = peppolId.slice(colonIndex + 1);\n return this.adapter.lookupDirectory(scheme, id);\n }\n\n /**\n * Search the Peppol Directory for participants.\n *\n * @example\n * ```ts\n * const result = await peppol.directory.search({ name: \"Acme\", country: \"BE\" });\n * console.log(result.data); // DirectoryEntry[]\n * console.log(result.meta.totalCount);\n * ```\n */\n async search(options: DirectorySearchOptions): Promise<DirectorySearchResult> {\n if (!options.name && !options.country && !options.vatNumber) {\n throw new PeppolError(\"At least one search criterion is required (name, country, or vatNumber)\");\n }\n if (options.name && options.name.length < 3) {\n throw new PeppolError(\"Search name must be at least 3 characters\");\n }\n if (!this.adapter.searchDirectory) {\n throw new PeppolError(\"Directory search is not supported by this backend adapter\");\n }\n\n const params: Record<string, string> = {};\n if (options.name) params.name = options.name;\n if (options.country) params.country = options.country;\n if (options.vatNumber) params.vatNumber = options.vatNumber;\n if (options.limit !== undefined) params.limit = String(options.limit);\n if (options.offset !== undefined) params.offset = String(options.offset);\n\n return this.adapter.searchDirectory(params);\n }\n\n /**\n * Search the Peppol Directory by VAT number.\n * Convenience method — equivalent to `search({ vatNumber })`.\n *\n * @example\n * ```ts\n * const result = await peppol.directory.searchByVat(\"BE0685660237\");\n * ```\n */\n async searchByVat(vatNumber: string): Promise<DirectorySearchResult> {\n return this.search({ vatNumber });\n }\n}\n\n// ─── Event Operations ────────────────────────────────────────\n\nclass EventOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List events with optional filtering and pagination.\n *\n * @example\n * ```ts\n * const result = await peppol.events.list({ limit: 10 });\n * console.log(result.data, result.meta);\n *\n * // Filter by invoice\n * const invoiceEvents = await peppol.events.list({ invoiceId: \"inv-123\" });\n * ```\n */\n async list(options?: ListEventsOptions): Promise<PaginatedResult<EventEntry>> {\n return this.adapter.listEvents(options);\n }\n\n /**\n * Async iterator over all events, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const event of peppol.events.listAll({ invoiceId: \"inv-123\" })) {\n * console.log(event.name, event.createdAt);\n * }\n * ```\n */\n listAll(options?: Omit<ListEventsOptions, \"offset\">): AsyncIterable<EventEntry> {\n return paginate(\n (offset, limit) => this.adapter.listEvents({ ...options, offset, limit }),\n options,\n );\n }\n}\n\n// ─── Contact Operations ─────────────────────────────────────\n\nclass ContactOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List contacts with optional filtering and pagination.\n *\n * @example\n * ```ts\n * const result = await peppol.contacts.list({ limit: 10, isClient: true });\n * console.log(result.data, result.meta);\n * ```\n */\n async list(options?: ListContactsOptions): Promise<PaginatedResult<Contact>> {\n return this.adapter.listContacts(options);\n }\n\n /**\n * Get a single contact by ID.\n *\n * @example\n * ```ts\n * const contact = await peppol.contacts.get(\"123\");\n * console.log(contact.name, contact.peppolId);\n * ```\n */\n async get(id: string): Promise<Contact> {\n return this.adapter.getContact(id);\n }\n\n /**\n * Create a new contact.\n *\n * @example\n * ```ts\n * const contact = await peppol.contacts.create({\n * name: \"ACMEDIA\",\n * peppolId: \"0208:0685660237\",\n * country: \"BE\",\n * isClient: true,\n * });\n * ```\n */\n async create(input: ContactInput): Promise<Contact> {\n return this.adapter.createContact(input);\n }\n\n /**\n * Update an existing contact.\n *\n * @example\n * ```ts\n * const updated = await peppol.contacts.update(\"123\", { email: \"new@acme.com\" });\n * ```\n */\n async update(id: string, input: Partial<ContactInput>): Promise<Contact> {\n return this.adapter.updateContact(id, input);\n }\n\n /**\n * Delete a contact.\n *\n * @example\n * ```ts\n * await peppol.contacts.delete(\"123\");\n * ```\n */\n async delete(id: string): Promise<void> {\n return this.adapter.deleteContact(id);\n }\n\n /**\n * Async iterator over all contacts, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const contact of peppol.contacts.listAll({ isClient: true })) {\n * console.log(contact.name, contact.peppolId);\n * }\n * ```\n */\n listAll(options?: Omit<ListContactsOptions, \"offset\">): AsyncIterable<Contact> {\n return paginate(\n (offset, limit) => this.adapter.listContacts({ ...options, offset, limit }),\n options,\n );\n }\n}\n\n/**\n * Sub-tenant Legal Entity operations — **platform accounts only**.\n *\n * Every method here requires a platform account and a master API key; a\n * standard key gets 403 `master_key_required`. Each one repeats the\n * requirement because an IDE shows only the member being hovered.\n *\n * @see https://getpeppr.dev/docs/platform/legal-entities/\n */\nclass LegalEntityOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Create a sub-tenant Legal Entity for one of your customers.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * Your own company's legal entity is managed in the console, on the Peppol\n * identity page; this creates an entity for a customer of yours.\n *\n * Idempotent on `externalId`: repeated calls with the same `externalId` return\n * the existing entity (HTTP 200) instead of creating a duplicate. Transient 5xx\n * failures are NOT auto-retried unless you pass `options.idempotencyKey`.\n *\n * @example\n * ```ts\n * const le = await peppol.legalEntities.create({\n * externalId: \"tenant-42\",\n * companyName: \"Acme Health AB\",\n * country: \"SE\",\n * address: { line1: \"Storgatan 1\", city: \"Stockholm\", zip: \"11122\" },\n * identifier: { scheme: \"0007\", value: \"5560000001\" },\n * }, { idempotencyKey: \"tenant-42-create\" });\n * ```\n */\n async create(input: LegalEntityInput, options?: LegalEntityRequestOptions): Promise<LegalEntity> {\n return this.adapter.createLegalEntity(input, options);\n }\n\n /**\n * Fetch a single sub-tenant Legal Entity by id.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * For production entities the `status` reflects the attestation lifecycle\n * (awaiting_authz → attested → active).\n */\n async get(id: string): Promise<LegalEntity> {\n return this.adapter.getLegalEntity(id);\n }\n\n /**\n * List your sub-tenant Legal Entities, newest first.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * This lists the customers you have onboarded, never your own legal entity.\n */\n async list(options?: ListLegalEntitiesOptions): Promise<PaginatedResult<LegalEntity>> {\n return this.adapter.listLegalEntities(options);\n }\n\n /**\n * Async iterator over all sub-tenant Legal Entities, handling pagination.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * @example\n * ```ts\n * for await (const le of peppol.legalEntities.listAll()) console.log(le.id, le.status);\n * ```\n */\n listAll(options?: Omit<ListLegalEntitiesOptions, \"offset\">): AsyncIterable<LegalEntity> {\n return paginate(\n (offset, limit) => this.adapter.listLegalEntities({ ...options, offset, limit }),\n options,\n );\n }\n\n /**\n * Archive (soft-delete) a sub-tenant Legal Entity. The id stays resolvable\n * for audit.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n */\n async archive(id: string): Promise<ArchiveLegalEntityResult> {\n return this.adapter.archiveLegalEntity(id);\n }\n\n /**\n * Request a sub-tenant attestation (production only). Emails the co-branded\n * confirmation link to the sub-tenant contact and returns the pending status.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * Transient failures are NOT auto-retried unless you pass `options.idempotencyKey`;\n * re-issuing mints a fresh token, so a retried call is safe.\n *\n * @example\n * ```ts\n * await peppol.legalEntities.requestAttestation(le.id, { contactEmail: \"owner@acme.example\" });\n * ```\n */\n async requestAttestation(id: string, input: AttestationInput, options?: LegalEntityRequestOptions): Promise<AttestationResult> {\n return this.adapter.requestLegalEntityAttestation(id, input, options);\n }\n}\n\n// ─── Bank Account Operations ─────────────────────────────────\n\nclass BankAccountOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List bank accounts with optional pagination.\n *\n * @example\n * ```ts\n * const result = await peppol.bankAccounts.list({ limit: 10 });\n * console.log(result.data, result.meta);\n * ```\n */\n async list(options?: ListBankAccountsOptions): Promise<PaginatedResult<BankAccount>> {\n return this.adapter.listBankAccounts(options);\n }\n\n /**\n * Get a single bank account by ID.\n *\n * @example\n * ```ts\n * const account = await peppol.bankAccounts.get(\"123\");\n * console.log(account.name, account.iban);\n * ```\n */\n async get(id: string): Promise<BankAccount> {\n return this.adapter.getBankAccount(id);\n }\n\n /**\n * Create a new bank account.\n *\n * @example\n * ```ts\n * const account = await peppol.bankAccounts.create({\n * name: \"Main Account\",\n * iban: \"BE68539007547034\",\n * bic: \"BBRUBEBB\",\n * country: \"BE\",\n * });\n * ```\n */\n async create(input: BankAccountInput): Promise<BankAccount> {\n return this.adapter.createBankAccount(input);\n }\n\n /**\n * Update an existing bank account.\n *\n * @example\n * ```ts\n * const updated = await peppol.bankAccounts.update(\"123\", { name: \"Updated Name\" });\n * ```\n */\n async update(id: string, input: Partial<BankAccountInput>): Promise<BankAccount> {\n return this.adapter.updateBankAccount(id, input);\n }\n\n /**\n * Delete a bank account.\n *\n * @example\n * ```ts\n * await peppol.bankAccounts.delete(\"123\");\n * ```\n */\n async delete(id: string): Promise<void> {\n return this.adapter.deleteBankAccount(id);\n }\n\n /**\n * Async iterator over all bank accounts, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const account of peppol.bankAccounts.listAll()) {\n * console.log(account.name, account.iban);\n * }\n * ```\n */\n listAll(options?: Omit<ListBankAccountsOptions, \"offset\">): AsyncIterable<BankAccount> {\n return paginate(\n (offset, limit) => this.adapter.listBankAccounts({ ...options, offset, limit }),\n options,\n );\n }\n}\n\n// ─── Transport Operations ────────────────────────────────────\n\nclass TransportOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List all available transport types in the network.\n * Returns global transport types (not account-scoped).\n *\n * @example\n * ```ts\n * const types = await peppol.transports.listTypes();\n * console.log(types); // [{ code: \"peppol\", name: \"Peppol BIS 3.0\" }, ...]\n * ```\n */\n async listTypes(): Promise<TransportType[]> {\n return this.adapter.listTransportTypes();\n }\n\n /**\n * List configured transports for this account.\n *\n * @example\n * ```ts\n * const transports = await peppol.transports.list();\n * console.log(transports); // [{ id: \"t-1\", transportTypeCode: \"peppol\", name: \"...\" }, ...]\n * ```\n */\n async list(): Promise<Transport[]> {\n return this.adapter.listTransports();\n }\n\n /**\n * Get a single transport by code.\n *\n * @example\n * ```ts\n * const transport = await peppol.transports.get(\"peppol\");\n * ```\n */\n async get(code: string): Promise<Transport> {\n return this.adapter.getTransport(code);\n }\n\n /**\n * Create a new transport.\n *\n * @example\n * ```ts\n * const transport = await peppol.transports.create({\n * transportTypeCode: \"peppol\",\n * email: \"billing@acme.com\",\n * });\n * ```\n */\n async create(input: TransportInput): Promise<Transport> {\n return this.adapter.createTransport(input);\n }\n\n /**\n * Update an existing transport.\n *\n * @example\n * ```ts\n * const transport = await peppol.transports.update(\"peppol\", { email: \"new@acme.com\" });\n * ```\n */\n async update(code: string, input: TransportUpdateInput): Promise<Transport> {\n return this.adapter.updateTransport(code, input);\n }\n\n /**\n * Delete a transport.\n *\n * @example\n * ```ts\n * await peppol.transports.delete(\"peppol\");\n * ```\n */\n async delete(code: string): Promise<void> {\n return this.adapter.deleteTransport(code);\n }\n}\n\n// ─── Webhook Helper ─────────────────────────────────────────\n\n/** Default tolerance for webhook timestamp verification (5 minutes) */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/**\n * Parse and verify a webhook payload from getpeppr.\n *\n * getpeppr signs webhooks with HMAC-SHA256. The signature header format is:\n * `Getpeppr-Signature: t={timestamp},s={hmac_sha256_hex}`\n *\n * The signed payload is: `{timestamp}.{raw_json_body}`\n *\n * @example\n * ```ts\n * import { webhooks } from \"@getpeppr/sdk\";\n *\n * app.post(\"/webhooks/peppol\", async (req, res) => {\n * try {\n * const event = await webhooks.constructEvent(\n * req.body, // raw body string (NOT parsed JSON)\n * req.headers[\"getpeppr-signature\"], // signature header\n * \"whsec_your_webhook_secret\", // your endpoint's signing secret\n * );\n * switch (event.type) {\n * case \"inbound.invoice.received\":\n * console.log(\"New invoice from:\", event.data.sender.peppolId);\n * break;\n * }\n * res.sendStatus(200);\n * } catch (err) {\n * res.status(400).send(\"Webhook verification failed\");\n * }\n * });\n * ```\n */\nexport const webhooks = {\n /**\n * Parse a webhook payload without signature verification.\n * Use `constructEvent()` for verified parsing in production.\n */\n parse(payload: unknown): WebhookEvent {\n return payload as WebhookEvent;\n },\n\n /**\n * Verify and parse a webhook payload using HMAC-SHA256 signature.\n * Throws `PeppolError` if verification fails.\n *\n * @param rawBody — The raw request body string (NOT parsed JSON)\n * @param signatureHeader — The `Getpeppr-Signature` header value\n * @param secret — Your webhook secret from getpeppr\n * @param toleranceSeconds — Max age of the webhook in seconds (default: 300 = 5 min)\n */\n async constructEvent(\n rawBody: string,\n signatureHeader: string,\n secret: string,\n toleranceSeconds?: number,\n ): Promise<WebhookEvent> {\n if (!rawBody) {\n throw new PeppolError(\"Webhook error: missing request body\");\n }\n if (!signatureHeader) {\n throw new PeppolError(\"Webhook error: missing Getpeppr-Signature header\");\n }\n if (!secret) {\n throw new PeppolError(\"Webhook error: missing webhook secret\");\n }\n\n // Parse header: t={timestamp},s={signature}\n const match = signatureHeader.match(/t=([^,]+),s=(.+)/);\n if (!match) {\n throw new PeppolError(\n \"Webhook error: invalid signature header format. Expected 't={timestamp},s={signature}'\"\n );\n }\n\n const [, timestampStr, receivedSignature] = match;\n const timestamp = Number(timestampStr);\n\n if (!Number.isFinite(timestamp)) {\n throw new PeppolError(\"Webhook error: invalid timestamp in signature header\");\n }\n\n // Check timestamp tolerance (prevent replay attacks)\n const tolerance = toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > tolerance) {\n throw new PeppolError(\n `Webhook error: timestamp too old or too new (received: ${timestamp}, now: ${now}, tolerance: ${tolerance}s)`\n );\n }\n\n // Compute expected signature: HMAC-SHA256(secret, \"{timestamp}.{rawBody}\")\n const signedPayload = `${timestampStr}.${rawBody}`;\n const expectedSignature = await computeHmacSha256(secret, signedPayload);\n\n // Constant-time comparison to prevent timing attacks\n if (!timingSafeEqual(expectedSignature, receivedSignature)) {\n throw new PeppolError(\"Webhook error: signature verification failed\");\n }\n\n // Parse and return the event\n try {\n const parsed = typeof rawBody === \"string\" ? JSON.parse(rawBody) : rawBody;\n return parsed as WebhookEvent;\n } catch {\n throw new PeppolError(\"Webhook error: invalid JSON payload\");\n }\n },\n};\n\n/**\n * Compute HMAC-SHA256 hex digest.\n * Uses Web Crypto API (works in Node.js 18+, Deno, Bun, browsers).\n */\nasync function computeHmacSha256(secret: string, message: string): Promise<string> {\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(message));\n return Array.from(new Uint8Array(signature))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks.\n */\nfunction timingSafeEqual(a: string, b: string): boolean {\n const len = Math.max(a.length, b.length);\n let result = a.length ^ b.length; // non-zero if lengths differ\n for (let i = 0; i < len; i++) {\n result |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);\n }\n return result === 0;\n}\n","/**\n * Offline Schematron-like Validation\n *\n * Reimplements a subset of the Peppol BIS 3.0 business rules as pure TypeScript\n * checks. This is NOT a full XSD/XSLT schematron processor — it's a fast, offline\n * validator that catches the most commonly violated rules before the invoice\n * reaches the network.\n *\n * ⛔ The rules covered are exactly those in `SDK_SCHEMATRON_RULE_IDS` (below),\n * and that registry is the only place the count lives. This header said\n * \"~25\" while the registry held 18 — a number recited in prose drifts from the\n * one the code measures, and only the code can be right.\n * `ubl-validation/__tests__/sdk-non-contradiction.test.ts` pins the length, so\n * adding or removing a rule without updating the registry reds.\n *\n * Rules are grouped by category:\n * - BR-xx — Required field rules (EN 16931)\n * - BR-CO-xx — Calculation / cross-field consistency rules\n * - BR-S-xx — Tax category rules\n * - PEPPOL-xx — Peppol BIS 3.0 specific rules\n *\n * Design: each rule is a pure function (InvoiceInput) => SchematronViolation[].\n * No side effects, no XML, no network.\n */\n\nimport type { InvoiceInput, InvoiceLine } from \"../types/invoice.js\";\nimport { resolveUnit, getAllUnits } from \"./code-lists.js\";\n\n// ─── Types ──────────────────────────────────────────────────────────────────────\n\nexport interface SchematronViolation {\n /** Peppol business rule identifier (e.g., \"BR-02\", \"BR-S-05\") */\n ruleId: string;\n /** Severity: \"error\" blocks sending, \"warning\" is advisory */\n severity: \"error\" | \"warning\";\n /** Human-readable description of the violation */\n message: string;\n /** Relevant field path (e.g., \"lines[0].vatRate\") */\n field?: string;\n}\n\nexport interface SchematronResult {\n /**\n * ⚠️ « Aucun problème parmi les contrôles effectués » — PAS « conforme Peppol ».\n * Ce validateur couvre 18 règles sur les 333+ que le réseau applique.\n * Le verdict qui engage est rendu à l'envoi.\n */\n valid: boolean;\n /** Ce qui a réellement été vérifié — pour que l'appelant sache ce que `valid` couvre. */\n coverage: { rulesChecked: number; ofNetworkFatalRules: \"partial\" };\n /** Blocking violations — invoice would be rejected */\n errors: SchematronViolation[];\n /** Advisory notices — invoice may be accepted but is suboptimal */\n warnings: SchematronViolation[];\n}\n\n// ─── Rule function type ─────────────────────────────────────────────────────────\n\ntype RuleFn = (input: InvoiceInput) => SchematronViolation[];\n\n// ─── Helpers ────────────────────────────────────────────────────────────────────\n\nfunction violation(\n ruleId: string,\n severity: \"error\" | \"warning\",\n message: string,\n field?: string,\n): SchematronViolation {\n return { ruleId, severity, message, field };\n}\n\n/** Build a Set of all known UN/ECE Rec20 unit codes (lazy singleton). */\nlet _knownUnitCodes: Set<string> | undefined;\nfunction getKnownUnitCodes(): Set<string> {\n if (!_knownUnitCodes) {\n _knownUnitCodes = new Set(getAllUnits().map((u) => u.code));\n }\n return _knownUnitCodes;\n}\n\n/**\n * The ten VAT category codes EN 16931 allows, verbatim from `BR-CL-17`'s test:\n * `' AE L M E S Z G O K B '`.\n *\n * ⚠️ This set used to hold NINE — `B` (Italian split payment) was missing, so\n * the validator reported \"invalid\" for a code the network accepts. Being\n * stricter than the network is the worse of the two errors (GPR-904): a false\n * refusal closes a corridor, a malformed document costs one document.\n */\nexport const VALID_VAT_CATEGORIES: ReadonlySet<string> = new Set([\"S\", \"Z\", \"E\", \"AE\", \"K\", \"G\", \"O\", \"L\", \"M\", \"B\"]);\n\n/**\n * The categories the gateway can actually put on the wire.\n *\n * `L` (IGIC) and `M` (IPSI) were translated to `canary_islands` /\n * `ceuta_melilla` — values absent from every Storecove artefact — and `B` has no\n * provider equivalent at all (GPR-1012). They are valid EN 16931 codes that we\n * cannot route, which is a different finding from \"not a category\", and saying\n * so is the whole point: the previous message conflated the two.\n *\n * Drift-locked against the gateway's own table by\n * `console/src/lib/api/__tests__/vat-category-sdk-alignment.test.ts`.\n */\nexport const SENDABLE_VAT_CATEGORIES = [\"S\", \"Z\", \"E\", \"AE\", \"K\", \"G\", \"O\"] as const;\nconst UNROUTABLE_VAT_CATEGORIES = new Set([\"L\", \"M\", \"B\"]);\n\n/**\n * Compute the net amount for a single invoice line.\n * Formula: (quantity * unitPrice / baseQuantity) + charges - allowances\n */\nfunction computeLineNet(line: InvoiceLine): number {\n const baseQty = line.baseQuantity ?? 1;\n if (baseQty === 0) return NaN; // Will be caught by BR-CO-10\n const baseAmount = (line.quantity * line.unitPrice) / baseQty;\n const chargeTotal = (line.charges ?? []).reduce((sum, c) => sum + c.amount, 0);\n const allowanceTotal = (line.allowances ?? []).reduce((sum, a) => sum + a.amount, 0);\n return baseAmount + chargeTotal - allowanceTotal;\n}\n\n// ─── Required Field Rules (BR-01 to BR-10) ──────────────────────────────────────\n\n/**\n * BR-01: Invoice shall have a Specification identifier.\n * Auto-pass: the gateway always sets \"urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\".\n */\n// (no-op — always satisfied)\n\n/**\n * BR-02: An Invoice shall have an Invoice number.\n */\nconst br02: RuleFn = (input) => {\n if (!input.number?.trim()) {\n return [violation(\"BR-02\", \"error\", \"Invoice number is required.\", \"number\")];\n }\n return [];\n};\n\n/**\n * BR-03: An Invoice shall have an Invoice issue date.\n * The SDK defaults to today if omitted, so this is a warning.\n */\nconst br03: RuleFn = (input) => {\n if (!input.date) {\n return [\n violation(\n \"BR-03\",\n \"warning\",\n \"Invoice issue date is not set. The SDK will default to today's date.\",\n \"date\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * BR-04: An Invoice shall have an Invoice currency code.\n * Auto-pass: defaults to EUR.\n */\n// (no-op)\n\n/**\n * BR-05: An Invoice shall have an Invoice type code.\n * Auto-pass: always set (380 for invoice, 381 for credit note).\n */\n// (no-op)\n\n/**\n * BR-06: An Invoice shall have the Seller VAT identifier or tax registration.\n * The `from` field is deprecated — seller is determined by API key.\n * Only warn if `from` IS provided but has no vatNumber.\n */\nconst br06: RuleFn = (input) => {\n if (input.from && !input.from.vatNumber) {\n return [\n violation(\n \"BR-06\",\n \"warning\",\n \"Seller party has no VAT number. The gateway will use the account's VAT registration.\",\n \"from.vatNumber\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * BR-07: An Invoice shall have the Buyer name.\n */\nconst br07: RuleFn = (input) => {\n if (!input.to?.name?.trim()) {\n return [violation(\"BR-07\", \"error\", \"Buyer name is required.\", \"to.name\")];\n }\n return [];\n};\n\n/**\n * BR-08: An Invoice shall have at least one Invoice line.\n */\nconst br08: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) {\n return [violation(\"BR-08\", \"error\", \"Invoice must have at least one line item.\", \"lines\")];\n }\n return [];\n};\n\n/**\n * BR-09: An Invoice shall have the Payment due date or Payment terms.\n */\nconst br09: RuleFn = (input) => {\n if (!input.dueDate && !input.paymentTerms) {\n return [\n violation(\n \"BR-09\",\n \"warning\",\n \"Neither due date nor payment terms specified. At least one is recommended.\",\n \"dueDate\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * BR-10: An Invoice shall have the Buyer reference or Order reference.\n */\nconst br10: RuleFn = (input) => {\n if (!input.buyerReference && !input.orderReference) {\n return [\n violation(\n \"BR-10\",\n \"warning\",\n \"Neither buyerReference nor orderReference specified. Peppol BIS 3.0 requires at least one.\",\n \"buyerReference\",\n ),\n ];\n }\n return [];\n};\n\n// ─── Calculation Rules (BR-CO) ──────────────────────────────────────────────────\n\n/**\n * BR-CO-10: Sum of Invoice line net amounts = sum of (quantity x unit price / base quantity)\n * adjusted by line allowances/charges.\n *\n * Since InvoiceInput has no explicit totals, we verify each line's computation is valid\n * (no NaN, no Infinity, handles baseQuantity correctly).\n */\nconst brCo10: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n const net = computeLineNet(line);\n\n if (!Number.isFinite(net)) {\n const baseQty = line.baseQuantity ?? 1;\n const detail =\n baseQty === 0\n ? \"baseQuantity is 0, causing division by zero.\"\n : \"Computed line amount is not a finite number.\";\n violations.push(\n violation(\"BR-CO-10\", \"error\", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-CO-13: Invoice total VAT amount = sum of (line net amount x VAT rate / 100) per category.\n *\n * We verify the VAT computation is valid and consistent. Since InvoiceInput has no explicit\n * VAT total field, we check that the computed amount is finite and non-negative.\n */\nconst brCo13: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) return [];\n\n let totalVat = 0;\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n const net = computeLineNet(line);\n if (!Number.isFinite(net)) continue; // Already caught by BR-CO-10\n totalVat += net * (line.vatRate / 100);\n }\n\n // Include document-level allowances/charges in VAT\n for (const allowance of input.allowances ?? []) {\n totalVat -= allowance.amount * (allowance.vatRate / 100);\n }\n for (const charge of input.charges ?? []) {\n totalVat += charge.amount * (charge.vatRate / 100);\n }\n\n if (!Number.isFinite(totalVat)) {\n return [\n violation(\n \"BR-CO-13\",\n \"error\",\n \"Computed total VAT amount is not a finite number. Check line amounts and VAT rates.\",\n ),\n ];\n }\n\n if (totalVat < -0.01) {\n return [\n violation(\n \"BR-CO-13\",\n \"warning\",\n `Computed total VAT is negative (${totalVat.toFixed(2)}). This is unusual for an invoice.`,\n ),\n ];\n }\n\n return [];\n};\n\n/**\n * BR-CO-15: Invoice tax inclusive amount = Invoice total amount without VAT + Invoice total VAT amount.\n *\n * We verify the computation produces a finite, non-negative result.\n */\nconst brCo15: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) return [];\n\n let lineTotal = 0;\n let vatTotal = 0;\n\n for (const line of input.lines) {\n const net = computeLineNet(line);\n if (!Number.isFinite(net)) continue;\n lineTotal += net;\n vatTotal += net * (line.vatRate / 100);\n }\n\n // Document-level allowances/charges\n for (const allowance of input.allowances ?? []) {\n lineTotal -= allowance.amount;\n vatTotal -= allowance.amount * (allowance.vatRate / 100);\n }\n for (const charge of input.charges ?? []) {\n lineTotal += charge.amount;\n vatTotal += charge.amount * (charge.vatRate / 100);\n }\n\n const taxInclusive = lineTotal + vatTotal;\n\n if (!Number.isFinite(taxInclusive)) {\n return [\n violation(\n \"BR-CO-15\",\n \"error\",\n \"Computed tax-inclusive amount is not a finite number.\",\n ),\n ];\n }\n\n if (taxInclusive < -0.01) {\n return [\n violation(\n \"BR-CO-15\",\n \"warning\",\n `Computed tax-inclusive amount is negative (${taxInclusive.toFixed(2)}). Consider using a credit note instead.`,\n ),\n ];\n }\n\n return [];\n};\n\n/**\n * BR-CO-16: Amount due for payment = Invoice total amount with VAT - Paid amount + Rounding amount.\n *\n * Verifies payable amount is non-negative when prepaidAmount is used.\n */\nconst brCo16: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) return [];\n\n let lineTotal = 0;\n let vatTotal = 0;\n\n for (const line of input.lines) {\n const net = computeLineNet(line);\n if (!Number.isFinite(net)) continue;\n lineTotal += net;\n vatTotal += net * (line.vatRate / 100);\n }\n\n // Document-level allowances/charges\n for (const allowance of input.allowances ?? []) {\n lineTotal -= allowance.amount;\n vatTotal -= allowance.amount * (allowance.vatRate / 100);\n }\n for (const charge of input.charges ?? []) {\n lineTotal += charge.amount;\n vatTotal += charge.amount * (charge.vatRate / 100);\n }\n\n const taxInclusive = lineTotal + vatTotal;\n const prepaid = input.prepaidAmount ?? 0;\n const rounding = input.roundingAmount ?? 0;\n const payable = taxInclusive - prepaid + rounding;\n\n if (!Number.isFinite(payable)) {\n return [\n violation(\n \"BR-CO-16\",\n \"error\",\n \"Computed payable amount is not a finite number.\",\n ),\n ];\n }\n\n if (payable < -0.01) {\n return [\n violation(\n \"BR-CO-16\",\n \"warning\",\n `Computed payable amount is negative (${payable.toFixed(2)}). Prepaid amount (${prepaid}) exceeds the invoice total.`,\n ),\n ];\n }\n\n return [];\n};\n\n// ─── Tax Category Rules (one family PER category) ───────────────────────────────\n\n/**\n * BR-S-05: In an Invoice line where the Invoiced item VAT category code is \"Standard rated\" (S),\n * the Invoiced item VAT rate shall be greater than zero.\n *\n * ⚠️ Cited `BR-S-01` until GPR-1069. `BR-S-01` is a real rule, which is exactly why\n * the mistake survived: it governs the VAT BREAKDOWN, not the line rate. Verbatim,\n * `CEN-EN16931-UBL.sch:344` (release v3.0.20).\n */\nconst brS05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n const category = line.vatCategory ?? \"S\"; // Default is standard rate\n if (category === \"S\" && (line.vatRate === undefined || line.vatRate <= 0)) {\n violations.push(\n violation(\n \"BR-S-05\",\n \"error\",\n `Line ${i}: standard rate (S) requires vatRate > 0, got ${line.vatRate ?? \"undefined\"}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-Z-05: In an Invoice line where the Invoiced item VAT category code is \"Zero rated\" (Z),\n * the Invoiced item VAT rate shall be 0 (zero).\n *\n * ⚠️ Cited `BR-S-05` until GPR-1069 — the `S` family, not the `Z` one.\n * Verbatim, `CEN-EN16931-UBL.sch:358` (release v3.0.20).\n */\nconst brZ05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.vatCategory === \"Z\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-Z-05\",\n \"error\",\n `Line ${i}: zero-rated (Z) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-E-05: In an Invoice line where the Invoiced item VAT category code is \"Exempt from VAT\" (E),\n * the Invoiced item VAT rate shall be 0 (zero).\n *\n * ⚠️ Cited `BR-S-06` until GPR-1069 — the `S` family, not the `E` one.\n * Verbatim, `CEN-EN16931-UBL.sch:260` (release v3.0.20).\n */\nconst brE05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.vatCategory === \"E\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-E-05\",\n \"error\",\n `Line ${i}: exempt (E) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-AE-05: In an Invoice line where the Invoiced item VAT category code is \"Reverse charge\" (AE),\n * the Invoiced item VAT rate shall be 0 (zero).\n *\n * ⚠️ Cited `BR-S-08` until GPR-1069 — the `S` family, not the `AE` one.\n * Verbatim, `CEN-EN16931-UBL.sch:246` (release v3.0.20).\n */\nconst brAe05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.vatCategory === \"AE\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-AE-05\",\n \"error\",\n `Line ${i}: reverse charge (AE) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n// ─── Peppol-Specific Rules ──────────────────────────────────────────────────────\n\n/**\n * PEPPOL-EN16931-R001: Business process MUST be provided.\n * Auto-pass: the gateway always sets \"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\".\n */\n// (no-op)\n\n/**\n * PEPPOL-EN16931-R004: A Buyer electronic address SHALL exist.\n */\nconst peppolR004: RuleFn = (input) => {\n if (!input.to?.peppolId) {\n return [\n violation(\n \"PEPPOL-EN16931-R004\",\n \"error\",\n \"Buyer electronic address (peppolId) is required for Peppol delivery.\",\n \"to.peppolId\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * VAT category codes, checked on lines and on document-level allowances and\n * charges alike.\n *\n * Two DISTINCT findings, because they are two different problems (GPR-1012):\n * - `BR-CL-17` — not a VAT category code at all. This is the real rule id;\n * the previous code cited `PEPPOL-EN16931-R006`, which does NOT exist in\n * rulebook v3.0.20 (that family stops at R005, R007, R008).\n * - `unsupported_vat_category` — a valid EN 16931 code the gateway cannot put\n * on the wire. No Peppol rule to cite: it is a provider-capability limit,\n * and calling it \"invalid\" was simply false.\n *\n * Codes are CASE-SENSITIVE, and saying so is load-bearing: `\"ae\"` used to be\n * coerced to standard rate by the gateway, shipping a valid invoice that never\n * shifted the VAT liability to the buyer.\n */\nconst vatCategoryCodes: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n const sendable = SENDABLE_VAT_CATEGORIES.join(\", \");\n\n /**\n * A VAT category is at most two characters, so a longer value is already\n * wrong and quoting it whole gains nothing. Unbounded, a 100 kB category\n * produced a 100 kB message that `validate/server` returned verbatim.\n */\n const echo = (v: string): string => (v.length <= 16 ? v : `${v.slice(0, 16)}…`);\n\n const check = (cat: string | undefined, field: string, label: string): void => {\n // `null` counts as ABSENT, exactly like `undefined` — the gateway's\n // `isSupplied` says so, and a validator that disagrees with the endpoint it\n // advises is worse than no validator. JSON serialisers emit `null` for an\n // unset field routinely, and the previous code reported\n // `\"null\" is not a VAT category code` for a payload that sends fine.\n if (cat === undefined || cat === null) return;\n\n if (!VALID_VAT_CATEGORIES.has(cat)) {\n violations.push(\n violation(\n \"BR-CL-17\",\n \"error\",\n `${label}: \"${echo(cat)}\" is not a VAT category code. Use one of: ${sendable}. ` +\n `Codes are case-sensitive — \"AE\" is reverse charge, \"ae\" is not a category.`,\n field,\n ),\n );\n return;\n }\n\n if (UNROUTABLE_VAT_CATEGORIES.has(cat)) {\n violations.push(\n violation(\n \"unsupported_vat_category\",\n \"error\",\n `${label}: VAT category \"${echo(cat)}\" is valid under EN 16931 but getpeppr cannot route it — ` +\n `our provider has no vocabulary for it. Sendable categories: ${sendable}.`,\n field,\n ),\n );\n }\n };\n\n (input.lines ?? []).forEach((line, i) =>\n check(line.vatCategory, `lines[${i}].vatCategory`, `Line ${i}`),\n );\n (input.allowances ?? []).forEach((a, i) =>\n check(a.vatCategory, `allowances[${i}].vatCategory`, `Allowance ${i}`),\n );\n (input.charges ?? []).forEach((c, i) =>\n check(c.vatCategory, `charges[${i}].vatCategory`, `Charge ${i}`),\n );\n\n return violations;\n};\n\n/**\n * PEPPOL-EN16931-R080: Unit of measure MUST be coded using UN/ECE Recommendation 20.\n * Warning-level since unknown codes pass through to the gateway which may accept them.\n */\nconst peppolR080: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n const knownCodes = getKnownUnitCodes();\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.unit) {\n const resolved = resolveUnit(line.unit);\n if (!knownCodes.has(resolved)) {\n violations.push(\n violation(\n \"PEPPOL-EN16931-R080\",\n \"warning\",\n `Line ${i}: unit \"${line.unit}\" (resolved: \"${resolved}\") is not a known UN/ECE Rec20 code. Common codes: EA, HUR, DAY, KGM.`,\n `lines[${i}].unit`,\n ),\n );\n }\n }\n // No unit specified → defaults to \"EA\" which is valid → no violation\n }\n\n return violations;\n};\n\n// ─── Rule Registry ──────────────────────────────────────────────────────────────\n\n/** All active rules in evaluation order. */\nconst ALL_RULES: readonly RuleFn[] = [\n // Required fields (BR)\n br02,\n br03,\n br06,\n br07,\n br08,\n br09,\n br10,\n // Calculations (BR-CO)\n brCo10,\n brCo13,\n brCo15,\n brCo16,\n // Tax categories (one family per category)\n brS05,\n brZ05,\n brE05,\n brAe05,\n // Peppol-specific\n peppolR004,\n vatCategoryCodes,\n peppolR080,\n];\n\n// ─── Main Validation Function ───────────────────────────────────────────────────\n\n/**\n * Validate an InvoiceInput against Peppol BIS 3.0 business rules (offline).\n *\n * Runs the rules listed in `SDK_SCHEMATRON_RULE_IDS` — a subset of the most\n * commonly violated ones — as pure TypeScript checks. No XML generation, no\n * network calls: instant feedback. The count is read from the registry, never\n * written here; `result.coverage.rulesChecked` reports it at runtime.\n *\n * ⚠️ A pass means \"nothing wrong among the checks performed\", NOT \"Peppol\n * conformant\" — the verdict that commits is the one returned at send time.\n *\n * @param input - The invoice to validate\n * @returns Validation result with errors (blocking) and warnings (advisory)\n *\n * @example\n * ```ts\n * const result = validateSchematron({\n * number: \"INV-001\",\n * to: { name: \"Acme\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * lines: [{ description: \"Widget\", quantity: 1, unitPrice: 100, vatRate: 21 }],\n * });\n *\n * if (!result.valid) {\n * console.error(\"Validation failed:\", result.errors);\n * }\n * ```\n */\nexport function validateSchematron(input: InvoiceInput): SchematronResult {\n const errors: SchematronViolation[] = [];\n const warnings: SchematronViolation[] = [];\n\n for (const rule of ALL_RULES) {\n const violations = rule(input);\n for (const v of violations) {\n if (v.severity === \"error\") {\n errors.push(v);\n } else {\n warnings.push(v);\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n coverage: { rulesChecked: SDK_SCHEMATRON_RULE_IDS.length, ofNetworkFatalRules: \"partial\" },\n errors,\n warnings,\n };\n}\n\n/**\n * GPR-1069 — les règles que CE validateur couvre réellement.\n *\n * ⚠️ 18 sur les 333+ que le réseau applique. Ce module est un PRÉ-CONTRÔLE local :\n * il attrape les erreurs les plus fréquentes sans appel réseau. Le verdict qui\n * engage est celui rendu à l'envoi.\n *\n * ⛔ Ces identifiants sont ceux que CE FICHIER émet (`violation(\"BR-xx\", ...)`).\n * Les QUATRE règles de catégorie de TVA ont été confrontées une par une au\n * rulebook gravé et corrigées (GPR-1069) : elles citaient toutes la famille\n * `BR-S-`, celle de la catégorie « standard », pour des règles gouvernant `Z`,\n * `E` et `AE`. ⚠️ **Les quatorze autres n'ont PAS été auditées de la même\n * façon**, et au moins `BR-06`, `BR-08`, `BR-09`, `BR-10`, `BR-CO-13`,\n * `PEPPOL-EN16931-R004` et `PEPPOL-EN16931-R080` désignent officiellement une\n * règle DIFFÉRENTE de celle qu'ils vérifient ici — écart relevé par lecture du\n * `.sch`, non tranché (GPR-897 §5.5, GPR-1069).\n *\n * ⭐ Un identifiant faux ne se voit pas à l'existence : les quatre corrigés\n * existaient tous dans le rulebook. Seule la comparaison des COMPORTEMENTS les\n * a trouvés — `ubl-validation/__tests__/sdk-non-contradiction.test.ts`, côté\n * console, qui fait tourner ce module et le moteur officiel sur le même\n * document et rougit si leurs verdicts s'opposent.\n */\nexport const SDK_SCHEMATRON_RULE_IDS = [\n \"BR-02\", \"BR-03\", \"BR-06\", \"BR-07\", \"BR-08\", \"BR-09\", \"BR-10\",\n \"BR-CL-17\", \"BR-CO-10\", \"BR-CO-13\", \"BR-CO-15\", \"BR-CO-16\",\n \"BR-S-05\", \"BR-Z-05\", \"BR-E-05\", \"BR-AE-05\",\n \"PEPPOL-EN16931-R004\", \"PEPPOL-EN16931-R080\",\n] as const;\n","import type { Command } from \"commander\";\nimport { readAndValidateInvoiceJson } from \"../utils/file.js\";\nimport { formatValidationResult } from \"../formatters/validation.js\";\nimport {\n validateInvoice,\n validateSchematron,\n validateCountryRules,\n type InvoiceInput,\n type ValidationError,\n type ValidationWarning,\n type SchematronViolation,\n} from \"@getpeppr/sdk\";\n\nexport interface MergedValidationResult {\n structure: {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n };\n schematron: {\n errors: SchematronViolation[];\n warnings: SchematronViolation[];\n };\n countryRules: {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n };\n totalErrors: number;\n totalWarnings: number;\n valid: boolean;\n}\n\nexport function runValidation(input: InvoiceInput): MergedValidationResult {\n const structure = validateInvoice(input);\n const schematron = validateSchematron(input);\n const countryRules = validateCountryRules(input);\n\n const totalErrors =\n structure.errors.length +\n schematron.errors.length +\n countryRules.errors.length;\n\n const totalWarnings =\n structure.warnings.length +\n schematron.warnings.length +\n countryRules.warnings.length;\n\n return {\n structure: { errors: structure.errors, warnings: structure.warnings },\n schematron: { errors: schematron.errors, warnings: schematron.warnings },\n countryRules: {\n errors: countryRules.errors,\n warnings: countryRules.warnings,\n },\n totalErrors,\n totalWarnings,\n valid: totalErrors === 0,\n };\n}\n\nexport function registerValidateCommand(program: Command): void {\n program\n .command(\"validate\")\n .description(\"Validate a Peppol invoice JSON file\")\n .argument(\"<file>\", \"path to invoice JSON file\")\n .option(\"--json\", \"output results as JSON\")\n .option(\"--quiet\", \"exit code only, no output\")\n .action(async (file: string, options: { json?: boolean; quiet?: boolean }) => {\n // 1. Read and parse the JSON file\n // Fatal errors always go to stderr regardless of --quiet (UNIX convention)\n const input = readAndValidateInvoiceJson(file);\n\n // 2. Run all 3 validators\n const result = runValidation(input);\n\n // 3. Output\n if (options.quiet) {\n process.exit(result.valid ? 0 : 1);\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n process.exit(result.valid ? 0 : 1);\n }\n\n // 4. Formatted output\n const output = formatValidationResult(file, result);\n console.log(output);\n process.exit(result.valid ? 0 : 1);\n });\n}\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport { INVOICE_TEMPLATE } from \"../templates/invoice.js\";\nimport { CREDIT_NOTE_TEMPLATE } from \"../templates/credit-note.js\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Scaffold a starter invoice JSON file\")\n .argument(\"[filename]\", \"output filename\", \"invoice.json\")\n .option(\"--credit-note\", \"generate a credit note template instead\")\n .option(\"--force\", \"overwrite existing file\")\n .action(\n (\n filename: string,\n options: { creditNote?: boolean; force?: boolean },\n ) => {\n const resolved = resolve(filename);\n\n if (existsSync(resolved) && !options.force) {\n exitWithError(\n `Error: ${filename} already exists. Use --force to overwrite.`,\n );\n }\n\n const template = options.creditNote\n ? CREDIT_NOTE_TEMPLATE\n : INVOICE_TEMPLATE;\n\n try {\n writeFileSync(\n resolved,\n JSON.stringify(template, null, 2) + \"\\n\",\n \"utf-8\",\n );\n } catch {\n exitWithError(`Error: could not write file — ${resolved}`);\n }\n\n process.stderr.write(`${pc.green(\"\\u2713\")} Created ${filename}\n\n Next steps:\n 1. Edit the file with your invoice data\n 2. Validate: getpeppr validate ${filename}\n 3. Convert to XML: getpeppr convert ${filename}\n 4. Send: getpeppr send ${filename}\n\n ${pc.dim(\"Sandbox note:\")} this template includes VAT. To send it on a sandbox\n account, first register your VAT on the Peppol identity page, or set each\n line's \"vatCategory\" to \"O\" (outside the scope of VAT) for a no-VAT test send.\\n`);\n\n process.exit(0);\n },\n );\n}\n","import type { InvoiceInput } from \"@getpeppr/sdk\";\n\nexport const INVOICE_TEMPLATE: InvoiceInput = {\n number: \"INV-2026-001\",\n date: \"2026-01-15\",\n dueDate: \"2026-02-15\",\n currency: \"EUR\",\n buyerReference: \"PO-2026-042\",\n from: {\n name: \"Dupont & Fils SPRL\",\n peppolId: \"0208:0685660237\",\n street: \"Avenue Louise 54\",\n city: \"Bruxelles\",\n postalCode: \"1050\",\n country: \"BE\",\n },\n // Sandbox test receiver (GPR-828): the only recipient guaranteed reachable on\n // the Storecove test network -- real directory companies make sandbox sends fail.\n to: {\n name: \"SPF Economie (test receiver)\",\n peppolId: \"9925:BE0314595348\",\n street: \"Rue du Progr\\u00e8s 50\",\n city: \"Brussels\",\n postalCode: \"1210\",\n country: \"BE\",\n },\n lines: [\n {\n description: \"Conseil en transformation num\\u00e9rique\",\n quantity: 10,\n unitPrice: 950,\n vatRate: 21,\n },\n {\n description: \"Software license \\u2014 annual subscription\",\n quantity: 1,\n unitPrice: 2400,\n vatRate: 0,\n vatCategory: \"AE\",\n },\n ],\n paymentTerms: \"Net 30 days\",\n paymentReference: \"+++000/0000/00097+++\",\n};\n","import type { InvoiceInput } from \"@getpeppr/sdk\";\n\nexport const CREDIT_NOTE_TEMPLATE: InvoiceInput = {\n number: \"CN-2026-001\",\n date: \"2026-02-01\",\n currency: \"EUR\",\n isCreditNote: true,\n invoiceReference: \"INV-2026-001\",\n from: {\n name: \"Dupont & Fils SPRL\",\n peppolId: \"0208:0685660237\",\n street: \"Avenue Louise 54\",\n city: \"Bruxelles\",\n postalCode: \"1050\",\n country: \"BE\",\n },\n // Sandbox test receiver (GPR-828) \\u2014 keep in sync with templates/invoice.ts.\n to: {\n name: \"SPF Economie (test receiver)\",\n peppolId: \"9925:BE0314595348\",\n street: \"Rue du Progr\\u00e8s 50\",\n city: \"Brussels\",\n postalCode: \"1210\",\n country: \"BE\",\n },\n lines: [\n {\n description: \"Avoir partiel \\u2014 Conseil en transformation num\\u00e9rique\",\n quantity: 2,\n unitPrice: 950,\n vatRate: 21,\n },\n ],\n note: \"Avoir pour prestations non r\\u00e9alis\\u00e9es \\u2014 r\\u00e9f. INV-2026-001\",\n};\n","import { writeFileSync } from \"node:fs\";\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { readAndValidateInvoiceJson } from \"../utils/file.js\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport { runValidation } from \"./validate.js\";\nimport { formatValidationResult } from \"../formatters/validation.js\";\nimport {\n buildInvoiceXml,\n buildCreditNoteXml,\n type InvoiceInput,\n type CreditNoteInput,\n} from \"@getpeppr/sdk\";\n\nexport function registerConvertCommand(program: Command): void {\n program\n .command(\"convert\")\n .description(\n \"Convert a getpeppr JSON invoice to Peppol BIS 3.0 UBL XML\",\n )\n .argument(\"<file>\", \"path to invoice JSON file\")\n .option(\"-o, --output <file>\", \"write XML to file instead of stdout\")\n .option(\"--validate\", \"validate the invoice before converting\")\n .action(\n async (\n file: string,\n options: { output?: string; validate?: boolean },\n ) => {\n // 1. Read and parse the JSON file\n const input = readAndValidateInvoiceJson(file);\n\n // 2. If --validate, run validation first\n if (options.validate) {\n const result = runValidation(input);\n const formatted = formatValidationResult(file, result);\n\n if (!result.valid) {\n // Errors: show on stderr, exit 1, NO XML\n process.stderr.write(formatted + \"\\n\");\n process.exit(1);\n }\n\n if (result.totalWarnings > 0) {\n // Warnings only: show on stderr, continue to conversion\n process.stderr.write(formatted + \"\\n\");\n }\n }\n\n // 3. Detect document type\n const isCreditNote = input.isCreditNote === true;\n\n // 4. Generate XML\n let xml: string;\n try {\n if (isCreditNote) {\n xml = buildCreditNoteXml(input as CreditNoteInput);\n } else {\n xml = buildInvoiceXml(input);\n }\n } catch (err: unknown) {\n const message =\n err instanceof Error ? err.message : \"Unknown error\";\n exitWithError(`Error: XML generation failed — ${message}`);\n }\n\n // 5. Clean empty lines from XML\n xml = xml.replace(/^[ \\t]*\\n/gm, \"\");\n\n // 6. Output\n const docType = isCreditNote\n ? \"UBL 2.1 CreditNote\"\n : \"UBL 2.1 Invoice\";\n\n if (options.output) {\n writeFileSync(options.output, xml, \"utf-8\");\n process.stderr.write(\n `${pc.green(\"✓\")} Converted to ${options.output} (${docType})\\n`,\n );\n } else {\n process.stdout.write(xml + \"\\n\");\n }\n },\n );\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport {\n lookupParticipant,\n searchParticipants,\n DirectoryError,\n type DirectoryMatch,\n type SearchResult,\n} from \"../lib/peppol-directory.js\";\n\n// ─── Country name helper ──────────────────────────\n\nconst COUNTRY_NAMES: Record<string, string> = {\n AT: \"Austria\",\n BE: \"Belgium\",\n BG: \"Bulgaria\",\n HR: \"Croatia\",\n CY: \"Cyprus\",\n CZ: \"Czechia\",\n DK: \"Denmark\",\n EE: \"Estonia\",\n FI: \"Finland\",\n FR: \"France\",\n DE: \"Germany\",\n GR: \"Greece\",\n HU: \"Hungary\",\n IS: \"Iceland\",\n IE: \"Ireland\",\n IT: \"Italy\",\n LV: \"Latvia\",\n LT: \"Lithuania\",\n LU: \"Luxembourg\",\n MT: \"Malta\",\n NL: \"Netherlands\",\n NO: \"Norway\",\n PL: \"Poland\",\n PT: \"Portugal\",\n RO: \"Romania\",\n SK: \"Slovakia\",\n SI: \"Slovenia\",\n ES: \"Spain\",\n SE: \"Sweden\",\n CH: \"Switzerland\",\n GB: \"United Kingdom\",\n US: \"United States\",\n AU: \"Australia\",\n CA: \"Canada\",\n SG: \"Singapore\",\n JP: \"Japan\",\n NZ: \"New Zealand\",\n};\n\nfunction countryLabel(code: string): string {\n const name = COUNTRY_NAMES[code.toUpperCase()];\n return name ? `${name} (${code})` : code;\n}\n\n// ─── Output formatting ───────────────────────────\n\nfunction formatLookupResult(match: DirectoryMatch): string {\n const lines: string[] = [];\n lines.push(`${pc.green(\"\\u2713\")} ${match.name}`);\n lines.push(` ${pc.dim(\"Peppol ID\")} ${match.peppolId}`);\n lines.push(` ${pc.dim(\"Country\")} ${countryLabel(match.country)}`);\n if (match.registrationDate) {\n lines.push(` ${pc.dim(\"Registered\")} ${match.registrationDate}`);\n }\n if (match.vatNumber) {\n lines.push(` ${pc.dim(\"VAT\")} ${match.vatNumber}`);\n }\n if (match.capabilities.length > 0) {\n lines.push(\n ` ${pc.dim(\"Capabilities\")} ${match.capabilities.join(\", \")}`,\n );\n }\n if (match.contactEmail) {\n lines.push(` ${pc.dim(\"Contact\")} ${match.contactEmail}`);\n }\n if (match.website) {\n lines.push(` ${pc.dim(\"Website\")} ${match.website}`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction formatSearchResults(result: SearchResult): string {\n const lines: string[] = [];\n const plural = result.totalCount === 1 ? \"participant\" : \"participants\";\n lines.push(`Found ${result.totalCount} ${plural}:\\n`);\n\n // Column headers\n const nameW = 26;\n const idW = 23;\n const countryW = 9;\n\n lines.push(\n ` ${\"Name\".padEnd(nameW)}${\"Peppol ID\".padEnd(idW)}${\"Country\".padEnd(countryW)}Capabilities`,\n );\n lines.push(` ${\"─\".repeat(nameW + idW + countryW + 20)}`);\n\n for (const m of result.matches) {\n const name = m.name.length > nameW - 1 ? m.name.slice(0, nameW - 2) + \"…\" : m.name;\n const caps = m.capabilities.join(\", \");\n lines.push(\n ` ${name.padEnd(nameW)}${m.peppolId.padEnd(idW)}${m.country.padEnd(countryW)}${caps}`,\n );\n }\n\n if (result.hasMore) {\n lines.push(\n `\\n ${pc.dim(`Showing ${result.matches.length} of ${result.totalCount} results.`)}`,\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n// ─── Input validation ─────────────────────────────\n\nfunction validatePeppolId(raw: string): {\n ok: true;\n scheme: string;\n id: string;\n} | { ok: false; error: string } {\n const colonIndex = raw.indexOf(\":\");\n if (colonIndex === -1) {\n return {\n ok: false,\n error: `Invalid Peppol ID format: \"${raw}\". Expected format: scheme:id (e.g. 0208:0685660237)`,\n };\n }\n\n const scheme = raw.slice(0, colonIndex);\n const id = raw.slice(colonIndex + 1);\n\n if (!/^\\d{4}$/.test(scheme)) {\n return {\n ok: false,\n error: `Invalid scheme \"${scheme}\". Must be exactly 4 digits (e.g. 0208).`,\n };\n }\n\n if (!/^[A-Za-z0-9:.\\-]+$/.test(id)) {\n return {\n ok: false,\n error: `Invalid participant ID \"${id}\". Only letters, digits, colons, dots and hyphens are allowed.`,\n };\n }\n\n return { ok: true, scheme, id };\n}\n\n// ─── Command registration ─────────────────────────\n\nexport function registerLookupCommand(program: Command): void {\n program\n .command(\"lookup\")\n .description(\"Look up a participant in the Peppol Directory\")\n .argument(\"[peppolId]\", \"Peppol participant ID (format: scheme:id)\")\n .option(\"--name <name>\", \"search by company name (min 3 chars)\")\n .option(\"--country <code>\", \"filter by ISO 2-letter country code\")\n .option(\"--json\", \"output results as JSON\")\n .option(\"--limit <n>\", \"max results (default 10)\", \"10\")\n .action(\n async (\n peppolId: string | undefined,\n options: {\n name?: string;\n country?: string;\n json?: boolean;\n limit?: string;\n },\n ) => {\n const isSearch = Boolean(options.name);\n const isLookup = Boolean(peppolId);\n\n // Must have at least one criterion\n if (!isSearch && !isLookup) {\n exitWithError(\"Provide a Peppol ID or use --name to search.\");\n }\n\n // Validate --country format\n if (options.country) {\n const normalized = options.country.toUpperCase();\n if (!/^[A-Z]{2}$/.test(normalized)) {\n exitWithError(\n `Invalid country code \"${options.country}\". Must be 2 letters (e.g. BE, DE, FR).`,\n );\n }\n options.country = normalized;\n }\n\n if (isLookup) {\n await handleLookup(peppolId!, options);\n } else {\n await handleSearch(options);\n }\n },\n );\n}\n\n// ─── Lookup handler ───────────────────────────────\n\nasync function handleLookup(\n peppolId: string,\n options: { json?: boolean },\n): Promise<void> {\n const parsed = validatePeppolId(peppolId);\n if (!parsed.ok) {\n exitWithError(parsed.error);\n }\n\n let result: DirectoryMatch | null;\n\n try {\n result = await lookupParticipant(parsed.scheme, parsed.id);\n } catch (err) {\n if (err instanceof DirectoryError) {\n exitWithError(\n `${pc.red(\"\\u2717\")} Peppol Directory returned an error (HTTP ${err.status ?? \"unknown\"}). Try again later.`,\n );\n }\n exitWithError(\n `${pc.red(\"\\u2717\")} Could not reach Peppol Directory. Check your internet connection.`,\n );\n }\n\n if (!result) {\n if (options.json) {\n console.log(JSON.stringify(null));\n } else {\n process.stderr.write(\n `${pc.red(\"\\u2717\")} Participant not found: ${peppolId}\\n`,\n );\n }\n process.exit(1);\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(formatLookupResult(result));\n }\n process.exit(0);\n}\n\n// ─── Search handler ───────────────────────────────\n\nasync function handleSearch(options: {\n name?: string;\n country?: string;\n json?: boolean;\n limit?: string;\n}): Promise<void> {\n if (options.name && options.name.length < 3) {\n exitWithError(\n `Search name must be at least 3 characters. Got: \"${options.name}\"`,\n );\n }\n\n const limit = parseInt(options.limit ?? \"10\", 10);\n\n let result: SearchResult;\n\n try {\n result = await searchParticipants({\n name: options.name,\n country: options.country,\n limit,\n });\n } catch (err) {\n if (err instanceof DirectoryError) {\n exitWithError(\n `${pc.red(\"\\u2717\")} Peppol Directory returned an error (HTTP ${err.status ?? \"unknown\"}). Try again later.`,\n );\n }\n exitWithError(\n `${pc.red(\"\\u2717\")} Could not reach Peppol Directory. Check your internet connection.`,\n );\n }\n\n if (result.matches.length === 0) {\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n process.stderr.write(\"No participants found.\\n\");\n }\n process.exit(1);\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(formatSearchResults(result));\n }\n process.exit(0);\n}\n","const BASE_URL = \"https://directory.peppol.eu/search/1.0/json\";\n\n// ─── Errors ───────────────────────────────────────\n\nexport class DirectoryError extends Error {\n readonly status?: number;\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"DirectoryError\";\n this.status = status;\n }\n}\n\n// ─── Public types ─────────────────────────────────\n\nexport interface DirectoryMatch {\n name: string;\n peppolId: string;\n country: string;\n capabilities: string[];\n registrationDate?: string;\n vatNumber?: string;\n contactEmail?: string;\n website?: string;\n}\n\nexport interface SearchResult {\n matches: DirectoryMatch[];\n totalCount: number;\n hasMore: boolean;\n}\n\n// ─── Response types (Peppol Directory JSON) ───────\n\ninterface DirectoryParticipantID {\n scheme: string;\n value: string;\n}\n\ninterface DirectoryDocType {\n scheme: string;\n value: string;\n}\n\ninterface DirectoryEntity {\n name: Array<{ name: string; language?: string }>;\n countryCode: string;\n geoInfo?: string;\n identifiers?: Array<{ scheme: string; value: string }>;\n websites?: string[];\n contacts?: Array<{ type: string; name?: string; email?: string }>;\n additionalInfo?: string;\n regDate?: string;\n}\n\ninterface DirectoryMatchRaw {\n participantID: DirectoryParticipantID;\n docTypes?: DirectoryDocType[];\n entities: DirectoryEntity[];\n}\n\ninterface DirectoryResponse {\n \"total-result-count\": number;\n \"result-page-index\": number;\n \"result-page-count\": number;\n matches: DirectoryMatchRaw[];\n}\n\n// ─── Parsing helpers ──────────────────────────────\n\nexport function stripQuotes(name: string): string {\n if (name.startsWith('\"') && name.endsWith('\"') && name.length >= 2) {\n return name.slice(1, -1);\n }\n return name;\n}\n\nexport function pickBestName(\n names: Array<{ name: string; language?: string }>,\n): string {\n if (names.length === 0) return \"\";\n const english = names.find((n) => n.language === \"en\");\n return (english ?? names[0]).name;\n}\n\nexport function mapDocType(urn: string): string | null {\n if (urn.includes(\"Invoice-2::Invoice##\")) return \"invoice\";\n if (urn.includes(\"CreditNote-2::CreditNote##\")) return \"credit_note\";\n if (urn.includes(\"ApplicationResponse\")) return \"application_response\";\n if (urn.includes(\"Order-2::Order##\")) return \"order\";\n if (urn.includes(\"DespatchAdvice\")) return \"despatch_advice\";\n return null;\n}\n\nexport function findVatIdentifier(\n identifiers: Array<{ scheme: string; value: string }>,\n): string | undefined {\n const match = identifiers.find((id) => {\n const s = id.scheme.toLowerCase();\n return s.includes(\"vat\") || s.includes(\"cbe\") || s.includes(\"tax\");\n });\n return match?.value;\n}\n\nexport function parseParticipantId(value: string): {\n scheme: string;\n id: string;\n} {\n const colonIndex = value.indexOf(\":\");\n if (colonIndex === -1) {\n return { scheme: \"\", id: value };\n }\n return {\n scheme: value.slice(0, colonIndex),\n id: value.slice(colonIndex + 1),\n };\n}\n\n// ─── Internal: parse a raw match ──────────────────\n\nfunction parseMatch(raw: DirectoryMatchRaw): DirectoryMatch {\n const entity = raw.entities[0];\n const rawName = entity ? pickBestName(entity.name) : \"\";\n const name = stripQuotes(rawName);\n const country = entity?.countryCode ?? \"\";\n\n const capabilities = (raw.docTypes ?? [])\n .map((dt) => mapDocType(dt.value))\n .filter((c): c is string => c !== null)\n // Deduplicate\n .filter((c, i, arr) => arr.indexOf(c) === i);\n\n const vatNumber = entity?.identifiers\n ? findVatIdentifier(entity.identifiers)\n : undefined;\n\n const contactEmail = entity?.contacts?.find((c) => c.email)?.email;\n const website =\n entity?.websites && entity.websites.length > 0\n ? entity.websites[0]\n : undefined;\n\n return {\n name,\n peppolId: raw.participantID.value,\n country,\n capabilities,\n registrationDate: entity?.regDate,\n vatNumber,\n contactEmail,\n website,\n };\n}\n\n// ─── Public API ───────────────────────────────────\n\nexport async function lookupParticipant(\n scheme: string,\n id: string,\n): Promise<DirectoryMatch | null> {\n const participantParam = `iso6523-actorid-upis::${scheme}:${normalizeParticipantIdentifier(scheme, id)}`;\n const url = `${BASE_URL}?participant=${encodeURIComponent(participantParam)}`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(15_000),\n headers: { \"User-Agent\": \"@getpeppr/cli\" },\n });\n if (!response.ok) {\n throw new DirectoryError(\n `Lookup failed: HTTP ${response.status} ${response.statusText}`,\n response.status,\n );\n }\n const data = (await response.json()) as DirectoryResponse;\n\n if (!data.matches || data.matches.length === 0) {\n return null;\n }\n\n return parseMatch(data.matches[0]);\n}\n\nfunction normalizeParticipantIdentifier(scheme: string, id: string): string {\n if (scheme === \"0208\") {\n return id.replace(/^BE(?=(?:0|1)\\d{9}$)/i, \"\");\n }\n\n return id;\n}\n\nexport async function searchParticipants(opts: {\n name?: string;\n country?: string;\n limit?: number;\n}): Promise<SearchResult> {\n const params = new URLSearchParams();\n if (opts.name) params.set(\"name\", opts.name);\n if (opts.country) params.set(\"country\", opts.country);\n\n const url = `${BASE_URL}?${params.toString()}`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(15_000),\n headers: { \"User-Agent\": \"@getpeppr/cli\" },\n });\n if (!response.ok) {\n throw new DirectoryError(\n `Search failed: HTTP ${response.status} ${response.statusText}`,\n response.status,\n );\n }\n const data = (await response.json()) as DirectoryResponse;\n\n const allMatches = (data.matches ?? []).map(parseMatch);\n\n const limit = opts.limit ?? 10;\n const matches = allMatches.slice(0, limit);\n\n const totalCount = data[\"total-result-count\"] ?? 0;\n const hasMore = totalCount > matches.length;\n\n return {\n matches,\n totalCount,\n hasMore,\n };\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { Peppol } from \"@getpeppr/sdk\";\n\nimport { exitWithError } from \"../utils/errors.js\";\nimport { resolveApiKey, AuthError } from \"../lib/auth.js\";\nimport { buildPayload, MutexError } from \"../lib/send-payload.js\";\nimport { confirmInteractive } from \"../lib/confirm.js\";\nimport { pollUntilTerminal } from \"../lib/watch.js\";\nimport { formatSendResult } from \"../formatters/send-result.js\";\nimport { runValidation } from \"./validate.js\";\n\ninterface SendFlags {\n prod?: boolean;\n local?: boolean;\n key?: string;\n to?: string;\n country?: string;\n amount?: string;\n currency?: string;\n desc?: string;\n attachment?: boolean;\n watch?: boolean;\n yes?: boolean;\n validate?: boolean; // commander negates --no-validate to validate=false\n json?: boolean;\n quiet?: boolean;\n}\n\nconst API_BASE = \"https://api.getpeppr.dev/v1\";\nconst LOCAL_BASE = \"http://localhost:3001/api/v1\";\nconst DASHBOARD_BASE = \"https://console.getpeppr.dev/invoices\";\n\nexport function registerSendCommand(program: Command): void {\n program\n .command(\"send\")\n .description(\"Send an invoice to the Peppol network via getpeppr API\")\n .argument(\"[file]\", \"optional path to invoice JSON (mutex with --to/--amount/...)\")\n .option(\"--prod\", \"target production (live keys + confirmation)\")\n .option(\"--local\", \"target localhost:3001 dev server\")\n .option(\"--key <key>\", \"override API key — for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.\")\n .option(\"--to <peppol-id>\", \"recipient peppol id (e.g., 9925:BE0314595348)\")\n .option(\"--country <iso>\", \"recipient ISO 3166-1 alpha-2 country override (e.g., BE)\")\n .option(\"--amount <number>\", \"line amount in major currency units (decimal allowed)\")\n .option(\"--currency <iso>\", \"ISO 4217 currency (default EUR)\")\n .option(\"--desc <text>\", \"line description\")\n .option(\"--attachment\", \"attach the test PDF\")\n .option(\"--watch\", \"poll status until a terminal state (60s timeout)\")\n .option(\"-y, --yes\", \"skip --prod confirmation prompt\")\n .option(\"--no-validate\", \"skip pre-validation locally\")\n .option(\"--json\", \"output JSON\")\n .option(\"--quiet\", \"exit code only, no output\")\n .action(async (file: string | undefined, flags: SendFlags) => {\n // 1. Resolve auth\n let auth;\n try {\n auth = resolveApiKey({\n flagKey: flags.key,\n forceProd: Boolean(flags.prod),\n forceLocal: Boolean(flags.local),\n });\n } catch (e) {\n if (e instanceof AuthError) {\n exitWithError(e.message);\n return;\n }\n throw e;\n }\n\n // 2. Build payload\n const overrides = {\n to: flags.to,\n country: flags.country,\n amount: flags.amount != null ? Number(flags.amount) : undefined,\n currency: flags.currency,\n description: flags.desc,\n attachment: flags.attachment,\n };\n let payload;\n try {\n payload = buildPayload({ file, overrides });\n } catch (e) {\n if (e instanceof MutexError) {\n exitWithError(e.message);\n return;\n }\n if (e instanceof Error) {\n exitWithError(e.message);\n return;\n }\n throw e;\n }\n\n // 3. Pre-validate (unless --no-validate)\n if (flags.validate !== false) {\n const result = runValidation(payload);\n if (!result.valid) {\n process.stderr.write(\n `${pc.red(\"✗\")} Pre-validation failed (${result.totalErrors} errors). Use --no-validate to skip.\\n`,\n );\n process.exit(2);\n }\n }\n\n // 4. --prod confirmation\n if (flags.prod && !flags.yes) {\n const confirmed = await confirmInteractive({\n prompt: pc.yellow(\"⚠ About to send a REAL invoice on the Peppol network. Continue?\"),\n defaultYes: false,\n });\n if (!confirmed) {\n if (!flags.quiet) process.stderr.write(\"Cancelled.\\n\");\n process.exit(0);\n }\n }\n\n // 5. Build SDK client\n const baseUrl = flags.local ? LOCAL_BASE : API_BASE;\n const client = new Peppol({ apiKey: auth.apiKey, baseUrl });\n\n // 6. Send\n let result;\n try {\n result = await client.invoices.send(payload);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.red(\"✗\")} ${msg}\\n`);\n process.exit(1);\n }\n\n const dashboardUrl = `${DASHBOARD_BASE}/${result.id}`;\n\n // 7. --watch\n let finalStatus: string = result.status;\n let timedOut = false;\n // GPR-1061 — a watch that could not run is not a delivery confirmation.\n // The error used to be printed and forgotten: `finalStatus` stayed at the\n // send-time \"submitted\" and the process exited 0, so an automation gating\n // on the exit code read a broken API as a successful delivery.\n let watchFailed = false;\n if (flags.watch) {\n const onTransition = (s: string) => {\n if (!flags.quiet && !flags.json) {\n process.stderr.write(` ${pc.cyan(\"→\")} ${s}\\n`);\n }\n };\n try {\n const w = await pollUntilTerminal(client, result.id, {\n intervalMs: 2000,\n timeoutMs: 60_000,\n onTransition,\n });\n finalStatus = w.finalStatus;\n timedOut = w.timedOut;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.yellow(\"⚠\")} Watch error: ${msg}\\n`);\n watchFailed = true;\n }\n if (timedOut) {\n process.stderr.write(\n `${pc.yellow(\"⚠\")} Timeout — invoice was sent but delivery not confirmed in 60s.\\n`,\n );\n }\n }\n\n // 8. Output\n const mode = flags.quiet ? \"quiet\" : flags.json ? \"json\" : \"formatted\";\n const output = formatSendResult(\n {\n id: result.id,\n number: payload.number,\n status: finalStatus,\n warnings: result.warnings,\n dashboardUrl,\n },\n mode,\n );\n if (output) process.stdout.write(output + \"\\n\");\n\n // 9. Exit code — no_action = not deliverable, a terminal failure (GPR-830)\n //\n // `watchFailed` is deliberately distinct from `timedOut` (GPR-1061). A\n // timeout means the send worked and delivery is simply unconfirmed within\n // the window — still exit 0, as before. A watch ERROR means the API\n // answered something the SDK refused to interpret, so the status printed\n // above is the send-time one and nothing about delivery is known.\n if (\n watchFailed ||\n finalStatus === \"rejected\" ||\n finalStatus === \"failed\" ||\n finalStatus === \"no_action\"\n ) {\n process.exit(1);\n }\n process.exit(0);\n });\n}\n","import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n renameSync,\n} from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport interface Credentials {\n sandbox?: string;\n live?: string;\n}\n\nexport function getCredentialsPath(): string {\n if (platform() === \"win32\") {\n const appdata = process.env.APPDATA ?? join(homedir(), \"AppData\", \"Roaming\");\n return join(appdata, \"getpeppr\", \"credentials.json\");\n }\n // XDG-compliant default; respects $XDG_CONFIG_HOME\n const xdg = process.env.XDG_CONFIG_HOME ?? join(homedir(), \".config\");\n return join(xdg, \"getpeppr\", \"credentials.json\");\n}\n\nexport function readCredentials(): Credentials | null {\n const path = getCredentialsPath();\n if (!existsSync(path)) return null;\n\n // Permission check (POSIX only)\n if (platform() !== \"win32\") {\n const stats = statSync(path);\n const mode = stats.mode & 0o777;\n if (mode !== 0o600) {\n process.stderr.write(\n `⚠ Config file mode was ${mode.toString(8)}; restoring to 600.\\n`,\n );\n chmodSync(path, 0o600);\n }\n }\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf-8\");\n } catch {\n process.stderr.write(`⚠ Could not read config file: ${path}\\n`);\n return null;\n }\n\n try {\n const data = JSON.parse(raw) as Credentials;\n return data;\n } catch {\n process.stderr.write(`⚠ Malformed JSON in config file: ${path}\\n`);\n return null;\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const path = getCredentialsPath();\n const dir = dirname(path);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n\n // Atomic write: tmp file + rename, with mode 600 (POSIX only)\n const tmpPath = `${path}.tmp`;\n const data = JSON.stringify(creds, null, 2) + \"\\n\";\n\n // Defensive: clean up any orphan tmp from a previous crashed run.\n try { rmSync(tmpPath, { force: true }); } catch { /* best effort */ }\n\n // flag: \"wx\" fails if tmp exists (eliminates mode retention) + explicit chmod as belt-and-suspenders.\n writeFileSync(tmpPath, data, { mode: 0o600, flag: \"wx\" });\n chmodSync(tmpPath, 0o600);\n\n try {\n renameSync(tmpPath, path);\n } catch (e) {\n try { rmSync(tmpPath, { force: true }); } catch { /* best effort */ }\n throw e;\n }\n}\n\nexport function deleteCredentials(): boolean {\n const path = getCredentialsPath();\n if (!existsSync(path)) return false;\n rmSync(path);\n return true;\n}\n","import { readCredentials } from \"./credentials-store.js\";\n\nexport type Environment = \"sandbox\" | \"live\";\nexport type AuthSource = \"flag\" | \"env\" | \"config\";\n\nexport interface ResolvedAuth {\n apiKey: string;\n source: AuthSource;\n environment: Environment;\n}\n\nexport interface ResolveOptions {\n flagKey?: string;\n forceProd: boolean;\n forceLocal: boolean; // reserved for Task 10 (--local flag); resolveApiKey itself does not use it\n}\n\nexport class AuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nexport function resolveApiKey(opts: ResolveOptions): ResolvedAuth {\n const env: Environment = opts.forceProd ? \"live\" : \"sandbox\";\n\n // 1. Flag has highest priority\n if (opts.flagKey) {\n return { apiKey: opts.flagKey, source: \"flag\", environment: env };\n }\n\n // 2. Env var\n const envKey = process.env.GETPEPPR_API_KEY;\n if (envKey) {\n return { apiKey: envKey, source: \"env\", environment: env };\n }\n\n // 3. Config file\n const creds = readCredentials();\n if (creds) {\n const key = env === \"live\" ? creds.live : creds.sandbox;\n if (key) {\n return { apiKey: key, source: \"config\", environment: env };\n }\n if (env === \"live\") {\n throw new AuthError(\n `Config has no live API key. Run \\`getpeppr login\\` again with --live, or pass --key.`,\n );\n }\n }\n\n // 4. Nothing found\n throw new AuthError(\n `No API key found. Run \\`getpeppr login\\` or set GETPEPPR_API_KEY.`,\n );\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { InvoiceInput } from \"@getpeppr/sdk\";\nimport { buildDefaultSendPayload, type SendDefaultOverrides } from \"../templates/send-default.js\";\n\nexport class MutexError extends Error {\n constructor() {\n super(\"Cannot combine custom file with override flags. Use one or the other.\");\n this.name = \"MutexError\";\n }\n}\n\nexport interface BuildPayloadOptions {\n file?: string;\n overrides?: SendDefaultOverrides;\n}\n\nfunction hasOverrides(o?: SendDefaultOverrides): boolean {\n if (!o) return false;\n // Use `!= null` for amount (handles 0) and explicit string-emptiness check for `to`.\n // `attachment: false` is the default behaviour, so we treat it as \"no override expressed\".\n // `attachment: true` is the only way to opt into the attachment override.\n return Boolean(\n (o.to != null && o.to !== \"\") ||\n (o.country != null && o.country !== \"\") ||\n o.amount != null ||\n o.currency ||\n o.description ||\n o.attachment === true,\n );\n}\n\nexport function buildPayload(opts: BuildPayloadOptions): InvoiceInput {\n if (opts.file && hasOverrides(opts.overrides)) {\n throw new MutexError();\n }\n\n if (opts.file) {\n const absPath = resolve(opts.file);\n if (!existsSync(absPath)) {\n throw new Error(`Error: file not found — ${absPath}`);\n }\n let raw: string;\n try {\n raw = readFileSync(absPath, \"utf-8\");\n } catch {\n throw new Error(`Error: could not read file — ${absPath}`);\n }\n try {\n return JSON.parse(raw) as InvoiceInput;\n } catch {\n throw new Error(`Error: invalid JSON in file — ${absPath}`);\n }\n }\n\n return buildDefaultSendPayload(opts.overrides);\n}\n","import type { InvoiceInput, PeppolId, CountryCode } from \"@getpeppr/sdk\";\n\n// Minimal valid PDF (Storecove validates content). Canonical source is\n// packages/sdk/scripts/send-test-invoice.ts — if that script's PDF is ever\n// updated, this duplicate must be kept in sync. The scripts/ directory is\n// excluded from SDK tsconfig so cross-package import isn't possible.\nconst MINIMAL_PDF = `%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n0000000009 00000 n\n0000000058 00000 n\n0000000115 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxref\n190\n%%EOF`;\n\nexport const MINIMAL_TEST_PDF_BASE64 = Buffer.from(MINIMAL_PDF).toString(\"base64\");\n\nexport interface SendDefaultOverrides {\n to?: string;\n country?: string;\n amount?: number;\n currency?: string;\n description?: string;\n attachment?: boolean;\n}\n\nconst SCHEME_COUNTRY_DEFAULTS: Record<string, CountryCode> = {\n \"0009\": \"FR\" as CountryCode,\n \"0204\": \"DE\" as CountryCode,\n \"0208\": \"BE\" as CountryCode,\n \"9925\": \"BE\" as CountryCode,\n};\n\nfunction deriveCountryFromPeppolId(peppolId: PeppolId): CountryCode {\n const [scheme, identifier = \"\"] = peppolId.split(\":\");\n const alphaPrefix = identifier.slice(0, 2);\n\n if (/^[A-Za-z]{2}$/.test(alphaPrefix)) {\n return alphaPrefix.toUpperCase() as CountryCode;\n }\n\n return SCHEME_COUNTRY_DEFAULTS[scheme] ?? (\"BE\" as CountryCode);\n}\n\nexport function buildDefaultSendPayload(overrides: SendDefaultOverrides = {}): InvoiceInput {\n const today = new Date();\n const due = new Date(today.getTime() + 30 * 86400000);\n const isoToday = today.toISOString().slice(0, 10);\n const isoDue = due.toISOString().slice(0, 10);\n\n // TODO(Task 10 send command): validate scheme:id format upstream before calling.\n // Cast is safe assuming caller passes valid Peppol ID format (XXXX:YYYYYY).\n const peppolId = (overrides.to ?? \"9925:BE0314595348\") as PeppolId; // SPF Economie BE — accepts test invoices\n const amount = overrides.amount ?? 100;\n const currency = overrides.currency ?? \"EUR\";\n const description = overrides.description ?? \"Test service from getpeppr\";\n\n // Unique invoice number: TEST-{base36 timestamp}-{4-char random hex}.\n // The random suffix guarantees uniqueness even when two calls land within the same millisecond.\n const randomSuffix = Math.floor(Math.random() * 0x10000)\n .toString(16)\n .toUpperCase()\n .padStart(4, \"0\");\n const number = `TEST-${Date.now().toString(36).toUpperCase()}-${randomSuffix}`;\n\n // Best-effort country derivation from Peppol ID. Some Belgian 0208 IDs are bare\n // enterprise numbers (e.g. 0208:0738836782), so fall back to the scheme mapping.\n // CountryCode is `\"BE\" | \"FR\" | ... | (string & {})` so any string is accepted.\n const country = overrides.country != null\n ? overrides.country.toUpperCase() as CountryCode\n : deriveCountryFromPeppolId(peppolId);\n\n const payload: InvoiceInput = {\n number,\n date: isoToday,\n dueDate: isoDue,\n currency,\n to: {\n name: peppolId === \"9925:BE0314595348\" ? \"SPF Economie (TEST)\" : \"Test Recipient\",\n peppolId,\n country,\n street: \"Rue de la Loi 1\",\n city: \"Brussels\",\n postalCode: \"1000\",\n },\n lines: [\n {\n description,\n quantity: 1,\n unitPrice: amount,\n vatRate: 0,\n // vatCategory \"O\" = \"Services outside scope of tax\" (UBL 2.1 / EN 16931).\n // Public entities (SPF Economie) are VAT-exempt. No `taxExemptReason` field\n // exists in InvoiceLine — Storecove derives exemption from the category code.\n // If sandbox returns 422 on this combination, fallback is vatRate: 21 + vatCategory: \"S\".\n vatCategory: \"O\",\n },\n ],\n };\n\n if (overrides.attachment) {\n payload.attachments = [\n {\n id: \"ATT-001\",\n description: \"Test document\",\n filename: \"test.pdf\",\n mimeType: \"application/pdf\",\n content: MINIMAL_TEST_PDF_BASE64,\n },\n ];\n }\n\n return payload;\n}\n","import type { Readable, Writable } from \"node:stream\";\nimport { createInterface } from \"node:readline\";\n\nexport interface ConfirmOptions {\n prompt: string;\n defaultYes: boolean;\n stdin?: Readable;\n stdout?: Writable;\n}\n\nexport async function confirmInteractive(opts: ConfirmOptions): Promise<boolean> {\n const stdin = (opts.stdin ?? process.stdin) as Readable & { isTTY?: boolean };\n const stdout = opts.stdout ?? process.stdout;\n\n // Non-TTY (CI, piped, vitest) → fall back to default.\n // Treat any non-true value (false, undefined) as non-TTY.\n if (stdin.isTTY !== true) {\n return opts.defaultYes;\n }\n\n const suffix = opts.defaultYes ? \"[Y/n]\" : \"[y/N]\";\n return new Promise<boolean>((resolve) => {\n const rl = createInterface({ input: stdin, output: stdout });\n let settled = false;\n\n rl.question(`${opts.prompt} ${suffix} `, (answer) => {\n settled = true;\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n if (trimmed === \"\") return resolve(opts.defaultYes);\n if (trimmed === \"y\" || trimmed === \"yes\") return resolve(true);\n if (trimmed === \"n\" || trimmed === \"no\") return resolve(false);\n // Unrecognized input → defaultYes (lenient)\n return resolve(opts.defaultYes);\n });\n\n // Guard: if stdin closes without newline (Ctrl+D, EOF), question callback\n // never fires. Resolve to defaultYes consistent with lenient-fallback policy.\n rl.once(\"close\", () => {\n if (!settled) resolve(opts.defaultYes);\n });\n });\n}\n","// `no_action` = not deliverable (no recipient on the Peppol network) — terminal\n// for wait semantics: no event ever follows it (GPR-830, spec §3.12).\nexport type TerminalStatus = \"delivered\" | \"accepted\" | \"rejected\" | \"failed\" | \"no_action\";\n\nconst TERMINAL_STATES = new Set<TerminalStatus>([\n \"delivered\",\n \"accepted\",\n \"rejected\",\n \"failed\",\n \"no_action\",\n]);\n\nexport interface WatchOptions {\n intervalMs?: number;\n timeoutMs?: number;\n onTransition?: (status: string) => void;\n}\n\nexport interface WatchResult {\n finalStatus: string;\n timedOut: boolean;\n}\n\ninterface StatusFetcher {\n invoices: { getStatus: (id: string) => Promise<{ status: string }> };\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nexport async function pollUntilTerminal(\n client: StatusFetcher,\n documentId: string,\n options: WatchOptions = {},\n): Promise<WatchResult> {\n const intervalMs = options.intervalMs ?? 2000;\n const timeoutMs = options.timeoutMs ?? 60_000;\n const start = Date.now();\n\n let lastStatus = \"\";\n\n while (Date.now() - start < timeoutMs) {\n const { status } = await client.invoices.getStatus(documentId);\n\n if (status !== lastStatus) {\n options.onTransition?.(status);\n lastStatus = status;\n }\n\n if (TERMINAL_STATES.has(status as TerminalStatus)) {\n return { finalStatus: status, timedOut: false };\n }\n\n await sleep(intervalMs);\n }\n\n return { finalStatus: lastStatus, timedOut: true };\n}\n","import pc from \"picocolors\";\n\nexport interface SendResultPayload {\n id: string;\n number: string;\n status: string;\n warnings?: { message: string }[];\n dashboardUrl: string;\n}\n\nexport type OutputMode = \"formatted\" | \"json\" | \"quiet\";\n\nexport function formatSendResult(result: SendResultPayload, mode: OutputMode): string {\n if (mode === \"quiet\") return \"\";\n\n if (mode === \"json\") {\n return JSON.stringify(result, null, 2);\n }\n\n // formatted\n const lines: string[] = [];\n lines.push(`${pc.green(\"✓\")} Sent ${pc.bold(result.number)}`);\n lines.push(` id: ${result.id}`);\n lines.push(` Status: ${pc.cyan(result.status)}`);\n lines.push(` Track: ${pc.dim(result.dashboardUrl)}`);\n\n const wCount = result.warnings?.length ?? 0;\n if (wCount > 0) {\n lines.push(` ${pc.yellow(`${wCount} warning${wCount === 1 ? \"\" : \"s\"}`)}`);\n for (const w of result.warnings ?? []) {\n lines.push(` ${pc.yellow(\"⚠\")} ${w.message}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n","import { createInterface } from \"node:readline\";\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport {\n getCredentialsPath,\n readCredentials,\n writeCredentials,\n} from \"../lib/credentials-store.js\";\n\ninterface LoginFlags {\n key?: string;\n sandbox?: boolean;\n live?: boolean;\n}\n\nasync function promptMaskedKey(envLabel: string): Promise<string> {\n if (process.stdin.isTTY !== true) {\n exitWithError(\"Error: --key flag required when stdin is not a TTY (CI mode).\");\n }\n\n process.stdout.write(`Paste your ${envLabel} API key (input hidden): `);\n\n return new Promise<string>((resolve) => {\n let buffer = \"\";\n const onData = (chunk: Buffer) => {\n const c = chunk.toString(\"utf-8\");\n if (c === \"\\n\" || c === \"\\r\" || c === \"\\r\\n\") {\n process.stdin.setRawMode(false);\n process.stdin.removeListener(\"data\", onData);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n resolve(buffer);\n return;\n }\n if (c === \"\\x03\") {\n // Ctrl-C in raw mode: SIGINT is disabled, byte arrives as ETX (0x03)\n process.stdin.setRawMode(false);\n process.stdin.removeListener(\"data\", onData);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n process.exit(130);\n }\n if (c === \"\\x7f\" || c === \"\\b\") {\n // Backspace: POSIX terminals send DEL (0x7f), some send BS (0x08 / \"\\b\")\n buffer = buffer.slice(0, -1);\n return;\n }\n buffer += c;\n };\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on(\"data\", onData);\n });\n}\n\nasync function promptEnvironment(): Promise<\"sandbox\" | \"live\"> {\n if (process.stdin.isTTY !== true) return \"sandbox\";\n\n return new Promise<\"sandbox\" | \"live\">((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(\"Environment? (s)andbox / (l)ive [sandbox]: \", (answer) => {\n rl.close();\n const a = answer.trim().toLowerCase();\n if (a === \"l\" || a === \"live\") return resolve(\"live\");\n return resolve(\"sandbox\");\n });\n });\n}\n\nexport function registerLoginCommand(program: Command): void {\n program\n .command(\"login\")\n .description(\"Save a getpeppr API key to ~/.config/getpeppr/credentials.json\")\n .option(\"--key <key>\", \"API key — for CI/scripted use only; visible in `ps` and shell history. Prefer the interactive prompt or GETPEPPR_API_KEY env var.\")\n .option(\"--sandbox\", \"store as sandbox key (default)\")\n .option(\"--live\", \"store as live (production) key\")\n .action(async (flags: LoginFlags) => {\n if (!flags.live && !flags.sandbox && process.stdin.isTTY !== true) {\n exitWithError(\"Error: --sandbox or --live required when stdin is not a TTY (CI mode).\");\n }\n\n let env: \"sandbox\" | \"live\";\n if (flags.live) env = \"live\";\n else if (flags.sandbox) env = \"sandbox\";\n else env = await promptEnvironment();\n\n let key: string;\n if (flags.key) {\n key = flags.key;\n } else {\n key = (await promptMaskedKey(env)).trim();\n if (!key) exitWithError(\"Error: empty API key.\");\n }\n\n const existing = readCredentials() ?? {};\n const next = { ...existing, [env]: key };\n writeCredentials(next);\n\n const path = getCredentialsPath();\n process.stderr.write(\n `${pc.green(\"✓\")} Saved ${env} key to ${path} (mode 600)\\n`,\n );\n });\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { deleteCredentials, getCredentialsPath } from \"../lib/credentials-store.js\";\n\nexport function registerLogoutCommand(program: Command): void {\n program\n .command(\"logout\")\n .description(\"Remove ~/.config/getpeppr/credentials.json\")\n .action(() => {\n const path = getCredentialsPath();\n const removed = deleteCredentials();\n if (removed) {\n process.stderr.write(`${pc.green(\"✓\")} Removed ${path}\\n`);\n } else {\n process.stderr.write(`No credentials to remove (${path})\\n`);\n }\n process.exit(0);\n });\n}\n"],"mappings":"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","names":["warn","resolve","error","program","existsSync","resolve","pc","program","resolve","existsSync","pc","writeFileSync","pc","program","writeFileSync","pc","pc","pc","program","pc","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","resolve","resolve","existsSync","readFileSync","resolve","sleep","pc","program","result","pc","createInterface","pc","resolve","createInterface","program","pc","pc","program","pc","require"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/utils/file.ts","../src/utils/errors.ts","../src/formatters/validation.ts","../../sdk/src/core/ubl-builder.ts","../../sdk/src/core/checksums/luhn.ts","../../sdk/src/core/country-rules.ts","../../sdk/src/core/code-lists.ts","../../sdk/src/core/validator.ts","../../sdk/src/core/status-precedence.ts","../../sdk/src/version.ts","../../sdk/src/core/client.ts","../../sdk/src/core/schematron.ts","../src/commands/validate.ts","../src/commands/init.ts","../src/templates/invoice.ts","../src/templates/credit-note.ts","../src/commands/convert.ts","../src/commands/lookup.ts","../src/lib/peppol-directory.ts","../src/commands/send.ts","../src/lib/credentials-store.ts","../src/lib/auth.ts","../src/lib/send-payload.ts","../src/templates/send-default.ts","../src/lib/confirm.ts","../src/lib/watch.ts","../src/formatters/send-result.ts","../src/commands/login.ts","../src/commands/whoami.ts","../src/commands/logout.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { registerValidateCommand } from \"./commands/validate.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerConvertCommand } from \"./commands/convert.js\";\nimport { registerLookupCommand } from \"./commands/lookup.js\";\nimport { registerSendCommand } from \"./commands/send.js\";\nimport { registerLoginCommand } from \"./commands/login.js\";\nimport { registerWhoamiCommand } from \"./commands/whoami.js\";\nimport { registerLogoutCommand } from \"./commands/logout.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"getpeppr\")\n .description(\"CLI tool for Peppol e-invoice validation and development\")\n .version(version);\n\nregisterValidateCommand(program);\nregisterInitCommand(program);\nregisterConvertCommand(program);\nregisterLookupCommand(program);\nregisterSendCommand(program);\nregisterLoginCommand(program);\nregisterWhoamiCommand(program);\nregisterLogoutCommand(program);\n\nprogram.parse();\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { InvoiceInput } from \"@getpeppr/sdk\";\nimport { exitWithError } from \"./errors.js\";\n\nexport type FileReadResult =\n | { ok: true; data: unknown }\n | { ok: false; error: string };\n\nexport function readJsonFile(filePath: string): FileReadResult {\n const resolved = resolve(filePath);\n\n if (!existsSync(resolved)) {\n return { ok: false, error: `Error: file not found — ${resolved}` };\n }\n\n let content: string;\n try {\n content = readFileSync(resolved, \"utf-8\");\n } catch {\n return { ok: false, error: `Error: could not read file — ${resolved}` };\n }\n\n try {\n const data: unknown = JSON.parse(content);\n return { ok: true, data };\n } catch {\n return { ok: false, error: `Error: invalid JSON in file — ${resolved}` };\n }\n}\n\nexport function readAndValidateInvoiceJson(filePath: string): InvoiceInput {\n const parseResult = readJsonFile(filePath);\n if (!parseResult.ok) {\n exitWithError(parseResult.error);\n }\n\n if (\n typeof parseResult.data !== \"object\" ||\n parseResult.data === null ||\n Array.isArray(parseResult.data)\n ) {\n exitWithError(\n \"Error: JSON file must contain an object, not an array or primitive\",\n );\n }\n\n return parseResult.data as InvoiceInput;\n}\n","export function exitWithError(message: string, code = 2): never {\n process.stderr.write(message + \"\\n\");\n process.exit(code);\n}\n","import pc from \"picocolors\";\nimport type { MergedValidationResult } from \"../commands/validate.js\";\nimport type { ValidationError, ValidationWarning, SchematronViolation } from \"@getpeppr/sdk\";\n\nfunction sectionHeader(title: string): string {\n const pad = 45 - title.length - 4;\n return pc.dim(`── ${title} ${\"─\".repeat(Math.max(pad, 3))}`);\n}\n\nfunction formatError(item: ValidationError | SchematronViolation): string {\n const ruleId = \"ruleId\" in item && item.ruleId ? pc.dim(` (${item.ruleId})`) : \"\";\n const field = \"field\" in item && item.field ? `${item.field} — ` : \"\";\n return ` ${pc.red(\"✗\")} ${field}${item.message}${ruleId}`;\n}\n\nfunction formatWarning(item: ValidationWarning | SchematronViolation): string {\n const ruleId = \"ruleId\" in item && item.ruleId ? pc.dim(` (${item.ruleId})`) : \"\";\n const field = \"field\" in item && item.field ? `${item.field} — ` : \"\";\n return ` ${pc.yellow(\"⚠\")} ${field}${item.message}${ruleId}`;\n}\n\nfunction formatSection(\n title: string,\n errors: (ValidationError | SchematronViolation)[],\n warnings: (ValidationWarning | SchematronViolation)[],\n): string {\n const lines: string[] = [sectionHeader(title)];\n\n if (errors.length === 0 && warnings.length === 0) {\n lines.push(` ${pc.green(\"✓\")} All rules passed`);\n return lines.join(\"\\n\");\n }\n\n if (errors.length === 0) {\n lines.push(` ${pc.green(\"✓\")} No errors`);\n }\n\n for (const err of errors) {\n lines.push(formatError(err));\n }\n\n for (const warn of warnings) {\n lines.push(formatWarning(warn));\n }\n\n return lines.join(\"\\n\");\n}\n\nexport function formatValidationResult(\n filename: string,\n result: MergedValidationResult,\n): string {\n const lines: string[] = [];\n\n lines.push(`\\nValidating: ${pc.bold(filename)}\\n`);\n\n lines.push(\n formatSection(\n \"Structure\",\n result.structure.errors,\n result.structure.warnings,\n ),\n );\n lines.push(\"\");\n\n lines.push(\n formatSection(\n \"Business Rules (Peppol BIS 3.0)\",\n result.schematron.errors,\n result.schematron.warnings,\n ),\n );\n lines.push(\"\");\n\n lines.push(\n formatSection(\n \"Country Rules\",\n result.countryRules.errors,\n result.countryRules.warnings,\n ),\n );\n lines.push(\"\");\n\n // Summary\n lines.push(sectionHeader(\"Summary\"));\n const { totalErrors, totalWarnings, valid } = result;\n\n if (valid && totalWarnings === 0) {\n lines.push(` ${pc.green(pc.bold(\"✓ Invoice is valid\"))}`);\n } else if (valid) {\n lines.push(\n ` ${pc.green(pc.bold(\"✓ Invoice is valid\"))} ${pc.dim(`(${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"})`)}`,\n );\n } else {\n const parts: string[] = [];\n parts.push(`${totalErrors} error${totalErrors === 1 ? \"\" : \"s\"}`);\n if (totalWarnings > 0) {\n parts.push(`${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"}`);\n }\n lines.push(\n ` ${pc.red(pc.bold(`✗ ${parts.join(\", \")}`))} — invoice non-compliant`,\n );\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n","/**\n * UBL XML Builder\n *\n * Converts our clean JSON invoice format to Peppol BIS 3.0 compliant UBL 2.1 XML.\n * This is the core abstraction that hides XML complexity from developers.\n *\n * Reference: https://docs.peppol.eu/poacc/billing/3.0/\n */\n\nimport type { InvoiceInput, CreditNoteInput, InvoiceLine, Party, Delivery, AllowanceCharge, Attachment, InvoicePeriod } from \"../types/invoice.js\";\n\nconst UBL_NS = \"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\";\nconst CAC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\";\nconst CBC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\";\nconst CREDIT_NOTE_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2\";\n\n// Peppol BIS 3.0 customization and profile IDs\nconst PEPPOL_CUSTOMIZATION_ID =\n \"urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\";\nconst PEPPOL_PROFILE_ID = \"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\";\n\n/** Default unit of measure */\nconst DEFAULT_UNIT = \"EA\";\n\n/** Default payment means code (30 = credit transfer) */\nconst DEFAULT_PAYMENT_MEANS = 30;\n\n/** Map human-readable unit names to UN/ECE Recommendation 20 codes */\nconst UNIT_CODE_MAP: Record<string, string> = {\n each: \"EA\", piece: \"EA\", pieces: \"EA\",\n hour: \"HUR\", hours: \"HUR\",\n day: \"DAY\", days: \"DAY\",\n week: \"WEE\", weeks: \"WEE\",\n month: \"MON\", months: \"MON\",\n year: \"ANN\", years: \"ANN\",\n kilogram: \"KGM\", kg: \"KGM\",\n meter: \"MTR\", metre: \"MTR\",\n liter: \"LTR\", litre: \"LTR\",\n unit: \"C62\", units: \"C62\",\n set: \"SET\", sets: \"SET\",\n pack: \"PK\", packs: \"PK\",\n};\n\n/**\n * Resolve a human-readable unit name to its UN/ECE Recommendation 20 code.\n * If already a valid UBL code (2-3 uppercase chars) or unknown, passes through unchanged.\n */\nfunction resolveUnitCode(unit: string): string {\n return UNIT_CODE_MAP[unit.toLowerCase()] ?? unit;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\nfunction formatDate(dateStr?: string): string {\n if (!dateStr) {\n return new Date().toISOString().split(\"T\")[0]!;\n }\n // Accept ISO 8601 date or datetime\n return dateStr.split(\"T\")[0]!;\n}\n\nfunction formatAmount(amount: number): string {\n return amount.toFixed(2);\n}\n\n/** Round to 2 decimal places to prevent IEEE 754 accumulation errors */\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nfunction parsePeppolId(peppolId: string): { scheme: string; id: string } {\n const scheme = peppolId.split(\":\")[0]!;\n const id = peppolId.split(\":\").slice(1).join(\":\");\n return { scheme, id };\n}\n\nfunction buildPartyXml(party: Party, role: \"AccountingSupplierParty\" | \"AccountingCustomerParty\"): string {\n const { scheme: endpointScheme, id: endpointId } = parsePeppolId(party.peppolId);\n\n return `\n <cac:${role}>\n <cac:Party>\n <cbc:EndpointID schemeID=\"${escapeXml(endpointScheme)}\">${escapeXml(endpointId)}</cbc:EndpointID>\n <cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(endpointScheme)}\">${escapeXml(endpointId)}</cbc:ID>\n </cac:PartyIdentification>\n <cac:PartyName>\n <cbc:Name>${escapeXml(party.name)}</cbc:Name>\n </cac:PartyName>\n <cac:PostalAddress>\n ${party.street ? `<cbc:StreetName>${escapeXml(party.street)}</cbc:StreetName>` : \"\"}\n ${party.city ? `<cbc:CityName>${escapeXml(party.city)}</cbc:CityName>` : \"\"}\n ${party.postalCode ? `<cbc:PostalZone>${escapeXml(party.postalCode)}</cbc:PostalZone>` : \"\"}\n <cac:Country>\n <cbc:IdentificationCode>${escapeXml(party.country)}</cbc:IdentificationCode>\n </cac:Country>\n </cac:PostalAddress>\n ${\n party.vatNumber\n ? `<cac:PartyTaxScheme>\n <cbc:CompanyID>${escapeXml(party.vatNumber)}</cbc:CompanyID>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:PartyTaxScheme>`\n : \"\"\n }\n <cac:PartyLegalEntity>\n <cbc:RegistrationName>${escapeXml(party.name)}</cbc:RegistrationName>\n ${party.companyId ? `<cbc:CompanyID>${escapeXml(party.companyId)}</cbc:CompanyID>` : \"\"}\n </cac:PartyLegalEntity>\n ${(party.contactName || party.phone || party.email)\n ? `<cac:Contact>\n ${party.contactName ? `<cbc:Name>${escapeXml(party.contactName)}</cbc:Name>` : \"\"}\n ${party.phone ? `<cbc:Telephone>${escapeXml(party.phone)}</cbc:Telephone>` : \"\"}\n ${party.email ? `<cbc:ElectronicMail>${escapeXml(party.email)}</cbc:ElectronicMail>` : \"\"}\n </cac:Contact>`\n : \"\"\n }\n </cac:Party>\n </cac:${role}>`;\n}\n\nfunction buildPayeePartyXml(party: Party): string {\n const { scheme, id } = parsePeppolId(party.peppolId);\n\n return `\n <cac:PayeeParty>\n <cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(scheme)}\">${escapeXml(id)}</cbc:ID>\n </cac:PartyIdentification>\n <cac:PartyName>\n <cbc:Name>${escapeXml(party.name)}</cbc:Name>\n </cac:PartyName>\n ${party.companyId\n ? `<cac:PartyLegalEntity>\n <cbc:RegistrationName>${escapeXml(party.name)}</cbc:RegistrationName>\n <cbc:CompanyID>${escapeXml(party.companyId)}</cbc:CompanyID>\n </cac:PartyLegalEntity>`\n : \"\"\n }\n </cac:PayeeParty>`;\n}\n\nfunction buildTaxRepresentativePartyXml(party: Party): string {\n const parts: string[] = [\n \" <cac:TaxRepresentativeParty>\",\n \" <cac:PartyName>\",\n ` <cbc:Name>${escapeXml(party.name)}</cbc:Name>`,\n \" </cac:PartyName>\",\n ];\n\n // PostalAddress\n parts.push(\" <cac:PostalAddress>\");\n if (party.street) {\n parts.push(` <cbc:StreetName>${escapeXml(party.street)}</cbc:StreetName>`);\n }\n if (party.city) {\n parts.push(` <cbc:CityName>${escapeXml(party.city)}</cbc:CityName>`);\n }\n if (party.postalCode) {\n parts.push(` <cbc:PostalZone>${escapeXml(party.postalCode)}</cbc:PostalZone>`);\n }\n parts.push(\" <cac:Country>\");\n parts.push(` <cbc:IdentificationCode>${escapeXml(party.country)}</cbc:IdentificationCode>`);\n parts.push(\" </cac:Country>\");\n parts.push(\" </cac:PostalAddress>\");\n\n // PartyTaxScheme (vatNumber → CompanyID)\n if (party.vatNumber) {\n parts.push(\" <cac:PartyTaxScheme>\");\n parts.push(` <cbc:CompanyID>${escapeXml(party.vatNumber)}</cbc:CompanyID>`);\n parts.push(\" <cac:TaxScheme>\");\n parts.push(\" <cbc:ID>VAT</cbc:ID>\");\n parts.push(\" </cac:TaxScheme>\");\n parts.push(\" </cac:PartyTaxScheme>\");\n }\n\n parts.push(\" </cac:TaxRepresentativeParty>\");\n return parts.join(\"\\n\");\n}\n\nfunction buildAttachmentXml(attachment: Attachment): string {\n const parts: string[] = [\n \"<cac:AdditionalDocumentReference>\",\n ` <cbc:ID>${escapeXml(attachment.id)}</cbc:ID>`,\n ];\n\n if (attachment.description) {\n parts.push(` <cbc:DocumentDescription>${escapeXml(attachment.description)}</cbc:DocumentDescription>`);\n }\n\n if (attachment.content || attachment.url) {\n parts.push(\" <cac:Attachment>\");\n if (attachment.content && attachment.mimeType && attachment.filename) {\n parts.push(\n ` <cbc:EmbeddedDocumentBinaryObject mimeCode=\"${escapeXml(attachment.mimeType)}\" filename=\"${escapeXml(attachment.filename)}\">${attachment.content}</cbc:EmbeddedDocumentBinaryObject>`,\n );\n } else if (attachment.url) {\n parts.push(\n ` <cac:ExternalReference>\\n <cbc:URI>${escapeXml(attachment.url)}</cbc:URI>\\n </cac:ExternalReference>`,\n );\n }\n parts.push(\" </cac:Attachment>\");\n }\n\n parts.push(\"</cac:AdditionalDocumentReference>\");\n return parts.join(\"\\n \");\n}\n\nfunction buildInvoicePeriodXml(period: InvoicePeriod): string {\n const parts: string[] = [\"<cac:InvoicePeriod>\"];\n if (period.startDate) {\n parts.push(` <cbc:StartDate>${formatDate(period.startDate)}</cbc:StartDate>`);\n }\n if (period.endDate) {\n parts.push(` <cbc:EndDate>${formatDate(period.endDate)}</cbc:EndDate>`);\n }\n parts.push(\"</cac:InvoicePeriod>\");\n return parts.join(\"\\n \");\n}\n\nfunction buildDeliveryXml(delivery: Delivery): string {\n const parts: string[] = [\"<cac:Delivery>\"];\n\n if (delivery.date) {\n parts.push(` <cbc:ActualDeliveryDate>${formatDate(delivery.date)}</cbc:ActualDeliveryDate>`);\n }\n\n if (delivery.locationId || delivery.address) {\n parts.push(\" <cac:DeliveryLocation>\");\n if (delivery.locationId) {\n parts.push(` <cbc:ID>${escapeXml(delivery.locationId)}</cbc:ID>`);\n }\n if (delivery.address) {\n parts.push(\" <cac:Address>\");\n if (delivery.address.street) {\n parts.push(` <cbc:StreetName>${escapeXml(delivery.address.street)}</cbc:StreetName>`);\n }\n if (delivery.address.city) {\n parts.push(` <cbc:CityName>${escapeXml(delivery.address.city)}</cbc:CityName>`);\n }\n if (delivery.address.postalCode) {\n parts.push(` <cbc:PostalZone>${escapeXml(delivery.address.postalCode)}</cbc:PostalZone>`);\n }\n parts.push(` <cac:Country>\\n <cbc:IdentificationCode>${escapeXml(delivery.address.country)}</cbc:IdentificationCode>\\n </cac:Country>`);\n parts.push(\" </cac:Address>\");\n }\n parts.push(\" </cac:DeliveryLocation>\");\n }\n\n parts.push(\"</cac:Delivery>\");\n return parts.join(\"\\n \");\n}\n\nfunction buildDocumentAllowanceChargeXml(\n item: AllowanceCharge,\n isCharge: boolean,\n currency: string,\n): string {\n const vatCategory = item.vatCategory ?? \"S\";\n return `\n <cac:AllowanceCharge>\n <cbc:ChargeIndicator>${isCharge}</cbc:ChargeIndicator>\n <cbc:AllowanceChargeReason>${escapeXml(item.reason)}</cbc:AllowanceChargeReason>\n <cbc:Amount currencyID=\"${escapeXml(currency)}\">${formatAmount(item.amount)}</cbc:Amount>\n <cac:TaxCategory>\n <cbc:ID>${vatCategory}</cbc:ID>\n <cbc:Percent>${item.vatRate}</cbc:Percent>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:TaxCategory>\n </cac:AllowanceCharge>`;\n}\n\nfunction buildLineAllowanceChargeXml(\n reason: string,\n amount: number,\n isCharge: boolean,\n currency: string,\n): string {\n return `\n <cac:AllowanceCharge>\n <cbc:ChargeIndicator>${isCharge}</cbc:ChargeIndicator>\n <cbc:AllowanceChargeReason>${escapeXml(reason)}</cbc:AllowanceChargeReason>\n <cbc:Amount currencyID=\"${escapeXml(currency)}\">${formatAmount(amount)}</cbc:Amount>\n </cac:AllowanceCharge>`;\n}\n\nfunction calculateLineExtensionAmount(line: InvoiceLine): number {\n const base = line.quantity * line.unitPrice;\n const lineAllowances = (line.allowances ?? []).reduce((sum, a) => sum + a.amount, 0);\n const lineCharges = (line.charges ?? []).reduce((sum, c) => sum + c.amount, 0);\n return base - lineAllowances + lineCharges;\n}\n\ntype LineType = \"InvoiceLine\" | \"CreditNoteLine\";\ntype QuantityType = \"InvoicedQuantity\" | \"CreditedQuantity\";\n\nfunction buildDocumentLineXml(\n line: InvoiceLine,\n index: number,\n currency: string,\n lineTag: LineType,\n qtyTag: QuantityType,\n): string {\n const lineTotal = calculateLineExtensionAmount(line);\n const unit = resolveUnitCode(line.unit ?? DEFAULT_UNIT);\n const vatCategory = line.vatCategory ?? \"S\";\n\n const lineAllowancesXml = (line.allowances ?? [])\n .map((a) => buildLineAllowanceChargeXml(a.reason, a.amount, false, currency))\n .join(\"\");\n const lineChargesXml = (line.charges ?? [])\n .map((c) => buildLineAllowanceChargeXml(c.reason, c.amount, true, currency))\n .join(\"\");\n\n return `\n <cac:${lineTag}>\n <cbc:ID>${index + 1}</cbc:ID>\n ${line.accountingCost ? `<cbc:AccountingCost>${escapeXml(line.accountingCost)}</cbc:AccountingCost>` : \"\"}\n <cbc:${qtyTag} unitCode=\"${escapeXml(unit)}\">${Number(line.quantity.toFixed(6))}</cbc:${qtyTag}>\n <cbc:LineExtensionAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(lineTotal)}</cbc:LineExtensionAmount>\n ${lineAllowancesXml}${lineChargesXml}\n <cac:Item>\n <cbc:Name>${escapeXml(line.description)}</cbc:Name>\n ${\n line.itemId\n ? `<cac:SellersItemIdentification>\n <cbc:ID>${escapeXml(line.itemId)}</cbc:ID>\n </cac:SellersItemIdentification>`\n : \"\"\n }\n <cac:ClassifiedTaxCategory>\n <cbc:ID>${vatCategory}</cbc:ID>\n <cbc:Percent>${line.vatRate}</cbc:Percent>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:ClassifiedTaxCategory>\n ${\n line.standardItemId\n ? `<cac:StandardItemIdentification>\n <cbc:ID schemeID=\"${escapeXml(line.standardItemScheme ?? \"0160\")}\">${escapeXml(line.standardItemId)}</cbc:ID>\n </cac:StandardItemIdentification>`\n : \"\"\n }\n ${\n line.commodityCode && line.commodityScheme\n ? `<cac:CommodityClassification>\n <cbc:ItemClassificationCode listID=\"${escapeXml(line.commodityScheme)}\">${escapeXml(line.commodityCode)}</cbc:ItemClassificationCode>\n </cac:CommodityClassification>`\n : \"\"\n }\n ${(line.properties ?? []).map(\n (p) => `<cac:AdditionalItemProperty>\n <cbc:Name>${escapeXml(p.name)}</cbc:Name>\n <cbc:Value>${escapeXml(p.value)}</cbc:Value>\n </cac:AdditionalItemProperty>`\n ).join(\"\\n \")}\n </cac:Item>\n <cac:Price>\n <cbc:PriceAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(line.unitPrice)}</cbc:PriceAmount>\n ${line.baseQuantity != null ? `<cbc:BaseQuantity unitCode=\"${escapeXml(resolveUnitCode(line.baseQuantityUnit ?? line.unit ?? DEFAULT_UNIT))}\">${line.baseQuantity}</cbc:BaseQuantity>` : \"\"}\n </cac:Price>\n </cac:${lineTag}>`;\n}\n\nfunction buildInvoiceLineXml(line: InvoiceLine, index: number, currency: string): string {\n return buildDocumentLineXml(line, index, currency, \"InvoiceLine\", \"InvoicedQuantity\");\n}\n\ninterface TaxSubtotal {\n vatRate: number;\n vatCategory: string;\n taxableAmount: number;\n taxAmount: number;\n}\n\nfunction calculateTaxSubtotals(\n lines: InvoiceLine[],\n allowances?: AllowanceCharge[],\n charges?: AllowanceCharge[],\n): TaxSubtotal[] {\n const groups = new Map<string, TaxSubtotal>();\n\n function addToGroup(vatCategory: string, vatRate: number, amount: number) {\n const key = `${vatCategory}-${vatRate}`;\n const existing = groups.get(key);\n if (existing) {\n existing.taxableAmount = round2(existing.taxableAmount + amount);\n } else {\n groups.set(key, {\n vatRate,\n vatCategory,\n taxableAmount: amount,\n taxAmount: 0, // computed once per group below (BR-CO-17)\n });\n }\n }\n\n for (const line of lines) {\n addToGroup(line.vatCategory ?? \"S\", line.vatRate, calculateLineExtensionAmount(line));\n }\n\n for (const a of allowances ?? []) {\n addToGroup(a.vatCategory ?? \"S\", a.vatRate, -a.amount);\n }\n\n for (const c of charges ?? []) {\n addToGroup(c.vatCategory ?? \"S\", c.vatRate, c.amount);\n }\n\n // BR-CO-17: BT-117 = round2(group taxable base × rate), rounded ONCE per group —\n // accumulating per-line rounded taxes drifts a cent on sub-cent line amounts\n // (2 × €0.03 @21% → 0.02 instead of the compliant 0.01) and diverges from the\n // grouped figure the getpeppr gateway sends to the provider (GPR-833).\n return Array.from(groups.values()).map((subtotal) => ({\n ...subtotal,\n taxAmount: round2(subtotal.taxableAmount * (subtotal.vatRate / 100)),\n }));\n}\n\n// ─── Shared document-level XML fragments ───────────────────\n\ninterface DocumentTotals {\n lineExtensionAmount: number;\n allowanceTotalAmount: number;\n chargeTotalAmount: number;\n taxExclusiveAmount: number;\n totalTax: number;\n taxInclusiveAmount: number;\n payableAmount: number;\n taxSubtotals: TaxSubtotal[];\n}\n\nfunction calculateDocumentTotals(\n lines: InvoiceLine[],\n allowances?: AllowanceCharge[],\n charges?: AllowanceCharge[],\n): DocumentTotals {\n const taxSubtotals = calculateTaxSubtotals(lines, allowances, charges);\n const lineExtensionAmount = lines.reduce(\n (sum, line) => sum + calculateLineExtensionAmount(line),\n 0,\n );\n const allowanceTotalAmount = (allowances ?? []).reduce((sum, a) => sum + a.amount, 0);\n const chargeTotalAmount = (charges ?? []).reduce((sum, c) => sum + c.amount, 0);\n const taxExclusiveAmount = round2(lineExtensionAmount - allowanceTotalAmount + chargeTotalAmount);\n const totalTax = round2(taxSubtotals.reduce((sum, st) => sum + st.taxAmount, 0));\n const taxInclusiveAmount = round2(taxExclusiveAmount + totalTax);\n return {\n lineExtensionAmount,\n allowanceTotalAmount,\n chargeTotalAmount,\n taxExclusiveAmount,\n totalTax,\n taxInclusiveAmount,\n payableAmount: taxInclusiveAmount,\n taxSubtotals,\n };\n}\n\nfunction buildTaxTotalXml(taxSubtotals: TaxSubtotal[], totalTax: number, currency: string): string {\n const subtotalsXml = taxSubtotals\n .map(\n (st) => `\n <cac:TaxSubtotal>\n <cbc:TaxableAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(st.taxableAmount)}</cbc:TaxableAmount>\n <cbc:TaxAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(st.taxAmount)}</cbc:TaxAmount>\n <cac:TaxCategory>\n <cbc:ID>${st.vatCategory}</cbc:ID>\n <cbc:Percent>${st.vatRate}</cbc:Percent>\n <cac:TaxScheme>\n <cbc:ID>VAT</cbc:ID>\n </cac:TaxScheme>\n </cac:TaxCategory>\n </cac:TaxSubtotal>`,\n )\n .join(\"\");\n\n return `<cac:TaxTotal>\n <cbc:TaxAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totalTax)}</cbc:TaxAmount>\n ${subtotalsXml}\n </cac:TaxTotal>`;\n}\n\nfunction buildTaxCurrencyTotalXml(totalTax: number, taxCurrency: string, rate: number): string {\n const convertedAmount = Math.round(totalTax * rate * 100) / 100;\n return `<cac:TaxTotal>\n <cbc:TaxAmount currencyID=\"${escapeXml(taxCurrency)}\">${formatAmount(convertedAmount)}</cbc:TaxAmount>\n </cac:TaxTotal>`;\n}\n\ninterface LegalMonetaryTotalOptions {\n prepaidAmount?: number;\n roundingAmount?: number;\n}\n\n/** BT-115 arithmetic — the single formula behind both the rendered\n * cbc:PayableAmount and computeUblPayableAmount. Rounded via toFixed to be\n * EXACTLY the figure formatAmount renders (Math.round-based round2 drifts a\n * cent from the historic rendering on float dust, e.g. roundingAmount −0.325). */\nfunction payableFromTaxInclusive(\n taxInclusiveAmount: number,\n prepaidAmount?: number,\n roundingAmount?: number,\n): number {\n return Number((taxInclusiveAmount - (prepaidAmount ?? 0) + (roundingAmount ?? 0)).toFixed(2));\n}\n\n/** Monetary-only projection of an invoice / credit note — the fields that\n * determine the legal amount due. Party and routing data are irrelevant here. */\nexport interface UblMonetaryInput {\n lines: InvoiceLine[];\n allowances?: AllowanceCharge[];\n charges?: AllowanceCharge[];\n prepaidAmount?: number;\n roundingAmount?: number;\n}\n\n/**\n * BT-115 PayableAmount of the document — the legal amount due, integrating\n * line- and document-level allowances/charges, VAT, prepaid and rounding.\n * This is the SAME computation buildInvoiceXml/buildCreditNoteXml render into\n * cac:LegalMonetaryTotal, exposed so consumers (e.g. the getpeppr gateway's\n * settlement ledger, GPR-833) never re-derive the amount from a parallel\n * formula that would drift from the UBL on the network.\n */\nexport function computeUblPayableAmount(input: UblMonetaryInput): number {\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n return payableFromTaxInclusive(totals.taxInclusiveAmount, input.prepaidAmount, input.roundingAmount);\n}\n\nfunction buildLegalMonetaryTotalXml(totals: DocumentTotals, currency: string, options?: LegalMonetaryTotalOptions): string {\n const prepaid = options?.prepaidAmount;\n const rounding = options?.roundingAmount;\n const payableAmount = payableFromTaxInclusive(totals.taxInclusiveAmount, prepaid, rounding);\n\n return `<cac:LegalMonetaryTotal>\n <cbc:LineExtensionAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.lineExtensionAmount)}</cbc:LineExtensionAmount>\n <cbc:TaxExclusiveAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.taxExclusiveAmount)}</cbc:TaxExclusiveAmount>\n <cbc:TaxInclusiveAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.taxInclusiveAmount)}</cbc:TaxInclusiveAmount>\n ${totals.allowanceTotalAmount > 0 ? `<cbc:AllowanceTotalAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.allowanceTotalAmount)}</cbc:AllowanceTotalAmount>` : \"\"}\n ${totals.chargeTotalAmount > 0 ? `<cbc:ChargeTotalAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(totals.chargeTotalAmount)}</cbc:ChargeTotalAmount>` : \"\"}\n ${prepaid != null ? `<cbc:PrepaidAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(prepaid)}</cbc:PrepaidAmount>` : \"\"}\n ${rounding != null ? `<cbc:PayableRoundingAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(rounding)}</cbc:PayableRoundingAmount>` : \"\"}\n <cbc:PayableAmount currencyID=\"${escapeXml(currency)}\">${formatAmount(payableAmount)}</cbc:PayableAmount>\n </cac:LegalMonetaryTotal>`;\n}\n\nfunction buildPaymentMeansXml(input: InvoiceInput | CreditNoteInput): string {\n const paymentMeans = input.paymentMeans ?? DEFAULT_PAYMENT_MEANS;\n return `<cac:PaymentMeans>\n <cbc:PaymentMeansCode>${paymentMeans}</cbc:PaymentMeansCode>\n ${input.paymentReference ? `<cbc:PaymentID>${escapeXml(input.paymentReference)}</cbc:PaymentID>` : \"\"}\n ${\n input.paymentIban\n ? `<cac:PayeeFinancialAccount>\n <cbc:ID>${escapeXml(input.paymentIban)}</cbc:ID>\n ${\n input.paymentBic\n ? `<cac:FinancialInstitutionBranch>\n <cbc:ID>${escapeXml(input.paymentBic)}</cbc:ID>\n </cac:FinancialInstitutionBranch>`\n : \"\"\n }\n </cac:PayeeFinancialAccount>`\n : \"\"\n }\n </cac:PaymentMeans>`;\n}\n\nfunction buildCreditNoteLineXml(line: InvoiceLine, index: number, currency: string): string {\n return buildDocumentLineXml(line, index, currency, \"CreditNoteLine\", \"CreditedQuantity\");\n}\n\nfunction buildOrderReferenceXml(orderReference?: string, salesOrderReference?: string): string {\n if (!orderReference && !salesOrderReference) return \"\";\n const parts: string[] = [\"<cac:OrderReference>\"];\n if (orderReference) {\n parts.push(`<cbc:ID>${escapeXml(orderReference)}</cbc:ID>`);\n }\n if (salesOrderReference) {\n parts.push(`<cbc:SalesOrderID>${escapeXml(salesOrderReference)}</cbc:SalesOrderID>`);\n }\n parts.push(\"</cac:OrderReference>\");\n return parts.join(\"\");\n}\n\n/**\n * Build a Peppol BIS 3.0 compliant UBL 2.1 Invoice XML from a simple JSON input.\n */\nexport function buildInvoiceXml(input: InvoiceInput): string {\n const currency = input.currency ?? \"EUR\";\n const date = formatDate(input.date);\n const dueDate = input.dueDate ? formatDate(input.dueDate) : undefined;\n const hasTaxCurrency = input.taxCurrency && input.taxCurrency !== currency;\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n\n const linesXml = input.lines\n .map((line, i) => buildInvoiceLineXml(line, i, currency))\n .join(\"\");\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"${UBL_NS}\"\n xmlns:cac=\"${CAC_NS}\"\n xmlns:cbc=\"${CBC_NS}\">\n <cbc:CustomizationID>${PEPPOL_CUSTOMIZATION_ID}</cbc:CustomizationID>\n <cbc:ProfileID>${PEPPOL_PROFILE_ID}</cbc:ProfileID>\n <cbc:ID>${escapeXml(input.number)}</cbc:ID>\n <cbc:IssueDate>${date}</cbc:IssueDate>\n ${dueDate ? `<cbc:DueDate>${dueDate}</cbc:DueDate>` : \"\"}\n ${input.taxPointDate ? `<cbc:TaxPointDate>${formatDate(input.taxPointDate)}</cbc:TaxPointDate>` : \"\"}\n <cbc:InvoiceTypeCode>${input.invoiceTypeCode ?? (input.isCreditNote ? 381 : 380)}</cbc:InvoiceTypeCode>\n ${input.note ? `<cbc:Note>${escapeXml(input.note)}</cbc:Note>` : \"\"}\n ${input.accountingCost ? `<cbc:AccountingCost>${escapeXml(input.accountingCost)}</cbc:AccountingCost>` : \"\"}\n <cbc:DocumentCurrencyCode>${escapeXml(currency)}</cbc:DocumentCurrencyCode>\n ${hasTaxCurrency ? `<cbc:TaxCurrencyCode>${escapeXml(input.taxCurrency!)}</cbc:TaxCurrencyCode>` : \"\"}\n ${input.buyerReference ? `<cbc:BuyerReference>${escapeXml(input.buyerReference)}</cbc:BuyerReference>` : \"\"}\n ${input.invoicePeriod ? buildInvoicePeriodXml(input.invoicePeriod) : \"\"}\n ${buildOrderReferenceXml(input.orderReference, input.salesOrderReference)}\n ${input.despatchReference ? `<cac:DespatchDocumentReference><cbc:ID>${escapeXml(input.despatchReference)}</cbc:ID></cac:DespatchDocumentReference>` : \"\"}\n ${input.receiptReference ? `<cac:ReceiptDocumentReference><cbc:ID>${escapeXml(input.receiptReference)}</cbc:ID></cac:ReceiptDocumentReference>` : \"\"}\n ${input.contractReference ? `<cac:ContractDocumentReference><cbc:ID>${escapeXml(input.contractReference)}</cbc:ID></cac:ContractDocumentReference>` : \"\"}\n ${(input.attachments ?? []).map((a) => buildAttachmentXml(a)).join(\"\\n \")}\n ${input.projectReference ? `<cac:ProjectReference><cbc:ID>${escapeXml(input.projectReference)}</cbc:ID></cac:ProjectReference>` : \"\"}\n ${input.from ? buildPartyXml(input.from, \"AccountingSupplierParty\") : \"\"}\n ${buildPartyXml(input.to, \"AccountingCustomerParty\")}\n ${input.payeeParty ? buildPayeePartyXml(input.payeeParty) : \"\"}\n ${input.taxRepresentative ? buildTaxRepresentativePartyXml(input.taxRepresentative) : \"\"}\n ${input.delivery ? buildDeliveryXml(input.delivery) : \"\"}\n ${buildPaymentMeansXml(input)}\n ${input.paymentTerms ? `<cac:PaymentTerms>\\n <cbc:Note>${escapeXml(input.paymentTerms)}</cbc:Note>\\n </cac:PaymentTerms>` : \"\"}\n ${(input.allowances ?? []).map((a) => buildDocumentAllowanceChargeXml(a, false, currency)).join(\"\")}\n ${(input.charges ?? []).map((c) => buildDocumentAllowanceChargeXml(c, true, currency)).join(\"\")}\n ${hasTaxCurrency && input.taxCurrencyRate ? buildTaxCurrencyTotalXml(totals.totalTax, input.taxCurrency!, input.taxCurrencyRate) : \"\"}\n ${buildTaxTotalXml(totals.taxSubtotals, totals.totalTax, currency)}\n ${buildLegalMonetaryTotalXml(totals, currency, { prepaidAmount: input.prepaidAmount, roundingAmount: input.roundingAmount })}\n ${linesXml}\n</Invoice>`;\n}\n\n/**\n * Build a Peppol BIS 3.0 compliant UBL 2.1 Credit Note XML.\n *\n * Generates XML directly with correct CreditNote elements — no string replacement.\n */\nexport function buildCreditNoteXml(input: CreditNoteInput): string {\n const currency = input.currency ?? \"EUR\";\n const date = formatDate(input.date);\n const dueDate = input.dueDate ? formatDate(input.dueDate) : undefined;\n const hasTaxCurrency = input.taxCurrency && input.taxCurrency !== currency;\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n\n const linesXml = input.lines\n .map((line, i) => buildCreditNoteLineXml(line, i, currency))\n .join(\"\");\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CreditNote xmlns=\"${CREDIT_NOTE_NS}\"\n xmlns:cac=\"${CAC_NS}\"\n xmlns:cbc=\"${CBC_NS}\">\n <cbc:CustomizationID>${PEPPOL_CUSTOMIZATION_ID}</cbc:CustomizationID>\n <cbc:ProfileID>${PEPPOL_PROFILE_ID}</cbc:ProfileID>\n <cbc:ID>${escapeXml(input.number)}</cbc:ID>\n <cbc:IssueDate>${date}</cbc:IssueDate>\n ${dueDate ? `<cbc:DueDate>${dueDate}</cbc:DueDate>` : \"\"}\n ${input.taxPointDate ? `<cbc:TaxPointDate>${formatDate(input.taxPointDate)}</cbc:TaxPointDate>` : \"\"}\n <cbc:CreditNoteTypeCode>${input.invoiceTypeCode ?? 381}</cbc:CreditNoteTypeCode>\n ${input.note ? `<cbc:Note>${escapeXml(input.note)}</cbc:Note>` : \"\"}\n ${input.accountingCost ? `<cbc:AccountingCost>${escapeXml(input.accountingCost)}</cbc:AccountingCost>` : \"\"}\n <cbc:DocumentCurrencyCode>${escapeXml(currency)}</cbc:DocumentCurrencyCode>\n ${hasTaxCurrency ? `<cbc:TaxCurrencyCode>${escapeXml(input.taxCurrency!)}</cbc:TaxCurrencyCode>` : \"\"}\n ${input.buyerReference ? `<cbc:BuyerReference>${escapeXml(input.buyerReference)}</cbc:BuyerReference>` : \"\"}\n ${input.invoicePeriod ? buildInvoicePeriodXml(input.invoicePeriod) : \"\"}\n ${buildOrderReferenceXml(input.orderReference, input.salesOrderReference)}\n <cac:BillingReference><cac:InvoiceDocumentReference><cbc:ID>${escapeXml(input.invoiceReference)}</cbc:ID></cac:InvoiceDocumentReference></cac:BillingReference>\n ${input.despatchReference ? `<cac:DespatchDocumentReference><cbc:ID>${escapeXml(input.despatchReference)}</cbc:ID></cac:DespatchDocumentReference>` : \"\"}\n ${input.receiptReference ? `<cac:ReceiptDocumentReference><cbc:ID>${escapeXml(input.receiptReference)}</cbc:ID></cac:ReceiptDocumentReference>` : \"\"}\n ${input.contractReference ? `<cac:ContractDocumentReference><cbc:ID>${escapeXml(input.contractReference)}</cbc:ID></cac:ContractDocumentReference>` : \"\"}\n ${(input.attachments ?? []).map((a) => buildAttachmentXml(a)).join(\"\\n \")}\n ${input.projectReference ? `<cac:ProjectReference><cbc:ID>${escapeXml(input.projectReference)}</cbc:ID></cac:ProjectReference>` : \"\"}\n ${input.from ? buildPartyXml(input.from, \"AccountingSupplierParty\") : \"\"}\n ${buildPartyXml(input.to, \"AccountingCustomerParty\")}\n ${input.payeeParty ? buildPayeePartyXml(input.payeeParty) : \"\"}\n ${input.taxRepresentative ? buildTaxRepresentativePartyXml(input.taxRepresentative) : \"\"}\n ${input.delivery ? buildDeliveryXml(input.delivery) : \"\"}\n ${buildPaymentMeansXml(input)}\n ${input.paymentTerms ? `<cac:PaymentTerms>\\n <cbc:Note>${escapeXml(input.paymentTerms)}</cbc:Note>\\n </cac:PaymentTerms>` : \"\"}\n ${(input.allowances ?? []).map((a) => buildDocumentAllowanceChargeXml(a, false, currency)).join(\"\")}\n ${(input.charges ?? []).map((c) => buildDocumentAllowanceChargeXml(c, true, currency)).join(\"\")}\n ${hasTaxCurrency && input.taxCurrencyRate ? buildTaxCurrencyTotalXml(totals.totalTax, input.taxCurrency!, input.taxCurrencyRate) : \"\"}\n ${buildTaxTotalXml(totals.taxSubtotals, totals.totalTax, currency)}\n ${buildLegalMonetaryTotalXml(totals, currency, { prepaidAmount: input.prepaidAmount, roundingAmount: input.roundingAmount })}\n ${linesXml}\n</CreditNote>`;\n}\n","/**\n * Luhn mod-10 checksum used by French SIREN/SIRET identifiers.\n * Input is checked digits-only: callers must `.trim()` and ensure length.\n */\n\nexport function isValidLuhn(input: string): boolean {\n // Runtime guard for untyped (plain JS) callers: RegExp.test() coerces\n // numbers, but the digit loop below silently misbehaves on non-strings.\n if (typeof input !== \"string\") return false;\n if (!/^\\d+$/.test(input)) return false;\n let sum = 0;\n let alt = false;\n for (let i = input.length - 1; i >= 0; i--) {\n let n = input.charCodeAt(i) - 48;\n if (alt) {\n n *= 2;\n if (n > 9) n -= 9;\n }\n sum += n;\n alt = !alt;\n }\n return sum % 10 === 0;\n}\n\n/** SIREN of La Poste — the only unit whose SIRETs may fail Luhn (INSEE-documented). */\nconst LA_POSTE_SIREN = \"356000000\";\n\n/**\n * SIRET checksum per the INSEE validation contract:\n * - the embedded SIREN (first 9 digits) must itself be Luhn-valid;\n * - the full 14 digits must be Luhn-valid, EXCEPT for La Poste\n * (SIREN 356000000 exactly): its establishment SIRETs may fail Luhn and are\n * then valid when the sum of the 14 digits is a multiple of 5. The head\n * office (…00048) satisfies standard Luhn — the digit-sum rule is a\n * fallback, not a replacement.\n */\nexport function isValidLuhnSiret(input: string): boolean {\n if (typeof input !== \"string\") return false;\n if (!/^\\d{14}$/.test(input)) return false;\n\n const siren = input.slice(0, 9);\n if (!isValidLuhn(siren)) return false;\n\n if (isValidLuhn(input)) return true;\n\n if (siren === LA_POSTE_SIREN) {\n let sum = 0;\n for (let i = 0; i < input.length; i++) {\n sum += input.charCodeAt(i) - 48;\n }\n return sum % 5 === 0;\n }\n\n return false;\n}\n","/**\n * Country-Specific Validation Rules\n *\n * Produces warnings (not blocking errors) for country-specific invoice requirements.\n * Invoices can still be sent, but developers get helpful feedback about\n * local compliance expectations.\n *\n * Each rule has a unique ID: {CC}-{NN} (e.g., BE-01, FR-02).\n */\n\nimport type {\n InvoiceInput,\n ValidationError,\n ValidationWarning,\n} from \"../types/invoice.js\";\nimport { isValidLuhn, isValidLuhnSiret } from \"./checksums/index.js\";\n\n// ─── Result Type ─────────────────────────────────────────────\n\nexport interface CountryValidationResult {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nfunction warn(field: string, message: string, ruleId: string): ValidationWarning {\n return { field, message, ruleId };\n}\n\n// ─── Belgium (BE) ────────────────────────────────────────────\n\n/**\n * Belgian structured communication format: +++NNN/NNNN/NNNNN+++\n * The last 2 of the 12 digits are a mod-97 check digit.\n * If base mod 97 === 0, the check digit is 97.\n */\nconst BE_STRUCTURED_RE = /^\\+{3}\\d{3}\\/\\d{4}\\/\\d{5}\\+{3}$/;\n\nfunction validateBelgianCheckDigit(reference: string): boolean {\n // Extract the 12 digits from +++NNN/NNNN/NNNNN+++\n const digits = reference.replace(/[^0-9]/g, \"\");\n if (digits.length !== 12) return false;\n\n const base = parseInt(digits.slice(0, 10), 10);\n const check = parseInt(digits.slice(10, 12), 10);\n const expected = base % 97 === 0 ? 97 : base % 97;\n\n return check === expected;\n}\n\nfunction validateBelgium(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const ref = input.paymentReference;\n\n if (ref && BE_STRUCTURED_RE.test(ref)) {\n // It's in structured format — verify the checksum\n if (!validateBelgianCheckDigit(ref)) {\n warnings.push(\n warn(\n \"paymentReference\",\n `Belgian structured communication \"${ref}\" has an invalid mod-97 checksum. Verify the reference.`,\n \"BE-01\",\n ),\n );\n }\n } else if (!ref) {\n warnings.push(\n warn(\n \"paymentReference\",\n \"Belgian recipients typically expect a structured communication reference (+++NNN/NNNN/NNNNN+++ format).\",\n \"BE-02\",\n ),\n );\n }\n}\n\n/**\n * Seller-direction Belgian rules: only payment reference validation.\n * Separated from validateBelgium() to prevent buyer-focused rules\n * from accidentally firing with buyer data in a seller context.\n */\nfunction validateBelgiumSeller(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const ref = input.paymentReference;\n\n if (ref && BE_STRUCTURED_RE.test(ref)) {\n if (!validateBelgianCheckDigit(ref)) {\n warnings.push(\n warn(\n \"paymentReference\",\n `Belgian structured communication \"${ref}\" has an invalid mod-97 checksum. Verify the reference.`,\n \"BE-01\",\n ),\n );\n }\n } else if (!ref) {\n warnings.push(\n warn(\n \"paymentReference\",\n \"Belgian sellers typically include a structured communication reference (+++NNN/NNNN/NNNNN+++ format).\",\n \"BE-02\",\n ),\n );\n }\n}\n\n// ─── France (FR) ─────────────────────────────────────────────\n\nconst FR_SIREN_RE = /^\\d{9}$/;\nconst FR_SIRET_RE = /^\\d{14}$/;\n// The 2-character key may be alphanumeric, but letters I and O are excluded\n// from the key alphabet (confusable with 1 and 0).\nconst FR_VAT_RE = /^FR[0-9A-HJ-NP-Z]{2}\\d{9}$/;\n// Numeric-key form only — alphanumeric keys exist (rare but legitimate) and\n// the DGFiP key formula does not apply to them.\nconst FR_VAT_NUMERIC_KEY_RE = /^FR(\\d{2})(\\d{9})$/;\n\n/** Peppol schemes whose value is a SIREN or SIRET (SIRENE 0002, SIRET 0009, FR:CTC 0225). */\nconst FR_SIREN_BASED_SCHEMES = [\"0002\", \"0009\", \"0225\"];\n\n/**\n * DGFiP key formula for numeric-key French VAT numbers.\n * Deliberately the only VAT-content check: no Luhn on the embedded SIREN\n * (exotic but legitimate registrations, e.g. Monaco, may not carry an\n * INSEE Luhn-valid SIREN) and no cross-check against companyId (VAT-group\n * members — assujetti unique — legitimately use the group VAT number,\n * whose SIREN differs from their own).\n */\nfunction frVatKey(siren: string): number {\n return (12 + 3 * (Number(siren) % 97)) % 97;\n}\n\nfunction isValidSirenOrSiret(id: string): boolean {\n if (FR_SIREN_RE.test(id)) return isValidLuhn(id);\n if (FR_SIRET_RE.test(id)) return isValidLuhnSiret(id);\n return false;\n}\n\n/**\n * Buyer-side French identifier checks. Seller-side rules are deliberately\n * absent: `InvoiceInput.from` is deprecated/ignored (the seller is the API\n * key's Legal Entity, whose SIREN and VAT number the gateway verifies against\n * INSEE/VIES at onboarding), and VAT-rate policing is not possible offline\n * (rates depend on the place of supply, not on party countries).\n */\nfunction validateFrance(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const { companyId, companyIdScheme, vatNumber } = input.to ?? {};\n\n // companyId is only a SIREN/SIRET when no scheme is set or the scheme is\n // SIREN-based — a French company may legitimately use e.g. a GLN (0088).\n const companyIdIsSiren =\n !companyIdScheme || FR_SIREN_BASED_SCHEMES.includes(companyIdScheme);\n\n // \"Provided\" means anything but null/undefined/empty string — falsy garbage\n // like 0 or NaN from untyped JS callers must warn, not silently pass.\n if (companyId != null && companyId !== \"\" && companyIdIsSiren) {\n if (typeof companyId !== \"string\") {\n // No raw interpolation: String(Symbol) in a template literal throws.\n warnings.push(\n warn(\n \"to.companyId\",\n \"French company ID should be a string of 9 (SIREN) or 14 (SIRET) digits.\",\n \"FR-01\",\n ),\n );\n } else if (!FR_SIREN_RE.test(companyId) && !FR_SIRET_RE.test(companyId)) {\n warnings.push(\n warn(\n \"to.companyId\",\n `French company ID should be a 9-digit SIREN or 14-digit SIRET, got \"${companyId}\".`,\n \"FR-01\",\n ),\n );\n } else if (!isValidSirenOrSiret(companyId)) {\n warnings.push(\n warn(\n \"to.companyId\",\n `French company ID \"${companyId}\" has an invalid checksum. Verify the SIREN/SIRET.`,\n \"FR-01\",\n ),\n );\n }\n }\n\n if (vatNumber != null && vatNumber !== \"\") {\n if (typeof vatNumber !== \"string\") {\n warnings.push(\n warn(\n \"to.vatNumber\",\n \"French VAT number should be a string matching FR + 2 characters + 9 digits (SIREN).\",\n \"FR-02\",\n ),\n );\n } else if (!FR_VAT_RE.test(vatNumber)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `French VAT number should match format FR + 2 characters + 9 digits (SIREN), got \"${vatNumber}\".`,\n \"FR-02\",\n ),\n );\n } else {\n const numericKey = FR_VAT_NUMERIC_KEY_RE.exec(vatNumber);\n if (numericKey) {\n const [, key, siren] = numericKey;\n if (Number(key) !== frVatKey(siren)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `French VAT number \"${vatNumber}\" has an invalid verification key — expected FR${String(frVatKey(siren)).padStart(2, \"0\")}${siren}. Likely a typo.`,\n \"FR-03\",\n ),\n );\n }\n }\n }\n }\n}\n\n// ─── Italy (IT) ──────────────────────────────────────────────\n\nfunction validateItaly(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n if (!input.buyerReference) {\n warnings.push(\n warn(\n \"buyerReference\",\n \"Italian recipients (SDI) typically require a buyer reference (CIG/CUP code). Consider setting buyerReference.\",\n \"IT-01\",\n ),\n );\n }\n\n const peppolId = input.to?.peppolId;\n if (peppolId?.startsWith(\"0201:\")) {\n const fiscalCode = peppolId.slice(5);\n if (fiscalCode.length !== 11 && fiscalCode.length !== 16) {\n warnings.push(\n warn(\n \"to.peppolId\",\n `Italian fiscal code (after 0201:) should be 11 digits (partita IVA) or 16 characters (codice fiscale), got ${fiscalCode.length} characters.`,\n \"IT-02\",\n ),\n );\n }\n }\n}\n\n// ─── Netherlands (NL) ───────────────────────────────────────\n\nconst NL_KVK_RE = /^\\d{8}$/;\nconst NL_VAT_RE = /^NL\\d{9}B\\d{2}$/;\n\nfunction validateNetherlands(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const { companyId, vatNumber } = input.to ?? {};\n\n if (companyId && !NL_KVK_RE.test(companyId)) {\n warnings.push(\n warn(\n \"to.companyId\",\n `Dutch KVK number should be exactly 8 digits, got \"${companyId}\".`,\n \"NL-01\",\n ),\n );\n }\n\n if (vatNumber && !NL_VAT_RE.test(vatNumber)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `Dutch VAT number should match format NL + 9 digits + B + 2 digits, got \"${vatNumber}\".`,\n \"NL-02\",\n ),\n );\n }\n}\n\n// ─── Germany (DE) ────────────────────────────────────────────\n\nconst DE_VAT_RE = /^DE\\d{9}$/;\n\nfunction validateGermany(\n input: InvoiceInput,\n _errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const { vatNumber } = input.to ?? {};\n\n if (vatNumber && !DE_VAT_RE.test(vatNumber)) {\n warnings.push(\n warn(\n \"to.vatNumber\",\n `German VAT number should match format DE + 9 digits, got \"${vatNumber}\".`,\n \"DE-01\",\n ),\n );\n }\n}\n\n// ─── Main Entry Point ───────────────────────────────────────\n\n/**\n * Validate country-specific rules for an invoice.\n *\n * Returns warnings for common compliance issues specific to the\n * recipient's country. These are advisory — the invoice can still be sent.\n *\n * @example\n * ```ts\n * const result = validateCountryRules(invoice);\n * for (const w of result.warnings) {\n * console.warn(`[${w.ruleId}] ${w.field}: ${w.message}`);\n * }\n * ```\n */\nexport function validateCountryRules(input: InvoiceInput): CountryValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n const buyerCountry = input.to?.country;\n const sellerCountry = input.from?.country;\n\n // Buyer-country rules\n if (buyerCountry) {\n switch (buyerCountry) {\n case \"BE\": validateBelgium(input, errors, warnings); break;\n case \"FR\": validateFrance(input, errors, warnings); break;\n case \"IT\": validateItaly(input, errors, warnings); break;\n case \"NL\": validateNetherlands(input, errors, warnings); break;\n case \"DE\": validateGermany(input, errors, warnings); break;\n }\n }\n\n // Seller-country rules (skip if same as buyer to avoid duplicates)\n if (sellerCountry && sellerCountry !== buyerCountry) {\n switch (sellerCountry) {\n case \"BE\": validateBelgiumSeller(input, errors, warnings); break;\n }\n }\n\n return { errors, warnings };\n}\n","/**\n * Peppol Code Lists — Static lookup utilities\n *\n * Provides tree-shakeable helper functions for common Peppol-related code lists:\n * countries, EAS schemes, unit codes, VAT categories, and payment means.\n *\n * All data is static — no API calls, no side effects.\n */\n\n// ─── Countries (ISO 3166-1 alpha-2) ───────────────────────────────────────────\n\n/** EU + EEA + common Peppol trading partners (~50 most used) */\nconst COUNTRIES: ReadonlyMap<string, string> = new Map([\n // EU member states\n [\"AT\", \"Austria\"],\n [\"BE\", \"Belgium\"],\n [\"BG\", \"Bulgaria\"],\n [\"HR\", \"Croatia\"],\n [\"CY\", \"Cyprus\"],\n [\"CZ\", \"Czechia\"],\n [\"DK\", \"Denmark\"],\n [\"EE\", \"Estonia\"],\n [\"FI\", \"Finland\"],\n [\"FR\", \"France\"],\n [\"DE\", \"Germany\"],\n [\"GR\", \"Greece\"],\n [\"HU\", \"Hungary\"],\n [\"IE\", \"Ireland\"],\n [\"IT\", \"Italy\"],\n [\"LV\", \"Latvia\"],\n [\"LT\", \"Lithuania\"],\n [\"LU\", \"Luxembourg\"],\n [\"MT\", \"Malta\"],\n [\"NL\", \"Netherlands\"],\n [\"PL\", \"Poland\"],\n [\"PT\", \"Portugal\"],\n [\"RO\", \"Romania\"],\n [\"SK\", \"Slovakia\"],\n [\"SI\", \"Slovenia\"],\n [\"ES\", \"Spain\"],\n [\"SE\", \"Sweden\"],\n // EEA (non-EU)\n [\"IS\", \"Iceland\"],\n [\"LI\", \"Liechtenstein\"],\n [\"NO\", \"Norway\"],\n // Common Peppol trading partners\n [\"GB\", \"United Kingdom\"],\n [\"CH\", \"Switzerland\"],\n [\"US\", \"United States\"],\n [\"CA\", \"Canada\"],\n [\"AU\", \"Australia\"],\n [\"NZ\", \"New Zealand\"],\n [\"SG\", \"Singapore\"],\n [\"JP\", \"Japan\"],\n [\"KR\", \"South Korea\"],\n [\"IN\", \"India\"],\n [\"TR\", \"Turkey\"],\n [\"SA\", \"Saudi Arabia\"],\n [\"AE\", \"United Arab Emirates\"],\n [\"IL\", \"Israel\"],\n [\"ZA\", \"South Africa\"],\n [\"BR\", \"Brazil\"],\n [\"MX\", \"Mexico\"],\n [\"MY\", \"Malaysia\"],\n [\"TH\", \"Thailand\"],\n [\"ID\", \"Indonesia\"],\n]);\n\n/**\n * Get the country name for an ISO 3166-1 alpha-2 code.\n *\n * @param code - Two-letter country code (case-insensitive)\n * @returns Country name or `undefined` if not found\n *\n * @example\n * ```ts\n * getCountryName(\"FR\") // \"France\"\n * getCountryName(\"XX\") // undefined\n * ```\n */\nexport function getCountryName(code: string): string | undefined {\n return COUNTRIES.get(code.toUpperCase());\n}\n\n/**\n * Get all supported countries.\n *\n * @returns Array of `{ code, name }` objects sorted by name\n */\nexport function getAllCountries(): Array<{ code: string; name: string }> {\n return Array.from(COUNTRIES.entries())\n .map(([code, name]) => ({ code, name }))\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\n// ─── Currencies (ISO 4217) ────────────────────────────────────────────────────\n\n/**\n * A currency entry per ISO 4217.\n */\nexport interface Currency {\n /** Three-letter ISO 4217 code (uppercase) */\n code: string;\n /** Currency name */\n name: string;\n /** Standard minor unit count (e.g., 2 for EUR, 0 for JPY, 3 for BHD) */\n minorUnits: number;\n}\n\n/** Common Peppol/EU trade currencies (~30 most used) */\nconst CURRENCIES: ReadonlyMap<string, Currency> = new Map([\n [\"EUR\", { code: \"EUR\", name: \"Euro\", minorUnits: 2 }],\n [\"USD\", { code: \"USD\", name: \"US Dollar\", minorUnits: 2 }],\n [\"GBP\", { code: \"GBP\", name: \"Pound Sterling\", minorUnits: 2 }],\n [\"CHF\", { code: \"CHF\", name: \"Swiss Franc\", minorUnits: 2 }],\n [\"DKK\", { code: \"DKK\", name: \"Danish Krone\", minorUnits: 2 }],\n [\"NOK\", { code: \"NOK\", name: \"Norwegian Krone\", minorUnits: 2 }],\n [\"SEK\", { code: \"SEK\", name: \"Swedish Krona\", minorUnits: 2 }],\n [\"PLN\", { code: \"PLN\", name: \"Polish Zloty\", minorUnits: 2 }],\n [\"CZK\", { code: \"CZK\", name: \"Czech Koruna\", minorUnits: 2 }],\n [\"HUF\", { code: \"HUF\", name: \"Hungarian Forint\", minorUnits: 2 }],\n [\"RON\", { code: \"RON\", name: \"Romanian Leu\", minorUnits: 2 }],\n [\"BGN\", { code: \"BGN\", name: \"Bulgarian Lev\", minorUnits: 2 }],\n [\"HRK\", { code: \"HRK\", name: \"Croatian Kuna\", minorUnits: 2 }],\n [\"ISK\", { code: \"ISK\", name: \"Icelandic Krona\", minorUnits: 0 }],\n [\"TRY\", { code: \"TRY\", name: \"Turkish Lira\", minorUnits: 2 }],\n [\"JPY\", { code: \"JPY\", name: \"Japanese Yen\", minorUnits: 0 }],\n [\"CNY\", { code: \"CNY\", name: \"Chinese Yuan\", minorUnits: 2 }],\n [\"KRW\", { code: \"KRW\", name: \"South Korean Won\", minorUnits: 0 }],\n [\"INR\", { code: \"INR\", name: \"Indian Rupee\", minorUnits: 2 }],\n [\"SGD\", { code: \"SGD\", name: \"Singapore Dollar\", minorUnits: 2 }],\n [\"AUD\", { code: \"AUD\", name: \"Australian Dollar\", minorUnits: 2 }],\n [\"NZD\", { code: \"NZD\", name: \"New Zealand Dollar\", minorUnits: 2 }],\n [\"CAD\", { code: \"CAD\", name: \"Canadian Dollar\", minorUnits: 2 }],\n [\"BRL\", { code: \"BRL\", name: \"Brazilian Real\", minorUnits: 2 }],\n [\"MXN\", { code: \"MXN\", name: \"Mexican Peso\", minorUnits: 2 }],\n [\"ZAR\", { code: \"ZAR\", name: \"South African Rand\", minorUnits: 2 }],\n [\"AED\", { code: \"AED\", name: \"UAE Dirham\", minorUnits: 2 }],\n [\"SAR\", { code: \"SAR\", name: \"Saudi Riyal\", minorUnits: 2 }],\n [\"ILS\", { code: \"ILS\", name: \"Israeli Shekel\", minorUnits: 2 }],\n [\"HKD\", { code: \"HKD\", name: \"Hong Kong Dollar\", minorUnits: 2 }],\n [\"TWD\", { code: \"TWD\", name: \"Taiwan Dollar\", minorUnits: 2 }],\n]);\n\n/**\n * Look up a currency by ISO 4217 code.\n *\n * @param code - Three-letter currency code (case-insensitive)\n * @returns The currency entry or `undefined` if not found\n *\n * @example\n * ```ts\n * getCurrency(\"EUR\") // { code: \"EUR\", name: \"Euro\", minorUnits: 2 }\n * getCurrency(\"eu\") // undefined\n * ```\n */\nexport function getCurrency(code: string): Currency | undefined {\n return CURRENCIES.get(code.toUpperCase());\n}\n\n/**\n * Get all supported currencies.\n *\n * @returns Array sorted by ISO code ascending\n */\nexport function getAllCurrencies(): Currency[] {\n return Array.from(CURRENCIES.values()).sort((a, b) => a.code.localeCompare(b.code));\n}\n\n// ─── EAS Schemes (Peppol participant identifier schemes) ──────────────────────\n\n/**\n * A Peppol Electronic Address Scheme (EAS) entry.\n */\nexport interface EasScheme {\n /** Numeric EAS code (e.g. \"0088\") */\n code: string;\n /** Human-readable scheme name */\n name: string;\n /** ISO country code if scheme is country-specific */\n country?: string;\n}\n\nconst EAS_SCHEMES: readonly EasScheme[] = [\n { code: \"0002\", name: \"System Information et Repertoire des Entreprises et des Etablissements (SIRENE)\", country: \"FR\" },\n { code: \"0007\", name: \"Organisationsnummer\", country: \"SE\" },\n { code: \"0009\", name: \"SIRET-CODE\", country: \"FR\" },\n { code: \"0088\", name: \"EAN Location Code (GLN)\" },\n { code: \"0096\", name: \"Danish Chamber of Commerce (P-nummer)\", country: \"DK\" },\n { code: \"0184\", name: \"Danish Central Business Register (CVR)\", country: \"DK\" },\n { code: \"0190\", name: \"Dutch Chamber of Commerce (KVK)\", country: \"NL\" },\n { code: \"0191\", name: \"Organisatie Identificatie Nummer (OIN)\", country: \"NL\" },\n { code: \"0192\", name: \"Danish SE-number (Erhvervsstyrelsen)\", country: \"DK\" },\n { code: \"0195\", name: \"Singapore Unique Entity Number (UEN)\", country: \"SG\" },\n { code: \"0196\", name: \"Icelandic Kennitala\", country: \"IS\" },\n { code: \"0198\", name: \"Danish ERST id (Erhvervsstyrelsen)\", country: \"DK\" },\n { code: \"0200\", name: \"Lithuanian Legal Entity Register (GRIS)\", country: \"LT\" },\n { code: \"0201\", name: \"Italian Codice Destinatario\", country: \"IT\" },\n { code: \"0202\", name: \"Italian Fiscal Code (Codice Fiscale)\", country: \"IT\" },\n { code: \"0204\", name: \"German Leitweg-ID\", country: \"DE\" },\n { code: \"0208\", name: \"Belgian Enterprise Number (KBO/BCE)\", country: \"BE\" },\n { code: \"0209\", name: \"German Creditor Identifier (GS1)\", country: \"DE\" },\n { code: \"0210\", name: \"Italian Codice Fiscale (per IPA)\", country: \"IT\" },\n { code: \"0211\", name: \"Italian Partita IVA (VAT number)\", country: \"IT\" },\n { code: \"0212\", name: \"Finnish OVT code\", country: \"FI\" },\n { code: \"0213\", name: \"Finnish OP identifier\", country: \"FI\" },\n { code: \"0225\", name: \"FRCTC Electronic Address\", country: \"FR\" },\n { code: \"9957\", name: \"French VAT number\", country: \"FR\" },\n] as const;\n\n/** Lookup index: EAS code → scheme */\nconst EAS_BY_CODE: ReadonlyMap<string, EasScheme> = new Map(\n EAS_SCHEMES.map((s) => [s.code, s]),\n);\n\n/**\n * Look up an EAS scheme by its numeric code.\n *\n * @param code - EAS code (e.g. \"0088\", \"0208\")\n * @returns The scheme or `undefined` if not found\n *\n * @example\n * ```ts\n * getEasScheme(\"0208\") // { code: \"0208\", name: \"Belgian Enterprise Number (KBO/BCE)\", country: \"BE\" }\n * getEasScheme(\"9999\") // undefined\n * ```\n */\nexport function getEasScheme(code: string): EasScheme | undefined {\n return EAS_BY_CODE.get(code);\n}\n\n/**\n * Get all known EAS schemes.\n *\n * @returns Array of EAS schemes sorted by code\n */\nexport function getAllEasSchemes(): EasScheme[] {\n return [...EAS_SCHEMES];\n}\n\n// ─── Unit Codes (UN/ECE Recommendation 20) ────────────────────────────────────\n\n/** Human-readable aliases → UN/ECE unit codes */\nconst UNIT_ALIAS_MAP: Record<string, string> = {\n each: \"EA\", piece: \"EA\", pieces: \"EA\",\n hour: \"HUR\", hours: \"HUR\",\n day: \"DAY\", days: \"DAY\",\n week: \"WEE\", weeks: \"WEE\",\n month: \"MON\", months: \"MON\",\n year: \"ANN\", years: \"ANN\",\n kilogram: \"KGM\", kg: \"KGM\",\n meter: \"MTR\", metre: \"MTR\",\n liter: \"LTR\", litre: \"LTR\",\n unit: \"C62\", units: \"C62\",\n set: \"SET\", sets: \"SET\",\n pack: \"PK\", packs: \"PK\",\n minute: \"MIN\", minutes: \"MIN\",\n second: \"SEC\", seconds: \"SEC\",\n tonne: \"TNE\", ton: \"TNE\",\n \"square metre\": \"MTK\", \"square meter\": \"MTK\", sqm: \"MTK\",\n};\n\n/** Canonical unit codes with human-readable names */\nconst UNIT_CODES: ReadonlyMap<string, string> = new Map([\n [\"EA\", \"Each\"],\n [\"HUR\", \"Hour\"],\n [\"DAY\", \"Day\"],\n [\"WEE\", \"Week\"],\n [\"MON\", \"Month\"],\n [\"ANN\", \"Year\"],\n [\"MIN\", \"Minute\"],\n [\"SEC\", \"Second\"],\n [\"KGM\", \"Kilogram\"],\n [\"MTR\", \"Metre\"],\n [\"LTR\", \"Litre\"],\n [\"MTK\", \"Square metre\"],\n [\"TNE\", \"Tonne\"],\n [\"C62\", \"One (unit)\"],\n [\"SET\", \"Set\"],\n [\"PK\", \"Pack\"],\n]);\n\n/**\n * Resolve a human-readable unit name or alias to its UN/ECE Recommendation 20 code.\n *\n * Accepts both aliases (\"hours\", \"kg\") and canonical codes (\"HUR\", \"KGM\").\n * Unknown values pass through unchanged.\n *\n * @param input - Unit name or code\n * @returns Resolved UN/ECE code\n *\n * @example\n * ```ts\n * resolveUnit(\"hours\") // \"HUR\"\n * resolveUnit(\"HUR\") // \"HUR\"\n * resolveUnit(\"kg\") // \"KGM\"\n * resolveUnit(\"XYZ\") // \"XYZ\" (passthrough)\n * ```\n */\nexport function resolveUnit(input: string): string {\n return UNIT_ALIAS_MAP[input.toLowerCase()] ?? input;\n}\n\n/**\n * Get all supported unit codes with human-readable names.\n *\n * @returns Array of `{ code, name }` objects sorted by code\n */\nexport function getAllUnits(): Array<{ code: string; name: string }> {\n return Array.from(UNIT_CODES.entries())\n .map(([code, name]) => ({ code, name }))\n .sort((a, b) => a.code.localeCompare(b.code));\n}\n\n// ─── VAT Categories (UNCL 5305) ──────────────────────────────────────────────\n\n/**\n * A Peppol VAT category entry.\n */\nexport interface VatCategory {\n /** Category code (e.g. \"S\", \"Z\", \"AE\") */\n code: string;\n /** Short name */\n name: string;\n /** Longer description */\n description: string;\n /**\n * Whether getpeppr can actually put this category on the wire (GPR-1012).\n *\n * `false` means the code is valid under EN 16931 but our provider has no\n * vocabulary for it, so a send carrying it is refused with a 422\n * (`unsupported_vat_category`). Listing such a code without saying so is what\n * let `L` and `M` be advertised for months as usable regimes.\n */\n sendable: boolean;\n}\n\n/**\n * The ten codes `BR-CL-17` allows, verbatim: `' AE L M E S Z G O K B '`.\n *\n * ⚠️ This list held NINE until GPR-1012 — `B` (Italian split payment) was\n * missing, so a developer reading it concluded the network refuses a code it\n * accepts. And `L`/`M` were listed with no hint that they cannot be delivered.\n * Both halves of the same defect: a catalogue that describes the network must\n * describe it exactly, and a catalogue that implies capability must be honest\n * about ours.\n */\nconst VAT_CATEGORIES: readonly VatCategory[] = [\n { code: \"S\", name: \"Standard rate\", description: \"Standard VAT rate applies\", sendable: true },\n { code: \"Z\", name: \"Zero rated\", description: \"Zero-rated goods — VAT at 0% but right to deduct input VAT\", sendable: true },\n { code: \"E\", name: \"Exempt\", description: \"Exempt from VAT — no right to deduct input VAT\", sendable: true },\n { code: \"AE\", name: \"Reverse charge\", description: \"VAT reverse charge — customer accounts for VAT\", sendable: true },\n { code: \"K\", name: \"Intra-community supply\", description: \"Intra-community supply of goods — exempt with right to deduct\", sendable: true },\n { code: \"G\", name: \"Export outside the EU\", description: \"Free export item — tax not charged\", sendable: true },\n { code: \"O\", name: \"Outside scope of VAT\", description: \"Services outside scope of VAT\", sendable: true },\n { code: \"B\", name: \"Split payment\", description: \"Italian split payment — NOT sendable via getpeppr (no provider vocabulary)\", sendable: false },\n { code: \"L\", name: \"Canary Islands IGIC\", description: \"Canary Islands general indirect tax (IGIC) — NOT sendable via getpeppr (no provider vocabulary)\", sendable: false },\n { code: \"M\", name: \"Ceuta and Melilla IPSI\", description: \"Tax for production, services and importation in Ceuta and Melilla (IPSI) — NOT sendable via getpeppr (no provider vocabulary)\", sendable: false },\n] as const;\n\n/**\n * Get all Peppol VAT category codes, sendable or not.\n *\n * Filter on `sendable` to get only the ones getpeppr can deliver — the others\n * are listed so the catalogue matches EN 16931, not because they can be used.\n *\n * @returns Array of VAT categories\n */\nexport function getVatCategories(): VatCategory[] {\n return [...VAT_CATEGORIES];\n}\n\n// ─── Payment Means (UNCL 4461) ───────────────────────────────────────────────\n\n/**\n * A payment means code entry.\n */\nexport interface PaymentMeansCode {\n /** Numeric code */\n code: number;\n /** Human-readable description */\n name: string;\n}\n\nconst PAYMENT_MEANS_CODES: readonly PaymentMeansCode[] = [\n { code: 10, name: \"Cash\" },\n { code: 20, name: \"Cheque\" },\n { code: 30, name: \"Credit transfer\" },\n { code: 42, name: \"Payment to bank account\" },\n { code: 48, name: \"Bank card\" },\n { code: 49, name: \"Direct debit\" },\n { code: 57, name: \"Standing agreement\" },\n { code: 58, name: \"SEPA credit transfer\" },\n { code: 59, name: \"SEPA direct debit\" },\n] as const;\n\n/**\n * Get all supported payment means codes.\n *\n * @returns Array of payment means codes sorted by code\n */\nexport function getPaymentMeansCodes(): PaymentMeansCode[] {\n return [...PAYMENT_MEANS_CODES];\n}\n","/**\n * Invoice Validator\n *\n * Validates invoice data BEFORE conversion to XML.\n * Implements key Peppol BIS 3.0 business rules with human-readable error messages.\n *\n * Design principle: Errors tell you WHAT's wrong, WHERE it is, and HOW to fix it.\n * No developer should need to Google a Peppol rule ID.\n */\n\nimport type {\n InvoiceInput,\n InvoiceLine,\n Party,\n ValidationResult,\n ValidationError,\n ValidationWarning,\n} from \"../types/invoice.js\";\nimport { validateCountryRules } from \"./country-rules.js\";\nimport { getCurrency } from \"./code-lists.js\";\n\nfunction error(field: string, message: string, ruleId?: string, suggestion?: string): ValidationError {\n return { field, message, ruleId, suggestion };\n}\n\nfunction warning(field: string, message: string, ruleId?: string): ValidationWarning {\n return { field, message, ruleId };\n}\n\n/**\n * Type-guard that pushes a clean ValidationError when value is not a string.\n * Returns false to signal that downstream string-only checks should be skipped.\n * Prevents raw TypeError bubbling out of the SDK on malformed input (GPR-414 #3).\n */\nfunction assertString(\n value: unknown,\n fieldPath: string,\n errors: ValidationError[],\n): value is string {\n if (typeof value !== \"string\") {\n errors.push(error(\n fieldPath,\n `Expected string, received ${value === null ? \"null\" : typeof value}`,\n undefined,\n \"Check your payload — this field must be a text value\",\n ));\n return false;\n }\n return true;\n}\n\nconst ISO_DATE_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction validateParty(party: Party, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (party.name === undefined || party.name === null || party.name === \"\") {\n errors.push(error(`${path}.name`, \"Business name is required\", \"BR-06\"));\n } else if (!assertString(party.name, `${path}.name`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.name.trim()) {\n errors.push(error(`${path}.name`, \"Business name is required\", \"BR-06\"));\n }\n\n if (party.peppolId === undefined || party.peppolId === null || (party.peppolId as string) === \"\") {\n errors.push(\n error(\n `${path}.peppolId`,\n \"Peppol participant ID is required\",\n undefined,\n 'Format: \"scheme:id\", e.g. \"0208:0685660237\" for Belgian companies'\n )\n );\n } else if (!assertString(party.peppolId, `${path}.peppolId`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.peppolId.includes(\":\")) {\n errors.push(\n error(\n `${path}.peppolId`,\n `Invalid Peppol ID format: \"${party.peppolId}\"`,\n undefined,\n 'Must be \"scheme:id\" format. Common schemes: 0208 (Belgium), 0009 (France SIRET), 0204 (Germany Leitweg)'\n )\n );\n }\n\n if (party.country === undefined || party.country === null || party.country === \"\") {\n errors.push(error(`${path}.country`, \"Country code is required\", \"BR-11\"));\n } else if (!assertString(party.country, `${path}.country`, errors)) {\n // skip — assertString already pushed the type error\n } else if (party.country.length !== 2) {\n errors.push(\n error(\n `${path}.country`,\n `Invalid country code: \"${party.country}\"`,\n undefined,\n \"Must be ISO 3166-1 alpha-2 (e.g., BE, FR, DE, NL)\"\n )\n );\n }\n\n return errors;\n}\n\n/** Validate buyer postal address — required by Peppol BIS 3.0 (BG-8) and Storecove */\nfunction validateBuyerAddress(party: Party, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (party.street === undefined || party.street === null || party.street === \"\") {\n errors.push(error(`${path}.street`, \"Street address is required for the buyer\", \"BR-50\",\n 'e.g. \"123 Business Street\"'));\n } else if (!assertString(party.street, `${path}.street`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.street.trim()) {\n errors.push(error(`${path}.street`, \"Street address is required for the buyer\", \"BR-50\",\n 'e.g. \"123 Business Street\"'));\n }\n\n if (party.city === undefined || party.city === null || party.city === \"\") {\n errors.push(error(`${path}.city`, \"City is required for the buyer\", \"BR-51\",\n 'e.g. \"Brussels\"'));\n } else if (!assertString(party.city, `${path}.city`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.city.trim()) {\n errors.push(error(`${path}.city`, \"City is required for the buyer\", \"BR-51\",\n 'e.g. \"Brussels\"'));\n }\n\n if (party.postalCode === undefined || party.postalCode === null || party.postalCode === \"\") {\n errors.push(error(`${path}.postalCode`, \"Postal code is required for the buyer\", \"BR-53\",\n 'e.g. \"1000\"'));\n } else if (!assertString(party.postalCode, `${path}.postalCode`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!party.postalCode.trim()) {\n errors.push(error(`${path}.postalCode`, \"Postal code is required for the buyer\", \"BR-53\",\n 'e.g. \"1000\"'));\n }\n\n return errors;\n}\n\nfunction validateLine(line: InvoiceLine, index: number, isCreditNote = false): ValidationError[] {\n const errors: ValidationError[] = [];\n const path = `lines[${index}]`;\n\n if (line.description === undefined || line.description === null || line.description === \"\") {\n errors.push(error(`${path}.description`, \"Line item description is required\", \"BR-25\"));\n } else if (!assertString(line.description, `${path}.description`, errors)) {\n // skip — assertString already pushed the type error\n } else if (!line.description.trim()) {\n errors.push(error(`${path}.description`, \"Line item description is required\", \"BR-25\"));\n }\n\n if (line.quantity === undefined || line.quantity === null) {\n errors.push(error(`${path}.quantity`, \"Quantity is required\", \"BR-22\"));\n } else if (line.quantity <= 0 && !isCreditNote) {\n errors.push(\n error(\n `${path}.quantity`,\n `Quantity must be positive, got ${line.quantity}`,\n undefined,\n \"For returns/credits, use a credit note instead\"\n )\n );\n }\n\n if (line.unitPrice === undefined || line.unitPrice === null) {\n errors.push(error(`${path}.unitPrice`, \"Unit price is required\", \"BR-26\"));\n } else if (line.unitPrice < 0) {\n errors.push(\n error(\n `${path}.unitPrice`,\n `Unit price cannot be negative, got ${line.unitPrice}`,\n undefined,\n \"For discounts, use a negative quantity or a separate discount line\"\n )\n );\n }\n\n if (line.vatRate === undefined || line.vatRate === null) {\n errors.push(error(`${path}.vatRate`, \"VAT rate is required\", \"BR-CO-17\"));\n } else if (line.vatRate < 0 || line.vatRate > 100) {\n errors.push(\n error(\n `${path}.vatRate`,\n `VAT rate must be between 0 and 100, got ${line.vatRate}`,\n undefined,\n \"Use 0 for zero-rated, 21 for standard Belgian VAT, etc.\"\n )\n );\n }\n\n return errors;\n}\n\n/**\n * Validate an invoice input before sending.\n * Returns human-readable errors with suggestions for fixes.\n */\nexport function validateInvoice(input: InvoiceInput): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n // ── Invoice-level validation ──\n\n if (input.number === undefined || input.number === null || input.number === \"\") {\n errors.push(\n error(\"number\", \"Invoice number is required\", \"BR-02\", \"Must be unique per supplier\")\n );\n } else if (!assertString(input.number, \"number\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!input.number.trim()) {\n errors.push(\n error(\"number\", \"Invoice number is required\", \"BR-02\", \"Must be unique per supplier\")\n );\n }\n\n // ── Invoice type code validation ──\n\n const VALID_TYPE_CODES = [380, 381, 383, 384, 386, 389, 751];\n if (input.invoiceTypeCode != null && !VALID_TYPE_CODES.includes(input.invoiceTypeCode)) {\n errors.push(\n error(\n \"invoiceTypeCode\",\n `Invalid invoice type code: ${input.invoiceTypeCode}`,\n undefined,\n \"Valid codes: 380, 381, 383, 384, 386, 389, 751\"\n )\n );\n }\n\n // ── Credit note validation ──\n\n if (input.isCreditNote) {\n const ref = input.invoiceReference;\n if (ref === undefined || ref === null || ref === \"\") {\n errors.push(error(\n \"invoiceReference\",\n \"Reference to the original invoice is required for credit notes\",\n undefined,\n 'Set invoiceReference to the original invoice number (e.g., \"INV-001\")'\n ));\n } else if (!assertString(ref, \"invoiceReference\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!ref.trim()) {\n errors.push(error(\n \"invoiceReference\",\n \"Reference to the original invoice is required for credit notes\",\n undefined,\n 'Set invoiceReference to the original invoice number (e.g., \"INV-001\")'\n ));\n }\n }\n\n if (input.from) {\n warnings.push(\n warning(\n \"from\",\n \"Seller info is determined by your API key. The 'from' field is deprecated and ignored.\",\n )\n );\n }\n\n if (!input.to) {\n errors.push(error(\"to\", \"Buyer (to) is required\", \"BR-07\"));\n } else {\n errors.push(...validateParty(input.to, \"to\"));\n errors.push(...validateBuyerAddress(input.to, \"to\"));\n }\n\n if (input.payeeParty) {\n const ppName = input.payeeParty.name;\n if (ppName === undefined || ppName === null || ppName === \"\") {\n errors.push(error(\"payeeParty.name\", \"Payee party name is required\", \"BR-17\"));\n } else if (!assertString(ppName, \"payeeParty.name\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!ppName.trim()) {\n errors.push(error(\"payeeParty.name\", \"Payee party name is required\", \"BR-17\"));\n }\n\n const ppId = input.payeeParty.peppolId;\n if (ppId === undefined || ppId === null || (ppId as string) === \"\") {\n errors.push(\n error(\n \"payeeParty.peppolId\",\n \"Payee party Peppol ID is required\",\n undefined,\n 'Format: \"scheme:id\", e.g. \"0208:0685660237\"'\n )\n );\n } else if (!assertString(ppId, \"payeeParty.peppolId\", errors)) {\n // skip — assertString already pushed the type error\n } else if (!ppId.includes(\":\")) {\n errors.push(\n error(\n \"payeeParty.peppolId\",\n `Invalid Peppol ID format: \"${ppId}\"`,\n undefined,\n 'Must be \"scheme:id\" format'\n )\n );\n }\n }\n\n if (!input.lines || input.lines.length === 0) {\n errors.push(\n error(\"lines\", \"At least one line item is required\", \"BR-16\", \"Add items to the lines array\")\n );\n } else {\n for (let i = 0; i < input.lines.length; i++) {\n errors.push(...validateLine(input.lines[i]!, i, input.isCreditNote));\n }\n }\n\n // ── Date validation ──\n\n if (input.date) {\n if (!ISO_DATE_RE.test(input.date)) {\n errors.push(\n error(\"date\", `Invalid date format: \"${input.date}\"`, undefined, \"Use ISO 8601: YYYY-MM-DD\")\n );\n }\n }\n\n if (input.dueDate) {\n if (!ISO_DATE_RE.test(input.dueDate)) {\n errors.push(\n error(\n \"dueDate\",\n `Invalid due date format: \"${input.dueDate}\"`,\n undefined,\n \"Use ISO 8601: YYYY-MM-DD\"\n )\n );\n }\n }\n\n // ── TaxPointDate validation (BT-7) ──\n\n if (input.taxPointDate) {\n if (!ISO_DATE_RE.test(input.taxPointDate)) {\n errors.push(\n error(\n \"taxPointDate\",\n `Invalid tax point date format: \"${input.taxPointDate}\"`,\n undefined,\n \"Use ISO 8601: YYYY-MM-DD\"\n )\n );\n }\n }\n\n // ── RoundingAmount validation (BT-114) ──\n\n if (input.roundingAmount !== undefined && input.roundingAmount !== null) {\n if (input.roundingAmount < -0.99 || input.roundingAmount > 0.99) {\n errors.push(\n error(\n \"roundingAmount\",\n `Rounding amount must be between -0.99 and 0.99, got ${input.roundingAmount}`,\n undefined,\n \"Rounding is stored as integer cents (±99). Use values like 0.50 or -0.25.\"\n )\n );\n }\n }\n\n // ── BuyerReference / OrderReference (BT-10) ──\n\n if (!input.buyerReference && !input.orderReference) {\n warnings.push(\n warning(\n \"buyerReference\",\n \"Either buyerReference or orderReference is required by Peppol BIS 3.0 (BT-10).\",\n \"BR-10\"\n )\n );\n }\n\n // ── TaxCurrencyCode validation ──\n\n if (input.taxCurrency && input.taxCurrency !== (input.currency ?? \"EUR\") && !input.taxCurrencyRate) {\n errors.push(\n error(\n \"taxCurrencyRate\",\n \"Tax currency rate is required when taxCurrency differs from document currency\",\n \"BR-53\",\n \"Set taxCurrencyRate to the exchange rate from document currency to tax currency\"\n )\n );\n }\n\n if (input.taxCurrency && input.taxCurrency === (input.currency ?? \"EUR\")) {\n warnings.push(\n warning(\"taxCurrency\", \"Tax currency is the same as document currency — TaxCurrencyCode will be omitted\")\n );\n }\n\n if (input.taxCurrencyRate !== undefined && input.taxCurrencyRate <= 0) {\n errors.push(\n error(\n \"taxCurrencyRate\",\n `Tax currency rate must be positive, got ${input.taxCurrencyRate}`,\n undefined,\n \"Set to the exchange rate from document currency to tax currency\"\n )\n );\n }\n\n // ── Currency code validation (ISO 4217) ──\n\n if (input.currency && !getCurrency(input.currency)) {\n errors.push(\n error(\n \"currency\",\n `Invalid currency code: \"${input.currency}\"`,\n undefined,\n 'Use ISO 4217 (e.g., \"EUR\", \"USD\", \"GBP\", \"JPY\"). See https://getpeppr.dev/docs/types/#currency'\n )\n );\n }\n\n if (input.taxCurrency && !getCurrency(input.taxCurrency)) {\n errors.push(\n error(\n \"taxCurrency\",\n `Invalid tax currency code: \"${input.taxCurrency}\"`,\n undefined,\n 'Use ISO 4217 (e.g., \"EUR\", \"USD\")'\n )\n );\n }\n\n // ── Warnings (non-blocking) ──\n\n if (!input.dueDate) {\n warnings.push(warning(\"dueDate\", \"No due date specified. Recommended for payment terms.\", \"BR-09\"));\n }\n\n if (!input.to?.vatNumber) {\n warnings.push(warning(\"to.vatNumber\", \"Buyer VAT number not provided. May be required for B2B.\"));\n }\n\n if (input.paymentMeans === 30 && !input.paymentIban) {\n warnings.push(\n warning(\n \"paymentIban\",\n \"Payment means is credit transfer but no IBAN provided. Buyer won't know where to pay.\"\n )\n );\n }\n\n // ── Cross-field validation ──\n\n if (input.from?.peppolId && input.to?.peppolId && input.from.peppolId === input.to.peppolId) {\n errors.push(\n error(\n \"to.peppolId\",\n \"Buyer and seller cannot have the same Peppol ID\",\n undefined,\n \"Check that 'from' and 'to' are different parties\"\n )\n );\n }\n\n // ── Country-specific rules (advisory warnings) ──\n\n const countryResult = validateCountryRules(input);\n warnings.push(...countryResult.warnings);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","import type { DocumentStatus } from \"../types/invoice\";\n\n/** Wait-semantics family of a status (spec parente §3.12 — orthogonal to its §8.1 position). */\nexport type StatusFamily = \"progress\" | \"terminal-success\" | \"terminal-failure\" | \"fallback\";\n\nexport interface StatusPrecedenceEntry {\n status: DocumentStatus;\n family: StatusFamily;\n}\n\n/**\n * The §8.1 synthesis precedence as DATA — index 0 = most final. `waitFor()`\n * derives its terminal sets from the `family` column instead of a hard-coded\n * list (§8.7). The console locks this table against its own `synthesize()`\n * branch order, so a drift between packages fails CI, not production.\n */\nexport const STATUS_PRECEDENCE: readonly StatusPrecedenceEntry[] = [\n { status: \"failed\", family: \"terminal-failure\" },\n { status: \"rejected\", family: \"terminal-failure\" },\n { status: \"paid\", family: \"terminal-success\" },\n { status: \"partially_paid\", family: \"progress\" },\n { status: \"accepted\", family: \"progress\" },\n { status: \"conditionally_accepted\", family: \"progress\" },\n { status: \"under_query\", family: \"progress\" },\n { status: \"in_process\", family: \"progress\" },\n { status: \"cleared\", family: \"progress\" },\n { status: \"delivered\", family: \"progress\" },\n { status: \"acknowledged\", family: \"progress\" },\n // Terminal for developer wait semantics only — stays rank 40 (non-terminal)\n // in the projection guard (§3.12 two-level terminality).\n { status: \"no_action\", family: \"terminal-failure\" },\n { status: \"submitted\", family: \"progress\" },\n { status: \"unknown\", family: \"fallback\" },\n];\n\nexport function statusFamily(status: DocumentStatus): StatusFamily {\n return STATUS_PRECEDENCE.find((e) => e.status === status)?.family ?? \"fallback\";\n}\n\n/** Derived — never hard-code this list again (§8.7). */\nexport const TERMINAL_FAILURE_STATUSES: readonly DocumentStatus[] = STATUS_PRECEDENCE\n .filter((e) => e.family === \"terminal-failure\")\n .map((e) => e.status);\n","/** SDK version — keep in sync with package.json on each release. */\nexport const SDK_VERSION = \"4.3.0\";\n","/**\n * getpeppr SDK Client\n *\n * The main entry point. Designed to feel like Stripe's SDK:\n *\n * const peppol = new Peppol({ apiKey: \"sk_live_...\" });\n * const result = await peppol.invoices.send({ from, to, lines });\n *\n * All requests go through the getpeppr API gateway (api.getpeppr.dev),\n * which handles Peppol delivery, billing, and usage tracking.\n * Use `baseUrl` to point to a custom instance or localhost.\n */\n\nimport type {\n PeppolConfig,\n InvoiceInput,\n CreditNoteInput,\n SendResult,\n StatusDetail,\n StatusDetailEntry,\n ValidationResult,\n WebhookEvent,\n RetryConfig,\n DocumentStatus,\n WaitForOptions,\n PaginatedResult,\n InvoiceSummary,\n GetStatusOptions,\n ListInvoicesOptions,\n DirectoryEntry,\n DirectorySearchOptions,\n DirectorySearchResult,\n PeppolId,\n DocumentFormat,\n ServerValidationResult,\n EventEntry,\n ListEventsOptions,\n BatchSendOptions,\n BatchSendResult,\n InvoiceOperationOptions,\n RequestLogEntry,\n ResponseLogEntry,\n Contact,\n ContactInput,\n ListContactsOptions,\n BankAccount,\n BankAccountInput,\n ListBankAccountsOptions,\n ImportInvoiceOptions,\n TransportType,\n Transport,\n TransportInput,\n TransportUpdateInput,\n MarkAsState,\n MarkAsOptions,\n InvoiceUpdateInput,\n LegalEntityInput,\n LegalEntity,\n LegalEntityStatus,\n ListLegalEntitiesOptions,\n ArchiveLegalEntityResult,\n AttestationInput,\n AttestationResult,\n LegalEntityRequestOptions,\n AccountIdentity,\n AccountIdentityLegalEntity,\n AccountIdentityAddress,\n AccountIdentifier,\n} from \"../types/invoice.js\";\nimport { buildInvoiceXml, buildCreditNoteXml } from \"./ubl-builder.js\";\nimport { validateInvoice } from \"./validator.js\";\nimport { statusFamily, TERMINAL_FAILURE_STATUSES } from \"./status-precedence.js\";\nimport { SDK_VERSION } from \"../version.js\";\n\n// ─── Backend Adapter Interface ──────────────────────────────\n\n/**\n * Backend adapter interface for the SDK's transport layer.\n * The default implementation hits the getpeppr API gateway.\n *\n * @internal transport contract. This interface is NOT meant to be implemented by\n * consumers — `PeppolConfig` exposes no adapter injection point, so the only\n * implementer is the built-in `GetpepprAdapter`. New gateway features add methods\n * here as minor releases (as contacts/bank-accounts/transports did); external\n * `implements BackendAdapter` is unsupported and may break across minor versions.\n */\nexport interface BackendAdapter {\n /** Provider name (for logging) */\n readonly name: string;\n /** Send an invoice as structured JSON (gateway handles UBL generation) */\n sendInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult>;\n /** Create a draft invoice without sending (POST /invoices, no send_after_import) */\n createInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult>;\n /** Send an existing draft invoice by ID (POST /invoices/send/{id}, returns 204) */\n sendInvoiceById(id: string): Promise<void>;\n /** @deprecated Credit notes now route through sendInvoice with isCreditNote: true */\n sendCreditNote(input: CreditNoteInput): Promise<SendResult>;\n /** Validate an invoice server-side (free, no metering) */\n validateDocument(input: InvoiceInput): Promise<{ valid: boolean; errors: string[] }>;\n /** List invoices with pagination and filtering */\n listInvoices(options?: ListInvoicesOptions): Promise<PaginatedResult<InvoiceSummary>>;\n /** Get document status by ID */\n getStatus(documentId: string, options?: GetStatusOptions): Promise<SendResult>;\n /** Look up a Peppol participant in the directory */\n lookupDirectory(scheme: string, id: string): Promise<DirectoryEntry>;\n /** Search the Peppol Directory for participants */\n searchDirectory?(params: Record<string, string>): Promise<DirectorySearchResult>;\n /** Export an invoice in a specific format (e.g., PDF) — returns raw binary */\n getInvoiceAs(id: string, format: DocumentFormat): Promise<ArrayBuffer>;\n /** Validate an invoice server-side through the getpeppr gateway's offline SDK-backed checks. */\n validateDocumentServer(input: InvoiceInput): Promise<ServerValidationResult>;\n /** List events with optional filtering and pagination */\n listEvents(options?: ListEventsOptions): Promise<PaginatedResult<EventEntry>>;\n /** Acknowledge a received invoice (POST /invoices/{id}/ack) */\n acknowledgeInvoice(id: string): Promise<SendResult>;\n /** List contacts with optional filtering and pagination */\n listContacts(options?: ListContactsOptions): Promise<PaginatedResult<Contact>>;\n /** Get a single contact by ID */\n getContact(id: string): Promise<Contact>;\n /** Create a new contact */\n createContact(input: ContactInput): Promise<Contact>;\n /** Update an existing contact */\n updateContact(id: string, input: Partial<ContactInput>): Promise<Contact>;\n /** Delete a contact */\n deleteContact(id: string): Promise<void>;\n /** List bank accounts with optional pagination */\n listBankAccounts(options?: ListBankAccountsOptions): Promise<PaginatedResult<BankAccount>>;\n /** Get a single bank account by ID */\n getBankAccount(id: string): Promise<BankAccount>;\n /** Create a new bank account */\n createBankAccount(input: BankAccountInput): Promise<BankAccount>;\n /** Update an existing bank account */\n updateBankAccount(id: string, input: Partial<BankAccountInput>): Promise<BankAccount>;\n /** Delete a bank account */\n deleteBankAccount(id: string): Promise<void>;\n /** Import an invoice from a file (XML, PDF, etc.) */\n importInvoice(options: ImportInvoiceOptions): Promise<SendResult>;\n /** List all available transport types (global, not account-scoped) */\n listTransportTypes(): Promise<TransportType[]>;\n /** List configured transports for this account */\n listTransports(): Promise<Transport[]>;\n /** Get a single transport by code */\n getTransport(code: string): Promise<Transport>;\n /** Create a new transport */\n createTransport(input: TransportInput): Promise<Transport>;\n /** Update an existing transport */\n updateTransport(code: string, input: TransportUpdateInput): Promise<Transport>;\n /** Delete a transport */\n deleteTransport(code: string): Promise<void>;\n /** Update an existing invoice */\n updateInvoice(id: string, input: InvoiceUpdateInput): Promise<SendResult>;\n /** Delete an invoice */\n deleteInvoice(id: string): Promise<SendResult>;\n /** Transition an invoice to a new state */\n markInvoiceAs(id: string, state: MarkAsState, options?: MarkAsOptions): Promise<SendResult>;\n /** Create a sub-tenant Legal Entity (master key). */\n createLegalEntity(input: LegalEntityInput, options?: LegalEntityRequestOptions): Promise<LegalEntity>;\n /** Fetch a single sub-tenant Legal Entity by id (master key). */\n getLegalEntity(id: string): Promise<LegalEntity>;\n /** List sub-tenant Legal Entities (master key), paginated. */\n listLegalEntities(options?: ListLegalEntitiesOptions): Promise<PaginatedResult<LegalEntity>>;\n /** Archive (soft-delete) a sub-tenant Legal Entity (master key). */\n archiveLegalEntity(id: string): Promise<ArchiveLegalEntityResult>;\n /** Request (or resend) a sub-tenant attestation — production only (master key). */\n requestLegalEntityAttestation(id: string, input: AttestationInput, options?: LegalEntityRequestOptions): Promise<AttestationResult>;\n /** Read the Peppol identity of the account behind this API key — works with ANY key. */\n getIdentity(): Promise<AccountIdentity>;\n}\n\n// ─── Retry & Header Utilities ────────────────────────────────────────\n\n/**\n * Case-insensitive header lookup. Per RFC 7230 §3.2, HTTP header names are\n * case-insensitive. Some adapters (axios default, Cloudflare Workers, proxies) lowercase\n * header keys, which made the strict bracket lookup miss user-supplied lowercase\n * keys and silently disabled retry safety on POST requests with idempotency keys.\n *\n * When multiple headers match (e.g. \"Idempotency-Key\" and \"idempotency-key\" both present),\n * returns the value of the first matching key in insertion order.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function findHeaderCaseInsensitive(\n headers: Record<string, string> | undefined,\n name: string,\n): string | undefined {\n if (!headers) return undefined;\n const target = name.toLowerCase();\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === target) return value;\n }\n return undefined;\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction calculateRetryDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n retryAfterMs?: number,\n): number {\n if (retryAfterMs !== undefined) return Math.min(retryAfterMs, maxDelayMs);\n const exponentialDelay = initialDelayMs * Math.pow(2, attempt);\n const jitter = Math.random() * initialDelayMs;\n return Math.min(exponentialDelay + jitter, maxDelayMs);\n}\n\n/**\n * Parse the Retry-After header value into milliseconds.\n * Supports integer seconds (e.g., \"1\", \"60\") and HTTP-date format.\n * Returns undefined if the header is missing or unparseable.\n */\nfunction parseRetryAfter(headerValue: string | null): number | undefined {\n if (!headerValue) return undefined;\n\n // Try integer seconds first (most common for rate limiters)\n const seconds = Number(headerValue);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n // Try HTTP-date format (e.g., \"Wed, 21 Oct 2025 07:28:00 GMT\")\n const dateMs = Date.parse(headerValue);\n if (!Number.isNaN(dateMs)) {\n const delayMs = dateMs - Date.now();\n return delayMs > 0 ? delayMs : 0;\n }\n\n return undefined;\n}\n\n/**\n * C0 controls, DEL, and C1 (U+0080–U+009F).\n *\n * ⛔ These matter ONLY on the parsed path, and that is the whole point. JSON\n * forbids raw C0 inside a string, so they always travel the wire escaped and\n * the old verbatim format kept them inert. `JSON.parse` decodes them into real\n * bytes, and a terminal ACTS on them: `ESC [ 2K` clears the line, so a third\n * party's text overwrites what was just printed, and a newline forges a log\n * line (CWE-117/150). The CLI writes `e.message` straight to stderr.\n *\n * C1 is included because U+009B is a single-character CSI — some terminals\n * treat it exactly like `ESC [`.\n */\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001F\\u007F-\\u009F]/g;\n\n/**\n * Accept a `docs` value only if it is an absolute http(s) URL, and return the\n * PARSED form.\n *\n * Two distinct reasons, both measured. `new URL` normalises control characters\n * out of the href — most are percent-encoded (`ESC` becomes `%1B`) while TAB,\n * LF and CR are STRIPPED outright per the WHATWG parser — so the link cannot\n * smuggle an escape sequence either way. And it happily accepts\n * `javascript:`: parsing alone is not validation, the protocol has to be\n * checked.\n */\n/** Replace every control character with a space. */\nfunction stripControls(value: string): string {\n return value.replace(CONTROL_CHARACTERS, \" \");\n}\n\n/**\n * Own-property read. `Object.hasOwn`, never a bare index: this object comes off\n * the wire, so an inherited value from a host that polluted `Object.prototype`\n * would otherwise be preferred over the fallback.\n */\nfunction readOwn(source: object, key: string): unknown {\n return Object.hasOwn(source, key) ? (source as Record<string, unknown>)[key] : undefined;\n}\n\n/**\n * Read a field as a displayable sentence, or `null` if it cannot be one.\n *\n * ⛔ Sanitises BEFORE the emptiness check, never after: control characters are\n * not whitespace, so trimming first would accept a value that is technically\n * non-empty and says nothing.\n */\nfunction readSentence(source: object, key: string): string | null {\n const value = readOwn(source, key);\n if (typeof value !== \"string\") return null;\n const cleaned = stripControls(value).trim();\n return cleaned === \"\" ? null : cleaned;\n}\n\nfunction safeDocsUrl(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n let parsed: URL;\n try {\n parsed = new URL(value);\n } catch {\n return null;\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") return null;\n return parsed.href;\n}\n\n/**\n * Build the human-readable message for a failed response.\n *\n * The gateway answers 4xx with `{ error, code, docs }`. Pasting that JSON into\n * `Error.message` leaks braces to humans — the CLI prints `e.message` straight\n * to the terminal — so when the envelope is recognisable we show the sentence\n * and, when present, the docs link.\n *\n * Deliberately general rather than keyed on any one `code`: every gateway 4xx\n * shares this envelope, and a special case would leave the rest printing JSON.\n *\n * Falls back to the verbatim body for anything unrecognised — a proxy's HTML, a\n * bare JSON scalar, an envelope with no usable sentence. The fallback must stay\n * byte-identical to the old format: it is what non-gateway failures still show.\n *\n * ⚠️ This shapes the MESSAGE only. `PeppolApiError.responseBody` keeps the raw\n * body because `.code` reparses it.\n */\nfunction formatApiErrorMessage(status: number, rawBody: string): string {\n // ⛔ The fallback is sanitised TOO, and that is not belt-and-braces.\n //\n // JSON forbids only C0 (U+0000–U+001F); DEL and C1 travel the wire RAW. So a\n // body whose sentence is nothing but those characters cleans to empty, falls\n // through to here, and the raw body carries them straight into the message —\n // the exact injection the sanitiser exists to stop, through its own back door\n // (found by gate, second pass).\n //\n // This gives up \"the fallback is byte-identical to the old format\". That\n // promise was never worth a live injection path: an unrecognised body is\n // still shown verbatim, minus characters a terminal would ACT on.\n const verbatim = `getpeppr API error (${status}): ${stripControls(rawBody)}`;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawBody);\n } catch {\n return verbatim;\n }\n\n // A bare string, array or null parses fine but is not an envelope.\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return verbatim;\n }\n\n // ⛔ `message` FIRST, then `error`. Several routes under `app/api/v1/` —\n // `invoices/route.ts`, `invoices/send/[id]`, `onboarding/legal-entity` —\n // emit `{ error: <machine code>, message: <human sentence> }`. Reading\n // `error` there prints \"unsupported_vat_category\" and drops the sentence\n // explaining what to do, which is strictly worse than the raw JSON this\n // replaced. Most other routes put the sentence in `error`, so both shapes\n // have to work.\n //\n // ⚠️ No count here on purpose: this comment first said \"nine sites\", the real\n // figure was eleven, and it moves whenever a route is added. Name the files,\n // not the tally (the GPR-1019 lesson).\n const sentence = readSentence(parsed, \"message\") ?? readSentence(parsed, \"error\");\n if (sentence === null) return verbatim;\n\n const link = safeDocsUrl(readOwn(parsed, \"docs\"));\n return `getpeppr API error (${status}): ${sentence}${link ? ` See ${link}` : \"\"}`;\n}\n\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof PeppolApiError) {\n return RETRYABLE_STATUS_CODES.has(error.statusCode);\n }\n // Retry on timeout/abort errors\n if (error instanceof Error && error.name === \"AbortError\") {\n return true;\n }\n // Retry on transient network errors (DNS failure, connection refused, reset, timeout, etc.)\n if (error instanceof TypeError && /fetch failed|network|ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT/i.test(error.message)) {\n return true;\n }\n return false;\n}\n\n// ─── getpeppr API Adapter ───────────────────────────────────\n\nconst DEFAULT_BASE_URL = \"https://api.getpeppr.dev/v1\";\n\nclass GetpepprAdapter implements BackendAdapter {\n readonly name = \"getpeppr\";\n private baseUrl: string;\n private apiKey: string;\n private timeout: number;\n private retryConfig: Required<RetryConfig>;\n private onRequest?: (entry: RequestLogEntry) => void;\n private onResponse?: (entry: ResponseLogEntry) => void;\n\n constructor(config: PeppolConfig) {\n this.apiKey = config.apiKey;\n this.timeout = config.timeout ?? 30_000;\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.retryConfig = {\n maxRetries: config.retry?.maxRetries ?? 3,\n initialDelayMs: config.retry?.initialDelayMs ?? 500,\n maxDelayMs: config.retry?.maxDelayMs ?? 30_000,\n };\n this.onRequest = config.onRequest;\n this.onResponse = config.onResponse;\n }\n\n private async request<T>(method: string, path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<T> {\n const { maxRetries, initialDelayMs, maxDelayMs } = this.retryConfig;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await this.doRequest<T>(method, path, body, extraHeaders);\n } catch (err) {\n lastError = err;\n // 429 (rate limit) is always safe to retry — the request was never processed.\n // For other retryable errors (500, 502, 503, 504, network failures),\n // only retry non-idempotent methods (POST, PUT, PATCH) if an Idempotency-Key was\n // provided, to prevent duplicate side effects (e.g., sending the same invoice twice).\n const is429 = err instanceof PeppolApiError && err.statusCode === 429;\n const isSafeMethod = /^(GET|DELETE|HEAD)$/i.test(method);\n const hasIdempotencyKey = !!findHeaderCaseInsensitive(extraHeaders, \"Idempotency-Key\");\n const canRetry = is429 || isSafeMethod || hasIdempotencyKey;\n if (attempt < maxRetries && canRetry && isRetryableError(err)) {\n const retryAfterMs = err instanceof PeppolApiError ? err.retryAfterMs : undefined;\n await sleep(calculateRetryDelay(attempt, initialDelayMs, maxDelayMs, retryAfterMs));\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private async doRequest<T>(method: string, path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const requestHeaders: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"User-Agent\": `getpeppr-sdk/${SDK_VERSION}`,\n ...extraHeaders,\n };\n\n const startTime = Date.now();\n if (this.onRequest) {\n try {\n this.onRequest({\n method,\n url,\n headers: { ...requestHeaders },\n body,\n timestamp: startTime,\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers: requestHeaders,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => \"Unknown error\");\n const retryAfterMs = response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined;\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: errorBody,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n throw new PeppolApiError(\n formatApiErrorMessage(response.status, errorBody),\n response.status,\n errorBody,\n retryAfterMs,\n );\n }\n\n // 204 No Content — no body to parse (e.g., sendInvoiceById)\n if (response.status === 204) {\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: undefined,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n return undefined as T;\n }\n\n let responseBody: T;\n try {\n responseBody = (await response.json()) as T;\n } catch {\n throw new PeppolApiError(\n `getpeppr API error: unexpected response format (status ${response.status})`,\n response.status,\n \"Response body is not valid JSON\",\n );\n }\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n // GPR-1061 — a COPY, not the live object. The hook used to receive\n // the very body the parsers then read: a hook that redacts fields\n // before logging them (an entirely reasonable hook) could delete\n // `status` and make the SDK blame the gateway for the omission.\n //\n // The clone is not guaranteed: structuredClone throws RangeError\n // past roughly 3000 levels of nesting. Falling back to the live\n // object would reopen the mutation above, and letting the throw\n // escape would silently drop the log — the surrounding catch\n // swallows everything — so the hook fires with a marker instead.\n body: cloneForHook(responseBody),\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n return responseBody;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // NOTE: sendInvoice and createInvoice hit the same SDK endpoint (POST /invoices).\n // The gateway (Tasks 9-10) differentiates them: sendInvoice wraps with\n // { invoice: {...}, send_after_import: true }, createInvoice omits the flag.\n async sendInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) {\n headers[\"Idempotency-Key\"] = options.idempotencyKey;\n }\n if (options?.validateRecipient) {\n headers[\"X-Validate-Recipient\"] = options.validateRecipient === true ? \"warn\" : String(options.validateRecipient);\n }\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices\", input, headers);\n return parseSendResult(result);\n }\n\n async createInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) {\n headers[\"Idempotency-Key\"] = options.idempotencyKey;\n }\n if (options?.validateRecipient) {\n headers[\"X-Validate-Recipient\"] = options.validateRecipient === true ? \"warn\" : String(options.validateRecipient);\n }\n // Signal to the gateway that this is a draft (no auto-send).\n // The gateway reads `_draft` and strips it before forwarding to the provider.\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices\", { ...input, _draft: true }, headers);\n return parseSendResult(result);\n }\n\n async sendInvoiceById(id: string): Promise<void> {\n await this.request<void>(\"POST\", `/invoices/send/${id}`);\n }\n\n async sendCreditNote(input: CreditNoteInput): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/credit-notes\", input);\n return parseSendResult(result);\n }\n\n async validateDocument(input: InvoiceInput): Promise<{ valid: boolean; errors: string[] }> {\n return this.request<{ valid: boolean; errors: string[] }>(\"POST\", \"/validate\", input);\n }\n\n async listInvoices(options?: ListInvoicesOptions): Promise<PaginatedResult<InvoiceSummary>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n if (options?.includeLines) params.set(\"include\", \"lines\");\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/invoices${query}`);\n\n // Gateway returns { invoices: [...], meta: {...} }\n //\n // GPR-1061 — guarded, because `body.invoices ?? body.data ?? []` reads an\n // empty page out of anything that is not an object: `200 \"ok\"` or `200 42`\n // returned a successful, empty, fabricated result, and `200 null` threw a\n // TypeError. An empty page a caller believes is real is the same class of\n // defect as an invented status.\n const envelope = requireRecordBody(result, \"the invoice list\");\n const rows = envelope.invoices ?? envelope.data ?? [];\n if (!Array.isArray(rows)) {\n throw new PeppolProtocolError(\n \"The getpeppr API answered the invoice list without an array of invoices. \" +\n \"Please report this response to support@getpeppr.dev.\",\n \"invoices\",\n boundedBody(envelope),\n );\n }\n const invoices = rows as Record<string, unknown>[];\n const meta = envelope.meta as Record<string, unknown> | undefined;\n\n return {\n data: invoices.map(parseInvoiceSummary),\n meta: {\n totalCount: Number(meta?.total_count ?? invoices.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n hasMore: meta ? Number(meta.total_count) > Number(meta.offset) + Number(meta.limit) : false,\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async getStatus(documentId: string, options?: GetStatusOptions): Promise<SendResult> {\n // GPR-1061 — `?include=evidence` makes the gateway read the sending evidence\n // from the network so it can return `peppolMessageId`. It is opt-in because\n // it costs a provider round trip, and it degrades silently: an in-flight\n // document simply comes back without the field.\n const query = options?.includeEvidence ? \"?include=evidence\" : \"\";\n const result = await this.request<Record<string, unknown>>(\n \"GET\",\n `/invoices/${documentId}${query}`,\n );\n return parseSendResult(result);\n }\n\n async lookupDirectory(scheme: string, id: string): Promise<DirectoryEntry> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/directory/${scheme}/${id}`);\n return parseDirectoryEntry(result);\n }\n\n async searchDirectory(params: Record<string, string>): Promise<DirectorySearchResult> {\n const query = new URLSearchParams(params).toString();\n const result = await this.request<Record<string, unknown>>(\"GET\", `/directory/search?${query}`);\n\n // Gateway returns { data: [...], meta: {...} } — entries are already in SDK\n // shape, but the pagination meta is snake_case (total_count, has_more) —\n // same split as listEvents (GPR-868).\n const data = (result.data ?? []) as DirectoryEntry[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data,\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? data.length),\n offset: Number(meta?.offset ?? params.offset ?? 0),\n limit: Number(meta?.limit ?? params.limit ?? 20),\n hasMore:\n meta?.has_more != null || meta?.hasMore != null\n ? Boolean(meta.has_more ?? meta.hasMore)\n : Number(meta?.total_count ?? meta?.totalCount ?? 0) >\n Number(meta?.offset ?? 0) + Number(meta?.limit ?? 0),\n },\n };\n }\n\n async getInvoiceAs(id: string, format: DocumentFormat): Promise<ArrayBuffer> {\n const { maxRetries, initialDelayMs, maxDelayMs } = this.retryConfig;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await this.doRequestBinary(`/invoices/${id}/as/${format}`);\n } catch (err) {\n lastError = err;\n if (attempt < maxRetries && isRetryableError(err)) {\n const retryAfterMs = err instanceof PeppolApiError ? err.retryAfterMs : undefined;\n await sleep(calculateRetryDelay(attempt, initialDelayMs, maxDelayMs, retryAfterMs));\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private async doRequestBinary(path: string): Promise<ArrayBuffer> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const requestHeaders = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n\n const startTime = Date.now();\n if (this.onRequest) {\n try {\n this.onRequest({\n method: \"GET\",\n url,\n headers: { ...requestHeaders },\n timestamp: startTime,\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: requestHeaders,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => \"Unknown error\");\n const retryAfterMs = response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined;\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: errorBody,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n throw new PeppolApiError(\n formatApiErrorMessage(response.status, errorBody),\n response.status,\n errorBody,\n retryAfterMs,\n );\n }\n\n const responseBody = await response.arrayBuffer();\n\n if (this.onResponse) {\n try {\n this.onResponse({\n status: response.status,\n headers: Object.fromEntries(response.headers.entries()),\n body: `[ArrayBuffer: ${responseBody.byteLength} bytes]`,\n durationMs: Date.now() - startTime,\n timestamp: Date.now(),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\n return responseBody;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async validateDocumentServer(input: InvoiceInput): Promise<ServerValidationResult> {\n return this.request<ServerValidationResult>(\"POST\", \"/validate/server\", input);\n }\n\n async listEvents(options?: ListEventsOptions): Promise<PaginatedResult<EventEntry>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n if (options?.invoiceId) params.set(\"invoiceId\", options.invoiceId);\n if (options?.dateFrom) params.set(\"dateFrom\", options.dateFrom);\n if (options?.dateTo) params.set(\"dateTo\", options.dateTo);\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/events${query}`);\n\n // Rows are camelCase (id, eventType, documentId, metadata, createdAt);\n // pagination meta is snake_case (total_count, has_more) — same split as\n // invoices.list (GPR-738). Read both forms defensively.\n const events = (result.data ?? []) as Record<string, unknown>[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data: events.map((evt) => ({\n id: String(evt.id ?? \"\"),\n eventType: String(evt.eventType ?? evt.event_type ?? \"\"),\n documentId: (evt.documentId ?? evt.document_id ?? null) as string | null,\n metadata: (evt.metadata ?? null) as Record<string, unknown> | null,\n createdAt: String(evt.createdAt ?? evt.created_at ?? \"\"),\n })),\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? events.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n // Prefer the gateway's authoritative has_more; fall back to computing it\n // from total_count/offset/limit so listAll() paginates correctly even if\n // a response omits the flag.\n hasMore:\n meta?.has_more != null || meta?.hasMore != null\n ? Boolean(meta.has_more ?? meta.hasMore)\n : Number(meta?.total_count ?? meta?.totalCount ?? 0) >\n Number(meta?.offset ?? options?.offset ?? 0) +\n Number(meta?.limit ?? options?.limit ?? 0),\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async acknowledgeInvoice(id: string): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"POST\", `/invoices/${id}/ack`);\n return parseSendResult(result);\n }\n\n async updateInvoice(id: string, input: InvoiceUpdateInput): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/invoices/${id}`, input);\n return parseSendResult(result);\n }\n\n async deleteInvoice(id: string): Promise<SendResult> {\n const result = await this.request<Record<string, unknown>>(\"DELETE\", `/invoices/${id}`);\n return parseSendResult(result);\n }\n\n async markInvoiceAs(id: string, state: MarkAsState, options?: MarkAsOptions): Promise<SendResult> {\n const body: Record<string, unknown> = { state };\n if (options?.commit) body.commit = options.commit;\n if (options?.reason) body.reason = options.reason;\n const result = await this.request<Record<string, unknown>>(\"POST\", `/invoices/${id}/mark-as`, body);\n return parseSendResult(result);\n }\n\n async listContacts(options?: ListContactsOptions): Promise<PaginatedResult<Contact>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n if (options?.name) params.set(\"name\", options.name);\n if (options?.isClient != null) params.set(\"isClient\", String(options.isClient));\n if (options?.isProvider != null) params.set(\"isProvider\", String(options.isProvider));\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/contacts${query}`);\n\n const contacts = (result.contacts ?? result.data ?? []) as Record<string, unknown>[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data: contacts.map(parseContact),\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? contacts.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n hasMore: meta\n ? Number(meta.total_count ?? meta.totalCount) > Number(meta.offset) + Number(meta.limit)\n : false,\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async getContact(id: string): Promise<Contact> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/contacts/${id}`);\n return parseContact(result);\n }\n\n async createContact(input: ContactInput): Promise<Contact> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/contacts\", input);\n return parseContact(result);\n }\n\n async updateContact(id: string, input: Partial<ContactInput>): Promise<Contact> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/contacts/${id}`, input);\n return parseContact(result);\n }\n\n async deleteContact(id: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/contacts/${id}`);\n }\n\n async createLegalEntity(input: LegalEntityInput, options?: LegalEntityRequestOptions): Promise<LegalEntity> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) headers[\"Idempotency-Key\"] = options.idempotencyKey;\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/legal-entities\", input, headers);\n return parseLegalEntity(result);\n }\n\n async getLegalEntity(id: string): Promise<LegalEntity> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/legal-entities/${id}`);\n return parseLegalEntity(result);\n }\n\n async listLegalEntities(options?: ListLegalEntitiesOptions): Promise<PaginatedResult<LegalEntity>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/legal-entities${query}`);\n\n // The route returns { data, pagination: { total_count, offset, limit, has_more } }.\n const rows = (result.data ?? []) as Record<string, unknown>[];\n const pagination = result.pagination as Record<string, unknown> | undefined;\n\n return {\n data: rows.map(parseLegalEntity),\n meta: {\n totalCount: Number(pagination?.total_count ?? rows.length),\n offset: Number(pagination?.offset ?? options?.offset ?? 0),\n limit: Number(pagination?.limit ?? options?.limit ?? 50),\n hasMore: Boolean(pagination?.has_more ?? false),\n truncated: false,\n },\n };\n }\n\n async archiveLegalEntity(id: string): Promise<ArchiveLegalEntityResult> {\n const result = await this.request<Record<string, unknown>>(\"DELETE\", `/legal-entities/${id}`);\n return {\n id: String(result.id ?? id),\n externalId: result.externalId != null ? String(result.externalId) : null,\n status: \"archived\",\n };\n }\n\n async requestLegalEntityAttestation(id: string, input: AttestationInput, options?: LegalEntityRequestOptions): Promise<AttestationResult> {\n const headers: Record<string, string> = {};\n if (options?.idempotencyKey) headers[\"Idempotency-Key\"] = options.idempotencyKey;\n const result = await this.request<Record<string, unknown>>(\n \"POST\",\n `/legal-entities/${id}/attestation`,\n input,\n headers,\n );\n return {\n id: String(result.id ?? id),\n externalId: result.externalId != null ? String(result.externalId) : null,\n status: String(result.status ?? \"\") as LegalEntityStatus,\n expiresAt: String(result.expiresAt ?? \"\"),\n };\n }\n\n async getIdentity(): Promise<AccountIdentity> {\n const result = await this.request<Record<string, unknown>>(\"GET\", \"/identity\");\n return parseAccountIdentity(result);\n }\n\n async listBankAccounts(options?: ListBankAccountsOptions): Promise<PaginatedResult<BankAccount>> {\n const params = new URLSearchParams();\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.offset != null) params.set(\"offset\", String(options.offset));\n const query = params.toString() ? `?${params.toString()}` : \"\";\n\n const result = await this.request<Record<string, unknown>>(\"GET\", `/bank-accounts${query}`);\n\n const bankAccounts = (result.bankAccounts ?? result.data ?? []) as Record<string, unknown>[];\n const meta = result.meta as Record<string, unknown> | undefined;\n\n return {\n data: bankAccounts.map(parseBankAccount),\n meta: {\n totalCount: Number(meta?.total_count ?? meta?.totalCount ?? bankAccounts.length),\n offset: Number(meta?.offset ?? options?.offset ?? 0),\n limit: Number(meta?.limit ?? options?.limit ?? 25),\n hasMore: meta\n ? Number(meta.total_count ?? meta.totalCount) > Number(meta.offset) + Number(meta.limit)\n : false,\n truncated: Boolean(meta?.truncated ?? false),\n },\n };\n }\n\n async getBankAccount(id: string): Promise<BankAccount> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/bank-accounts/${id}`);\n return parseBankAccount(result);\n }\n\n async createBankAccount(input: BankAccountInput): Promise<BankAccount> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/bank-accounts\", input);\n return parseBankAccount(result);\n }\n\n async updateBankAccount(id: string, input: Partial<BankAccountInput>): Promise<BankAccount> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/bank-accounts/${id}`, input);\n return parseBankAccount(result);\n }\n\n async deleteBankAccount(id: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/bank-accounts/${id}`);\n }\n\n async importInvoice(options: ImportInvoiceOptions): Promise<SendResult> {\n const body = {\n file: arrayBufferToBase64(options.file),\n filename: options.filename,\n mimeType: options.mimeType ?? detectMimeType(options.filename),\n // Declared, never derived from the document: routing decides delivery, and\n // parsing a caller's XML for a destination would put a parse error on the\n // \"whose invoice goes where\" path.\n to: options.to,\n };\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices/import\", body);\n return parseSendResult(result);\n }\n\n async listTransportTypes(): Promise<TransportType[]> {\n const result = await this.request<Record<string, unknown>>(\"GET\", \"/transports/types\");\n const types = (result.transportTypes ?? result.data ?? []) as Record<string, unknown>[];\n return types.map((t) => ({\n code: String(t.code ?? \"\"),\n name: String(t.name ?? \"\"),\n }));\n }\n\n async listTransports(): Promise<Transport[]> {\n const result = await this.request<Record<string, unknown>>(\"GET\", \"/transports\");\n const transports = (result.transports ?? result.data ?? []) as Record<string, unknown>[];\n return transports.map(parseTransport);\n }\n\n async getTransport(code: string): Promise<Transport> {\n const result = await this.request<Record<string, unknown>>(\"GET\", `/transports/${code}`);\n return parseTransport(result);\n }\n\n async createTransport(input: TransportInput): Promise<Transport> {\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/transports\", input);\n return parseTransport(result);\n }\n\n async updateTransport(code: string, input: TransportUpdateInput): Promise<Transport> {\n const result = await this.request<Record<string, unknown>>(\"PUT\", `/transports/${code}`, input);\n return parseTransport(result);\n }\n\n async deleteTransport(code: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/transports/${code}`);\n }\n}\n\n// ─── Import Helpers ──────────────────────────────────────────\n\n/** Convert ArrayBuffer or Uint8Array to base64 string (works in all runtimes). */\nexport function arrayBufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n}\n\n/** Detect MIME type from a filename's extension. */\nexport function detectMimeType(filename: string): string {\n const ext = filename.split(\".\").pop()?.toLowerCase();\n switch (ext) {\n case \"xml\": return \"application/xml\";\n case \"pdf\": return \"application/pdf\";\n case \"json\": return \"application/json\";\n default: return \"application/octet-stream\";\n }\n}\n\n/**\n * Read the wire status, or refuse (GPR-1061).\n *\n * The SDK used to fall back to `\"submitted\"` here. That value is not a terminal\n * state, so unless `submitted` was itself the status being waited for — and\n * `waitFor()` does check its targets first — `waitFor()` and `getpeppr send\n * --watch` could only time out on it, on a document that had in fact been\n * delivered. A plausible substitute is worse than a missing one: a consumer\n * reading `status` has no way to tell it apart from a measurement.\n */\n/** Upper bound on the serialised body carried by a PeppolProtocolError. */\nconst PROTOCOL_ERROR_BODY_LIMIT = 2000;\n\n/**\n * Deep-copy a response body for a logging hook, or hand it a marker.\n *\n * The hook must never receive the object the parsers go on to read (GPR-1061),\n * and it must never be skipped in silence either: the call site swallows hook\n * errors by design, so a `structuredClone` that throws would delete the log\n * entry without a trace.\n */\nfunction cloneForHook(body: unknown): unknown {\n try {\n return structuredClone(body);\n } catch {\n return \"[response body could not be copied for logging]\";\n }\n}\n\n/**\n * Serialise the offending body for a protocol error, bounded.\n *\n * An invoice payload has no natural size limit — 400 lines is an ordinary\n * document — and this string ends up on an exception a consumer may log. Cap\n * it: the point is to identify the shape that broke, not to archive the body.\n */\nfunction boundedBody(raw: unknown): string {\n let serialised: string;\n try {\n serialised = JSON.stringify(raw) ?? String(raw);\n } catch {\n serialised = \"[unserialisable response body]\";\n }\n if (serialised.length <= PROTOCOL_ERROR_BODY_LIMIT) return serialised;\n let head = serialised.slice(0, PROTOCOL_ERROR_BODY_LIMIT);\n // Never end on a lone high surrogate: the cut would split a character in two\n // and the payload kept for a support report would stop being what the gateway\n // sent, replaced by U+FFFD the moment it is encoded.\n if (/[\\uD800-\\uDBFF]$/.test(head)) head = head.slice(0, -1);\n return `${head}… [truncated, ${serialised.length} chars]`;\n}\n\n/**\n * Refuse a 2xx body the SDK cannot parse honestly (GPR-1061).\n *\n * `raw` is typed `Record<string, unknown>` by a cast, not by validation, so a\n * body that is not an object at all reaches here — `200 null` from a proxy in\n * front of the gateway is enough. Left unguarded that surfaces as a TypeError,\n * losing the type, the field and the body a support report needs.\n */\nfunction requireRecordBody(raw: unknown, surface: string): Record<string, unknown> {\n if (isRecord(raw)) return raw;\n throw new PeppolProtocolError(\n `The getpeppr API answered ${surface} with a body that is not an object. ` +\n `Please report this response to support@getpeppr.dev.`,\n \"body\",\n boundedBody(raw),\n );\n}\n\nfunction requireWireStatus(candidate: unknown, raw: Record<string, unknown>, surface: string): string {\n // A TYPE check, not a truthiness check. Everything here came off the wire and\n // TypeScript constrains none of it: `String(false)` is `\"false\"` and\n // `String({})` is `\"[object Object]\"`, both of which mapStatus would coerce\n // to \"unknown\" — and a polling loop starts over on \"unknown\".\n if (typeof candidate === \"string\" && candidate.trim() !== \"\") return candidate;\n // The body stays on `responseBody`, never in `message`: the message is what\n // the CLI prints and what most consumers log by reflex.\n throw new PeppolProtocolError(\n `The getpeppr API answered ${surface} without a status. The SDK will not ` +\n `invent one — please report this response to support@getpeppr.dev.`,\n \"status\",\n boundedBody(raw),\n );\n}\n\n/**\n * An identifier the gateway MAY send, kept only if it is really a string.\n *\n * A TYPE guard, never a coercion: `String(42)` is `\"42\"` and `String({})` is\n * `\"[object Object]\"` — both look like identifiers and resolve to nothing on\n * the next call. Nothing here is constrained by TypeScript; the response body\n * is a cast over parsed JSON. Same doctrine as `requireWireStatus`: the SDK\n * does not invent a value it was not given (GPR-1061).\n */\nfunction optionalWireId(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() !== \"\" ? value : undefined;\n}\n\nfunction parseSendResult(body: Record<string, unknown>): SendResult {\n const result = requireRecordBody(body, \"this request\");\n const rawStatus = requireWireStatus(result.status, result, \"this request\");\n const sendResult: SendResult = {\n id: String(result.id ?? \"\"),\n status: mapStatus(rawStatus),\n rawStatus,\n // A TYPE guard like the identifiers below, not a cast. This line used to\n // read `as string | undefined`, which types a number as a string and hands\n // a consumer an AS4 id that never existed.\n peppolMessageId: optionalWireId(result.peppolMessageId ?? result.peppol_message_id),\n ublXml: result.ublXml as string | undefined,\n warnings: Array.isArray(result.warnings) ? result.warnings : undefined,\n };\n // GPR-1061 — this used to fall back to `new Date().toISOString()`. A timestamp\n // stamped at the moment of the call is indistinguishable from one the gateway\n // measured, and no consumer can tell them apart. Absent stays absent.\n //\n // `updatedAt` was in this chain too and is gone: it is a different\n // measurement, and serving it under `createdAt` is the same fiction wearing\n // a plausible value. `created_at` stays — it is the snake_case spelling of\n // the same field, not another field.\n const createdAt = result.createdAt ?? result.created_at;\n if (createdAt != null) sendResult.createdAt = String(createdAt);\n const detail = parseStatusDetail(result.detail);\n if (detail) sendResult.detail = detail;\n // ⛔ GPR-1069 — `parseSendResult` est une LISTE BLANCHE : tout champ non\n // recopié ici est SUPPRIMÉ silencieusement pour l'utilisateur du SDK. Le\n // gateway et l'OpenAPI exposaient déjà `rulebook` sur le 201 d'import que\n // cette liste jetait — la promesse « nous vous disons contre quelle version\n // nous avons validé » était donc tenue en HTTP brut et fausse via le SDK.\n //\n // ⚠️ Garde de FORME, pas cast : les deux champs doivent être des chaînes.\n // Un objet partiel venu du réseau n'entre pas — mieux vaut absent que\n // `verifiedAt: undefined` sous un type qui le déclare requis.\n const rulebook = result.rulebook;\n if (\n typeof rulebook === \"object\" && rulebook !== null &&\n typeof (rulebook as Record<string, unknown>).peppol === \"string\" &&\n typeof (rulebook as Record<string, unknown>).verifiedAt === \"string\"\n ) {\n sendResult.rulebook = rulebook as { peppol: string; verifiedAt: string };\n }\n // ⛔ GPR-1089 — MÊME liste blanche, MÊME oubli, un ticket plus tard. Le champ\n // `transmission` a été ajouté au 201 de la passerelle, au schéma OpenAPI et\n // au type `SendResult`, et pas ici : il existait donc en HTTP brut et\n // disparaissait via le SDK, exactement comme `rulebook` ci-dessus. Le\n // commentaire au-dessus racontait déjà l'incident au moment où il a été\n // reproduit. **Ajouter un champ au reçu, c'est ajouter une ligne ICI.**\n //\n // ⚠️ Garde de TYPE, jamais de valeur. Refuser un `mode` que ce SDK ne connaît\n // pas rendrait `transmission` ABSENT, et un appelant lit une absence comme\n // « envoi JSON, aucun octet à moi » — faux, et dangereux pour précisément le\n // client qui scelle ses documents. Une valeur inconnue passe donc intacte.\n //\n // ⛔ `readOwn`, JAMAIS un accès indexé nu — ce fichier porte cette primitive\n // et documente exactement ce risque à son site. Une lecture nue accepte une\n // propriété HÉRITÉE : sur un hôte dont `Object.prototype` est pollué, un\n // corps sans `transmission` en gagne une, et un objet à moitié formé passe la\n // garde avant de violer le type publié. Trouvé par la gate, sur ma propre\n // remédiation, à quelques lignes d'un helper écrit pour ça.\n //\n // ⚠️ L'objet reconstruit est neuf, pas l'objet du réseau : le conserver\n // laisserait passer son prototype et ses clés surnuméraires.\n const transmission = result.transmission;\n if (typeof transmission === \"object\" && transmission !== null && !Array.isArray(transmission)) {\n const mode = readOwn(transmission, \"mode\");\n const bytePreservation = readOwn(transmission, \"bytePreservation\");\n if (typeof mode === \"string\" && typeof bytePreservation === \"string\") {\n sendResult.transmission = { mode, bytePreservation };\n }\n }\n // GPR-1061 — `id` keeps whatever meaning its surface gives it; these two say\n // which identifier you are actually holding.\n const submissionId = optionalWireId(result.submissionId);\n if (submissionId) sendResult.submissionId = submissionId;\n const providerDocumentId = optionalWireId(result.providerDocumentId);\n if (providerDocumentId) sendResult.providerDocumentId = providerDocumentId;\n return sendResult;\n}\n\nfunction parseDirectoryEntry(result: Record<string, unknown>): DirectoryEntry {\n const participant = isRecord(result.participant) ? result.participant : result;\n const scheme = participant.scheme == null ? undefined : String(participant.scheme);\n const id = participant.id == null ? undefined : String(participant.id);\n const peppolId =\n participant.peppolId == null\n ? formatPeppolId(scheme, id)\n : String(participant.peppolId);\n\n return {\n name: String(participant.name ?? \"\"),\n peppolId: peppolId as PeppolId,\n country: String(participant.country ?? \"\"),\n capabilities: Array.isArray(participant.capabilities)\n ? participant.capabilities.map(String)\n : [],\n registrationDate: participant.registrationDate == null ? undefined : String(participant.registrationDate),\n vatNumber: participant.vatNumber == null ? undefined : String(participant.vatNumber),\n additionalIds: Array.isArray(participant.additionalIds)\n ? participant.additionalIds.filter(isRecord).map((entry) => ({\n scheme: String(entry.scheme ?? \"\"),\n value: String(entry.value ?? \"\"),\n }))\n : undefined,\n contactInfo: isRecord(participant.contactInfo)\n ? {\n name: participant.contactInfo.name == null ? undefined : String(participant.contactInfo.name),\n email: participant.contactInfo.email == null ? undefined : String(participant.contactInfo.email),\n phone: participant.contactInfo.phone == null ? undefined : String(participant.contactInfo.phone),\n }\n : undefined,\n website: participant.website == null ? undefined : String(participant.website),\n };\n}\n\nfunction formatPeppolId(scheme: string | undefined, id: string | undefined): string {\n if (!id) return scheme ? `${scheme}:` : \"\";\n if (id.includes(\":\")) return id;\n return scheme ? `${scheme}:${id}` : id;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nconst STATUS_DETAIL_AXES = [\"platformFiscal\", \"delivery\", \"businessDisposition\", \"settlement\"] as const;\n\n/** Rebuild one axis entry by ALLOWLIST — the public type has no `message` field\n * and parsing must not smuggle one (or any unknown key) in at runtime. Returns\n * undefined when the required identifying fields are missing. */\nfunction parseStatusDetailEntry(raw: unknown): StatusDetailEntry | undefined {\n if (\n !isRecord(raw) ||\n typeof raw.axis !== \"string\" ||\n typeof raw.jurisdiction !== \"string\" ||\n typeof raw.code !== \"string\" ||\n typeof raw.label !== \"string\" ||\n typeof raw.codeSystem !== \"string\" ||\n typeof raw.codeVersion !== \"string\"\n ) {\n return undefined;\n }\n const entry: StatusDetailEntry = {\n axis: raw.axis as StatusDetailEntry[\"axis\"],\n jurisdiction: raw.jurisdiction,\n code: raw.code,\n label: raw.label,\n codeSystem: raw.codeSystem,\n codeVersion: raw.codeVersion,\n };\n if (isRecord(raw.standardCode) && typeof raw.standardCode.system === \"string\" && typeof raw.standardCode.code === \"string\") {\n entry.standardCode = { system: raw.standardCode.system, code: raw.standardCode.code };\n }\n if (typeof raw.reason === \"string\") entry.reason = raw.reason;\n if (Array.isArray(raw.warnings) && raw.warnings.every((w) => typeof w === \"string\")) {\n entry.warnings = [...raw.warnings];\n }\n if (typeof raw.failureCategory === \"string\") {\n entry.failureCategory = raw.failureCategory as StatusDetailEntry[\"failureCategory\"];\n }\n if (\n isRecord(raw.payment) &&\n typeof raw.payment.amount === \"number\" &&\n typeof raw.payment.currency === \"string\" &&\n typeof raw.payment.date === \"string\"\n ) {\n entry.payment = { amount: raw.payment.amount, currency: raw.payment.currency, date: raw.payment.date };\n }\n if (typeof raw.paymentSemantics === \"string\") {\n entry.paymentSemantics = raw.paymentSemantics as StatusDetailEntry[\"paymentSemantics\"];\n }\n if (typeof raw.actor === \"string\") entry.actor = raw.actor as StatusDetailEntry[\"actor\"];\n return entry;\n}\n\n/** Tolerant client-side pick of the per-axis detail map — never throws on gateway JSON. */\nfunction parseStatusDetail(raw: unknown): StatusDetail | undefined {\n if (!isRecord(raw)) return undefined;\n const detail: StatusDetail = {};\n for (const axis of STATUS_DETAIL_AXES) {\n const entry = parseStatusDetailEntry(raw[axis]);\n if (entry) detail[axis] = entry;\n }\n return Object.keys(detail).length > 0 ? detail : undefined;\n}\n\nfunction parseContact(raw: Record<string, unknown>): Contact {\n const contact: Contact = {\n id: String(raw.id ?? \"\"),\n name: String(raw.name ?? \"\"),\n };\n\n if (raw.peppolId != null) contact.peppolId = String(raw.peppolId);\n if (raw.vatNumber != null) contact.vatNumber = String(raw.vatNumber);\n if (raw.companyId != null) contact.companyId = String(raw.companyId);\n if (raw.street != null) contact.street = String(raw.street);\n if (raw.city != null) contact.city = String(raw.city);\n if (raw.postalCode != null) contact.postalCode = String(raw.postalCode);\n if (raw.country != null) contact.country = String(raw.country);\n if (raw.email != null) contact.email = String(raw.email);\n if (raw.phone != null) contact.phone = String(raw.phone);\n if (raw.isClient != null) contact.isClient = Boolean(raw.isClient);\n if (raw.isProvider != null) contact.isProvider = Boolean(raw.isProvider);\n if (raw.createdAt != null) contact.createdAt = String(raw.createdAt);\n if (raw.updatedAt != null) contact.updatedAt = String(raw.updatedAt);\n if (raw.directoryVerified != null) contact.directoryVerified = Boolean(raw.directoryVerified);\n if (raw.directoryLastChecked != null) contact.directoryLastChecked = String(raw.directoryLastChecked);\n\n return contact;\n}\n\nfunction parseLegalEntity(raw: Record<string, unknown>): LegalEntity {\n const idObj = raw.identifier as Record<string, unknown> | null | undefined;\n const le: LegalEntity = {\n id: String(raw.id ?? \"\"),\n externalId: raw.externalId != null ? String(raw.externalId) : null,\n companyName: raw.companyName != null ? String(raw.companyName) : null,\n country: raw.country != null ? String(raw.country) : null,\n identifier:\n idObj && idObj.scheme != null && idObj.value != null\n ? { scheme: String(idObj.scheme), value: String(idObj.value) }\n : null,\n status: String(raw.status ?? \"pending\") as LegalEntityStatus,\n environment: String(raw.environment ?? \"\"),\n createdAt: String(raw.createdAt ?? \"\"),\n };\n if (raw.verificationDetail != null) {\n le.verificationDetail = raw.verificationDetail as LegalEntity[\"verificationDetail\"];\n }\n return le;\n}\n\n/**\n * ⛔ WHITELIST parse, like `parseSendResult` above (GPR-1069 then GPR-1089 —\n * twice in two consecutive tickets): every field of the frozen GET /v1/identity\n * contract is copied here DELIBERATELY, and any field not copied here is\n * silently dropped for the SDK user while existing in raw HTTP. Adding a field\n * to the gateway response means adding a line HERE, and a key to the\n * enumeration test in `identity.test.ts`.\n *\n * Form guards (`typeof`), never casts — nothing off the wire is constrained by\n * TypeScript. And the SDK never fabricates a value the network did not send:\n * an absent optional stays `null`; a REQUIRED field absent or malformed is\n * REFUSED (`PeppolProtocolError`), because inventing `environment` or `[]` for\n * `identifiers` would hand the caller an answer (\"sandbox\", \"not registered\")\n * nobody measured.\n */\nfunction parseAccountIdentity(raw: Record<string, unknown>): AccountIdentity {\n const result = requireRecordBody(raw, \"the identity request\");\n\n const environment = readOwn(result, \"environment\");\n if (typeof environment !== \"string\" || environment.trim() === \"\") {\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request without an environment. \" +\n \"The SDK will not invent one — please report this response to support@getpeppr.dev.\",\n \"environment\",\n boundedBody(result),\n );\n }\n\n const identifiersRaw = readOwn(result, \"identifiers\");\n if (!Array.isArray(identifiersRaw)) {\n // Inventing `[]` would tell the caller \"you hold no identifiers\" — an\n // absence read as information, the exact `transmission` lesson above.\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request without an identifiers array. \" +\n \"The SDK will not invent one — please report this response to support@getpeppr.dev.\",\n \"identifiers\",\n boundedBody(result),\n );\n }\n const identifiers: AccountIdentifier[] = identifiersRaw.map((row) => {\n // A row this SDK cannot represent is REFUSED, never silently dropped:\n // dropping one answers \"am I registered?\" with a false no.\n if (!isRecord(row)) {\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request with a malformed identifier row. \" +\n \"Please report this response to support@getpeppr.dev.\",\n \"identifiers\",\n boundedBody(result),\n );\n }\n const scheme = readOwn(row, \"scheme\");\n const value = readOwn(row, \"value\");\n // ⚠️ `status` gets a TYPE guard, never a VALUE guard: an unknown status\n // passes through unchanged (same reasoning as `rawStatus`).\n const status = readOwn(row, \"status\");\n if (typeof scheme !== \"string\" || typeof value !== \"string\" || typeof status !== \"string\") {\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request with a malformed identifier row. \" +\n \"Please report this response to support@getpeppr.dev.\",\n \"identifiers\",\n boundedBody(result),\n );\n }\n const createdAt = readOwn(row, \"createdAt\");\n return {\n scheme,\n value,\n status,\n createdAt: typeof createdAt === \"string\" ? createdAt : null,\n };\n });\n\n return {\n environment,\n legalEntity: parseAccountIdentityLegalEntity(readOwn(result, \"legalEntity\"), result),\n identifiers,\n };\n}\n\n/**\n * `null` in, `null` out — no legal entity yet is an answer, not a gap.\n *\n * ⛔ But ONLY an explicit `null` is that answer. The field is REQUIRED by the\n * contract: a missing key, a string or an array is protocol corruption, and\n * mapping it to `null` would turn a corrupted response into a confident\n * \"you have no identity\" (gate finding D7 — a custom `baseUrl` server can\n * produce this today). Refuse, never translate.\n */\nfunction parseAccountIdentityLegalEntity(raw: unknown, body: unknown): AccountIdentityLegalEntity | null {\n if (raw === null) return null;\n if (!isRecord(raw)) {\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request without a valid legalEntity field. \" +\n \"Please report this response to support@getpeppr.dev.\",\n \"legalEntity\",\n // The FULL body, per the responseBody contract — `raw` alone serialises\n // to the string \"undefined\" when the field is missing (2nd-pass gate N1).\n boundedBody(body),\n );\n }\n const companyName = readOwn(raw, \"companyName\");\n const country = readOwn(raw, \"country\");\n const createdAt = readOwn(raw, \"createdAt\");\n return {\n companyName: typeof companyName === \"string\" ? companyName : null,\n country: typeof country === \"string\" ? country : null,\n address: parseAccountIdentityAddress(readOwn(raw, \"address\")),\n createdAt: typeof createdAt === \"string\" ? createdAt : null,\n };\n}\n\nfunction parseAccountIdentityAddress(raw: unknown): AccountIdentityAddress | null {\n if (!isRecord(raw)) return null;\n const line1 = readOwn(raw, \"line1\");\n const city = readOwn(raw, \"city\");\n const zip = readOwn(raw, \"zip\");\n return {\n line1: typeof line1 === \"string\" ? line1 : null,\n city: typeof city === \"string\" ? city : null,\n zip: typeof zip === \"string\" ? zip : null,\n };\n}\n\nfunction parseInvoiceSummary(row: Record<string, unknown>): InvoiceSummary {\n // The gateway returns camelCase rows (`invoiceNumber`, `createdAt`, …);\n // `number` is accepted as a legacy fallback for back-compat (GPR-738).\n const raw = requireRecordBody(row, \"this invoice row\");\n const rawStatus = requireWireStatus(raw.state ?? raw.status, raw, \"this invoice row\");\n const summary: InvoiceSummary = {\n id: String(raw.id ?? \"\"),\n number: String(raw.invoiceNumber ?? raw.number ?? \"\"),\n status: mapStatus(rawStatus),\n rawStatus,\n };\n const detail = parseStatusDetail(raw.detail);\n if (detail) summary.detail = detail;\n // GPR-1062 — the gateway has always sent `providerDocumentId` here and this\n // parser dropped it, so `list()` and `getStatus()` did not compose.\n const submissionId = optionalWireId(raw.submissionId);\n if (submissionId) summary.submissionId = submissionId;\n const providerDocumentId = optionalWireId(raw.providerDocumentId);\n if (providerDocumentId) summary.providerDocumentId = providerDocumentId;\n if (raw.createdAt != null) summary.createdAt = String(raw.createdAt);\n if (typeof raw.isCreditNote === \"boolean\") summary.isCreditNote = raw.isCreditNote;\n if (raw.recipientName != null) summary.recipientName = String(raw.recipientName);\n if (raw.totalAmount != null && Number.isFinite(Number(raw.totalAmount))) {\n summary.totalAmount = Number(raw.totalAmount);\n }\n if (raw.currency != null) summary.currency = String(raw.currency);\n if (raw.environment != null) summary.environment = String(raw.environment);\n return summary;\n}\n\nfunction parseBankAccount(raw: Record<string, unknown>): BankAccount {\n const account: BankAccount = {\n id: String(raw.id ?? \"\"),\n name: String(raw.name ?? \"\"),\n type: (raw.type === \"number\" ? \"number\" : \"iban\") as \"iban\" | \"number\",\n };\n\n if (raw.iban != null) account.iban = String(raw.iban);\n if (raw.number != null) account.number = String(raw.number);\n if (raw.bic != null) account.bic = String(raw.bic);\n if (raw.country != null) account.country = String(raw.country);\n if (raw.createdAt != null) account.createdAt = String(raw.createdAt);\n if (raw.updatedAt != null) account.updatedAt = String(raw.updatedAt);\n\n return account;\n}\n\nfunction parseTransport(raw: Record<string, unknown>): Transport {\n return {\n id: String(raw.id ?? \"\"),\n transportTypeCode: String(raw.transportTypeCode ?? \"\"),\n name: String(raw.name ?? \"\"),\n status: raw.status ? String(raw.status) : undefined,\n };\n}\n\n// getpeppr gateway document lifecycle states.\n// Mapped from Storecove webhook events. See: Storecove API v2 §3.3.4\nconst VALID_STATUSES = new Set<DocumentStatus>([\n \"submitted\", \"delivered\", \"accepted\", \"rejected\", \"paid\", \"failed\",\n \"cleared\", \"acknowledged\", \"in_process\", \"under_query\",\n \"conditionally_accepted\", \"partially_paid\", \"no_action\",\n \"unknown\", // explicitly known: gateway may emit this when it can't map a Storecove status\n]);\n\n// Note: each call to mapStatus that hits the unknown fallback emits its own console.warn.\n// No dedup is intentional — callers see the warning proportionally to how often the\n// unknown status appears (matches Stripe/AWS SDK convention).\n/** @internal — exported for testing only; not part of the public SDK surface. */\nexport function mapStatus(raw: string): DocumentStatus {\n const s = raw.toLowerCase() as DocumentStatus;\n if (VALID_STATUSES.has(s)) return s;\n console.warn(\n `[getpeppr] Unknown gateway status received: \"${raw}\" — ` +\n `please report to support@getpeppr.dev. Coercing to \"unknown\".`,\n );\n return \"unknown\";\n}\n\n// ─── Error Classes ──────────────────────────────────────────\n\nexport class PeppolError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PeppolError\";\n }\n}\n\nexport class PeppolValidationError extends PeppolError {\n constructor(\n message: string,\n public readonly validation: ValidationResult\n ) {\n super(message);\n this.name = \"PeppolValidationError\";\n }\n}\n\n/**\n * The gateway answered 2xx with a body the SDK cannot honestly parse — a field\n * the contract makes mandatory is missing.\n *\n * The SDK raises this instead of substituting a plausible value: a fabricated\n * status is indistinguishable from a measured one for anyone reading `status`\n * (GPR-1061). Nothing you sent causes it and retrying will not clear it — it is\n * worth reporting, with the caveat on `responseBody` below.\n */\nexport class PeppolProtocolError extends PeppolError {\n constructor(\n message: string,\n /** The field the response lacked, or `\"body\"` when it is not an object. */\n public readonly field: string,\n /**\n * The offending response body, serialised and capped at 2000 characters.\n *\n * This is your own document data as the gateway returned it. It is here so\n * you can see the shape that broke — treat it like any other payload before\n * putting it somewhere it will be retained.\n */\n public readonly responseBody: string,\n ) {\n super(message);\n this.name = \"PeppolProtocolError\";\n }\n}\n\nexport class PeppolApiError extends PeppolError {\n /** Parsed Retry-After delay in milliseconds (present on 429 responses) */\n public readonly retryAfterMs?: number;\n\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly responseBody: string,\n retryAfterMs?: number,\n ) {\n super(message);\n this.name = \"PeppolApiError\";\n this.retryAfterMs = retryAfterMs;\n }\n\n /**\n * The gateway's machine-readable error code, parsed from the JSON response body\n * (e.g. \"le_cap_exceeded\", \"identifier_immutable\", \"legal_entity_locked\", \"forbidden\").\n * Returns undefined when the body is not JSON or carries no string `code`.\n */\n get code(): string | undefined {\n try {\n const parsed = JSON.parse(this.responseBody) as { code?: unknown };\n return typeof parsed?.code === \"string\" ? parsed.code : undefined;\n } catch {\n return undefined;\n }\n }\n}\n\n// ─── Main SDK Client ────────────────────────────────────────\n\nexport class Peppol {\n private adapter: BackendAdapter;\n public readonly invoices: InvoiceOperations;\n public readonly creditNotes: CreditNoteOperations;\n public readonly directory: DirectoryOperations;\n public readonly events: EventOperations;\n public readonly contacts: ContactOperations;\n public readonly bankAccounts: BankAccountOperations;\n public readonly transports: TransportOperations;\n /**\n * Your own account's Peppol identity — works with ANY key, standard keys\n * included. `peppol.identity.get()` answers \"who am I on the Peppol\n * network?\" for the account behind the key making the call.\n */\n public readonly identity: IdentityOperations;\n /**\n * Sub-tenant Legal Entities — **platform accounts only**.\n *\n * Requires a platform account and a **master API key**. With a standard key\n * every call here fails with 403 `master_key_required`.\n *\n * Onboarding your OWN company is not done through this API: your legal entity\n * is managed in the console, on the Peppol identity page — and READ from the\n * API with `peppol.identity.get()`, which works with any key. This surface is\n * for platforms that onboard their customers as sub-tenants.\n *\n * **Getting access:** platform mode is enabled by getpeppr on your account —\n * email hello@getpeppr.dev to have it switched on. Once it is, you create the\n * master key yourself at https://console.getpeppr.dev/api-keys.\n *\n * @see https://getpeppr.dev/docs/platform/legal-entities/\n */\n public readonly legalEntities: LegalEntityOperations;\n\n constructor(config: PeppolConfig) {\n if (!config.apiKey) {\n throw new PeppolError(\n 'API key is required. Sign up at https://console.getpeppr.dev to get your sandbox key.'\n );\n }\n\n this.adapter = new GetpepprAdapter(config);\n this.invoices = new InvoiceOperations(this.adapter);\n this.creditNotes = new CreditNoteOperations(this.adapter);\n this.directory = new DirectoryOperations(this.adapter);\n this.events = new EventOperations(this.adapter);\n this.contacts = new ContactOperations(this.adapter);\n this.bankAccounts = new BankAccountOperations(this.adapter);\n this.transports = new TransportOperations(this.adapter);\n this.identity = new IdentityOperations(this.adapter);\n this.legalEntities = new LegalEntityOperations(this.adapter);\n }\n\n /**\n * Validate an invoice without sending it.\n * Useful for pre-flight checks in your UI.\n */\n validate(input: InvoiceInput): ValidationResult {\n return validateInvoice(input);\n }\n\n /**\n * Generate UBL XML without sending.\n * Useful for debugging or manual submission.\n */\n toXml(input: InvoiceInput): string {\n const validation = validateInvoice(input);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n validation\n );\n }\n if (input.isCreditNote) {\n return buildCreditNoteXml(input as unknown as CreditNoteInput);\n }\n return buildInvoiceXml(input);\n }\n}\n\n/** @internal — exported for testing only; not part of the public SDK surface. */\nexport async function* paginate<T>(\n fetchPage: (offset: number, limit: number) => Promise<PaginatedResult<T>>,\n options?: { limit?: number },\n): AsyncGenerator<T> {\n const pageSize = options?.limit ?? 25;\n let offset = 0;\n\n while (true) {\n const page = await fetchPage(offset, pageSize);\n if (page.data.length === 0) break; // safety: empty page (even with hasMore=true) ends iteration\n for (const item of page.data) {\n yield item;\n }\n if (!page.meta.hasMore) break;\n offset += page.data.length; // FIX (GPR-414 #6): was += pageSize, which silently skipped records on partial pages\n }\n}\n\nclass InvoiceOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Create a draft invoice without sending it.\n * Validates input client-side, then creates the invoice via the gateway.\n * Use `sendById()` to send the draft when ready.\n *\n * @example\n * ```ts\n * const draft = await peppol.invoices.create({ number: \"INV-001\", to, lines });\n * // Later, when ready:\n * await peppol.invoices.sendById(draft.id);\n * ```\n */\n async create(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const validation = validateInvoice(input);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed:\\n${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : \"\"}`).join(\"\\n\")}`,\n validation\n );\n }\n\n const result = await this.adapter.createInvoice(input, options);\n\n if (validation.warnings.length > 0) {\n result.warnings = validation.warnings;\n }\n\n return result;\n }\n\n /**\n * Send an existing draft invoice by ID.\n * The invoice must have been previously created with `create()`.\n *\n * @example\n * ```ts\n * await peppol.invoices.sendById(\"inv-1\");\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support draft sending\n */\n async sendById(id: string): Promise<void> {\n return this.adapter.sendInvoiceById(id);\n }\n\n /**\n * Send an invoice via Peppol.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.send({\n * number: \"INV-001\",\n * from: { name: \"My Company\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * to: { name: \"Client Co\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * lines: [\n * { description: \"Consulting\", quantity: 10, unitPrice: 150, vatRate: 21 }\n * ]\n * });\n * ```\n */\n async send(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n // Client-side validation for fast feedback\n const validation = validateInvoice(input);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed:\\n${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : \"\"}`).join(\"\\n\")}`,\n validation\n );\n }\n\n // Send structured JSON — gateway handles UBL generation\n const result = await this.adapter.sendInvoice(input, options);\n\n if (validation.warnings.length > 0) {\n result.warnings = validation.warnings;\n }\n\n return result;\n }\n\n /** List invoices with pagination, filtering, and proper metadata */\n async list(options?: ListInvoicesOptions): Promise<PaginatedResult<InvoiceSummary>> {\n return this.adapter.listInvoices(options);\n }\n\n /**\n * Async iterator over all invoices, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const invoice of peppol.invoices.listAll()) {\n * console.log(invoice.id, invoice.status);\n * }\n * ```\n */\n listAll(options?: Omit<ListInvoicesOptions, \"offset\">): AsyncIterable<InvoiceSummary> {\n return paginate(\n (offset, limit) => this.adapter.listInvoices({ ...options, offset, limit }),\n options,\n );\n }\n\n /**\n * Get the status of a sent invoice.\n *\n * @param options.includeEvidence Ask the gateway to read the sending evidence\n * from the Peppol network so the result carries `peppolMessageId`. Costs one\n * provider round trip, so it is off by default; if the document has not gone\n * out yet, or the read fails, the field is simply absent and everything else\n * is unaffected.\n *\n * @example\n * ```ts\n * const status = await peppol.invoices.getStatus(id);\n * const proof = await peppol.invoices.getStatus(id, { includeEvidence: true });\n * ```\n */\n async getStatus(documentId: string, options?: GetStatusOptions): Promise<SendResult> {\n return this.adapter.getStatus(documentId, options);\n }\n\n /**\n * Export an invoice in a specific format (e.g., PDF, UBL XML).\n * Returns raw binary data as an ArrayBuffer.\n *\n * @example\n * ```ts\n * const pdf = await peppol.invoices.getAs(\"inv-123\", \"pdf\");\n * fs.writeFileSync(\"invoice.pdf\", Buffer.from(pdf));\n * ```\n */\n async getAs(id: string, format: DocumentFormat): Promise<ArrayBuffer> {\n return this.adapter.getInvoiceAs(id, format);\n }\n\n /**\n * Validate an invoice server-side using the getpeppr gateway's offline SDK-backed checks.\n * The gateway runs SDK validation, verifies UBL XML generation, and evaluates offline\n * Peppol business rules without sending the invoice to Storecove.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.validateServer({\n * number: \"INV-001\",\n * to: { name: \"Acme\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * lines: [{ description: \"Item\", quantity: 1, unitPrice: 100, vatRate: 21 }]\n * });\n * console.log(result.valid, result.schematron.errors);\n * ```\n * Validation findings return a structured result with valid=false. Transport, auth,\n * malformed request, and unexpected gateway failures still throw PeppolApiError.\n */\n async validateServer(input: InvoiceInput): Promise<ServerValidationResult> {\n return this.adapter.validateDocumentServer(input);\n }\n\n /**\n * Send a UBL Invoice or CreditNote you built yourself.\n *\n * getpeppr does not regenerate, normalise, or repair the document — we\n * forward the bytes you supplied, unchanged, to the network. Only UBL Invoice\n * and CreditNote are accepted — a PDF, a CII document, or an XML that is\n * neither is refused. The file is base64-encoded into a JSON body; there is\n * no multipart upload.\n *\n * ⚠️ Byte-for-byte equality is NOT guaranteed, because the network\n * re-serialises the document in transit. Measured 2026-08-18 on a test\n * document: namespace declarations come back reordered, numeric character\n * references are resolved (`&#65;` → `A`), whitespace inside tags is dropped,\n * and no element was added, removed or altered. That is one document and four\n * kinds of difference — indicative, not a warranty of what is preserved.\n * **If you seal your documents, hash a canonical form (C14N) rather than the\n * raw bytes.**\n *\n * The receipt says this itself, so your code need not rely on this comment:\n * a successful import carries `transmission`, whose `bytePreservation` this\n * gateway sets to `\"not_guaranteed\"` (GPR-1089). It is a guarantee we decline\n * to give, not a claim that your document was altered.\n *\n * ⚠️ Read the value, do not assume it. This SDK talks to whatever gateway\n * version you point it at: one predating GPR-1089 returns no `transmission`\n * at all, and the field is typed `string` so a later value reaches you rather\n * than being dropped. **Absent is not `false`** — it means the gateway did\n * not say, never that your bytes are safe.\n *\n * `to` is required and is never read from the document. Routing decides\n * delivery, the document travels as payload, and getpeppr will not guess a\n * destination by parsing your XML.\n *\n * Before transmission the document is validated against the complete official\n * OpenPeppol rulebooks. A document violating a `fatal` rule is refused and is\n * NOT sent; the error names the rule.\n *\n * @example\n * ```ts\n * const xmlBytes = fs.readFileSync(\"invoice.xml\");\n * const result = await peppol.invoices.importFile({\n * file: xmlBytes,\n * filename: \"invoice.xml\",\n * to: { peppolId: \"0208:0685660237\" },\n * });\n * console.log(result.id, result.status);\n * ```\n *\n * @throws {PeppolApiError} 400 — `invalid_base64`, or a missing `file` /\n * `filename`. `missing_recipient` when `to.peppolId` is absent.\n * @throws {PeppolApiError} 422 — the document was refused and NOT sent. Two\n * families, and they do NOT retry the same way:\n *\n * - **The document was rejected** (`validation_failed`, `not_ubl_document`,\n * `document_too_complex`, `undecodable_document`, `unsupported_encoding`).\n * Terminal: the same bytes fail identically forever. Fix the document —\n * retrying is pure waste, and `validation_failed` names the rule.\n * - **The account may not send right now** (`peppol_identity_incomplete`,\n * `peppol_identity_not_verified`, `platform_billing_not_active`,\n * `production_access_expired`). ⛔ NOT terminal: these describe account\n * state, and account state changes — a verification completes, a contract\n * is activated. The identical document will go through once it does.\n *\n * Treating the second family as terminal costs a customer a real invoice;\n * treating the first as retryable costs an infinite loop. See the API\n * reference for the full list.\n */\n async importFile(options: ImportInvoiceOptions): Promise<SendResult> {\n return this.adapter.importInvoice(options);\n }\n\n /**\n * Acknowledge a received invoice.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.acknowledge(\"inv-123\");\n * console.log(result.status); // \"accepted\"\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support acknowledgement\n */\n async acknowledge(id: string): Promise<SendResult> {\n return this.adapter.acknowledgeInvoice(id);\n }\n\n /**\n * Update an existing invoice (draft only).\n * Only include the fields you want to change — partial updates are supported.\n *\n * @example\n * ```ts\n * const updated = await peppol.invoices.update(\"inv-123\", {\n * dueDate: \"2026-04-01\",\n * lines: [\n * { id: \"line-1\", quantity: 5 },\n * { id: \"line-2\", _destroy: true },\n * ],\n * });\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support invoice updates\n */\n async update(id: string, input: InvoiceUpdateInput): Promise<SendResult> {\n return this.adapter.updateInvoice(id, input);\n }\n\n /**\n * Delete an invoice.\n *\n * @example\n * ```ts\n * const deleted = await peppol.invoices.delete(\"inv-123\");\n * ```\n * @throws {PeppolApiError} 501 if the gateway provider does not support invoice deletion\n */\n async delete(id: string): Promise<SendResult> {\n return this.adapter.deleteInvoice(id);\n }\n\n /**\n * Transition an invoice to a new state.\n * The gateway validates the state machine — invalid transitions return an error.\n *\n * `\"paid\"` on a French CTC invoice reports the payment collection\n * (« signalement d'encaissement ») to the tax authority via the gateway —\n * a legal obligation of the French mandate for service invoices. The full\n * amount is reported from the invoice's stored tax breakdown (no amount to\n * pass), at most once per invoice: replays return the same report (200),\n * a concurrent report returns 409, a non-French invoice returns 422.\n * The invoice's own status becomes `paid` later, when the network confirms\n * (webhook / polling), not synchronously with this call.\n *\n * @example\n * ```ts\n * // France: report that the customer paid this invoice\n * await peppol.invoices.markAs(\"inv-123\", \"paid\");\n * ```\n * @throws {PeppolApiError} 422 for \"paid\" on a non-French-CTC invoice; 501 for states the provider does not support\n */\n async markAs(id: string, state: MarkAsState, options?: MarkAsOptions): Promise<SendResult> {\n return this.adapter.markInvoiceAs(id, state, options);\n }\n\n /**\n * Send multiple invoices in parallel with controlled concurrency.\n * Each invoice is validated and sent individually — failures don't affect other invoices\n * unless `stopOnError: true` is set.\n *\n * The SDK's built-in retry logic (including 429 Retry-After) provides automatic\n * rate-limit handling at the request level.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.sendBatch([invoice1, invoice2, invoice3], {\n * concurrency: 3,\n * });\n * console.log(`${result.succeeded.length} sent, ${result.failed.length} failed`);\n * ```\n */\n async sendBatch(\n inputs: InvoiceInput[],\n options?: BatchSendOptions,\n ): Promise<BatchSendResult> {\n const concurrency = options?.concurrency ?? 5;\n const stopOnError = options?.stopOnError ?? false;\n\n const succeeded: BatchSendResult[\"succeeded\"] = [];\n const failed: BatchSendResult[\"failed\"] = [];\n let stopped = false;\n\n // Process in chunks of `concurrency` size\n for (let i = 0; i < inputs.length; i += concurrency) {\n if (stopped) break;\n\n const chunk = inputs.slice(i, i + concurrency);\n const promises = chunk.map(async (input, j) => {\n const index = i + j;\n if (stopped) return;\n try {\n const result = await this.send(input);\n succeeded.push({ index, result });\n } catch (error) {\n failed.push({ index, input, error: error as Error });\n if (stopOnError) {\n stopped = true;\n }\n }\n });\n\n await Promise.all(promises);\n }\n\n return { succeeded, failed, total: inputs.length };\n }\n\n /**\n * Poll until an invoice reaches a target status.\n *\n * @example\n * ```ts\n * const result = await peppol.invoices.waitFor(id, \"accepted\", { timeout: 60000 });\n * ```\n */\n async waitFor(\n documentId: string,\n targetStatus: DocumentStatus | DocumentStatus[],\n options?: WaitForOptions,\n ): Promise<SendResult> {\n const timeout = options?.timeout ?? 120_000;\n const interval = options?.interval ?? 5_000;\n const targets = Array.isArray(targetStatus) ? targetStatus : [targetStatus];\n // §8.7 — terminal sets DERIVED from the precedence table, never hard-coded.\n // Targets are checked first, so explicitly waiting for a terminal still resolves.\n const startTime = Date.now();\n\n while (true) {\n const result = await this.getStatus(documentId);\n\n if (targets.includes(result.status)) {\n return result;\n }\n\n if (TERMINAL_FAILURE_STATUSES.includes(result.status)) {\n throw new PeppolError(\n `Document ${documentId} reached terminal status \"${result.status}\" while waiting for \"${targets.join('\" or \"')}\"`\n );\n }\n\n if (statusFamily(result.status) === \"terminal-success\") {\n // The document reached a terminal success (paid) that outranks every\n // progress target in the §8.1 precedence: the target was PASSED, not\n // missed — resolve with the real result instead of timing out (GPR-825).\n if (targets.every((t) => statusFamily(t) === \"progress\")) {\n return result;\n }\n // A failure/unknown target can never be reached anymore — fail fast.\n throw new PeppolError(\n `Document ${documentId} reached terminal status \"${result.status}\" while waiting for \"${targets.join('\" or \"')}\"`\n );\n }\n\n if (Date.now() - startTime >= timeout) {\n throw new PeppolError(\n `Timed out waiting for document ${documentId} to reach status \"${targets.join('\" or \"')}\" (last: \"${result.status}\")`\n );\n }\n\n await sleep(interval);\n }\n }\n}\n\n/** @deprecated Use peppol.invoices.send() with isCreditNote: true instead */\nclass CreditNoteOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Send a credit note via Peppol.\n * @deprecated Use peppol.invoices.send({ ...input, isCreditNote: true }) instead.\n */\n async send(input: CreditNoteInput): Promise<SendResult> {\n // Convert to InvoiceInput with isCreditNote flag and delegate to sendInvoice\n const invoiceInput: InvoiceInput = {\n ...input,\n isCreditNote: true,\n invoiceReference: input.invoiceReference,\n };\n\n const validation = validateInvoice(invoiceInput);\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Credit note validation failed:\\n${validation.errors.map((e) => ` - ${e.field}: ${e.message}`).join(\"\\n\")}`,\n validation\n );\n }\n\n // Route through sendInvoice — the provider has no separate credit-notes endpoint\n return this.adapter.sendInvoice(invoiceInput);\n }\n}\n\n// ─── Directory Operations ───────────────────────────────────\n\nclass DirectoryOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Look up a Peppol participant in the directory.\n *\n * @example\n * ```ts\n * const entry = await peppol.directory.lookup(\"0208:0685660237\");\n * console.log(entry.name, entry.capabilities);\n * ```\n */\n async lookup(peppolId: PeppolId): Promise<DirectoryEntry> {\n const colonIndex = peppolId.indexOf(\":\");\n if (colonIndex === -1) {\n throw new PeppolError(\n 'Invalid Peppol ID format. Expected \"scheme:id\" (e.g., \"0208:0685660237\")',\n );\n }\n const scheme = peppolId.slice(0, colonIndex);\n const id = peppolId.slice(colonIndex + 1);\n return this.adapter.lookupDirectory(scheme, id);\n }\n\n /**\n * Search the Peppol Directory for participants.\n *\n * @example\n * ```ts\n * const result = await peppol.directory.search({ name: \"Acme\", country: \"BE\" });\n * console.log(result.data); // DirectoryEntry[]\n * console.log(result.meta.totalCount);\n * ```\n */\n async search(options: DirectorySearchOptions): Promise<DirectorySearchResult> {\n if (!options.name && !options.country && !options.vatNumber) {\n throw new PeppolError(\"At least one search criterion is required (name, country, or vatNumber)\");\n }\n if (options.name && options.name.length < 3) {\n throw new PeppolError(\"Search name must be at least 3 characters\");\n }\n if (!this.adapter.searchDirectory) {\n throw new PeppolError(\"Directory search is not supported by this backend adapter\");\n }\n\n const params: Record<string, string> = {};\n if (options.name) params.name = options.name;\n if (options.country) params.country = options.country;\n if (options.vatNumber) params.vatNumber = options.vatNumber;\n if (options.limit !== undefined) params.limit = String(options.limit);\n if (options.offset !== undefined) params.offset = String(options.offset);\n\n return this.adapter.searchDirectory(params);\n }\n\n /**\n * Search the Peppol Directory by VAT number.\n * Convenience method — equivalent to `search({ vatNumber })`.\n *\n * @example\n * ```ts\n * const result = await peppol.directory.searchByVat(\"BE0685660237\");\n * ```\n */\n async searchByVat(vatNumber: string): Promise<DirectorySearchResult> {\n return this.search({ vatNumber });\n }\n}\n\n// ─── Event Operations ────────────────────────────────────────\n\nclass EventOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List events with optional filtering and pagination.\n *\n * @example\n * ```ts\n * const result = await peppol.events.list({ limit: 10 });\n * console.log(result.data, result.meta);\n *\n * // Filter by invoice\n * const invoiceEvents = await peppol.events.list({ invoiceId: \"inv-123\" });\n * ```\n */\n async list(options?: ListEventsOptions): Promise<PaginatedResult<EventEntry>> {\n return this.adapter.listEvents(options);\n }\n\n /**\n * Async iterator over all events, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const event of peppol.events.listAll({ invoiceId: \"inv-123\" })) {\n * console.log(event.name, event.createdAt);\n * }\n * ```\n */\n listAll(options?: Omit<ListEventsOptions, \"offset\">): AsyncIterable<EventEntry> {\n return paginate(\n (offset, limit) => this.adapter.listEvents({ ...options, offset, limit }),\n options,\n );\n }\n}\n\n// ─── Contact Operations ─────────────────────────────────────\n\nclass ContactOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List contacts with optional filtering and pagination.\n *\n * @example\n * ```ts\n * const result = await peppol.contacts.list({ limit: 10, isClient: true });\n * console.log(result.data, result.meta);\n * ```\n */\n async list(options?: ListContactsOptions): Promise<PaginatedResult<Contact>> {\n return this.adapter.listContacts(options);\n }\n\n /**\n * Get a single contact by ID.\n *\n * @example\n * ```ts\n * const contact = await peppol.contacts.get(\"123\");\n * console.log(contact.name, contact.peppolId);\n * ```\n */\n async get(id: string): Promise<Contact> {\n return this.adapter.getContact(id);\n }\n\n /**\n * Create a new contact.\n *\n * @example\n * ```ts\n * const contact = await peppol.contacts.create({\n * name: \"ACMEDIA\",\n * peppolId: \"0208:0685660237\",\n * country: \"BE\",\n * isClient: true,\n * });\n * ```\n */\n async create(input: ContactInput): Promise<Contact> {\n return this.adapter.createContact(input);\n }\n\n /**\n * Update an existing contact.\n *\n * @example\n * ```ts\n * const updated = await peppol.contacts.update(\"123\", { email: \"new@acme.com\" });\n * ```\n */\n async update(id: string, input: Partial<ContactInput>): Promise<Contact> {\n return this.adapter.updateContact(id, input);\n }\n\n /**\n * Delete a contact.\n *\n * @example\n * ```ts\n * await peppol.contacts.delete(\"123\");\n * ```\n */\n async delete(id: string): Promise<void> {\n return this.adapter.deleteContact(id);\n }\n\n /**\n * Async iterator over all contacts, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const contact of peppol.contacts.listAll({ isClient: true })) {\n * console.log(contact.name, contact.peppolId);\n * }\n * ```\n */\n listAll(options?: Omit<ListContactsOptions, \"offset\">): AsyncIterable<Contact> {\n return paginate(\n (offset, limit) => this.adapter.listContacts({ ...options, offset, limit }),\n options,\n );\n }\n}\n\n// ─── Identity Operations ─────────────────────────────────────\n\n/**\n * Your own account's Peppol identity — readable with ANY API key.\n *\n * Unlike `peppol.legalEntities` (platform accounts, master key only), this\n * surface answers \"who am I on the Peppol network?\" for the account behind\n * the key making the call — standard keys included.\n */\nclass IdentityOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Read the Peppol identity of your own account: the environment this key\n * operates in, your legal entity as the gateway holds it, and the Peppol\n * identifiers registered for it.\n *\n * Works with ANY API key — standard keys included; no platform mode or\n * master key required. This is the read counterpart to onboarding: your\n * legal entity is created and edited in the console (Peppol identity page)\n * or via onboarding, and this call is how you READ it from the API.\n *\n * @example\n * ```ts\n * const me = await peppol.identity.get();\n * console.log(me.environment, me.legalEntity?.companyName);\n * for (const id of me.identifiers) {\n * console.log(`${id.scheme}:${id.value} — ${id.status}`);\n * }\n * ```\n */\n async get(): Promise<AccountIdentity> {\n return this.adapter.getIdentity();\n }\n}\n\n/**\n * Sub-tenant Legal Entity operations — **platform accounts only**.\n *\n * Every method here requires a platform account and a master API key; a\n * standard key gets 403 `master_key_required`. Each one repeats the\n * requirement because an IDE shows only the member being hovered.\n *\n * @see https://getpeppr.dev/docs/platform/legal-entities/\n */\nclass LegalEntityOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Create a sub-tenant Legal Entity for one of your customers.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * Your own company's legal entity is managed in the console, on the Peppol\n * identity page (and read from the API with `peppol.identity.get()`); this\n * creates an entity for a customer of yours.\n *\n * Idempotent on `externalId`: repeated calls with the same `externalId` return\n * the existing entity (HTTP 200) instead of creating a duplicate. Transient 5xx\n * failures are NOT auto-retried unless you pass `options.idempotencyKey`.\n *\n * @example\n * ```ts\n * const le = await peppol.legalEntities.create({\n * externalId: \"tenant-42\",\n * companyName: \"Acme Health AB\",\n * country: \"SE\",\n * address: { line1: \"Storgatan 1\", city: \"Stockholm\", zip: \"11122\" },\n * identifier: { scheme: \"0007\", value: \"5560000001\" },\n * }, { idempotencyKey: \"tenant-42-create\" });\n * ```\n */\n async create(input: LegalEntityInput, options?: LegalEntityRequestOptions): Promise<LegalEntity> {\n return this.adapter.createLegalEntity(input, options);\n }\n\n /**\n * Fetch a single sub-tenant Legal Entity by id.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * For production entities the `status` reflects the attestation lifecycle\n * (awaiting_authz → attested → active).\n */\n async get(id: string): Promise<LegalEntity> {\n return this.adapter.getLegalEntity(id);\n }\n\n /**\n * List your sub-tenant Legal Entities, newest first.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * This lists the customers you have onboarded, never your own legal entity.\n */\n async list(options?: ListLegalEntitiesOptions): Promise<PaginatedResult<LegalEntity>> {\n return this.adapter.listLegalEntities(options);\n }\n\n /**\n * Async iterator over all sub-tenant Legal Entities, handling pagination.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * @example\n * ```ts\n * for await (const le of peppol.legalEntities.listAll()) console.log(le.id, le.status);\n * ```\n */\n listAll(options?: Omit<ListLegalEntitiesOptions, \"offset\">): AsyncIterable<LegalEntity> {\n return paginate(\n (offset, limit) => this.adapter.listLegalEntities({ ...options, offset, limit }),\n options,\n );\n }\n\n /**\n * Archive (soft-delete) a sub-tenant Legal Entity. The id stays resolvable\n * for audit.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n */\n async archive(id: string): Promise<ArchiveLegalEntityResult> {\n return this.adapter.archiveLegalEntity(id);\n }\n\n /**\n * Request a sub-tenant attestation (production only). Emails the co-branded\n * confirmation link to the sub-tenant contact and returns the pending status.\n *\n * **Platform accounts only — requires a master API key.** Platform mode is\n * enabled by getpeppr: email hello@getpeppr.dev, then create the key at\n * https://console.getpeppr.dev/api-keys.\n *\n * Transient failures are NOT auto-retried unless you pass `options.idempotencyKey`;\n * re-issuing mints a fresh token, so a retried call is safe.\n *\n * @example\n * ```ts\n * await peppol.legalEntities.requestAttestation(le.id, { contactEmail: \"owner@acme.example\" });\n * ```\n */\n async requestAttestation(id: string, input: AttestationInput, options?: LegalEntityRequestOptions): Promise<AttestationResult> {\n return this.adapter.requestLegalEntityAttestation(id, input, options);\n }\n}\n\n// ─── Bank Account Operations ─────────────────────────────────\n\nclass BankAccountOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List bank accounts with optional pagination.\n *\n * @example\n * ```ts\n * const result = await peppol.bankAccounts.list({ limit: 10 });\n * console.log(result.data, result.meta);\n * ```\n */\n async list(options?: ListBankAccountsOptions): Promise<PaginatedResult<BankAccount>> {\n return this.adapter.listBankAccounts(options);\n }\n\n /**\n * Get a single bank account by ID.\n *\n * @example\n * ```ts\n * const account = await peppol.bankAccounts.get(\"123\");\n * console.log(account.name, account.iban);\n * ```\n */\n async get(id: string): Promise<BankAccount> {\n return this.adapter.getBankAccount(id);\n }\n\n /**\n * Create a new bank account.\n *\n * @example\n * ```ts\n * const account = await peppol.bankAccounts.create({\n * name: \"Main Account\",\n * iban: \"BE68539007547034\",\n * bic: \"BBRUBEBB\",\n * country: \"BE\",\n * });\n * ```\n */\n async create(input: BankAccountInput): Promise<BankAccount> {\n return this.adapter.createBankAccount(input);\n }\n\n /**\n * Update an existing bank account.\n *\n * @example\n * ```ts\n * const updated = await peppol.bankAccounts.update(\"123\", { name: \"Updated Name\" });\n * ```\n */\n async update(id: string, input: Partial<BankAccountInput>): Promise<BankAccount> {\n return this.adapter.updateBankAccount(id, input);\n }\n\n /**\n * Delete a bank account.\n *\n * @example\n * ```ts\n * await peppol.bankAccounts.delete(\"123\");\n * ```\n */\n async delete(id: string): Promise<void> {\n return this.adapter.deleteBankAccount(id);\n }\n\n /**\n * Async iterator over all bank accounts, automatically handling pagination.\n *\n * @example\n * ```ts\n * for await (const account of peppol.bankAccounts.listAll()) {\n * console.log(account.name, account.iban);\n * }\n * ```\n */\n listAll(options?: Omit<ListBankAccountsOptions, \"offset\">): AsyncIterable<BankAccount> {\n return paginate(\n (offset, limit) => this.adapter.listBankAccounts({ ...options, offset, limit }),\n options,\n );\n }\n}\n\n// ─── Transport Operations ────────────────────────────────────\n\nclass TransportOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * List all available transport types in the network.\n * Returns global transport types (not account-scoped).\n *\n * @example\n * ```ts\n * const types = await peppol.transports.listTypes();\n * console.log(types); // [{ code: \"peppol\", name: \"Peppol BIS 3.0\" }, ...]\n * ```\n */\n async listTypes(): Promise<TransportType[]> {\n return this.adapter.listTransportTypes();\n }\n\n /**\n * List configured transports for this account.\n *\n * @example\n * ```ts\n * const transports = await peppol.transports.list();\n * console.log(transports); // [{ id: \"t-1\", transportTypeCode: \"peppol\", name: \"...\" }, ...]\n * ```\n */\n async list(): Promise<Transport[]> {\n return this.adapter.listTransports();\n }\n\n /**\n * Get a single transport by code.\n *\n * @example\n * ```ts\n * const transport = await peppol.transports.get(\"peppol\");\n * ```\n */\n async get(code: string): Promise<Transport> {\n return this.adapter.getTransport(code);\n }\n\n /**\n * Create a new transport.\n *\n * @example\n * ```ts\n * const transport = await peppol.transports.create({\n * transportTypeCode: \"peppol\",\n * email: \"billing@acme.com\",\n * });\n * ```\n */\n async create(input: TransportInput): Promise<Transport> {\n return this.adapter.createTransport(input);\n }\n\n /**\n * Update an existing transport.\n *\n * @example\n * ```ts\n * const transport = await peppol.transports.update(\"peppol\", { email: \"new@acme.com\" });\n * ```\n */\n async update(code: string, input: TransportUpdateInput): Promise<Transport> {\n return this.adapter.updateTransport(code, input);\n }\n\n /**\n * Delete a transport.\n *\n * @example\n * ```ts\n * await peppol.transports.delete(\"peppol\");\n * ```\n */\n async delete(code: string): Promise<void> {\n return this.adapter.deleteTransport(code);\n }\n}\n\n// ─── Webhook Helper ─────────────────────────────────────────\n\n/** Default tolerance for webhook timestamp verification (5 minutes) */\nconst DEFAULT_TOLERANCE_SECONDS = 300;\n\n/**\n * Parse and verify a webhook payload from getpeppr.\n *\n * getpeppr signs webhooks with HMAC-SHA256. The signature header format is:\n * `Getpeppr-Signature: t={timestamp},s={hmac_sha256_hex}`\n *\n * The signed payload is: `{timestamp}.{raw_json_body}`\n *\n * @example\n * ```ts\n * import { webhooks } from \"@getpeppr/sdk\";\n *\n * app.post(\"/webhooks/peppol\", async (req, res) => {\n * try {\n * const event = await webhooks.constructEvent(\n * req.body, // raw body string (NOT parsed JSON)\n * req.headers[\"getpeppr-signature\"], // signature header\n * \"whsec_your_webhook_secret\", // your endpoint's signing secret\n * );\n * switch (event.type) {\n * case \"inbound.invoice.received\":\n * console.log(\"New invoice from:\", event.data.sender.peppolId);\n * break;\n * }\n * res.sendStatus(200);\n * } catch (err) {\n * res.status(400).send(\"Webhook verification failed\");\n * }\n * });\n * ```\n */\nexport const webhooks = {\n /**\n * Parse a webhook payload without signature verification.\n * Use `constructEvent()` for verified parsing in production.\n */\n parse(payload: unknown): WebhookEvent {\n return payload as WebhookEvent;\n },\n\n /**\n * Verify and parse a webhook payload using HMAC-SHA256 signature.\n * Throws `PeppolError` if verification fails.\n *\n * @param rawBody — The raw request body string (NOT parsed JSON)\n * @param signatureHeader — The `Getpeppr-Signature` header value\n * @param secret — Your webhook secret from getpeppr\n * @param toleranceSeconds — Max age of the webhook in seconds (default: 300 = 5 min)\n */\n async constructEvent(\n rawBody: string,\n signatureHeader: string,\n secret: string,\n toleranceSeconds?: number,\n ): Promise<WebhookEvent> {\n if (!rawBody) {\n throw new PeppolError(\"Webhook error: missing request body\");\n }\n if (!signatureHeader) {\n throw new PeppolError(\"Webhook error: missing Getpeppr-Signature header\");\n }\n if (!secret) {\n throw new PeppolError(\"Webhook error: missing webhook secret\");\n }\n\n // Parse header: t={timestamp},s={signature}\n const match = signatureHeader.match(/t=([^,]+),s=(.+)/);\n if (!match) {\n throw new PeppolError(\n \"Webhook error: invalid signature header format. Expected 't={timestamp},s={signature}'\"\n );\n }\n\n const [, timestampStr, receivedSignature] = match;\n const timestamp = Number(timestampStr);\n\n if (!Number.isFinite(timestamp)) {\n throw new PeppolError(\"Webhook error: invalid timestamp in signature header\");\n }\n\n // Check timestamp tolerance (prevent replay attacks)\n const tolerance = toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > tolerance) {\n throw new PeppolError(\n `Webhook error: timestamp too old or too new (received: ${timestamp}, now: ${now}, tolerance: ${tolerance}s)`\n );\n }\n\n // Compute expected signature: HMAC-SHA256(secret, \"{timestamp}.{rawBody}\")\n const signedPayload = `${timestampStr}.${rawBody}`;\n const expectedSignature = await computeHmacSha256(secret, signedPayload);\n\n // Constant-time comparison to prevent timing attacks\n if (!timingSafeEqual(expectedSignature, receivedSignature)) {\n throw new PeppolError(\"Webhook error: signature verification failed\");\n }\n\n // Parse and return the event\n try {\n const parsed = typeof rawBody === \"string\" ? JSON.parse(rawBody) : rawBody;\n return parsed as WebhookEvent;\n } catch {\n throw new PeppolError(\"Webhook error: invalid JSON payload\");\n }\n },\n};\n\n/**\n * Compute HMAC-SHA256 hex digest.\n * Uses Web Crypto API (works in Node.js 18+, Deno, Bun, browsers).\n */\nasync function computeHmacSha256(secret: string, message: string): Promise<string> {\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(message));\n return Array.from(new Uint8Array(signature))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks.\n */\nfunction timingSafeEqual(a: string, b: string): boolean {\n const len = Math.max(a.length, b.length);\n let result = a.length ^ b.length; // non-zero if lengths differ\n for (let i = 0; i < len; i++) {\n result |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);\n }\n return result === 0;\n}\n","/**\n * Offline Schematron-like Validation\n *\n * Reimplements a subset of the Peppol BIS 3.0 business rules as pure TypeScript\n * checks. This is NOT a full XSD/XSLT schematron processor — it's a fast, offline\n * validator that catches the most commonly violated rules before the invoice\n * reaches the network.\n *\n * ⛔ The rules covered are exactly those in `SDK_SCHEMATRON_RULE_IDS` (below),\n * and that registry is the only place the count lives. This header said\n * \"~25\" while the registry held 18 — a number recited in prose drifts from the\n * one the code measures, and only the code can be right.\n * `ubl-validation/__tests__/sdk-non-contradiction.test.ts` pins the length, so\n * adding or removing a rule without updating the registry reds.\n *\n * Rules are grouped by category:\n * - BR-xx — Required field rules (EN 16931)\n * - BR-CO-xx — Calculation / cross-field consistency rules\n * - BR-S-xx — Tax category rules\n * - PEPPOL-xx — Peppol BIS 3.0 specific rules\n *\n * Design: each rule is a pure function (InvoiceInput) => SchematronViolation[].\n * No side effects, no XML, no network.\n */\n\nimport type { InvoiceInput, InvoiceLine } from \"../types/invoice.js\";\nimport { resolveUnit, getAllUnits } from \"./code-lists.js\";\n\n// ─── Types ──────────────────────────────────────────────────────────────────────\n\nexport interface SchematronViolation {\n /** Peppol business rule identifier (e.g., \"BR-02\", \"BR-S-05\") */\n ruleId: string;\n /** Severity: \"error\" blocks sending, \"warning\" is advisory */\n severity: \"error\" | \"warning\";\n /** Human-readable description of the violation */\n message: string;\n /** Relevant field path (e.g., \"lines[0].vatRate\") */\n field?: string;\n}\n\nexport interface SchematronResult {\n /**\n * ⚠️ « Aucun problème parmi les contrôles effectués » — PAS « conforme Peppol ».\n * Ce validateur couvre 18 règles sur les 333+ que le réseau applique.\n * Le verdict qui engage est rendu à l'envoi.\n */\n valid: boolean;\n /** Ce qui a réellement été vérifié — pour que l'appelant sache ce que `valid` couvre. */\n coverage: { rulesChecked: number; ofNetworkFatalRules: \"partial\" };\n /** Blocking violations — invoice would be rejected */\n errors: SchematronViolation[];\n /** Advisory notices — invoice may be accepted but is suboptimal */\n warnings: SchematronViolation[];\n}\n\n// ─── Rule function type ─────────────────────────────────────────────────────────\n\ntype RuleFn = (input: InvoiceInput) => SchematronViolation[];\n\n// ─── Helpers ────────────────────────────────────────────────────────────────────\n\nfunction violation(\n ruleId: string,\n severity: \"error\" | \"warning\",\n message: string,\n field?: string,\n): SchematronViolation {\n return { ruleId, severity, message, field };\n}\n\n/** Build a Set of all known UN/ECE Rec20 unit codes (lazy singleton). */\nlet _knownUnitCodes: Set<string> | undefined;\nfunction getKnownUnitCodes(): Set<string> {\n if (!_knownUnitCodes) {\n _knownUnitCodes = new Set(getAllUnits().map((u) => u.code));\n }\n return _knownUnitCodes;\n}\n\n/**\n * The ten VAT category codes EN 16931 allows, verbatim from `BR-CL-17`'s test:\n * `' AE L M E S Z G O K B '`.\n *\n * ⚠️ This set used to hold NINE — `B` (Italian split payment) was missing, so\n * the validator reported \"invalid\" for a code the network accepts. Being\n * stricter than the network is the worse of the two errors (GPR-904): a false\n * refusal closes a corridor, a malformed document costs one document.\n */\nexport const VALID_VAT_CATEGORIES: ReadonlySet<string> = new Set([\"S\", \"Z\", \"E\", \"AE\", \"K\", \"G\", \"O\", \"L\", \"M\", \"B\"]);\n\n/**\n * The categories the gateway can actually put on the wire.\n *\n * `L` (IGIC) and `M` (IPSI) were translated to `canary_islands` /\n * `ceuta_melilla` — values absent from every Storecove artefact — and `B` has no\n * provider equivalent at all (GPR-1012). They are valid EN 16931 codes that we\n * cannot route, which is a different finding from \"not a category\", and saying\n * so is the whole point: the previous message conflated the two.\n *\n * Drift-locked against the gateway's own table by\n * `console/src/lib/api/__tests__/vat-category-sdk-alignment.test.ts`.\n */\nexport const SENDABLE_VAT_CATEGORIES = [\"S\", \"Z\", \"E\", \"AE\", \"K\", \"G\", \"O\"] as const;\nconst UNROUTABLE_VAT_CATEGORIES = new Set([\"L\", \"M\", \"B\"]);\n\n/**\n * Compute the net amount for a single invoice line.\n * Formula: (quantity * unitPrice / baseQuantity) + charges - allowances\n */\nfunction computeLineNet(line: InvoiceLine): number {\n const baseQty = line.baseQuantity ?? 1;\n if (baseQty === 0) return NaN; // Will be caught by BR-CO-10\n const baseAmount = (line.quantity * line.unitPrice) / baseQty;\n const chargeTotal = (line.charges ?? []).reduce((sum, c) => sum + c.amount, 0);\n const allowanceTotal = (line.allowances ?? []).reduce((sum, a) => sum + a.amount, 0);\n return baseAmount + chargeTotal - allowanceTotal;\n}\n\n// ─── Required Field Rules (BR-01 to BR-10) ──────────────────────────────────────\n\n/**\n * BR-01: Invoice shall have a Specification identifier.\n * Auto-pass: the gateway always sets \"urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\".\n */\n// (no-op — always satisfied)\n\n/**\n * BR-02: An Invoice shall have an Invoice number.\n */\nconst br02: RuleFn = (input) => {\n if (!input.number?.trim()) {\n return [violation(\"BR-02\", \"error\", \"Invoice number is required.\", \"number\")];\n }\n return [];\n};\n\n/**\n * BR-03: An Invoice shall have an Invoice issue date.\n * The SDK defaults to today if omitted, so this is a warning.\n */\nconst br03: RuleFn = (input) => {\n if (!input.date) {\n return [\n violation(\n \"BR-03\",\n \"warning\",\n \"Invoice issue date is not set. The SDK will default to today's date.\",\n \"date\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * BR-04: An Invoice shall have an Invoice currency code.\n * Auto-pass: defaults to EUR.\n */\n// (no-op)\n\n/**\n * BR-05: An Invoice shall have an Invoice type code.\n * Auto-pass: always set (380 for invoice, 381 for credit note).\n */\n// (no-op)\n\n/**\n * BR-06: An Invoice shall have the Seller VAT identifier or tax registration.\n * The `from` field is deprecated — seller is determined by API key.\n * Only warn if `from` IS provided but has no vatNumber.\n */\nconst br06: RuleFn = (input) => {\n if (input.from && !input.from.vatNumber) {\n return [\n violation(\n \"BR-06\",\n \"warning\",\n \"Seller party has no VAT number. The gateway will use the account's VAT registration.\",\n \"from.vatNumber\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * BR-07: An Invoice shall have the Buyer name.\n */\nconst br07: RuleFn = (input) => {\n if (!input.to?.name?.trim()) {\n return [violation(\"BR-07\", \"error\", \"Buyer name is required.\", \"to.name\")];\n }\n return [];\n};\n\n/**\n * BR-08: An Invoice shall have at least one Invoice line.\n */\nconst br08: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) {\n return [violation(\"BR-08\", \"error\", \"Invoice must have at least one line item.\", \"lines\")];\n }\n return [];\n};\n\n/**\n * BR-09: An Invoice shall have the Payment due date or Payment terms.\n */\nconst br09: RuleFn = (input) => {\n if (!input.dueDate && !input.paymentTerms) {\n return [\n violation(\n \"BR-09\",\n \"warning\",\n \"Neither due date nor payment terms specified. At least one is recommended.\",\n \"dueDate\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * BR-10: An Invoice shall have the Buyer reference or Order reference.\n */\nconst br10: RuleFn = (input) => {\n if (!input.buyerReference && !input.orderReference) {\n return [\n violation(\n \"BR-10\",\n \"warning\",\n \"Neither buyerReference nor orderReference specified. Peppol BIS 3.0 requires at least one.\",\n \"buyerReference\",\n ),\n ];\n }\n return [];\n};\n\n// ─── Calculation Rules (BR-CO) ──────────────────────────────────────────────────\n\n/**\n * BR-CO-10: Sum of Invoice line net amounts = sum of (quantity x unit price / base quantity)\n * adjusted by line allowances/charges.\n *\n * Since InvoiceInput has no explicit totals, we verify each line's computation is valid\n * (no NaN, no Infinity, handles baseQuantity correctly).\n */\nconst brCo10: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n const net = computeLineNet(line);\n\n if (!Number.isFinite(net)) {\n const baseQty = line.baseQuantity ?? 1;\n const detail =\n baseQty === 0\n ? \"baseQuantity is 0, causing division by zero.\"\n : \"Computed line amount is not a finite number.\";\n violations.push(\n violation(\"BR-CO-10\", \"error\", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-CO-13: Invoice total VAT amount = sum of (line net amount x VAT rate / 100) per category.\n *\n * We verify the VAT computation is valid and consistent. Since InvoiceInput has no explicit\n * VAT total field, we check that the computed amount is finite and non-negative.\n */\nconst brCo13: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) return [];\n\n let totalVat = 0;\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n const net = computeLineNet(line);\n if (!Number.isFinite(net)) continue; // Already caught by BR-CO-10\n totalVat += net * (line.vatRate / 100);\n }\n\n // Include document-level allowances/charges in VAT\n for (const allowance of input.allowances ?? []) {\n totalVat -= allowance.amount * (allowance.vatRate / 100);\n }\n for (const charge of input.charges ?? []) {\n totalVat += charge.amount * (charge.vatRate / 100);\n }\n\n if (!Number.isFinite(totalVat)) {\n return [\n violation(\n \"BR-CO-13\",\n \"error\",\n \"Computed total VAT amount is not a finite number. Check line amounts and VAT rates.\",\n ),\n ];\n }\n\n if (totalVat < -0.01) {\n return [\n violation(\n \"BR-CO-13\",\n \"warning\",\n `Computed total VAT is negative (${totalVat.toFixed(2)}). This is unusual for an invoice.`,\n ),\n ];\n }\n\n return [];\n};\n\n/**\n * BR-CO-15: Invoice tax inclusive amount = Invoice total amount without VAT + Invoice total VAT amount.\n *\n * We verify the computation produces a finite, non-negative result.\n */\nconst brCo15: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) return [];\n\n let lineTotal = 0;\n let vatTotal = 0;\n\n for (const line of input.lines) {\n const net = computeLineNet(line);\n if (!Number.isFinite(net)) continue;\n lineTotal += net;\n vatTotal += net * (line.vatRate / 100);\n }\n\n // Document-level allowances/charges\n for (const allowance of input.allowances ?? []) {\n lineTotal -= allowance.amount;\n vatTotal -= allowance.amount * (allowance.vatRate / 100);\n }\n for (const charge of input.charges ?? []) {\n lineTotal += charge.amount;\n vatTotal += charge.amount * (charge.vatRate / 100);\n }\n\n const taxInclusive = lineTotal + vatTotal;\n\n if (!Number.isFinite(taxInclusive)) {\n return [\n violation(\n \"BR-CO-15\",\n \"error\",\n \"Computed tax-inclusive amount is not a finite number.\",\n ),\n ];\n }\n\n if (taxInclusive < -0.01) {\n return [\n violation(\n \"BR-CO-15\",\n \"warning\",\n `Computed tax-inclusive amount is negative (${taxInclusive.toFixed(2)}). Consider using a credit note instead.`,\n ),\n ];\n }\n\n return [];\n};\n\n/**\n * BR-CO-16: Amount due for payment = Invoice total amount with VAT - Paid amount + Rounding amount.\n *\n * Verifies payable amount is non-negative when prepaidAmount is used.\n */\nconst brCo16: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) return [];\n\n let lineTotal = 0;\n let vatTotal = 0;\n\n for (const line of input.lines) {\n const net = computeLineNet(line);\n if (!Number.isFinite(net)) continue;\n lineTotal += net;\n vatTotal += net * (line.vatRate / 100);\n }\n\n // Document-level allowances/charges\n for (const allowance of input.allowances ?? []) {\n lineTotal -= allowance.amount;\n vatTotal -= allowance.amount * (allowance.vatRate / 100);\n }\n for (const charge of input.charges ?? []) {\n lineTotal += charge.amount;\n vatTotal += charge.amount * (charge.vatRate / 100);\n }\n\n const taxInclusive = lineTotal + vatTotal;\n const prepaid = input.prepaidAmount ?? 0;\n const rounding = input.roundingAmount ?? 0;\n const payable = taxInclusive - prepaid + rounding;\n\n if (!Number.isFinite(payable)) {\n return [\n violation(\n \"BR-CO-16\",\n \"error\",\n \"Computed payable amount is not a finite number.\",\n ),\n ];\n }\n\n if (payable < -0.01) {\n return [\n violation(\n \"BR-CO-16\",\n \"warning\",\n `Computed payable amount is negative (${payable.toFixed(2)}). Prepaid amount (${prepaid}) exceeds the invoice total.`,\n ),\n ];\n }\n\n return [];\n};\n\n// ─── Tax Category Rules (one family PER category) ───────────────────────────────\n\n/**\n * BR-S-05: In an Invoice line where the Invoiced item VAT category code is \"Standard rated\" (S),\n * the Invoiced item VAT rate shall be greater than zero.\n *\n * ⚠️ Cited `BR-S-01` until GPR-1069. `BR-S-01` is a real rule, which is exactly why\n * the mistake survived: it governs the VAT BREAKDOWN, not the line rate. Verbatim,\n * `CEN-EN16931-UBL.sch:344` (release v3.0.20).\n */\nconst brS05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n const category = line.vatCategory ?? \"S\"; // Default is standard rate\n if (category === \"S\" && (line.vatRate === undefined || line.vatRate <= 0)) {\n violations.push(\n violation(\n \"BR-S-05\",\n \"error\",\n `Line ${i}: standard rate (S) requires vatRate > 0, got ${line.vatRate ?? \"undefined\"}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-Z-05: In an Invoice line where the Invoiced item VAT category code is \"Zero rated\" (Z),\n * the Invoiced item VAT rate shall be 0 (zero).\n *\n * ⚠️ Cited `BR-S-05` until GPR-1069 — the `S` family, not the `Z` one.\n * Verbatim, `CEN-EN16931-UBL.sch:358` (release v3.0.20).\n */\nconst brZ05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.vatCategory === \"Z\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-Z-05\",\n \"error\",\n `Line ${i}: zero-rated (Z) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-E-05: In an Invoice line where the Invoiced item VAT category code is \"Exempt from VAT\" (E),\n * the Invoiced item VAT rate shall be 0 (zero).\n *\n * ⚠️ Cited `BR-S-06` until GPR-1069 — the `S` family, not the `E` one.\n * Verbatim, `CEN-EN16931-UBL.sch:260` (release v3.0.20).\n */\nconst brE05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.vatCategory === \"E\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-E-05\",\n \"error\",\n `Line ${i}: exempt (E) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * BR-AE-05: In an Invoice line where the Invoiced item VAT category code is \"Reverse charge\" (AE),\n * the Invoiced item VAT rate shall be 0 (zero).\n *\n * ⚠️ Cited `BR-S-08` until GPR-1069 — the `S` family, not the `AE` one.\n * Verbatim, `CEN-EN16931-UBL.sch:246` (release v3.0.20).\n */\nconst brAe05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.vatCategory === \"AE\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-AE-05\",\n \"error\",\n `Line ${i}: reverse charge (AE) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n\n return violations;\n};\n\n// ─── Peppol-Specific Rules ──────────────────────────────────────────────────────\n\n/**\n * PEPPOL-EN16931-R001: Business process MUST be provided.\n * Auto-pass: the gateway always sets \"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\".\n */\n// (no-op)\n\n/**\n * PEPPOL-EN16931-R004: A Buyer electronic address SHALL exist.\n */\nconst peppolR004: RuleFn = (input) => {\n if (!input.to?.peppolId) {\n return [\n violation(\n \"PEPPOL-EN16931-R004\",\n \"error\",\n \"Buyer electronic address (peppolId) is required for Peppol delivery.\",\n \"to.peppolId\",\n ),\n ];\n }\n return [];\n};\n\n/**\n * VAT category codes, checked on lines and on document-level allowances and\n * charges alike.\n *\n * Two DISTINCT findings, because they are two different problems (GPR-1012):\n * - `BR-CL-17` — not a VAT category code at all. This is the real rule id;\n * the previous code cited `PEPPOL-EN16931-R006`, which does NOT exist in\n * rulebook v3.0.20 (that family stops at R005, R007, R008).\n * - `unsupported_vat_category` — a valid EN 16931 code the gateway cannot put\n * on the wire. No Peppol rule to cite: it is a provider-capability limit,\n * and calling it \"invalid\" was simply false.\n *\n * Codes are CASE-SENSITIVE, and saying so is load-bearing: `\"ae\"` used to be\n * coerced to standard rate by the gateway, shipping a valid invoice that never\n * shifted the VAT liability to the buyer.\n */\nconst vatCategoryCodes: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n const sendable = SENDABLE_VAT_CATEGORIES.join(\", \");\n\n /**\n * A VAT category is at most two characters, so a longer value is already\n * wrong and quoting it whole gains nothing. Unbounded, a 100 kB category\n * produced a 100 kB message that `validate/server` returned verbatim.\n */\n const echo = (v: string): string => (v.length <= 16 ? v : `${v.slice(0, 16)}…`);\n\n const check = (cat: string | undefined, field: string, label: string): void => {\n // `null` counts as ABSENT, exactly like `undefined` — the gateway's\n // `isSupplied` says so, and a validator that disagrees with the endpoint it\n // advises is worse than no validator. JSON serialisers emit `null` for an\n // unset field routinely, and the previous code reported\n // `\"null\" is not a VAT category code` for a payload that sends fine.\n if (cat === undefined || cat === null) return;\n\n if (!VALID_VAT_CATEGORIES.has(cat)) {\n violations.push(\n violation(\n \"BR-CL-17\",\n \"error\",\n `${label}: \"${echo(cat)}\" is not a VAT category code. Use one of: ${sendable}. ` +\n `Codes are case-sensitive — \"AE\" is reverse charge, \"ae\" is not a category.`,\n field,\n ),\n );\n return;\n }\n\n if (UNROUTABLE_VAT_CATEGORIES.has(cat)) {\n violations.push(\n violation(\n \"unsupported_vat_category\",\n \"error\",\n `${label}: VAT category \"${echo(cat)}\" is valid under EN 16931 but getpeppr cannot route it — ` +\n `our provider has no vocabulary for it. Sendable categories: ${sendable}.`,\n field,\n ),\n );\n }\n };\n\n (input.lines ?? []).forEach((line, i) =>\n check(line.vatCategory, `lines[${i}].vatCategory`, `Line ${i}`),\n );\n (input.allowances ?? []).forEach((a, i) =>\n check(a.vatCategory, `allowances[${i}].vatCategory`, `Allowance ${i}`),\n );\n (input.charges ?? []).forEach((c, i) =>\n check(c.vatCategory, `charges[${i}].vatCategory`, `Charge ${i}`),\n );\n\n return violations;\n};\n\n/**\n * PEPPOL-EN16931-R080: Unit of measure MUST be coded using UN/ECE Recommendation 20.\n * Warning-level since unknown codes pass through to the gateway which may accept them.\n */\nconst peppolR080: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n const knownCodes = getKnownUnitCodes();\n\n for (let i = 0; i < input.lines.length; i++) {\n const line = input.lines[i]!;\n if (line.unit) {\n const resolved = resolveUnit(line.unit);\n if (!knownCodes.has(resolved)) {\n violations.push(\n violation(\n \"PEPPOL-EN16931-R080\",\n \"warning\",\n `Line ${i}: unit \"${line.unit}\" (resolved: \"${resolved}\") is not a known UN/ECE Rec20 code. Common codes: EA, HUR, DAY, KGM.`,\n `lines[${i}].unit`,\n ),\n );\n }\n }\n // No unit specified → defaults to \"EA\" which is valid → no violation\n }\n\n return violations;\n};\n\n// ─── Rule Registry ──────────────────────────────────────────────────────────────\n\n/** All active rules in evaluation order. */\nconst ALL_RULES: readonly RuleFn[] = [\n // Required fields (BR)\n br02,\n br03,\n br06,\n br07,\n br08,\n br09,\n br10,\n // Calculations (BR-CO)\n brCo10,\n brCo13,\n brCo15,\n brCo16,\n // Tax categories (one family per category)\n brS05,\n brZ05,\n brE05,\n brAe05,\n // Peppol-specific\n peppolR004,\n vatCategoryCodes,\n peppolR080,\n];\n\n// ─── Main Validation Function ───────────────────────────────────────────────────\n\n/**\n * Validate an InvoiceInput against Peppol BIS 3.0 business rules (offline).\n *\n * Runs the rules listed in `SDK_SCHEMATRON_RULE_IDS` — a subset of the most\n * commonly violated ones — as pure TypeScript checks. No XML generation, no\n * network calls: instant feedback. The count is read from the registry, never\n * written here; `result.coverage.rulesChecked` reports it at runtime.\n *\n * ⚠️ A pass means \"nothing wrong among the checks performed\", NOT \"Peppol\n * conformant\" — the verdict that commits is the one returned at send time.\n *\n * @param input - The invoice to validate\n * @returns Validation result with errors (blocking) and warnings (advisory)\n *\n * @example\n * ```ts\n * const result = validateSchematron({\n * number: \"INV-001\",\n * to: { name: \"Acme\", peppolId: \"0208:0685660237\", country: \"BE\" },\n * lines: [{ description: \"Widget\", quantity: 1, unitPrice: 100, vatRate: 21 }],\n * });\n *\n * if (!result.valid) {\n * console.error(\"Validation failed:\", result.errors);\n * }\n * ```\n */\nexport function validateSchematron(input: InvoiceInput): SchematronResult {\n const errors: SchematronViolation[] = [];\n const warnings: SchematronViolation[] = [];\n\n for (const rule of ALL_RULES) {\n const violations = rule(input);\n for (const v of violations) {\n if (v.severity === \"error\") {\n errors.push(v);\n } else {\n warnings.push(v);\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n coverage: { rulesChecked: SDK_SCHEMATRON_RULE_IDS.length, ofNetworkFatalRules: \"partial\" },\n errors,\n warnings,\n };\n}\n\n/**\n * GPR-1069 — les règles que CE validateur couvre réellement.\n *\n * ⚠️ 18 sur les 333+ que le réseau applique. Ce module est un PRÉ-CONTRÔLE local :\n * il attrape les erreurs les plus fréquentes sans appel réseau. Le verdict qui\n * engage est celui rendu à l'envoi.\n *\n * ⛔ Ces identifiants sont ceux que CE FICHIER émet (`violation(\"BR-xx\", ...)`).\n * Les QUATRE règles de catégorie de TVA ont été confrontées une par une au\n * rulebook gravé et corrigées (GPR-1069) : elles citaient toutes la famille\n * `BR-S-`, celle de la catégorie « standard », pour des règles gouvernant `Z`,\n * `E` et `AE`. ⚠️ **Les quatorze autres n'ont PAS été auditées de la même\n * façon**, et au moins `BR-06`, `BR-08`, `BR-09`, `BR-10`, `BR-CO-13`,\n * `PEPPOL-EN16931-R004` et `PEPPOL-EN16931-R080` désignent officiellement une\n * règle DIFFÉRENTE de celle qu'ils vérifient ici — écart relevé par lecture du\n * `.sch`, non tranché (GPR-897 §5.5, GPR-1069).\n *\n * ⭐ Un identifiant faux ne se voit pas à l'existence : les quatre corrigés\n * existaient tous dans le rulebook. Seule la comparaison des COMPORTEMENTS les\n * a trouvés — `ubl-validation/__tests__/sdk-non-contradiction.test.ts`, côté\n * console, qui fait tourner ce module et le moteur officiel sur le même\n * document et rougit si leurs verdicts s'opposent.\n */\nexport const SDK_SCHEMATRON_RULE_IDS = [\n \"BR-02\", \"BR-03\", \"BR-06\", \"BR-07\", \"BR-08\", \"BR-09\", \"BR-10\",\n \"BR-CL-17\", \"BR-CO-10\", \"BR-CO-13\", \"BR-CO-15\", \"BR-CO-16\",\n \"BR-S-05\", \"BR-Z-05\", \"BR-E-05\", \"BR-AE-05\",\n \"PEPPOL-EN16931-R004\", \"PEPPOL-EN16931-R080\",\n] as const;\n","import type { Command } from \"commander\";\nimport { readAndValidateInvoiceJson } from \"../utils/file.js\";\nimport { formatValidationResult } from \"../formatters/validation.js\";\nimport {\n validateInvoice,\n validateSchematron,\n validateCountryRules,\n type InvoiceInput,\n type ValidationError,\n type ValidationWarning,\n type SchematronViolation,\n} from \"@getpeppr/sdk\";\n\nexport interface MergedValidationResult {\n structure: {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n };\n schematron: {\n errors: SchematronViolation[];\n warnings: SchematronViolation[];\n };\n countryRules: {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n };\n totalErrors: number;\n totalWarnings: number;\n valid: boolean;\n}\n\nexport function runValidation(input: InvoiceInput): MergedValidationResult {\n const structure = validateInvoice(input);\n const schematron = validateSchematron(input);\n const countryRules = validateCountryRules(input);\n\n const totalErrors =\n structure.errors.length +\n schematron.errors.length +\n countryRules.errors.length;\n\n const totalWarnings =\n structure.warnings.length +\n schematron.warnings.length +\n countryRules.warnings.length;\n\n return {\n structure: { errors: structure.errors, warnings: structure.warnings },\n schematron: { errors: schematron.errors, warnings: schematron.warnings },\n countryRules: {\n errors: countryRules.errors,\n warnings: countryRules.warnings,\n },\n totalErrors,\n totalWarnings,\n valid: totalErrors === 0,\n };\n}\n\nexport function registerValidateCommand(program: Command): void {\n program\n .command(\"validate\")\n .description(\"Validate a Peppol invoice JSON file\")\n .argument(\"<file>\", \"path to invoice JSON file\")\n .option(\"--json\", \"output results as JSON\")\n .option(\"--quiet\", \"exit code only, no output\")\n .action(async (file: string, options: { json?: boolean; quiet?: boolean }) => {\n // 1. Read and parse the JSON file\n // Fatal errors always go to stderr regardless of --quiet (UNIX convention)\n const input = readAndValidateInvoiceJson(file);\n\n // 2. Run all 3 validators\n const result = runValidation(input);\n\n // 3. Output\n if (options.quiet) {\n process.exit(result.valid ? 0 : 1);\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n process.exit(result.valid ? 0 : 1);\n }\n\n // 4. Formatted output\n const output = formatValidationResult(file, result);\n console.log(output);\n process.exit(result.valid ? 0 : 1);\n });\n}\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport { INVOICE_TEMPLATE } from \"../templates/invoice.js\";\nimport { CREDIT_NOTE_TEMPLATE } from \"../templates/credit-note.js\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Scaffold a starter invoice JSON file\")\n .argument(\"[filename]\", \"output filename\", \"invoice.json\")\n .option(\"--credit-note\", \"generate a credit note template instead\")\n .option(\"--force\", \"overwrite existing file\")\n .action(\n (\n filename: string,\n options: { creditNote?: boolean; force?: boolean },\n ) => {\n const resolved = resolve(filename);\n\n if (existsSync(resolved) && !options.force) {\n exitWithError(\n `Error: ${filename} already exists. Use --force to overwrite.`,\n );\n }\n\n const template = options.creditNote\n ? CREDIT_NOTE_TEMPLATE\n : INVOICE_TEMPLATE;\n\n try {\n writeFileSync(\n resolved,\n JSON.stringify(template, null, 2) + \"\\n\",\n \"utf-8\",\n );\n } catch {\n exitWithError(`Error: could not write file — ${resolved}`);\n }\n\n process.stderr.write(`${pc.green(\"\\u2713\")} Created ${filename}\n\n Next steps:\n 1. Edit the file with your invoice data\n 2. Validate: getpeppr validate ${filename}\n 3. Convert to XML: getpeppr convert ${filename}\n 4. Send: getpeppr send ${filename}\n\n ${pc.dim(\"Sandbox note:\")} this template includes VAT. To send it on a sandbox\n account, first register your VAT on the Peppol identity page, or set each\n line's \"vatCategory\" to \"O\" (outside the scope of VAT) for a no-VAT test send.\\n`);\n\n process.exit(0);\n },\n );\n}\n","import type { InvoiceInput } from \"@getpeppr/sdk\";\n\nexport const INVOICE_TEMPLATE: InvoiceInput = {\n number: \"INV-2026-001\",\n date: \"2026-01-15\",\n dueDate: \"2026-02-15\",\n currency: \"EUR\",\n buyerReference: \"PO-2026-042\",\n from: {\n name: \"Dupont & Fils SPRL\",\n peppolId: \"0208:0685660237\",\n street: \"Avenue Louise 54\",\n city: \"Bruxelles\",\n postalCode: \"1050\",\n country: \"BE\",\n },\n // Sandbox test receiver (GPR-828): the only recipient guaranteed reachable on\n // the Storecove test network -- real directory companies make sandbox sends fail.\n to: {\n name: \"SPF Economie (test receiver)\",\n peppolId: \"9925:BE0314595348\",\n street: \"Rue du Progr\\u00e8s 50\",\n city: \"Brussels\",\n postalCode: \"1210\",\n country: \"BE\",\n },\n lines: [\n {\n description: \"Conseil en transformation num\\u00e9rique\",\n quantity: 10,\n unitPrice: 950,\n vatRate: 21,\n },\n {\n description: \"Software license \\u2014 annual subscription\",\n quantity: 1,\n unitPrice: 2400,\n vatRate: 0,\n vatCategory: \"AE\",\n },\n ],\n paymentTerms: \"Net 30 days\",\n paymentReference: \"+++000/0000/00097+++\",\n};\n","import type { InvoiceInput } from \"@getpeppr/sdk\";\n\nexport const CREDIT_NOTE_TEMPLATE: InvoiceInput = {\n number: \"CN-2026-001\",\n date: \"2026-02-01\",\n currency: \"EUR\",\n isCreditNote: true,\n invoiceReference: \"INV-2026-001\",\n from: {\n name: \"Dupont & Fils SPRL\",\n peppolId: \"0208:0685660237\",\n street: \"Avenue Louise 54\",\n city: \"Bruxelles\",\n postalCode: \"1050\",\n country: \"BE\",\n },\n // Sandbox test receiver (GPR-828) \\u2014 keep in sync with templates/invoice.ts.\n to: {\n name: \"SPF Economie (test receiver)\",\n peppolId: \"9925:BE0314595348\",\n street: \"Rue du Progr\\u00e8s 50\",\n city: \"Brussels\",\n postalCode: \"1210\",\n country: \"BE\",\n },\n lines: [\n {\n description: \"Avoir partiel \\u2014 Conseil en transformation num\\u00e9rique\",\n quantity: 2,\n unitPrice: 950,\n vatRate: 21,\n },\n ],\n note: \"Avoir pour prestations non r\\u00e9alis\\u00e9es \\u2014 r\\u00e9f. INV-2026-001\",\n};\n","import { writeFileSync } from \"node:fs\";\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { readAndValidateInvoiceJson } from \"../utils/file.js\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport { runValidation } from \"./validate.js\";\nimport { formatValidationResult } from \"../formatters/validation.js\";\nimport {\n buildInvoiceXml,\n buildCreditNoteXml,\n type InvoiceInput,\n type CreditNoteInput,\n} from \"@getpeppr/sdk\";\n\nexport function registerConvertCommand(program: Command): void {\n program\n .command(\"convert\")\n .description(\n \"Convert a getpeppr JSON invoice to Peppol BIS 3.0 UBL XML\",\n )\n .argument(\"<file>\", \"path to invoice JSON file\")\n .option(\"-o, --output <file>\", \"write XML to file instead of stdout\")\n .option(\"--validate\", \"validate the invoice before converting\")\n .action(\n async (\n file: string,\n options: { output?: string; validate?: boolean },\n ) => {\n // 1. Read and parse the JSON file\n const input = readAndValidateInvoiceJson(file);\n\n // 2. If --validate, run validation first\n if (options.validate) {\n const result = runValidation(input);\n const formatted = formatValidationResult(file, result);\n\n if (!result.valid) {\n // Errors: show on stderr, exit 1, NO XML\n process.stderr.write(formatted + \"\\n\");\n process.exit(1);\n }\n\n if (result.totalWarnings > 0) {\n // Warnings only: show on stderr, continue to conversion\n process.stderr.write(formatted + \"\\n\");\n }\n }\n\n // 3. Detect document type\n const isCreditNote = input.isCreditNote === true;\n\n // 4. Generate XML\n let xml: string;\n try {\n if (isCreditNote) {\n xml = buildCreditNoteXml(input as CreditNoteInput);\n } else {\n xml = buildInvoiceXml(input);\n }\n } catch (err: unknown) {\n const message =\n err instanceof Error ? err.message : \"Unknown error\";\n exitWithError(`Error: XML generation failed — ${message}`);\n }\n\n // 5. Clean empty lines from XML\n xml = xml.replace(/^[ \\t]*\\n/gm, \"\");\n\n // 6. Output\n const docType = isCreditNote\n ? \"UBL 2.1 CreditNote\"\n : \"UBL 2.1 Invoice\";\n\n if (options.output) {\n writeFileSync(options.output, xml, \"utf-8\");\n process.stderr.write(\n `${pc.green(\"✓\")} Converted to ${options.output} (${docType})\\n`,\n );\n } else {\n process.stdout.write(xml + \"\\n\");\n }\n },\n );\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport {\n lookupParticipant,\n searchParticipants,\n DirectoryError,\n type DirectoryMatch,\n type SearchResult,\n} from \"../lib/peppol-directory.js\";\n\n// ─── Country name helper ──────────────────────────\n\nconst COUNTRY_NAMES: Record<string, string> = {\n AT: \"Austria\",\n BE: \"Belgium\",\n BG: \"Bulgaria\",\n HR: \"Croatia\",\n CY: \"Cyprus\",\n CZ: \"Czechia\",\n DK: \"Denmark\",\n EE: \"Estonia\",\n FI: \"Finland\",\n FR: \"France\",\n DE: \"Germany\",\n GR: \"Greece\",\n HU: \"Hungary\",\n IS: \"Iceland\",\n IE: \"Ireland\",\n IT: \"Italy\",\n LV: \"Latvia\",\n LT: \"Lithuania\",\n LU: \"Luxembourg\",\n MT: \"Malta\",\n NL: \"Netherlands\",\n NO: \"Norway\",\n PL: \"Poland\",\n PT: \"Portugal\",\n RO: \"Romania\",\n SK: \"Slovakia\",\n SI: \"Slovenia\",\n ES: \"Spain\",\n SE: \"Sweden\",\n CH: \"Switzerland\",\n GB: \"United Kingdom\",\n US: \"United States\",\n AU: \"Australia\",\n CA: \"Canada\",\n SG: \"Singapore\",\n JP: \"Japan\",\n NZ: \"New Zealand\",\n};\n\nexport function countryLabel(code: string): string {\n const name = COUNTRY_NAMES[code.toUpperCase()];\n return name ? `${name} (${code})` : code;\n}\n\n// ─── Output formatting ───────────────────────────\n\nfunction formatLookupResult(match: DirectoryMatch): string {\n const lines: string[] = [];\n lines.push(`${pc.green(\"\\u2713\")} ${match.name}`);\n lines.push(` ${pc.dim(\"Peppol ID\")} ${match.peppolId}`);\n lines.push(` ${pc.dim(\"Country\")} ${countryLabel(match.country)}`);\n if (match.registrationDate) {\n lines.push(` ${pc.dim(\"Registered\")} ${match.registrationDate}`);\n }\n if (match.vatNumber) {\n lines.push(` ${pc.dim(\"VAT\")} ${match.vatNumber}`);\n }\n if (match.capabilities.length > 0) {\n lines.push(\n ` ${pc.dim(\"Capabilities\")} ${match.capabilities.join(\", \")}`,\n );\n }\n if (match.contactEmail) {\n lines.push(` ${pc.dim(\"Contact\")} ${match.contactEmail}`);\n }\n if (match.website) {\n lines.push(` ${pc.dim(\"Website\")} ${match.website}`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction formatSearchResults(result: SearchResult): string {\n const lines: string[] = [];\n const plural = result.totalCount === 1 ? \"participant\" : \"participants\";\n lines.push(`Found ${result.totalCount} ${plural}:\\n`);\n\n // Column headers\n const nameW = 26;\n const idW = 23;\n const countryW = 9;\n\n lines.push(\n ` ${\"Name\".padEnd(nameW)}${\"Peppol ID\".padEnd(idW)}${\"Country\".padEnd(countryW)}Capabilities`,\n );\n lines.push(` ${\"─\".repeat(nameW + idW + countryW + 20)}`);\n\n for (const m of result.matches) {\n const name = m.name.length > nameW - 1 ? m.name.slice(0, nameW - 2) + \"…\" : m.name;\n const caps = m.capabilities.join(\", \");\n lines.push(\n ` ${name.padEnd(nameW)}${m.peppolId.padEnd(idW)}${m.country.padEnd(countryW)}${caps}`,\n );\n }\n\n if (result.hasMore) {\n lines.push(\n `\\n ${pc.dim(`Showing ${result.matches.length} of ${result.totalCount} results.`)}`,\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n// ─── Input validation ─────────────────────────────\n\nfunction validatePeppolId(raw: string): {\n ok: true;\n scheme: string;\n id: string;\n} | { ok: false; error: string } {\n const colonIndex = raw.indexOf(\":\");\n if (colonIndex === -1) {\n return {\n ok: false,\n error: `Invalid Peppol ID format: \"${raw}\". Expected format: scheme:id (e.g. 0208:0685660237)`,\n };\n }\n\n const scheme = raw.slice(0, colonIndex);\n const id = raw.slice(colonIndex + 1);\n\n if (!/^\\d{4}$/.test(scheme)) {\n return {\n ok: false,\n error: `Invalid scheme \"${scheme}\". Must be exactly 4 digits (e.g. 0208).`,\n };\n }\n\n if (!/^[A-Za-z0-9:.\\-]+$/.test(id)) {\n return {\n ok: false,\n error: `Invalid participant ID \"${id}\". Only letters, digits, colons, dots and hyphens are allowed.`,\n };\n }\n\n return { ok: true, scheme, id };\n}\n\n// ─── Command registration ─────────────────────────\n\nexport function registerLookupCommand(program: Command): void {\n program\n .command(\"lookup\")\n .description(\"Look up a participant in the Peppol Directory\")\n .argument(\"[peppolId]\", \"Peppol participant ID (format: scheme:id)\")\n .option(\"--name <name>\", \"search by company name (min 3 chars)\")\n .option(\"--country <code>\", \"filter by ISO 2-letter country code\")\n .option(\"--json\", \"output results as JSON\")\n .option(\"--limit <n>\", \"max results (default 10)\", \"10\")\n .action(\n async (\n peppolId: string | undefined,\n options: {\n name?: string;\n country?: string;\n json?: boolean;\n limit?: string;\n },\n ) => {\n const isSearch = Boolean(options.name);\n const isLookup = Boolean(peppolId);\n\n // Must have at least one criterion\n if (!isSearch && !isLookup) {\n exitWithError(\"Provide a Peppol ID or use --name to search.\");\n }\n\n // Validate --country format\n if (options.country) {\n const normalized = options.country.toUpperCase();\n if (!/^[A-Z]{2}$/.test(normalized)) {\n exitWithError(\n `Invalid country code \"${options.country}\". Must be 2 letters (e.g. BE, DE, FR).`,\n );\n }\n options.country = normalized;\n }\n\n if (isLookup) {\n await handleLookup(peppolId!, options);\n } else {\n await handleSearch(options);\n }\n },\n );\n}\n\n// ─── Lookup handler ───────────────────────────────\n\nasync function handleLookup(\n peppolId: string,\n options: { json?: boolean },\n): Promise<void> {\n const parsed = validatePeppolId(peppolId);\n if (!parsed.ok) {\n exitWithError(parsed.error);\n }\n\n let result: DirectoryMatch | null;\n\n try {\n result = await lookupParticipant(parsed.scheme, parsed.id);\n } catch (err) {\n if (err instanceof DirectoryError) {\n exitWithError(\n `${pc.red(\"\\u2717\")} Peppol Directory returned an error (HTTP ${err.status ?? \"unknown\"}). Try again later.`,\n );\n }\n exitWithError(\n `${pc.red(\"\\u2717\")} Could not reach Peppol Directory. Check your internet connection.`,\n );\n }\n\n if (!result) {\n if (options.json) {\n console.log(JSON.stringify(null));\n } else {\n process.stderr.write(\n `${pc.red(\"\\u2717\")} Participant not found: ${peppolId}\\n`,\n );\n }\n process.exit(1);\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(formatLookupResult(result));\n }\n process.exit(0);\n}\n\n// ─── Search handler ───────────────────────────────\n\nasync function handleSearch(options: {\n name?: string;\n country?: string;\n json?: boolean;\n limit?: string;\n}): Promise<void> {\n if (options.name && options.name.length < 3) {\n exitWithError(\n `Search name must be at least 3 characters. Got: \"${options.name}\"`,\n );\n }\n\n const limit = parseInt(options.limit ?? \"10\", 10);\n\n let result: SearchResult;\n\n try {\n result = await searchParticipants({\n name: options.name,\n country: options.country,\n limit,\n });\n } catch (err) {\n if (err instanceof DirectoryError) {\n exitWithError(\n `${pc.red(\"\\u2717\")} Peppol Directory returned an error (HTTP ${err.status ?? \"unknown\"}). Try again later.`,\n );\n }\n exitWithError(\n `${pc.red(\"\\u2717\")} Could not reach Peppol Directory. Check your internet connection.`,\n );\n }\n\n if (result.matches.length === 0) {\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n process.stderr.write(\"No participants found.\\n\");\n }\n process.exit(1);\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(formatSearchResults(result));\n }\n process.exit(0);\n}\n","const BASE_URL = \"https://directory.peppol.eu/search/1.0/json\";\n\n// ─── Errors ───────────────────────────────────────\n\nexport class DirectoryError extends Error {\n readonly status?: number;\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"DirectoryError\";\n this.status = status;\n }\n}\n\n// ─── Public types ─────────────────────────────────\n\nexport interface DirectoryMatch {\n name: string;\n peppolId: string;\n country: string;\n capabilities: string[];\n registrationDate?: string;\n vatNumber?: string;\n contactEmail?: string;\n website?: string;\n}\n\nexport interface SearchResult {\n matches: DirectoryMatch[];\n totalCount: number;\n hasMore: boolean;\n}\n\n// ─── Response types (Peppol Directory JSON) ───────\n\ninterface DirectoryParticipantID {\n scheme: string;\n value: string;\n}\n\ninterface DirectoryDocType {\n scheme: string;\n value: string;\n}\n\ninterface DirectoryEntity {\n name: Array<{ name: string; language?: string }>;\n countryCode: string;\n geoInfo?: string;\n identifiers?: Array<{ scheme: string; value: string }>;\n websites?: string[];\n contacts?: Array<{ type: string; name?: string; email?: string }>;\n additionalInfo?: string;\n regDate?: string;\n}\n\ninterface DirectoryMatchRaw {\n participantID: DirectoryParticipantID;\n docTypes?: DirectoryDocType[];\n entities: DirectoryEntity[];\n}\n\ninterface DirectoryResponse {\n \"total-result-count\": number;\n \"result-page-index\": number;\n \"result-page-count\": number;\n matches: DirectoryMatchRaw[];\n}\n\n// ─── Parsing helpers ──────────────────────────────\n\nexport function stripQuotes(name: string): string {\n if (name.startsWith('\"') && name.endsWith('\"') && name.length >= 2) {\n return name.slice(1, -1);\n }\n return name;\n}\n\nexport function pickBestName(\n names: Array<{ name: string; language?: string }>,\n): string {\n if (names.length === 0) return \"\";\n const english = names.find((n) => n.language === \"en\");\n return (english ?? names[0]).name;\n}\n\nexport function mapDocType(urn: string): string | null {\n if (urn.includes(\"Invoice-2::Invoice##\")) return \"invoice\";\n if (urn.includes(\"CreditNote-2::CreditNote##\")) return \"credit_note\";\n if (urn.includes(\"ApplicationResponse\")) return \"application_response\";\n if (urn.includes(\"Order-2::Order##\")) return \"order\";\n if (urn.includes(\"DespatchAdvice\")) return \"despatch_advice\";\n return null;\n}\n\nexport function findVatIdentifier(\n identifiers: Array<{ scheme: string; value: string }>,\n): string | undefined {\n const match = identifiers.find((id) => {\n const s = id.scheme.toLowerCase();\n return s.includes(\"vat\") || s.includes(\"cbe\") || s.includes(\"tax\");\n });\n return match?.value;\n}\n\nexport function parseParticipantId(value: string): {\n scheme: string;\n id: string;\n} {\n const colonIndex = value.indexOf(\":\");\n if (colonIndex === -1) {\n return { scheme: \"\", id: value };\n }\n return {\n scheme: value.slice(0, colonIndex),\n id: value.slice(colonIndex + 1),\n };\n}\n\n// ─── Internal: parse a raw match ──────────────────\n\nfunction parseMatch(raw: DirectoryMatchRaw): DirectoryMatch {\n const entity = raw.entities[0];\n const rawName = entity ? pickBestName(entity.name) : \"\";\n const name = stripQuotes(rawName);\n const country = entity?.countryCode ?? \"\";\n\n const capabilities = (raw.docTypes ?? [])\n .map((dt) => mapDocType(dt.value))\n .filter((c): c is string => c !== null)\n // Deduplicate\n .filter((c, i, arr) => arr.indexOf(c) === i);\n\n const vatNumber = entity?.identifiers\n ? findVatIdentifier(entity.identifiers)\n : undefined;\n\n const contactEmail = entity?.contacts?.find((c) => c.email)?.email;\n const website =\n entity?.websites && entity.websites.length > 0\n ? entity.websites[0]\n : undefined;\n\n return {\n name,\n peppolId: raw.participantID.value,\n country,\n capabilities,\n registrationDate: entity?.regDate,\n vatNumber,\n contactEmail,\n website,\n };\n}\n\n// ─── Public API ───────────────────────────────────\n\nexport async function lookupParticipant(\n scheme: string,\n id: string,\n): Promise<DirectoryMatch | null> {\n const participantParam = `iso6523-actorid-upis::${scheme}:${normalizeParticipantIdentifier(scheme, id)}`;\n const url = `${BASE_URL}?participant=${encodeURIComponent(participantParam)}`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(15_000),\n headers: { \"User-Agent\": \"@getpeppr/cli\" },\n });\n if (!response.ok) {\n throw new DirectoryError(\n `Lookup failed: HTTP ${response.status} ${response.statusText}`,\n response.status,\n );\n }\n const data = (await response.json()) as DirectoryResponse;\n\n if (!data.matches || data.matches.length === 0) {\n return null;\n }\n\n return parseMatch(data.matches[0]);\n}\n\nfunction normalizeParticipantIdentifier(scheme: string, id: string): string {\n if (scheme === \"0208\") {\n return id.replace(/^BE(?=(?:0|1)\\d{9}$)/i, \"\");\n }\n\n return id;\n}\n\nexport async function searchParticipants(opts: {\n name?: string;\n country?: string;\n limit?: number;\n}): Promise<SearchResult> {\n const params = new URLSearchParams();\n if (opts.name) params.set(\"name\", opts.name);\n if (opts.country) params.set(\"country\", opts.country);\n\n const url = `${BASE_URL}?${params.toString()}`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(15_000),\n headers: { \"User-Agent\": \"@getpeppr/cli\" },\n });\n if (!response.ok) {\n throw new DirectoryError(\n `Search failed: HTTP ${response.status} ${response.statusText}`,\n response.status,\n );\n }\n const data = (await response.json()) as DirectoryResponse;\n\n const allMatches = (data.matches ?? []).map(parseMatch);\n\n const limit = opts.limit ?? 10;\n const matches = allMatches.slice(0, limit);\n\n const totalCount = data[\"total-result-count\"] ?? 0;\n const hasMore = totalCount > matches.length;\n\n return {\n matches,\n totalCount,\n hasMore,\n };\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { Peppol } from \"@getpeppr/sdk\";\n\nimport { exitWithError } from \"../utils/errors.js\";\nimport { resolveApiKey, AuthError } from \"../lib/auth.js\";\nimport { buildPayload, MutexError } from \"../lib/send-payload.js\";\nimport { confirmInteractive } from \"../lib/confirm.js\";\nimport { pollUntilTerminal } from \"../lib/watch.js\";\nimport { formatSendResult } from \"../formatters/send-result.js\";\nimport { runValidation } from \"./validate.js\";\n\ninterface SendFlags {\n prod?: boolean;\n local?: boolean;\n key?: string;\n to?: string;\n country?: string;\n amount?: string;\n currency?: string;\n desc?: string;\n attachment?: boolean;\n watch?: boolean;\n yes?: boolean;\n validate?: boolean; // commander negates --no-validate to validate=false\n json?: boolean;\n quiet?: boolean;\n}\n\nconst API_BASE = \"https://api.getpeppr.dev/v1\";\nconst LOCAL_BASE = \"http://localhost:3001/api/v1\";\nconst DASHBOARD_BASE = \"https://console.getpeppr.dev/invoices\";\n\nexport function registerSendCommand(program: Command): void {\n program\n .command(\"send\")\n .description(\"Send an invoice to the Peppol network via getpeppr API\")\n .argument(\"[file]\", \"optional path to invoice JSON (mutex with --to/--amount/...)\")\n .option(\"--prod\", \"target production (live keys + confirmation)\")\n .option(\"--local\", \"target localhost:3001 dev server\")\n .option(\"--key <key>\", \"override API key — for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.\")\n .option(\"--to <peppol-id>\", \"recipient peppol id (e.g., 9925:BE0314595348)\")\n .option(\"--country <iso>\", \"recipient ISO 3166-1 alpha-2 country override (e.g., BE)\")\n .option(\"--amount <number>\", \"line amount in major currency units (decimal allowed)\")\n .option(\"--currency <iso>\", \"ISO 4217 currency (default EUR)\")\n .option(\"--desc <text>\", \"line description\")\n .option(\"--attachment\", \"attach the test PDF\")\n .option(\"--watch\", \"poll status until a terminal state (60s timeout)\")\n .option(\"-y, --yes\", \"skip --prod confirmation prompt\")\n .option(\"--no-validate\", \"skip pre-validation locally\")\n .option(\"--json\", \"output JSON\")\n .option(\"--quiet\", \"exit code only, no output\")\n .action(async (file: string | undefined, flags: SendFlags) => {\n // 1. Resolve auth\n let auth;\n try {\n auth = resolveApiKey({\n flagKey: flags.key,\n forceProd: Boolean(flags.prod),\n forceLocal: Boolean(flags.local),\n });\n } catch (e) {\n if (e instanceof AuthError) {\n exitWithError(e.message);\n return;\n }\n throw e;\n }\n\n // 2. Build payload\n const overrides = {\n to: flags.to,\n country: flags.country,\n amount: flags.amount != null ? Number(flags.amount) : undefined,\n currency: flags.currency,\n description: flags.desc,\n attachment: flags.attachment,\n };\n let payload;\n try {\n payload = buildPayload({ file, overrides });\n } catch (e) {\n if (e instanceof MutexError) {\n exitWithError(e.message);\n return;\n }\n if (e instanceof Error) {\n exitWithError(e.message);\n return;\n }\n throw e;\n }\n\n // 3. Pre-validate (unless --no-validate)\n if (flags.validate !== false) {\n const result = runValidation(payload);\n if (!result.valid) {\n process.stderr.write(\n `${pc.red(\"✗\")} Pre-validation failed (${result.totalErrors} errors). Use --no-validate to skip.\\n`,\n );\n process.exit(2);\n }\n }\n\n // 4. --prod confirmation\n if (flags.prod && !flags.yes) {\n const confirmed = await confirmInteractive({\n prompt: pc.yellow(\"⚠ About to send a REAL invoice on the Peppol network. Continue?\"),\n defaultYes: false,\n });\n if (!confirmed) {\n if (!flags.quiet) process.stderr.write(\"Cancelled.\\n\");\n process.exit(0);\n }\n }\n\n // 5. Build SDK client\n const baseUrl = flags.local ? LOCAL_BASE : API_BASE;\n const client = new Peppol({ apiKey: auth.apiKey, baseUrl });\n\n // 6. Send\n let result;\n try {\n result = await client.invoices.send(payload);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.red(\"✗\")} ${msg}\\n`);\n process.exit(1);\n }\n\n const dashboardUrl = `${DASHBOARD_BASE}/${result.id}`;\n\n // 7. --watch\n let finalStatus: string = result.status;\n let timedOut = false;\n // GPR-1061 — a watch that could not run is not a delivery confirmation.\n // The error used to be printed and forgotten: `finalStatus` stayed at the\n // send-time \"submitted\" and the process exited 0, so an automation gating\n // on the exit code read a broken API as a successful delivery.\n let watchFailed = false;\n if (flags.watch) {\n const onTransition = (s: string) => {\n if (!flags.quiet && !flags.json) {\n process.stderr.write(` ${pc.cyan(\"→\")} ${s}\\n`);\n }\n };\n try {\n const w = await pollUntilTerminal(client, result.id, {\n intervalMs: 2000,\n timeoutMs: 60_000,\n onTransition,\n });\n finalStatus = w.finalStatus;\n timedOut = w.timedOut;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.yellow(\"⚠\")} Watch error: ${msg}\\n`);\n watchFailed = true;\n }\n if (timedOut) {\n process.stderr.write(\n `${pc.yellow(\"⚠\")} Timeout — invoice was sent but delivery not confirmed in 60s.\\n`,\n );\n }\n }\n\n // 8. Output\n const mode = flags.quiet ? \"quiet\" : flags.json ? \"json\" : \"formatted\";\n const output = formatSendResult(\n {\n id: result.id,\n number: payload.number,\n status: finalStatus,\n warnings: result.warnings,\n dashboardUrl,\n },\n mode,\n );\n if (output) process.stdout.write(output + \"\\n\");\n\n // 9. Exit code — no_action = not deliverable, a terminal failure (GPR-830)\n //\n // `watchFailed` is deliberately distinct from `timedOut` (GPR-1061). A\n // timeout means the send worked and delivery is simply unconfirmed within\n // the window — still exit 0, as before. A watch ERROR means the API\n // answered something the SDK refused to interpret, so the status printed\n // above is the send-time one and nothing about delivery is known.\n if (\n watchFailed ||\n finalStatus === \"rejected\" ||\n finalStatus === \"failed\" ||\n finalStatus === \"no_action\"\n ) {\n process.exit(1);\n }\n process.exit(0);\n });\n}\n","import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n renameSync,\n} from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport interface Credentials {\n sandbox?: string;\n live?: string;\n}\n\nexport function getCredentialsPath(): string {\n if (platform() === \"win32\") {\n const appdata = process.env.APPDATA ?? join(homedir(), \"AppData\", \"Roaming\");\n return join(appdata, \"getpeppr\", \"credentials.json\");\n }\n // XDG-compliant default; respects $XDG_CONFIG_HOME\n const xdg = process.env.XDG_CONFIG_HOME ?? join(homedir(), \".config\");\n return join(xdg, \"getpeppr\", \"credentials.json\");\n}\n\nexport function readCredentials(): Credentials | null {\n const path = getCredentialsPath();\n if (!existsSync(path)) return null;\n\n // Permission check (POSIX only)\n if (platform() !== \"win32\") {\n const stats = statSync(path);\n const mode = stats.mode & 0o777;\n if (mode !== 0o600) {\n process.stderr.write(\n `⚠ Config file mode was ${mode.toString(8)}; restoring to 600.\\n`,\n );\n chmodSync(path, 0o600);\n }\n }\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf-8\");\n } catch {\n process.stderr.write(`⚠ Could not read config file: ${path}\\n`);\n return null;\n }\n\n try {\n const data = JSON.parse(raw) as Credentials;\n return data;\n } catch {\n process.stderr.write(`⚠ Malformed JSON in config file: ${path}\\n`);\n return null;\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const path = getCredentialsPath();\n const dir = dirname(path);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n\n // Atomic write: tmp file + rename, with mode 600 (POSIX only)\n const tmpPath = `${path}.tmp`;\n const data = JSON.stringify(creds, null, 2) + \"\\n\";\n\n // Defensive: clean up any orphan tmp from a previous crashed run.\n try { rmSync(tmpPath, { force: true }); } catch { /* best effort */ }\n\n // flag: \"wx\" fails if tmp exists (eliminates mode retention) + explicit chmod as belt-and-suspenders.\n writeFileSync(tmpPath, data, { mode: 0o600, flag: \"wx\" });\n chmodSync(tmpPath, 0o600);\n\n try {\n renameSync(tmpPath, path);\n } catch (e) {\n try { rmSync(tmpPath, { force: true }); } catch { /* best effort */ }\n throw e;\n }\n}\n\nexport function deleteCredentials(): boolean {\n const path = getCredentialsPath();\n if (!existsSync(path)) return false;\n rmSync(path);\n return true;\n}\n","import { readCredentials } from \"./credentials-store.js\";\n\nexport type Environment = \"sandbox\" | \"live\";\nexport type AuthSource = \"flag\" | \"env\" | \"config\";\n\nexport interface ResolvedAuth {\n apiKey: string;\n source: AuthSource;\n environment: Environment;\n}\n\nexport interface ResolveOptions {\n flagKey?: string;\n forceProd: boolean;\n forceLocal: boolean; // reserved for Task 10 (--local flag); resolveApiKey itself does not use it\n}\n\nexport class AuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nexport function resolveApiKey(opts: ResolveOptions): ResolvedAuth {\n const env: Environment = opts.forceProd ? \"live\" : \"sandbox\";\n\n // 1. Flag has highest priority\n if (opts.flagKey) {\n return { apiKey: opts.flagKey, source: \"flag\", environment: env };\n }\n\n // 2. Env var\n const envKey = process.env.GETPEPPR_API_KEY;\n if (envKey) {\n return { apiKey: envKey, source: \"env\", environment: env };\n }\n\n // 3. Config file\n const creds = readCredentials();\n if (creds) {\n const key = env === \"live\" ? creds.live : creds.sandbox;\n if (key) {\n return { apiKey: key, source: \"config\", environment: env };\n }\n if (env === \"live\") {\n throw new AuthError(\n `Config has no live API key. Run \\`getpeppr login\\` again with --live, or pass --key.`,\n );\n }\n }\n\n // 4. Nothing found\n throw new AuthError(\n `No API key found. Run \\`getpeppr login\\` or set GETPEPPR_API_KEY.`,\n );\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { InvoiceInput } from \"@getpeppr/sdk\";\nimport { buildDefaultSendPayload, type SendDefaultOverrides } from \"../templates/send-default.js\";\n\nexport class MutexError extends Error {\n constructor() {\n super(\"Cannot combine custom file with override flags. Use one or the other.\");\n this.name = \"MutexError\";\n }\n}\n\nexport interface BuildPayloadOptions {\n file?: string;\n overrides?: SendDefaultOverrides;\n}\n\nfunction hasOverrides(o?: SendDefaultOverrides): boolean {\n if (!o) return false;\n // Use `!= null` for amount (handles 0) and explicit string-emptiness check for `to`.\n // `attachment: false` is the default behaviour, so we treat it as \"no override expressed\".\n // `attachment: true` is the only way to opt into the attachment override.\n return Boolean(\n (o.to != null && o.to !== \"\") ||\n (o.country != null && o.country !== \"\") ||\n o.amount != null ||\n o.currency ||\n o.description ||\n o.attachment === true,\n );\n}\n\nexport function buildPayload(opts: BuildPayloadOptions): InvoiceInput {\n if (opts.file && hasOverrides(opts.overrides)) {\n throw new MutexError();\n }\n\n if (opts.file) {\n const absPath = resolve(opts.file);\n if (!existsSync(absPath)) {\n throw new Error(`Error: file not found — ${absPath}`);\n }\n let raw: string;\n try {\n raw = readFileSync(absPath, \"utf-8\");\n } catch {\n throw new Error(`Error: could not read file — ${absPath}`);\n }\n try {\n return JSON.parse(raw) as InvoiceInput;\n } catch {\n throw new Error(`Error: invalid JSON in file — ${absPath}`);\n }\n }\n\n return buildDefaultSendPayload(opts.overrides);\n}\n","import type { InvoiceInput, PeppolId, CountryCode } from \"@getpeppr/sdk\";\n\n// Minimal valid PDF (Storecove validates content). Canonical source is\n// packages/sdk/scripts/send-test-invoice.ts — if that script's PDF is ever\n// updated, this duplicate must be kept in sync. The scripts/ directory is\n// excluded from SDK tsconfig so cross-package import isn't possible.\nconst MINIMAL_PDF = `%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n0000000009 00000 n\n0000000058 00000 n\n0000000115 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxref\n190\n%%EOF`;\n\nexport const MINIMAL_TEST_PDF_BASE64 = Buffer.from(MINIMAL_PDF).toString(\"base64\");\n\nexport interface SendDefaultOverrides {\n to?: string;\n country?: string;\n amount?: number;\n currency?: string;\n description?: string;\n attachment?: boolean;\n}\n\nconst SCHEME_COUNTRY_DEFAULTS: Record<string, CountryCode> = {\n \"0009\": \"FR\" as CountryCode,\n \"0204\": \"DE\" as CountryCode,\n \"0208\": \"BE\" as CountryCode,\n \"9925\": \"BE\" as CountryCode,\n};\n\nfunction deriveCountryFromPeppolId(peppolId: PeppolId): CountryCode {\n const [scheme, identifier = \"\"] = peppolId.split(\":\");\n const alphaPrefix = identifier.slice(0, 2);\n\n if (/^[A-Za-z]{2}$/.test(alphaPrefix)) {\n return alphaPrefix.toUpperCase() as CountryCode;\n }\n\n return SCHEME_COUNTRY_DEFAULTS[scheme] ?? (\"BE\" as CountryCode);\n}\n\nexport function buildDefaultSendPayload(overrides: SendDefaultOverrides = {}): InvoiceInput {\n const today = new Date();\n const due = new Date(today.getTime() + 30 * 86400000);\n const isoToday = today.toISOString().slice(0, 10);\n const isoDue = due.toISOString().slice(0, 10);\n\n // TODO(Task 10 send command): validate scheme:id format upstream before calling.\n // Cast is safe assuming caller passes valid Peppol ID format (XXXX:YYYYYY).\n const peppolId = (overrides.to ?? \"9925:BE0314595348\") as PeppolId; // SPF Economie BE — accepts test invoices\n const amount = overrides.amount ?? 100;\n const currency = overrides.currency ?? \"EUR\";\n const description = overrides.description ?? \"Test service from getpeppr\";\n\n // Unique invoice number: TEST-{base36 timestamp}-{4-char random hex}.\n // The random suffix guarantees uniqueness even when two calls land within the same millisecond.\n const randomSuffix = Math.floor(Math.random() * 0x10000)\n .toString(16)\n .toUpperCase()\n .padStart(4, \"0\");\n const number = `TEST-${Date.now().toString(36).toUpperCase()}-${randomSuffix}`;\n\n // Best-effort country derivation from Peppol ID. Some Belgian 0208 IDs are bare\n // enterprise numbers (e.g. 0208:0738836782), so fall back to the scheme mapping.\n // CountryCode is `\"BE\" | \"FR\" | ... | (string & {})` so any string is accepted.\n const country = overrides.country != null\n ? overrides.country.toUpperCase() as CountryCode\n : deriveCountryFromPeppolId(peppolId);\n\n const payload: InvoiceInput = {\n number,\n date: isoToday,\n dueDate: isoDue,\n currency,\n to: {\n name: peppolId === \"9925:BE0314595348\" ? \"SPF Economie (TEST)\" : \"Test Recipient\",\n peppolId,\n country,\n street: \"Rue de la Loi 1\",\n city: \"Brussels\",\n postalCode: \"1000\",\n },\n lines: [\n {\n description,\n quantity: 1,\n unitPrice: amount,\n vatRate: 0,\n // vatCategory \"O\" = \"Services outside scope of tax\" (UBL 2.1 / EN 16931).\n // Public entities (SPF Economie) are VAT-exempt. No `taxExemptReason` field\n // exists in InvoiceLine — Storecove derives exemption from the category code.\n // If sandbox returns 422 on this combination, fallback is vatRate: 21 + vatCategory: \"S\".\n vatCategory: \"O\",\n },\n ],\n };\n\n if (overrides.attachment) {\n payload.attachments = [\n {\n id: \"ATT-001\",\n description: \"Test document\",\n filename: \"test.pdf\",\n mimeType: \"application/pdf\",\n content: MINIMAL_TEST_PDF_BASE64,\n },\n ];\n }\n\n return payload;\n}\n","import type { Readable, Writable } from \"node:stream\";\nimport { createInterface } from \"node:readline\";\n\nexport interface ConfirmOptions {\n prompt: string;\n defaultYes: boolean;\n stdin?: Readable;\n stdout?: Writable;\n}\n\nexport async function confirmInteractive(opts: ConfirmOptions): Promise<boolean> {\n const stdin = (opts.stdin ?? process.stdin) as Readable & { isTTY?: boolean };\n const stdout = opts.stdout ?? process.stdout;\n\n // Non-TTY (CI, piped, vitest) → fall back to default.\n // Treat any non-true value (false, undefined) as non-TTY.\n if (stdin.isTTY !== true) {\n return opts.defaultYes;\n }\n\n const suffix = opts.defaultYes ? \"[Y/n]\" : \"[y/N]\";\n return new Promise<boolean>((resolve) => {\n const rl = createInterface({ input: stdin, output: stdout });\n let settled = false;\n\n rl.question(`${opts.prompt} ${suffix} `, (answer) => {\n settled = true;\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n if (trimmed === \"\") return resolve(opts.defaultYes);\n if (trimmed === \"y\" || trimmed === \"yes\") return resolve(true);\n if (trimmed === \"n\" || trimmed === \"no\") return resolve(false);\n // Unrecognized input → defaultYes (lenient)\n return resolve(opts.defaultYes);\n });\n\n // Guard: if stdin closes without newline (Ctrl+D, EOF), question callback\n // never fires. Resolve to defaultYes consistent with lenient-fallback policy.\n rl.once(\"close\", () => {\n if (!settled) resolve(opts.defaultYes);\n });\n });\n}\n","// `no_action` = not deliverable (no recipient on the Peppol network) — terminal\n// for wait semantics: no event ever follows it (GPR-830, spec §3.12).\nexport type TerminalStatus = \"delivered\" | \"accepted\" | \"rejected\" | \"failed\" | \"no_action\";\n\nconst TERMINAL_STATES = new Set<TerminalStatus>([\n \"delivered\",\n \"accepted\",\n \"rejected\",\n \"failed\",\n \"no_action\",\n]);\n\nexport interface WatchOptions {\n intervalMs?: number;\n timeoutMs?: number;\n onTransition?: (status: string) => void;\n}\n\nexport interface WatchResult {\n finalStatus: string;\n timedOut: boolean;\n}\n\ninterface StatusFetcher {\n invoices: { getStatus: (id: string) => Promise<{ status: string }> };\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nexport async function pollUntilTerminal(\n client: StatusFetcher,\n documentId: string,\n options: WatchOptions = {},\n): Promise<WatchResult> {\n const intervalMs = options.intervalMs ?? 2000;\n const timeoutMs = options.timeoutMs ?? 60_000;\n const start = Date.now();\n\n let lastStatus = \"\";\n\n while (Date.now() - start < timeoutMs) {\n const { status } = await client.invoices.getStatus(documentId);\n\n if (status !== lastStatus) {\n options.onTransition?.(status);\n lastStatus = status;\n }\n\n if (TERMINAL_STATES.has(status as TerminalStatus)) {\n return { finalStatus: status, timedOut: false };\n }\n\n await sleep(intervalMs);\n }\n\n return { finalStatus: lastStatus, timedOut: true };\n}\n","import pc from \"picocolors\";\n\nexport interface SendResultPayload {\n id: string;\n number: string;\n status: string;\n warnings?: { message: string }[];\n dashboardUrl: string;\n}\n\nexport type OutputMode = \"formatted\" | \"json\" | \"quiet\";\n\nexport function formatSendResult(result: SendResultPayload, mode: OutputMode): string {\n if (mode === \"quiet\") return \"\";\n\n if (mode === \"json\") {\n return JSON.stringify(result, null, 2);\n }\n\n // formatted\n const lines: string[] = [];\n lines.push(`${pc.green(\"✓\")} Sent ${pc.bold(result.number)}`);\n lines.push(` id: ${result.id}`);\n lines.push(` Status: ${pc.cyan(result.status)}`);\n lines.push(` Track: ${pc.dim(result.dashboardUrl)}`);\n\n const wCount = result.warnings?.length ?? 0;\n if (wCount > 0) {\n lines.push(` ${pc.yellow(`${wCount} warning${wCount === 1 ? \"\" : \"s\"}`)}`);\n for (const w of result.warnings ?? []) {\n lines.push(` ${pc.yellow(\"⚠\")} ${w.message}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n","import { createInterface } from \"node:readline\";\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { exitWithError } from \"../utils/errors.js\";\nimport {\n getCredentialsPath,\n readCredentials,\n writeCredentials,\n} from \"../lib/credentials-store.js\";\n\ninterface LoginFlags {\n key?: string;\n sandbox?: boolean;\n live?: boolean;\n}\n\nasync function promptMaskedKey(envLabel: string): Promise<string> {\n if (process.stdin.isTTY !== true) {\n exitWithError(\"Error: --key flag required when stdin is not a TTY (CI mode).\");\n }\n\n process.stdout.write(`Paste your ${envLabel} API key (input hidden): `);\n\n return new Promise<string>((resolve) => {\n let buffer = \"\";\n const onData = (chunk: Buffer) => {\n const c = chunk.toString(\"utf-8\");\n if (c === \"\\n\" || c === \"\\r\" || c === \"\\r\\n\") {\n process.stdin.setRawMode(false);\n process.stdin.removeListener(\"data\", onData);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n resolve(buffer);\n return;\n }\n if (c === \"\\x03\") {\n // Ctrl-C in raw mode: SIGINT is disabled, byte arrives as ETX (0x03)\n process.stdin.setRawMode(false);\n process.stdin.removeListener(\"data\", onData);\n process.stdin.pause();\n process.stdout.write(\"\\n\");\n process.exit(130);\n }\n if (c === \"\\x7f\" || c === \"\\b\") {\n // Backspace: POSIX terminals send DEL (0x7f), some send BS (0x08 / \"\\b\")\n buffer = buffer.slice(0, -1);\n return;\n }\n buffer += c;\n };\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on(\"data\", onData);\n });\n}\n\nasync function promptEnvironment(): Promise<\"sandbox\" | \"live\"> {\n if (process.stdin.isTTY !== true) return \"sandbox\";\n\n return new Promise<\"sandbox\" | \"live\">((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(\"Environment? (s)andbox / (l)ive [sandbox]: \", (answer) => {\n rl.close();\n const a = answer.trim().toLowerCase();\n if (a === \"l\" || a === \"live\") return resolve(\"live\");\n return resolve(\"sandbox\");\n });\n });\n}\n\nexport function registerLoginCommand(program: Command): void {\n program\n .command(\"login\")\n .description(\"Save a getpeppr API key to ~/.config/getpeppr/credentials.json\")\n .option(\"--key <key>\", \"API key — for CI/scripted use only; visible in `ps` and shell history. Prefer the interactive prompt or GETPEPPR_API_KEY env var.\")\n .option(\"--sandbox\", \"store as sandbox key (default)\")\n .option(\"--live\", \"store as live (production) key\")\n .action(async (flags: LoginFlags) => {\n if (!flags.live && !flags.sandbox && process.stdin.isTTY !== true) {\n exitWithError(\"Error: --sandbox or --live required when stdin is not a TTY (CI mode).\");\n }\n\n let env: \"sandbox\" | \"live\";\n if (flags.live) env = \"live\";\n else if (flags.sandbox) env = \"sandbox\";\n else env = await promptEnvironment();\n\n let key: string;\n if (flags.key) {\n key = flags.key;\n } else {\n key = (await promptMaskedKey(env)).trim();\n if (!key) exitWithError(\"Error: empty API key.\");\n }\n\n const existing = readCredentials() ?? {};\n const next = { ...existing, [env]: key };\n writeCredentials(next);\n\n const path = getCredentialsPath();\n process.stderr.write(\n `${pc.green(\"✓\")} Saved ${env} key to ${path} (mode 600)\\n`,\n );\n });\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { Peppol, type AccountIdentity } from \"@getpeppr/sdk\";\n\nimport { exitWithError } from \"../utils/errors.js\";\nimport { resolveApiKey, AuthError } from \"../lib/auth.js\";\nimport { countryLabel } from \"./lookup.js\";\n\ninterface WhoamiFlags {\n prod?: boolean;\n local?: boolean;\n key?: string;\n json?: boolean;\n}\n\nconst API_BASE = \"https://api.getpeppr.dev/v1\";\nconst LOCAL_BASE = \"http://localhost:3001/api/v1\";\nconst PEPPOL_IDENTITY_URL = \"https://console.getpeppr.dev/peppol-identity\";\n\n// ─── Terminal safety ─────────────────────────────\n\n/**\n * Strip every C0/C1 control character (plus DEL) from a server-provided\n * string before it reaches a human terminal. A hostile companyName such as\n * \"A\\x1b]52;c;…\\x07\" could otherwise forge display lines or trigger OSC 52\n * clipboard writes. Printable Unicode (accents, CJK…) passes through.\n *\n * The `--json` output is exempt ON PURPOSE: it is a machine contract, and\n * JSON.stringify already escapes control characters.\n */\nfunction sanitizeTerminal(s: string): string {\n // eslint-disable-next-line no-control-regex\n return s.replace(/[\\x00-\\x1f\\x7f-\\x9f]/g, \"\");\n}\n\n// ─── Output formatting ───────────────────────────\n\nfunction formatIdentity(identity: AccountIdentity): string {\n const lines: string[] = [];\n\n lines.push(\n ` ${pc.dim(\"Environment\")} ${sanitizeTerminal(identity.environment)}`,\n );\n\n const le = identity.legalEntity;\n if (!le) {\n lines.push(\"\");\n lines.push(\n `${pc.yellow(\"!\")} No Peppol identity in this environment yet.`,\n );\n lines.push(\n ` Create your legal entity in the console: ${PEPPOL_IDENTITY_URL}`,\n );\n return lines.join(\"\\n\");\n }\n\n lines.unshift(\n `${pc.green(\"✓\")} ${\n le.companyName != null\n ? sanitizeTerminal(le.companyName)\n : pc.dim(\"(no company name)\")\n }`,\n );\n if (le.country) {\n lines.push(\n ` ${pc.dim(\"Country\")} ${sanitizeTerminal(countryLabel(le.country))}`,\n );\n }\n if (le.address) {\n const parts = [le.address.line1, le.address.zip, le.address.city]\n .filter((p): p is string => Boolean(p))\n .map(sanitizeTerminal);\n if (parts.length > 0) {\n lines.push(` ${pc.dim(\"Address\")} ${parts.join(\", \")}`);\n }\n }\n if (le.createdAt) {\n lines.push(` ${pc.dim(\"Created\")} ${sanitizeTerminal(le.createdAt)}`);\n }\n\n lines.push(\"\");\n if (identity.identifiers.length === 0) {\n lines.push(\n `${pc.dim(\"No identifiers registered yet.\")} Register one in the console: ${PEPPOL_IDENTITY_URL}`,\n );\n return lines.join(\"\\n\");\n }\n\n const plural = identity.identifiers.length === 1 ? \"identifier\" : \"identifiers\";\n lines.push(`${identity.identifiers.length} Peppol ${plural}:`);\n\n // Status text stays verbatim — the vocabulary is open, never remap or\n // hide — apart from control-character stripping (terminal safety above).\n const rows = identity.identifiers.map((id) => ({\n peppolId: sanitizeTerminal(`${id.scheme}:${id.value}`),\n status: sanitizeTerminal(id.status),\n createdAt: id.createdAt ? sanitizeTerminal(id.createdAt) : null,\n }));\n\n const idW = Math.max(...rows.map((r) => r.peppolId.length)) + 3;\n const statusW = Math.max(...rows.map((r) => r.status.length)) + 3;\n\n for (const row of rows) {\n const line = ` ${row.peppolId.padEnd(idW)}${row.status.padEnd(statusW)}${\n row.createdAt ? pc.dim(row.createdAt) : \"\"\n }`;\n lines.push(line.trimEnd());\n }\n\n return lines.join(\"\\n\");\n}\n\n// ─── Command registration ─────────────────────────\n\nexport function registerWhoamiCommand(program: Command): void {\n program\n .command(\"whoami\")\n .description(\"Show the Peppol identity of the account behind your API key\")\n .option(\"--prod\", \"use the live API key (default: sandbox)\")\n .option(\"--local\", \"target localhost:3001 dev server\")\n .option(\n \"--key <key>\",\n \"override API key — for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.\",\n )\n .option(\"--json\", \"output the identity as JSON\")\n .action(async (flags: WhoamiFlags) => {\n // 1. Resolve auth — same flow as `send`\n let auth;\n try {\n auth = resolveApiKey({\n flagKey: flags.key,\n forceProd: Boolean(flags.prod),\n forceLocal: Boolean(flags.local),\n });\n } catch (e) {\n if (e instanceof AuthError) {\n exitWithError(e.message);\n return;\n }\n throw e;\n }\n\n // 2. Call the API\n const baseUrl = flags.local ? LOCAL_BASE : API_BASE;\n const client = new Peppol({ apiKey: auth.apiKey, baseUrl });\n\n let identity: AccountIdentity;\n try {\n identity = await client.identity.get();\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.red(\"✗\")} ${sanitizeTerminal(msg)}\\n`);\n process.exit(1);\n return;\n }\n\n // 3. Output\n if (flags.json) {\n // Machine contract: verbatim — JSON.stringify escapes control chars.\n console.log(JSON.stringify(identity, null, 2));\n } else {\n console.log(formatIdentity(identity));\n }\n // No process.exit(0) on success: let Node flush stdout and exit\n // naturally, otherwise a piped `whoami --json | jq` can lose output.\n process.exitCode = 0;\n });\n}\n","import type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { deleteCredentials, getCredentialsPath } from \"../lib/credentials-store.js\";\n\nexport function registerLogoutCommand(program: Command): void {\n program\n .command(\"logout\")\n .description(\"Remove ~/.config/getpeppr/credentials.json\")\n .action(() => {\n const path = getCredentialsPath();\n const removed = deleteCredentials();\n if (removed) {\n process.stderr.write(`${pc.green(\"✓\")} Removed ${path}\\n`);\n } else {\n process.stderr.write(`No credentials to remove (${path})\\n`);\n }\n process.exit(0);\n });\n}\n"],"mappings":"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","names":["warn","resolve","error","program","existsSync","resolve","pc","program","resolve","existsSync","pc","writeFileSync","pc","program","writeFileSync","pc","pc","pc","program","pc","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","resolve","resolve","existsSync","readFileSync","resolve","sleep","pc","program","result","pc","createInterface","pc","resolve","createInterface","program","pc","pc","API_BASE","LOCAL_BASE","pc","program","pc","program","pc","require"]}