@getpeppr/cli 0.3.1 → 0.4.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 CHANGED
@@ -735,6 +735,131 @@ function validateCountryRules(input) {
735
735
  return { errors, warnings };
736
736
  }
737
737
 
738
+ // ../sdk/dist/core/code-lists.js
739
+ var CURRENCIES = /* @__PURE__ */ new Map([
740
+ ["EUR", { code: "EUR", name: "Euro", minorUnits: 2 }],
741
+ ["USD", { code: "USD", name: "US Dollar", minorUnits: 2 }],
742
+ ["GBP", { code: "GBP", name: "Pound Sterling", minorUnits: 2 }],
743
+ ["CHF", { code: "CHF", name: "Swiss Franc", minorUnits: 2 }],
744
+ ["DKK", { code: "DKK", name: "Danish Krone", minorUnits: 2 }],
745
+ ["NOK", { code: "NOK", name: "Norwegian Krone", minorUnits: 2 }],
746
+ ["SEK", { code: "SEK", name: "Swedish Krona", minorUnits: 2 }],
747
+ ["PLN", { code: "PLN", name: "Polish Zloty", minorUnits: 2 }],
748
+ ["CZK", { code: "CZK", name: "Czech Koruna", minorUnits: 2 }],
749
+ ["HUF", { code: "HUF", name: "Hungarian Forint", minorUnits: 2 }],
750
+ ["RON", { code: "RON", name: "Romanian Leu", minorUnits: 2 }],
751
+ ["BGN", { code: "BGN", name: "Bulgarian Lev", minorUnits: 2 }],
752
+ ["HRK", { code: "HRK", name: "Croatian Kuna", minorUnits: 2 }],
753
+ ["ISK", { code: "ISK", name: "Icelandic Krona", minorUnits: 0 }],
754
+ ["TRY", { code: "TRY", name: "Turkish Lira", minorUnits: 2 }],
755
+ ["JPY", { code: "JPY", name: "Japanese Yen", minorUnits: 0 }],
756
+ ["CNY", { code: "CNY", name: "Chinese Yuan", minorUnits: 2 }],
757
+ ["KRW", { code: "KRW", name: "South Korean Won", minorUnits: 0 }],
758
+ ["INR", { code: "INR", name: "Indian Rupee", minorUnits: 2 }],
759
+ ["SGD", { code: "SGD", name: "Singapore Dollar", minorUnits: 2 }],
760
+ ["AUD", { code: "AUD", name: "Australian Dollar", minorUnits: 2 }],
761
+ ["NZD", { code: "NZD", name: "New Zealand Dollar", minorUnits: 2 }],
762
+ ["CAD", { code: "CAD", name: "Canadian Dollar", minorUnits: 2 }],
763
+ ["BRL", { code: "BRL", name: "Brazilian Real", minorUnits: 2 }],
764
+ ["MXN", { code: "MXN", name: "Mexican Peso", minorUnits: 2 }],
765
+ ["ZAR", { code: "ZAR", name: "South African Rand", minorUnits: 2 }],
766
+ ["AED", { code: "AED", name: "UAE Dirham", minorUnits: 2 }],
767
+ ["SAR", { code: "SAR", name: "Saudi Riyal", minorUnits: 2 }],
768
+ ["ILS", { code: "ILS", name: "Israeli Shekel", minorUnits: 2 }],
769
+ ["HKD", { code: "HKD", name: "Hong Kong Dollar", minorUnits: 2 }],
770
+ ["TWD", { code: "TWD", name: "Taiwan Dollar", minorUnits: 2 }]
771
+ ]);
772
+ function getCurrency(code) {
773
+ return CURRENCIES.get(code.toUpperCase());
774
+ }
775
+ var EAS_SCHEMES = [
776
+ { code: "0002", name: "System Information et Repertoire des Entreprises et des Etablissements (SIRENE)", country: "FR" },
777
+ { code: "0007", name: "Organisationsnummer", country: "SE" },
778
+ { code: "0009", name: "SIRET-CODE", country: "FR" },
779
+ { code: "0088", name: "EAN Location Code (GLN)" },
780
+ { code: "0096", name: "Danish Chamber of Commerce (P-nummer)", country: "DK" },
781
+ { code: "0184", name: "Danish Central Business Register (CVR)", country: "DK" },
782
+ { code: "0190", name: "Dutch Chamber of Commerce (KVK)", country: "NL" },
783
+ { code: "0191", name: "Organisatie Identificatie Nummer (OIN)", country: "NL" },
784
+ { code: "0192", name: "Danish SE-number (Erhvervsstyrelsen)", country: "DK" },
785
+ { code: "0195", name: "Singapore Unique Entity Number (UEN)", country: "SG" },
786
+ { code: "0196", name: "Icelandic Kennitala", country: "IS" },
787
+ { code: "0198", name: "Danish ERST id (Erhvervsstyrelsen)", country: "DK" },
788
+ { code: "0200", name: "Lithuanian Legal Entity Register (GRIS)", country: "LT" },
789
+ { code: "0201", name: "Italian Codice Destinatario", country: "IT" },
790
+ { code: "0202", name: "Italian Fiscal Code (Codice Fiscale)", country: "IT" },
791
+ { code: "0204", name: "German Leitweg-ID", country: "DE" },
792
+ { code: "0208", name: "Belgian Enterprise Number (KBO/BCE)", country: "BE" },
793
+ { code: "0209", name: "German Creditor Identifier (GS1)", country: "DE" },
794
+ { code: "0210", name: "Italian Codice Fiscale (per IPA)", country: "IT" },
795
+ { code: "0211", name: "Italian Partita IVA (VAT number)", country: "IT" },
796
+ { code: "0212", name: "Finnish OVT code", country: "FI" },
797
+ { code: "0213", name: "Finnish OP identifier", country: "FI" },
798
+ { code: "0225", name: "FRCTC Electronic Address", country: "FR" },
799
+ { code: "9957", name: "French VAT number", country: "FR" }
800
+ ];
801
+ var EAS_BY_CODE = new Map(EAS_SCHEMES.map((s) => [s.code, s]));
802
+ var UNIT_ALIAS_MAP = {
803
+ each: "EA",
804
+ piece: "EA",
805
+ pieces: "EA",
806
+ hour: "HUR",
807
+ hours: "HUR",
808
+ day: "DAY",
809
+ days: "DAY",
810
+ week: "WEE",
811
+ weeks: "WEE",
812
+ month: "MON",
813
+ months: "MON",
814
+ year: "ANN",
815
+ years: "ANN",
816
+ kilogram: "KGM",
817
+ kg: "KGM",
818
+ meter: "MTR",
819
+ metre: "MTR",
820
+ liter: "LTR",
821
+ litre: "LTR",
822
+ unit: "C62",
823
+ units: "C62",
824
+ set: "SET",
825
+ sets: "SET",
826
+ pack: "PK",
827
+ packs: "PK",
828
+ minute: "MIN",
829
+ minutes: "MIN",
830
+ second: "SEC",
831
+ seconds: "SEC",
832
+ tonne: "TNE",
833
+ ton: "TNE",
834
+ "square metre": "MTK",
835
+ "square meter": "MTK",
836
+ sqm: "MTK"
837
+ };
838
+ var UNIT_CODES = /* @__PURE__ */ new Map([
839
+ ["EA", "Each"],
840
+ ["HUR", "Hour"],
841
+ ["DAY", "Day"],
842
+ ["WEE", "Week"],
843
+ ["MON", "Month"],
844
+ ["ANN", "Year"],
845
+ ["MIN", "Minute"],
846
+ ["SEC", "Second"],
847
+ ["KGM", "Kilogram"],
848
+ ["MTR", "Metre"],
849
+ ["LTR", "Litre"],
850
+ ["MTK", "Square metre"],
851
+ ["TNE", "Tonne"],
852
+ ["C62", "One (unit)"],
853
+ ["SET", "Set"],
854
+ ["PK", "Pack"]
855
+ ]);
856
+ function resolveUnit(input) {
857
+ return UNIT_ALIAS_MAP[input.toLowerCase()] ?? input;
858
+ }
859
+ function getAllUnits() {
860
+ return Array.from(UNIT_CODES.entries()).map(([code, name]) => ({ code, name })).sort((a, b) => a.code.localeCompare(b.code));
861
+ }
862
+
738
863
  // ../sdk/dist/core/validator.js
