@getpeppr/cli 0.11.1 → 0.12.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/canonical-schemes.ts","../../sdk/src/core/peppol-id.ts","../../sdk/src/core/iso6523-icd-codes.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/schematron.ts","../../sdk/src/core/status-precedence.ts","../../sdk/src/version.ts","../../sdk/src/core/api-result.ts","../../sdk/src/core/client.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/lib/dashboard-url.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(\"✓\")} No findings`);\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 \"Offline Checks (partial)\",\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(\"✓ Pre-flight checks passed\"))}`);\n } else if (valid) {\n lines.push(\n ` ${pc.green(pc.bold(\"✓ Pre-flight checks passed\"))} ${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(\"✗ Pre-flight checks found errors\"))} ${pc.dim(`(${parts.join(\", \")})`)}`,\n );\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n","/**\n * Les DEUX noms d'un scheme Peppol, et comment ramener l'un à l'autre — GPR-1109.\n *\n * La code list publie chaque scheme sous deux orthographes : le code EAS\n * numérique (`iso6523`, ex. `0204`) et la forme symbolique (`schemeid`, ex.\n * `DE:LWID`). Ce sont deux NOMS du MÊME scheme, pas deux schemes.\n *\n * ## ⛔ Pourquoi cette table existe\n *\n * Mesuré en production le 2026-08-20 : un compte dont l'identifiant est\n * enregistré sous la forme symbolique ne pouvait envoyer AUCUN document par\n * `POST /v1/invoices/import`.\n *\n * - document déclarant `0204` → conforme, puis `422 supplier_identity_not_owned`\n * - document déclarant `DE:LWID` → `422 validation_failed` (BR-CL-25 : le\n * schemeID doit appartenir à la CEF EAS code list, donc être numérique)\n *\n * Aucune troisième écriture n'existait, et **9 comptes sur 18** étaient dans ce\n * cas. Le défaut n'était dans aucune des deux règles — c'était le chaînon\n * manquant entre elles.\n *\n * ## ⛔ POURQUOI UNE CONSTANTE GRAVÉE ET PAS UN READ DU JSON\n *\n * Exactement la raison de `ROUTABLE_SCHEMES`, à côté : l'artefact versionné est\n * l'AUTORITÉ, mais il se lit avec `readFileSync(__dirname + …)`, ce qui est bon\n * dans un test et faux dans une route Next.js — le bundler ne trace pas une\n * lecture de fichier au runtime, donc le JSON n'existe pas dans la fonction\n * déployée. Même forme, même garde-fou : `__tests__/canonical-schemes-drift.test.ts`\n * RE-DÉRIVE cette table depuis le JSON et échoue dans les DEUX sens.\n * **Ne jamais éditer cette liste à la main — la régénérer.**\n *\n * ## ⭐ Pourquoi TOUTES les entrées, y compris les dépréciées\n *\n * Canonicaliser est une **traduction**, pas une **autorisation**. Un scheme\n * déprécié peut parfaitement être enregistré sur un compte ancien ; refuser de le\n * traduire le rendrait invisible à la garde de propriété alors que la ligne\n * existe en base — on transformerait un scheme retiré du catalogue en compte\n * bloqué. L'autorisation, elle, est le rôle de `isRoutableScheme`, qui filtre\n * bien sur active+registrable.\n *\n * ## Ce que cette table ne fait PAS\n *\n * Elle ne dit pas qu'un scheme est routable, ni qu'un identifiant est bien formé,\n * ni qu'il appartient à l'appelant. Traduction d'un NOM, rien d'autre.\n */\n\n/** Dérivée de participant-identifier-schemes-v9.7.json — entrées: 105 | actives: 84 | paires alias→code: 105 */\nconst ALIAS_TO_EAS: ReadonlyMap<string, string> = new Map([\n [\"AD:VAT\", \"9922\"],\n [\"AE:TIN\", \"0235\"],\n [\"AL:VAT\", \"9923\"],\n [\"AT:CID\", \"9916\"],\n [\"AT:GOV\", \"9915\"],\n [\"AT:KUR\", \"9919\"],\n [\"AT:VAT\", \"9914\"],\n [\"AU:ABN\", \"0151\"],\n [\"BA:VAT\", \"9924\"],\n [\"BE:CBE\", \"9956\"],\n [\"BE:EN\", \"0208\"],\n [\"BE:VAT\", \"9925\"],\n [\"BG:VAT\", \"9926\"],\n [\"CH:UIDB\", \"0183\"],\n [\"CH:VAT\", \"9927\"],\n [\"CY:VAT\", \"9928\"],\n [\"CZ:VAT\", \"9929\"],\n [\"DE:GEBA\", \"0246\"],\n [\"DE:LID\", \"9958\"],\n [\"DE:LWID\", \"0204\"],\n [\"DE:VAT\", \"9930\"],\n [\"DK:CPR\", \"9901\"],\n [\"DK:CVR\", \"9902\"],\n [\"DK:DIGST\", \"0184\"],\n [\"DK:ERST\", \"0198\"],\n [\"DK:P\", \"0096\"],\n [\"DK:SE\", \"9904\"],\n [\"DK:VANS\", \"9905\"],\n [\"DUNS\", \"0060\"],\n [\"EE:CC\", \"0191\"],\n [\"EE:VAT\", \"9931\"],\n [\"ES:VAT\", \"9920\"],\n [\"EU:NAL\", \"0130\"],\n [\"EU:REID\", \"9913\"],\n [\"EU:VAT\", \"9912\"],\n [\"FI:NSI\", \"0215\"],\n [\"FI:ORG\", \"0212\"],\n [\"FI:OVT\", \"0037\"],\n [\"FI:OVT2\", \"0216\"],\n [\"FI:VAT\", \"0213\"],\n [\"FR:CTC\", \"0225\"],\n [\"FR:SIRENE\", \"0002\"],\n [\"FR:SIRET\", \"0009\"],\n [\"FR:VAT\", \"9957\"],\n [\"GB:VAT\", \"9932\"],\n [\"GLN\", \"0088\"],\n [\"GR:VAT\", \"9933\"],\n [\"GS1\", \"0209\"],\n [\"HR:VAT\", \"9934\"],\n [\"HU:VAT\", \"9910\"],\n [\"IBAN\", \"9918\"],\n [\"IE:VAT\", \"9935\"],\n [\"IS:KT\", \"9917\"],\n [\"IS:KTNR\", \"0196\"],\n [\"IT:CF\", \"9907\"],\n [\"IT:CFI\", \"0210\"],\n [\"IT:COD\", \"0205\"],\n [\"IT:CUUO\", \"0201\"],\n [\"IT:FTI\", \"0097\"],\n [\"IT:IPA\", \"9921\"],\n [\"IT:IVA\", \"0211\"],\n [\"IT:SECETI\", \"0142\"],\n [\"IT:SIA\", \"0135\"],\n [\"IT:VAT\", \"9906\"],\n [\"JP:IIN\", \"0221\"],\n [\"JP:SST\", \"0188\"],\n [\"LEI\", \"0199\"],\n [\"LI:VAT\", \"9936\"],\n [\"LT:LEC\", \"0200\"],\n [\"LT:VAT\", \"9937\"],\n [\"LU:MAT\", \"0240\"],\n [\"LU:VAT\", \"9938\"],\n [\"LV:URN\", \"0218\"],\n [\"LV:VAT\", \"9939\"],\n [\"MC:VAT\", \"9940\"],\n [\"ME:VAT\", \"9941\"],\n [\"MK:VAT\", \"9942\"],\n [\"MT:VAT\", \"9943\"],\n [\"MY:EIF\", \"0230\"],\n [\"NG:TID\", \"0244\"],\n [\"NL:KVK\", \"0106\"],\n [\"NL:OIN\", \"9954\"],\n [\"NL:OINO\", \"0190\"],\n [\"NL:VAT\", \"9944\"],\n [\"NO:ORG\", \"0192\"],\n [\"NO:ORGNR\", \"9908\"],\n [\"NO:VAT\", \"9909\"],\n [\"OM:VAT\", \"0248\"],\n [\"PL:VAT\", \"9945\"],\n [\"PT:VAT\", \"9946\"],\n [\"RO:VAT\", \"9947\"],\n [\"RS:VAT\", \"9948\"],\n [\"SE:ORGNR\", \"0007\"],\n [\"SE:VAT\", \"9955\"],\n [\"SG:UEN\", \"0195\"],\n [\"SI:VAT\", \"9949\"],\n [\"SK:DIC\", \"0245\"],\n [\"SK:ICO\", \"0158\"],\n [\"SK:VAT\", \"9950\"],\n [\"SM:VAT\", \"9951\"],\n [\"SPIS\", \"0242\"],\n [\"TR:VAT\", \"9952\"],\n [\"UBLBE\", \"0193\"],\n [\"US:EIN\", \"9959\"],\n [\"VA:VAT\", \"9953\"],\n]);\n\n/**\n * Pli ASCII, jamais `toUpperCase()`.\n *\n * ⛔ LE CONTRE-EXEMPLE DÉPEND DU SENS DU PLI, et cette phrase a d'abord dit le\n * contraire. Le module voisin (`routable-schemes.ts`) cite le signe Kelvin\n * U+212A, qui se replie en `k` — mais sous `toLowerCase()`, le sens dans lequel\n * IL plie. Mesuré : sous `toUpperCase()` le Kelvin ne bouge pas, il est déjà\n * majuscule. Reprendre son exemple ici était un fait juste appliqué au mauvais\n * site.\n *\n * Les caractères qui deviennent ASCII en pliant vers le HAUT sont d'une autre\n * famille — mesurés : `ı` (U+0131) → `I`, `ß` → `SS`, `fi` → `FI`. Un pli\n * Unicode ferait donc traduire `ıE:VAT` comme s'il s'agissait de `IE:VAT`, soit\n * deux schemes distincts fusionnés — un envoi légitime refusé à tort.\n *\n * L'ENTRÉE vient du réseau ou de la base : elle n'est pas contrainte à l'ASCII,\n * même si un nom de scheme publié l'est.\n */\nfunction asciiUpper(value: string): string {\n let out = \"\";\n for (const char of value) {\n const code = char.charCodeAt(0);\n out += code >= 0x61 && code <= 0x7a ? String.fromCharCode(code - 32) : char;\n }\n return out;\n}\n\n/**\n * Ramène un scheme à son code EAS numérique — la forme que le RÉSEAU exige.\n *\n * ⚠️ Un scheme inconnu ressort **inchangé** (trimé), jamais `null` et jamais une\n * exception. Transformer « je ne connais pas ce nom » en « je refuse » ferait de\n * cette table une allowlist, c'est-à-dire nous rendrait plus stricts que le\n * réseau — l'erreur symétrique d'une mort asynchrone, et la pire des deux\n * (GPR-904). Un scheme neuf, publié après notre version de la code list, doit\n * continuer de fonctionner comme avant.\n */\nexport function canonicalScheme(scheme: string): string {\n return lookupCanonicalScheme(scheme) ?? scheme.trim();\n}\n\n/**\n * Le même lookup, mais qui DIT quand il ne connaît pas — `undefined`, jamais\n * l'entrée renvoyée telle quelle.\n *\n * ⛔ Cette distinction n'est pas cosmétique. `canonicalScheme` trime avant de\n * rendre, donc « inconnu » et « connu » se ressemblent dangereusement : comparer\n * son retour à l'entrée BRUTE fait lire « résolu » là où seul un espace a\n * disparu. Mesuré (GPR-1110) : `\" 0193:ABCD\"` ressortait trimé, donc différent de\n * l'entrée, donc pris pour un scheme à deux segments — et `\" 0193:ABCD:EFGH\"` se\n * découpait en `{scheme:\"0193:ABCD\", id:\"EFGH\"}`.\n *\n * ⭐ Tout appelant qui a besoin de savoir SI la table connaît un nom doit utiliser\n * cette fonction. `canonicalScheme` reste le bon choix pour TRADUIRE, où\n * l'identité sur un scheme inconnu est le comportement voulu (GPR-904).\n */\nexport function lookupCanonicalScheme(scheme: string): string | undefined {\n return ALIAS_TO_EAS.get(asciiUpper(scheme.trim()));\n}\n\n/**\n * Le PAYS d'un scheme Peppol — GPR-1116.\n *\n * La même code list qui publie les deux noms d'un scheme publie aussi son pays\n * (`country`, code ISO). Cette table en est la seconde projection, gravée pour\n * exactement la raison écrite plus haut : le JSON fait autorité, mais un bundler\n * ne trace pas sa lecture, donc il n'existe pas dans une fonction déployée.\n *\n * ## Pourquoi elle existe\n *\n * Le template que `getpeppr init` dépose chez le développeur devinait le pays du\n * destinataire depuis une table de QUATRE schemes (`0009`, `0204`, `0208`,\n * `9925`), et repliait tout le reste sur `\"BE\"` en dur. Un destinataire\n * norvégien, suédois, néerlandais ou turc était donc déclaré belge — dans le\n * premier fichier que le développeur reçoit de nous. La liste officielle couvre\n * 96 schemes nationaux sur 50 pays.\n *\n * Le pays du destinataire est BT-55 (EN 16931) : c'est lui qui décide QUELLES\n * regles nationales le réseau applique au document. Un pays faux ne dégrade pas\n * la facture, il la fait juger par le mauvais rulebook.\n *\n * ## Les 9 schemes SANS pays sont absents, et c'est le point\n *\n * `DUNS`, `GLN`, `LEI`, `IBAN`, `EU:VAT`… portent `international` dans la liste.\n * « International » n'est pas un code pays : les mapper vers quoi que ce soit\n * inventerait une donnée. Ils ressortent `undefined`, et c'est à l'appelant de\n * décider quoi faire d'un identifiant qui ne dit pas son pays — ce qu'aucune\n * valeur de repli ne peut faire à sa place.\n */\n/** Dérivée de participant-identifier-schemes-v9.7.json — schemes avec pays: 96 | sans (international): 9 | pays distincts: 50 */\nconst EAS_TO_COUNTRY: ReadonlyMap<string, string> = new Map([\n [\"0002\", \"FR\"],\n [\"0007\", \"SE\"],\n [\"0009\", \"FR\"],\n [\"0037\", \"FI\"],\n [\"0096\", \"DK\"],\n [\"0097\", \"IT\"],\n [\"0106\", \"NL\"],\n [\"0135\", \"IT\"],\n [\"0142\", \"IT\"],\n [\"0151\", \"AU\"],\n [\"0158\", \"SK\"],\n [\"0183\", \"CH\"],\n [\"0184\", \"DK\"],\n [\"0188\", \"JP\"],\n [\"0190\", \"NL\"],\n [\"0191\", \"EE\"],\n [\"0192\", \"NO\"],\n [\"0193\", \"BE\"],\n [\"0195\", \"SG\"],\n [\"0196\", \"IS\"],\n [\"0198\", \"DK\"],\n [\"0200\", \"LT\"],\n [\"0201\", \"IT\"],\n [\"0204\", \"DE\"],\n [\"0205\", \"IT\"],\n [\"0208\", \"BE\"],\n [\"0210\", \"IT\"],\n [\"0211\", \"IT\"],\n [\"0212\", \"FI\"],\n [\"0213\", \"FI\"],\n [\"0215\", \"FI\"],\n [\"0216\", \"FI\"],\n [\"0218\", \"LV\"],\n [\"0221\", \"JP\"],\n [\"0225\", \"FR\"],\n [\"0230\", \"MY\"],\n [\"0235\", \"AE\"],\n [\"0240\", \"LU\"],\n [\"0244\", \"NG\"],\n [\"0245\", \"SK\"],\n [\"0246\", \"DE\"],\n [\"0248\", \"OM\"],\n [\"9901\", \"DK\"],\n [\"9902\", \"DK\"],\n [\"9904\", \"DK\"],\n [\"9905\", \"DK\"],\n [\"9906\", \"IT\"],\n [\"9907\", \"IT\"],\n [\"9908\", \"NO\"],\n [\"9909\", \"NO\"],\n [\"9910\", \"HU\"],\n [\"9914\", \"AT\"],\n [\"9915\", \"AT\"],\n [\"9916\", \"AT\"],\n [\"9917\", \"IS\"],\n [\"9919\", \"AT\"],\n [\"9920\", \"ES\"],\n [\"9921\", \"IT\"],\n [\"9922\", \"AD\"],\n [\"9923\", \"AL\"],\n [\"9924\", \"BA\"],\n [\"9925\", \"BE\"],\n [\"9926\", \"BG\"],\n [\"9927\", \"CH\"],\n [\"9928\", \"CY\"],\n [\"9929\", \"CZ\"],\n [\"9930\", \"DE\"],\n [\"9931\", \"EE\"],\n [\"9932\", \"GB\"],\n [\"9933\", \"GR\"],\n [\"9934\", \"HR\"],\n [\"9935\", \"IE\"],\n [\"9936\", \"LI\"],\n [\"9937\", \"LT\"],\n [\"9938\", \"LU\"],\n [\"9939\", \"LV\"],\n [\"9940\", \"MC\"],\n [\"9941\", \"ME\"],\n [\"9942\", \"MK\"],\n [\"9943\", \"MT\"],\n [\"9944\", \"NL\"],\n [\"9945\", \"PL\"],\n [\"9946\", \"PT\"],\n [\"9947\", \"RO\"],\n [\"9948\", \"RS\"],\n [\"9949\", \"SI\"],\n [\"9950\", \"SK\"],\n [\"9951\", \"SM\"],\n [\"9952\", \"TR\"],\n [\"9953\", \"VA\"],\n [\"9954\", \"NL\"],\n [\"9955\", \"SE\"],\n [\"9956\", \"BE\"],\n [\"9957\", \"FR\"],\n [\"9958\", \"DE\"],\n [\"9959\", \"US\"],\n]);\n\n/**\n * Le pays d'un scheme, ou `undefined` quand la liste n'en publie pas.\n *\n * Accepte les DEUX orthographes : elle canonicalise avant de consulter, donc\n * `\"NO:ORG\"` et `\"0192\"` rendent tous deux `\"NO\"`.\n *\n * `undefined` couvre DEUX situations que l'appelant doit distinguer lui-même\n * s'il y tient : un scheme international (`DUNS`), et un scheme que notre version\n * de la liste ne connait pas encore. Les confondre dans un repli en dur est\n * précisément le défaut que ce module ferme — ne jamais rendre un pays par\n * défaut ici, ou l'information manquante serait maquillée en fait.\n */\nexport function countryForScheme(scheme: string): string | undefined {\n return EAS_TO_COUNTRY.get(canonicalScheme(scheme));\n}\n\n/**\n * ⚠️ Écrites pour le test de dérive, mais PUBLIÉES depuis `index.ts` (GPR-1110) —\n * le verrou vit dans la console et la table dans le SDK, donc il n'existe pas de\n * chemin privé entre les deux. Elles font par conséquent partie du contrat du\n * paquet : les retirer serait un changement majeur, pas un nettoyage.\n */\nexport const CANONICAL_SCHEME_COUNT = ALIAS_TO_EAS.size;\nexport const CANONICAL_SCHEMES_VERSION = \"9.7\";\n\n/** Nombre de schemes pour lesquels la liste publie un pays. Verrouille par le test de derive. */\nexport const SCHEME_COUNTRY_COUNT = EAS_TO_COUNTRY.size;\n","/**\n * Découper un identifiant Peppol — GPR-1110.\n *\n * Un identifiant Peppol s'écrit `<scheme>:<valeur>`, mais le scheme lui-même a\n * DEUX orthographes légales : son code EAS numérique (`9932`) et sa forme\n * symbolique (`GB:VAT`), qui contient un `:`. Le séparateur du couple et un\n * caractère du scheme sont donc le MÊME caractère — c'est toute la difficulté,\n * et la raison pour laquelle ce module existe plutôt qu'un `split(\":\")`.\n *\n * Il vit à part de `ubl-builder.ts` parce qu'il a deux appelants aux besoins\n * distincts : le constructeur d'UBL, qui doit écrire un `@schemeID` conforme à\n * `BR-CL-25`, et `directory.lookup`, qui doit interroger le registre sous le\n * scheme que celui-ci indexe. Les deux découpaient séparément, et les deux se\n * trompaient de la même manière.\n */\nimport { canonicalScheme, lookupCanonicalScheme } from \"./canonical-schemes.js\";\n\n/**\n * Un identifiant Peppol est-il assez bien formé pour qu'on écrive son scheme ?\n *\n * ⛔ « Contient un `:` » ne suffisait pas, et « deux segments non vides » non plus\n * — les deux ont été essayés et démolis par une gate (GPR-1110) :\n *\n * | entrée | découpage | pourquoi ça passait |\n * | -- | -- | -- |\n * | `\":x\"` | scheme vide | aucun contrôle sur les segments |\n * | `\"0208:\"` | valeur vide | idem |\n * | `\"GB:VAT\"` | `{GB, VAT}` | **deux segments non vides** — le code du scheme copié SANS son identifiant |\n *\n * Le dernier est le piège : `GB:VAT` est exactement ce que `SCHEMES_BY_COUNTRY`\n * affiche comme `code`, donc le copier seul est l'erreur qu'un développeur\n * commet naturellement. Il produisait `schemeID=\"GB\"`, hors CEF EAS code list.\n *\n * ⚠️ Le contrôle du scheme est SYNTAXIQUE, jamais une allowlist : quatre chiffres,\n * ou l'une des valeurs littérales que `BR-CL-25` admet. Un code publié après notre\n * version de la code list doit continuer de traverser — être plus strict que le\n * réseau est l'erreur symétrique, et la pire des deux (GPR-904).\n */\nexport function isWellFormedPeppolId(peppolId: string): boolean {\n if (!peppolId.includes(\":\")) return false;\n const { scheme, id } = parsePeppolId(peppolId);\n // ⛔ `id.length > 0` acceptait `\"0208:\\n\"` — un identifiant fait d'un seul\n // caractère blanc est vide pour le réseau, et le laisser passer grave une\n // valeur qu'aucun registre ne peut résoudre. Mesuré par gate (GPR-1116).\n return id.trim().length > 0 && (/^\\d{4}$/.test(scheme) || EAS_LITERAL_SCHEMES.has(scheme));\n}\n\n/**\n * Les schemes qu'un ENDPOINT (BT-34) ne peut pas porter — GPR-1116.\n *\n * ⚠️ `isWellFormedPeppolId` sert DEUX questions qui n'ont pas la même règle :\n * l'adresse d'une partie (`validateParty`, jugée par `BR-CL-25`) et le\n * bénéficiaire du paiement (`payeeParty`, jugé par `BR-CL-10`). `SEPA` est\n * légal pour le second et ne l'est pas pour le premier — la liste littérale\n * ci-dessus les mélange, par héritage.\n *\n * ⭐ La forme juste serait un paramètre `usage`, comme en porte déjà\n * `validatePeppolIdentifier` : « un identifiant se valide contre l'USAGE,\n * jamais dans l'absolu ». Cet export est le pas intermédiaire — il permet à un\n * appelant qui sait juger une ADRESSE de retirer ce qui n'en est pas une, sans\n * changer le verdict des appelants existants. Suivi : GPR-1128.\n */\nexport const NON_ENDPOINT_SCHEMES: ReadonlySet<string> = new Set([\"SEPA\"]);\n\n/**\n * Les valeurs non numériques que `BR-CL-25` énumère, plus `SEPA`, que `BR-CL-10`\n * admet sous le vendeur et le bénéficiaire. Gravées depuis les asserts.\n */\nconst EAS_LITERAL_SCHEMES: ReadonlySet<string> = new Set([\"AN\", \"AQ\", \"AS\", \"AU\", \"EM\", \"SEPA\"]);\n\n/**\n * Sépare un identifiant Peppol en son scheme EAS **numérique** et sa valeur.\n *\n * ⛔ **Ne découpe PAS sur le premier `:`.** Mesuré sur la code list officielle\n * v9.7 : 98 des 105 formes symboliques portent un `:`. Découper par position\n * rendait `{ scheme: \"GB\", id: \"VAT:123456789\" }` pour un vendeur britannique —\n * le scheme hors CEF EAS code list (`BR-CL-25`, fatale) ET la valeur corrompue.\n * `GB:VAT` étant le code que `SCHEMES_BY_COUNTRY` RECOMMANDE au Royaume-Uni,\n * le défaut frappait quiconque suivait notre propre guidage.\n * ⚠️ Cette phrase a dit « le SEUL code » jusqu'à GPR-1041, qui a ajouté `0060`,\n * `0088` et `0199` pour les sociétés sous le seuil de TVA. Le motif du défaut\n * est intact — c'est la RECOMMANDATION qui le rendait atteignable, pas\n * l'exclusivité — mais l'exclusivité, elle, n'est plus vraie.\n *\n * ⭐ **Le scheme occupe au plus DEUX segments**, et ce n'est pas une prudence :\n * mesuré sur la v9.7, aucune forme symbolique ne porte plus d'un `:`. La VALEUR,\n * elle, n'est bornée par rien — d'où l'essai du candidat long d'abord, puis le\n * repli sur le court. L'ordre inverse ferait dépendre le point de coupe de la\n * valeur, ce qui est exactement le défaut qu'on ferme.\n *\n * ⚠️ Un scheme que la table ne connaît pas ressort **inchangé**, jamais en\n * exception : c'est la doctrine de `canonicalScheme` (GPR-904), et elle vaut ici\n * aussi. Un scheme numérique publié après notre version de la code list doit\n * continuer de traverser — être plus strict que le réseau est l'erreur\n * symétrique, et la pire des deux.\n */\nexport function parsePeppolId(peppolId: string): { scheme: string; id: string } {\n const first = peppolId.indexOf(\":\");\n if (first === -1) {\n // Le type `PeppolId` l'interdit, mais un appelant JavaScript n'a pas de type.\n // Canonicaliser quand même : `DUNS` seul vaut mieux que `DUNS` recopié tel quel.\n return { scheme: canonicalScheme(peppolId), id: \"\" };\n }\n\n const second = peppolId.indexOf(\":\", first + 1);\n if (second !== -1) {\n // ⛔ On DEMANDE à la table si elle connaît ce nom ; on ne DÉDUIT pas la\n // réponse en comparant deux chaînes. `canonicalScheme` trime son entrée, donc\n // « le retour diffère de ce que j'ai passé » est vrai aussi quand seul un\n // espace a disparu : `\" 0193:ABCD:EFGH\"` se découpait en\n // `{scheme:\"0193:ABCD\", id:\"EFGH\"}` (GPR-1110, trouvé par gate).\n const resolved = lookupCanonicalScheme(peppolId.slice(0, second));\n if (resolved !== undefined) {\n return { scheme: resolved, id: peppolId.slice(second + 1) };\n }\n }\n\n // Un seul segment de scheme : soit le code EAS numérique (rendu tel quel), soit\n // l'une des 7 formes symboliques sans `:` de la v9.7 (`DUNS`, `GLN`, `LEI`…).\n return {\n scheme: canonicalScheme(peppolId.slice(0, first)),\n id: peppolId.slice(first + 1),\n };\n}\n","/**\n * La liste ISO 6523 ICD — celle que `BR-CL-10` exige, et qui n'est PAS la liste EAS.\n *\n * ## ⛔ Deux listes, deux règles, deux champs — ne jamais les confondre\n *\n * | Champ UBL | Règle | Liste | `9932` (GB) admis ? |\n * | -- | -- | -- | -- |\n * | `cbc:EndpointID/@schemeID` | `BR-CL-25` | CEF **EAS** (104 valeurs) | ✅ oui |\n * | `cac:PartyIdentification/cbc:ID/@schemeID` | `BR-CL-10` | ISO 6523 **ICD** (243 valeurs) | ⛔ non |\n *\n * ⚠️ `PEPPOL_ICD_CODES`, dans le module voisin, porte « ICD » dans son nom mais\n * contient les `99xx` : c'est la liste EAS. Ne pas s'en servir pour juger\n * `BR-CL-10` — le nom ment, la constante ci-dessous ne ment pas.\n *\n * ## Pourquoi cette constante existe (GPR-1110)\n *\n * Mesuré le 2026-08-20 par `POST /v1/validate/ubl`, sur ce que NOTRE constructeur\n * produit : un vendeur `9932` (GB), `9935` (IE) ou `9930` (DE USt-IdNr) recevait\n * `BR-CL-10` **fatale**, localisée sur\n * `/Invoice/AccountingSupplierParty/Party/PartyIdentification/ID`. Les témoins\n * `0208` (BE) et `0204` (DE) ne la recevaient pas. Le défaut est indépendant du\n * découpage que ce ticket corrige par ailleurs : il frappait DÉJÀ la forme\n * numérique, et aucun des 1038 tests du paquet ne pouvait le voir.\n *\n * La conduite qui en découle est celle que la spec `BT-29` prescrit et que le tir\n * réseau de GPR-1102 avait déjà mesurée : `9932` et `9935` n'apparaissent ni en\n * BT-29 ni en BT-30, seulement en BT-31. Un scheme hors de cette liste ne\n * s'écrit donc PAS en `PartyIdentification` — le champ est optionnel, et\n * l'omettre est la seule écriture conforme.\n *\n * ## Provenance\n *\n * Extraite mécaniquement de l'énumération littérale de `BR-CL-10` dans\n * `console/src/lib/api/peppol-schematron/CEN-EN16931-UBL.sch` (rulebook Peppol\n * `v3.0.21`, empreinte gravée dans son `manifest.ts`). 243 valeurs, `0002`–`0248`,\n * avec quatre trous réels (`0092`, `0103`, `0181`, `0182`) — d'où une liste\n * explicite et non une plage.\n *\n * ⛔ **Ne jamais éditer à la main — la régénérer depuis le `.sch`.** Le verrou de\n * dérive vit auprès de l'artefact, dans\n * `console/src/lib/api/peppol-schematron/__tests__/`.\n */\n/**\n * ⛔ `ReadonlySet` est un type, pas une garantie de runtime : un `Set` exporté\n * reste mutable pour qui le reçoit, et celui-ci PILOTE directement l'XML émis.\n * Mesuré (GPR-1110) : un simple `ISO6523_ICD_CODES.add(\"9932\")` chez le\n * consommateur suffisait à faire écrire un `PartyIdentification schemeID=\"9932\"`,\n * fatal sous `BR-CL-10`, dans un document jusque-là conforme. Le paquet est\n * PUBLIÉ — la seule frontière qui tienne est celle qu'on impose au runtime.\n */\nconst ICD_CODES = new Set([\n \"0002\", \"0003\", \"0004\", \"0005\", \"0006\", \"0007\", \"0008\", \"0009\", \"0010\",\n \"0011\", \"0012\", \"0013\", \"0014\", \"0015\", \"0016\", \"0017\", \"0018\", \"0019\",\n \"0020\", \"0021\", \"0022\", \"0023\", \"0024\", \"0025\", \"0026\", \"0027\", \"0028\",\n \"0029\", \"0030\", \"0031\", \"0032\", \"0033\", \"0034\", \"0035\", \"0036\", \"0037\",\n \"0038\", \"0039\", \"0040\", \"0041\", \"0042\", \"0043\", \"0044\", \"0045\", \"0046\",\n \"0047\", \"0048\", \"0049\", \"0050\", \"0051\", \"0052\", \"0053\", \"0054\", \"0055\",\n \"0056\", \"0057\", \"0058\", \"0059\", \"0060\", \"0061\", \"0062\", \"0063\", \"0064\",\n \"0065\", \"0066\", \"0067\", \"0068\", \"0069\", \"0070\", \"0071\", \"0072\", \"0073\",\n \"0074\", \"0075\", \"0076\", \"0077\", \"0078\", \"0079\", \"0080\", \"0081\", \"0082\",\n \"0083\", \"0084\", \"0085\", \"0086\", \"0087\", \"0088\", \"0089\", \"0090\", \"0091\",\n \"0093\", \"0094\", \"0095\", \"0096\", \"0097\", \"0098\", \"0099\", \"0100\", \"0101\",\n \"0102\", \"0104\", \"0105\", \"0106\", \"0107\", \"0108\", \"0109\", \"0110\", \"0111\",\n \"0112\", \"0113\", \"0114\", \"0115\", \"0116\", \"0117\", \"0118\", \"0119\", \"0120\",\n \"0121\", \"0122\", \"0123\", \"0124\", \"0125\", \"0126\", \"0127\", \"0128\", \"0129\",\n \"0130\", \"0131\", \"0132\", \"0133\", \"0134\", \"0135\", \"0136\", \"0137\", \"0138\",\n \"0139\", \"0140\", \"0141\", \"0142\", \"0143\", \"0144\", \"0145\", \"0146\", \"0147\",\n \"0148\", \"0149\", \"0150\", \"0151\", \"0152\", \"0153\", \"0154\", \"0155\", \"0156\",\n \"0157\", \"0158\", \"0159\", \"0160\", \"0161\", \"0162\", \"0163\", \"0164\", \"0165\",\n \"0166\", \"0167\", \"0168\", \"0169\", \"0170\", \"0171\", \"0172\", \"0173\", \"0174\",\n \"0175\", \"0176\", \"0177\", \"0178\", \"0179\", \"0180\", \"0183\", \"0184\", \"0185\",\n \"0186\", \"0187\", \"0188\", \"0189\", \"0190\", \"0191\", \"0192\", \"0193\", \"0194\",\n \"0195\", \"0196\", \"0197\", \"0198\", \"0199\", \"0200\", \"0201\", \"0202\", \"0203\",\n \"0204\", \"0205\", \"0206\", \"0207\", \"0208\", \"0209\", \"0210\", \"0211\", \"0212\",\n \"0213\", \"0214\", \"0215\", \"0216\", \"0217\", \"0218\", \"0219\", \"0220\", \"0221\",\n \"0222\", \"0223\", \"0224\", \"0225\", \"0226\", \"0227\", \"0228\", \"0229\", \"0230\",\n \"0231\", \"0232\", \"0233\", \"0234\", \"0235\", \"0236\", \"0237\", \"0238\", \"0239\",\n \"0240\", \"0241\", \"0242\", \"0243\", \"0244\", \"0245\", \"0246\", \"0247\", \"0248\",\n]);\n\n/**\n * La vue publique : toute mutation lève au lieu d'altérer silencieusement ce que\n * le constructeur écrira. `add`/`delete`/`clear` sont neutralisés, l'itération et\n * `has` restent intacts.\n */\nexport const ISO6523_ICD_CODES: ReadonlySet<string> = Object.freeze({\n has: (v: string) => ICD_CODES.has(v),\n get size() {\n return ICD_CODES.size;\n },\n keys: () => ICD_CODES.keys(),\n values: () => ICD_CODES.values(),\n entries: () => ICD_CODES.entries(),\n forEach: (fn: (v: string, v2: string, set: ReadonlySet<string>) => void, thisArg?: unknown) =>\n ICD_CODES.forEach((v, v2) => fn.call(thisArg, v, v2, ISO6523_ICD_CODES)),\n [Symbol.iterator]: () => ICD_CODES[Symbol.iterator](),\n}) as ReadonlySet<string>;\n\n/**\n * Ce scheme peut-il légalement porter un `@schemeID` de `PartyIdentification/ID` ?\n *\n * ⚠️ Attend un code EAS **déjà canonicalisé** (`9932`, pas `GB:VAT`) : la question\n * porte sur l'appartenance à une liste, jamais sur l'orthographe. Passer une forme\n * symbolique rendrait `false` pour une raison qui n'est pas la bonne.\n */\nexport function isIso6523IcdCode(scheme: string): boolean {\n return ICD_CODES.has(scheme);\n}\n\n/**\n * Où un `cac:PartyIdentification/cbc:ID` peut apparaître, au sens de `BR-CL-10`.\n *\n * La règle discrimine par ANCÊTRE, pas seulement par code — d'où ce paramètre.\n */\nexport type PartyIdentificationContext =\n | \"AccountingSupplierParty\"\n | \"AccountingCustomerParty\"\n | \"PayeeParty\";\n\n/**\n * Ce scheme peut-il légalement porter le `@schemeID` d'un `PartyIdentification/ID`\n * dans CE contexte ?\n *\n * ⛔ `BR-CL-10` n'est PAS « le code appartient à la liste ICD ». Sa forme complète,\n * lue jusqu'au bout de l'assert dans `CEN-EN16931-UBL.sch` :\n *\n * ```\n * (schemeID ∈ liste ICD)\n * OU (schemeID = 'SEPA' ET ancêtre ∈ {AccountingSupplierParty, PayeeParty})\n * ```\n *\n * ⚠️ La clause `or` vit APRÈS les 243 codes. Une extraction qui capture la liste\n * puis juge sur elle ne la voit jamais — c'est ainsi qu'une première version de\n * ce module a traité l'appartenance ICD comme toute la règle, et jeté en silence\n * un identifiant `SEPA` que le réseau accepte. **Être plus strict que la spec est\n * l'erreur symétrique de la laisser passer, pas une prudence** (GPR-1110).\n *\n * ⭐ Mesuré le 2026-08-20 : chez le BÉNÉFICIAIRE, le préjudice est réel — un\n * `PayeeParty` n'écrit aucun `EndpointID`, donc rien d'autre ne refuse le\n * document et l'identifiant disparaît sans bruit (`conformant: true` sans lui).\n * Chez le VENDEUR il ne l'est pas : l'`EndpointID` porte le même scheme et\n * `BR-CL-25`, qui ne connaît pas `SEPA`, rend le document fatal de toute façon.\n * La règle est appliquée telle qu'elle est écrite dans les deux cas — être fidèle\n * à la spec vaut mieux qu'optimiser pour ce qu'on peut observer aujourd'hui.\n */\nexport function canCarryPartyIdentification(\n scheme: string,\n context: PartyIdentificationContext,\n): boolean {\n if (ICD_CODES.has(scheme)) return true;\n return scheme === \"SEPA\" && context !== \"AccountingCustomerParty\";\n}\n","/**\n * UBL XML Builder\n *\n * Converts our clean JSON invoice format to a Peppol BIS 3.0 UBL 2.1 structure.\n * Compliance still depends on the supplied business data; use `Peppol.toXml()`\n * for the SDK's blocking offline checks before generating XML.\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\";\nimport { parsePeppolId } from \"./peppol-id.js\";\nimport { canCarryPartyIdentification } from \"./iso6523-icd-codes.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/** VAT categories whose breakdown requires BT-120 or BT-121. */\nconst EXEMPTION_REASON_CATEGORIES = new Set([\"E\", \"AE\", \"K\", \"G\", \"O\"]);\nconst EXEMPTION_REASON_RULES: Readonly<Record<string, string>> = {\n E: \"BR-E-10\",\n AE: \"BR-AE-10\",\n K: \"BR-IC-10\",\n G: \"BR-G-10\",\n O: \"BR-O-10\",\n};\n\n/** @internal Stable, non-echoing input error used by `Peppol.toXml()`. */\nexport class UblBuilderInputError extends Error {\n constructor(\n message: string,\n public readonly field: string,\n public readonly ruleId?: string,\n ) {\n super(message);\n this.name = \"UblBuilderInputError\";\n }\n}\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\nfunction formatVatRate(vatRate: number, field: string): string {\n if (typeof vatRate !== \"number\" || !Number.isFinite(vatRate)) {\n throw new UblBuilderInputError(\"vatRate must be a finite number.\", field);\n }\n return String(vatRate);\n}\n\nfunction assertValidBaseQuantity(baseQuantity: number, field: string): void {\n if (\n typeof baseQuantity !== \"number\" ||\n !Number.isFinite(baseQuantity) ||\n baseQuantity <= 0\n ) {\n throw new UblBuilderInputError(\n \"baseQuantity must be a finite number greater than zero.\",\n field,\n \"PEPPOL-EN16931-R121\",\n );\n }\n}\n\n// GPR-1170 — the direction of an adjustment travels in the ELEMENT\n// (BG-20/21/27/28, ChargeIndicator), never in the sign: BR-CO-11/12/13 and\n// PEPPOL-EN16931-R120 sum these amounts as magnitudes. The input contract is\n// getpeppr-local (rule id \"GPR-1170\"): only `undefined` means absent, amounts\n// are finite >= 0, and every final derivation stays finite. Invalid inputs are\n// rejected at this boundary instead of being normalized away — the Storecove\n// mapper rejects the same inputs, keeping both rendering surfaces in parity.\nconst ADJUSTMENT_CONTRACT_RULE = \"GETPEPPR-ALLOWANCE-CHARGE-AMOUNT\";\nconst ADJUSTMENT_AMOUNT_MESSAGE =\n \"Allowance and charge amounts must be finite numbers greater than or equal to zero. An allowance reduces the amount and a charge increases it; encode the direction in the field, never in the sign.\";\n\n// GPR-1170 — individually finite inputs can overflow once summed; every final\n// derivation must be finite before it is rendered or sent.\nconst DERIVED_AMOUNT_CONTRACT_RULE = \"GETPEPPR-DERIVED-AMOUNT\";\nconst NON_FINITE_DERIVED_AMOUNT_MESSAGE =\n \"Derived amount is not finite (overflow). Reduce quantities, prices or adjustment amounts so every total stays representable.\";\n\n// A monetary amount is deliverable only if it survives the cents scaling the\n// delivery pipeline actually performs (the provider-side 2-decimal rounding).\nfunction survivesCents(value: number): boolean {\n return Number.isFinite(value) && Number.isFinite(value * 100);\n}\n\nfunction assertValidAdjustmentAmounts(\n items: unknown,\n field: string,\n): void {\n // Only `undefined` means absent; `null` is a malformed form.\n if (items === undefined) return;\n if (!Array.isArray(items)) {\n throw new UblBuilderInputError(\n `${field} must be an array — omit the field instead of sending ${items === null ? \"null\" : typeof items}`,\n field,\n ADJUSTMENT_CONTRACT_RULE,\n );\n }\n for (const [i, item] of items.entries()) {\n const amount = (item as { amount?: unknown } | null)?.amount;\n if (\n item === null ||\n typeof item !== \"object\" ||\n typeof amount !== \"number\" ||\n !Number.isFinite(amount) ||\n amount < 0\n ) {\n throw new UblBuilderInputError(ADJUSTMENT_AMOUNT_MESSAGE, `${field}[${i}].amount`, ADJUSTMENT_CONTRACT_RULE);\n }\n }\n}\n\nfunction assertDocumentAdjustmentAmounts(input: InvoiceInput | CreditNoteInput): void {\n for (const [i, line] of input.lines.entries()) {\n assertValidAdjustmentAmounts(line.allowances, `lines[${i}].allowances`);\n assertValidAdjustmentAmounts(line.charges, `lines[${i}].charges`);\n }\n assertValidAdjustmentAmounts((input as InvoiceInput).allowances as unknown, \"allowances\");\n assertValidAdjustmentAmounts((input as InvoiceInput).charges as unknown, \"charges\");\n}\n\nfunction formatBaseQuantity(baseQuantity: number, field: string): string {\n assertValidBaseQuantity(baseQuantity, field);\n\n const numeric = String(baseQuantity);\n const exponentMarker = numeric.search(/[eE]/);\n if (exponentMarker === -1) return numeric;\n\n const coefficient = numeric.slice(0, exponentMarker);\n const exponent = Number(numeric.slice(exponentMarker + 1));\n const decimalPoint = coefficient.indexOf(\".\");\n const digits = coefficient.replace(\".\", \"\");\n const integerDigits = decimalPoint === -1 ? coefficient.length : decimalPoint;\n const outputPoint = integerDigits + exponent;\n\n if (outputPoint <= 0) {\n return `0.${\"0\".repeat(-outputPoint)}${digits}`;\n }\n if (outputPoint >= digits.length) {\n return `${digits}${\"0\".repeat(outputPoint - digits.length)}`;\n }\n return `${digits.slice(0, outputPoint)}.${digits.slice(outputPoint)}`;\n}\n\n/** Peppol monetary rounding shared with the gateway mapper. */\nexport function roundUblCurrencyAmount(value: number): number {\n const rounded = Math.round((value + Math.sign(value) * Number.EPSILON) * 100) / 100;\n return Object.is(rounded, -0) ? 0 : rounded;\n}\n\nfunction normalizedTaxExemptReason(vatCategory: string, reason: string | undefined): string | undefined {\n if (!EXEMPTION_REASON_CATEGORIES.has(vatCategory) || typeof reason !== \"string\") {\n return undefined;\n }\n const normalized = reason.trim();\n for (const character of normalized) {\n const codePoint = character.codePointAt(0)!;\n const allowed =\n codePoint === 0x09 ||\n codePoint === 0x0a ||\n codePoint === 0x0d ||\n (codePoint >= 0x20 && codePoint <= 0xd7ff) ||\n (codePoint >= 0xe000 && codePoint <= 0xfffd) ||\n (codePoint >= 0x10000 && codePoint <= 0x10ffff);\n if (!allowed) {\n throw new UblBuilderInputError(\n \"taxExemptReason contains an invalid XML character.\",\n \"taxExemptReason\",\n );\n }\n }\n return normalized || undefined;\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 ${\n // ⛔ DEUX listes, pas une. `BR-CL-25` juge l'EndpointID ci-dessus contre la\n // liste EAS (104 valeurs, jusqu'à `9959`) ; `BR-CL-10` juge CE champ-ci\n // contre la liste ISO 6523 ICD (243 valeurs, `0002`–`0248`). `9932` (GB),\n // `9935` (IE) et `9930` (DE) sont légaux là-haut et FATALS ici.\n //\n // Le champ (BT-29) est optionnel : l'omettre est la seule écriture\n // conforme pour ces schemes, et c'est ce que le tir réseau de GPR-1102\n // avait déjà mesuré — `9932`/`9935` n'apparaissent ni en BT-29 ni en\n // BT-30, seulement en BT-31. Émettre quand même rendait `BR-CL-10` fatale\n // pour tout vendeur britannique, irlandais ou allemand en `9930`,\n // y compris en écrivant la forme numérique (GPR-1110).\n //\n // ⚠️ BR-CO-26 exige alors qu'un autre identifiant porte l'expéditeur —\n // `vatNumber` (BT-31) ou `companyId` (BT-30) ci-dessous. `validateInvoice`\n // AVERTIT quand il n'y en a aucun ; il ne refuse pas, et `toXml()` rend\n // donc bel et bien un document que le réseau rejettera. C'est délibéré :\n // `from` est déclaré « deprecated and ignored » à l'envoi, où l'expéditeur\n // vient de la clé API — bloquer ici casserait des appelants dont le\n // document part très bien.\n canCarryPartyIdentification(endpointScheme, role)\n ? `<cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(endpointScheme)}\">${escapeXml(endpointId)}</cbc:ID>\n </cac:PartyIdentification>`\n : \"\"\n }\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 ${\n // Même règle qu'au-dessus : `BR-CL-10` a pour contexte TOUT\n // `cac:PartyIdentification/cbc:ID[@schemeID]`, PayeeParty compris. Le\n // bénéficiaire (BT-60) reste identifié par son nom, toujours émis.\n canCarryPartyIdentification(scheme, \"PayeeParty\")\n ? `<cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(scheme)}\">${escapeXml(id)}</cbc:ID>\n </cac:PartyIdentification>`\n : \"\"\n }\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>${escapeXml(vatCategory)}</cbc:ID>\n ${vatCategory === \"O\" ? \"\" : `<cbc:Percent>${formatVatRate(item.vatRate, \"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, lineIndex: number): number {\n // PEPPOL-EN16931-R120: BT-131 = quantity × (BT-146 / BT-149) + charges − allowances.\n if (line.baseQuantity !== undefined) {\n assertValidBaseQuantity(line.baseQuantity, `lines[${lineIndex}].baseQuantity`);\n }\n const base = (line.quantity * line.unitPrice) / (line.baseQuantity ?? 1);\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 const total = base - lineAllowances + lineCharges;\n // GPR-1170 — individually finite inputs can still overflow once summed\n // (two 1e308 charges). A non-finite BT-131 must never be rendered.\n if (!survivesCents(total)) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n `lines[${lineIndex}]`,\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\n return total;\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, index);\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>${escapeXml(vatCategory)}</cbc:ID>\n ${vatCategory === \"O\" ? \"\" : `<cbc:Percent>${formatVatRate(line.vatRate, \"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 !== undefined ? `<cbc:BaseQuantity unitCode=\"${escapeXml(resolveUnitCode(line.baseQuantityUnit ?? line.unit ?? DEFAULT_UNIT))}\">${formatBaseQuantity(line.baseQuantity, `lines[${index}].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 taxExemptReason?: string;\n taxableAmount: number;\n taxAmount: number;\n}\n\nfunction calculateTaxSubtotals(\n lines: InvoiceLine[],\n allowances?: AllowanceCharge[],\n charges?: AllowanceCharge[],\n options: { forUbl?: boolean } = {},\n): TaxSubtotal[] {\n const groups = new Map<string, TaxSubtotal>();\n\n function addToGroup(\n vatCategory: string,\n vatRate: number,\n amount: number,\n taxExemptReason?: string,\n field = \"taxExemptReason\",\n ) {\n if (typeof vatCategory !== \"string\") {\n throw new UblBuilderInputError(\"vatCategory must be a string.\", `${field}.vatCategory`);\n }\n formatVatRate(vatRate, `${field}.vatRate`);\n // BR-O-05/06/07 omit the rate entirely; treating every supplied O rate as\n // the same zero-tax group also prevents duplicate O breakdowns.\n if (options.forUbl && vatCategory === \"O\" && vatRate !== 0) {\n throw new UblBuilderInputError(\n \"Category O must use vatRate 0 in SDK input.\",\n `${field}.vatRate`,\n );\n }\n const effectiveVatRate = options.forUbl && vatCategory === \"O\" ? 0 : vatRate;\n const reason = options.forUbl\n ? normalizedTaxExemptReason(vatCategory, taxExemptReason)\n : undefined;\n const key = `${vatCategory}-${effectiveVatRate}`;\n const existing = groups.get(key);\n if (existing) {\n if (reason && existing.taxExemptReason && reason !== existing.taxExemptReason) {\n throw new UblBuilderInputError(\n `Conflicting taxExemptReason values for VAT group ${vatCategory}/${effectiveVatRate}.`,\n \"taxExemptReason\",\n );\n }\n existing.taxExemptReason ??= reason;\n existing.taxableAmount += amount;\n } else {\n groups.set(key, {\n vatRate: effectiveVatRate,\n vatCategory,\n taxExemptReason: reason,\n taxableAmount: amount,\n taxAmount: 0, // computed once per group below (BR-CO-17)\n });\n }\n }\n\n for (const [index, line] of lines.entries()) {\n addToGroup(\n line.vatCategory ?? \"S\",\n line.vatRate,\n calculateLineExtensionAmount(line, index),\n line.taxExemptReason,\n `lines[${index}]`,\n );\n }\n\n for (const [index, a] of (allowances ?? []).entries()) {\n addToGroup(a.vatCategory ?? \"S\", a.vatRate, -a.amount, a.taxExemptReason, `allowances[${index}]`);\n }\n\n for (const [index, c] of (charges ?? []).entries()) {\n addToGroup(c.vatCategory ?? \"S\", c.vatRate, c.amount, c.taxExemptReason, `charges[${index}]`);\n }\n\n if (options.forUbl) {\n for (const subtotal of groups.values()) {\n if (EXEMPTION_REASON_CATEGORIES.has(subtotal.vatCategory) && !subtotal.taxExemptReason) {\n throw new UblBuilderInputError(\n `VAT category ${subtotal.vatCategory} requires a non-empty taxExemptReason.`,\n \"taxExemptReason\",\n EXEMPTION_REASON_RULES[subtotal.vatCategory],\n );\n }\n }\n }\n\n // BR-CO-17: BT-117 = round(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 const taxableAmount = roundUblCurrencyAmount(subtotal.taxableAmount);\n const taxAmount = roundUblCurrencyAmount(taxableAmount * (subtotal.vatRate / 100));\n // GPR-1170 — every grouped derivation must stay finite; a FINITE taxable\n // can still overflow once its rate is applied.\n if (!survivesCents(taxableAmount) || !survivesCents(taxAmount)) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n \"totals\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\n return { ...subtotal, taxableAmount, taxAmount };\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 options: { forUbl?: boolean } = {},\n): DocumentTotals {\n const taxSubtotals = calculateTaxSubtotals(lines, allowances, charges, options);\n const lineExtensionAmount = lines.reduce(\n (sum, line, index) => sum + calculateLineExtensionAmount(line, index),\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 = roundUblCurrencyAmount(\n lineExtensionAmount - allowanceTotalAmount + chargeTotalAmount,\n );\n // GPR-1170 — the aggregate derivations must stay finite too:\n // line nets can each be fine while their document totals overflow.\n if (\n !survivesCents(allowanceTotalAmount) ||\n !survivesCents(chargeTotalAmount) ||\n !survivesCents(taxExclusiveAmount)\n ) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n \"totals\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\n const totalTax = roundUblCurrencyAmount(\n taxSubtotals.reduce((sum, st) => sum + st.taxAmount, 0),\n );\n const taxInclusiveAmount = roundUblCurrencyAmount(taxExclusiveAmount + totalTax);\n // GPR-1170 — ALL final derivations are checked explicitly (BR-CO-15 chain):\n // every subtotal is finite but their sum (or the addition below) can still\n // overflow. Nothing non-finite is rendered.\n if (!survivesCents(totalTax) || !survivesCents(taxInclusiveAmount)) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n \"totals\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\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>${escapeXml(st.vatCategory)}</cbc:ID>\n ${st.vatCategory === \"O\" ? \"\" : `<cbc:Percent>${formatVatRate(st.vatRate, \"vatRate\")}</cbc:Percent>`}\n ${st.taxExemptReason ? `<cbc:TaxExemptionReason>${escapeXml(st.taxExemptReason)}</cbc:TaxExemptionReason>` : \"\"}\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 = roundUblCurrencyAmount(totalTax * rate);\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 (the shared currency rounder 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/** The two distinct legal totals rendered in `cac:LegalMonetaryTotal`. */\nexport interface UblMonetaryAmounts {\n /** BT-112 — document total including VAT; prepaid/rounding do not change it. */\n taxInclusiveAmount: number;\n /** BT-115 — amount due after prepaid amount and payable rounding. */\n payableAmount: number;\n}\n\n/**\n * BT-112 and BT-115 from the same calculation used by the Invoice and CreditNote\n * XML builders. Consumers that need both totals must call this projection once,\n * rather than maintaining a second partial formula for the display amount.\n */\nexport function computeUblMonetaryAmounts(input: UblMonetaryInput): UblMonetaryAmounts {\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n return {\n taxInclusiveAmount: totals.taxInclusiveAmount,\n payableAmount: payableFromTaxInclusive(\n totals.taxInclusiveAmount,\n input.prepaidAmount,\n input.roundingAmount,\n ),\n };\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 return computeUblMonetaryAmounts(input).payableAmount;\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 UBL 2.1 Invoice XML from a simple JSON input.\n *\n * This low-level builder does not run the full Peppol rulebook. Compliance is\n * conditional on the input (for example, BuyerReference or OrderReference is\n * required, and exempt VAT breakdowns need `taxExemptReason`). Prefer\n * `Peppol.toXml()` when blocking SDK validation is required before rendering.\n */\nexport function buildInvoiceXml(input: InvoiceInput): string {\n assertDocumentAdjustmentAmounts(input);\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, { forUbl: true });\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 UBL 2.1 Credit Note XML.\n * Compliance is conditional on the business data; see `buildInvoiceXml`.\n *\n * Generates XML directly with correct CreditNote elements — no string replacement.\n */\nexport function buildCreditNoteXml(input: CreditNoteInput): string {\n assertDocumentAdjustmentAmounts(input);\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, { forUbl: true });\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 // ⛔ GPR-1199 — Sweden is deliberately absent, buyer side AND seller side, and\n // the playbook requires the decision be written rather than left to silence.\n //\n // Every one of the thirteen `SE-R-*` assertions — the seven fatal ones and the\n // six payment-means warnings — takes its SUBJECT from\n // `//cac:AccountingSupplierParty`, read verbatim from the versioned rulebook\n // (Peppol v3.0.20, `PEPPOL-EN16931-UBL.sch` l. 643-695) on 2026-08-27.\n //\n // ⚠️ ONE context also mentions the customer, and saying \"not one judges the\n // customer\" would be too broad: `SE-R-012` (warning, domestic credit transfer)\n // reads `//cac:AccountingCustomerParty/…/IdentificationCode = 'SE'` — but as a\n // DOMESTICITY CONDITION, never as the thing being judged. What it asserts is\n // still the supplier's `cac:PaymentMeans`.\n //\n // The conclusion is unchanged: no `SE-R-*` rule places a requirement ON the\n // buyer. A buyer-side warning here would assert a Swedish requirement against\n // a party the Swedish rulebook asks nothing of — the\n // two-correct-rules-that-contradict shape of GPR-1109, manufactured on purpose.\n //\n // The seller side is closed for a different reason: `SE-R-004`/`-013` judge the\n // `CompanyID` the Swedish cartridge INJECTS from the registered\n // organisationsnummer, not anything `input.from` carries. A warning on\n // `from.companyId` would fire on a field the gateway overrides, which is worse\n // than no warning — it teaches a rule that is not the one being applied.\n //\n // What a Swedish sender actually gets is upstream of this file: an actionable\n // 422 naming `SE-R-003` when no orgnr is registered, and the format check the\n // add-identifier modal now runs (`peppol-identifier-rules.ts`, `0007`).\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 and HRK are GONE (GPR-1205). Neither is in BR-CL-04/BR-CL-05 of the\n // graved 3.0.21 rulebooks — Bulgaria and Croatia both joined the euro — so\n // accepting them here would wave through a document the network refuses, which\n // is the exact failure this release closes. XCG replaces ANG (never carried\n // here) for the Dutch Caribbean. `currency-codes-network-parity.test.ts` reds\n // if this table ever readmits a code the rulebooks reject.\n [\"XCG\", { code: \"XCG\", name: \"Caribbean Guilder\", 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 sorted by code.\n *\n * @returns Array of payment means codes\n */\nexport function getPaymentMeansCodes(): PaymentMeansCode[] {\n return [...PAYMENT_MEANS_CODES];\n}\n\n// ─── Invoice type codes (UNTDID 1001, BR-CL-01) ──────────────────────────────\n\n/**\n * GPR-1234 — les DEUX vocabulaires de BR-CL-01, verbatim du rulebook gravé.\n *\n * Jusqu'ici `validator.ts` décidait sur une liste écrite à la main de 7 codes,\n * publiée telle quelle dans `openapi.yaml`. Or BR-CL-01 — fatale — définit deux\n * vocabulaires DISJOINTS : 50 codes pour `<cbc:InvoiceTypeCode>`, 13 pour\n * `<cbc:CreditNoteTypeCode>` (seul `81` figure dans les deux). La liste unique\n * décrivait comme valides 6 codes illégaux pour un avoir, et refusait 44 codes\n * légaux pour une facture — dont `326` (facture partielle), que `DE-R-017`\n * cite nommément dans le même rulebook. Approximer une liste externe est le\n * défaut, la lire est le correctif (même leçon que BR-CL-14) : la source est\n * `peppol-schematron/CEN-EN16931-UBL.sch` v3.0.21, et le verrou console\n * `invoice-type-codes-network-parity.test.ts` rougit au premier écart.\n */\nconst INVOICE_TYPE_CODES = [\n 71, 80, 81, 82, 84, 102, 130, 202, 203, 204, 211, 218, 219, 295, 325, 326,\n 331, 380, 382, 383, 384, 385, 386, 387, 388, 389, 390, 393, 394, 395, 456,\n 457, 471, 472, 473, 500, 501, 527, 553, 575, 623, 633, 751, 780, 817, 870,\n 875, 876, 877, 935,\n] as const;\n\n/** Les 13 codes légaux en `<cbc:CreditNoteTypeCode>` — voir `INVOICE_TYPE_CODES`. */\nconst CREDIT_NOTE_TYPE_CODES = [\n 81, 83, 261, 262, 296, 308, 381, 396, 420, 458, 502, 503, 532,\n] as const;\n\n/**\n * Any legal document type code — the UNION of both BR-CL-01 vocabularies.\n *\n * ⚠️ This type cannot express the context: `381` is legal on a credit note but\n * fatal on an invoice, `382` the reverse. Runtime validation\n * (`validateInvoice`) picks the vocabulary from `isCreditNote` — the type is\n * only the outer bound.\n */\nexport type InvoiceTypeCode =\n | (typeof INVOICE_TYPE_CODES)[number]\n | (typeof CREDIT_NOTE_TYPE_CODES)[number];\n\n/**\n * The 50 UNTDID 1001 codes BR-CL-01 allows as `<cbc:InvoiceTypeCode>`.\n *\n * @returns A fresh array — mutating the result cannot poison the vocabulary\n */\nexport function getInvoiceTypeCodes(): number[] {\n return [...INVOICE_TYPE_CODES];\n}\n\n/**\n * The 13 UNTDID 1001 codes BR-CL-01 allows as `<cbc:CreditNoteTypeCode>`.\n *\n * @returns A fresh array — mutating the result cannot poison the vocabulary\n */\nexport function getCreditNoteTypeCodes(): number[] {\n return [...CREDIT_NOTE_TYPE_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, getCreditNoteTypeCodes, getInvoiceTypeCodes } from \"./code-lists.js\";\nimport { parsePeppolId, isWellFormedPeppolId } from \"./peppol-id.js\";\nimport { canCarryPartyIdentification } from \"./iso6523-icd-codes.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\n// GPR-1170 — stable public contract identifiers for the allowance/charge\n// amount contract (getpeppr-local; NOT Peppol rule numbers, NOT ticket ids).\nconst ALLOWANCE_CHARGE_CONTRACT_RULE = \"GETPEPPR-ALLOWANCE-CHARGE-AMOUNT\";\nconst DERIVED_AMOUNT_CONTRACT_RULE = \"GETPEPPR-DERIVED-AMOUNT\";\n\n// A monetary amount is deliverable only if it survives the cents scaling the\n// delivery pipeline actually performs (the provider-side 2-decimal rounding).\nfunction survivesCents(value: number): boolean {\n return Number.isFinite(value) && Number.isFinite(value * 100);\n}\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 (!isWellFormedPeppolId(party.peppolId)) {\n // ⛔ Ni « contient un `:` » ni « deux segments non vides » ne suffisent : le\n // contrôle vit dans `isWellFormedPeppolId`, qui juge le couple réellement\n // produit. Les trois sites qui acceptent un `peppolId` l'appellent — un\n // renforcement posé sur un seul d'entre eux laisse les autres ouverts, et\n // c'est ce qui s'est produit (GPR-1110, relevé par gate).\n errors.push(\n error(\n `${path}.peppolId`,\n `Invalid Peppol ID format: \"${party.peppolId}\"`,\n undefined,\n 'Must be \"scheme:id\" — e.g. \"0208:0685660237\" or \"GB:VAT:123456789\". The scheme alone (\"GB:VAT\") is not an identifier.'\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.baseQuantity !== undefined) {\n if (\n typeof line.baseQuantity !== \"number\" ||\n !Number.isFinite(line.baseQuantity) ||\n line.baseQuantity <= 0\n ) {\n errors.push(\n error(\n `${path}.baseQuantity`,\n \"Base quantity must be a finite number greater than zero\",\n \"PEPPOL-EN16931-R121\",\n \"Use a positive number for the item price base quantity\",\n )\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 // GPR-1170 — the direction of an allowance/charge travels in the field, never\n // in the sign (the Peppol equations BR-CO-11/12/13 and R120 describe how the\n // amounts are summed; the input contract itself is getpeppr-local, rule ids\n // GETPEPPR-ALLOWANCE-CHARGE-AMOUNT / GETPEPPR-DERIVED-AMOUNT). Only\n // `undefined` means absent; a negative or non-finite amount flips the\n // semantic and is rejected instead of being normalized away — the Storecove\n // mapper rejects the same inputs, keeping both surfaces in parity.\n const adjustmentItems: Record<\"allowances\" | \"charges\", Array<{ amount?: unknown } | null>> = {\n allowances: Array.isArray(line.allowances) ? line.allowances : [],\n charges: Array.isArray(line.charges) ? line.charges : [],\n };\n for (const kind of [\"allowances\", \"charges\"] as const) {\n const items = line[kind] as unknown;\n if (items === undefined) continue;\n if (!Array.isArray(items)) {\n errors.push(error(\n `${path}.${kind}`,\n `${kind} must be an array — omit the field instead of sending ${items === null ? \"null\" : typeof items}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n ));\n continue;\n }\n for (const [i, item] of items.entries()) {\n const amount = (item as { amount?: unknown } | null)?.amount;\n if (typeof amount !== \"number\" || !Number.isFinite(amount) || amount < 0) {\n errors.push(\n error(\n `${path}.${kind}[${i}].amount`,\n `Allowance and charge amounts must be zero or positive finite numbers, got ${String(amount)}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n \"An allowance reduces the amount and a charge increases it — encode the direction in the field, never in the sign.\"\n )\n );\n }\n }\n }\n\n // GPR-1170 — individually finite inputs can overflow once summed; BOTH final\n // derivations of the line (net and its VAT share) must stay representable.\n const bq = typeof line.baseQuantity === \"number\" && line.baseQuantity > 0 ? line.baseQuantity : 1;\n const derivedNet =\n (line.quantity ?? 0) * (line.unitPrice ?? 0) / bq -\n adjustmentItems.allowances.reduce((sum, a) => sum + ((a as { amount?: number })?.amount ?? 0), 0) +\n adjustmentItems.charges.reduce((sum, c) => sum + ((c as { amount?: number })?.amount ?? 0), 0);\n const derivedVat = derivedNet * ((typeof line.vatRate === \"number\" ? line.vatRate : 0) / 100);\n if (!survivesCents(derivedNet) || !survivesCents(derivedVat)) {\n errors.push(\n error(\n path,\n \"Derived amount is not finite (overflow). Reduce quantities, prices or adjustment amounts so every total stays representable.\",\n DERIVED_AMOUNT_CONTRACT_RULE,\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 (BR-CL-01) ──\n //\n // GPR-1234 — la règle est CONTEXTUELLE : 50 codes sont légaux en\n // `<cbc:InvoiceTypeCode>`, 13 autres en `<cbc:CreditNoteTypeCode>`.\n // `ubl-builder.ts` écrit l'un ou l'autre élément selon `isCreditNote`, donc\n // le vocabulaire qui décide suit le même discriminateur. L'ancienne liste\n // unique de 7 codes laissait passer 381 sur une facture et refusait 382/326\n // qui y sont légaux.\n if (input.invoiceTypeCode != null) {\n const isCreditNote = input.isCreditNote === true;\n const legalCodes = isCreditNote ? getCreditNoteTypeCodes() : getInvoiceTypeCodes();\n if (!legalCodes.includes(input.invoiceTypeCode)) {\n errors.push(\n error(\n \"invoiceTypeCode\",\n `Invalid ${isCreditNote ? \"credit note\" : \"invoice\"} type code: ${input.invoiceTypeCode}`,\n \"BR-CL-01\",\n `Valid ${isCreditNote ? \"credit note\" : \"invoice\"} type codes: ${legalCodes.join(\", \")}`\n )\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 // GPR-1110 — le corollaire de l'omission décidée dans `ubl-builder.ts`.\n //\n // Un scheme hors liste ISO 6523 ICD (`9932` GB, `9935` IE, `9930` DE…) ne peut\n // pas s'écrire en `PartyIdentification/ID` : `BR-CL-10` y est fatale. Le champ\n // est donc omis, et avec lui BT-29 — il faut alors que BT-30 (`companyId`) ou\n // BT-31 (`vatNumber`) porte l'expéditeur, sans quoi `BR-CO-26` tombe.\n //\n // ⚠️ AVERTISSEMENT et non erreur : `from` est déclaré ignoré trois lignes\n // au-dessus, donc à l'envoi ce champ ne décide de rien. Le seul chemin où ce\n // XML compte est `toXml()` — « manual submission » — et y bloquer un appelant\n // dont l'envoi normal fonctionne serait une régression de contrat.\n //\n // Mesuré le 2026-08-20 (`POST /v1/validate/ubl`) : une facture GB sans TVA\n // rend `BR-S-02` ET `BR-CO-26`, deux fatales. La même avec `vatNumber` rend\n // `conformant: true`.\n // ⚠️ Pas de garde `includes(\":\")` ici : un `peppolId` dépourvu de `:` est\n // malformé, et c'est précisément le cas où l'avertissement est le plus utile.\n // `parsePeppolId` le gère (scheme canonicalisé, valeur vide) plutôt que de\n // lever, donc filtrer en amont ne ferait que rendre la garde muette là où le\n // document est le plus sûrement refusé.\n const fromId = input.from.peppolId;\n // (`!== \"\"` est refusé par TS : le type littéral `${string}:${string}` exclut\n // la chaîne vide, que seul un appelant JavaScript peut fournir.)\n if (typeof fromId === \"string\" && fromId.length > 0) {\n const { scheme } = parsePeppolId(fromId);\n const bt29Written = canCarryPartyIdentification(scheme, \"AccountingSupplierParty\");\n if (!bt29Written && !input.from.vatNumber && !input.from.companyId) {\n warnings.push(\n warning(\n \"from.peppolId\",\n `Scheme \"${scheme}\" cannot carry a seller identifier (BT-29), so that field is omitted. Add a vatNumber (BT-31) or companyId (BT-30), or the network will reject the document under BR-CO-26.`,\n \"BR-CO-26\",\n )\n );\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 // Le TROISIÈME site, et celui qu'un renforcement posé sur `validateParty`\n // laisse ouvert : le bénéficiaire a sa propre validation (GPR-1110).\n } else if (!isWellFormedPeppolId(ppId)) {\n errors.push(\n error(\n \"payeeParty.peppolId\",\n `Invalid Peppol ID format: \"${ppId}\"`,\n undefined,\n 'Must be \"scheme:id\" — e.g. \"0208:0685660237\". The scheme alone (\"GB:VAT\") is not an identifier.'\n )\n );\n }\n }\n\n const linesValue = input.lines as unknown;\n if (!Array.isArray(linesValue)) {\n errors.push(error(\"lines\", \"Line items must be an array\", undefined));\n } else if (linesValue.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 (const [i, line] of linesValue.entries()) {\n if (line === null || typeof line !== \"object\") {\n errors.push(error(`lines[${i}]`, `Line item ${i} must be an object`, undefined));\n continue;\n }\n errors.push(...validateLine(line as InvoiceLine, i, input.isCreditNote));\n }\n }\n\n for (const field of [\"allowances\", \"charges\"] as const) {\n const value = input[field] as unknown;\n if (value === undefined) continue;\n if (!Array.isArray(value)) {\n errors.push(error(\n field,\n `${field} must be an array — omit the field instead of sending ${value === null ? \"null\" : typeof value}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n ));\n continue;\n }\n for (const [index, item] of value.entries()) {\n if (item === null || typeof item !== \"object\") {\n errors.push(error(`${field}[${index}]`, `${field}[${index}] must be an object`, undefined));\n continue;\n }\n // GPR-1170 — document-level adjustments follow the same input contract as\n // line-level ones (getpeppr-local; BR-CO-13 describes how BT-107/BT-108\n // are summed, it does not mandate this contract).\n const amount = (item as { amount?: unknown }).amount;\n if (typeof amount !== \"number\" || !Number.isFinite(amount) || amount < 0) {\n errors.push(\n error(\n `${field}[${index}].amount`,\n `Allowance and charge amounts must be zero or positive finite numbers, got ${String(amount)}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n \"An allowance reduces the amount and a charge increases it — encode the direction in the field, never in the sign.\"\n )\n );\n }\n }\n }\n\n // GPR-1170 — document totals derived from accepted inputs must stay finite\n // before rendering. Only structurally valid collections contribute to the\n // sums: a malformed shape is reported above and must never TypeError here.\n if (Array.isArray(input.lines)) {\n const itemsOf = (value: unknown): Array<{ amount?: unknown; vatRate?: unknown }> =>\n Array.isArray(value) ? value : [];\n const amountOf = (item: unknown): number =>\n typeof (item as { amount?: unknown } | null)?.amount === \"number\"\n ? (item as { amount: number }).amount\n : 0;\n const lineNets = (input.lines as InvoiceLine[]).reduce((sum, line) => {\n if (typeof line !== \"object\" || line === null) return sum;\n const lbq = typeof line.baseQuantity === \"number\" && line.baseQuantity > 0 ? line.baseQuantity : 1;\n return (\n sum +\n ((line.quantity ?? 0) * (line.unitPrice ?? 0)) / lbq -\n itemsOf(line.allowances).reduce((s, a) => s + amountOf(a), 0) +\n itemsOf(line.charges).reduce((s, c) => s + amountOf(c), 0)\n );\n }, 0);\n const allowanceTotal = itemsOf(input.allowances).reduce((s, a) => s + amountOf(a), 0);\n const chargeTotal = itemsOf(input.charges).reduce((s, c) => s + amountOf(c), 0);\n const vatOf = (items: unknown, sign: number): number => {\n if (!Array.isArray(items)) return 0;\n return items.reduce((s, it) => {\n const rec = it as { amount?: unknown; vatRate?: unknown } | null;\n const amount = typeof rec?.amount === \"number\" ? rec.amount : 0;\n const rate = typeof rec?.vatRate === \"number\" ? rec.vatRate : 0;\n return s + sign * amount * (rate / 100);\n }, 0);\n };\n const docVat =\n vatOf(input.allowances, -1) +\n vatOf(input.charges, 1) +\n (input.lines as InvoiceLine[]).reduce((s, line) => {\n if (typeof line !== \"object\" || line === null) return s;\n const lbq = typeof line.baseQuantity === \"number\" && line.baseQuantity > 0 ? line.baseQuantity : 1;\n const net = ((line.quantity ?? 0) * (line.unitPrice ?? 0)) / lbq;\n return s + net * ((typeof line.vatRate === \"number\" ? line.vatRate : 0) / 100);\n }, 0);\n if (\n !survivesCents(lineNets - allowanceTotal + chargeTotal) ||\n !survivesCents(docVat)\n ) {\n errors.push(\n error(\n \"totals\",\n \"Derived amount is not finite (overflow). Reduce quantities, prices or adjustment amounts so every total stays representable.\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n )\n );\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","/**\n * Offline Schematron-like Validation\n *\n * Runs a small set of pure TypeScript pre-flight checks. Some reproduce a\n * Peppol BIS 3.0 business rule; others are explicitly GETPEPPR-local\n * diagnostics. This is NOT a full XSD/XSLT Schematron processor — it catches\n * common problems before the invoice reaches the network.\n *\n * ⛔ The registered checks counted by `coverage.rulesChecked` are exactly\n * those in `SDK_SCHEMATRON_RULE_IDS` (below), and that registry is the only\n * place the count lives. `validateSchematron()` can additionally emit the\n * legacy provider-routability diagnostic `unsupported_vat_category`, outside\n * that count. The separate VAT-only UBL-builder preflight can emit `SDK-INPUT`;\n * it does not return Schematron coverage. This header once said \"~25\" while the registry held a different\n * number — prose counts drift from one the code measures, and only the code can\n * 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 * - GETPEPPR-xx — SDK-local diagnostics with no exact network-rule equivalent\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 /** Network-rule or product-local diagnostic identifier. */\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 * Le nombre exact de contrôles enregistrés vit dans `SDK_SCHEMATRON_RULE_IDS`.\n * Le diagnostic de capacité historique `unsupported_vat_category` peut\n * apparaître en plus, hors de ce compteur.\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 from the SDK's small common-unit catalogue (lazy singleton). */\nlet _sdkUnitCodes: Set<string> | undefined;\nfunction getSdkUnitCodes(): Set<string> {\n if (!_sdkUnitCodes) {\n _sdkUnitCodes = new Set(getAllUnits().map((u) => u.code));\n }\n return _sdkUnitCodes;\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; // Caught by GETPEPPR-LINE-NET-SANITY.\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 * SDK-local notice: the issue date will default to today when omitted.\n */\nconst issueDateDefaulted: RuleFn = (input) => {\n if (!input.date) {\n return [\n violation(\n \"GETPEPPR-ISSUE-DATE-DEFAULTED\",\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 * SDK-local recommendation: a deprecated `from` payload should carry a VAT number.\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 sellerVatRecommendation: RuleFn = (input) => {\n if (input.from && !input.from.vatNumber) {\n return [\n violation(\n \"GETPEPPR-FROM-VAT-RECOMMENDED\",\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-16: An Invoice shall have at least one Invoice line.\n */\nconst br16: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) {\n return [violation(\"BR-16\", \"error\", \"Invoice must have at least one line item.\", \"lines\")];\n }\n return [];\n};\n\n/**\n * SDK-local recommendation: provide a Payment due date or Payment terms.\n */\nconst paymentTimingRecommendation: RuleFn = (input) => {\n if (!input.dueDate && !input.paymentTerms) {\n return [\n violation(\n \"GETPEPPR-PAYMENT-TIMING-RECOMMENDED\",\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 * SDK-local recommendation: provide a Buyer reference or Order reference.\n * The official R003 has the same predicate but is fatal; this SDK check remains\n * advisory, so borrowing that identifier would overstate the verdict.\n */\nconst buyerOrOrderReferenceRecommendation: RuleFn = (input) => {\n if (!input.buyerReference && !input.orderReference) {\n return [\n violation(\n \"GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED\",\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 * SDK-local line-net sanity check. InvoiceInput has no explicit line-extension\n * total to compare as official BR-CO-10 does, so this only verifies that each\n * line computation is finite (no NaN/Infinity; valid baseQuantity).\n */\nconst lineNetSanity: 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(\"GETPEPPR-LINE-NET-SANITY\", \"error\", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * SDK-local sanity check for the computed VAT amount.\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 computedVatSanity: 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 GETPEPPR-LINE-NET-SANITY.\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 \"GETPEPPR-COMPUTED-VAT-SANITY\",\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 \"GETPEPPR-COMPUTED-VAT-SANITY\",\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 * SDK-local sanity check for the computed tax-inclusive amount.\n *\n * We verify the computation produces a finite, non-negative result.\n */\nconst taxInclusiveSanity: 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 \"GETPEPPR-TAX-INCLUSIVE-SANITY\",\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 \"GETPEPPR-TAX-INCLUSIVE-SANITY\",\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 * SDK-local sanity check for the computed payable amount.\n *\n * Verifies that the derived payable amount is finite and non-negative.\n */\nconst payableSanity: 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 \"GETPEPPR-PAYABLE-SANITY\",\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 \"GETPEPPR-PAYABLE-SANITY\",\n \"warning\",\n `Computed payable amount is negative (${payable.toFixed(2)}). ` +\n `Check invoice totals, prepaid amount (${prepaid}), and rounding amount (${rounding}).`,\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/** BR-G-05: Export outside the EU (G) line VAT rate shall be zero. */\nconst brG05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n for (let i = 0; i < (input.lines ?? []).length; i++) {\n const line = input.lines![i]!;\n if (line.vatCategory === \"G\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-G-05\",\n \"error\",\n `Line ${i}: export outside the EU (G) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n return violations;\n};\n\n/** BR-IC-05: Intra-community supply (K) line VAT rate shall be zero. */\nconst brIc05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n for (let i = 0; i < (input.lines ?? []).length; i++) {\n const line = input.lines![i]!;\n if (line.vatCategory === \"K\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-IC-05\",\n \"error\",\n `Line ${i}: intra-community supply (K) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n return violations;\n};\n\n/** BR-*-06/07: document allowances and charges use the category's legal rate. */\nconst documentAdjustmentVatRates: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n const configs = new Map<string, {\n allowanceRule: string;\n chargeRule: string;\n valid: (rate: number) => boolean;\n label: string;\n }>([\n [\"S\", { allowanceRule: \"BR-S-06\", chargeRule: \"BR-S-07\", valid: (rate) => rate > 0, label: \"standard rate (S)\" }],\n [\"Z\", { allowanceRule: \"BR-Z-06\", chargeRule: \"BR-Z-07\", valid: (rate) => rate === 0, label: \"zero-rated (Z)\" }],\n [\"E\", { allowanceRule: \"BR-E-06\", chargeRule: \"BR-E-07\", valid: (rate) => rate === 0, label: \"exempt (E)\" }],\n [\"AE\", { allowanceRule: \"BR-AE-06\", chargeRule: \"BR-AE-07\", valid: (rate) => rate === 0, label: \"reverse charge (AE)\" }],\n [\"G\", { allowanceRule: \"BR-G-06\", chargeRule: \"BR-G-07\", valid: (rate) => rate === 0, label: \"export outside the EU (G)\" }],\n [\"K\", { allowanceRule: \"BR-IC-06\", chargeRule: \"BR-IC-07\", valid: (rate) => rate === 0, label: \"intra-community supply (K)\" }],\n ]);\n\n const check = (\n items: InvoiceInput[\"allowances\"] | InvoiceInput[\"charges\"],\n kind: \"allowance\" | \"charge\",\n ): void => {\n (items ?? []).forEach((item, index) => {\n const category = item.vatCategory ?? \"S\";\n const config = configs.get(category);\n if (!config || config.valid(item.vatRate)) return;\n const ruleId = kind === \"allowance\" ? config.allowanceRule : config.chargeRule;\n violations.push(violation(\n ruleId,\n \"error\",\n `Document ${kind} ${index}: ${config.label} has an invalid vatRate (${item.vatRate}).`,\n `${kind === \"allowance\" ? \"allowances\" : \"charges\"}[${index}].vatRate`,\n ));\n });\n };\n\n check(input.allowances, \"allowance\");\n check(input.charges, \"charge\");\n return violations;\n};\n\ntype ExemptionCategory = \"E\" | \"AE\" | \"G\" | \"O\" | \"K\";\n\n/**\n * BR-*-10 applies to each VAT breakdown, not to every source line. Mirror the\n * builder's grouping so a line, allowance, and charge in one group yield one\n * actionable violation rather than three duplicates.\n */\nfunction exemptionReasonRule(\n vatCategory: ExemptionCategory,\n ruleId: \"BR-E-10\" | \"BR-AE-10\" | \"BR-G-10\" | \"BR-O-10\" | \"BR-IC-10\",\n label: string,\n): RuleFn {\n return (input) => {\n const groups = new Map<string, { hasReason: boolean; field: string }>();\n\n const add = (category: string | undefined, rate: number, reason: string | undefined, field: string): void => {\n if (category !== vatCategory) return;\n const effectiveRate = category === \"O\" ? 0 : rate;\n const key = `${category}-${effectiveRate}`;\n const hasReason = typeof reason === \"string\" && reason.trim().length > 0;\n const existing = groups.get(key);\n if (existing) {\n existing.hasReason ||= hasReason;\n } else {\n groups.set(key, { hasReason, field });\n }\n };\n\n (input.lines ?? []).forEach((line, index) => {\n add(line.vatCategory ?? \"S\", line.vatRate, line.taxExemptReason, `lines[${index}].taxExemptReason`);\n });\n (input.allowances ?? []).forEach((item, index) => {\n add(item.vatCategory ?? \"S\", item.vatRate, item.taxExemptReason, `allowances[${index}].taxExemptReason`);\n });\n (input.charges ?? []).forEach((item, index) => {\n add(item.vatCategory ?? \"S\", item.vatRate, item.taxExemptReason, `charges[${index}].taxExemptReason`);\n });\n\n return [...groups.values()]\n .filter((group) => !group.hasReason)\n .map((group) => violation(\n ruleId,\n \"error\",\n `${label} requires a non-empty taxExemptReason in its VAT breakdown.`,\n group.field,\n ));\n };\n}\n\nconst brE10 = exemptionReasonRule(\"E\", \"BR-E-10\", \"Exempt from VAT (E)\");\nconst brAe10 = exemptionReasonRule(\"AE\", \"BR-AE-10\", \"Reverse charge (AE)\");\nconst brG10 = exemptionReasonRule(\"G\", \"BR-G-10\", \"Export outside the EU (G)\");\nconst brO10 = exemptionReasonRule(\"O\", \"BR-O-10\", \"Not subject to VAT (O)\");\nconst brIc10 = exemptionReasonRule(\"K\", \"BR-IC-10\", \"Intra-community supply (K)\");\n\n/** BR-CL-17 only — no gateway/provider routability policy. */\nconst builderVatCategoryValidity: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n const check = (category: string | undefined, field: string): void => {\n if (category !== undefined && !VALID_VAT_CATEGORIES.has(category)) {\n violations.push(violation(\n \"BR-CL-17\",\n \"error\",\n \"VAT category is not an EN 16931 code.\",\n field,\n ));\n }\n };\n (input.lines ?? []).forEach((item, index) => check(item.vatCategory, `lines[${index}].vatCategory`));\n (input.allowances ?? []).forEach((item, index) => check(item.vatCategory, `allowances[${index}].vatCategory`));\n (input.charges ?? []).forEach((item, index) => check(item.vatCategory, `charges[${index}].vatCategory`));\n return violations;\n};\n\nconst UBL_BUILDER_VAT_RULES: readonly RuleFn[] = [\n builderVatCategoryValidity,\n brS05,\n brZ05,\n brE05,\n brAe05,\n brG05,\n brIc05,\n documentAdjustmentVatRates,\n brE10,\n brAe10,\n brG10,\n brO10,\n brIc10,\n];\n\n/**\n * The VAT-only preflight used by `Peppol.toXml()`.\n * It intentionally excludes provider-routability checks: local UBL generation\n * may validly use categories such as L/M that the getpeppr gateway cannot send.\n */\nexport function validateUblBuilderVat(input: InvoiceInput): SchematronViolation[] {\n const shapeViolations: SchematronViolation[] = [];\n const checkCollection = (value: unknown, field: \"lines\" | \"allowances\" | \"charges\"): void => {\n if (field === \"lines\" || value !== undefined) {\n if (!Array.isArray(value)) {\n shapeViolations.push(violation(\n \"SDK-INPUT\",\n \"error\",\n `${field} must be an array.`,\n field,\n ));\n return;\n }\n }\n if (!Array.isArray(value)) return;\n for (const [index, item] of value.entries()) {\n const itemField = `${field}[${index}]`;\n if (item === null || typeof item !== \"object\") {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField} must be an object.`, itemField));\n continue;\n }\n const candidate = item as { vatRate?: unknown; vatCategory?: unknown; taxExemptReason?: unknown };\n if (typeof candidate.vatRate !== \"number\" || !Number.isFinite(candidate.vatRate)) {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField}.vatRate must be a finite number.`, `${itemField}.vatRate`));\n }\n if (candidate.vatCategory !== undefined && typeof candidate.vatCategory !== \"string\") {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField}.vatCategory must be a string.`, `${itemField}.vatCategory`));\n }\n if (candidate.taxExemptReason !== undefined && typeof candidate.taxExemptReason !== \"string\") {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField}.taxExemptReason must be a string.`, `${itemField}.taxExemptReason`));\n }\n }\n };\n checkCollection(input.lines, \"lines\");\n checkCollection(input.allowances, \"allowances\");\n checkCollection(input.charges, \"charges\");\n if (shapeViolations.length > 0) return shapeViolations;\n\n const oRateViolations: SchematronViolation[] = [];\n const checkORates = (\n items: readonly { vatCategory?: string; vatRate: number }[] | undefined,\n field: \"lines\" | \"allowances\" | \"charges\",\n ): void => {\n (items ?? []).forEach((item, index) => {\n if (item.vatCategory === \"O\" && item.vatRate !== 0) {\n oRateViolations.push(violation(\n \"SDK-INPUT\",\n \"error\",\n `Category O must use vatRate 0 in SDK input.`,\n `${field}[${index}].vatRate`,\n ));\n }\n });\n };\n checkORates(input.lines, \"lines\");\n checkORates(input.allowances, \"allowances\");\n checkORates(input.charges, \"charges\");\n\n return [\n ...oRateViolations,\n ...UBL_BUILDER_VAT_RULES.flatMap((rule) => rule(input)),\n ];\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 * SDK-local requirement: a Buyer Peppol ID must be present and non-empty.\n * R010 only checks node existence; the SDK's predicate is deliberately broader.\n */\nconst buyerPeppolIdRequired: RuleFn = (input) => {\n if (!input.to?.peppolId) {\n return [\n violation(\n \"GETPEPPR-BUYER-PEPPOL-ID-REQUIRED\",\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 * SDK-local unit-code diagnostic. The SDK convenience list is intentionally\n * smaller than the official Rec20/21 list, so this warning cannot claim BR-CL-23.\n */\nconst unitCodeRecognised: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n const knownCodes = getSdkUnitCodes();\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 \"GETPEPPR-UNIT-CODE-RECOGNISED\",\n \"warning\",\n `Line ${i}: unit \"${line.unit}\" (resolved: \"${resolved}\") is not in the SDK's common unit list. ` +\n `It may still be a valid UN/ECE Rec20/21 code; network validation decides. 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 issueDateDefaulted,\n sellerVatRecommendation,\n br07,\n br16,\n paymentTimingRecommendation,\n buyerOrOrderReferenceRecommendation,\n // Calculations (BR-CO)\n lineNetSanity,\n computedVatSanity,\n taxInclusiveSanity,\n payableSanity,\n // Tax categories (one family per category)\n brS05,\n brZ05,\n brE05,\n brAe05,\n brG05,\n brIc05,\n documentAdjustmentVatRates,\n brE10,\n brAe10,\n brG10,\n brO10,\n brIc10,\n // Peppol-specific\n buyerPeppolIdRequired,\n vatCategoryCodes,\n unitCodeRecognised,\n];\n\n// ─── Main Validation Function ───────────────────────────────────────────────────\n\n/**\n * Validate an InvoiceInput with offline Peppol pre-flight checks.\n *\n * Runs the controls listed in `SDK_SCHEMATRON_RULE_IDS` as pure TypeScript\n * checks. Official IDs identify exact network-rule equivalents; `GETPEPPR-*`\n * IDs identify local diagnostics. No XML generation, no network calls. The\n * count is read from the registry, never written here;\n * `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/GPR-1084 — les contrôles enregistrés que ce validateur exécute.\n *\n * ⚠️ 37 contrôles enregistrés, dont 10 diagnostics explicitement locaux,\n * face aux 333+ règles que le réseau applique. Le diagnostic historique de\n * capacité `unsupported_vat_category` peut être émis en plus par\n * `validateSchematron`, sans être compté dans `coverage.rulesChecked`.\n * `SDK-INPUT` appartient au pré-contrôle distinct du builder UBL et n'entre\n * pas dans un `SchematronResult`.\n * 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 23 règles de catégorie de TVA ont été confrontées au rulebook gravé :\n * quatre ont d'abord été corrigées par GPR-1069, puis GPR-1068 a ajouté les\n * familles ligne/adjustment/motif manquantes. GPR-1084 a ensuite confronté ses\n * sept contrôles ciblés et quatre collisions adjacentes trouvées par la même\n * preuve : seul `BR-08` était une correspondance exacte, vers `BR-16`; les dix\n * autres portent désormais un ID `GETPEPPR-*` qui annonce leur portée locale.\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\", \"GETPEPPR-ISSUE-DATE-DEFAULTED\", \"GETPEPPR-FROM-VAT-RECOMMENDED\", \"BR-07\", \"BR-16\",\n \"GETPEPPR-PAYMENT-TIMING-RECOMMENDED\", \"GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED\",\n \"BR-CL-17\", \"GETPEPPR-LINE-NET-SANITY\", \"GETPEPPR-COMPUTED-VAT-SANITY\",\n \"GETPEPPR-TAX-INCLUSIVE-SANITY\", \"GETPEPPR-PAYABLE-SANITY\",\n \"BR-S-05\", \"BR-Z-05\", \"BR-E-05\", \"BR-AE-05\", \"BR-G-05\", \"BR-IC-05\",\n \"BR-S-06\", \"BR-S-07\", \"BR-Z-06\", \"BR-Z-07\", \"BR-E-06\", \"BR-E-07\",\n \"BR-AE-06\", \"BR-AE-07\", \"BR-G-06\", \"BR-G-07\", \"BR-IC-06\", \"BR-IC-07\",\n \"BR-E-10\", \"BR-AE-10\", \"BR-G-10\", \"BR-O-10\", \"BR-IC-10\",\n \"GETPEPPR-BUYER-PEPPOL-ID-REQUIRED\", \"GETPEPPR-UNIT-CODE-RECOGNISED\",\n] as const;\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 = \"5.2.0\";\n","/**\n * GPR-1178 — reading the getpeppr result contract off the response headers.\n *\n * The gateway publishes five additive headers on every public `/v1` response\n * IT WRITES (GPR-1174), plus a sixth — `Getpeppr-Result-Docs` — only when the\n * result has a guide to link to. They ride alongside every body shape the API\n * already returns — `{data,meta}`, bare objects, bare arrays, bodyless `204`s,\n * PDFs, redirects — which is why the contract lives in headers and not in a\n * JSON envelope.\n *\n * ⚠️ \"Plus a sixth\" is not a footnote: only a MINORITY of results carry a guide,\n * so the docs header is absent from most responses. Read its absence as normal —\n * a client treating it as guaranteed would read the ordinary case as a fault.\n *\n * ⛔ NO COUNT HERE, deliberately. An earlier draft of this very sentence said\n * \"73 of 229\", which was measured and correct on the day — and is a fact about\n * a catalogue that grows every tranche, written where nothing can update it.\n * That is the defect this ticket exists to close, reintroduced in the fix for\n * it. The public reference page DERIVES its count and cannot go stale; the\n * always-on five and the conditional sixth are partitioned mechanically in the\n * console's `lib/api/results/headers.ts`, against the builder that emits them,\n * with a test that fails if the conditional one stops being a minority.\n *\n * ⚠️ \"It writes\" is load-bearing, and this sentence said \"every public /v1\n * response\" until GPR-1181's relance. Some requests never reach the gateway:\n * the hosting platform answers them at its own border, with none of the six —\n * a verb outside the seven Next dispatches gets `405 text/plain` straight from\n * the edge. That is precisely why every field below is optional and why\n * `parseApiResultHeaders` returns `undefined` rather than an empty object: a\n * caller must be able to tell \"getpeppr said nothing\" from \"getpeppr said\n * nothing useful\". Measured inventory: the console's\n * `lib/api/results/platform-terminations.ts`.\n *\n * ## What this module refuses to do\n *\n * **Fabricate.** Every field is optional, and an unreadable value yields an\n * ABSENT field rather than a plausible one. A caller reads absence as \"the\n * gateway did not say\"; a fabricated value is indistinguishable from a measured\n * one and no downstream check can catch it.\n *\n * **Truncate.** An over-long value is dropped whole. A truncated sentence reads\n * exactly like a complete one — the same failure, wearing the shape of success.\n *\n * **Close the enums.** `remediation` and `code` are typed open on purpose: a\n * value this SDK build has never heard of is passed through verbatim. Refusing\n * it would blank the field and turn \"new\" into \"absent\" for a client running an\n * older SDK against a newer gateway — and that skew is the normal state, not\n * the exception.\n */\n\n/**\n * The six header names, exactly as `packages/console/src/lib/api/results/headers.ts`\n * emits them. Lookup is case-insensitive (`Headers.get` handles that), so this\n * spelling is documentation and a test anchor, not a matching requirement.\n */\nexport const API_RESULT_HEADER_NAMES = {\n requestId: \"Getpeppr-Request-Id\",\n resultCode: \"Getpeppr-Result-Code\",\n resultMessage: \"Getpeppr-Result-Message\",\n retryable: \"Getpeppr-Retryable\",\n remediation: \"Getpeppr-Remediation\",\n docs: \"Getpeppr-Result-Docs\",\n} as const;\n\n/**\n * What the caller should DO about this result.\n *\n * The catalogue's enum is closed today; this type is deliberately open so a\n * value added server-side reaches you rather than vanishing. The listed members\n * are the ones the catalogue defines today; do not assume the set is closed.\n */\nexport type ApiResultRemediation =\n | \"none\"\n | \"fix_request\"\n | \"authenticate\"\n | \"retry\"\n | \"retry_after\"\n | \"wait\"\n | \"contact_support\"\n | (string & {});\n\n/**\n * A stable getpeppr result code, spelled `domain.outcome`\n * (e.g. `\"invoices_import.validation_failed\"`, `\"auth.api_key_invalid\"`).\n *\n * Typed `string` rather than a generated union: pinning the union in a\n * published package would make every gateway-side addition a breaking change\n * for anyone who has not upgraded.\n */\nexport type ApiResultCode = string;\n\n/**\n * The canonical result of one HTTP response, as the gateway declared it.\n *\n * Every field is optional and independently so. A gateway that has not yet\n * activated the catalogue emits none of them, and a proxy may strip some — so\n * never infer one field's meaning from another's presence.\n */\nexport interface ApiResult {\n /**\n * Server-generated correlation id (`req_` + 32 hex today). Quote it to\n * support and they can find this exact request.\n *\n * `undefined` when the gateway sent no request-id header — pre-activation\n * deployments, and any hop that strips unknown headers.\n */\n requestId?: string;\n /**\n * Stable machine-readable code for this outcome.\n *\n * ⚠️ NOT the same field as `PeppolApiError.code`, which reads `body.code` and\n * carries a route-specific sub-reason. Both can be present and different.\n *\n * `undefined` when the header is absent or unreadable.\n */\n code?: ApiResultCode;\n /** Catalogue sentence for `code`. `undefined` when absent, blank or over-long. */\n message?: string;\n /**\n * Whether retrying this same request can succeed, as decided by the CODE and\n * not by the status alone.\n *\n * `undefined` when the header is absent or is anything other than `true` /\n * `false` — an unreadable value must never become a retry permission.\n */\n retryable?: boolean;\n /** Recommended action. `undefined` when the header is absent or blank. */\n remediation?: ApiResultRemediation;\n /**\n * Documentation link for this code, normalised through the URL parser.\n *\n * `undefined` when absent, relative, carrying any scheme other than\n * `https:`, carrying credentials in the authority, or malformed enough that\n * the URL parser would have to repair it — `javascript:` parses perfectly\n * well, so parsing is not validation.\n */\n docs?: string;\n}\n\n/**\n * C0 controls, DEL, and C1 (U+0080–U+009F).\n *\n * `Headers` already refuses CR, LF and NUL, so response splitting is closed\n * before this module runs. DEL and C1 travel RAW, and a terminal ACTS on them:\n * U+009B is a single-character CSI, equivalent to `ESC [`. These values reach\n * `Error.message`, which the CLI writes straight to stderr (CWE-117/150).\n *\n * @internal\n */\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001F\\u007F-\\u009F]/g;\n\n/**\n * Replace every control character with a space.\n *\n * @internal — exported for `client.ts`, which sanitises error bodies with the\n * same rule. One definition, deliberately: two copies of a security invariant\n * are two things free to drift apart.\n */\nexport function stripControls(value: string): string {\n return value.replace(CONTROL_CHARACTERS, \" \");\n}\n\n/**\n * Accept a value only if it is an absolute http(s) URL, and return the PARSED\n * form.\n *\n * Two reasons, both measured. `new URL` normalises control characters out of\n * the href — most percent-encoded (`ESC` becomes `%1B`), while TAB, LF and CR\n * are STRIPPED per the WHATWG parser — so the link cannot smuggle an escape\n * sequence either way. And it happily accepts `javascript:`, so the protocol\n * has to be checked separately.\n *\n * Returning `parsed.href` rather than the input is the GPR-1174 lesson:\n * validating one string and emitting another is how a check gets bypassed.\n *\n * @internal\n */\nexport function 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 * Generous byte ceilings, measured the way an origin serialises — the catalogue\n * caps these at 96 / 256 / 512 and bounds the whole block at 1024 bytes.\n *\n * These are 4-8x the real budget on purpose. They are not a second copy of the\n * server's contract (which would go stale); they are an absurdity guard, so a\n * proxy that injects a novel cannot push it into a terminal or a log line.\n *\n * ⛔ `retryable` is bounded TOO, and that is not symmetry for its own sake.\n * `\"true\"` is 4 bytes, so the field looks like it needs no ceiling — but\n * `String.prototype.trim()` strips Unicode whitespace, NBSP included, so 8 KB of\n * U+00A0 followed by `true` parses to `true` (gate finding). Every value off\n * the wire is bounded before it is interpreted; none is exempt.\n */\nconst MAX_BYTES = {\n requestId: 256,\n code: 256,\n message: 1024,\n remediation: 64,\n docs: 2048,\n // ⚠️ A COST bound, not a correctness one — and the distinction is measured.\n // When this field was still trimmed, a huge padded value could normalise into\n // `true`, so the ceiling changed the verdict. Now that the token is compared\n // verbatim, no string can be both over-long and equal to \"true\"/\"false\": a\n // mutation removing this ceiling SURVIVES the suite, and correctly so. It\n // stays to bound the whitespace/control scan on an absurd value, and it is\n // the one entry here with no test — deliberately, since any assertion would\n // be satisfied by both answers.\n retryable: 32,\n} as const;\n\n/**\n * A well-formed absolute https URL, matched on the RAW value.\n *\n * Deliberately narrower than what `new URL` accepts: no userinfo, no backslash,\n * no empty or repeated authority separator, no whitespace. Every documentation\n * link the catalogue publishes satisfies it — verified against all 72 of them.\n */\nconst STRICT_HTTPS_URL = /^https:\\/\\/[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?(?::\\d{1,5})?(?:\\/[^\\s\\\\]*)?$/i;\n\nconst TEXT_ENCODER = new TextEncoder();\n\n/** Bounded, or `undefined`. Applied before anything interprets the value. */\nfunction withinBudget(raw: string | null, maxBytes: number): string | undefined {\n if (raw === null) return undefined;\n return TEXT_ENCODER.encode(raw).length > maxBytes ? undefined : raw;\n}\n\n/**\n * A HUMAN sentence: sanitise it so it is safe to print, then require that\n * something survives.\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(raw: string | null, maxBytes: number): string | undefined {\n const bounded = withinBudget(raw, maxBytes);\n if (bounded === undefined) return undefined;\n const cleaned = stripControls(bounded).trim();\n return cleaned === \"\" ? undefined : cleaned;\n}\n\n/**\n * A MACHINE token: REJECT anything carrying a control character. Never repair it.\n *\n * ⛔⭐ The distinction from `readSentence` is the whole point, and getting it\n * wrong was a gate finding. Sanitising replaces the offending byte with a space\n * and trims — so `\"retry_after\" + U+007F` cleans to exactly `\"retry_after\"`, and\n * a value the gateway never sent becomes a valid enum member the SDK then acts\n * on. For a sentence, repairing is right: the reader wants something printable.\n * For a token something COMPARES against, repairing manufactures a fact.\n *\n * A human sentence is displayed; a machine token is obeyed. Only one of those\n * may be guessed at.\n */\nfunction readMachineToken(raw: string | null, maxBytes: number): string | undefined {\n const bounded = withinBudget(raw, maxBytes);\n if (bounded === undefined) return undefined;\n if (bounded === \"\") return undefined;\n // ⚠️ `.test()` on a /g regex is stateful — build a fresh matcher each call.\n if (new RegExp(CONTROL_CHARACTERS.source).test(bounded)) return undefined;\n // ⛔⭐ NO trim, and no other normalisation. This is the second half of the\n // same lesson, and the first fix missed it (gate, pass 2).\n //\n // `Headers.get` ALREADY strips leading and trailing ASCII whitespace —\n // measured: `new Headers({x: \" true \"}).get(\"x\")` returns `\"true\"`. So a\n // `.trim()` here can only ever strip what the transport left in place, which\n // is Unicode whitespace: `String.prototype.trim` treats NBSP as space, so\n // `NBSP + \"true\"` was normalised to `\"true\"` and honoured as a retry\n // permission — exactly the value-manufacturing this function exists to stop,\n // through a door I opened while closing the other one.\n //\n // No legitimate machine token carries whitespace: not a `domain.outcome`\n // code, not a remediation enum member, not a `req_` id, not a URL. Refusing\n // the whole class is both simpler and stricter than trying to normalise it.\n if (/\\s/u.test(bounded)) return undefined;\n return bounded;\n}\n\n/**\n * `true` / `false` and nothing else.\n *\n * ⛔ The tempting shorthand is `raw !== \"false\"`. It reads as equivalent and is\n * not: it turns `\"maybe\"`, `\"1\"` and `\"\"` — anything a proxy or a partial\n * deployment might put there — into a retry permission the gateway never\n * granted. Unreadable must mean \"the gateway did not say\", so the caller falls\n * back to the status policy instead of inheriting a fabricated yes.\n */\nfunction readBoolean(raw: string | null): boolean | undefined {\n const token = readMachineToken(raw, MAX_BYTES.retryable);\n if (token === undefined) return undefined;\n // ⛔⭐ Compared VERBATIM — no `toLowerCase()`, which is the third door of the\n // same class (gate, pass 3). The first was repairing control characters, the\n // second was `trim()` swallowing NBSP, and this was the same tolerance\n // wearing a third face: `Getpeppr-Retryable: TRUE` became a retry permission\n // on a 400, measured at 2 requests instead of 1.\n //\n // The writer emits exactly two literals, both lowercase\n // (`packages/console/src/lib/api/results/headers.ts`:\n // `definition.retryable ? \"true\" : \"false\"`), and HTTP never rewrites the\n // CASE of a header value — only the name. So there is no legitimate `TRUE` to\n // accommodate, and accepting one can only ever mean obeying something the\n // gateway did not say.\n if (token === \"true\") return true;\n if (token === \"false\") return false;\n return undefined;\n}\n\n/**\n * The `docs` link, held to the CONTRACT the catalogue declares — which is\n * `https://${string}`, not \"any URL\".\n *\n * Three refusals beyond `safeDocsUrl`, all from the same gate pass:\n * - **`http:`** — the server type forbids it; accepting it here would let a hop\n * downgrade a link we print to a developer.\n * - **credentials in the authority** — `https://getpeppr.dev@evil.test` reads as\n * getpeppr.dev to a human and resolves to evil.test. This is the GPR-1174\n * `apiRedirect` lesson, one layer down.\n * - **a control character anywhere in the raw value** — checked BEFORE parsing,\n * because `new URL` silently strips TAB/LF/CR out of the href and would hand\n * back a clean-looking link built from a value we should have refused.\n */\nfunction readDocsUrl(raw: string | null): string | undefined {\n const token = readMachineToken(raw, MAX_BYTES.docs);\n if (token === undefined) return undefined;\n\n // ⛔⭐ The WHOLE SHAPE is validated before parsing — not the prefix, and not a\n // growing list of special cases.\n //\n // `new URL` REPAIRS a malformed authority rather than rejecting it, so any\n // check made AFTER parsing arrives too late. Measured, every one of these\n // becomes a clean `https://<host>/path` that a `url.protocol` check waves\n // through:\n //\n // https:evil.test/path https:///getpeppr.dev/x\n // https:/evil.test/path https:////getpeppr.dev/x\n // https:\\\\evil.test/path https://\\getpeppr.dev/x\n // https://@getpeppr.dev/x\n //\n // A prefix test caught the first column and not the second — which is why\n // this is now a full-shape match: scheme, a host of ordinary hostname\n // characters, an optional port, then an optional path. Nothing the parser\n // would need to repair can satisfy it. Same lesson as GPR-1174, third\n // telling: validate the string you are going to USE.\n if (!STRICT_HTTPS_URL.test(token)) return undefined;\n\n const parsed = safeDocsUrl(token);\n if (parsed === null) return undefined;\n const url = new URL(parsed);\n if (url.protocol !== \"https:\") return undefined;\n // `https://getpeppr.dev@evil.test` reads as getpeppr.dev to a human and\n // resolves to evil.test.\n if (url.username !== \"\" || url.password !== \"\") return undefined;\n\n // ⚠️ DELIBERATELY not an allowlist of hosts. `https://getpeppr.dev.evil.test`\n // does get through, and that is an accepted limit rather than an oversight:\n // pinning our documentation domain inside a published SDK would silently\n // blank every docs link the day that domain changes, and this value is a link\n // shown to a developer — never fetched, never executed. The gate raised it;\n // this comment is the decision, so the next reader does not re-litigate it.\n return url.href;\n}\n\n/**\n * Read the getpeppr result contract from a response's headers.\n *\n * Returns `undefined` when NOTHING usable is present — an un-activated gateway,\n * a stripping proxy, or a block whose every value was unreadable. That is a\n * distinct answer from \"a result with all fields absent\", and callers rely on\n * it: `ResponseLogEntry.result` and `PeppolApiError.result` stay `undefined`\n * rather than carrying an empty shell that looks like a contract.\n */\nexport function parseApiResultHeaders(headers: Headers): ApiResult | undefined {\n const requestId = readMachineToken(headers.get(API_RESULT_HEADER_NAMES.requestId), MAX_BYTES.requestId);\n const code = readMachineToken(headers.get(API_RESULT_HEADER_NAMES.resultCode), MAX_BYTES.code);\n const message = readSentence(headers.get(API_RESULT_HEADER_NAMES.resultMessage), MAX_BYTES.message);\n const retryable = readBoolean(headers.get(API_RESULT_HEADER_NAMES.retryable));\n const remediation = readMachineToken(headers.get(API_RESULT_HEADER_NAMES.remediation), MAX_BYTES.remediation);\n const docs = readDocsUrl(headers.get(API_RESULT_HEADER_NAMES.docs));\n\n const result: ApiResult = {};\n if (requestId !== undefined) result.requestId = requestId;\n if (code !== undefined) result.code = code;\n if (message !== undefined) result.message = message;\n if (retryable !== undefined) result.retryable = retryable;\n if (remediation !== undefined) result.remediation = remediation;\n if (docs !== undefined) result.docs = docs;\n\n return Object.keys(result).length === 0 ? undefined : result;\n}\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 IdempotentRequestOptions,\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 LegalEntityRegistrationFailureReason,\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, UblBuilderInputError } from \"./ubl-builder.js\";\nimport { parsePeppolId } from \"./peppol-id.js\";\nimport { validateInvoice } from \"./validator.js\";\nimport { validateUblBuilderVat } from \"./schematron.js\";\nimport { statusFamily, TERMINAL_FAILURE_STATUSES } from \"./status-precedence.js\";\nimport { SDK_VERSION } from \"../version.js\";\nimport { parseApiResultHeaders, stripControls, safeDocsUrl } from \"./api-result.js\";\nimport type { ApiResult, ApiResultCode, ApiResultRemediation } from \"./api-result.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 /** @deprecated The current Storecove gateway rejects drafts with 422. */\n createInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult>;\n /** @deprecated The current Storecove gateway rejects draft sending with 501. */\n sendInvoiceById(id: string, options?: IdempotentRequestOptions): 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 /** @deprecated The current Storecove gateway rejects acknowledgement with 501. */\n acknowledgeInvoice(id: string, options?: IdempotentRequestOptions): 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, options?: IdempotentRequestOptions): 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, options?: IdempotentRequestOptions): 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 /** @deprecated The current Storecove gateway rejects invoice updates with 501. */\n updateInvoice(id: string, input: InvoiceUpdateInput): Promise<SendResult>;\n /** @deprecated The current Storecove gateway rejects invoice deletion with 501. */\n deleteInvoice(id: string): Promise<SendResult>;\n /** Report a French CTC invoice as paid; other state transitions return 501. */\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\n/**\n * The four bytes the transport strips from the edges of a header value before\n * it goes on the wire: HTAB `%x09`, LF `%x0A`, CR `%x0D`, SP `%x20`.\n *\n * ⛔ The source is the WHATWG Fetch \"normalize a potential value\" algorithm,\n * NOT RFC 9110 §5.6.3 — which this comment cited until a gate checked it\n * (GPR-1188). RFC 9110 §5.6.3 reads `OWS = *( SP / HTAB )`, verbatim: no CR, no\n * LF. The behaviour described below is right; the citation was not.\n *\n * ⚠️ NOT `String.prototype.trim()`, which also eats NBSP and every other Unicode\n * space. The wire keeps those, so trimming them here would make the SDK's idea\n * of the key differ from the gateway's — the very gap this file exists to close.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function normalizeHeaderValue(value: string): string {\n return value.replace(/^[\\t\\n\\r ]+|[\\t\\n\\r ]+$/g, \"\");\n}\n\n/**\n * Whether the transport can carry these bytes at all.\n *\n * The whitelist is `field-value` itself, RFC 9110 §5.5:\n *\n * field-value = *( HTAB / SP / VCHAR / obs-text )\n * VCHAR = %x21-7E\n * obs-text = %x80-FF\n *\n * So: HTAB, SP, `%x21-7E`, `%x80-FF`. Everything else — `%x00-08`, `%x0A-1F`,\n * `%x7F`, and any code unit above `%xFF` — makes the request throw before it\n * leaves, as a bare `TypeError` from the runtime, which `instanceof PeppolError`\n * does not catch. The error-handling pattern the README teaches would miss it.\n *\n * ⛔⭐ THE MISTAKE THIS REPLACED, because it is the interesting one: the rule was\n * first derived from `new Headers()`, and `new Headers()` is NOT the sink.\n * `fetch` is, and it is stricter — it refuses every C0 control and DEL that\n * `Headers` waves through. Twenty-nine values therefore passed validation and\n * died at dispatch with `InvalidArgumentError: invalid Idempotency-Key header`,\n * untyped, after FOUR attempts, since the retry guard had seen a non-blank\n * header. Bounding a value for one sink does not bound it for the next; the\n * spec is the only model that names them all. (Found by gate, GPR-1185.)\n *\n * ⭐ Refusing here takes nothing away from a caller: by construction every value\n * this rejects could never have left the machine. `idempotency-key.test.ts`\n * pins that against `fetch` itself, not against a stand-in.\n */\nfunction isCarriableHeaderValue(value: string): boolean {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n const carriable =\n code === 0x09 || (code >= 0x20 && code <= 0x7e) || (code >= 0x80 && code <= 0xff);\n if (!carriable) return false;\n }\n return true;\n}\n\nfunction idempotencyKeyRefusal(message: string): PeppolValidationError {\n return new PeppolValidationError(`Invalid idempotency key: ${message}`, {\n valid: false,\n errors: [{ field: \"idempotencyKey\", message }],\n warnings: [],\n });\n}\n\n/**\n * Write the `Idempotency-Key` header, or refuse a key that cannot protect\n * anything. Every write surface that accepts `options.idempotencyKey` goes\n * through here, so the rule lives in one place.\n *\n * ⛔ A key made of whitespace is TRUTHY in JavaScript but EMPTY on the wire. The\n * SDK used to read it as \"a key was supplied\" and unlock its POST retry, while\n * the gateway saw no key at all, skipped its cache and its lock, and treated\n * every attempt as new — one `POST /v1/invoices` leaving FOUR times under the\n * default retry config (`maxRetries: 3`), each able to submit the invoice. A key that does not protect is worse than no key: it\n * removes the very guard its absence would have kept shut.\n *\n * ⚠️ The type says `string`, but the SDK runs on the caller's machine, which may\n * not be typed. `[]` is the sharp case — truthy, and `String([])` is `\"\"`.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function applyIdempotencyKey(\n headers: Record<string, string>,\n options: { idempotencyKey?: string } | undefined,\n): void {\n const key = options?.idempotencyKey;\n // Absent means absent — the caller opted out of idempotency, which is legal.\n if (key === undefined || key === null) return;\n\n if (typeof key !== \"string\") {\n throw idempotencyKeyRefusal(\n `expected a string, received ${Array.isArray(key) ? \"an array\" : `a ${typeof key}`}.`,\n );\n }\n\n const normalized = normalizeHeaderValue(key);\n if (normalized === \"\") {\n throw idempotencyKeyRefusal(\n \"the key is blank once HTTP whitespace is stripped, so it would reach the gateway empty and protect nothing. Pass a non-blank key, or omit the option.\",\n );\n }\n if (!isCarriableHeaderValue(normalized)) {\n throw idempotencyKeyRefusal(\n \"the key contains a character no HTTP header can carry. A header value may hold only HTAB, space, U+0021-U+007E and U+0080-U+00FF (RFC 9110 field-value) — so every control character other than the tab, plus DEL and anything above U+00FF, is refused by the transport itself.\",\n );\n }\n\n // Post the bytes the wire would actually keep, so what the SDK believes it\n // sent and what the gateway reads can never drift apart.\n headers[\"Idempotency-Key\"] = normalized;\n}\n\n/**\n * Whether these headers carry an idempotency key the gateway can actually USE.\n *\n * The second, independent lock. `applyIdempotencyKey` guards nine call sites —\n * four until GPR-1189 opened the header on every operation the contract lists\n * it on — and a tenth added later would skip it. This sits on the single path\n * every retry goes through, and it reads the value that would TRAVEL rather\n * than the presence of a property — so a blank header cannot unlock a replay\n * whatever put it there.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function carriesUsableIdempotencyKey(headers: Record<string, string> | undefined): boolean {\n if (!headers) return false;\n // ⚠️ EVERY matching spelling, not the first one. HTTP header names are\n // case-insensitive and the transport COMBINES duplicates into one comma-joined\n // value, so `{\"Idempotency-Key\": \" \", \"idempotency-key\": \"k\"}` travels as\n // `\", k\"` — a usable key. Reading only the first match called that blank and\n // withheld a retry that was in fact safe. No current writer builds such an\n // object (each surface starts from a fresh `{}`), so this is the lock, not the\n // fix; a fifth call site added later is exactly what it guards. (Gate, GPR-1185.)\n for (const [name, value] of Object.entries(headers)) {\n if (name.toLowerCase() !== \"idempotency-key\") continue;\n if (typeof value === \"string\" && normalizeHeaderValue(value) !== \"\") return true;\n }\n return false;\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 * ⛔ `Retry-After` is read on a 429 and NOWHERE else. Do not widen this to\n * \"whenever the remediation says retry_after\" (GPR-1178 tried, gate caught it).\n *\n * The reasoning that failed: grepping the catalogue shows many\n * `remediation: \"retry_after\"` entries, so surely some sit on 503s. Measured,\n * joining the STATUS this time: all 22 of them are 429s, `provider.throttled`\n * included. The clause was dead code — and worse than dead, because the same\n * untrusted hop that sets `Retry-After` also sets `Getpeppr-Remediation`, so\n * widening let it choose the CONDITION as well as the delay.\n *\n * Counting rows is not counting situations.\n */\n\n/**\n * ⛔ `stripControls` and `safeDocsUrl` live in `./api-result.js`, imported above.\n *\n * They were defined here first, for the parsed error body. The result headers\n * need the exact same rule, and a second copy of a security invariant is two\n * things free to drift apart — so there is one definition, in the module with\n * no dependencies of its own.\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\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\n/**\n * Should this failure be retried at all?\n *\n * ## The gateway's answer wins, in BOTH directions\n *\n * `Getpeppr-Retryable` is derived from the CATALOGUE CODE, not from the status,\n * and the status alone gets it wrong at both ends. Measured against the\n * catalogue (GPR-1174): nine PUBLIC 5xx codes are permanently fatal — among them\n * `provider.not_supported` (501), `provider.authentication_failed` (502) and\n * `server.unexpected_error` (500) — and status-only policy retried three of\n * those four times for nothing. In the other direction three 409s\n * (`idempotency.concurrent_request`, `idempotency.cache_unreadable`,\n * `legal_entities.creation_in_progress`) clear on their own within moments, and\n * status-only policy never retried them at all.\n *\n * ## Absent is not false\n *\n * `retryable` is `undefined` for a gateway that predates the catalogue, for a\n * proxy that strips unknown headers, AND for a value this SDK cannot parse. All\n * three fall back to the historic status list — which is fail-safe in the sense\n * that matters: an unreadable header can neither GRANT a retry the status never\n * allowed, nor REVOKE one it already earned.\n *\n * ⚠️ This answers \"can retrying succeed\", never \"is replaying THIS request\n * safe\". The idempotency guard in `request()` answers the second, and a\n * retryable result does not relax it.\n */\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof PeppolApiError) {\n if (error.retryable !== undefined) return error.retryable;\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 // TWO independent questions, and both must answer yes.\n //\n // 1. CAN retrying succeed? — `isRetryableError`, which asks the gateway's\n // result code first and falls back to the status list. It no longer\n // means \"500, 502, 503, 504\": the catalogue marks some of those fatal\n // and some 409s retryable.\n // 2. Is replaying THIS request safe? — the guard below. 429 always is\n // (the request was never processed) and so are GET/DELETE/HEAD; every\n // other method needs an Idempotency-Key, or a retry could send the\n // same invoice twice.\n //\n // ⛔ A `retryable: true` result answers the first question only. It must\n // never be read as permission to replay a non-idempotent write.\n //\n // ⛔ And the key must be USABLE, not merely present: a value made of\n // whitespace is truthy here and empty on the wire, so the gateway skips\n // its cache and its lock while the SDK believes it is protected\n // (GPR-1185). `carriesUsableIdempotencyKey` asks what would travel.\n const is429 = err instanceof PeppolApiError && err.statusCode === 429;\n const isSafeMethod = /^(GET|DELETE|HEAD)$/i.test(method);\n const hasIdempotencyKey = carriesUsableIdempotencyKey(extraHeaders);\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 // The canonical result rides on the response HEADERS, so it is read the\n // same way for every shape the API returns — success, failure, 204,\n // binary. Parsed once, here, before any branch.\n //\n // ⚠️ \"read the same way\", NOT \"always present\": the gateway's result flag\n // is off until GPR-1181, and a proxy may strip unknown headers, so\n // `undefined` is the normal answer today.\n const result = parseApiResultHeaders(response.headers);\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 result: cloneResultForHook(result),\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 result,\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 result: cloneResultForHook(result),\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 // ⛔ The hook fires BEFORE the throw, unlike every earlier version of\n // this branch. A response that ARRIVED must be logged: a 2xx whose body\n // is a proxy's HTML is the failure a developer most needs to see, and\n // it was the only one their logging never showed them.\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 result: cloneResultForHook(result),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\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 undefined,\n result,\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 result: cloneResultForHook(result),\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 // sendInvoice and createInvoice hit the same endpoint. The latter adds the\n // legacy `_draft` marker, which the current gateway rejects explicitly.\n async sendInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\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 applyIdempotencyKey(headers, options);\n if (options?.validateRecipient) {\n headers[\"X-Validate-Recipient\"] = options.validateRecipient === true ? \"warn\" : String(options.validateRecipient);\n }\n // Preserve the legacy draft request shape so the gateway can return its\n // explicit 422 `drafts_not_supported` capability refusal.\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, options?: IdempotentRequestOptions): Promise<void> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n await this.request<void>(\"POST\", `/invoices/send/${id}`, undefined, headers);\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?.number != null) params.set(\"number\", options.number);\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 // The canonical result rides on the response HEADERS, so it is read the\n // same way for every shape the API returns — success, failure, 204,\n // binary. Parsed once, here, before any branch.\n //\n // ⚠️ \"read the same way\", NOT \"always present\": the gateway's result flag\n // is off until GPR-1181, and a proxy may strip unknown headers, so\n // `undefined` is the normal answer today.\n const result = parseApiResultHeaders(response.headers);\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 result: cloneResultForHook(result),\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 result,\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 result: cloneResultForHook(result),\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?.documentId != null) params.set(\"documentId\", options.documentId);\n if (options?.invoiceId != null) 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, options?: IdempotentRequestOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", `/invoices/${id}/ack`, undefined, headers);\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, options?: IdempotentRequestOptions): Promise<Contact> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/contacts\", input, headers);\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 applyIdempotencyKey(headers, options);\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 applyIdempotencyKey(headers, options);\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, options?: IdempotentRequestOptions): Promise<BankAccount> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/bank-accounts\", input, headers);\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 // ⛔ GPR-1129 — ce corps est une LISTE BLANCHE, exactement comme\n // `parseSendResult` l'est en sortie : tout champ non recopié ici est\n // supprimé en SILENCE, et la capacité correspondante devient\n // inatteignable pour quiconque passe par le SDK.\n //\n // Quatrième occurrence de cette classe, la première dans le sens REQUÊTE\n // (`rulebook` GPR-1069, `transmission` GPR-1089, `duplicateOf` GPR-1105\n // étaient des champs de RÉPONSE). Le préjudice n'est pas symétrique : un\n // champ de réponse jeté casse qui le lit, un champ de requête jeté\n // produit un refus que l'appelant ne peut relier à rien — il envoie\n // `sender`, la passerelle ne le voit jamais, et le 422 qu'il reçoit parle\n // d'une identité qu'il ne revendiquait pas.\n //\n // ⚠️ Conditionnel, jamais `sender: options.sender` : une clé présente à\n // `undefined` disparaît du JSON, donc l'écriture nue passerait les tests\n // tout en salissant le corps des envois standards.\n ...(options.sender ? { sender: options.sender } : {}),\n };\n // ⛔ The key is a HEADER, and the whitelist above is exactly why that has to\n // be said out loud: `idempotencyKey` lives on the same options object as the\n // body fields, so copying it across with its neighbours would put it in the\n // JSON — where the gateway never looks — and the SDK would then unlock its\n // POST retry on a key that protects nothing (GPR-1189).\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices/import\", body, headers);\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 */\n/**\n * A COPY of the result for the logging hook — never the object the retry loop\n * reads (GPR-1178, found by gate).\n *\n * ⚠️ Applied at all six hook sites, but only five of them are TESTABLE. On the\n * JSON-success path nothing reads `result` afterwards — no error is built, the\n * retry loop is over — so un-cloning there has no observable effect and a\n * mutation campaign finds the mutant surviving. That is honest, not a hole: a\n * test asserting anything at that site would be satisfied by both answers. The\n * clone stays for consistency across the six, and this note exists so the next\n * reader does not mistake it for a protection a test is holding.\n *\n * Exactly the `cloneForHook` failure one field over, and this repo has already\n * paid for it once: a hook that strips falsy values before logging them — an\n * entirely reasonable hook — deletes `retryable: false`, and `isRetryableError`\n * then reads `undefined` and falls back to the status policy. Measured effect:\n * a fatal 500 goes from 1 request to 4. It can erase a received `requestId` the\n * same way.\n *\n * A shallow copy is enough and is the point: `ApiResult` is flat, all primitives.\n */\nfunction cloneResultForHook(result: ApiResult | undefined): ApiResult | undefined {\n return result === undefined ? undefined : { ...result };\n}\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-1092 — TROISIÈME occurrence de l'oubli que les deux blocs ci-dessus\n // racontent (`rulebook`, puis `transmission`). Le gateway pose `duplicateOf` sur\n // le 201 quand le même document repart au-delà de la fenêtre de refus : c'est\n // la SEULE façon dont un appelant apprend qu'un second exemplaire vient\n // d'arriver chez son destinataire. Sans cette ligne, l'information existe en\n // HTTP brut et disparaît pour tout utilisateur du SDK — et la promesse écrite\n // dans `openapi.yaml` serait fausse pour eux.\n //\n // Garde de FORME via `optionalWireId`, comme les identifiants voisins : un\n // champ non-chaîne est absent plutôt que menteur.\n //\n // ⛔ `readOwn`, JAMAIS un accès indexé nu — même raison que `transmission`\n // vingt lignes plus haut, et je l'ai quand même écrit nu en première\n // rédaction (trouvé au tour 2 de la gate). Sur un hôte dont\n // `Object.prototype` est pollué, un corps SANS `duplicateOf` en gagne un :\n // le SDK annoncerait alors au client qu'un second exemplaire de sa facture\n // vient d'être accepté pour transmission, en nommant le document d'un tiers.\n const duplicateOf = optionalWireId(readOwn(result, \"duplicateOf\"));\n if (duplicateOf) sendResult.duplicateOf = duplicateOf;\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 networkDiscovery:\n raw.networkDiscovery && typeof raw.networkDiscovery === \"object\"\n ? raw.networkDiscovery as LegalEntity[\"networkDiscovery\"]\n : { state: \"pending\", attempts: 0 },\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 if (raw.registrationDetail && typeof raw.registrationDetail === \"object\") {\n const reason = (raw.registrationDetail as Record<string, unknown>).reason;\n const safeReasons: readonly LegalEntityRegistrationFailureReason[] = [\n \"already_registered\",\n \"invalid_format\",\n \"provider_error\",\n ];\n le.registrationDetail = {\n reason: safeReasons.includes(reason as LegalEntityRegistrationFailureReason)\n ? reason as LegalEntityRegistrationFailureReason\n : \"provider_error\",\n };\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 sandboxFirstSend: parseSandboxFirstSendProfile(\n readOwn(result, \"sandboxFirstSend\"),\n result,\n ),\n };\n}\n\nfunction parseSandboxFirstSendProfile(\n raw: unknown,\n body: unknown,\n): AccountIdentity[\"sandboxFirstSend\"] {\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 sandboxFirstSend field. Please report this response to support@getpeppr.dev.\",\n \"sandboxFirstSend\",\n boundedBody(body),\n );\n }\n const status = readOwn(raw, \"status\");\n if (status === \"blocked\") {\n const code = readOwn(raw, \"code\");\n const message = readOwn(raw, \"message\");\n if (\n typeof code === \"string\" &&\n code.trim() !== \"\" &&\n typeof message === \"string\" &&\n message.trim() !== \"\"\n ) {\n return { status, code, message };\n }\n }\n if (status === \"ready\") {\n const taxMode = readOwn(raw, \"taxMode\");\n const line = readOwn(raw, \"line\");\n if (\n (taxMode === \"outside_scope\" || taxMode === \"reverse_charge\") &&\n isRecord(line)\n ) {\n const vatRate = readOwn(line, \"vatRate\");\n const vatCategory = readOwn(line, \"vatCategory\");\n const taxExemptReason = readOwn(line, \"taxExemptReason\");\n if (\n vatRate === 0 &&\n typeof taxExemptReason === \"string\" &&\n taxExemptReason.trim() !== \"\" &&\n taxMode === \"outside_scope\" &&\n vatCategory === \"O\"\n ) {\n return {\n status,\n taxMode,\n line: { vatRate, vatCategory, taxExemptReason },\n };\n }\n if (\n vatRate === 0 &&\n typeof taxExemptReason === \"string\" &&\n taxExemptReason.trim() !== \"\" &&\n taxMode === \"reverse_charge\" &&\n vatCategory === \"AE\"\n ) {\n return {\n status,\n taxMode,\n line: { vatRate, vatCategory, taxExemptReason },\n };\n }\n }\n }\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request with a malformed sandboxFirstSend profile. Please report this response to support@getpeppr.dev.\",\n \"sandboxFirstSend\",\n boundedBody(body),\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 /**\n * Parsed `Retry-After` delay in milliseconds.\n *\n * `undefined` unless this response is a **429** AND carried a readable\n * `Retry-After`. No other status reads that header, whatever its remediation\n * says — measured, all 22 `retry_after` entries in the catalogue are 429s.\n * The gateway does not attach the header to every throttled answer either.\n */\n public readonly retryAfterMs?: number;\n\n /**\n * The canonical result the gateway declared for this response, read from its\n * six headers — no body parsing required.\n *\n * `undefined` against a gateway that has not activated the result catalogue,\n * and behind any hop that strips unknown headers. The flattened accessors\n * below all read from here, so they are `undefined` together.\n */\n public readonly result?: ApiResult;\n\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly responseBody: string,\n retryAfterMs?: number,\n result?: ApiResult,\n ) {\n super(message);\n this.name = \"PeppolApiError\";\n this.retryAfterMs = retryAfterMs;\n this.result = result;\n }\n\n /**\n * Stable getpeppr result code for this failure (e.g. `\"auth.api_key_invalid\"`).\n *\n * ⛔ NOT the same field as {@link code}, and they can both be present with\n * different values: this one is the catalogue's global code, `code` is the\n * route's own sub-reason from the body.\n *\n * `undefined` when the gateway sent no result headers.\n */\n get resultCode(): ApiResultCode | undefined {\n return this.result?.code;\n }\n\n /**\n * The catalogue's sentence for {@link resultCode}.\n *\n * ⚠️ Usually SHORTER on detail than `.message`, which is built from the\n * response body and can name the offending field or rule. Show `.message` to\n * a human; use this one when you want the stable phrasing.\n *\n * `undefined` when the gateway sent no result headers.\n */\n get resultMessage(): string | undefined {\n return this.result?.message;\n }\n\n /**\n * Server-generated correlation id for this exact request. Quote it to support.\n *\n * `undefined` when the gateway sent no result headers — which includes every\n * response from a deployment predating the catalogue.\n */\n get requestId(): string | undefined {\n return this.result?.requestId;\n }\n\n /**\n * Whether retrying this same request can succeed, per the catalogue.\n *\n * ⚠️ `undefined` means \"the gateway did not say\", NOT \"no\" — the SDK then\n * falls back to its historic status policy. A `false` here is an explicit\n * refusal and the SDK will not retry, whatever the status.\n */\n get retryable(): boolean | undefined {\n return this.result?.retryable;\n }\n\n /**\n * What to do about it: `\"none\"`, `\"fix_request\"`, `\"authenticate\"`,\n * `\"retry\"`, `\"retry_after\"`, `\"wait\"` or `\"contact_support\"` today.\n *\n * Typed open — a value added server-side reaches you rather than vanishing.\n * `undefined` when the gateway sent no result headers.\n */\n get remediation(): ApiResultRemediation | undefined {\n return this.result?.remediation;\n }\n\n /**\n * Documentation link for {@link resultCode}, when the catalogue provides one.\n *\n * `undefined` when the gateway sent no result headers, when the catalogue\n * entry has no docs link, or when the value was not a plain `https://` URL\n * (`http:`, credentials in the authority, and anything the URL parser would\n * have to repair are all refused).\n */\n get docs(): string | undefined {\n return this.result?.docs;\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:** in the sandbox, an organisation admin starts the\n * platform sandbox trial from the console overview (or chooses \"A platform\n * for my customers\" at signup), then creates the sandbox master key at\n * https://console.getpeppr.dev/api-keys. Production platform access is set up\n * with our team — email hello@getpeppr.dev to request it.\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 the structured JSON send payload without sending it.\n * Useful for pre-flight checks in your UI; provider-side normalization still\n * applies on send. `toXml()` adds the stricter direct-UBL builder checks.\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 baseValidation = validateInvoice(input);\n const vatViolations = baseValidation.valid ? validateUblBuilderVat(input) : [];\n const validation: ValidationResult = {\n valid: baseValidation.valid && vatViolations.every((item) => item.severity !== \"error\"),\n errors: [\n ...baseValidation.errors,\n ...vatViolations\n .filter((item) => item.severity === \"error\")\n .map(({ field, message, ruleId }) => ({\n field: field ?? \"invoice\",\n message,\n ruleId: ruleId === \"SDK-INPUT\" ? undefined : ruleId,\n })),\n ],\n warnings: baseValidation.warnings,\n };\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n validation\n );\n }\n try {\n if (input.isCreditNote) {\n return buildCreditNoteXml(input as unknown as CreditNoteInput);\n }\n return buildInvoiceXml(input);\n } catch (error) {\n if (error instanceof UblBuilderInputError) {\n const builderValidation: ValidationResult = {\n valid: false,\n errors: [{ field: error.field, message: error.message, ruleId: error.ruleId }],\n warnings: validation.warnings,\n };\n throw new PeppolValidationError(\n `Invoice validation failed: ${error.message}`,\n builderValidation,\n );\n }\n throw error;\n }\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\n/** Builder-only BT-120 text must not cross the JSON gateway boundary. */\nfunction toGatewayInvoiceInput(input: InvoiceInput): InvoiceInput {\n const stripReason = <T extends { taxExemptReason?: string }>(item: T): Omit<T, \"taxExemptReason\"> => {\n const { taxExemptReason: _builderOnly, ...gatewayItem } = item;\n return gatewayItem;\n };\n return {\n ...input,\n lines: input.lines.map(stripReason),\n ...(input.allowances ? { allowances: input.allowances.map(stripReason) } : {}),\n ...(input.charges ? { charges: input.charges.map(stripReason) } : {}),\n };\n}\n\nclass InvoiceOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Request draft creation from the gateway.\n *\n * @deprecated The current Storecove-backed gateway does not support drafts\n * and returns 422 `drafts_not_supported`. Submit the final document with\n * `invoices.send()` instead.\n * @throws {PeppolApiError} 422 with code `drafts_not_supported`\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(toGatewayInvoiceInput(input), options);\n\n if (validation.warnings.length > 0) {\n result.warnings = validation.warnings;\n }\n\n return result;\n }\n\n /**\n * Request sending of an existing draft invoice by ID.\n *\n * @deprecated The current Storecove-backed gateway has no draft lifecycle and\n * always returns 501. Submit the final document with `invoices.send()`.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async sendById(id: string, options?: IdempotentRequestOptions): Promise<void> {\n return this.adapter.sendInvoiceById(id, options);\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(toGatewayInvoiceInput(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 * pre-flight checks without sending the invoice to Storecove. This is not a Peppol\n * conformance verdict.\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 * Request acknowledgement of a received invoice.\n *\n * @deprecated The current Storecove-backed gateway does not support\n * acknowledgement and always returns 501.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async acknowledge(id: string, options?: IdempotentRequestOptions): Promise<SendResult> {\n return this.adapter.acknowledgeInvoice(id, options);\n }\n\n /**\n * Request an update to an existing invoice.\n *\n * @deprecated Storecove documents are immutable after submission. The\n * current gateway always returns 501; issue a credit note instead.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async update(id: string, input: InvoiceUpdateInput): Promise<SendResult> {\n return this.adapter.updateInvoice(id, input);\n }\n\n /**\n * Request deletion of an invoice.\n *\n * @deprecated The current Storecove-backed gateway does not support invoice\n * deletion and always returns 501.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async delete(id: string): Promise<SendResult> {\n return this.adapter.deleteInvoice(id);\n }\n\n /**\n * Report a French CTC invoice as paid.\n * Other state transitions are retained for API compatibility but the current\n * Storecove-backed gateway returns 501 for them.\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(toGatewayInvoiceInput(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 if (!peppolId.includes(\":\")) {\n throw new PeppolError(\n 'Invalid Peppol ID format. Expected \"scheme:id\" (e.g., \"0208:0685660237\")',\n );\n }\n // ⛔ Découpait sur le premier `:`, donc `GB:VAT:123456789` interrogeait le\n // registre sous le scheme `GB`, qui n'existe pas (GPR-1110). Le registre\n // indexe sous le code EAS NUMÉRIQUE — le fait était déjà écrit dans la note\n // de GPR-755, sans qu'on le relie au découpage.\n const { scheme, id } = parsePeppolId(peppolId);\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 provider document ID or getpeppr submission ID\n * const invoiceEvents = await peppol.events.list({ documentId: \"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({ documentId: \"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, options?: IdempotentRequestOptions): Promise<Contact> {\n return this.adapter.createContact(input, options);\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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, options?: IdempotentRequestOptions): Promise<BankAccount> {\n return this.adapter.createBankAccount(input, options);\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 * String(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 * // `event.data` is `unknown` on the envelope — narrow it per type\n * const data = event.data as { sender: { peppolId: string } };\n * console.log(\"New invoice from:\", data.sender.peppolId);\n * break;\n * }\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","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 offline template starts with O/0 tax lines.\n On send, the CLI checks GET /v1/identity and refuses a conflicting sender\n profile before anything reaches the provider.\\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: 0,\n vatCategory: \"O\",\n taxExemptReason: \"Integration test\",\n },\n {\n description: \"Software license \\u2014 annual subscription\",\n quantity: 1,\n unitPrice: 2400,\n vatRate: 0,\n vatCategory: \"O\",\n taxExemptReason: \"Integration test\",\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: 0,\n vatCategory: \"O\",\n taxExemptReason: \"Integration test\",\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 { parsePeppolId } from \"@getpeppr/sdk\";\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\n/**\n * Valide un identifiant Peppol saisi en ligne de commande — GPR-1116.\n *\n * ⛔ Cette fonction REFUSAIT la seule forme que notre propre guidage propose au\n * Royaume-Uni. Elle découpait sur le premier `:`, obtenait `scheme = \"GB\"`, et\n * répondait « Invalid scheme \"GB\". Must be exactly 4 digits ». L'utilisateur\n * tapait exactement ce que `SCHEMES_BY_COUNTRY` lui donne, et le CLI l'accusait\n * d'une faute qu'il n'avait pas commise. C'est le pire mode d'échec possible :\n * un refus qui désigne le mauvais coupable.\n *\n * ⭐ On canonicalise AVANT de valider. Le contrôle des quatre chiffres est\n * conservé — il attrape encore une vraie faute de frappe — mais il s'applique\n * désormais au scheme RÉSOLU, pas au fragment que le découpage a produit.\n *\n * ⚠️ Exportée pour être testée directement. Le paquet est bundlé par tsup\n * (`noExternal`), donc cela n'élargit aucune surface publique npm.\n */\nexport function 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, id } = parsePeppolId(raw);\n\n if (!/^\\d{4}$/.test(scheme)) {\n return {\n ok: false,\n error: `Invalid scheme \"${scheme}\". Must be a 4-digit EAS code (e.g. 0208) or a published symbolic scheme (e.g. GB:VAT).`,\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","import { parsePeppolId } from \"@getpeppr/sdk\";\n\nconst 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\n/**\n * Sépare un identifiant Peppol — GPR-1116.\n *\n * ⛔ Découpait sur le premier `:`, ce qui est faux dès que le scheme porte sa\n * forme symbolique : `GB:VAT:123456789` rendait `{ scheme: \"GB\", id:\n * \"VAT:123456789\" }`. Le registre n'indexe pas sous `GB` — il indexe sous le code\n * EAS numérique — donc la recherche ne rendait rien, sans jamais dire pourquoi.\n *\n * ⭐ Le découpage vit dans `@getpeppr/sdk` (`parsePeppolId`) : il résout le\n * préfixe CONTRE la code list au lieu de le deviner par position. Ce paquet\n * bundle le SDK, donc converger dessus ne coûte rien à l'utilisateur final — et\n * évite une seconde implémentation qui dériverait de la première.\n *\n * ⚠️ Le contrat « pas de `:` ⇒ scheme vide » est conservé tel quel : il vaut\n * pour une saisie partielle en cours de frappe, où inventer un scheme serait\n * pire que n'en rendre aucun.\n */\nexport function parseParticipantId(value: string): {\n scheme: string;\n id: string;\n} {\n if (!value.includes(\":\")) {\n return { scheme: \"\", id: value };\n }\n return parsePeppolId(value);\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 { dashboardUrlForSendResult } from \"../lib/dashboard-url.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\";\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. Build SDK client before validation: the sandbox integration fixture\n // needs the provider-side sender profile before its tax fields are final.\n const baseUrl = flags.local ? LOCAL_BASE : API_BASE;\n const client = new Peppol({ apiKey: auth.apiKey, baseUrl });\n\n if (auth.environment === \"sandbox\") {\n let profile;\n try {\n profile = (await client.identity.get()).sandboxFirstSend;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.red(\"✢\")} Could not verify the sandbox sender profile: ${msg}\\n`);\n process.exit(1);\n return;\n }\n if (!profile || profile.status !== \"ready\") {\n const message = profile?.status === \"blocked\"\n ? profile.message\n : \"The sandbox first-send profile is unavailable.\";\n process.stderr.write(`${pc.red(\"✢\")} ${message}\\n`);\n process.exit(1);\n return;\n }\n\n const taxEntries = [payload.lines, payload.allowances, payload.charges]\n .filter(Array.isArray)\n .flat();\n const payloadOutsideScope =\n taxEntries.length > 0 &&\n taxEntries.every((entry) => entry.vatCategory === \"O\");\n const profileOutsideScope = profile.taxMode === \"outside_scope\";\n\n if (file) {\n // A file is fiscal intent. Never rewrite it silently; refuse locally\n // before the API/provider if it conflicts with the measured sender.\n if (payloadOutsideScope !== profileOutsideScope) {\n process.stderr.write(\n `${pc.red(\"✢\")} This file's tax mode does not match the sandbox sender. ` +\n `GET /v1/identity recommends ${profile.line.vatCategory}/0. Nothing was sent.\\n`,\n );\n process.exit(1);\n return;\n }\n } else {\n // No file means the CLI's own integration fixture, not customer data:\n // adapt every generated line to the exact profile by construction.\n payload.lines = payload.lines.map((line) => ({ ...line, ...profile.line }));\n }\n }\n\n // 4. 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 // 5. --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 // 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 = dashboardUrlForSendResult(result);\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\";\nimport { parsePeppolId, countryForScheme } 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\n/**\n * Le pays du destinataire, dérivé de son identifiant — GPR-1116.\n *\n * ⛔ Cette fonction portait DEUX défauts, et il faut les nommer tous les deux\n * parce que corriger l'un seul laisse l'autre livrer un pays faux.\n *\n * 1. Elle découpait par `peppolId.split(\":\")`. La forme symbolique d'un scheme\n * contient elle-même un `:` (98 des 105 entrées de la code list v9.7), donc\n * `GB:VAT:123456789` rendait `identifier = \"VAT\"`, dont le préfixe `VA`\n * passait le test alphabétique : un vendeur britannique devenait le Vatican.\n *\n * 2. Sa table de repli portait QUATRE schemes et renvoyait `\"BE\"` pour tout le\n * reste. Norvège, Suède, Pays-Bas, Turquie — tous déclarés belges, en\n * silence. La code list officielle couvre 96 schemes nationaux sur 50 pays,\n * et `countryForScheme` la consulte.\n *\n * ⭐ L'ordre compte : on demande d'abord son pays au SCHEME, qui est une donnée\n * publiée, avant de regarder le préfixe de la VALEUR, qui est une heuristique.\n * L'ordre inverse — celui d'avant — laissait une coïncidence de deux lettres\n * l'emporter sur la liste officielle.\n *\n * ⚠️ Le repli final reste `\"BE\"`, mais il ne s'applique plus qu'à un identifiant\n * dont NI le scheme NI la valeur ne disent le pays (`DUNS`, `GLN`, un code publié\n * après notre version de la liste). C'est un défaut de dernier recours dans un\n * fichier d'exemple, plus une réponse par défaut donnée à la moitié du monde.\n */\nfunction deriveCountryFromPeppolId(peppolId: PeppolId): CountryCode {\n const { scheme, id } = parsePeppolId(peppolId);\n\n const published = countryForScheme(scheme);\n if (published !== undefined) {\n return published as CountryCode;\n }\n\n // Certains identifiants portent leur pays en préfixe (`BE0314595348`). C'est\n // une heuristique, pas une règle — d'où sa place APRÈS la liste publiée.\n const alphaPrefix = id.slice(0, 2);\n if (/^[A-Za-z]{2}$/.test(alphaPrefix)) {\n return alphaPrefix.toUpperCase() as CountryCode;\n }\n\n return \"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\" = outside the scope of VAT (UBL 2.1 / EN 16931).\n // This offline fixture starts at O/0. Before sending, the CLI reads\n // GET /identity and replaces these tax fields with the sender-specific\n // O/0 or AE/0 first-send profile. The SDK transport strips the\n // builder-only reason so Storecove can derive its own provider text.\n vatCategory: \"O\",\n taxExemptReason: \"Not subject to VAT\",\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 type { SendResult } from \"@getpeppr/sdk\";\n\nconst DASHBOARD_INVOICES_BASE = \"https://console.getpeppr.dev/invoices\";\n\n/** Build the dashboard link printed after a successful send. */\nexport function dashboardUrlForSendResult(\n result: Pick<SendResult, \"id\">,\n): string {\n return `${DASHBOARD_INVOICES_BASE}/${result.id}`;\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 the credentials file ($XDG_CONFIG_HOME/getpeppr, %APPDATA%\\\\getpeppr on Windows)\")\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 the stored credentials file\")\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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Q,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAA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","names":["warn","DERIVED_AMOUNT_CONTRACT_RULE","survivesCents","resolve","readSentence","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","pc","result","createInterface","pc","resolve","createInterface","program","pc","pc","API_BASE","LOCAL_BASE","pc","program","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/canonical-schemes.ts","../../sdk/src/core/peppol-id.ts","../../sdk/src/core/iso6523-icd-codes.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/schematron.ts","../../sdk/src/core/status-precedence.ts","../../sdk/src/version.ts","../../sdk/src/core/api-result.ts","../../sdk/src/core/client.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/lib/dashboard-url.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(\"✓\")} No findings`);\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 \"Offline Checks (partial)\",\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(\"✓ Pre-flight checks passed\"))}`);\n } else if (valid) {\n lines.push(\n ` ${pc.green(pc.bold(\"✓ Pre-flight checks passed\"))} ${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(\"✗ Pre-flight checks found errors\"))} ${pc.dim(`(${parts.join(\", \")})`)}`,\n );\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n","/**\n * Les DEUX noms d'un scheme Peppol, et comment ramener l'un à l'autre — GPR-1109.\n *\n * La code list publie chaque scheme sous deux orthographes : le code EAS\n * numérique (`iso6523`, ex. `0204`) et la forme symbolique (`schemeid`, ex.\n * `DE:LWID`). Ce sont deux NOMS du MÊME scheme, pas deux schemes.\n *\n * ## ⛔ Pourquoi cette table existe\n *\n * Mesuré en production le 2026-08-20 : un compte dont l'identifiant est\n * enregistré sous la forme symbolique ne pouvait envoyer AUCUN document par\n * `POST /v1/invoices/import`.\n *\n * - document déclarant `0204` → conforme, puis `422 supplier_identity_not_owned`\n * - document déclarant `DE:LWID` → `422 validation_failed` (BR-CL-25 : le\n * schemeID doit appartenir à la CEF EAS code list, donc être numérique)\n *\n * Aucune troisième écriture n'existait, et **9 comptes sur 18** étaient dans ce\n * cas. Le défaut n'était dans aucune des deux règles — c'était le chaînon\n * manquant entre elles.\n *\n * ## ⛔ POURQUOI UNE CONSTANTE GRAVÉE ET PAS UN READ DU JSON\n *\n * Exactement la raison de `ROUTABLE_SCHEMES`, à côté : l'artefact versionné est\n * l'AUTORITÉ, mais il se lit avec `readFileSync(__dirname + …)`, ce qui est bon\n * dans un test et faux dans une route Next.js — le bundler ne trace pas une\n * lecture de fichier au runtime, donc le JSON n'existe pas dans la fonction\n * déployée. Même forme, même garde-fou : `__tests__/canonical-schemes-drift.test.ts`\n * RE-DÉRIVE cette table depuis le JSON et échoue dans les DEUX sens.\n * **Ne jamais éditer cette liste à la main — la régénérer.**\n *\n * ## ⭐ Pourquoi TOUTES les entrées, y compris les dépréciées\n *\n * Canonicaliser est une **traduction**, pas une **autorisation**. Un scheme\n * déprécié peut parfaitement être enregistré sur un compte ancien ; refuser de le\n * traduire le rendrait invisible à la garde de propriété alors que la ligne\n * existe en base — on transformerait un scheme retiré du catalogue en compte\n * bloqué. L'autorisation, elle, est le rôle de `isRoutableScheme`, qui filtre\n * bien sur active+registrable.\n *\n * ## Ce que cette table ne fait PAS\n *\n * Elle ne dit pas qu'un scheme est routable, ni qu'un identifiant est bien formé,\n * ni qu'il appartient à l'appelant. Traduction d'un NOM, rien d'autre.\n */\n\n/** Dérivée de participant-identifier-schemes-v9.7.json — entrées: 105 | actives: 84 | paires alias→code: 105 */\nconst ALIAS_TO_EAS: ReadonlyMap<string, string> = new Map([\n [\"AD:VAT\", \"9922\"],\n [\"AE:TIN\", \"0235\"],\n [\"AL:VAT\", \"9923\"],\n [\"AT:CID\", \"9916\"],\n [\"AT:GOV\", \"9915\"],\n [\"AT:KUR\", \"9919\"],\n [\"AT:VAT\", \"9914\"],\n [\"AU:ABN\", \"0151\"],\n [\"BA:VAT\", \"9924\"],\n [\"BE:CBE\", \"9956\"],\n [\"BE:EN\", \"0208\"],\n [\"BE:VAT\", \"9925\"],\n [\"BG:VAT\", \"9926\"],\n [\"CH:UIDB\", \"0183\"],\n [\"CH:VAT\", \"9927\"],\n [\"CY:VAT\", \"9928\"],\n [\"CZ:VAT\", \"9929\"],\n [\"DE:GEBA\", \"0246\"],\n [\"DE:LID\", \"9958\"],\n [\"DE:LWID\", \"0204\"],\n [\"DE:VAT\", \"9930\"],\n [\"DK:CPR\", \"9901\"],\n [\"DK:CVR\", \"9902\"],\n [\"DK:DIGST\", \"0184\"],\n [\"DK:ERST\", \"0198\"],\n [\"DK:P\", \"0096\"],\n [\"DK:SE\", \"9904\"],\n [\"DK:VANS\", \"9905\"],\n [\"DUNS\", \"0060\"],\n [\"EE:CC\", \"0191\"],\n [\"EE:VAT\", \"9931\"],\n [\"ES:VAT\", \"9920\"],\n [\"EU:NAL\", \"0130\"],\n [\"EU:REID\", \"9913\"],\n [\"EU:VAT\", \"9912\"],\n [\"FI:NSI\", \"0215\"],\n [\"FI:ORG\", \"0212\"],\n [\"FI:OVT\", \"0037\"],\n [\"FI:OVT2\", \"0216\"],\n [\"FI:VAT\", \"0213\"],\n [\"FR:CTC\", \"0225\"],\n [\"FR:SIRENE\", \"0002\"],\n [\"FR:SIRET\", \"0009\"],\n [\"FR:VAT\", \"9957\"],\n [\"GB:VAT\", \"9932\"],\n [\"GLN\", \"0088\"],\n [\"GR:VAT\", \"9933\"],\n [\"GS1\", \"0209\"],\n [\"HR:VAT\", \"9934\"],\n [\"HU:VAT\", \"9910\"],\n [\"IBAN\", \"9918\"],\n [\"IE:VAT\", \"9935\"],\n [\"IS:KT\", \"9917\"],\n [\"IS:KTNR\", \"0196\"],\n [\"IT:CF\", \"9907\"],\n [\"IT:CFI\", \"0210\"],\n [\"IT:COD\", \"0205\"],\n [\"IT:CUUO\", \"0201\"],\n [\"IT:FTI\", \"0097\"],\n [\"IT:IPA\", \"9921\"],\n [\"IT:IVA\", \"0211\"],\n [\"IT:SECETI\", \"0142\"],\n [\"IT:SIA\", \"0135\"],\n [\"IT:VAT\", \"9906\"],\n [\"JP:IIN\", \"0221\"],\n [\"JP:SST\", \"0188\"],\n [\"LEI\", \"0199\"],\n [\"LI:VAT\", \"9936\"],\n [\"LT:LEC\", \"0200\"],\n [\"LT:VAT\", \"9937\"],\n [\"LU:MAT\", \"0240\"],\n [\"LU:VAT\", \"9938\"],\n [\"LV:URN\", \"0218\"],\n [\"LV:VAT\", \"9939\"],\n [\"MC:VAT\", \"9940\"],\n [\"ME:VAT\", \"9941\"],\n [\"MK:VAT\", \"9942\"],\n [\"MT:VAT\", \"9943\"],\n [\"MY:EIF\", \"0230\"],\n [\"NG:TID\", \"0244\"],\n [\"NL:KVK\", \"0106\"],\n [\"NL:OIN\", \"9954\"],\n [\"NL:OINO\", \"0190\"],\n [\"NL:VAT\", \"9944\"],\n [\"NO:ORG\", \"0192\"],\n [\"NO:ORGNR\", \"9908\"],\n [\"NO:VAT\", \"9909\"],\n [\"OM:VAT\", \"0248\"],\n [\"PL:VAT\", \"9945\"],\n [\"PT:VAT\", \"9946\"],\n [\"RO:VAT\", \"9947\"],\n [\"RS:VAT\", \"9948\"],\n [\"SE:ORGNR\", \"0007\"],\n [\"SE:VAT\", \"9955\"],\n [\"SG:UEN\", \"0195\"],\n [\"SI:VAT\", \"9949\"],\n [\"SK:DIC\", \"0245\"],\n [\"SK:ICO\", \"0158\"],\n [\"SK:VAT\", \"9950\"],\n [\"SM:VAT\", \"9951\"],\n [\"SPIS\", \"0242\"],\n [\"TR:VAT\", \"9952\"],\n [\"UBLBE\", \"0193\"],\n [\"US:EIN\", \"9959\"],\n [\"VA:VAT\", \"9953\"],\n]);\n\n/**\n * Pli ASCII, jamais `toUpperCase()`.\n *\n * ⛔ LE CONTRE-EXEMPLE DÉPEND DU SENS DU PLI, et cette phrase a d'abord dit le\n * contraire. Le module voisin (`routable-schemes.ts`) cite le signe Kelvin\n * U+212A, qui se replie en `k` — mais sous `toLowerCase()`, le sens dans lequel\n * IL plie. Mesuré : sous `toUpperCase()` le Kelvin ne bouge pas, il est déjà\n * majuscule. Reprendre son exemple ici était un fait juste appliqué au mauvais\n * site.\n *\n * Les caractères qui deviennent ASCII en pliant vers le HAUT sont d'une autre\n * famille — mesurés : `ı` (U+0131) → `I`, `ß` → `SS`, `fi` → `FI`. Un pli\n * Unicode ferait donc traduire `ıE:VAT` comme s'il s'agissait de `IE:VAT`, soit\n * deux schemes distincts fusionnés — un envoi légitime refusé à tort.\n *\n * L'ENTRÉE vient du réseau ou de la base : elle n'est pas contrainte à l'ASCII,\n * même si un nom de scheme publié l'est.\n */\nfunction asciiUpper(value: string): string {\n let out = \"\";\n for (const char of value) {\n const code = char.charCodeAt(0);\n out += code >= 0x61 && code <= 0x7a ? String.fromCharCode(code - 32) : char;\n }\n return out;\n}\n\n/**\n * Ramène un scheme à son code EAS numérique — la forme que le RÉSEAU exige.\n *\n * ⚠️ Un scheme inconnu ressort **inchangé** (trimé), jamais `null` et jamais une\n * exception. Transformer « je ne connais pas ce nom » en « je refuse » ferait de\n * cette table une allowlist, c'est-à-dire nous rendrait plus stricts que le\n * réseau — l'erreur symétrique d'une mort asynchrone, et la pire des deux\n * (GPR-904). Un scheme neuf, publié après notre version de la code list, doit\n * continuer de fonctionner comme avant.\n */\nexport function canonicalScheme(scheme: string): string {\n return lookupCanonicalScheme(scheme) ?? scheme.trim();\n}\n\n/**\n * Le même lookup, mais qui DIT quand il ne connaît pas — `undefined`, jamais\n * l'entrée renvoyée telle quelle.\n *\n * ⛔ Cette distinction n'est pas cosmétique. `canonicalScheme` trime avant de\n * rendre, donc « inconnu » et « connu » se ressemblent dangereusement : comparer\n * son retour à l'entrée BRUTE fait lire « résolu » là où seul un espace a\n * disparu. Mesuré (GPR-1110) : `\" 0193:ABCD\"` ressortait trimé, donc différent de\n * l'entrée, donc pris pour un scheme à deux segments — et `\" 0193:ABCD:EFGH\"` se\n * découpait en `{scheme:\"0193:ABCD\", id:\"EFGH\"}`.\n *\n * ⭐ Tout appelant qui a besoin de savoir SI la table connaît un nom doit utiliser\n * cette fonction. `canonicalScheme` reste le bon choix pour TRADUIRE, où\n * l'identité sur un scheme inconnu est le comportement voulu (GPR-904).\n */\nexport function lookupCanonicalScheme(scheme: string): string | undefined {\n return ALIAS_TO_EAS.get(asciiUpper(scheme.trim()));\n}\n\n/**\n * Le PAYS d'un scheme Peppol — GPR-1116.\n *\n * La même code list qui publie les deux noms d'un scheme publie aussi son pays\n * (`country`, code ISO). Cette table en est la seconde projection, gravée pour\n * exactement la raison écrite plus haut : le JSON fait autorité, mais un bundler\n * ne trace pas sa lecture, donc il n'existe pas dans une fonction déployée.\n *\n * ## Pourquoi elle existe\n *\n * Le template que `getpeppr init` dépose chez le développeur devinait le pays du\n * destinataire depuis une table de QUATRE schemes (`0009`, `0204`, `0208`,\n * `9925`), et repliait tout le reste sur `\"BE\"` en dur. Un destinataire\n * norvégien, suédois, néerlandais ou turc était donc déclaré belge — dans le\n * premier fichier que le développeur reçoit de nous. La liste officielle couvre\n * 96 schemes nationaux sur 50 pays.\n *\n * Le pays du destinataire est BT-55 (EN 16931) : c'est lui qui décide QUELLES\n * regles nationales le réseau applique au document. Un pays faux ne dégrade pas\n * la facture, il la fait juger par le mauvais rulebook.\n *\n * ## Les 9 schemes SANS pays sont absents, et c'est le point\n *\n * `DUNS`, `GLN`, `LEI`, `IBAN`, `EU:VAT`… portent `international` dans la liste.\n * « International » n'est pas un code pays : les mapper vers quoi que ce soit\n * inventerait une donnée. Ils ressortent `undefined`, et c'est à l'appelant de\n * décider quoi faire d'un identifiant qui ne dit pas son pays — ce qu'aucune\n * valeur de repli ne peut faire à sa place.\n */\n/** Dérivée de participant-identifier-schemes-v9.7.json — schemes avec pays: 96 | sans (international): 9 | pays distincts: 50 */\nconst EAS_TO_COUNTRY: ReadonlyMap<string, string> = new Map([\n [\"0002\", \"FR\"],\n [\"0007\", \"SE\"],\n [\"0009\", \"FR\"],\n [\"0037\", \"FI\"],\n [\"0096\", \"DK\"],\n [\"0097\", \"IT\"],\n [\"0106\", \"NL\"],\n [\"0135\", \"IT\"],\n [\"0142\", \"IT\"],\n [\"0151\", \"AU\"],\n [\"0158\", \"SK\"],\n [\"0183\", \"CH\"],\n [\"0184\", \"DK\"],\n [\"0188\", \"JP\"],\n [\"0190\", \"NL\"],\n [\"0191\", \"EE\"],\n [\"0192\", \"NO\"],\n [\"0193\", \"BE\"],\n [\"0195\", \"SG\"],\n [\"0196\", \"IS\"],\n [\"0198\", \"DK\"],\n [\"0200\", \"LT\"],\n [\"0201\", \"IT\"],\n [\"0204\", \"DE\"],\n [\"0205\", \"IT\"],\n [\"0208\", \"BE\"],\n [\"0210\", \"IT\"],\n [\"0211\", \"IT\"],\n [\"0212\", \"FI\"],\n [\"0213\", \"FI\"],\n [\"0215\", \"FI\"],\n [\"0216\", \"FI\"],\n [\"0218\", \"LV\"],\n [\"0221\", \"JP\"],\n [\"0225\", \"FR\"],\n [\"0230\", \"MY\"],\n [\"0235\", \"AE\"],\n [\"0240\", \"LU\"],\n [\"0244\", \"NG\"],\n [\"0245\", \"SK\"],\n [\"0246\", \"DE\"],\n [\"0248\", \"OM\"],\n [\"9901\", \"DK\"],\n [\"9902\", \"DK\"],\n [\"9904\", \"DK\"],\n [\"9905\", \"DK\"],\n [\"9906\", \"IT\"],\n [\"9907\", \"IT\"],\n [\"9908\", \"NO\"],\n [\"9909\", \"NO\"],\n [\"9910\", \"HU\"],\n [\"9914\", \"AT\"],\n [\"9915\", \"AT\"],\n [\"9916\", \"AT\"],\n [\"9917\", \"IS\"],\n [\"9919\", \"AT\"],\n [\"9920\", \"ES\"],\n [\"9921\", \"IT\"],\n [\"9922\", \"AD\"],\n [\"9923\", \"AL\"],\n [\"9924\", \"BA\"],\n [\"9925\", \"BE\"],\n [\"9926\", \"BG\"],\n [\"9927\", \"CH\"],\n [\"9928\", \"CY\"],\n [\"9929\", \"CZ\"],\n [\"9930\", \"DE\"],\n [\"9931\", \"EE\"],\n [\"9932\", \"GB\"],\n [\"9933\", \"GR\"],\n [\"9934\", \"HR\"],\n [\"9935\", \"IE\"],\n [\"9936\", \"LI\"],\n [\"9937\", \"LT\"],\n [\"9938\", \"LU\"],\n [\"9939\", \"LV\"],\n [\"9940\", \"MC\"],\n [\"9941\", \"ME\"],\n [\"9942\", \"MK\"],\n [\"9943\", \"MT\"],\n [\"9944\", \"NL\"],\n [\"9945\", \"PL\"],\n [\"9946\", \"PT\"],\n [\"9947\", \"RO\"],\n [\"9948\", \"RS\"],\n [\"9949\", \"SI\"],\n [\"9950\", \"SK\"],\n [\"9951\", \"SM\"],\n [\"9952\", \"TR\"],\n [\"9953\", \"VA\"],\n [\"9954\", \"NL\"],\n [\"9955\", \"SE\"],\n [\"9956\", \"BE\"],\n [\"9957\", \"FR\"],\n [\"9958\", \"DE\"],\n [\"9959\", \"US\"],\n]);\n\n/**\n * Le pays d'un scheme, ou `undefined` quand la liste n'en publie pas.\n *\n * Accepte les DEUX orthographes : elle canonicalise avant de consulter, donc\n * `\"NO:ORG\"` et `\"0192\"` rendent tous deux `\"NO\"`.\n *\n * `undefined` couvre DEUX situations que l'appelant doit distinguer lui-même\n * s'il y tient : un scheme international (`DUNS`), et un scheme que notre version\n * de la liste ne connait pas encore. Les confondre dans un repli en dur est\n * précisément le défaut que ce module ferme — ne jamais rendre un pays par\n * défaut ici, ou l'information manquante serait maquillée en fait.\n */\nexport function countryForScheme(scheme: string): string | undefined {\n return EAS_TO_COUNTRY.get(canonicalScheme(scheme));\n}\n\n/**\n * ⚠️ Écrites pour le test de dérive, mais PUBLIÉES depuis `index.ts` (GPR-1110) —\n * le verrou vit dans la console et la table dans le SDK, donc il n'existe pas de\n * chemin privé entre les deux. Elles font par conséquent partie du contrat du\n * paquet : les retirer serait un changement majeur, pas un nettoyage.\n */\nexport const CANONICAL_SCHEME_COUNT = ALIAS_TO_EAS.size;\nexport const CANONICAL_SCHEMES_VERSION = \"9.7\";\n\n/** Nombre de schemes pour lesquels la liste publie un pays. Verrouille par le test de derive. */\nexport const SCHEME_COUNTRY_COUNT = EAS_TO_COUNTRY.size;\n","/**\n * Découper un identifiant Peppol — GPR-1110.\n *\n * Un identifiant Peppol s'écrit `<scheme>:<valeur>`, mais le scheme lui-même a\n * DEUX orthographes légales : son code EAS numérique (`9932`) et sa forme\n * symbolique (`GB:VAT`), qui contient un `:`. Le séparateur du couple et un\n * caractère du scheme sont donc le MÊME caractère — c'est toute la difficulté,\n * et la raison pour laquelle ce module existe plutôt qu'un `split(\":\")`.\n *\n * Il vit à part de `ubl-builder.ts` parce qu'il a deux appelants aux besoins\n * distincts : le constructeur d'UBL, qui doit écrire un `@schemeID` conforme à\n * `BR-CL-25`, et `directory.lookup`, qui doit interroger le registre sous le\n * scheme que celui-ci indexe. Les deux découpaient séparément, et les deux se\n * trompaient de la même manière.\n */\nimport { canonicalScheme, lookupCanonicalScheme } from \"./canonical-schemes.js\";\n\n/**\n * Un identifiant Peppol est-il assez bien formé pour qu'on écrive son scheme ?\n *\n * ⛔ « Contient un `:` » ne suffisait pas, et « deux segments non vides » non plus\n * — les deux ont été essayés et démolis par une gate (GPR-1110) :\n *\n * | entrée | découpage | pourquoi ça passait |\n * | -- | -- | -- |\n * | `\":x\"` | scheme vide | aucun contrôle sur les segments |\n * | `\"0208:\"` | valeur vide | idem |\n * | `\"GB:VAT\"` | `{GB, VAT}` | **deux segments non vides** — le code du scheme copié SANS son identifiant |\n *\n * Le dernier est le piège : `GB:VAT` est exactement ce que `SCHEMES_BY_COUNTRY`\n * affiche comme `code`, donc le copier seul est l'erreur qu'un développeur\n * commet naturellement. Il produisait `schemeID=\"GB\"`, hors CEF EAS code list.\n *\n * ⚠️ Le contrôle du scheme est SYNTAXIQUE, jamais une allowlist : quatre chiffres,\n * ou l'une des valeurs littérales que `BR-CL-25` admet. Un code publié après notre\n * version de la code list doit continuer de traverser — être plus strict que le\n * réseau est l'erreur symétrique, et la pire des deux (GPR-904).\n */\nexport function isWellFormedPeppolId(peppolId: string): boolean {\n if (!peppolId.includes(\":\")) return false;\n const { scheme, id } = parsePeppolId(peppolId);\n // ⛔ `id.length > 0` acceptait `\"0208:\\n\"` — un identifiant fait d'un seul\n // caractère blanc est vide pour le réseau, et le laisser passer grave une\n // valeur qu'aucun registre ne peut résoudre. Mesuré par gate (GPR-1116).\n return id.trim().length > 0 && (/^\\d{4}$/.test(scheme) || EAS_LITERAL_SCHEMES.has(scheme));\n}\n\n/**\n * Les schemes qu'un ENDPOINT (BT-34) ne peut pas porter — GPR-1116.\n *\n * ⚠️ `isWellFormedPeppolId` sert DEUX questions qui n'ont pas la même règle :\n * l'adresse d'une partie (`validateParty`, jugée par `BR-CL-25`) et le\n * bénéficiaire du paiement (`payeeParty`, jugé par `BR-CL-10`). `SEPA` est\n * légal pour le second et ne l'est pas pour le premier — la liste littérale\n * ci-dessus les mélange, par héritage.\n *\n * ⭐ La forme juste serait un paramètre `usage`, comme en porte déjà\n * `validatePeppolIdentifier` : « un identifiant se valide contre l'USAGE,\n * jamais dans l'absolu ». Cet export est le pas intermédiaire — il permet à un\n * appelant qui sait juger une ADRESSE de retirer ce qui n'en est pas une, sans\n * changer le verdict des appelants existants. Suivi : GPR-1128.\n */\nexport const NON_ENDPOINT_SCHEMES: ReadonlySet<string> = new Set([\"SEPA\"]);\n\n/**\n * Les valeurs non numériques que `BR-CL-25` énumère, plus `SEPA`, que `BR-CL-10`\n * admet sous le vendeur et le bénéficiaire. Gravées depuis les asserts.\n */\nconst EAS_LITERAL_SCHEMES: ReadonlySet<string> = new Set([\"AN\", \"AQ\", \"AS\", \"AU\", \"EM\", \"SEPA\"]);\n\n/**\n * Sépare un identifiant Peppol en son scheme EAS **numérique** et sa valeur.\n *\n * ⛔ **Ne découpe PAS sur le premier `:`.** Mesuré sur la code list officielle\n * v9.7 : 98 des 105 formes symboliques portent un `:`. Découper par position\n * rendait `{ scheme: \"GB\", id: \"VAT:123456789\" }` pour un vendeur britannique —\n * le scheme hors CEF EAS code list (`BR-CL-25`, fatale) ET la valeur corrompue.\n * `GB:VAT` étant le code que `SCHEMES_BY_COUNTRY` RECOMMANDE au Royaume-Uni,\n * le défaut frappait quiconque suivait notre propre guidage.\n * ⚠️ Cette phrase a dit « le SEUL code » jusqu'à GPR-1041, qui a ajouté `0060`,\n * `0088` et `0199` pour les sociétés sous le seuil de TVA. Le motif du défaut\n * est intact — c'est la RECOMMANDATION qui le rendait atteignable, pas\n * l'exclusivité — mais l'exclusivité, elle, n'est plus vraie.\n *\n * ⭐ **Le scheme occupe au plus DEUX segments**, et ce n'est pas une prudence :\n * mesuré sur la v9.7, aucune forme symbolique ne porte plus d'un `:`. La VALEUR,\n * elle, n'est bornée par rien — d'où l'essai du candidat long d'abord, puis le\n * repli sur le court. L'ordre inverse ferait dépendre le point de coupe de la\n * valeur, ce qui est exactement le défaut qu'on ferme.\n *\n * ⚠️ Un scheme que la table ne connaît pas ressort **inchangé**, jamais en\n * exception : c'est la doctrine de `canonicalScheme` (GPR-904), et elle vaut ici\n * aussi. Un scheme numérique publié après notre version de la code list doit\n * continuer de traverser — être plus strict que le réseau est l'erreur\n * symétrique, et la pire des deux.\n */\nexport function parsePeppolId(peppolId: string): { scheme: string; id: string } {\n const first = peppolId.indexOf(\":\");\n if (first === -1) {\n // Le type `PeppolId` l'interdit, mais un appelant JavaScript n'a pas de type.\n // Canonicaliser quand même : `DUNS` seul vaut mieux que `DUNS` recopié tel quel.\n return { scheme: canonicalScheme(peppolId), id: \"\" };\n }\n\n const second = peppolId.indexOf(\":\", first + 1);\n if (second !== -1) {\n // ⛔ On DEMANDE à la table si elle connaît ce nom ; on ne DÉDUIT pas la\n // réponse en comparant deux chaînes. `canonicalScheme` trime son entrée, donc\n // « le retour diffère de ce que j'ai passé » est vrai aussi quand seul un\n // espace a disparu : `\" 0193:ABCD:EFGH\"` se découpait en\n // `{scheme:\"0193:ABCD\", id:\"EFGH\"}` (GPR-1110, trouvé par gate).\n const resolved = lookupCanonicalScheme(peppolId.slice(0, second));\n if (resolved !== undefined) {\n return { scheme: resolved, id: peppolId.slice(second + 1) };\n }\n }\n\n // Un seul segment de scheme : soit le code EAS numérique (rendu tel quel), soit\n // l'une des 7 formes symboliques sans `:` de la v9.7 (`DUNS`, `GLN`, `LEI`…).\n return {\n scheme: canonicalScheme(peppolId.slice(0, first)),\n id: peppolId.slice(first + 1),\n };\n}\n","/**\n * La liste ISO 6523 ICD — celle que `BR-CL-10` exige, et qui n'est PAS la liste EAS.\n *\n * ## ⛔ Deux listes, deux règles, deux champs — ne jamais les confondre\n *\n * | Champ UBL | Règle | Liste | `9932` (GB) admis ? |\n * | -- | -- | -- | -- |\n * | `cbc:EndpointID/@schemeID` | `BR-CL-25` | CEF **EAS** (104 valeurs) | ✅ oui |\n * | `cac:PartyIdentification/cbc:ID/@schemeID` | `BR-CL-10` | ISO 6523 **ICD** (243 valeurs) | ⛔ non |\n *\n * ⚠️ `PEPPOL_ICD_CODES`, dans le module voisin, porte « ICD » dans son nom mais\n * contient les `99xx` : c'est la liste EAS. Ne pas s'en servir pour juger\n * `BR-CL-10` — le nom ment, la constante ci-dessous ne ment pas.\n *\n * ## Pourquoi cette constante existe (GPR-1110)\n *\n * Mesuré le 2026-08-20 par `POST /v1/validate/ubl`, sur ce que NOTRE constructeur\n * produit : un vendeur `9932` (GB), `9935` (IE) ou `9930` (DE USt-IdNr) recevait\n * `BR-CL-10` **fatale**, localisée sur\n * `/Invoice/AccountingSupplierParty/Party/PartyIdentification/ID`. Les témoins\n * `0208` (BE) et `0204` (DE) ne la recevaient pas. Le défaut est indépendant du\n * découpage que ce ticket corrige par ailleurs : il frappait DÉJÀ la forme\n * numérique, et aucun des 1038 tests du paquet ne pouvait le voir.\n *\n * La conduite qui en découle est celle que la spec `BT-29` prescrit et que le tir\n * réseau de GPR-1102 avait déjà mesurée : `9932` et `9935` n'apparaissent ni en\n * BT-29 ni en BT-30, seulement en BT-31. Un scheme hors de cette liste ne\n * s'écrit donc PAS en `PartyIdentification` — le champ est optionnel, et\n * l'omettre est la seule écriture conforme.\n *\n * ## Provenance\n *\n * Extraite mécaniquement de l'énumération littérale de `BR-CL-10` dans\n * `console/src/lib/api/peppol-schematron/CEN-EN16931-UBL.sch` (rulebook Peppol\n * `v3.0.21`, empreinte gravée dans son `manifest.ts`). 243 valeurs, `0002`–`0248`,\n * avec quatre trous réels (`0092`, `0103`, `0181`, `0182`) — d'où une liste\n * explicite et non une plage.\n *\n * ⛔ **Ne jamais éditer à la main — la régénérer depuis le `.sch`.** Le verrou de\n * dérive vit auprès de l'artefact, dans\n * `console/src/lib/api/peppol-schematron/__tests__/`.\n */\n/**\n * ⛔ `ReadonlySet` est un type, pas une garantie de runtime : un `Set` exporté\n * reste mutable pour qui le reçoit, et celui-ci PILOTE directement l'XML émis.\n * Mesuré (GPR-1110) : un simple `ISO6523_ICD_CODES.add(\"9932\")` chez le\n * consommateur suffisait à faire écrire un `PartyIdentification schemeID=\"9932\"`,\n * fatal sous `BR-CL-10`, dans un document jusque-là conforme. Le paquet est\n * PUBLIÉ — la seule frontière qui tienne est celle qu'on impose au runtime.\n */\nconst ICD_CODES = new Set([\n \"0002\", \"0003\", \"0004\", \"0005\", \"0006\", \"0007\", \"0008\", \"0009\", \"0010\",\n \"0011\", \"0012\", \"0013\", \"0014\", \"0015\", \"0016\", \"0017\", \"0018\", \"0019\",\n \"0020\", \"0021\", \"0022\", \"0023\", \"0024\", \"0025\", \"0026\", \"0027\", \"0028\",\n \"0029\", \"0030\", \"0031\", \"0032\", \"0033\", \"0034\", \"0035\", \"0036\", \"0037\",\n \"0038\", \"0039\", \"0040\", \"0041\", \"0042\", \"0043\", \"0044\", \"0045\", \"0046\",\n \"0047\", \"0048\", \"0049\", \"0050\", \"0051\", \"0052\", \"0053\", \"0054\", \"0055\",\n \"0056\", \"0057\", \"0058\", \"0059\", \"0060\", \"0061\", \"0062\", \"0063\", \"0064\",\n \"0065\", \"0066\", \"0067\", \"0068\", \"0069\", \"0070\", \"0071\", \"0072\", \"0073\",\n \"0074\", \"0075\", \"0076\", \"0077\", \"0078\", \"0079\", \"0080\", \"0081\", \"0082\",\n \"0083\", \"0084\", \"0085\", \"0086\", \"0087\", \"0088\", \"0089\", \"0090\", \"0091\",\n \"0093\", \"0094\", \"0095\", \"0096\", \"0097\", \"0098\", \"0099\", \"0100\", \"0101\",\n \"0102\", \"0104\", \"0105\", \"0106\", \"0107\", \"0108\", \"0109\", \"0110\", \"0111\",\n \"0112\", \"0113\", \"0114\", \"0115\", \"0116\", \"0117\", \"0118\", \"0119\", \"0120\",\n \"0121\", \"0122\", \"0123\", \"0124\", \"0125\", \"0126\", \"0127\", \"0128\", \"0129\",\n \"0130\", \"0131\", \"0132\", \"0133\", \"0134\", \"0135\", \"0136\", \"0137\", \"0138\",\n \"0139\", \"0140\", \"0141\", \"0142\", \"0143\", \"0144\", \"0145\", \"0146\", \"0147\",\n \"0148\", \"0149\", \"0150\", \"0151\", \"0152\", \"0153\", \"0154\", \"0155\", \"0156\",\n \"0157\", \"0158\", \"0159\", \"0160\", \"0161\", \"0162\", \"0163\", \"0164\", \"0165\",\n \"0166\", \"0167\", \"0168\", \"0169\", \"0170\", \"0171\", \"0172\", \"0173\", \"0174\",\n \"0175\", \"0176\", \"0177\", \"0178\", \"0179\", \"0180\", \"0183\", \"0184\", \"0185\",\n \"0186\", \"0187\", \"0188\", \"0189\", \"0190\", \"0191\", \"0192\", \"0193\", \"0194\",\n \"0195\", \"0196\", \"0197\", \"0198\", \"0199\", \"0200\", \"0201\", \"0202\", \"0203\",\n \"0204\", \"0205\", \"0206\", \"0207\", \"0208\", \"0209\", \"0210\", \"0211\", \"0212\",\n \"0213\", \"0214\", \"0215\", \"0216\", \"0217\", \"0218\", \"0219\", \"0220\", \"0221\",\n \"0222\", \"0223\", \"0224\", \"0225\", \"0226\", \"0227\", \"0228\", \"0229\", \"0230\",\n \"0231\", \"0232\", \"0233\", \"0234\", \"0235\", \"0236\", \"0237\", \"0238\", \"0239\",\n \"0240\", \"0241\", \"0242\", \"0243\", \"0244\", \"0245\", \"0246\", \"0247\", \"0248\",\n]);\n\n/**\n * La vue publique : toute mutation lève au lieu d'altérer silencieusement ce que\n * le constructeur écrira. `add`/`delete`/`clear` sont neutralisés, l'itération et\n * `has` restent intacts.\n */\nexport const ISO6523_ICD_CODES: ReadonlySet<string> = Object.freeze({\n has: (v: string) => ICD_CODES.has(v),\n get size() {\n return ICD_CODES.size;\n },\n keys: () => ICD_CODES.keys(),\n values: () => ICD_CODES.values(),\n entries: () => ICD_CODES.entries(),\n forEach: (fn: (v: string, v2: string, set: ReadonlySet<string>) => void, thisArg?: unknown) =>\n ICD_CODES.forEach((v, v2) => fn.call(thisArg, v, v2, ISO6523_ICD_CODES)),\n [Symbol.iterator]: () => ICD_CODES[Symbol.iterator](),\n}) as ReadonlySet<string>;\n\n/**\n * Ce scheme peut-il légalement porter un `@schemeID` de `PartyIdentification/ID` ?\n *\n * ⚠️ Attend un code EAS **déjà canonicalisé** (`9932`, pas `GB:VAT`) : la question\n * porte sur l'appartenance à une liste, jamais sur l'orthographe. Passer une forme\n * symbolique rendrait `false` pour une raison qui n'est pas la bonne.\n */\nexport function isIso6523IcdCode(scheme: string): boolean {\n return ICD_CODES.has(scheme);\n}\n\n/**\n * Où un `cac:PartyIdentification/cbc:ID` peut apparaître, au sens de `BR-CL-10`.\n *\n * La règle discrimine par ANCÊTRE, pas seulement par code — d'où ce paramètre.\n */\nexport type PartyIdentificationContext =\n | \"AccountingSupplierParty\"\n | \"AccountingCustomerParty\"\n | \"PayeeParty\";\n\n/**\n * Ce scheme peut-il légalement porter le `@schemeID` d'un `PartyIdentification/ID`\n * dans CE contexte ?\n *\n * ⛔ `BR-CL-10` n'est PAS « le code appartient à la liste ICD ». Sa forme complète,\n * lue jusqu'au bout de l'assert dans `CEN-EN16931-UBL.sch` :\n *\n * ```\n * (schemeID ∈ liste ICD)\n * OU (schemeID = 'SEPA' ET ancêtre ∈ {AccountingSupplierParty, PayeeParty})\n * ```\n *\n * ⚠️ La clause `or` vit APRÈS les 243 codes. Une extraction qui capture la liste\n * puis juge sur elle ne la voit jamais — c'est ainsi qu'une première version de\n * ce module a traité l'appartenance ICD comme toute la règle, et jeté en silence\n * un identifiant `SEPA` que le réseau accepte. **Être plus strict que la spec est\n * l'erreur symétrique de la laisser passer, pas une prudence** (GPR-1110).\n *\n * ⭐ Mesuré le 2026-08-20 : chez le BÉNÉFICIAIRE, le préjudice est réel — un\n * `PayeeParty` n'écrit aucun `EndpointID`, donc rien d'autre ne refuse le\n * document et l'identifiant disparaît sans bruit (`conformant: true` sans lui).\n * Chez le VENDEUR il ne l'est pas : l'`EndpointID` porte le même scheme et\n * `BR-CL-25`, qui ne connaît pas `SEPA`, rend le document fatal de toute façon.\n * La règle est appliquée telle qu'elle est écrite dans les deux cas — être fidèle\n * à la spec vaut mieux qu'optimiser pour ce qu'on peut observer aujourd'hui.\n */\nexport function canCarryPartyIdentification(\n scheme: string,\n context: PartyIdentificationContext,\n): boolean {\n if (ICD_CODES.has(scheme)) return true;\n return scheme === \"SEPA\" && context !== \"AccountingCustomerParty\";\n}\n","/**\n * UBL XML Builder\n *\n * Converts our clean JSON invoice format to a Peppol BIS 3.0 UBL 2.1 structure.\n * Compliance still depends on the supplied business data; use `Peppol.toXml()`\n * for the SDK's blocking offline checks before generating XML.\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\";\nimport { parsePeppolId } from \"./peppol-id.js\";\nimport { canCarryPartyIdentification } from \"./iso6523-icd-codes.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/** VAT categories whose breakdown requires BT-120 or BT-121. */\nconst EXEMPTION_REASON_CATEGORIES = new Set([\"E\", \"AE\", \"K\", \"G\", \"O\"]);\nconst EXEMPTION_REASON_RULES: Readonly<Record<string, string>> = {\n E: \"BR-E-10\",\n AE: \"BR-AE-10\",\n K: \"BR-IC-10\",\n G: \"BR-G-10\",\n O: \"BR-O-10\",\n};\n\n/** @internal Stable, non-echoing input error used by `Peppol.toXml()`. */\nexport class UblBuilderInputError extends Error {\n constructor(\n message: string,\n public readonly field: string,\n public readonly ruleId?: string,\n ) {\n super(message);\n this.name = \"UblBuilderInputError\";\n }\n}\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\nfunction formatVatRate(vatRate: number, field: string): string {\n if (typeof vatRate !== \"number\" || !Number.isFinite(vatRate)) {\n throw new UblBuilderInputError(\"vatRate must be a finite number.\", field);\n }\n return String(vatRate);\n}\n\nfunction assertValidBaseQuantity(baseQuantity: number, field: string): void {\n if (\n typeof baseQuantity !== \"number\" ||\n !Number.isFinite(baseQuantity) ||\n baseQuantity <= 0\n ) {\n throw new UblBuilderInputError(\n \"baseQuantity must be a finite number greater than zero.\",\n field,\n \"PEPPOL-EN16931-R121\",\n );\n }\n}\n\n// GPR-1170 — the direction of an adjustment travels in the ELEMENT\n// (BG-20/21/27/28, ChargeIndicator), never in the sign: BR-CO-11/12/13 and\n// PEPPOL-EN16931-R120 sum these amounts as magnitudes. The input contract is\n// getpeppr-local (rule id \"GPR-1170\"): only `undefined` means absent, amounts\n// are finite >= 0, and every final derivation stays finite. Invalid inputs are\n// rejected at this boundary instead of being normalized away — the Storecove\n// mapper rejects the same inputs, keeping both rendering surfaces in parity.\nconst ADJUSTMENT_CONTRACT_RULE = \"GETPEPPR-ALLOWANCE-CHARGE-AMOUNT\";\nconst ADJUSTMENT_AMOUNT_MESSAGE =\n \"Allowance and charge amounts must be finite numbers greater than or equal to zero. An allowance reduces the amount and a charge increases it; encode the direction in the field, never in the sign.\";\n\n// GPR-1170 — individually finite inputs can overflow once summed; every final\n// derivation must be finite before it is rendered or sent.\nconst DERIVED_AMOUNT_CONTRACT_RULE = \"GETPEPPR-DERIVED-AMOUNT\";\nconst NON_FINITE_DERIVED_AMOUNT_MESSAGE =\n \"Derived amount is not finite (overflow). Reduce quantities, prices or adjustment amounts so every total stays representable.\";\n\n// A monetary amount is deliverable only if it survives the cents scaling the\n// delivery pipeline actually performs (the provider-side 2-decimal rounding).\nfunction survivesCents(value: number): boolean {\n return Number.isFinite(value) && Number.isFinite(value * 100);\n}\n\nfunction assertValidAdjustmentAmounts(\n items: unknown,\n field: string,\n): void {\n // Only `undefined` means absent; `null` is a malformed form.\n if (items === undefined) return;\n if (!Array.isArray(items)) {\n throw new UblBuilderInputError(\n `${field} must be an array — omit the field instead of sending ${items === null ? \"null\" : typeof items}`,\n field,\n ADJUSTMENT_CONTRACT_RULE,\n );\n }\n for (const [i, item] of items.entries()) {\n const amount = (item as { amount?: unknown } | null)?.amount;\n if (\n item === null ||\n typeof item !== \"object\" ||\n typeof amount !== \"number\" ||\n !Number.isFinite(amount) ||\n amount < 0\n ) {\n throw new UblBuilderInputError(ADJUSTMENT_AMOUNT_MESSAGE, `${field}[${i}].amount`, ADJUSTMENT_CONTRACT_RULE);\n }\n }\n}\n\nfunction assertDocumentAdjustmentAmounts(input: InvoiceInput | CreditNoteInput): void {\n for (const [i, line] of input.lines.entries()) {\n assertValidAdjustmentAmounts(line.allowances, `lines[${i}].allowances`);\n assertValidAdjustmentAmounts(line.charges, `lines[${i}].charges`);\n }\n assertValidAdjustmentAmounts((input as InvoiceInput).allowances as unknown, \"allowances\");\n assertValidAdjustmentAmounts((input as InvoiceInput).charges as unknown, \"charges\");\n}\n\nfunction formatBaseQuantity(baseQuantity: number, field: string): string {\n assertValidBaseQuantity(baseQuantity, field);\n\n const numeric = String(baseQuantity);\n const exponentMarker = numeric.search(/[eE]/);\n if (exponentMarker === -1) return numeric;\n\n const coefficient = numeric.slice(0, exponentMarker);\n const exponent = Number(numeric.slice(exponentMarker + 1));\n const decimalPoint = coefficient.indexOf(\".\");\n const digits = coefficient.replace(\".\", \"\");\n const integerDigits = decimalPoint === -1 ? coefficient.length : decimalPoint;\n const outputPoint = integerDigits + exponent;\n\n if (outputPoint <= 0) {\n return `0.${\"0\".repeat(-outputPoint)}${digits}`;\n }\n if (outputPoint >= digits.length) {\n return `${digits}${\"0\".repeat(outputPoint - digits.length)}`;\n }\n return `${digits.slice(0, outputPoint)}.${digits.slice(outputPoint)}`;\n}\n\n/** Peppol monetary rounding shared with the gateway mapper. */\nexport function roundUblCurrencyAmount(value: number): number {\n const rounded = Math.round((value + Math.sign(value) * Number.EPSILON) * 100) / 100;\n return Object.is(rounded, -0) ? 0 : rounded;\n}\n\nfunction normalizedTaxExemptReason(vatCategory: string, reason: string | undefined): string | undefined {\n if (!EXEMPTION_REASON_CATEGORIES.has(vatCategory) || typeof reason !== \"string\") {\n return undefined;\n }\n const normalized = reason.trim();\n for (const character of normalized) {\n const codePoint = character.codePointAt(0)!;\n const allowed =\n codePoint === 0x09 ||\n codePoint === 0x0a ||\n codePoint === 0x0d ||\n (codePoint >= 0x20 && codePoint <= 0xd7ff) ||\n (codePoint >= 0xe000 && codePoint <= 0xfffd) ||\n (codePoint >= 0x10000 && codePoint <= 0x10ffff);\n if (!allowed) {\n throw new UblBuilderInputError(\n \"taxExemptReason contains an invalid XML character.\",\n \"taxExemptReason\",\n );\n }\n }\n return normalized || undefined;\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 ${\n // ⛔ DEUX listes, pas une. `BR-CL-25` juge l'EndpointID ci-dessus contre la\n // liste EAS (104 valeurs, jusqu'à `9959`) ; `BR-CL-10` juge CE champ-ci\n // contre la liste ISO 6523 ICD (243 valeurs, `0002`–`0248`). `9932` (GB),\n // `9935` (IE) et `9930` (DE) sont légaux là-haut et FATALS ici.\n //\n // Le champ (BT-29) est optionnel : l'omettre est la seule écriture\n // conforme pour ces schemes, et c'est ce que le tir réseau de GPR-1102\n // avait déjà mesuré — `9932`/`9935` n'apparaissent ni en BT-29 ni en\n // BT-30, seulement en BT-31. Émettre quand même rendait `BR-CL-10` fatale\n // pour tout vendeur britannique, irlandais ou allemand en `9930`,\n // y compris en écrivant la forme numérique (GPR-1110).\n //\n // ⚠️ BR-CO-26 exige alors qu'un autre identifiant porte l'expéditeur —\n // `vatNumber` (BT-31) ou `companyId` (BT-30) ci-dessous. `validateInvoice`\n // AVERTIT quand il n'y en a aucun ; il ne refuse pas, et `toXml()` rend\n // donc bel et bien un document que le réseau rejettera. C'est délibéré :\n // `from` est déclaré « deprecated and ignored » à l'envoi, où l'expéditeur\n // vient de la clé API — bloquer ici casserait des appelants dont le\n // document part très bien.\n canCarryPartyIdentification(endpointScheme, role)\n ? `<cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(endpointScheme)}\">${escapeXml(endpointId)}</cbc:ID>\n </cac:PartyIdentification>`\n : \"\"\n }\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 ${\n // Même règle qu'au-dessus : `BR-CL-10` a pour contexte TOUT\n // `cac:PartyIdentification/cbc:ID[@schemeID]`, PayeeParty compris. Le\n // bénéficiaire (BT-60) reste identifié par son nom, toujours émis.\n canCarryPartyIdentification(scheme, \"PayeeParty\")\n ? `<cac:PartyIdentification>\n <cbc:ID schemeID=\"${escapeXml(scheme)}\">${escapeXml(id)}</cbc:ID>\n </cac:PartyIdentification>`\n : \"\"\n }\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>${escapeXml(vatCategory)}</cbc:ID>\n ${vatCategory === \"O\" ? \"\" : `<cbc:Percent>${formatVatRate(item.vatRate, \"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, lineIndex: number): number {\n // PEPPOL-EN16931-R120: BT-131 = quantity × (BT-146 / BT-149) + charges − allowances.\n if (line.baseQuantity !== undefined) {\n assertValidBaseQuantity(line.baseQuantity, `lines[${lineIndex}].baseQuantity`);\n }\n const base = (line.quantity * line.unitPrice) / (line.baseQuantity ?? 1);\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 const total = base - lineAllowances + lineCharges;\n // GPR-1170 — individually finite inputs can still overflow once summed\n // (two 1e308 charges). A non-finite BT-131 must never be rendered.\n if (!survivesCents(total)) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n `lines[${lineIndex}]`,\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\n return total;\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, index);\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>${escapeXml(vatCategory)}</cbc:ID>\n ${vatCategory === \"O\" ? \"\" : `<cbc:Percent>${formatVatRate(line.vatRate, \"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 !== undefined ? `<cbc:BaseQuantity unitCode=\"${escapeXml(resolveUnitCode(line.baseQuantityUnit ?? line.unit ?? DEFAULT_UNIT))}\">${formatBaseQuantity(line.baseQuantity, `lines[${index}].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 taxExemptReason?: string;\n taxableAmount: number;\n taxAmount: number;\n}\n\nfunction calculateTaxSubtotals(\n lines: InvoiceLine[],\n allowances?: AllowanceCharge[],\n charges?: AllowanceCharge[],\n options: { forUbl?: boolean } = {},\n): TaxSubtotal[] {\n const groups = new Map<string, TaxSubtotal>();\n\n function addToGroup(\n vatCategory: string,\n vatRate: number,\n amount: number,\n taxExemptReason?: string,\n field = \"taxExemptReason\",\n ) {\n if (typeof vatCategory !== \"string\") {\n throw new UblBuilderInputError(\"vatCategory must be a string.\", `${field}.vatCategory`);\n }\n formatVatRate(vatRate, `${field}.vatRate`);\n // BR-O-05/06/07 omit the rate entirely; treating every supplied O rate as\n // the same zero-tax group also prevents duplicate O breakdowns.\n if (options.forUbl && vatCategory === \"O\" && vatRate !== 0) {\n throw new UblBuilderInputError(\n \"Category O must use vatRate 0 in SDK input.\",\n `${field}.vatRate`,\n );\n }\n const effectiveVatRate = options.forUbl && vatCategory === \"O\" ? 0 : vatRate;\n const reason = options.forUbl\n ? normalizedTaxExemptReason(vatCategory, taxExemptReason)\n : undefined;\n const key = `${vatCategory}-${effectiveVatRate}`;\n const existing = groups.get(key);\n if (existing) {\n if (reason && existing.taxExemptReason && reason !== existing.taxExemptReason) {\n throw new UblBuilderInputError(\n `Conflicting taxExemptReason values for VAT group ${vatCategory}/${effectiveVatRate}.`,\n \"taxExemptReason\",\n );\n }\n existing.taxExemptReason ??= reason;\n existing.taxableAmount += amount;\n } else {\n groups.set(key, {\n vatRate: effectiveVatRate,\n vatCategory,\n taxExemptReason: reason,\n taxableAmount: amount,\n taxAmount: 0, // computed once per group below (BR-CO-17)\n });\n }\n }\n\n for (const [index, line] of lines.entries()) {\n addToGroup(\n line.vatCategory ?? \"S\",\n line.vatRate,\n calculateLineExtensionAmount(line, index),\n line.taxExemptReason,\n `lines[${index}]`,\n );\n }\n\n for (const [index, a] of (allowances ?? []).entries()) {\n addToGroup(a.vatCategory ?? \"S\", a.vatRate, -a.amount, a.taxExemptReason, `allowances[${index}]`);\n }\n\n for (const [index, c] of (charges ?? []).entries()) {\n addToGroup(c.vatCategory ?? \"S\", c.vatRate, c.amount, c.taxExemptReason, `charges[${index}]`);\n }\n\n if (options.forUbl) {\n for (const subtotal of groups.values()) {\n if (EXEMPTION_REASON_CATEGORIES.has(subtotal.vatCategory) && !subtotal.taxExemptReason) {\n throw new UblBuilderInputError(\n `VAT category ${subtotal.vatCategory} requires a non-empty taxExemptReason.`,\n \"taxExemptReason\",\n EXEMPTION_REASON_RULES[subtotal.vatCategory],\n );\n }\n }\n }\n\n // BR-CO-17: BT-117 = round(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 const taxableAmount = roundUblCurrencyAmount(subtotal.taxableAmount);\n const taxAmount = roundUblCurrencyAmount(taxableAmount * (subtotal.vatRate / 100));\n // GPR-1170 — every grouped derivation must stay finite; a FINITE taxable\n // can still overflow once its rate is applied.\n if (!survivesCents(taxableAmount) || !survivesCents(taxAmount)) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n \"totals\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\n return { ...subtotal, taxableAmount, taxAmount };\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 options: { forUbl?: boolean } = {},\n): DocumentTotals {\n const taxSubtotals = calculateTaxSubtotals(lines, allowances, charges, options);\n const lineExtensionAmount = lines.reduce(\n (sum, line, index) => sum + calculateLineExtensionAmount(line, index),\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 = roundUblCurrencyAmount(\n lineExtensionAmount - allowanceTotalAmount + chargeTotalAmount,\n );\n // GPR-1170 — the aggregate derivations must stay finite too:\n // line nets can each be fine while their document totals overflow.\n if (\n !survivesCents(allowanceTotalAmount) ||\n !survivesCents(chargeTotalAmount) ||\n !survivesCents(taxExclusiveAmount)\n ) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n \"totals\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\n const totalTax = roundUblCurrencyAmount(\n taxSubtotals.reduce((sum, st) => sum + st.taxAmount, 0),\n );\n const taxInclusiveAmount = roundUblCurrencyAmount(taxExclusiveAmount + totalTax);\n // GPR-1170 — ALL final derivations are checked explicitly (BR-CO-15 chain):\n // every subtotal is finite but their sum (or the addition below) can still\n // overflow. Nothing non-finite is rendered.\n if (!survivesCents(totalTax) || !survivesCents(taxInclusiveAmount)) {\n throw new UblBuilderInputError(\n NON_FINITE_DERIVED_AMOUNT_MESSAGE,\n \"totals\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n );\n }\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>${escapeXml(st.vatCategory)}</cbc:ID>\n ${st.vatCategory === \"O\" ? \"\" : `<cbc:Percent>${formatVatRate(st.vatRate, \"vatRate\")}</cbc:Percent>`}\n ${st.taxExemptReason ? `<cbc:TaxExemptionReason>${escapeXml(st.taxExemptReason)}</cbc:TaxExemptionReason>` : \"\"}\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 = roundUblCurrencyAmount(totalTax * rate);\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 (the shared currency rounder 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/** The two distinct legal totals rendered in `cac:LegalMonetaryTotal`. */\nexport interface UblMonetaryAmounts {\n /** BT-112 — document total including VAT; prepaid/rounding do not change it. */\n taxInclusiveAmount: number;\n /** BT-115 — amount due after prepaid amount and payable rounding. */\n payableAmount: number;\n}\n\n/**\n * BT-112 and BT-115 from the same calculation used by the Invoice and CreditNote\n * XML builders. Consumers that need both totals must call this projection once,\n * rather than maintaining a second partial formula for the display amount.\n */\nexport function computeUblMonetaryAmounts(input: UblMonetaryInput): UblMonetaryAmounts {\n const totals = calculateDocumentTotals(input.lines, input.allowances, input.charges);\n return {\n taxInclusiveAmount: totals.taxInclusiveAmount,\n payableAmount: payableFromTaxInclusive(\n totals.taxInclusiveAmount,\n input.prepaidAmount,\n input.roundingAmount,\n ),\n };\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 return computeUblMonetaryAmounts(input).payableAmount;\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 UBL 2.1 Invoice XML from a simple JSON input.\n *\n * This low-level builder does not run the full Peppol rulebook. Compliance is\n * conditional on the input (for example, BuyerReference or OrderReference is\n * required, and exempt VAT breakdowns need `taxExemptReason`). Prefer\n * `Peppol.toXml()` when blocking SDK validation is required before rendering.\n */\nexport function buildInvoiceXml(input: InvoiceInput): string {\n assertDocumentAdjustmentAmounts(input);\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, { forUbl: true });\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 UBL 2.1 Credit Note XML.\n * Compliance is conditional on the business data; see `buildInvoiceXml`.\n *\n * Generates XML directly with correct CreditNote elements — no string replacement.\n */\nexport function buildCreditNoteXml(input: CreditNoteInput): string {\n assertDocumentAdjustmentAmounts(input);\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, { forUbl: true });\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 * GPR-1267 — these IDs are getpeppr-local advisory codes. They are NOT\n * Peppol/EN 16931 rule numbers, and none of them exists in the graved\n * rulebooks (`validator-rule-ids.test.ts` enforces the non-collision), so a\n * developer looking one up finds our docs, not a foreign rule.\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 // ⛔ GPR-1199 — Sweden is deliberately absent, buyer side AND seller side, and\n // the playbook requires the decision be written rather than left to silence.\n //\n // Every one of the thirteen `SE-R-*` assertions — the seven fatal ones and the\n // six payment-means warnings — takes its SUBJECT from\n // `//cac:AccountingSupplierParty`, read verbatim from the versioned rulebook\n // (Peppol v3.0.20, `PEPPOL-EN16931-UBL.sch` l. 643-695) on 2026-08-27.\n //\n // ⚠️ ONE context also mentions the customer, and saying \"not one judges the\n // customer\" would be too broad: `SE-R-012` (warning, domestic credit transfer)\n // reads `//cac:AccountingCustomerParty/…/IdentificationCode = 'SE'` — but as a\n // DOMESTICITY CONDITION, never as the thing being judged. What it asserts is\n // still the supplier's `cac:PaymentMeans`.\n //\n // The conclusion is unchanged: no `SE-R-*` rule places a requirement ON the\n // buyer. A buyer-side warning here would assert a Swedish requirement against\n // a party the Swedish rulebook asks nothing of — the\n // two-correct-rules-that-contradict shape of GPR-1109, manufactured on purpose.\n //\n // The seller side is closed for a different reason: `SE-R-004`/`-013` judge the\n // `CompanyID` the Swedish cartridge INJECTS from the registered\n // organisationsnummer, not anything `input.from` carries. A warning on\n // `from.companyId` would fire on a field the gateway overrides, which is worse\n // than no warning — it teaches a rule that is not the one being applied.\n //\n // What a Swedish sender actually gets is upstream of this file: an actionable\n // 422 naming `SE-R-003` when no orgnr is registered, and the format check the\n // add-identifier modal now runs (`peppol-identifier-rules.ts`, `0007`).\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 and HRK are GONE (GPR-1205). Neither is in BR-CL-04/BR-CL-05 of the\n // graved 3.0.21 rulebooks — Bulgaria and Croatia both joined the euro — so\n // accepting them here would wave through a document the network refuses, which\n // is the exact failure this release closes. XCG replaces ANG (never carried\n // here) for the Dutch Caribbean. `currency-codes-network-parity.test.ts` reds\n // if this table ever readmits a code the rulebooks reject.\n [\"XCG\", { code: \"XCG\", name: \"Caribbean Guilder\", 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 sorted by code.\n *\n * @returns Array of payment means codes\n */\nexport function getPaymentMeansCodes(): PaymentMeansCode[] {\n return [...PAYMENT_MEANS_CODES];\n}\n\n// ─── Invoice type codes (UNTDID 1001, BR-CL-01) ──────────────────────────────\n\n/**\n * GPR-1234 — les DEUX vocabulaires de BR-CL-01, verbatim du rulebook gravé.\n *\n * Jusqu'ici `validator.ts` décidait sur une liste écrite à la main de 7 codes,\n * publiée telle quelle dans `openapi.yaml`. Or BR-CL-01 — fatale — définit deux\n * vocabulaires DISJOINTS : 50 codes pour `<cbc:InvoiceTypeCode>`, 13 pour\n * `<cbc:CreditNoteTypeCode>` (seul `81` figure dans les deux). La liste unique\n * décrivait comme valides 6 codes illégaux pour un avoir, et refusait 44 codes\n * légaux pour une facture — dont `326` (facture partielle), que `DE-R-017`\n * cite nommément dans le même rulebook. Approximer une liste externe est le\n * défaut, la lire est le correctif (même leçon que BR-CL-14) : la source est\n * `peppol-schematron/CEN-EN16931-UBL.sch` v3.0.21, et le verrou console\n * `invoice-type-codes-network-parity.test.ts` rougit au premier écart.\n */\nconst INVOICE_TYPE_CODES = [\n 71, 80, 81, 82, 84, 102, 130, 202, 203, 204, 211, 218, 219, 295, 325, 326,\n 331, 380, 382, 383, 384, 385, 386, 387, 388, 389, 390, 393, 394, 395, 456,\n 457, 471, 472, 473, 500, 501, 527, 553, 575, 623, 633, 751, 780, 817, 870,\n 875, 876, 877, 935,\n] as const;\n\n/** Les 13 codes légaux en `<cbc:CreditNoteTypeCode>` — voir `INVOICE_TYPE_CODES`. */\nconst CREDIT_NOTE_TYPE_CODES = [\n 81, 83, 261, 262, 296, 308, 381, 396, 420, 458, 502, 503, 532,\n] as const;\n\n/**\n * Any legal document type code — the UNION of both BR-CL-01 vocabularies.\n *\n * ⚠️ This type cannot express the context: `381` is legal on a credit note but\n * fatal on an invoice, `382` the reverse. Runtime validation\n * (`validateInvoice`) picks the vocabulary from `isCreditNote` — the type is\n * only the outer bound.\n */\nexport type InvoiceTypeCode =\n | (typeof INVOICE_TYPE_CODES)[number]\n | (typeof CREDIT_NOTE_TYPE_CODES)[number];\n\n/**\n * The 50 UNTDID 1001 codes BR-CL-01 allows as `<cbc:InvoiceTypeCode>`.\n *\n * @returns A fresh array — mutating the result cannot poison the vocabulary\n */\nexport function getInvoiceTypeCodes(): number[] {\n return [...INVOICE_TYPE_CODES];\n}\n\n/**\n * The 13 UNTDID 1001 codes BR-CL-01 allows as `<cbc:CreditNoteTypeCode>`.\n *\n * @returns A fresh array — mutating the result cannot poison the vocabulary\n */\nexport function getCreditNoteTypeCodes(): number[] {\n return [...CREDIT_NOTE_TYPE_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, getCreditNoteTypeCodes, getInvoiceTypeCodes } from \"./code-lists.js\";\nimport { parsePeppolId, isWellFormedPeppolId } from \"./peppol-id.js\";\nimport { canCarryPartyIdentification } from \"./iso6523-icd-codes.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\n// GPR-1170 — stable public contract identifiers for the allowance/charge\n// amount contract (getpeppr-local; NOT Peppol rule numbers, NOT ticket ids).\nconst ALLOWANCE_CHARGE_CONTRACT_RULE = \"GETPEPPR-ALLOWANCE-CHARGE-AMOUNT\";\nconst DERIVED_AMOUNT_CONTRACT_RULE = \"GETPEPPR-DERIVED-AMOUNT\";\n\n// GPR-1267 — the same convention for the checks that have NO official rule to\n// cite. A ruleId matching /BR-/ or /PEPPOL-/ is a promise that the rulebook\n// contains that identifier AND that it says what the error says; both .sch\n// rulebooks are the arbiter (validator-rule-ids.test.ts enforces both halves).\nconst BUYER_ADDRESS_DELIVERY_RULE = \"GETPEPPR-BUYER-ADDRESS\";\nconst LINE_VAT_RATE_RULE = \"GETPEPPR-LINE-VAT-RATE\";\nconst TAX_CURRENCY_RATE_RULE = \"GETPEPPR-TAX-CURRENCY-RATE\";\n\n// A monetary amount is deliverable only if it survives the cents scaling the\n// delivery pipeline actually performs (the provider-side 2-decimal rounding).\nfunction survivesCents(value: number): boolean {\n return Number.isFinite(value) && Number.isFinite(value * 100);\n}\n\nfunction validateParty(party: Party, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // GPR-1267 — `validateParty` is called for the BUYER only (validator.ts, the\n // single `validateParty(input.to, \"to\")` site), and the official engine\n // renders BR-07 for a missing buyer name. BR-06 is the SELLER name rule;\n // citing it here sent developers reading about bank accounts' neighbour\n // instead of their own error. Verified against the graved CEN rulebook.\n if (party.name === undefined || party.name === null || party.name === \"\") {\n errors.push(error(`${path}.name`, \"Business name is required\", \"BR-07\"));\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-07\"));\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 (!isWellFormedPeppolId(party.peppolId)) {\n // ⛔ Ni « contient un `:` » ni « deux segments non vides » ne suffisent : le\n // contrôle vit dans `isWellFormedPeppolId`, qui juge le couple réellement\n // produit. Les trois sites qui acceptent un `peppolId` l'appellent — un\n // renforcement posé sur un seul d'entre eux laisse les autres ouverts, et\n // c'est ce qui s'est produit (GPR-1110, relevé par gate).\n errors.push(\n error(\n `${path}.peppolId`,\n `Invalid Peppol ID format: \"${party.peppolId}\"`,\n undefined,\n 'Must be \"scheme:id\" — e.g. \"0208:0685660237\" or \"GB:VAT:123456789\". The scheme alone (\"GB:VAT\") is not an identifier.'\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/**\n * Validate buyer postal address — required by Peppol BIS 3.0 (BG-8) and Storecove\n *\n * GPR-1267 — the address elements carry `GETPEPPR-BUYER-ADDRESS`, not a BR id.\n * Measured against the graved rulebooks: universally, EN 16931 requires only\n * that the address EXISTS (BR-10) with a country code (BR-11) — the official\n * engine accepts each element omitted alone. NL-R-002/004/006 mandate\n * street/city/postal code, but only for NL parties. This SDK check is the\n * getpeppr delivery contract (Storecove refuses a partial address for any\n * country), so it must not borrow a BR identifier: BR-50/51/53 are the payment\n * account, card-number truncation and accounting-currency rules.\n */\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\", BUYER_ADDRESS_DELIVERY_RULE,\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\", BUYER_ADDRESS_DELIVERY_RULE,\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\", BUYER_ADDRESS_DELIVERY_RULE,\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\", BUYER_ADDRESS_DELIVERY_RULE,\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\", BUYER_ADDRESS_DELIVERY_RULE,\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\", BUYER_ADDRESS_DELIVERY_RULE,\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.baseQuantity !== undefined) {\n if (\n typeof line.baseQuantity !== \"number\" ||\n !Number.isFinite(line.baseQuantity) ||\n line.baseQuantity <= 0\n ) {\n errors.push(\n error(\n `${path}.baseQuantity`,\n \"Base quantity must be a finite number greater than zero\",\n \"PEPPOL-EN16931-R121\",\n \"Use a positive number for the item price base quantity\",\n )\n );\n }\n }\n\n if (line.vatRate === undefined || line.vatRate === null) {\n // GPR-1267 — no universal rulebook rule mandates a rate on a LINE (UBL lines\n // carry no rate at all; the breakdown does). BR-CO-17 is the BT-117\n // equation and never demanded this input, so the requirement — the SDK's\n // input model feeding the VAT breakdown — carries its own id.\n errors.push(error(`${path}.vatRate`, \"VAT rate is required\", LINE_VAT_RATE_RULE));\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 // GPR-1170 — the direction of an allowance/charge travels in the field, never\n // in the sign (the Peppol equations BR-CO-11/12/13 and R120 describe how the\n // amounts are summed; the input contract itself is getpeppr-local, rule ids\n // GETPEPPR-ALLOWANCE-CHARGE-AMOUNT / GETPEPPR-DERIVED-AMOUNT). Only\n // `undefined` means absent; a negative or non-finite amount flips the\n // semantic and is rejected instead of being normalized away — the Storecove\n // mapper rejects the same inputs, keeping both surfaces in parity.\n const adjustmentItems: Record<\"allowances\" | \"charges\", Array<{ amount?: unknown } | null>> = {\n allowances: Array.isArray(line.allowances) ? line.allowances : [],\n charges: Array.isArray(line.charges) ? line.charges : [],\n };\n for (const kind of [\"allowances\", \"charges\"] as const) {\n const items = line[kind] as unknown;\n if (items === undefined) continue;\n if (!Array.isArray(items)) {\n errors.push(error(\n `${path}.${kind}`,\n `${kind} must be an array — omit the field instead of sending ${items === null ? \"null\" : typeof items}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n ));\n continue;\n }\n for (const [i, item] of items.entries()) {\n const amount = (item as { amount?: unknown } | null)?.amount;\n if (typeof amount !== \"number\" || !Number.isFinite(amount) || amount < 0) {\n errors.push(\n error(\n `${path}.${kind}[${i}].amount`,\n `Allowance and charge amounts must be zero or positive finite numbers, got ${String(amount)}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n \"An allowance reduces the amount and a charge increases it — encode the direction in the field, never in the sign.\"\n )\n );\n }\n }\n }\n\n // GPR-1170 — individually finite inputs can overflow once summed; BOTH final\n // derivations of the line (net and its VAT share) must stay representable.\n const bq = typeof line.baseQuantity === \"number\" && line.baseQuantity > 0 ? line.baseQuantity : 1;\n const derivedNet =\n (line.quantity ?? 0) * (line.unitPrice ?? 0) / bq -\n adjustmentItems.allowances.reduce((sum, a) => sum + ((a as { amount?: number })?.amount ?? 0), 0) +\n adjustmentItems.charges.reduce((sum, c) => sum + ((c as { amount?: number })?.amount ?? 0), 0);\n const derivedVat = derivedNet * ((typeof line.vatRate === \"number\" ? line.vatRate : 0) / 100);\n if (!survivesCents(derivedNet) || !survivesCents(derivedVat)) {\n errors.push(\n error(\n path,\n \"Derived amount is not finite (overflow). Reduce quantities, prices or adjustment amounts so every total stays representable.\",\n DERIVED_AMOUNT_CONTRACT_RULE,\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 (BR-CL-01) ──\n //\n // GPR-1234 — la règle est CONTEXTUELLE : 50 codes sont légaux en\n // `<cbc:InvoiceTypeCode>`, 13 autres en `<cbc:CreditNoteTypeCode>`.\n // `ubl-builder.ts` écrit l'un ou l'autre élément selon `isCreditNote`, donc\n // le vocabulaire qui décide suit le même discriminateur. L'ancienne liste\n // unique de 7 codes laissait passer 381 sur une facture et refusait 382/326\n // qui y sont légaux.\n if (input.invoiceTypeCode != null) {\n const isCreditNote = input.isCreditNote === true;\n const legalCodes = isCreditNote ? getCreditNoteTypeCodes() : getInvoiceTypeCodes();\n if (!legalCodes.includes(input.invoiceTypeCode)) {\n errors.push(\n error(\n \"invoiceTypeCode\",\n `Invalid ${isCreditNote ? \"credit note\" : \"invoice\"} type code: ${input.invoiceTypeCode}`,\n \"BR-CL-01\",\n `Valid ${isCreditNote ? \"credit note\" : \"invoice\"} type codes: ${legalCodes.join(\", \")}`\n )\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 // GPR-1110 — le corollaire de l'omission décidée dans `ubl-builder.ts`.\n //\n // Un scheme hors liste ISO 6523 ICD (`9932` GB, `9935` IE, `9930` DE…) ne peut\n // pas s'écrire en `PartyIdentification/ID` : `BR-CL-10` y est fatale. Le champ\n // est donc omis, et avec lui BT-29 — il faut alors que BT-30 (`companyId`) ou\n // BT-31 (`vatNumber`) porte l'expéditeur, sans quoi `BR-CO-26` tombe.\n //\n // ⚠️ AVERTISSEMENT et non erreur : `from` est déclaré ignoré trois lignes\n // au-dessus, donc à l'envoi ce champ ne décide de rien. Le seul chemin où ce\n // XML compte est `toXml()` — « manual submission » — et y bloquer un appelant\n // dont l'envoi normal fonctionne serait une régression de contrat.\n //\n // Mesuré le 2026-08-20 (`POST /v1/validate/ubl`) : une facture GB sans TVA\n // rend `BR-S-02` ET `BR-CO-26`, deux fatales. La même avec `vatNumber` rend\n // `conformant: true`.\n // ⚠️ Pas de garde `includes(\":\")` ici : un `peppolId` dépourvu de `:` est\n // malformé, et c'est précisément le cas où l'avertissement est le plus utile.\n // `parsePeppolId` le gère (scheme canonicalisé, valeur vide) plutôt que de\n // lever, donc filtrer en amont ne ferait que rendre la garde muette là où le\n // document est le plus sûrement refusé.\n const fromId = input.from.peppolId;\n // (`!== \"\"` est refusé par TS : le type littéral `${string}:${string}` exclut\n // la chaîne vide, que seul un appelant JavaScript peut fournir.)\n if (typeof fromId === \"string\" && fromId.length > 0) {\n const { scheme } = parsePeppolId(fromId);\n const bt29Written = canCarryPartyIdentification(scheme, \"AccountingSupplierParty\");\n if (!bt29Written && !input.from.vatNumber && !input.from.companyId) {\n warnings.push(\n warning(\n \"from.peppolId\",\n `Scheme \"${scheme}\" cannot carry a seller identifier (BT-29), so that field is omitted. Add a vatNumber (BT-31) or companyId (BT-30), or the network will reject the document under BR-CO-26.`,\n \"BR-CO-26\",\n )\n );\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 // Le TROISIÈME site, et celui qu'un renforcement posé sur `validateParty`\n // laisse ouvert : le bénéficiaire a sa propre validation (GPR-1110).\n } else if (!isWellFormedPeppolId(ppId)) {\n errors.push(\n error(\n \"payeeParty.peppolId\",\n `Invalid Peppol ID format: \"${ppId}\"`,\n undefined,\n 'Must be \"scheme:id\" — e.g. \"0208:0685660237\". The scheme alone (\"GB:VAT\") is not an identifier.'\n )\n );\n }\n }\n\n const linesValue = input.lines as unknown;\n if (!Array.isArray(linesValue)) {\n errors.push(error(\"lines\", \"Line items must be an array\", undefined));\n } else if (linesValue.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 (const [i, line] of linesValue.entries()) {\n if (line === null || typeof line !== \"object\") {\n errors.push(error(`lines[${i}]`, `Line item ${i} must be an object`, undefined));\n continue;\n }\n errors.push(...validateLine(line as InvoiceLine, i, input.isCreditNote));\n }\n }\n\n for (const field of [\"allowances\", \"charges\"] as const) {\n const value = input[field] as unknown;\n if (value === undefined) continue;\n if (!Array.isArray(value)) {\n errors.push(error(\n field,\n `${field} must be an array — omit the field instead of sending ${value === null ? \"null\" : typeof value}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n ));\n continue;\n }\n for (const [index, item] of value.entries()) {\n if (item === null || typeof item !== \"object\") {\n errors.push(error(`${field}[${index}]`, `${field}[${index}] must be an object`, undefined));\n continue;\n }\n // GPR-1170 — document-level adjustments follow the same input contract as\n // line-level ones (getpeppr-local; BR-CO-13 describes how BT-107/BT-108\n // are summed, it does not mandate this contract).\n const amount = (item as { amount?: unknown }).amount;\n if (typeof amount !== \"number\" || !Number.isFinite(amount) || amount < 0) {\n errors.push(\n error(\n `${field}[${index}].amount`,\n `Allowance and charge amounts must be zero or positive finite numbers, got ${String(amount)}`,\n ALLOWANCE_CHARGE_CONTRACT_RULE,\n \"An allowance reduces the amount and a charge increases it — encode the direction in the field, never in the sign.\"\n )\n );\n }\n }\n }\n\n // GPR-1170 — document totals derived from accepted inputs must stay finite\n // before rendering. Only structurally valid collections contribute to the\n // sums: a malformed shape is reported above and must never TypeError here.\n if (Array.isArray(input.lines)) {\n const itemsOf = (value: unknown): Array<{ amount?: unknown; vatRate?: unknown }> =>\n Array.isArray(value) ? value : [];\n const amountOf = (item: unknown): number =>\n typeof (item as { amount?: unknown } | null)?.amount === \"number\"\n ? (item as { amount: number }).amount\n : 0;\n const lineNets = (input.lines as InvoiceLine[]).reduce((sum, line) => {\n if (typeof line !== \"object\" || line === null) return sum;\n const lbq = typeof line.baseQuantity === \"number\" && line.baseQuantity > 0 ? line.baseQuantity : 1;\n return (\n sum +\n ((line.quantity ?? 0) * (line.unitPrice ?? 0)) / lbq -\n itemsOf(line.allowances).reduce((s, a) => s + amountOf(a), 0) +\n itemsOf(line.charges).reduce((s, c) => s + amountOf(c), 0)\n );\n }, 0);\n const allowanceTotal = itemsOf(input.allowances).reduce((s, a) => s + amountOf(a), 0);\n const chargeTotal = itemsOf(input.charges).reduce((s, c) => s + amountOf(c), 0);\n const vatOf = (items: unknown, sign: number): number => {\n if (!Array.isArray(items)) return 0;\n return items.reduce((s, it) => {\n const rec = it as { amount?: unknown; vatRate?: unknown } | null;\n const amount = typeof rec?.amount === \"number\" ? rec.amount : 0;\n const rate = typeof rec?.vatRate === \"number\" ? rec.vatRate : 0;\n return s + sign * amount * (rate / 100);\n }, 0);\n };\n const docVat =\n vatOf(input.allowances, -1) +\n vatOf(input.charges, 1) +\n (input.lines as InvoiceLine[]).reduce((s, line) => {\n if (typeof line !== \"object\" || line === null) return s;\n const lbq = typeof line.baseQuantity === \"number\" && line.baseQuantity > 0 ? line.baseQuantity : 1;\n const net = ((line.quantity ?? 0) * (line.unitPrice ?? 0)) / lbq;\n return s + net * ((typeof line.vatRate === \"number\" ? line.vatRate : 0) / 100);\n }, 0);\n if (\n !survivesCents(lineNets - allowanceTotal + chargeTotal) ||\n !survivesCents(docVat)\n ) {\n errors.push(\n error(\n \"totals\",\n \"Derived amount is not finite (overflow). Reduce quantities, prices or adjustment amounts so every total stays representable.\",\n DERIVED_AMOUNT_CONTRACT_RULE,\n )\n );\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 // GPR-1267 — PEPPOL-EN16931-R003 IS this rule: \"A buyer reference or\n // purchase order reference MUST be provided.\" BR-10 is the buyer\n // postal address.\n \"PEPPOL-EN16931-R003\"\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 // GPR-1267 — BR-53 mandates the BT-111 total in accounting currency,\n // which the builder derives itself; the client-supplied rate is an\n // input-contract requirement, not that rule.\n TAX_CURRENCY_RATE_RULE,\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 // GPR-1267 — no rulebook rule (EN 16931 or Peppol) mandates a due date, so\n // this advisory carries no ruleId at all — same shape as the buyer VAT\n // number and IBAN advisories below. BR-09 is the seller country code.\n warnings.push(warning(\"dueDate\", \"No due date specified. Recommended for payment terms.\"));\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","/**\n * Offline Schematron-like Validation\n *\n * Runs a small set of pure TypeScript pre-flight checks. Some reproduce a\n * Peppol BIS 3.0 business rule; others are explicitly GETPEPPR-local\n * diagnostics. This is NOT a full XSD/XSLT Schematron processor — it catches\n * common problems before the invoice reaches the network.\n *\n * ⛔ The registered checks counted by `coverage.rulesChecked` are exactly\n * those in `SDK_SCHEMATRON_RULE_IDS` (below), and that registry is the only\n * place the count lives. `validateSchematron()` can additionally emit the\n * legacy provider-routability diagnostic `unsupported_vat_category`, outside\n * that count. The separate VAT-only UBL-builder preflight can emit `SDK-INPUT`;\n * it does not return Schematron coverage. This header once said \"~25\" while the registry held a different\n * number — prose counts drift from one the code measures, and only the code can\n * 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 * - GETPEPPR-xx — SDK-local diagnostics with no exact network-rule equivalent\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 /** Network-rule or product-local diagnostic identifier. */\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 * Le nombre exact de contrôles enregistrés vit dans `SDK_SCHEMATRON_RULE_IDS`.\n * Le diagnostic de capacité historique `unsupported_vat_category` peut\n * apparaître en plus, hors de ce compteur.\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 from the SDK's small common-unit catalogue (lazy singleton). */\nlet _sdkUnitCodes: Set<string> | undefined;\nfunction getSdkUnitCodes(): Set<string> {\n if (!_sdkUnitCodes) {\n _sdkUnitCodes = new Set(getAllUnits().map((u) => u.code));\n }\n return _sdkUnitCodes;\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; // Caught by GETPEPPR-LINE-NET-SANITY.\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 * SDK-local notice: the issue date will default to today when omitted.\n */\nconst issueDateDefaulted: RuleFn = (input) => {\n if (!input.date) {\n return [\n violation(\n \"GETPEPPR-ISSUE-DATE-DEFAULTED\",\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 * SDK-local recommendation: a deprecated `from` payload should carry a VAT number.\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 sellerVatRecommendation: RuleFn = (input) => {\n if (input.from && !input.from.vatNumber) {\n return [\n violation(\n \"GETPEPPR-FROM-VAT-RECOMMENDED\",\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-16: An Invoice shall have at least one Invoice line.\n */\nconst br16: RuleFn = (input) => {\n if (!input.lines || input.lines.length === 0) {\n return [violation(\"BR-16\", \"error\", \"Invoice must have at least one line item.\", \"lines\")];\n }\n return [];\n};\n\n/**\n * SDK-local recommendation: provide a Payment due date or Payment terms.\n */\nconst paymentTimingRecommendation: RuleFn = (input) => {\n if (!input.dueDate && !input.paymentTerms) {\n return [\n violation(\n \"GETPEPPR-PAYMENT-TIMING-RECOMMENDED\",\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 * SDK-local recommendation: provide a Buyer reference or Order reference.\n * The official R003 has the same predicate but is fatal; this SDK check remains\n * advisory, so borrowing that identifier would overstate the verdict.\n */\nconst buyerOrOrderReferenceRecommendation: RuleFn = (input) => {\n if (!input.buyerReference && !input.orderReference) {\n return [\n violation(\n \"GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED\",\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 * SDK-local line-net sanity check. InvoiceInput has no explicit line-extension\n * total to compare as official BR-CO-10 does, so this only verifies that each\n * line computation is finite (no NaN/Infinity; valid baseQuantity).\n */\nconst lineNetSanity: 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(\"GETPEPPR-LINE-NET-SANITY\", \"error\", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`),\n );\n }\n }\n\n return violations;\n};\n\n/**\n * SDK-local sanity check for the computed VAT amount.\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 computedVatSanity: 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 GETPEPPR-LINE-NET-SANITY.\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 \"GETPEPPR-COMPUTED-VAT-SANITY\",\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 \"GETPEPPR-COMPUTED-VAT-SANITY\",\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 * SDK-local sanity check for the computed tax-inclusive amount.\n *\n * We verify the computation produces a finite, non-negative result.\n */\nconst taxInclusiveSanity: 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 \"GETPEPPR-TAX-INCLUSIVE-SANITY\",\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 \"GETPEPPR-TAX-INCLUSIVE-SANITY\",\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 * SDK-local sanity check for the computed payable amount.\n *\n * Verifies that the derived payable amount is finite and non-negative.\n */\nconst payableSanity: 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 \"GETPEPPR-PAYABLE-SANITY\",\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 \"GETPEPPR-PAYABLE-SANITY\",\n \"warning\",\n `Computed payable amount is negative (${payable.toFixed(2)}). ` +\n `Check invoice totals, prepaid amount (${prepaid}), and rounding amount (${rounding}).`,\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/** BR-G-05: Export outside the EU (G) line VAT rate shall be zero. */\nconst brG05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n for (let i = 0; i < (input.lines ?? []).length; i++) {\n const line = input.lines![i]!;\n if (line.vatCategory === \"G\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-G-05\",\n \"error\",\n `Line ${i}: export outside the EU (G) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n return violations;\n};\n\n/** BR-IC-05: Intra-community supply (K) line VAT rate shall be zero. */\nconst brIc05: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n for (let i = 0; i < (input.lines ?? []).length; i++) {\n const line = input.lines![i]!;\n if (line.vatCategory === \"K\" && line.vatRate !== 0) {\n violations.push(\n violation(\n \"BR-IC-05\",\n \"error\",\n `Line ${i}: intra-community supply (K) requires vatRate = 0, got ${line.vatRate}.`,\n `lines[${i}].vatRate`,\n ),\n );\n }\n }\n return violations;\n};\n\n/** BR-*-06/07: document allowances and charges use the category's legal rate. */\nconst documentAdjustmentVatRates: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n const configs = new Map<string, {\n allowanceRule: string;\n chargeRule: string;\n valid: (rate: number) => boolean;\n label: string;\n }>([\n [\"S\", { allowanceRule: \"BR-S-06\", chargeRule: \"BR-S-07\", valid: (rate) => rate > 0, label: \"standard rate (S)\" }],\n [\"Z\", { allowanceRule: \"BR-Z-06\", chargeRule: \"BR-Z-07\", valid: (rate) => rate === 0, label: \"zero-rated (Z)\" }],\n [\"E\", { allowanceRule: \"BR-E-06\", chargeRule: \"BR-E-07\", valid: (rate) => rate === 0, label: \"exempt (E)\" }],\n [\"AE\", { allowanceRule: \"BR-AE-06\", chargeRule: \"BR-AE-07\", valid: (rate) => rate === 0, label: \"reverse charge (AE)\" }],\n [\"G\", { allowanceRule: \"BR-G-06\", chargeRule: \"BR-G-07\", valid: (rate) => rate === 0, label: \"export outside the EU (G)\" }],\n [\"K\", { allowanceRule: \"BR-IC-06\", chargeRule: \"BR-IC-07\", valid: (rate) => rate === 0, label: \"intra-community supply (K)\" }],\n ]);\n\n const check = (\n items: InvoiceInput[\"allowances\"] | InvoiceInput[\"charges\"],\n kind: \"allowance\" | \"charge\",\n ): void => {\n (items ?? []).forEach((item, index) => {\n const category = item.vatCategory ?? \"S\";\n const config = configs.get(category);\n if (!config || config.valid(item.vatRate)) return;\n const ruleId = kind === \"allowance\" ? config.allowanceRule : config.chargeRule;\n violations.push(violation(\n ruleId,\n \"error\",\n `Document ${kind} ${index}: ${config.label} has an invalid vatRate (${item.vatRate}).`,\n `${kind === \"allowance\" ? \"allowances\" : \"charges\"}[${index}].vatRate`,\n ));\n });\n };\n\n check(input.allowances, \"allowance\");\n check(input.charges, \"charge\");\n return violations;\n};\n\ntype ExemptionCategory = \"E\" | \"AE\" | \"G\" | \"O\" | \"K\";\n\n/**\n * BR-*-10 applies to each VAT breakdown, not to every source line. Mirror the\n * builder's grouping so a line, allowance, and charge in one group yield one\n * actionable violation rather than three duplicates.\n */\nfunction exemptionReasonRule(\n vatCategory: ExemptionCategory,\n ruleId: \"BR-E-10\" | \"BR-AE-10\" | \"BR-G-10\" | \"BR-O-10\" | \"BR-IC-10\",\n label: string,\n): RuleFn {\n return (input) => {\n const groups = new Map<string, { hasReason: boolean; field: string }>();\n\n const add = (category: string | undefined, rate: number, reason: string | undefined, field: string): void => {\n if (category !== vatCategory) return;\n const effectiveRate = category === \"O\" ? 0 : rate;\n const key = `${category}-${effectiveRate}`;\n const hasReason = typeof reason === \"string\" && reason.trim().length > 0;\n const existing = groups.get(key);\n if (existing) {\n existing.hasReason ||= hasReason;\n } else {\n groups.set(key, { hasReason, field });\n }\n };\n\n (input.lines ?? []).forEach((line, index) => {\n add(line.vatCategory ?? \"S\", line.vatRate, line.taxExemptReason, `lines[${index}].taxExemptReason`);\n });\n (input.allowances ?? []).forEach((item, index) => {\n add(item.vatCategory ?? \"S\", item.vatRate, item.taxExemptReason, `allowances[${index}].taxExemptReason`);\n });\n (input.charges ?? []).forEach((item, index) => {\n add(item.vatCategory ?? \"S\", item.vatRate, item.taxExemptReason, `charges[${index}].taxExemptReason`);\n });\n\n return [...groups.values()]\n .filter((group) => !group.hasReason)\n .map((group) => violation(\n ruleId,\n \"error\",\n `${label} requires a non-empty taxExemptReason in its VAT breakdown.`,\n group.field,\n ));\n };\n}\n\nconst brE10 = exemptionReasonRule(\"E\", \"BR-E-10\", \"Exempt from VAT (E)\");\nconst brAe10 = exemptionReasonRule(\"AE\", \"BR-AE-10\", \"Reverse charge (AE)\");\nconst brG10 = exemptionReasonRule(\"G\", \"BR-G-10\", \"Export outside the EU (G)\");\nconst brO10 = exemptionReasonRule(\"O\", \"BR-O-10\", \"Not subject to VAT (O)\");\nconst brIc10 = exemptionReasonRule(\"K\", \"BR-IC-10\", \"Intra-community supply (K)\");\n\n/** BR-CL-17 only — no gateway/provider routability policy. */\nconst builderVatCategoryValidity: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n const check = (category: string | undefined, field: string): void => {\n if (category !== undefined && !VALID_VAT_CATEGORIES.has(category)) {\n violations.push(violation(\n \"BR-CL-17\",\n \"error\",\n \"VAT category is not an EN 16931 code.\",\n field,\n ));\n }\n };\n (input.lines ?? []).forEach((item, index) => check(item.vatCategory, `lines[${index}].vatCategory`));\n (input.allowances ?? []).forEach((item, index) => check(item.vatCategory, `allowances[${index}].vatCategory`));\n (input.charges ?? []).forEach((item, index) => check(item.vatCategory, `charges[${index}].vatCategory`));\n return violations;\n};\n\nconst UBL_BUILDER_VAT_RULES: readonly RuleFn[] = [\n builderVatCategoryValidity,\n brS05,\n brZ05,\n brE05,\n brAe05,\n brG05,\n brIc05,\n documentAdjustmentVatRates,\n brE10,\n brAe10,\n brG10,\n brO10,\n brIc10,\n];\n\n/**\n * The VAT-only preflight used by `Peppol.toXml()`.\n * It intentionally excludes provider-routability checks: local UBL generation\n * may validly use categories such as L/M that the getpeppr gateway cannot send.\n */\nexport function validateUblBuilderVat(input: InvoiceInput): SchematronViolation[] {\n const shapeViolations: SchematronViolation[] = [];\n const checkCollection = (value: unknown, field: \"lines\" | \"allowances\" | \"charges\"): void => {\n if (field === \"lines\" || value !== undefined) {\n if (!Array.isArray(value)) {\n shapeViolations.push(violation(\n \"SDK-INPUT\",\n \"error\",\n `${field} must be an array.`,\n field,\n ));\n return;\n }\n }\n if (!Array.isArray(value)) return;\n for (const [index, item] of value.entries()) {\n const itemField = `${field}[${index}]`;\n if (item === null || typeof item !== \"object\") {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField} must be an object.`, itemField));\n continue;\n }\n const candidate = item as { vatRate?: unknown; vatCategory?: unknown; taxExemptReason?: unknown };\n if (typeof candidate.vatRate !== \"number\" || !Number.isFinite(candidate.vatRate)) {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField}.vatRate must be a finite number.`, `${itemField}.vatRate`));\n }\n if (candidate.vatCategory !== undefined && typeof candidate.vatCategory !== \"string\") {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField}.vatCategory must be a string.`, `${itemField}.vatCategory`));\n }\n if (candidate.taxExemptReason !== undefined && typeof candidate.taxExemptReason !== \"string\") {\n shapeViolations.push(violation(\"SDK-INPUT\", \"error\", `${itemField}.taxExemptReason must be a string.`, `${itemField}.taxExemptReason`));\n }\n }\n };\n checkCollection(input.lines, \"lines\");\n checkCollection(input.allowances, \"allowances\");\n checkCollection(input.charges, \"charges\");\n if (shapeViolations.length > 0) return shapeViolations;\n\n const oRateViolations: SchematronViolation[] = [];\n const checkORates = (\n items: readonly { vatCategory?: string; vatRate: number }[] | undefined,\n field: \"lines\" | \"allowances\" | \"charges\",\n ): void => {\n (items ?? []).forEach((item, index) => {\n if (item.vatCategory === \"O\" && item.vatRate !== 0) {\n oRateViolations.push(violation(\n \"SDK-INPUT\",\n \"error\",\n `Category O must use vatRate 0 in SDK input.`,\n `${field}[${index}].vatRate`,\n ));\n }\n });\n };\n checkORates(input.lines, \"lines\");\n checkORates(input.allowances, \"allowances\");\n checkORates(input.charges, \"charges\");\n\n return [\n ...oRateViolations,\n ...UBL_BUILDER_VAT_RULES.flatMap((rule) => rule(input)),\n ];\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 * SDK-local requirement: a Buyer Peppol ID must be present and non-empty.\n * R010 only checks node existence; the SDK's predicate is deliberately broader.\n */\nconst buyerPeppolIdRequired: RuleFn = (input) => {\n if (!input.to?.peppolId) {\n return [\n violation(\n \"GETPEPPR-BUYER-PEPPOL-ID-REQUIRED\",\n \"error\",\n \"Buyer electronic address (peppolId) is required for Peppol delivery.\",\n \"to.peppolId\",\n ),\n ];\n }\n return [];\n};\n\n/** Profile 01/02 invoice codes from PEPPOL-EN16931-P0100. */\nconst PROFILE_INVOICE_TYPE_CODES: ReadonlySet<string> = new Set([\n \"71\", \"80\", \"82\", \"84\", \"102\", \"218\", \"219\", \"326\", \"331\", \"380\",\n \"382\", \"383\", \"384\", \"386\", \"388\", \"393\", \"395\", \"553\", \"575\", \"623\",\n \"780\", \"817\", \"870\", \"875\", \"876\", \"877\",\n]);\n\n/** Profile 01/02 credit-note codes from PEPPOL-EN16931-P0101. */\nconst PROFILE_CREDIT_NOTE_TYPE_CODES: ReadonlySet<string> = new Set([\n \"381\", \"396\", \"81\", \"83\", \"532\",\n]);\n\n/** XPath `normalize-space`: only the four XML whitespace characters collapse. */\nfunction normalizeXmlSpace(value: string): string {\n return value\n .replace(/[\\u0009\\u000A\\u000D\\u0020]+/g, \" \")\n .replace(/^ /, \"\")\n .replace(/ $/, \"\");\n}\n\nfunction normalizedTypeCode(value: unknown, fallback: number): string | undefined {\n if (value === undefined || value === null) return String(fallback);\n if (typeof value === \"number\" && Number.isFinite(value)) return String(value);\n if (typeof value === \"string\" && value.length <= 16) return normalizeXmlSpace(value);\n return undefined;\n}\n\nfunction normalizedCountry(value: unknown): string | undefined {\n return typeof value === \"string\" ? normalizeXmlSpace(value).toUpperCase() : undefined;\n}\n\nconst invoiceTypeCodeForProfile: RuleFn = (input) => {\n if (input.isCreditNote) return [];\n const invoiceTypeCode = normalizedTypeCode(input.invoiceTypeCode, 380);\n if (invoiceTypeCode !== undefined && PROFILE_INVOICE_TYPE_CODES.has(invoiceTypeCode)) return [];\n return [\n violation(\n \"PEPPOL-EN16931-P0100\",\n \"error\",\n \"Invoice type code is not allowed by the Peppol billing profile used by the local UBL builder.\",\n \"invoiceTypeCode\",\n ),\n ];\n};\n\nconst creditNoteTypeCodeForProfile: RuleFn = (input) => {\n if (!input.isCreditNote) return [];\n const invoiceTypeCode = normalizedTypeCode(input.invoiceTypeCode, 381);\n if (invoiceTypeCode !== undefined && PROFILE_CREDIT_NOTE_TYPE_CODES.has(invoiceTypeCode)) return [];\n return [\n violation(\n \"PEPPOL-EN16931-P0101\",\n \"error\",\n \"Credit note type code is not allowed by the Peppol billing profile used by the local UBL builder.\",\n \"invoiceTypeCode\",\n ),\n ];\n};\n\n/**\n * PEPPOL-EN16931-P0112: invoice type codes 326 and 384 are reserved for\n * domestic German documents. This mirrors the countries that the UBL builder\n * serialises from `from` and `to`; it deliberately does not infer an account\n * Legal Entity that is absent from the locally built document.\n */\nconst germanInvoiceTypeCode: RuleFn = (input) => {\n if (input.isCreditNote) return [];\n const invoiceTypeCode = normalizedTypeCode(input.invoiceTypeCode, 380);\n if (invoiceTypeCode !== \"326\" && invoiceTypeCode !== \"384\") return [];\n\n const sellerCountry = normalizedCountry(input.from?.country);\n const buyerCountry = normalizedCountry(input.to?.country);\n if (sellerCountry === \"DE\" && buyerCountry === \"DE\") return [];\n\n return [\n violation(\n \"PEPPOL-EN16931-P0112\",\n \"error\",\n \"Invoice type code 326 or 384 is only allowed when both buyer and seller are German organizations.\",\n \"invoiceTypeCode\",\n ),\n ];\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 * SDK-local unit-code diagnostic. The SDK convenience list is intentionally\n * smaller than the official Rec20/21 list, so this warning cannot claim BR-CL-23.\n */\nconst unitCodeRecognised: RuleFn = (input) => {\n const violations: SchematronViolation[] = [];\n if (!input.lines) return violations;\n\n const knownCodes = getSdkUnitCodes();\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 \"GETPEPPR-UNIT-CODE-RECOGNISED\",\n \"warning\",\n `Line ${i}: unit \"${line.unit}\" (resolved: \"${resolved}\") is not in the SDK's common unit list. ` +\n `It may still be a valid UN/ECE Rec20/21 code; network validation decides. 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 issueDateDefaulted,\n sellerVatRecommendation,\n br07,\n br16,\n paymentTimingRecommendation,\n buyerOrOrderReferenceRecommendation,\n // Calculations (BR-CO)\n lineNetSanity,\n computedVatSanity,\n taxInclusiveSanity,\n payableSanity,\n // Tax categories (one family per category)\n brS05,\n brZ05,\n brE05,\n brAe05,\n brG05,\n brIc05,\n documentAdjustmentVatRates,\n brE10,\n brAe10,\n brG10,\n brO10,\n brIc10,\n // Peppol-specific\n buyerPeppolIdRequired,\n invoiceTypeCodeForProfile,\n creditNoteTypeCodeForProfile,\n germanInvoiceTypeCode,\n vatCategoryCodes,\n unitCodeRecognised,\n];\n\n// ─── Main Validation Function ───────────────────────────────────────────────────\n\n/**\n * Validate an InvoiceInput with offline Peppol pre-flight checks.\n *\n * Runs the controls listed in `SDK_SCHEMATRON_RULE_IDS` as pure TypeScript\n * checks. Official IDs identify exact network-rule equivalents; `GETPEPPR-*`\n * IDs identify local diagnostics. No XML generation, no network calls. The\n * count is read from the registry, never written here;\n * `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/GPR-1084 — les contrôles enregistrés que ce validateur exécute.\n *\n * ⚠️ 40 contrôles enregistrés, dont 10 diagnostics explicitement locaux,\n * face aux 333+ règles que le réseau applique. Le diagnostic historique de\n * capacité `unsupported_vat_category` peut être émis en plus par\n * `validateSchematron`, sans être compté dans `coverage.rulesChecked`.\n * `SDK-INPUT` appartient au pré-contrôle distinct du builder UBL et n'entre\n * pas dans un `SchematronResult`.\n * 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 23 règles de catégorie de TVA ont été confrontées au rulebook gravé :\n * quatre ont d'abord été corrigées par GPR-1069, puis GPR-1068 a ajouté les\n * familles ligne/adjustment/motif manquantes. GPR-1084 a ensuite confronté ses\n * sept contrôles ciblés et quatre collisions adjacentes trouvées par la même\n * preuve : seul `BR-08` était une correspondance exacte, vers `BR-16`; les dix\n * autres portent désormais un ID `GETPEPPR-*` qui annonce leur portée locale.\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\", \"GETPEPPR-ISSUE-DATE-DEFAULTED\", \"GETPEPPR-FROM-VAT-RECOMMENDED\", \"BR-07\", \"BR-16\",\n \"GETPEPPR-PAYMENT-TIMING-RECOMMENDED\", \"GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED\",\n \"BR-CL-17\", \"GETPEPPR-LINE-NET-SANITY\", \"GETPEPPR-COMPUTED-VAT-SANITY\",\n \"GETPEPPR-TAX-INCLUSIVE-SANITY\", \"GETPEPPR-PAYABLE-SANITY\",\n \"BR-S-05\", \"BR-Z-05\", \"BR-E-05\", \"BR-AE-05\", \"BR-G-05\", \"BR-IC-05\",\n \"BR-S-06\", \"BR-S-07\", \"BR-Z-06\", \"BR-Z-07\", \"BR-E-06\", \"BR-E-07\",\n \"BR-AE-06\", \"BR-AE-07\", \"BR-G-06\", \"BR-G-07\", \"BR-IC-06\", \"BR-IC-07\",\n \"BR-E-10\", \"BR-AE-10\", \"BR-G-10\", \"BR-O-10\", \"BR-IC-10\",\n \"GETPEPPR-BUYER-PEPPOL-ID-REQUIRED\", \"PEPPOL-EN16931-P0100\",\n \"PEPPOL-EN16931-P0101\", \"PEPPOL-EN16931-P0112\",\n \"GETPEPPR-UNIT-CODE-RECOGNISED\",\n] as const;\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 = \"5.3.0\";\n","/**\n * GPR-1178 — reading the getpeppr result contract off the response headers.\n *\n * The gateway publishes five additive headers on every public `/v1` response\n * IT WRITES (GPR-1174), plus a sixth — `Getpeppr-Result-Docs` — only when the\n * result has a guide to link to. They ride alongside every body shape the API\n * already returns — `{data,meta}`, bare objects, bare arrays, bodyless `204`s,\n * PDFs, redirects — which is why the contract lives in headers and not in a\n * JSON envelope.\n *\n * ⚠️ \"Plus a sixth\" is not a footnote: only a MINORITY of results carry a guide,\n * so the docs header is absent from most responses. Read its absence as normal —\n * a client treating it as guaranteed would read the ordinary case as a fault.\n *\n * ⛔ NO COUNT HERE, deliberately. An earlier draft of this very sentence said\n * \"73 of 229\", which was measured and correct on the day — and is a fact about\n * a catalogue that grows every tranche, written where nothing can update it.\n * That is the defect this ticket exists to close, reintroduced in the fix for\n * it. The public reference page DERIVES its count and cannot go stale; the\n * always-on five and the conditional sixth are partitioned mechanically in the\n * console's `lib/api/results/headers.ts`, against the builder that emits them,\n * with a test that fails if the conditional one stops being a minority.\n *\n * ⚠️ \"It writes\" is load-bearing, and this sentence said \"every public /v1\n * response\" until GPR-1181's relance. Some requests never reach the gateway:\n * the hosting platform answers them at its own border, with none of the six —\n * a verb outside the seven Next dispatches gets `405 text/plain` straight from\n * the edge. That is precisely why every field below is optional and why\n * `parseApiResultHeaders` returns `undefined` rather than an empty object: a\n * caller must be able to tell \"getpeppr said nothing\" from \"getpeppr said\n * nothing useful\". Measured inventory: the console's\n * `lib/api/results/platform-terminations.ts`.\n *\n * ## What this module refuses to do\n *\n * **Fabricate.** Every field is optional, and an unreadable value yields an\n * ABSENT field rather than a plausible one. A caller reads absence as \"the\n * gateway did not say\"; a fabricated value is indistinguishable from a measured\n * one and no downstream check can catch it.\n *\n * **Truncate.** An over-long value is dropped whole. A truncated sentence reads\n * exactly like a complete one — the same failure, wearing the shape of success.\n *\n * **Close the enums.** `remediation` and `code` are typed open on purpose: a\n * value this SDK build has never heard of is passed through verbatim. Refusing\n * it would blank the field and turn \"new\" into \"absent\" for a client running an\n * older SDK against a newer gateway — and that skew is the normal state, not\n * the exception.\n */\n\n/**\n * The six header names, exactly as `packages/console/src/lib/api/results/headers.ts`\n * emits them. Lookup is case-insensitive (`Headers.get` handles that), so this\n * spelling is documentation and a test anchor, not a matching requirement.\n */\nexport const API_RESULT_HEADER_NAMES = {\n requestId: \"Getpeppr-Request-Id\",\n resultCode: \"Getpeppr-Result-Code\",\n resultMessage: \"Getpeppr-Result-Message\",\n retryable: \"Getpeppr-Retryable\",\n remediation: \"Getpeppr-Remediation\",\n docs: \"Getpeppr-Result-Docs\",\n} as const;\n\n/**\n * What the caller should DO about this result.\n *\n * The catalogue's enum is closed today; this type is deliberately open so a\n * value added server-side reaches you rather than vanishing. The listed members\n * are the ones the catalogue defines today; do not assume the set is closed.\n */\nexport type ApiResultRemediation =\n | \"none\"\n | \"fix_request\"\n | \"authenticate\"\n | \"retry\"\n | \"retry_after\"\n | \"wait\"\n | \"contact_support\"\n | (string & {});\n\n/**\n * A stable getpeppr result code, spelled `domain.outcome`\n * (e.g. `\"invoices_import.validation_failed\"`, `\"auth.api_key_invalid\"`).\n *\n * Typed `string` rather than a generated union: pinning the union in a\n * published package would make every gateway-side addition a breaking change\n * for anyone who has not upgraded.\n */\nexport type ApiResultCode = string;\n\n/**\n * The canonical result of one HTTP response, as the gateway declared it.\n *\n * Every field is optional and independently so. A gateway that has not yet\n * activated the catalogue emits none of them, and a proxy may strip some — so\n * never infer one field's meaning from another's presence.\n */\nexport interface ApiResult {\n /**\n * Server-generated correlation id (`req_` + 32 hex today). Quote it to\n * support and they can find this exact request.\n *\n * `undefined` when the gateway sent no request-id header — pre-activation\n * deployments, and any hop that strips unknown headers.\n */\n requestId?: string;\n /**\n * Stable machine-readable code for this outcome.\n *\n * ⚠️ NOT the same field as `PeppolApiError.code`, which reads `body.code` and\n * carries a route-specific sub-reason. Both can be present and different.\n *\n * `undefined` when the header is absent or unreadable.\n */\n code?: ApiResultCode;\n /** Catalogue sentence for `code`. `undefined` when absent, blank or over-long. */\n message?: string;\n /**\n * Whether retrying this same request can succeed, as decided by the CODE and\n * not by the status alone.\n *\n * `undefined` when the header is absent or is anything other than `true` /\n * `false` — an unreadable value must never become a retry permission.\n */\n retryable?: boolean;\n /** Recommended action. `undefined` when the header is absent or blank. */\n remediation?: ApiResultRemediation;\n /**\n * Documentation link for this code, normalised through the URL parser.\n *\n * `undefined` when absent, relative, carrying any scheme other than\n * `https:`, carrying credentials in the authority, or malformed enough that\n * the URL parser would have to repair it — `javascript:` parses perfectly\n * well, so parsing is not validation.\n */\n docs?: string;\n}\n\n/**\n * C0 controls, DEL, and C1 (U+0080–U+009F).\n *\n * `Headers` already refuses CR, LF and NUL, so response splitting is closed\n * before this module runs. DEL and C1 travel RAW, and a terminal ACTS on them:\n * U+009B is a single-character CSI, equivalent to `ESC [`. These values reach\n * `Error.message`, which the CLI writes straight to stderr (CWE-117/150).\n *\n * @internal\n */\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001F\\u007F-\\u009F]/g;\n\n/**\n * Replace every control character with a space.\n *\n * @internal — exported for `client.ts`, which sanitises error bodies with the\n * same rule. One definition, deliberately: two copies of a security invariant\n * are two things free to drift apart.\n */\nexport function stripControls(value: string): string {\n return value.replace(CONTROL_CHARACTERS, \" \");\n}\n\n/**\n * Accept a value only if it is an absolute http(s) URL, and return the PARSED\n * form.\n *\n * Two reasons, both measured. `new URL` normalises control characters out of\n * the href — most percent-encoded (`ESC` becomes `%1B`), while TAB, LF and CR\n * are STRIPPED per the WHATWG parser — so the link cannot smuggle an escape\n * sequence either way. And it happily accepts `javascript:`, so the protocol\n * has to be checked separately.\n *\n * Returning `parsed.href` rather than the input is the GPR-1174 lesson:\n * validating one string and emitting another is how a check gets bypassed.\n *\n * @internal\n */\nexport function 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 * Generous byte ceilings, measured the way an origin serialises — the catalogue\n * caps these at 96 / 256 / 512 and bounds the whole block at 1024 bytes.\n *\n * These are 4-8x the real budget on purpose. They are not a second copy of the\n * server's contract (which would go stale); they are an absurdity guard, so a\n * proxy that injects a novel cannot push it into a terminal or a log line.\n *\n * ⛔ `retryable` is bounded TOO, and that is not symmetry for its own sake.\n * `\"true\"` is 4 bytes, so the field looks like it needs no ceiling — but\n * `String.prototype.trim()` strips Unicode whitespace, NBSP included, so 8 KB of\n * U+00A0 followed by `true` parses to `true` (gate finding). Every value off\n * the wire is bounded before it is interpreted; none is exempt.\n */\nconst MAX_BYTES = {\n requestId: 256,\n code: 256,\n message: 1024,\n remediation: 64,\n docs: 2048,\n // ⚠️ A COST bound, not a correctness one — and the distinction is measured.\n // When this field was still trimmed, a huge padded value could normalise into\n // `true`, so the ceiling changed the verdict. Now that the token is compared\n // verbatim, no string can be both over-long and equal to \"true\"/\"false\": a\n // mutation removing this ceiling SURVIVES the suite, and correctly so. It\n // stays to bound the whitespace/control scan on an absurd value, and it is\n // the one entry here with no test — deliberately, since any assertion would\n // be satisfied by both answers.\n retryable: 32,\n} as const;\n\n/**\n * A well-formed absolute https URL, matched on the RAW value.\n *\n * Deliberately narrower than what `new URL` accepts: no userinfo, no backslash,\n * no empty or repeated authority separator, no whitespace. Every documentation\n * link the catalogue publishes satisfies it — verified against all 72 of them.\n */\nconst STRICT_HTTPS_URL = /^https:\\/\\/[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?(?::\\d{1,5})?(?:\\/[^\\s\\\\]*)?$/i;\n\nconst TEXT_ENCODER = new TextEncoder();\n\n/** Bounded, or `undefined`. Applied before anything interprets the value. */\nfunction withinBudget(raw: string | null, maxBytes: number): string | undefined {\n if (raw === null) return undefined;\n return TEXT_ENCODER.encode(raw).length > maxBytes ? undefined : raw;\n}\n\n/**\n * A HUMAN sentence: sanitise it so it is safe to print, then require that\n * something survives.\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(raw: string | null, maxBytes: number): string | undefined {\n const bounded = withinBudget(raw, maxBytes);\n if (bounded === undefined) return undefined;\n const cleaned = stripControls(bounded).trim();\n return cleaned === \"\" ? undefined : cleaned;\n}\n\n/**\n * A MACHINE token: REJECT anything carrying a control character. Never repair it.\n *\n * ⛔⭐ The distinction from `readSentence` is the whole point, and getting it\n * wrong was a gate finding. Sanitising replaces the offending byte with a space\n * and trims — so `\"retry_after\" + U+007F` cleans to exactly `\"retry_after\"`, and\n * a value the gateway never sent becomes a valid enum member the SDK then acts\n * on. For a sentence, repairing is right: the reader wants something printable.\n * For a token something COMPARES against, repairing manufactures a fact.\n *\n * A human sentence is displayed; a machine token is obeyed. Only one of those\n * may be guessed at.\n */\nfunction readMachineToken(raw: string | null, maxBytes: number): string | undefined {\n const bounded = withinBudget(raw, maxBytes);\n if (bounded === undefined) return undefined;\n if (bounded === \"\") return undefined;\n // ⚠️ `.test()` on a /g regex is stateful — build a fresh matcher each call.\n if (new RegExp(CONTROL_CHARACTERS.source).test(bounded)) return undefined;\n // ⛔⭐ NO trim, and no other normalisation. This is the second half of the\n // same lesson, and the first fix missed it (gate, pass 2).\n //\n // `Headers.get` ALREADY strips leading and trailing ASCII whitespace —\n // measured: `new Headers({x: \" true \"}).get(\"x\")` returns `\"true\"`. So a\n // `.trim()` here can only ever strip what the transport left in place, which\n // is Unicode whitespace: `String.prototype.trim` treats NBSP as space, so\n // `NBSP + \"true\"` was normalised to `\"true\"` and honoured as a retry\n // permission — exactly the value-manufacturing this function exists to stop,\n // through a door I opened while closing the other one.\n //\n // No legitimate machine token carries whitespace: not a `domain.outcome`\n // code, not a remediation enum member, not a `req_` id, not a URL. Refusing\n // the whole class is both simpler and stricter than trying to normalise it.\n if (/\\s/u.test(bounded)) return undefined;\n return bounded;\n}\n\n/**\n * `true` / `false` and nothing else.\n *\n * ⛔ The tempting shorthand is `raw !== \"false\"`. It reads as equivalent and is\n * not: it turns `\"maybe\"`, `\"1\"` and `\"\"` — anything a proxy or a partial\n * deployment might put there — into a retry permission the gateway never\n * granted. Unreadable must mean \"the gateway did not say\", so the caller falls\n * back to the status policy instead of inheriting a fabricated yes.\n */\nfunction readBoolean(raw: string | null): boolean | undefined {\n const token = readMachineToken(raw, MAX_BYTES.retryable);\n if (token === undefined) return undefined;\n // ⛔⭐ Compared VERBATIM — no `toLowerCase()`, which is the third door of the\n // same class (gate, pass 3). The first was repairing control characters, the\n // second was `trim()` swallowing NBSP, and this was the same tolerance\n // wearing a third face: `Getpeppr-Retryable: TRUE` became a retry permission\n // on a 400, measured at 2 requests instead of 1.\n //\n // The writer emits exactly two literals, both lowercase\n // (`packages/console/src/lib/api/results/headers.ts`:\n // `definition.retryable ? \"true\" : \"false\"`), and HTTP never rewrites the\n // CASE of a header value — only the name. So there is no legitimate `TRUE` to\n // accommodate, and accepting one can only ever mean obeying something the\n // gateway did not say.\n if (token === \"true\") return true;\n if (token === \"false\") return false;\n return undefined;\n}\n\n/**\n * The `docs` link, held to the CONTRACT the catalogue declares — which is\n * `https://${string}`, not \"any URL\".\n *\n * Three refusals beyond `safeDocsUrl`, all from the same gate pass:\n * - **`http:`** — the server type forbids it; accepting it here would let a hop\n * downgrade a link we print to a developer.\n * - **credentials in the authority** — `https://getpeppr.dev@evil.test` reads as\n * getpeppr.dev to a human and resolves to evil.test. This is the GPR-1174\n * `apiRedirect` lesson, one layer down.\n * - **a control character anywhere in the raw value** — checked BEFORE parsing,\n * because `new URL` silently strips TAB/LF/CR out of the href and would hand\n * back a clean-looking link built from a value we should have refused.\n */\nfunction readDocsUrl(raw: string | null): string | undefined {\n const token = readMachineToken(raw, MAX_BYTES.docs);\n if (token === undefined) return undefined;\n\n // ⛔⭐ The WHOLE SHAPE is validated before parsing — not the prefix, and not a\n // growing list of special cases.\n //\n // `new URL` REPAIRS a malformed authority rather than rejecting it, so any\n // check made AFTER parsing arrives too late. Measured, every one of these\n // becomes a clean `https://<host>/path` that a `url.protocol` check waves\n // through:\n //\n // https:evil.test/path https:///getpeppr.dev/x\n // https:/evil.test/path https:////getpeppr.dev/x\n // https:\\\\evil.test/path https://\\getpeppr.dev/x\n // https://@getpeppr.dev/x\n //\n // A prefix test caught the first column and not the second — which is why\n // this is now a full-shape match: scheme, a host of ordinary hostname\n // characters, an optional port, then an optional path. Nothing the parser\n // would need to repair can satisfy it. Same lesson as GPR-1174, third\n // telling: validate the string you are going to USE.\n if (!STRICT_HTTPS_URL.test(token)) return undefined;\n\n const parsed = safeDocsUrl(token);\n if (parsed === null) return undefined;\n const url = new URL(parsed);\n if (url.protocol !== \"https:\") return undefined;\n // `https://getpeppr.dev@evil.test` reads as getpeppr.dev to a human and\n // resolves to evil.test.\n if (url.username !== \"\" || url.password !== \"\") return undefined;\n\n // ⚠️ DELIBERATELY not an allowlist of hosts. `https://getpeppr.dev.evil.test`\n // does get through, and that is an accepted limit rather than an oversight:\n // pinning our documentation domain inside a published SDK would silently\n // blank every docs link the day that domain changes, and this value is a link\n // shown to a developer — never fetched, never executed. The gate raised it;\n // this comment is the decision, so the next reader does not re-litigate it.\n return url.href;\n}\n\n/**\n * Read the getpeppr result contract from a response's headers.\n *\n * Returns `undefined` when NOTHING usable is present — an un-activated gateway,\n * a stripping proxy, or a block whose every value was unreadable. That is a\n * distinct answer from \"a result with all fields absent\", and callers rely on\n * it: `ResponseLogEntry.result` and `PeppolApiError.result` stay `undefined`\n * rather than carrying an empty shell that looks like a contract.\n */\nexport function parseApiResultHeaders(headers: Headers): ApiResult | undefined {\n const requestId = readMachineToken(headers.get(API_RESULT_HEADER_NAMES.requestId), MAX_BYTES.requestId);\n const code = readMachineToken(headers.get(API_RESULT_HEADER_NAMES.resultCode), MAX_BYTES.code);\n const message = readSentence(headers.get(API_RESULT_HEADER_NAMES.resultMessage), MAX_BYTES.message);\n const retryable = readBoolean(headers.get(API_RESULT_HEADER_NAMES.retryable));\n const remediation = readMachineToken(headers.get(API_RESULT_HEADER_NAMES.remediation), MAX_BYTES.remediation);\n const docs = readDocsUrl(headers.get(API_RESULT_HEADER_NAMES.docs));\n\n const result: ApiResult = {};\n if (requestId !== undefined) result.requestId = requestId;\n if (code !== undefined) result.code = code;\n if (message !== undefined) result.message = message;\n if (retryable !== undefined) result.retryable = retryable;\n if (remediation !== undefined) result.remediation = remediation;\n if (docs !== undefined) result.docs = docs;\n\n return Object.keys(result).length === 0 ? undefined : result;\n}\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 IdempotentRequestOptions,\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 LegalEntityRegistrationFailureReason,\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, UblBuilderInputError } from \"./ubl-builder.js\";\nimport { parsePeppolId } from \"./peppol-id.js\";\nimport { validateInvoice } from \"./validator.js\";\nimport { validateUblBuilderVat } from \"./schematron.js\";\nimport { statusFamily, TERMINAL_FAILURE_STATUSES } from \"./status-precedence.js\";\nimport { SDK_VERSION } from \"../version.js\";\nimport { parseApiResultHeaders, stripControls, safeDocsUrl } from \"./api-result.js\";\nimport type { ApiResult, ApiResultCode, ApiResultRemediation } from \"./api-result.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 /** @deprecated The current Storecove gateway rejects drafts with 422. */\n createInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult>;\n /** @deprecated The current Storecove gateway rejects draft sending with 501. */\n sendInvoiceById(id: string, options?: IdempotentRequestOptions): 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 /** @deprecated The current Storecove gateway rejects acknowledgement with 501. */\n acknowledgeInvoice(id: string, options?: IdempotentRequestOptions): 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, options?: IdempotentRequestOptions): 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, options?: IdempotentRequestOptions): 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 /** @deprecated The current Storecove gateway rejects invoice updates with 501. */\n updateInvoice(id: string, input: InvoiceUpdateInput): Promise<SendResult>;\n /** @deprecated The current Storecove gateway rejects invoice deletion with 501. */\n deleteInvoice(id: string): Promise<SendResult>;\n /** Report a French CTC invoice as paid; other state transitions return 501. */\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\n/**\n * The four bytes the transport strips from the edges of a header value before\n * it goes on the wire: HTAB `%x09`, LF `%x0A`, CR `%x0D`, SP `%x20`.\n *\n * ⛔ The source is the WHATWG Fetch \"normalize a potential value\" algorithm,\n * NOT RFC 9110 §5.6.3 — which this comment cited until a gate checked it\n * (GPR-1188). RFC 9110 §5.6.3 reads `OWS = *( SP / HTAB )`, verbatim: no CR, no\n * LF. The behaviour described below is right; the citation was not.\n *\n * ⚠️ NOT `String.prototype.trim()`, which also eats NBSP and every other Unicode\n * space. The wire keeps those, so trimming them here would make the SDK's idea\n * of the key differ from the gateway's — the very gap this file exists to close.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function normalizeHeaderValue(value: string): string {\n return value.replace(/^[\\t\\n\\r ]+|[\\t\\n\\r ]+$/g, \"\");\n}\n\n/**\n * Whether the transport can carry these bytes at all.\n *\n * The whitelist is `field-value` itself, RFC 9110 §5.5:\n *\n * field-value = *( HTAB / SP / VCHAR / obs-text )\n * VCHAR = %x21-7E\n * obs-text = %x80-FF\n *\n * So: HTAB, SP, `%x21-7E`, `%x80-FF`. Everything else — `%x00-08`, `%x0A-1F`,\n * `%x7F`, and any code unit above `%xFF` — makes the request throw before it\n * leaves, as a bare `TypeError` from the runtime, which `instanceof PeppolError`\n * does not catch. The error-handling pattern the README teaches would miss it.\n *\n * ⛔⭐ THE MISTAKE THIS REPLACED, because it is the interesting one: the rule was\n * first derived from `new Headers()`, and `new Headers()` is NOT the sink.\n * `fetch` is, and it is stricter — it refuses every C0 control and DEL that\n * `Headers` waves through. Twenty-nine values therefore passed validation and\n * died at dispatch with `InvalidArgumentError: invalid Idempotency-Key header`,\n * untyped, after FOUR attempts, since the retry guard had seen a non-blank\n * header. Bounding a value for one sink does not bound it for the next; the\n * spec is the only model that names them all. (Found by gate, GPR-1185.)\n *\n * ⭐ Refusing here takes nothing away from a caller: by construction every value\n * this rejects could never have left the machine. `idempotency-key.test.ts`\n * pins that against `fetch` itself, not against a stand-in.\n */\nfunction isCarriableHeaderValue(value: string): boolean {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n const carriable =\n code === 0x09 || (code >= 0x20 && code <= 0x7e) || (code >= 0x80 && code <= 0xff);\n if (!carriable) return false;\n }\n return true;\n}\n\nfunction idempotencyKeyRefusal(message: string): PeppolValidationError {\n return new PeppolValidationError(`Invalid idempotency key: ${message}`, {\n valid: false,\n errors: [{ field: \"idempotencyKey\", message }],\n warnings: [],\n });\n}\n\n/**\n * Write the `Idempotency-Key` header, or refuse a key that cannot protect\n * anything. Every write surface that accepts `options.idempotencyKey` goes\n * through here, so the rule lives in one place.\n *\n * ⛔ A key made of whitespace is TRUTHY in JavaScript but EMPTY on the wire. The\n * SDK used to read it as \"a key was supplied\" and unlock its POST retry, while\n * the gateway saw no key at all, skipped its cache and its lock, and treated\n * every attempt as new — one `POST /v1/invoices` leaving FOUR times under the\n * default retry config (`maxRetries: 3`), each able to submit the invoice. A key that does not protect is worse than no key: it\n * removes the very guard its absence would have kept shut.\n *\n * ⚠️ The type says `string`, but the SDK runs on the caller's machine, which may\n * not be typed. `[]` is the sharp case — truthy, and `String([])` is `\"\"`.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function applyIdempotencyKey(\n headers: Record<string, string>,\n options: { idempotencyKey?: string } | undefined,\n): void {\n const key = options?.idempotencyKey;\n // Absent means absent — the caller opted out of idempotency, which is legal.\n if (key === undefined || key === null) return;\n\n if (typeof key !== \"string\") {\n throw idempotencyKeyRefusal(\n `expected a string, received ${Array.isArray(key) ? \"an array\" : `a ${typeof key}`}.`,\n );\n }\n\n const normalized = normalizeHeaderValue(key);\n if (normalized === \"\") {\n throw idempotencyKeyRefusal(\n \"the key is blank once HTTP whitespace is stripped, so it would reach the gateway empty and protect nothing. Pass a non-blank key, or omit the option.\",\n );\n }\n if (!isCarriableHeaderValue(normalized)) {\n throw idempotencyKeyRefusal(\n \"the key contains a character no HTTP header can carry. A header value may hold only HTAB, space, U+0021-U+007E and U+0080-U+00FF (RFC 9110 field-value) — so every control character other than the tab, plus DEL and anything above U+00FF, is refused by the transport itself.\",\n );\n }\n\n // Post the bytes the wire would actually keep, so what the SDK believes it\n // sent and what the gateway reads can never drift apart.\n headers[\"Idempotency-Key\"] = normalized;\n}\n\n/**\n * Whether these headers carry an idempotency key the gateway can actually USE.\n *\n * The second, independent lock. `applyIdempotencyKey` guards nine call sites —\n * four until GPR-1189 opened the header on every operation the contract lists\n * it on — and a tenth added later would skip it. This sits on the single path\n * every retry goes through, and it reads the value that would TRAVEL rather\n * than the presence of a property — so a blank header cannot unlock a replay\n * whatever put it there.\n *\n * @internal — exported for testing only; not part of the public SDK surface.\n */\nexport function carriesUsableIdempotencyKey(headers: Record<string, string> | undefined): boolean {\n if (!headers) return false;\n // ⚠️ EVERY matching spelling, not the first one. HTTP header names are\n // case-insensitive and the transport COMBINES duplicates into one comma-joined\n // value, so `{\"Idempotency-Key\": \" \", \"idempotency-key\": \"k\"}` travels as\n // `\", k\"` — a usable key. Reading only the first match called that blank and\n // withheld a retry that was in fact safe. No current writer builds such an\n // object (each surface starts from a fresh `{}`), so this is the lock, not the\n // fix; a fifth call site added later is exactly what it guards. (Gate, GPR-1185.)\n for (const [name, value] of Object.entries(headers)) {\n if (name.toLowerCase() !== \"idempotency-key\") continue;\n if (typeof value === \"string\" && normalizeHeaderValue(value) !== \"\") return true;\n }\n return false;\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 * ⛔ `Retry-After` is read on a 429 and NOWHERE else. Do not widen this to\n * \"whenever the remediation says retry_after\" (GPR-1178 tried, gate caught it).\n *\n * The reasoning that failed: grepping the catalogue shows many\n * `remediation: \"retry_after\"` entries, so surely some sit on 503s. Measured,\n * joining the STATUS this time: all 22 of them are 429s, `provider.throttled`\n * included. The clause was dead code — and worse than dead, because the same\n * untrusted hop that sets `Retry-After` also sets `Getpeppr-Remediation`, so\n * widening let it choose the CONDITION as well as the delay.\n *\n * Counting rows is not counting situations.\n */\n\n/**\n * ⛔ `stripControls` and `safeDocsUrl` live in `./api-result.js`, imported above.\n *\n * They were defined here first, for the parsed error body. The result headers\n * need the exact same rule, and a second copy of a security invariant is two\n * things free to drift apart — so there is one definition, in the module with\n * no dependencies of its own.\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\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\n/**\n * Should this failure be retried at all?\n *\n * ## The gateway's answer wins, in BOTH directions\n *\n * `Getpeppr-Retryable` is derived from the CATALOGUE CODE, not from the status,\n * and the status alone gets it wrong at both ends. Measured against the\n * catalogue (GPR-1174): nine PUBLIC 5xx codes are permanently fatal — among them\n * `provider.not_supported` (501), `provider.authentication_failed` (502) and\n * `server.unexpected_error` (500) — and status-only policy retried three of\n * those four times for nothing. In the other direction three 409s\n * (`idempotency.concurrent_request`, `idempotency.cache_unreadable`,\n * `legal_entities.creation_in_progress`) clear on their own within moments, and\n * status-only policy never retried them at all.\n *\n * ## Absent is not false\n *\n * `retryable` is `undefined` for a gateway that predates the catalogue, for a\n * proxy that strips unknown headers, AND for a value this SDK cannot parse. All\n * three fall back to the historic status list — which is fail-safe in the sense\n * that matters: an unreadable header can neither GRANT a retry the status never\n * allowed, nor REVOKE one it already earned.\n *\n * ⚠️ This answers \"can retrying succeed\", never \"is replaying THIS request\n * safe\". The idempotency guard in `request()` answers the second, and a\n * retryable result does not relax it.\n */\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof PeppolApiError) {\n if (error.retryable !== undefined) return error.retryable;\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 // TWO independent questions, and both must answer yes.\n //\n // 1. CAN retrying succeed? — `isRetryableError`, which asks the gateway's\n // result code first and falls back to the status list. It no longer\n // means \"500, 502, 503, 504\": the catalogue marks some of those fatal\n // and some 409s retryable.\n // 2. Is replaying THIS request safe? — the guard below. 429 always is\n // (the request was never processed) and so are GET/DELETE/HEAD; every\n // other method needs an Idempotency-Key, or a retry could send the\n // same invoice twice.\n //\n // ⛔ A `retryable: true` result answers the first question only. It must\n // never be read as permission to replay a non-idempotent write.\n //\n // ⛔ And the key must be USABLE, not merely present: a value made of\n // whitespace is truthy here and empty on the wire, so the gateway skips\n // its cache and its lock while the SDK believes it is protected\n // (GPR-1185). `carriesUsableIdempotencyKey` asks what would travel.\n const is429 = err instanceof PeppolApiError && err.statusCode === 429;\n const isSafeMethod = /^(GET|DELETE|HEAD)$/i.test(method);\n const hasIdempotencyKey = carriesUsableIdempotencyKey(extraHeaders);\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 // The canonical result rides on the response HEADERS, so it is read the\n // same way for every shape the API returns — success, failure, 204,\n // binary. Parsed once, here, before any branch.\n //\n // ⚠️ \"read the same way\", NOT \"always present\": the gateway's result flag\n // is off until GPR-1181, and a proxy may strip unknown headers, so\n // `undefined` is the normal answer today.\n const result = parseApiResultHeaders(response.headers);\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 result: cloneResultForHook(result),\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 result,\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 result: cloneResultForHook(result),\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 // ⛔ The hook fires BEFORE the throw, unlike every earlier version of\n // this branch. A response that ARRIVED must be logged: a 2xx whose body\n // is a proxy's HTML is the failure a developer most needs to see, and\n // it was the only one their logging never showed them.\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 result: cloneResultForHook(result),\n });\n } catch {\n // Hook errors must never break the request\n }\n }\n\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 undefined,\n result,\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 result: cloneResultForHook(result),\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 // sendInvoice and createInvoice hit the same endpoint. The latter adds the\n // legacy `_draft` marker, which the current gateway rejects explicitly.\n async sendInvoice(input: InvoiceInput, options?: InvoiceOperationOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\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 applyIdempotencyKey(headers, options);\n if (options?.validateRecipient) {\n headers[\"X-Validate-Recipient\"] = options.validateRecipient === true ? \"warn\" : String(options.validateRecipient);\n }\n // Preserve the legacy draft request shape so the gateway can return its\n // explicit 422 `drafts_not_supported` capability refusal.\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, options?: IdempotentRequestOptions): Promise<void> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n await this.request<void>(\"POST\", `/invoices/send/${id}`, undefined, headers);\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?.number != null) params.set(\"number\", options.number);\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 // The canonical result rides on the response HEADERS, so it is read the\n // same way for every shape the API returns — success, failure, 204,\n // binary. Parsed once, here, before any branch.\n //\n // ⚠️ \"read the same way\", NOT \"always present\": the gateway's result flag\n // is off until GPR-1181, and a proxy may strip unknown headers, so\n // `undefined` is the normal answer today.\n const result = parseApiResultHeaders(response.headers);\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 result: cloneResultForHook(result),\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 result,\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 result: cloneResultForHook(result),\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?.documentId != null) params.set(\"documentId\", options.documentId);\n if (options?.invoiceId != null) 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, options?: IdempotentRequestOptions): Promise<SendResult> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", `/invoices/${id}/ack`, undefined, headers);\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, options?: IdempotentRequestOptions): Promise<Contact> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/contacts\", input, headers);\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 applyIdempotencyKey(headers, options);\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 applyIdempotencyKey(headers, options);\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, options?: IdempotentRequestOptions): Promise<BankAccount> {\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/bank-accounts\", input, headers);\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 // ⛔ GPR-1129 — ce corps est une LISTE BLANCHE, exactement comme\n // `parseSendResult` l'est en sortie : tout champ non recopié ici est\n // supprimé en SILENCE, et la capacité correspondante devient\n // inatteignable pour quiconque passe par le SDK.\n //\n // Quatrième occurrence de cette classe, la première dans le sens REQUÊTE\n // (`rulebook` GPR-1069, `transmission` GPR-1089, `duplicateOf` GPR-1105\n // étaient des champs de RÉPONSE). Le préjudice n'est pas symétrique : un\n // champ de réponse jeté casse qui le lit, un champ de requête jeté\n // produit un refus que l'appelant ne peut relier à rien — il envoie\n // `sender`, la passerelle ne le voit jamais, et le 422 qu'il reçoit parle\n // d'une identité qu'il ne revendiquait pas.\n //\n // ⚠️ Conditionnel, jamais `sender: options.sender` : une clé présente à\n // `undefined` disparaît du JSON, donc l'écriture nue passerait les tests\n // tout en salissant le corps des envois standards.\n ...(options.sender ? { sender: options.sender } : {}),\n };\n // ⛔ The key is a HEADER, and the whitelist above is exactly why that has to\n // be said out loud: `idempotencyKey` lives on the same options object as the\n // body fields, so copying it across with its neighbours would put it in the\n // JSON — where the gateway never looks — and the SDK would then unlock its\n // POST retry on a key that protects nothing (GPR-1189).\n const headers: Record<string, string> = {};\n applyIdempotencyKey(headers, options);\n const result = await this.request<Record<string, unknown>>(\"POST\", \"/invoices/import\", body, headers);\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 */\n/**\n * A COPY of the result for the logging hook — never the object the retry loop\n * reads (GPR-1178, found by gate).\n *\n * ⚠️ Applied at all six hook sites, but only five of them are TESTABLE. On the\n * JSON-success path nothing reads `result` afterwards — no error is built, the\n * retry loop is over — so un-cloning there has no observable effect and a\n * mutation campaign finds the mutant surviving. That is honest, not a hole: a\n * test asserting anything at that site would be satisfied by both answers. The\n * clone stays for consistency across the six, and this note exists so the next\n * reader does not mistake it for a protection a test is holding.\n *\n * Exactly the `cloneForHook` failure one field over, and this repo has already\n * paid for it once: a hook that strips falsy values before logging them — an\n * entirely reasonable hook — deletes `retryable: false`, and `isRetryableError`\n * then reads `undefined` and falls back to the status policy. Measured effect:\n * a fatal 500 goes from 1 request to 4. It can erase a received `requestId` the\n * same way.\n *\n * A shallow copy is enough and is the point: `ApiResult` is flat, all primitives.\n */\nfunction cloneResultForHook(result: ApiResult | undefined): ApiResult | undefined {\n return result === undefined ? undefined : { ...result };\n}\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-1092 — TROISIÈME occurrence de l'oubli que les deux blocs ci-dessus\n // racontent (`rulebook`, puis `transmission`). Le gateway pose `duplicateOf` sur\n // le 201 quand le même document repart au-delà de la fenêtre de refus : c'est\n // la SEULE façon dont un appelant apprend qu'un second exemplaire vient\n // d'arriver chez son destinataire. Sans cette ligne, l'information existe en\n // HTTP brut et disparaît pour tout utilisateur du SDK — et la promesse écrite\n // dans `openapi.yaml` serait fausse pour eux.\n //\n // Garde de FORME via `optionalWireId`, comme les identifiants voisins : un\n // champ non-chaîne est absent plutôt que menteur.\n //\n // ⛔ `readOwn`, JAMAIS un accès indexé nu — même raison que `transmission`\n // vingt lignes plus haut, et je l'ai quand même écrit nu en première\n // rédaction (trouvé au tour 2 de la gate). Sur un hôte dont\n // `Object.prototype` est pollué, un corps SANS `duplicateOf` en gagne un :\n // le SDK annoncerait alors au client qu'un second exemplaire de sa facture\n // vient d'être accepté pour transmission, en nommant le document d'un tiers.\n const duplicateOf = optionalWireId(readOwn(result, \"duplicateOf\"));\n if (duplicateOf) sendResult.duplicateOf = duplicateOf;\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 networkDiscovery:\n raw.networkDiscovery && typeof raw.networkDiscovery === \"object\"\n ? raw.networkDiscovery as LegalEntity[\"networkDiscovery\"]\n : { state: \"pending\", attempts: 0 },\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 if (raw.registrationDetail && typeof raw.registrationDetail === \"object\") {\n const reason = (raw.registrationDetail as Record<string, unknown>).reason;\n const safeReasons: readonly LegalEntityRegistrationFailureReason[] = [\n \"already_registered\",\n \"invalid_format\",\n \"provider_error\",\n ];\n le.registrationDetail = {\n reason: safeReasons.includes(reason as LegalEntityRegistrationFailureReason)\n ? reason as LegalEntityRegistrationFailureReason\n : \"provider_error\",\n };\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 sandboxFirstSend: parseSandboxFirstSendProfile(\n readOwn(result, \"sandboxFirstSend\"),\n result,\n ),\n };\n}\n\nfunction parseSandboxFirstSendProfile(\n raw: unknown,\n body: unknown,\n): AccountIdentity[\"sandboxFirstSend\"] {\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 sandboxFirstSend field. Please report this response to support@getpeppr.dev.\",\n \"sandboxFirstSend\",\n boundedBody(body),\n );\n }\n const status = readOwn(raw, \"status\");\n if (status === \"blocked\") {\n const code = readOwn(raw, \"code\");\n const message = readOwn(raw, \"message\");\n if (\n typeof code === \"string\" &&\n code.trim() !== \"\" &&\n typeof message === \"string\" &&\n message.trim() !== \"\"\n ) {\n return { status, code, message };\n }\n }\n if (status === \"ready\") {\n const taxMode = readOwn(raw, \"taxMode\");\n const line = readOwn(raw, \"line\");\n if (\n (taxMode === \"outside_scope\" || taxMode === \"reverse_charge\") &&\n isRecord(line)\n ) {\n const vatRate = readOwn(line, \"vatRate\");\n const vatCategory = readOwn(line, \"vatCategory\");\n const taxExemptReason = readOwn(line, \"taxExemptReason\");\n if (\n vatRate === 0 &&\n typeof taxExemptReason === \"string\" &&\n taxExemptReason.trim() !== \"\" &&\n taxMode === \"outside_scope\" &&\n vatCategory === \"O\"\n ) {\n return {\n status,\n taxMode,\n line: { vatRate, vatCategory, taxExemptReason },\n };\n }\n if (\n vatRate === 0 &&\n typeof taxExemptReason === \"string\" &&\n taxExemptReason.trim() !== \"\" &&\n taxMode === \"reverse_charge\" &&\n vatCategory === \"AE\"\n ) {\n return {\n status,\n taxMode,\n line: { vatRate, vatCategory, taxExemptReason },\n };\n }\n }\n }\n throw new PeppolProtocolError(\n \"The getpeppr API answered the identity request with a malformed sandboxFirstSend profile. Please report this response to support@getpeppr.dev.\",\n \"sandboxFirstSend\",\n boundedBody(body),\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 /**\n * Parsed `Retry-After` delay in milliseconds.\n *\n * `undefined` unless this response is a **429** AND carried a readable\n * `Retry-After`. No other status reads that header, whatever its remediation\n * says — measured, all 22 `retry_after` entries in the catalogue are 429s.\n * The gateway does not attach the header to every throttled answer either.\n */\n public readonly retryAfterMs?: number;\n\n /**\n * The canonical result the gateway declared for this response, read from its\n * six headers — no body parsing required.\n *\n * `undefined` against a gateway that has not activated the result catalogue,\n * and behind any hop that strips unknown headers. The flattened accessors\n * below all read from here, so they are `undefined` together.\n */\n public readonly result?: ApiResult;\n\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly responseBody: string,\n retryAfterMs?: number,\n result?: ApiResult,\n ) {\n super(message);\n this.name = \"PeppolApiError\";\n this.retryAfterMs = retryAfterMs;\n this.result = result;\n }\n\n /**\n * Stable getpeppr result code for this failure (e.g. `\"auth.api_key_invalid\"`).\n *\n * ⛔ NOT the same field as {@link code}, and they can both be present with\n * different values: this one is the catalogue's global code, `code` is the\n * route's own sub-reason from the body.\n *\n * `undefined` when the gateway sent no result headers.\n */\n get resultCode(): ApiResultCode | undefined {\n return this.result?.code;\n }\n\n /**\n * The catalogue's sentence for {@link resultCode}.\n *\n * ⚠️ Usually SHORTER on detail than `.message`, which is built from the\n * response body and can name the offending field or rule. Show `.message` to\n * a human; use this one when you want the stable phrasing.\n *\n * `undefined` when the gateway sent no result headers.\n */\n get resultMessage(): string | undefined {\n return this.result?.message;\n }\n\n /**\n * Server-generated correlation id for this exact request. Quote it to support.\n *\n * `undefined` when the gateway sent no result headers — which includes every\n * response from a deployment predating the catalogue.\n */\n get requestId(): string | undefined {\n return this.result?.requestId;\n }\n\n /**\n * Whether retrying this same request can succeed, per the catalogue.\n *\n * ⚠️ `undefined` means \"the gateway did not say\", NOT \"no\" — the SDK then\n * falls back to its historic status policy. A `false` here is an explicit\n * refusal and the SDK will not retry, whatever the status.\n */\n get retryable(): boolean | undefined {\n return this.result?.retryable;\n }\n\n /**\n * What to do about it: `\"none\"`, `\"fix_request\"`, `\"authenticate\"`,\n * `\"retry\"`, `\"retry_after\"`, `\"wait\"` or `\"contact_support\"` today.\n *\n * Typed open — a value added server-side reaches you rather than vanishing.\n * `undefined` when the gateway sent no result headers.\n */\n get remediation(): ApiResultRemediation | undefined {\n return this.result?.remediation;\n }\n\n /**\n * Documentation link for {@link resultCode}, when the catalogue provides one.\n *\n * `undefined` when the gateway sent no result headers, when the catalogue\n * entry has no docs link, or when the value was not a plain `https://` URL\n * (`http:`, credentials in the authority, and anything the URL parser would\n * have to repair are all refused).\n */\n get docs(): string | undefined {\n return this.result?.docs;\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:** in the sandbox, an organisation admin starts the\n * platform sandbox trial from the console overview (or chooses \"A platform\n * for my customers\" at signup), then creates the sandbox master key at\n * https://console.getpeppr.dev/api-keys. Production platform access is set up\n * with our team — email hello@getpeppr.dev to request it.\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 the structured JSON send payload without sending it.\n * Useful for pre-flight checks in your UI; provider-side normalization still\n * applies on send. `toXml()` adds the stricter direct-UBL builder checks.\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 baseValidation = validateInvoice(input);\n const vatViolations = baseValidation.valid ? validateUblBuilderVat(input) : [];\n const validation: ValidationResult = {\n valid: baseValidation.valid && vatViolations.every((item) => item.severity !== \"error\"),\n errors: [\n ...baseValidation.errors,\n ...vatViolations\n .filter((item) => item.severity === \"error\")\n .map(({ field, message, ruleId }) => ({\n field: field ?? \"invoice\",\n message,\n ruleId: ruleId === \"SDK-INPUT\" ? undefined : ruleId,\n })),\n ],\n warnings: baseValidation.warnings,\n };\n if (!validation.valid) {\n throw new PeppolValidationError(\n `Invoice validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n validation\n );\n }\n try {\n if (input.isCreditNote) {\n return buildCreditNoteXml(input as unknown as CreditNoteInput);\n }\n return buildInvoiceXml(input);\n } catch (error) {\n if (error instanceof UblBuilderInputError) {\n const builderValidation: ValidationResult = {\n valid: false,\n errors: [{ field: error.field, message: error.message, ruleId: error.ruleId }],\n warnings: validation.warnings,\n };\n throw new PeppolValidationError(\n `Invoice validation failed: ${error.message}`,\n builderValidation,\n );\n }\n throw error;\n }\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\n/** Builder-only BT-120 text must not cross the JSON gateway boundary. */\nfunction toGatewayInvoiceInput(input: InvoiceInput): InvoiceInput {\n const stripReason = <T extends { taxExemptReason?: string }>(item: T): Omit<T, \"taxExemptReason\"> => {\n const { taxExemptReason: _builderOnly, ...gatewayItem } = item;\n return gatewayItem;\n };\n return {\n ...input,\n lines: input.lines.map(stripReason),\n ...(input.allowances ? { allowances: input.allowances.map(stripReason) } : {}),\n ...(input.charges ? { charges: input.charges.map(stripReason) } : {}),\n };\n}\n\nclass InvoiceOperations {\n constructor(private adapter: BackendAdapter) {}\n\n /**\n * Request draft creation from the gateway.\n *\n * @deprecated The current Storecove-backed gateway does not support drafts\n * and returns 422 `drafts_not_supported`. Submit the final document with\n * `invoices.send()` instead.\n * @throws {PeppolApiError} 422 with code `drafts_not_supported`\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(toGatewayInvoiceInput(input), options);\n\n if (validation.warnings.length > 0) {\n result.warnings = validation.warnings;\n }\n\n return result;\n }\n\n /**\n * Request sending of an existing draft invoice by ID.\n *\n * @deprecated The current Storecove-backed gateway has no draft lifecycle and\n * always returns 501. Submit the final document with `invoices.send()`.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async sendById(id: string, options?: IdempotentRequestOptions): Promise<void> {\n return this.adapter.sendInvoiceById(id, options);\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(toGatewayInvoiceInput(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 * pre-flight checks without sending the invoice to Storecove. This is not a Peppol\n * conformance verdict.\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 * Request acknowledgement of a received invoice.\n *\n * @deprecated The current Storecove-backed gateway does not support\n * acknowledgement and always returns 501.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async acknowledge(id: string, options?: IdempotentRequestOptions): Promise<SendResult> {\n return this.adapter.acknowledgeInvoice(id, options);\n }\n\n /**\n * Request an update to an existing invoice.\n *\n * @deprecated Storecove documents are immutable after submission. The\n * current gateway always returns 501; issue a credit note instead.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async update(id: string, input: InvoiceUpdateInput): Promise<SendResult> {\n return this.adapter.updateInvoice(id, input);\n }\n\n /**\n * Request deletion of an invoice.\n *\n * @deprecated The current Storecove-backed gateway does not support invoice\n * deletion and always returns 501.\n * @throws {PeppolApiError} 501 with the current gateway provider\n */\n async delete(id: string): Promise<SendResult> {\n return this.adapter.deleteInvoice(id);\n }\n\n /**\n * Report a French CTC invoice as paid.\n * Other state transitions are retained for API compatibility but the current\n * Storecove-backed gateway returns 501 for them.\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(toGatewayInvoiceInput(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 if (!peppolId.includes(\":\")) {\n throw new PeppolError(\n 'Invalid Peppol ID format. Expected \"scheme:id\" (e.g., \"0208:0685660237\")',\n );\n }\n // ⛔ Découpait sur le premier `:`, donc `GB:VAT:123456789` interrogeait le\n // registre sous le scheme `GB`, qui n'existe pas (GPR-1110). Le registre\n // indexe sous le code EAS NUMÉRIQUE — le fait était déjà écrit dans la note\n // de GPR-755, sans qu'on le relie au découpage.\n const { scheme, id } = parsePeppolId(peppolId);\n return this.adapter.lookupDirectory(scheme, id);\n }\n\n /**\n * Search the Peppol Directory for participants.\n * Pagination is exact and participant-based. Queries wider than the public\n * Directory's accessible result window are rejected; add narrower criteria.\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 provider document ID or getpeppr submission ID\n * const invoiceEvents = await peppol.events.list({ documentId: \"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({ documentId: \"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, options?: IdempotentRequestOptions): Promise<Contact> {\n return this.adapter.createContact(input, options);\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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.** In the sandbox,\n * an organisation admin starts the platform sandbox trial from the console\n * overview and creates a sandbox master key at\n * https://console.getpeppr.dev/api-keys; production platform access is set\n * up with our team (hello@getpeppr.dev).\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, options?: IdempotentRequestOptions): Promise<BankAccount> {\n return this.adapter.createBankAccount(input, options);\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 * String(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 * // `event.data` is `unknown` on the envelope — narrow it per type\n * const data = event.data as { sender: { peppolId: string } };\n * console.log(\"New invoice from:\", data.sender.peppolId);\n * break;\n * }\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","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\nconst SEND_INERT_INVOICE_TYPE_PROFILE_RULES = new Set([\n \"PEPPOL-EN16931-P0100\",\n \"PEPPOL-EN16931-P0101\",\n \"PEPPOL-EN16931-P0112\",\n]);\n\nfunction isSendRelevantSchematronViolation(\n violation: SchematronViolation,\n): boolean {\n return !(\n violation.field === \"invoiceTypeCode\" &&\n SEND_INERT_INVOICE_TYPE_PROFILE_RULES.has(violation.ruleId)\n );\n}\n\nfunction runMergedValidation(\n input: InvoiceInput,\n schematronFilter: (violation: SchematronViolation) => boolean,\n): MergedValidationResult {\n const structure = validateInvoice(input);\n const completeSchematron = validateSchematron(input);\n const schematron = {\n errors: completeSchematron.errors.filter(schematronFilter),\n warnings: completeSchematron.warnings,\n };\n const countryRules = validateCountryRules(input);\n\n // GPR-1267 — `validateInvoice()` ALREADY merges the country advisory\n // warnings into its own result. Summing both surfaces counted every country\n // warning twice (once under Structure, once under Country Rules) and\n // doubled `totalWarnings`. `validateCountryRules` is a pure function of the\n // input, so the copies inside `structure.warnings` are value-identical to\n // `countryRules.warnings` — removing them here restores one warning per\n // finding, displayed under its own section.\n const countryKeys = new Set(\n countryRules.warnings.map((w) => JSON.stringify([w.field, w.message, w.ruleId])),\n );\n const structureWarnings = structure.warnings.filter(\n (w) => !countryKeys.has(JSON.stringify([w.field, w.message, w.ruleId])),\n );\n\n const totalErrors =\n structure.errors.length +\n schematron.errors.length +\n countryRules.errors.length;\n\n const totalWarnings =\n structureWarnings.length +\n schematron.warnings.length +\n countryRules.warnings.length;\n\n return {\n structure: { errors: structure.errors, warnings: structureWarnings },\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\n/**\n * Full local-UBL validation used by `validate` and `convert --validate`.\n */\nexport function runValidation(input: InvoiceInput): MergedValidationResult {\n return runMergedValidation(input, () => true);\n}\n\n/**\n * JSON send preflight aligned with POST /v1/invoices.\n *\n * The provider route ignores invoiceTypeCode and derives the document kind\n * from isCreditNote, so local profile errors for that inert field cannot block\n * this command. Structured BR-CL-01 validation, warnings, and every other local\n * check remain active.\n */\nexport function runSendPreflight(input: InvoiceInput): MergedValidationResult {\n return runMergedValidation(input, isSendRelevantSchematronViolation);\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 offline template starts with O/0 tax lines.\n On send, the CLI checks GET /v1/identity and refuses a conflicting sender\n profile before anything reaches the provider.\\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: 0,\n vatCategory: \"O\",\n taxExemptReason: \"Integration test\",\n },\n {\n description: \"Software license \\u2014 annual subscription\",\n quantity: 1,\n unitPrice: 2400,\n vatRate: 0,\n vatCategory: \"O\",\n taxExemptReason: \"Integration test\",\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: 0,\n vatCategory: \"O\",\n taxExemptReason: \"Integration test\",\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 { parsePeppolId } from \"@getpeppr/sdk\";\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\n/**\n * Valide un identifiant Peppol saisi en ligne de commande — GPR-1116.\n *\n * ⛔ Cette fonction REFUSAIT la seule forme que notre propre guidage propose au\n * Royaume-Uni. Elle découpait sur le premier `:`, obtenait `scheme = \"GB\"`, et\n * répondait « Invalid scheme \"GB\". Must be exactly 4 digits ». L'utilisateur\n * tapait exactement ce que `SCHEMES_BY_COUNTRY` lui donne, et le CLI l'accusait\n * d'une faute qu'il n'avait pas commise. C'est le pire mode d'échec possible :\n * un refus qui désigne le mauvais coupable.\n *\n * ⭐ On canonicalise AVANT de valider. Le contrôle des quatre chiffres est\n * conservé — il attrape encore une vraie faute de frappe — mais il s'applique\n * désormais au scheme RÉSOLU, pas au fragment que le découpage a produit.\n *\n * ⚠️ Exportée pour être testée directement. Le paquet est bundlé par tsup\n * (`noExternal`), donc cela n'élargit aucune surface publique npm.\n */\nexport function 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, id } = parsePeppolId(raw);\n\n if (!/^\\d{4}$/.test(scheme)) {\n return {\n ok: false,\n error: `Invalid scheme \"${scheme}\". Must be a 4-digit EAS code (e.g. 0208) or a published symbolic scheme (e.g. GB:VAT).`,\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","import { parsePeppolId } from \"@getpeppr/sdk\";\n\nconst 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\n/**\n * Sépare un identifiant Peppol — GPR-1116.\n *\n * ⛔ Découpait sur le premier `:`, ce qui est faux dès que le scheme porte sa\n * forme symbolique : `GB:VAT:123456789` rendait `{ scheme: \"GB\", id:\n * \"VAT:123456789\" }`. Le registre n'indexe pas sous `GB` — il indexe sous le code\n * EAS numérique — donc la recherche ne rendait rien, sans jamais dire pourquoi.\n *\n * ⭐ Le découpage vit dans `@getpeppr/sdk` (`parsePeppolId`) : il résout le\n * préfixe CONTRE la code list au lieu de le deviner par position. Ce paquet\n * bundle le SDK, donc converger dessus ne coûte rien à l'utilisateur final — et\n * évite une seconde implémentation qui dériverait de la première.\n *\n * ⚠️ Le contrat « pas de `:` ⇒ scheme vide » est conservé tel quel : il vaut\n * pour une saisie partielle en cours de frappe, où inventer un scheme serait\n * pire que n'en rendre aucun.\n */\nexport function parseParticipantId(value: string): {\n scheme: string;\n id: string;\n} {\n if (!value.includes(\":\")) {\n return { scheme: \"\", id: value };\n }\n return parsePeppolId(value);\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 { dashboardUrlForSendResult } from \"../lib/dashboard-url.js\";\nimport { formatSendResult } from \"../formatters/send-result.js\";\nimport { runSendPreflight } 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\";\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 the JSON send preflight\")\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. Build SDK client before validation: the sandbox integration fixture\n // needs the provider-side sender profile before its tax fields are final.\n const baseUrl = flags.local ? LOCAL_BASE : API_BASE;\n const client = new Peppol({ apiKey: auth.apiKey, baseUrl });\n\n if (auth.environment === \"sandbox\") {\n let profile;\n try {\n profile = (await client.identity.get()).sandboxFirstSend;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`${pc.red(\"✢\")} Could not verify the sandbox sender profile: ${msg}\\n`);\n process.exit(1);\n return;\n }\n if (!profile || profile.status !== \"ready\") {\n const message = profile?.status === \"blocked\"\n ? profile.message\n : \"The sandbox first-send profile is unavailable.\";\n process.stderr.write(`${pc.red(\"✢\")} ${message}\\n`);\n process.exit(1);\n return;\n }\n\n const taxEntries = [payload.lines, payload.allowances, payload.charges]\n .filter(Array.isArray)\n .flat();\n const payloadOutsideScope =\n taxEntries.length > 0 &&\n taxEntries.every((entry) => entry.vatCategory === \"O\");\n const profileOutsideScope = profile.taxMode === \"outside_scope\";\n\n if (file) {\n // A file is fiscal intent. Never rewrite it silently; refuse locally\n // before the API/provider if it conflicts with the measured sender.\n if (payloadOutsideScope !== profileOutsideScope) {\n process.stderr.write(\n `${pc.red(\"✢\")} This file's tax mode does not match the sandbox sender. ` +\n `GET /v1/identity recommends ${profile.line.vatCategory}/0. Nothing was sent.\\n`,\n );\n process.exit(1);\n return;\n }\n } else {\n // No file means the CLI's own integration fixture, not customer data:\n // adapt every generated line to the exact profile by construction.\n payload.lines = payload.lines.map((line) => ({ ...line, ...profile.line }));\n }\n }\n\n // 4. Pre-validate (unless --no-validate)\n if (flags.validate !== false) {\n const result = runSendPreflight(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 // 5. --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 // 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 = dashboardUrlForSendResult(result);\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\";\nimport { parsePeppolId, countryForScheme } 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\n/**\n * Le pays du destinataire, dérivé de son identifiant — GPR-1116.\n *\n * ⛔ Cette fonction portait DEUX défauts, et il faut les nommer tous les deux\n * parce que corriger l'un seul laisse l'autre livrer un pays faux.\n *\n * 1. Elle découpait par `peppolId.split(\":\")`. La forme symbolique d'un scheme\n * contient elle-même un `:` (98 des 105 entrées de la code list v9.7), donc\n * `GB:VAT:123456789` rendait `identifier = \"VAT\"`, dont le préfixe `VA`\n * passait le test alphabétique : un vendeur britannique devenait le Vatican.\n *\n * 2. Sa table de repli portait QUATRE schemes et renvoyait `\"BE\"` pour tout le\n * reste. Norvège, Suède, Pays-Bas, Turquie — tous déclarés belges, en\n * silence. La code list officielle couvre 96 schemes nationaux sur 50 pays,\n * et `countryForScheme` la consulte.\n *\n * ⭐ L'ordre compte : on demande d'abord son pays au SCHEME, qui est une donnée\n * publiée, avant de regarder le préfixe de la VALEUR, qui est une heuristique.\n * L'ordre inverse — celui d'avant — laissait une coïncidence de deux lettres\n * l'emporter sur la liste officielle.\n *\n * ⚠️ Le repli final reste `\"BE\"`, mais il ne s'applique plus qu'à un identifiant\n * dont NI le scheme NI la valeur ne disent le pays (`DUNS`, `GLN`, un code publié\n * après notre version de la liste). C'est un défaut de dernier recours dans un\n * fichier d'exemple, plus une réponse par défaut donnée à la moitié du monde.\n */\nfunction deriveCountryFromPeppolId(peppolId: PeppolId): CountryCode {\n const { scheme, id } = parsePeppolId(peppolId);\n\n const published = countryForScheme(scheme);\n if (published !== undefined) {\n return published as CountryCode;\n }\n\n // Certains identifiants portent leur pays en préfixe (`BE0314595348`). C'est\n // une heuristique, pas une règle — d'où sa place APRÈS la liste publiée.\n const alphaPrefix = id.slice(0, 2);\n if (/^[A-Za-z]{2}$/.test(alphaPrefix)) {\n return alphaPrefix.toUpperCase() as CountryCode;\n }\n\n return \"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\" = outside the scope of VAT (UBL 2.1 / EN 16931).\n // This offline fixture starts at O/0. Before sending, the CLI reads\n // GET /identity and replaces these tax fields with the sender-specific\n // O/0 or AE/0 first-send profile. The SDK transport strips the\n // builder-only reason so Storecove can derive its own provider text.\n vatCategory: \"O\",\n taxExemptReason: \"Not subject to VAT\",\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 type { SendResult } from \"@getpeppr/sdk\";\n\nconst DASHBOARD_INVOICES_BASE = \"https://console.getpeppr.dev/invoices\";\n\n/** Build the dashboard link printed after a successful send. */\nexport function dashboardUrlForSendResult(\n result: Pick<SendResult, \"id\">,\n): string {\n return `${DASHBOARD_INVOICES_BASE}/${result.id}`;\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 the credentials file ($XDG_CONFIG_HOME/getpeppr, %APPDATA%\\\\getpeppr on Windows)\")\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 the stored credentials file\")\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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Q,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAAQ,IAAI;EACb,CAAC,QAA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","names":["warn","DERIVED_AMOUNT_CONTRACT_RULE","survivesCents","resolve","readSentence","error","violation","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","pc","result","createInterface","pc","resolve","createInterface","program","pc","pc","API_BASE","LOCAL_BASE","pc","program","pc","program","pc","require"]}