@getpeppr/cli 0.8.1 → 0.8.2

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 CHANGED
@@ -130,6 +130,518 @@ Validating: ${pc.bold(filename)}
130
130
  return lines.join("\n");
131
131
  }
132
132
 
133
+ // ../sdk/dist/core/canonical-schemes.js
134
+ var ALIAS_TO_EAS = /* @__PURE__ */ new Map([
135
+ ["AD:VAT", "9922"],
136
+ ["AE:TIN", "0235"],
137
+ ["AL:VAT", "9923"],
138
+ ["AT:CID", "9916"],
139
+ ["AT:GOV", "9915"],
140
+ ["AT:KUR", "9919"],
141
+ ["AT:VAT", "9914"],
142
+ ["AU:ABN", "0151"],
143
+ ["BA:VAT", "9924"],
144
+ ["BE:CBE", "9956"],
145
+ ["BE:EN", "0208"],
146
+ ["BE:VAT", "9925"],
147
+ ["BG:VAT", "9926"],
148
+ ["CH:UIDB", "0183"],
149
+ ["CH:VAT", "9927"],
150
+ ["CY:VAT", "9928"],
151
+ ["CZ:VAT", "9929"],
152
+ ["DE:GEBA", "0246"],
153
+ ["DE:LID", "9958"],
154
+ ["DE:LWID", "0204"],
155
+ ["DE:VAT", "9930"],
156
+ ["DK:CPR", "9901"],
157
+ ["DK:CVR", "9902"],
158
+ ["DK:DIGST", "0184"],
159
+ ["DK:ERST", "0198"],
160
+ ["DK:P", "0096"],
161
+ ["DK:SE", "9904"],
162
+ ["DK:VANS", "9905"],
163
+ ["DUNS", "0060"],
164
+ ["EE:CC", "0191"],
165
+ ["EE:VAT", "9931"],
166
+ ["ES:VAT", "9920"],
167
+ ["EU:NAL", "0130"],
168
+ ["EU:REID", "9913"],
169
+ ["EU:VAT", "9912"],
170
+ ["FI:NSI", "0215"],
171
+ ["FI:ORG", "0212"],
172
+ ["FI:OVT", "0037"],
173
+ ["FI:OVT2", "0216"],
174
+ ["FI:VAT", "0213"],
175
+ ["FR:CTC", "0225"],
176
+ ["FR:SIRENE", "0002"],
177
+ ["FR:SIRET", "0009"],
178
+ ["FR:VAT", "9957"],
179
+ ["GB:VAT", "9932"],
180
+ ["GLN", "0088"],
181
+ ["GR:VAT", "9933"],
182
+ ["GS1", "0209"],
183
+ ["HR:VAT", "9934"],
184
+ ["HU:VAT", "9910"],
185
+ ["IBAN", "9918"],
186
+ ["IE:VAT", "9935"],
187
+ ["IS:KT", "9917"],
188
+ ["IS:KTNR", "0196"],
189
+ ["IT:CF", "9907"],
190
+ ["IT:CFI", "0210"],
191
+ ["IT:COD", "0205"],
192
+ ["IT:CUUO", "0201"],
193
+ ["IT:FTI", "0097"],
194
+ ["IT:IPA", "9921"],
195
+ ["IT:IVA", "0211"],
196
+ ["IT:SECETI", "0142"],
197
+ ["IT:SIA", "0135"],
198
+ ["IT:VAT", "9906"],
199
+ ["JP:IIN", "0221"],
200
+ ["JP:SST", "0188"],
201
+ ["LEI", "0199"],
202
+ ["LI:VAT", "9936"],
203
+ ["LT:LEC", "0200"],
204
+ ["LT:VAT", "9937"],
205
+ ["LU:MAT", "0240"],
206
+ ["LU:VAT", "9938"],
207
+ ["LV:URN", "0218"],
208
+ ["LV:VAT", "9939"],
209
+ ["MC:VAT", "9940"],
210
+ ["ME:VAT", "9941"],
211
+ ["MK:VAT", "9942"],
212
+ ["MT:VAT", "9943"],
213
+ ["MY:EIF", "0230"],
214
+ ["NG:TID", "0244"],
215
+ ["NL:KVK", "0106"],
216
+ ["NL:OIN", "9954"],
217
+ ["NL:OINO", "0190"],
218
+ ["NL:VAT", "9944"],
219
+ ["NO:ORG", "0192"],
220
+ ["NO:ORGNR", "9908"],
221
+ ["NO:VAT", "9909"],
222
+ ["OM:VAT", "0248"],
223
+ ["PL:VAT", "9945"],
224
+ ["PT:VAT", "9946"],
225
+ ["RO:VAT", "9947"],
226
+ ["RS:VAT", "9948"],
227
+ ["SE:ORGNR", "0007"],
228
+ ["SE:VAT", "9955"],
229
+ ["SG:UEN", "0195"],
230
+ ["SI:VAT", "9949"],
231
+ ["SK:DIC", "0245"],
232
+ ["SK:ICO", "0158"],
233
+ ["SK:VAT", "9950"],
234
+ ["SM:VAT", "9951"],
235
+ ["SPIS", "0242"],
236
+ ["TR:VAT", "9952"],
237
+ ["UBLBE", "0193"],
238
+ ["US:EIN", "9959"],
239
+ ["VA:VAT", "9953"]
240
+ ]);
241
+ function asciiUpper(value) {
242
+ let out = "";
243
+ for (const char of value) {
244
+ const code = char.charCodeAt(0);
245
+ out += code >= 97 && code <= 122 ? String.fromCharCode(code - 32) : char;
246
+ }
247
+ return out;
248
+ }
249
+ function canonicalScheme(scheme) {
250
+ return lookupCanonicalScheme(scheme) ?? scheme.trim();
251
+ }
252
+ function lookupCanonicalScheme(scheme) {
253
+ return ALIAS_TO_EAS.get(asciiUpper(scheme.trim()));
254
+ }
255
+ var EAS_TO_COUNTRY = /* @__PURE__ */ new Map([
256
+ ["0002", "FR"],
257
+ ["0007", "SE"],
258
+ ["0009", "FR"],
259
+ ["0037", "FI"],
260
+ ["0096", "DK"],
261
+ ["0097", "IT"],
262
+ ["0106", "NL"],
263
+ ["0135", "IT"],
264
+ ["0142", "IT"],
265
+ ["0151", "AU"],
266
+ ["0158", "SK"],
267
+ ["0183", "CH"],
268
+ ["0184", "DK"],
269
+ ["0188", "JP"],
270
+ ["0190", "NL"],
271
+ ["0191", "EE"],
272
+ ["0192", "NO"],
273
+ ["0193", "BE"],
274
+ ["0195", "SG"],
275
+ ["0196", "IS"],
276
+ ["0198", "DK"],
277
+ ["0200", "LT"],
278
+ ["0201", "IT"],
279
+ ["0204", "DE"],
280
+ ["0205", "IT"],
281
+ ["0208", "BE"],
282
+ ["0210", "IT"],
283
+ ["0211", "IT"],
284
+ ["0212", "FI"],
285
+ ["0213", "FI"],
286
+ ["0215", "FI"],
287
+ ["0216", "FI"],
288
+ ["0218", "LV"],
289
+ ["0221", "JP"],
290
+ ["0225", "FR"],
291
+ ["0230", "MY"],
292
+ ["0235", "AE"],
293
+ ["0240", "LU"],
294
+ ["0244", "NG"],
295
+ ["0245", "SK"],
296
+ ["0246", "DE"],
297
+ ["0248", "OM"],
298
+ ["9901", "DK"],
299
+ ["9902", "DK"],
300
+ ["9904", "DK"],
301
+ ["9905", "DK"],
302
+ ["9906", "IT"],
303
+ ["9907", "IT"],
304
+ ["9908", "NO"],
305
+ ["9909", "NO"],
306
+ ["9910", "HU"],
307
+ ["9914", "AT"],
308
+ ["9915", "AT"],
309
+ ["9916", "AT"],
310
+ ["9917", "IS"],
311
+ ["9919", "AT"],
312
+ ["9920", "ES"],
313
+ ["9921", "IT"],
314
+ ["9922", "AD"],
315
+ ["9923", "AL"],
316
+ ["9924", "BA"],
317
+ ["9925", "BE"],
318
+ ["9926", "BG"],
319
+ ["9927", "CH"],
320
+ ["9928", "CY"],
321
+ ["9929", "CZ"],
322
+ ["9930", "DE"],
323
+ ["9931", "EE"],
324
+ ["9932", "GB"],
325
+ ["9933", "GR"],
326
+ ["9934", "HR"],
327
+ ["9935", "IE"],
328
+ ["9936", "LI"],
329
+ ["9937", "LT"],
330
+ ["9938", "LU"],
331
+ ["9939", "LV"],
332
+ ["9940", "MC"],
333
+ ["9941", "ME"],
334
+ ["9942", "MK"],
335
+ ["9943", "MT"],
336
+ ["9944", "NL"],
337
+ ["9945", "PL"],
338
+ ["9946", "PT"],
339
+ ["9947", "RO"],
340
+ ["9948", "RS"],
341
+ ["9949", "SI"],
342
+ ["9950", "SK"],
343
+ ["9951", "SM"],
344
+ ["9952", "TR"],
345
+ ["9953", "VA"],
346
+ ["9954", "NL"],
347
+ ["9955", "SE"],
348
+ ["9956", "BE"],
349
+ ["9957", "FR"],
350
+ ["9958", "DE"],
351
+ ["9959", "US"]
352
+ ]);
353
+ function countryForScheme(scheme) {
354
+ return EAS_TO_COUNTRY.get(canonicalScheme(scheme));
355
+ }
356
+ var CANONICAL_SCHEME_COUNT = ALIAS_TO_EAS.size;
357
+ var SCHEME_COUNTRY_COUNT = EAS_TO_COUNTRY.size;
358
+
359
+ // ../sdk/dist/core/peppol-id.js
360
+ function isWellFormedPeppolId(peppolId) {
361
+ if (!peppolId.includes(":"))
362
+ return false;
363
+ const { scheme, id } = parsePeppolId(peppolId);
364
+ return id.trim().length > 0 && (/^\d{4}$/.test(scheme) || EAS_LITERAL_SCHEMES.has(scheme));
365
+ }
366
+ var EAS_LITERAL_SCHEMES = /* @__PURE__ */ new Set(["AN", "AQ", "AS", "AU", "EM", "SEPA"]);
367
+ function parsePeppolId(peppolId) {
368
+ const first = peppolId.indexOf(":");
369
+ if (first === -1) {
370
+ return { scheme: canonicalScheme(peppolId), id: "" };
371
+ }
372
+ const second = peppolId.indexOf(":", first + 1);
373
+ if (second !== -1) {
374
+ const resolved = lookupCanonicalScheme(peppolId.slice(0, second));
375
+ if (resolved !== void 0) {
376
+ return { scheme: resolved, id: peppolId.slice(second + 1) };
377
+ }
378
+ }
379
+ return {
380
+ scheme: canonicalScheme(peppolId.slice(0, first)),
381
+ id: peppolId.slice(first + 1)
382
+ };
383
+ }
384
+
385
+ // ../sdk/dist/core/iso6523-icd-codes.js
386
+ var ICD_CODES = /* @__PURE__ */ new Set([
387
+ "0002",
388
+ "0003",
389
+ "0004",
390
+ "0005",
391
+ "0006",
392
+ "0007",
393
+ "0008",
394
+ "0009",
395
+ "0010",
396
+ "0011",
397
+ "0012",
398
+ "0013",
399
+ "0014",
400
+ "0015",
401
+ "0016",
402
+ "0017",
403
+ "0018",
404
+ "0019",
405
+ "0020",
406
+ "0021",
407
+ "0022",
408
+ "0023",
409
+ "0024",
410
+ "0025",
411
+ "0026",
412
+ "0027",
413
+ "0028",
414
+ "0029",
415
+ "0030",
416
+ "0031",
417
+ "0032",
418
+ "0033",
419
+ "0034",
420
+ "0035",
421
+ "0036",
422
+ "0037",
423
+ "0038",
424
+ "0039",
425
+ "0040",
426
+ "0041",
427
+ "0042",
428
+ "0043",
429
+ "0044",
430
+ "0045",
431
+ "0046",
432
+ "0047",
433
+ "0048",
434
+ "0049",
435
+ "0050",
436
+ "0051",
437
+ "0052",
438
+ "0053",
439
+ "0054",
440
+ "0055",
441
+ "0056",
442
+ "0057",
443
+ "0058",
444
+ "0059",
445
+ "0060",
446
+ "0061",
447
+ "0062",
448
+ "0063",
449
+ "0064",
450
+ "0065",
451
+ "0066",
452
+ "0067",
453
+ "0068",
454
+ "0069",
455
+ "0070",
456
+ "0071",
457
+ "0072",
458
+ "0073",
459
+ "0074",
460
+ "0075",
461
+ "0076",
462
+ "0077",
463
+ "0078",
464
+ "0079",
465
+ "0080",
466
+ "0081",
467
+ "0082",
468
+ "0083",
469
+ "0084",
470
+ "0085",
471
+ "0086",
472
+ "0087",
473
+ "0088",
474
+ "0089",
475
+ "0090",
476
+ "0091",
477
+ "0093",
478
+ "0094",
479
+ "0095",
480
+ "0096",
481
+ "0097",
482
+ "0098",
483
+ "0099",
484
+ "0100",
485
+ "0101",
486
+ "0102",
487
+ "0104",
488
+ "0105",
489
+ "0106",
490
+ "0107",
491
+ "0108",
492
+ "0109",
493
+ "0110",
494
+ "0111",
495
+ "0112",
496
+ "0113",
497
+ "0114",
498
+ "0115",
499
+ "0116",
500
+ "0117",
501
+ "0118",
502
+ "0119",
503
+ "0120",
504
+ "0121",
505
+ "0122",
506
+ "0123",
507
+ "0124",
508
+ "0125",
509
+ "0126",
510
+ "0127",
511
+ "0128",
512
+ "0129",
513
+ "0130",
514
+ "0131",
515
+ "0132",
516
+ "0133",
517
+ "0134",
518
+ "0135",
519
+ "0136",
520
+ "0137",
521
+ "0138",
522
+ "0139",
523
+ "0140",
524
+ "0141",
525
+ "0142",
526
+ "0143",
527
+ "0144",
528
+ "0145",
529
+ "0146",
530
+ "0147",
531
+ "0148",
532
+ "0149",
533
+ "0150",
534
+ "0151",
535
+ "0152",
536
+ "0153",
537
+ "0154",
538
+ "0155",
539
+ "0156",
540
+ "0157",
541
+ "0158",
542
+ "0159",
543
+ "0160",
544
+ "0161",
545
+ "0162",
546
+ "0163",
547
+ "0164",
548
+ "0165",
549
+ "0166",
550
+ "0167",
551
+ "0168",
552
+ "0169",
553
+ "0170",
554
+ "0171",
555
+ "0172",
556
+ "0173",
557
+ "0174",
558
+ "0175",
559
+ "0176",
560
+ "0177",
561
+ "0178",
562
+ "0179",
563
+ "0180",
564
+ "0183",
565
+ "0184",
566
+ "0185",
567
+ "0186",
568
+ "0187",
569
+ "0188",
570
+ "0189",
571
+ "0190",
572
+ "0191",
573
+ "0192",
574
+ "0193",
575
+ "0194",
576
+ "0195",
577
+ "0196",
578
+ "0197",
579
+ "0198",
580
+ "0199",
581
+ "0200",
582
+ "0201",
583
+ "0202",
584
+ "0203",
585
+ "0204",
586
+ "0205",
587
+ "0206",
588
+ "0207",
589
+ "0208",
590
+ "0209",
591
+ "0210",
592
+ "0211",
593
+ "0212",
594
+ "0213",
595
+ "0214",
596
+ "0215",
597
+ "0216",
598
+ "0217",
599
+ "0218",
600
+ "0219",
601
+ "0220",
602
+ "0221",
603
+ "0222",
604
+ "0223",
605
+ "0224",
606
+ "0225",
607
+ "0226",
608
+ "0227",
609
+ "0228",
610
+ "0229",
611
+ "0230",
612
+ "0231",
613
+ "0232",
614
+ "0233",
615
+ "0234",
616
+ "0235",
617
+ "0236",
618
+ "0237",
619
+ "0238",
620
+ "0239",
621
+ "0240",
622
+ "0241",
623
+ "0242",
624
+ "0243",
625
+ "0244",
626
+ "0245"
627
+ ]);
628
+ var ISO6523_ICD_CODES = Object.freeze({
629
+ has: (v) => ICD_CODES.has(v),
630
+ get size() {
631
+ return ICD_CODES.size;
632
+ },
633
+ keys: () => ICD_CODES.keys(),
634
+ values: () => ICD_CODES.values(),
635
+ entries: () => ICD_CODES.entries(),
636
+ forEach: (fn, thisArg) => ICD_CODES.forEach((v, v2) => fn.call(thisArg, v, v2, ISO6523_ICD_CODES)),
637
+ [Symbol.iterator]: () => ICD_CODES[Symbol.iterator]()
638
+ });
639
+ function canCarryPartyIdentification(scheme, context) {
640
+ if (ICD_CODES.has(scheme))
641
+ return true;
642
+ return scheme === "SEPA" && context !== "AccountingCustomerParty";
643
+ }
644
+
133
645
  // ../sdk/dist/core/ubl-builder.js