739
864
  function error(field, message, ruleId, suggestion) {
740
865
  return { field, message, ruleId, suggestion };
@@ -742,19 +867,31 @@ function error(field, message, ruleId, suggestion) {
742
867
  function warning(field, message, ruleId) {
743
868
  return { field, message, ruleId };
744
869
  }
870
+ function assertString(value, fieldPath, errors) {
871
+ if (typeof value !== "string") {
872
+ errors.push(error(fieldPath, `Expected string, received ${value === null ? "null" : typeof value}`, void 0, "Check your payload \u2014 this field must be a text value"));
873
+ return false;
874
+ }
875
+ return true;
876
+ }
745
877
  var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
746
878
  function validateParty(party, path) {
747
879
  const errors = [];
748
- if (!party.name?.trim()) {
880
+ if (party.name === void 0 || party.name === null || party.name === "") {
881
+ errors.push(error(`${path}.name`, "Business name is required", "BR-06"));
882
+ } else if (!assertString(party.name, `${path}.name`, errors)) {
883
+ } else if (!party.name.trim()) {
749
884
  errors.push(error(`${path}.name`, "Business name is required", "BR-06"));
750
885
  }
751
- if (!party.peppolId) {
886
+ if (party.peppolId === void 0 || party.peppolId === null || party.peppolId === "") {
752
887
  errors.push(error(`${path}.peppolId`, "Peppol participant ID is required", void 0, 'Format: "scheme:id", e.g. "0208:BE0123456789" for Belgian companies'));
888
+ } else if (!assertString(party.peppolId, `${path}.peppolId`, errors)) {
753
889
  } else if (!party.peppolId.includes(":")) {
754
890
  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)'));
755
891
  }
756
- if (!party.country) {
892
+ if (party.country === void 0 || party.country === null || party.country === "") {
757
893
  errors.push(error(`${path}.country`, "Country code is required", "BR-11"));
894
+ } else if (!assertString(party.country, `${path}.country`, errors)) {
758
895
  } else if (party.country.length !== 2) {
759
896
  errors.push(error(`${path}.country`, `Invalid country code: "${party.country}"`, void 0, "Must be ISO 3166-1 alpha-2 (e.g., BE, FR, DE, NL)"));
760
897
  }
@@ -762,13 +899,22 @@ function validateParty(party, path) {
762
899
  }
763
900
  function validateBuyerAddress(party, path) {
764
901
  const errors = [];
765
- if (!party.street?.trim()) {
902
+ if (party.street === void 0 || party.street === null || party.street === "") {
903
+ errors.push(error(`${path}.street`, "Street address is required for the buyer", "BR-50", 'e.g. "123 Business Street"'));
904
+ } else if (!assertString(party.street, `${path}.street`, errors)) {
905
+ } else if (!party.street.trim()) {
766
906
  errors.push(error(`${path}.street`, "Street address is required for the buyer", "BR-50", 'e.g. "123 Business Street"'));
767
907
  }
768
- if (!party.city?.trim()) {
908
+ if (party.city === void 0 || party.city === null || party.city === "") {
909
+ errors.push(error(`${path}.city`, "City is required for the buyer", "BR-51", 'e.g. "Brussels"'));
910
+ } else if (!assertString(party.city, `${path}.city`, errors)) {
911
+ } else if (!party.city.trim()) {
769
912
  errors.push(error(`${path}.city`, "City is required for the buyer", "BR-51", 'e.g. "Brussels"'));
770
913
  }
771
- if (!party.postalCode?.trim()) {
914
+ if (party.postalCode === void 0 || party.postalCode === null || party.postalCode === "") {
915
+ errors.push(error(`${path}.postalCode`, "Postal code is required for the buyer", "BR-53", 'e.g. "1000"'));
916
+ } else if (!assertString(party.postalCode, `${path}.postalCode`, errors)) {
917
+ } else if (!party.postalCode.trim()) {
772
918
  errors.push(error(`${path}.postalCode`, "Postal code is required for the buyer", "BR-53", 'e.g. "1000"'));
773
919
  }
774
920
  return errors;
@@ -776,7 +922,10 @@ function validateBuyerAddress(party, path) {
776
922
  function validateLine(line, index, isCreditNote = false) {
777
923
  const errors = [];
778
924
  const path = `lines[${index}]`;
779
- if (!line.description?.trim()) {
925
+ if (line.description === void 0 || line.description === null || line.description === "") {
926
+ errors.push(error(`${path}.description`, "Line item description is required", "BR-25"));
927
+ } else if (!assertString(line.description, `${path}.description`, errors)) {
928
+ } else if (!line.description.trim()) {
780
929
  errors.push(error(`${path}.description`, "Line item description is required", "BR-25"));
781
930
  }
782
931
  if (line.quantity === void 0 || line.quantity === null) {
@@ -799,15 +948,24 @@ function validateLine(line, index, isCreditNote = false) {
799
948
  function validateInvoice(input) {
800
949
  const errors = [];
801
950
  const warnings = [];
802
- if (!input.number?.trim()) {
951
+ if (input.number === void 0 || input.number === null || input.number === "") {
952
+ errors.push(error("number", "Invoice number is required", "BR-02", "Must be unique per supplier"));
953
+ } else if (!assertString(input.number, "number", errors)) {
954
+ } else if (!input.number.trim()) {
803
955
  errors.push(error("number", "Invoice number is required", "BR-02", "Must be unique per supplier"));
804
956
  }
805
957
  const VALID_TYPE_CODES = [380, 381, 383, 384, 386, 389, 751];
806
958
  if (input.invoiceTypeCode != null && !VALID_TYPE_CODES.includes(input.invoiceTypeCode)) {
807
959
  errors.push(error("invoiceTypeCode", `Invalid invoice type code: ${input.invoiceTypeCode}`, void 0, "Valid codes: 380, 381, 383, 384, 386, 389, 751"));
808
960
  }
809
- if (input.isCreditNote && !input.invoiceReference?.trim()) {
810
- errors.push(error("invoiceReference", "Reference to the original invoice is required for credit notes", void 0, 'Set invoiceReference to the original invoice number (e.g., "INV-001")'));
961
+ if (input.isCreditNote) {
962
+ const ref = input.invoiceReference;
963
+ if (ref === void 0 || ref === null || ref === "") {
964
+ errors.push(error("invoiceReference", "Reference to the original invoice is required for credit notes", void 0, 'Set invoiceReference to the original invoice number (e.g., "INV-001")'));
965
+ } else if (!assertString(ref, "invoiceReference", errors)) {
966
+ } else if (!ref.trim()) {
967
+ errors.push(error("invoiceReference", "Reference to the original invoice is required for credit notes", void 0, 'Set invoiceReference to the original invoice number (e.g., "INV-001")'));
968
+ }
811
969
  }
812
970
  if (input.from) {
813
971
  warnings.push(warning("from", "Seller info is determined by your API key. The 'from' field is deprecated and ignored."));
@@ -819,13 +977,19 @@ function validateInvoice(input) {
819
977
  errors.push(...validateBuyerAddress(input.to, "to"));
820
978
  }
821
979
  if (input.payeeParty) {
822
- if (!input.payeeParty.name?.trim()) {
980
+ const ppName = input.payeeParty.name;
981
+ if (ppName === void 0 || ppName === null || ppName === "") {
982
+ errors.push(error("payeeParty.name", "Payee party name is required", "BR-17"));
983
+ } else if (!assertString(ppName, "payeeParty.name", errors)) {
984
+ } else if (!ppName.trim()) {
823
985
  errors.push(error("payeeParty.name", "Payee party name is required", "BR-17"));
824
986
  }
825
- if (!input.payeeParty.peppolId) {
987
+ const ppId = input.payeeParty.peppolId;
988
+ if (ppId === void 0 || ppId === null || ppId === "") {
826
989
  errors.push(error("payeeParty.peppolId", "Payee party Peppol ID is required", void 0, 'Format: "scheme:id", e.g. "0208:BE0123456789"'));
827
- } else if (!input.payeeParty.peppolId.includes(":")) {
828
- errors.push(error("payeeParty.peppolId", `Invalid Peppol ID format: "${input.payeeParty.peppolId}"`, void 0, 'Must be "scheme:id" format'));
990
+ } else if (!assertString(ppId, "payeeParty.peppolId", errors)) {
991
+ } else if (!ppId.includes(":")) {
992
+ errors.push(error("payeeParty.peppolId", `Invalid Peppol ID format: "${ppId}"`, void 0, 'Must be "scheme:id" format'));
829
993
  }
830
994
  }
831
995
  if (!input.lines || input.lines.length === 0) {
@@ -867,6 +1031,12 @@ function validateInvoice(input) {
867
1031
  if (input.taxCurrencyRate !== void 0 && input.taxCurrencyRate <= 0) {
868
1032
  errors.push(error("taxCurrencyRate", `Tax currency rate must be positive, got ${input.taxCurrencyRate}`, void 0, "Set to the exchange rate from document currency to tax currency"));
869
1033
  }
1034
+ if (input.currency && !getCurrency(input.currency)) {
1035
+ errors.push(error("currency", `Invalid currency code: "${input.currency}"`, void 0, 'Use ISO 4217 (e.g., "EUR", "USD", "GBP", "JPY"). See https://getpeppr.dev/docs/types/#currency'));
1036
+ }
1037
+ if (input.taxCurrency && !getCurrency(input.taxCurrency)) {
1038
+ errors.push(error("taxCurrency", `Invalid tax currency code: "${input.taxCurrency}"`, void 0, 'Use ISO 4217 (e.g., "EUR", "USD")'));
1039
+ }
870
1040
  if (!input.dueDate) {
871
1041
  warnings.push(warning("dueDate", "No due date specified. Recommended for payment terms.", "BR-09"));
872
1042
  }
@@ -889,9 +1059,19 @@ function validateInvoice(input) {
889
1059
  }
890
1060
 
891
1061
  // ../sdk/dist/version.js
892
- var SDK_VERSION = "1.3.0";
1062
+ var SDK_VERSION = "1.4.0";
893
1063
 
894
1064
  // ../sdk/dist/core/client.js
1065
+ function findHeaderCaseInsensitive(headers, name) {
1066
+ if (!headers)
1067
+ return void 0;
1068
+ const target = name.toLowerCase();
1069
+ for (const [key, value] of Object.entries(headers)) {
1070
+ if (key.toLowerCase() === target)
1071
+ return value;
1072
+ }
1073
+ return void 0;
1074
+ }
895
1075
  var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
896
1076
  function sleep(ms) {
897
1077
  return new Promise((resolve4) => setTimeout(resolve4, ms));
@@ -960,7 +1140,7 @@ var GetpepprAdapter = class {
960
1140
  lastError = err;
961
1141
  const is429 = err instanceof PeppolApiError && err.statusCode === 429;
962
1142
  const isSafeMethod = /^(GET|DELETE|HEAD)$/i.test(method);
963
- const hasIdempotencyKey = !!extraHeaders?.["Idempotency-Key"];
1143
+ const hasIdempotencyKey = !!findHeaderCaseInsensitive(extraHeaders, "Idempotency-Key");
964
1144
  const canRetry = is429 || isSafeMethod || hasIdempotencyKey;
965
1145
  if (attempt < maxRetries && canRetry && isRetryableError(err)) {
966
1146
  const retryAfterMs = err instanceof PeppolApiError ? err.retryAfterMs : void 0;
@@ -1493,11 +1673,16 @@ var VALID_STATUSES = /* @__PURE__ */ new Set([
1493
1673
  "under_query",
1494
1674
  "conditionally_accepted",
1495
1675
  "partially_paid",
1496
- "no_action"
1676
+ "no_action",
1677
+ "unknown"
1678
+ // explicitly known: gateway may emit this when it can't map a Storecove status
1497
1679
  ]);
1498
1680
  function mapStatus(raw) {
1499
1681
  const s = raw.toLowerCase();
1500
- return VALID_STATUSES.has(s) ? s : "unknown";
1682
+ if (VALID_STATUSES.has(s))
1683
+ return s;
1684
+ console.warn(`[getpeppr] Unknown gateway status received: "${raw}" \u2014 please report to support@getpeppr.dev. Coercing to "unknown".`);
1685
+ return "unknown";
1501
1686
  }
1502
1687
  var PeppolError = class extends Error {
1503
1688
  constructor(message) {
@@ -1575,12 +1760,14 @@ async function* paginate(fetchPage, options) {
1575
1760
  let offset = 0;
1576
1761
  while (true) {
1577
1762
  const page = await fetchPage(offset, pageSize);
1763
+ if (page.data.length === 0)
1764
+ break;
1578
1765
  for (const item of page.data) {
1579
1766
  yield item;
1580
1767
  }
1581
1768
  if (!page.meta.hasMore)
1582
1769
  break;
1583
- offset += pageSize;
1770
+ offset += page.data.length;
1584
1771
  }
1585
1772
  }
1586
1773
  var InvoiceOperations = class {
@@ -2062,7 +2249,7 @@ var ContactOperations = class {
2062
2249
  * ```
2063
2250
  */
2064
2251
  listAll(options) {
2065
- return paginate((offset, limit) => this.adapter.listContacts({ ...options, offset, limit }));
2252
+ return paginate((offset, limit) => this.adapter.listContacts({ ...options, offset, limit }), options);
2066
2253
  }
2067
2254
  };
2068
2255
  var BankAccountOperations = class {
@@ -2143,7 +2330,7 @@ var BankAccountOperations = class {
2143
2330
  * ```
2144
2331
  */
2145
2332
  listAll(options) {
2146
- return paginate((offset, limit) => this.adapter.listBankAccounts({ ...options, offset, limit }));
2333
+ return paginate((offset, limit) => this.adapter.listBankAccounts({ ...options, offset, limit }), options);
2147
2334
  }
2148
2335
  };
2149
2336
  var TransportOperations = class {
@@ -2225,93 +2412,6 @@ var TransportOperations = class {
2225
2412
  }
2226
2413
  };
2227
2414
 
2228
- // ../sdk/dist/core/code-lists.js
2229
- var EAS_SCHEMES = [
2230
- { code: "0002", name: "System Information et Repertoire des Entreprises et des Etablissements (SIRENE)", country: "FR" },
2231
- { code: "0007", name: "Organisationsnummer", country: "SE" },
2232
- { code: "0009", name: "SIRET-CODE", country: "FR" },
2233
- { code: "0088", name: "EAN Location Code (GLN)" },
2234
- { code: "0096", name: "Danish Chamber of Commerce (P-nummer)", country: "DK" },
2235
- { code: "0184", name: "Danish Central Business Register (CVR)", country: "DK" },
2236
- { code: "0190", name: "Dutch Chamber of Commerce (KVK)", country: "NL" },
2237
- { code: "0191", name: "Organisatie Identificatie Nummer (OIN)", country: "NL" },
2238
- { code: "0192", name: "Danish SE-number (Erhvervsstyrelsen)", country: "DK" },
2239
- { code: "0195", name: "Singapore Unique Entity Number (UEN)", country: "SG" },
2240
- { code: "0196", name: "Icelandic Kennitala", country: "IS" },
2241
- { code: "0198", name: "Danish ERST id (Erhvervsstyrelsen)", country: "DK" },
2242
- { code: "0200", name: "Lithuanian Legal Entity Register (GRIS)", country: "LT" },
2243
- { code: "0201", name: "Italian Codice Destinatario", country: "IT" },
2244
- { code: "0202", name: "Italian Fiscal Code (Codice Fiscale)", country: "IT" },
2245
- { code: "0204", name: "German Leitweg-ID", country: "DE" },
2246
- { code: "0208", name: "Belgian Enterprise Number (KBO/BCE)", country: "BE" },
2247
- { code: "0209", name: "German Creditor Identifier (GS1)", country: "DE" },
2248
- { code: "0210", name: "Italian Codice Fiscale (per IPA)", country: "IT" },
2249
- { code: "0211", name: "Italian Partita IVA (VAT number)", country: "IT" },
2250
- { code: "0212", name: "Finnish OVT code", country: "FI" },
2251
- { code: "0213", name: "Finnish OP identifier", country: "FI" }
2252
- ];
2253
- var EAS_BY_CODE = new Map(EAS_SCHEMES.map((s) => [s.code, s]));
2254
- var UNIT_ALIAS_MAP = {
2255
- each: "EA",
2256
- piece: "EA",
2257
- pieces: "EA",
2258
- hour: "HUR",
2259
- hours: "HUR",
2260
- day: "DAY",
2261
- days: "DAY",
2262
- week: "WEE",
2263
- weeks: "WEE",
2264
- month: "MON",
2265
- months: "MON",
2266
- year: "ANN",
2267
- years: "ANN",
2268
- kilogram: "KGM",
2269
- kg: "KGM",
2270
- meter: "MTR",
2271
- metre: "MTR",
2272
- liter: "LTR",
2273
- litre: "LTR",
2274
- unit: "C62",
2275
- units: "C62",
2276
- set: "SET",
2277
- sets: "SET",
2278
- pack: "PK",
2279
- packs: "PK",
2280
- minute: "MIN",
2281
- minutes: "MIN",
2282
- second: "SEC",
2283
- seconds: "SEC",
2284
- tonne: "TNE",
2285
- ton: "TNE",
2286
- "square metre": "MTK",
2287
- "square meter": "MTK",
2288
- sqm: "MTK"
2289
- };
2290
- var UNIT_CODES = /* @__PURE__ */ new Map([
2291
- ["EA", "Each"],
2292
- ["HUR", "Hour"],
2293
- ["DAY", "Day"],
2294
- ["WEE", "Week"],
2295
- ["MON", "Month"],
2296
- ["ANN", "Year"],
2297
- ["MIN", "Minute"],
2298
- ["SEC", "Second"],
2299
- ["KGM", "Kilogram"],
2300
- ["MTR", "Metre"],
2301
- ["LTR", "Litre"],
2302
- ["MTK", "Square metre"],
2303
- ["TNE", "Tonne"],
2304
- ["C62", "One (unit)"],
2305
- ["SET", "Set"],
2306
- ["PK", "Pack"]
2307
- ]);
2308
- function resolveUnit(input) {
2309
- return UNIT_ALIAS_MAP[input.toLowerCase()] ?? input;
2310
- }
2311
- function getAllUnits() {
2312
- return Array.from(UNIT_CODES.entries()).map(([code, name]) => ({ code, name })).sort((a, b) => a.code.localeCompare(b.code));
2313
- }
2314
-
2315
2415
  // ../sdk/dist/core/schematron.js
2316
2416
  function violation(ruleId, severity, message, field) {
2317
2417
  return { ruleId, severity, message, field };
@@ -2839,6 +2939,14 @@ import pc4 from "picocolors";
2839
2939
 
2840
2940
  // src/lib/peppol-directory.ts
2841
2941
  var BASE_URL = "https://directory.peppol.eu/search/1.0/json";
2942
+ var DirectoryError = class extends Error {
2943
+ status;
2944
+ constructor(message, status) {
2945
+ super(message);
2946
+ this.name = "DirectoryError";
2947
+ this.status = status;
2948
+ }
2949
+ };
2842
2950
  function stripQuotes(name) {
2843
2951
  if (name.startsWith('"') && name.endsWith('"') && name.length >= 2) {
2844
2952
  return name.slice(1, -1);
@@ -2888,7 +2996,16 @@ function parseMatch(raw) {
2888
2996
  async function lookupParticipant(scheme, id) {
2889
2997
  const participantParam = `iso6523-actorid-upis::${scheme}:${id}`;
2890
2998
  const url = `${BASE_URL}?participant=${encodeURIComponent(participantParam)}`;
2891
- const response = await fetch(url);
2999
+ const response = await fetch(url, {
3000
+ signal: AbortSignal.timeout(15e3),
3001
+ headers: { "User-Agent": "@getpeppr/cli" }
3002
+ });
3003
+ if (!response.ok) {
3004
+ throw new DirectoryError(
3005
+ `Lookup failed: HTTP ${response.status} ${response.statusText}`,
3006
+ response.status
3007
+ );
3008
+ }
2892
3009
  const data = await response.json();
2893
3010
  if (!data.matches || data.matches.length === 0) {
2894
3011
  return null;
@@ -2900,7 +3017,16 @@ async function searchParticipants(opts) {
2900
3017
  if (opts.name) params.set("name", opts.name);
2901
3018
  if (opts.country) params.set("country", opts.country);
2902
3019
  const url = `${BASE_URL}?${params.toString()}`;
2903
- const response = await fetch(url);
3020
+ const response = await fetch(url, {
3021
+ signal: AbortSignal.timeout(15e3),
3022
+ headers: { "User-Agent": "@getpeppr/cli" }
3023
+ });
3024
+ if (!response.ok) {
3025
+ throw new DirectoryError(
3026
+ `Search failed: HTTP ${response.status} ${response.statusText}`,
3027
+ response.status
3028
+ );
3029
+ }
2904
3030
  const data = await response.json();
2905
3031
  const allMatches = (data.matches ?? []).map(parseMatch);
2906
3032
  const limit = opts.limit ?? 10;
@@ -3066,7 +3192,12 @@ async function handleLookup(peppolId, options) {
3066
3192
  let result;
3067
3193
  try {
3068
3194
  result = await lookupParticipant(parsed.scheme, parsed.id);
3069
- } catch {
3195
+ } catch (err) {
3196
+ if (err instanceof DirectoryError) {
3197
+ exitWithError(
3198
+ `${pc4.red("\u2717")} Peppol Directory returned an error (HTTP ${err.status ?? "unknown"}). Try again later.`
3199
+ );
3200
+ }
3070
3201
  exitWithError(
3071
3202
  `${pc4.red("\u2717")} Could not reach Peppol Directory. Check your internet connection.`
3072
3203
  );
@@ -3103,7 +3234,12 @@ async function handleSearch(options) {
3103
3234
  country: options.country,
3104
3235
  limit
3105
3236
  });
3106
- } catch {
3237
+ } catch (err) {
3238
+ if (err instanceof DirectoryError) {
3239
+ exitWithError(
3240
+ `${pc4.red("\u2717")} Peppol Directory returned an error (HTTP ${err.status ?? "unknown"}). Try again later.`
3241
+ );
3242
+ }
3107
3243
  exitWithError(
3108
3244
  `${pc4.red("\u2717")} Could not reach Peppol Directory. Check your internet connection.`
3109
3245
  );