134
646
  var UBL_NS = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2";
135
647
  var CAC_NS = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2";
@@ -184,20 +696,34 @@ function formatAmount(amount) {
184
696
  function round2(n) {
185
697
  return Math.round(n * 100) / 100;
186
698
  }
187
- function parsePeppolId(peppolId) {
188
- const scheme = peppolId.split(":")[0];
189
- const id = peppolId.split(":").slice(1).join(":");
190
- return { scheme, id };
191
- }
192
699
  function buildPartyXml(party, role) {
193
700
  const { scheme: endpointScheme, id: endpointId } = parsePeppolId(party.peppolId);
194
701
  return `
195
702
  <cac:${role}>
196
703
  <cac:Party>
197
704
  <cbc:EndpointID schemeID="${escapeXml(endpointScheme)}">${escapeXml(endpointId)}</cbc:EndpointID>
198
- <cac:PartyIdentification>
705
+ ${// ⛔ DEUX listes, pas une. `BR-CL-25` juge l'EndpointID ci-dessus contre la
706
+ // liste EAS (101 valeurs, jusqu'à `9959`) ; `BR-CL-10` juge CE champ-ci
707
+ // contre la liste ISO 6523 ICD (240 valeurs, `0002`–`0245`). `9932` (GB),
708
+ // `9935` (IE) et `9930` (DE) sont légaux là-haut et FATALS ici.
709
+ //
710
+ // Le champ (BT-29) est optionnel : l'omettre est la seule écriture
711
+ // conforme pour ces schemes, et c'est ce que le tir réseau de GPR-1102
712
+ // avait déjà mesuré — `9932`/`9935` n'apparaissent ni en BT-29 ni en
713
+ // BT-30, seulement en BT-31. Émettre quand même rendait `BR-CL-10` fatale
714
+ // pour tout vendeur britannique, irlandais ou allemand en `9930`,
715
+ // y compris en écrivant la forme numérique (GPR-1110).
716
+ //
717
+ // ⚠️ BR-CO-26 exige alors qu'un autre identifiant porte l'expéditeur —
718
+ // `vatNumber` (BT-31) ou `companyId` (BT-30) ci-dessous. `validateInvoice`
719
+ // AVERTIT quand il n'y en a aucun ; il ne refuse pas, et `toXml()` rend
720
+ // donc bel et bien un document que le réseau rejettera. C'est délibéré :
721
+ // `from` est déclaré « deprecated and ignored » à l'envoi, où l'expéditeur
722
+ // vient de la clé API — bloquer ici casserait des appelants dont le
723
+ // document part très bien.
724
+ canCarryPartyIdentification(endpointScheme, role) ? `<cac:PartyIdentification>
199
725
  <cbc:ID schemeID="${escapeXml(endpointScheme)}">${escapeXml(endpointId)}</cbc:ID>
200
- </cac:PartyIdentification>
726
+ </cac:PartyIdentification>` : ""}
201
727
  <cac:PartyName>
202
728
  <cbc:Name>${escapeXml(party.name)}</cbc:Name>
203
729
  </cac:PartyName>
@@ -231,9 +757,12 @@ function buildPayeePartyXml(party) {
231
757
  const { scheme, id } = parsePeppolId(party.peppolId);
232
758
  return `
233
759
  <cac:PayeeParty>
234
- <cac:PartyIdentification>
760
+ ${// Même règle qu'au-dessus : `BR-CL-10` a pour contexte TOUT
761
+ // `cac:PartyIdentification/cbc:ID[@schemeID]`, PayeeParty compris. Le
762
+ // bénéficiaire (BT-60) reste identifié par son nom, toujours émis.
763
+ canCarryPartyIdentification(scheme, "PayeeParty") ? `<cac:PartyIdentification>
235
764
  <cbc:ID schemeID="${escapeXml(scheme)}">${escapeXml(id)}</cbc:ID>
236
- </cac:PartyIdentification>
765
+ </cac:PartyIdentification>` : ""}
237
766
  <cac:PartyName>
238
767
  <cbc:Name>${escapeXml(party.name)}</cbc:Name>
239
768
  </cac:PartyName>
@@ -964,8 +1493,8 @@ function validateParty(party, path) {
964
1493
  if (party.peppolId === void 0 || party.peppolId === null || party.peppolId === "") {
965
1494
  errors.push(error(`${path}.peppolId`, "Peppol participant ID is required", void 0, 'Format: "scheme:id", e.g. "0208:0685660237" for Belgian companies'));
966
1495
  } else if (!assertString(party.peppolId, `${path}.peppolId`, errors)) {
967
- } else if (!party.peppolId.includes(":")) {
968
- errors.push(error(`${path}.peppolId`, `Invalid Peppol ID format: "${party.peppolId}"`, void 0, 'Must be "scheme:id" format. Common schemes: 0208 (Belgium), 0009 (France SIRET), 0204 (Germany Leitweg)'));
1496
+ } else if (!isWellFormedPeppolId(party.peppolId)) {
1497
+ errors.push(error(`${path}.peppolId`, `Invalid Peppol ID format: "${party.peppolId}"`, void 0, 'Must be "scheme:id" \u2014 e.g. "0208:0685660237" or "GB:VAT:123456789". The scheme alone ("GB:VAT") is not an identifier.'));
969
1498
  }
970
1499
  if (party.country === void 0 || party.country === null || party.country === "") {
971
1500
  errors.push(error(`${path}.country`, "Country code is required", "BR-11"));
@@ -1047,6 +1576,14 @@ function validateInvoice(input) {
1047
1576
  }
1048
1577
  if (input.from) {
1049
1578
  warnings.push(warning("from", "Seller info is determined by your API key. The 'from' field is deprecated and ignored."));
1579
+ const fromId = input.from.peppolId;
1580
+ if (typeof fromId === "string" && fromId.length > 0) {
1581
+ const { scheme } = parsePeppolId(fromId);
1582
+ const bt29Written = canCarryPartyIdentification(scheme, "AccountingSupplierParty");
1583
+ if (!bt29Written && !input.from.vatNumber && !input.from.companyId) {
1584
+ warnings.push(warning("from.peppolId", `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.`, "BR-CO-26"));
1585
+ }
1586
+ }
1050
1587
  }
1051
1588
  if (!input.to) {
1052
1589
  errors.push(error("to", "Buyer (to) is required", "BR-07"));
@@ -1066,8 +1603,8 @@ function validateInvoice(input) {
1066
1603
  if (ppId === void 0 || ppId === null || ppId === "") {
1067
1604
  errors.push(error("payeeParty.peppolId", "Payee party Peppol ID is required", void 0, 'Format: "scheme:id", e.g. "0208:0685660237"'));
1068
1605
  } else if (!assertString(ppId, "payeeParty.peppolId", errors)) {
1069
- } else if (!ppId.includes(":")) {
1070
- errors.push(error("payeeParty.peppolId", `Invalid Peppol ID format: "${ppId}"`, void 0, 'Must be "scheme:id" format'));
1606
+ } else if (!isWellFormedPeppolId(ppId)) {
1607
+ errors.push(error("payeeParty.peppolId", `Invalid Peppol ID format: "${ppId}"`, void 0, 'Must be "scheme:id" \u2014 e.g. "0208:0685660237". The scheme alone ("GB:VAT") is not an identifier.'));
1071
1608
  }
1072
1609
  }
1073
1610
  if (!input.lines || input.lines.length === 0) {
@@ -1161,7 +1698,7 @@ function statusFamily(status) {
1161
1698
  var TERMINAL_FAILURE_STATUSES = STATUS_PRECEDENCE.filter((e) => e.family === "terminal-failure").map((e) => e.status);
1162
1699
 
1163
1700
  // ../sdk/dist/version.js
1164
- var SDK_VERSION = "4.3.0";
1701
+ var SDK_VERSION = "4.5.0";
1165
1702
 
1166
1703
  // ../sdk/dist/core/client.js
1167
1704
  function findHeaderCaseInsensitive(headers, name) {
@@ -1761,7 +2298,24 @@ var GetpepprAdapter = class {
1761
2298
  // Declared, never derived from the document: routing decides delivery, and
1762
2299
  // parsing a caller's XML for a destination would put a parse error on the
1763
2300
  // "whose invoice goes where" path.
1764
- to: options.to
2301
+ to: options.to,
2302
+ // ⛔ GPR-1129 — ce corps est une LISTE BLANCHE, exactement comme
2303
+ // `parseSendResult` l'est en sortie : tout champ non recopié ici est
2304
+ // supprimé en SILENCE, et la capacité correspondante devient
2305
+ // inatteignable pour quiconque passe par le SDK.
2306
+ //
2307
+ // Quatrième occurrence de cette classe, la première dans le sens REQUÊTE
2308
+ // (`rulebook` GPR-1069, `transmission` GPR-1089, `duplicateOf` GPR-1105
2309
+ // étaient des champs de RÉPONSE). Le préjudice n'est pas symétrique : un
2310
+ // champ de réponse jeté casse qui le lit, un champ de requête jeté
2311
+ // produit un refus que l'appelant ne peut relier à rien — il envoie
2312
+ // `sender`, la passerelle ne le voit jamais, et le 422 qu'il reçoit parle
2313
+ // d'une identité qu'il ne revendiquait pas.
2314
+ //
2315
+ // ⚠️ Conditionnel, jamais `sender: options.sender` : une clé présente à
2316
+ // `undefined` disparaît du JSON, donc l'écriture nue passerait les tests
2317
+ // tout en salissant le corps des envois standards.
2318
+ ...options.sender ? { sender: options.sender } : {}
1765
2319
  };
1766
2320
  const result = await this.request("POST", "/invoices/import", body);
1767
2321
  return parseSendResult(result);
@@ -1883,6 +2437,9 @@ function parseSendResult(body) {
1883
2437
  sendResult.transmission = { mode, bytePreservation };
1884
2438
  }
1885
2439
  }
2440
+ const duplicateOf = optionalWireId(readOwn(result, "duplicateOf"));
2441
+ if (duplicateOf)
2442
+ sendResult.duplicateOf = duplicateOf;
1886
2443
  const submissionId = optionalWireId(result.submissionId);
1887
2444
  if (submissionId)
1888
2445
  sendResult.submissionId = submissionId;
@@ -2253,9 +2810,11 @@ var Peppol = class {
2253
2810
  * API with `peppol.identity.get()`, which works with any key. This surface is
2254
2811
  * for platforms that onboard their customers as sub-tenants.
2255
2812
  *
2256
- * **Getting access:** platform mode is enabled by getpeppr on your account —
2257
- * email hello@getpeppr.dev to have it switched on. Once it is, you create the
2258
- * master key yourself at https://console.getpeppr.dev/api-keys.
2813
+ * **Getting access:** in the sandbox, an organisation admin starts the
2814
+ * platform sandbox trial from the console overview (or chooses "A platform
2815
+ * for my customers" at signup), then creates the sandbox master key at
2816
+ * https://console.getpeppr.dev/api-keys. Production platform access is set up
2817
+ * with our team — email hello@getpeppr.dev to request it.
2259
2818
  *
2260
2819
  * @see https://getpeppr.dev/docs/platform/legal-entities/
2261
2820
  */
@@ -2702,12 +3261,10 @@ var DirectoryOperations = class {
2702
3261
  * ```
2703
3262
  */
2704
3263
  async lookup(peppolId) {
2705
- const colonIndex = peppolId.indexOf(":");
2706
- if (colonIndex === -1) {
3264
+ if (!peppolId.includes(":")) {
2707
3265
  throw new PeppolError('Invalid Peppol ID format. Expected "scheme:id" (e.g., "0208:0685660237")');
2708
3266
  }
2709
- const scheme = peppolId.slice(0, colonIndex);
2710
- const id = peppolId.slice(colonIndex + 1);
3267
+ const { scheme, id } = parsePeppolId(peppolId);
2711
3268
  return this.adapter.lookupDirectory(scheme, id);
2712
3269
  }
2713
3270
  /**
@@ -2907,9 +3464,11 @@ var LegalEntityOperations = class {
2907
3464
  /**
2908
3465
  * Create a sub-tenant Legal Entity for one of your customers.
2909
3466
  *
2910
- * **Platform accounts only — requires a master API key.** Platform mode is
2911
- * enabled by getpeppr: email hello@getpeppr.dev, then create the key at
2912
- * https://console.getpeppr.dev/api-keys.
3467
+ * **Platform accounts only — requires a master API key.** In the sandbox,
3468
+ * an organisation admin starts the platform sandbox trial from the console
3469
+ * overview and creates a sandbox master key at
3470
+ * https://console.getpeppr.dev/api-keys; production platform access is set
3471
+ * up with our team (hello@getpeppr.dev).
2913
3472
  *
2914
3473
  * Your own company's legal entity is managed in the console, on the Peppol
2915
3474
  * identity page (and read from the API with `peppol.identity.get()`); this
@@ -2936,9 +3495,11 @@ var LegalEntityOperations = class {
2936
3495
  /**
2937
3496
  * Fetch a single sub-tenant Legal Entity by id.
2938
3497
  *
2939
- * **Platform accounts only — requires a master API key.** Platform mode is
2940
- * enabled by getpeppr: email hello@getpeppr.dev, then create the key at
2941
- * https://console.getpeppr.dev/api-keys.
3498
+ * **Platform accounts only — requires a master API key.** In the sandbox,
3499
+ * an organisation admin starts the platform sandbox trial from the console
3500
+ * overview and creates a sandbox master key at
3501
+ * https://console.getpeppr.dev/api-keys; production platform access is set
3502
+ * up with our team (hello@getpeppr.dev).
2942
3503
  *
2943
3504
  * For production entities the `status` reflects the attestation lifecycle
2944
3505
  * (awaiting_authz → attested → active).
@@ -2949,9 +3510,11 @@ var LegalEntityOperations = class {
2949
3510
  /**
2950
3511
  * List your sub-tenant Legal Entities, newest first.
2951
3512
  *
2952
- * **Platform accounts only — requires a master API key.** Platform mode is
2953
- * enabled by getpeppr: email hello@getpeppr.dev, then create the key at
2954
- * https://console.getpeppr.dev/api-keys.
3513
+ * **Platform accounts only — requires a master API key.** In the sandbox,
3514
+ * an organisation admin starts the platform sandbox trial from the console
3515
+ * overview and creates a sandbox master key at
3516
+ * https://console.getpeppr.dev/api-keys; production platform access is set
3517
+ * up with our team (hello@getpeppr.dev).
2955
3518
  *
2956
3519
  * This lists the customers you have onboarded, never your own legal entity.
2957
3520
  */
@@ -2961,9 +3524,11 @@ var LegalEntityOperations = class {
2961
3524
  /**
2962
3525
  * Async iterator over all sub-tenant Legal Entities, handling pagination.
2963
3526
  *
2964
- * **Platform accounts only — requires a master API key.** Platform mode is
2965
- * enabled by getpeppr: email hello@getpeppr.dev, then create the key at
2966
- * https://console.getpeppr.dev/api-keys.
3527
+ * **Platform accounts only — requires a master API key.** In the sandbox,
3528
+ * an organisation admin starts the platform sandbox trial from the console
3529
+ * overview and creates a sandbox master key at
3530
+ * https://console.getpeppr.dev/api-keys; production platform access is set
3531
+ * up with our team (hello@getpeppr.dev).
2967
3532
  *
2968
3533
  * @example
2969
3534
  * ```ts
@@ -2977,9 +3542,11 @@ var LegalEntityOperations = class {
2977
3542
  * Archive (soft-delete) a sub-tenant Legal Entity. The id stays resolvable
2978
3543
  * for audit.
2979
3544
  *
2980
- * **Platform accounts only — requires a master API key.** Platform mode is
2981
- * enabled by getpeppr: email hello@getpeppr.dev, then create the key at
2982
- * https://console.getpeppr.dev/api-keys.
3545
+ * **Platform accounts only — requires a master API key.** In the sandbox,
3546
+ * an organisation admin starts the platform sandbox trial from the console
3547
+ * overview and creates a sandbox master key at
3548
+ * https://console.getpeppr.dev/api-keys; production platform access is set
3549
+ * up with our team (hello@getpeppr.dev).
2983
3550
  */
2984
3551
  async archive(id) {
2985
3552
  return this.adapter.archiveLegalEntity(id);
@@ -2988,9 +3555,11 @@ var LegalEntityOperations = class {
2988
3555
  * Request a sub-tenant attestation (production only). Emails the co-branded
2989
3556
  * confirmation link to the sub-tenant contact and returns the pending status.
2990
3557
  *
2991
- * **Platform accounts only — requires a master API key.** Platform mode is
2992
- * enabled by getpeppr: email hello@getpeppr.dev, then create the key at
2993
- * https://console.getpeppr.dev/api-keys.
3558
+ * **Platform accounts only — requires a master API key.** In the sandbox,
3559
+ * an organisation admin starts the platform sandbox trial from the console
3560
+ * overview and creates a sandbox master key at
3561
+ * https://console.getpeppr.dev/api-keys; production platform access is set
3562
+ * up with our team (hello@getpeppr.dev).
2994
3563
  *
2995
3564
  * Transient failures are NOT auto-retried unless you pass `options.idempotencyKey`;
2996
3565
  * re-issuing mints a fresh token, so a retried call is safe.
@@ -3927,12 +4496,11 @@ function validatePeppolId(raw) {
3927
4496
  error: `Invalid Peppol ID format: "${raw}". Expected format: scheme:id (e.g. 0208:0685660237)`
3928
4497
  };
3929
4498
  }
3930
- const scheme = raw.slice(0, colonIndex);
3931
- const id = raw.slice(colonIndex + 1);
4499
+ const { scheme, id } = parsePeppolId(raw);
3932
4500
  if (!/^\d{4}$/.test(scheme)) {
3933
4501
  return {
3934
4502
  ok: false,
3935
- error: `Invalid scheme "${scheme}". Must be exactly 4 digits (e.g. 0208).`
4503
+ error: `Invalid scheme "${scheme}". Must be a 4-digit EAS code (e.g. 0208) or a published symbolic scheme (e.g. GB:VAT).`
3936
4504
  };
3937
4505
  }
3938
4506
  if (!/^[A-Za-z0-9:.\-]+$/.test(id)) {
@@ -4179,19 +4747,17 @@ startxref
4179
4747
  190
4180
4748
  %%EOF`;
4181
4749
  var MINIMAL_TEST_PDF_BASE64 = Buffer.from(MINIMAL_PDF).toString("base64");
4182
- var SCHEME_COUNTRY_DEFAULTS = {
4183
- "0009": "FR",
4184
- "0204": "DE",
4185
- "0208": "BE",
4186
- "9925": "BE"
4187
- };
4188
4750
  function deriveCountryFromPeppolId(peppolId) {
4189
- const [scheme, identifier = ""] = peppolId.split(":");
4190
- const alphaPrefix = identifier.slice(0, 2);
4751
+ const { scheme, id } = parsePeppolId(peppolId);
4752
+ const published = countryForScheme(scheme);
4753
+ if (published !== void 0) {
4754
+ return published;
4755
+ }
4756
+ const alphaPrefix = id.slice(0, 2);
4191
4757
  if (/^[A-Za-z]{2}$/.test(alphaPrefix)) {
4192
4758
  return alphaPrefix.toUpperCase();
4193
4759
  }
4194
- return SCHEME_COUNTRY_DEFAULTS[scheme] ?? "BE";
4760
+ return "BE";
4195
4761
  }
4196
4762
  function buildDefaultSendPayload(overrides = {}) {
4197
4763
  const today = /* @__PURE__ */ new Date();