@getpeppr/cli 0.11.0 → 0.11.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/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ All notable changes to `@getpeppr/cli` are documented here.
4
4
 
5
5
  The CLI bundles `@getpeppr/sdk` into its published artifact (tsup `noExternal`), so `validate`, `convert` and `init` run the SDK's validators, country rules and UBL builder locally — an SDK release only reaches CLI users once the CLI is rebundled. Rebundle-only releases are listed with the SDK version they ship.
6
6
 
7
+ ## [0.11.1] — 2026-09-04
8
+
9
+ Rebundles `@getpeppr/sdk` 5.2.0 (GPR-1084).
10
+
11
+ - The `schematron` section of `getpeppr validate` now reports `BR-16` for a
12
+ missing invoice line and uses explicit `GETPEPPR-*` IDs for ten SDK-local
13
+ diagnostics that previously cited different official rules. The separate
14
+ `structure` and `countryRules` sections are unchanged (GPR-1267 tracks their
15
+ reverse audit).
16
+ - Validation predicates, warning/error severities and process exit codes are
17
+ unchanged. The unit warning also stops calling every code outside the SDK's
18
+ small convenience list invalid under Rec20, and the payable warning no longer
19
+ invents `prepaidAmount` as the only possible cause. Scripts that filter the
20
+ `schematron` result by an old rule ID or warning text must update that filter.
21
+ - Human-readable output now labels the section `Offline Checks (partial)` and
22
+ reports `Pre-flight checks passed` or `Pre-flight checks found errors`; it no
23
+ longer claims that the partial pass proves validity or non-compliance. The
24
+ `--json` shape and process exit codes are unchanged.
25
+
7
26
  ## [0.11.0] — 2026-09-04
8
27
 
9
28
  Rebundles `@getpeppr/sdk` 5.1.0.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @getpeppr/cli
2
2
 
3
- Developer toolkit for Peppol e-invoicing. Scaffold invoices, validate against Peppol BIS 3.0, convert to UBL XML, look up participants in the Peppol Directory, and send invoices to the Peppol network — all from the command line.
3
+ Developer toolkit for Peppol e-invoicing. Scaffold invoices, run offline pre-flight checks, convert to UBL XML, look up participants in the Peppol Directory, and send invoices to the Peppol network — all from the command line.
4
4
 
5
5
  ## Installation
6
6
 
@@ -30,7 +30,7 @@ The generated template includes a Belgian seller, the sandbox test receiver as b
30
30
 
31
31
  ### `getpeppr validate` — Validate an invoice
32
32
 
33
- Run offline validation against Peppol BIS 3.0 business rules:
33
+ Run partial offline pre-flight checks before the network applies the complete Peppol BIS 3.0 rulebooks:
34
34
 
35
35
  ```bash
36
36
  getpeppr validate invoice.json
@@ -44,14 +44,14 @@ Validating: invoice.json
44
44
  ── Structure ──────────────────────────────
45
45
  ✓ No errors
46
46
 
47
- ── Business Rules (Peppol BIS 3.0) ───────
48
- All rules passed
47
+ ── Offline Checks (partial) ───────────────────
48
+ No findings
49
49
 
50
50
  ── Country Rules ────────────────────────────
51
51
  ⚠ No structured communication reference (BE-02)
52
52
 
53
53
  ── Summary ──────────────────────────────────
54
- Invoice is valid (1 warning)
54
+ Pre-flight checks passed (1 warning)
55
55
  ```
56
56
 
57
57
  | Flag | Description |
@@ -235,7 +235,7 @@ GETPEPPR_API_KEY=$SANDBOX_KEY getpeppr send invoice.json --json
235
235
  The CLI runs three validation engines from the [@getpeppr/sdk](https://www.npmjs.com/package/@getpeppr/sdk):
236
236
 
237
237
  1. **Structure** — Required fields, type checks, format validation
238
- 2. **Business Rules** — Peppol BIS 3.0 / EN 16931 compliance (BR-xx, BR-CO-xx, PEPPOL-xx rules)
238
+ 2. **Offline Checks** — 37 registered partial pre-flight checks: exact network-rule equivalents plus explicit `GETPEPPR-*` diagnostics. The legacy provider-capability diagnostic `unsupported_vat_category` can also appear, but is outside that count. This is not a Peppol conformance verdict.
239
239
  3. **Country Rules** — Belgium (BE), France (FR), Italy (IT), Netherlands (NL), Germany (DE)
240
240
 
241
241
  Scaffolding (`init`), validation, and conversion run fully offline — no API key or network connection required. Only `lookup`, `send`, and `whoami` need a network connection. Before a sandbox `send`, the CLI reads `GET /v1/identity`: its own generated fixture is adapted to the returned O/0 or AE/0 profile, while a user-edited file is never rewritten silently and is refused locally if its tax mode conflicts with the sender.
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ function formatWarning(item) {
65
65
  function formatSection(title, errors, warnings) {
66
66
  const lines = [sectionHeader(title)];
67
67
  if (errors.length === 0 && warnings.length === 0) {
68
- lines.push(` ${pc.green("\u2713")} All rules passed`);
68
+ lines.push(` ${pc.green("\u2713")} No findings`);
69
69
  return lines.join("\n");
70
70
  }
71
71
  if (errors.length === 0) {
@@ -94,7 +94,7 @@ Validating: ${pc.bold(filename)}
94
94
  lines.push("");
95
95
  lines.push(
96
96
  formatSection(
97
- "Business Rules (Peppol BIS 3.0)",
97
+ "Offline Checks (partial)",
98
98
  result.schematron.errors,
99
99
  result.schematron.warnings
100
100
  )
@@ -111,10 +111,10 @@ Validating: ${pc.bold(filename)}
111
111
  lines.push(sectionHeader("Summary"));
112
112
  const { totalErrors, totalWarnings, valid } = result;
113
113
  if (valid && totalWarnings === 0) {
114
- lines.push(` ${pc.green(pc.bold("\u2713 Invoice is valid"))}`);
114
+ lines.push(` ${pc.green(pc.bold("\u2713 Pre-flight checks passed"))}`);
115
115
  } else if (valid) {
116
116
  lines.push(
117
- ` ${pc.green(pc.bold("\u2713 Invoice is valid"))} ${pc.dim(`(${totalWarnings} warning${totalWarnings === 1 ? "" : "s"})`)}`
117
+ ` ${pc.green(pc.bold("\u2713 Pre-flight checks passed"))} ${pc.dim(`(${totalWarnings} warning${totalWarnings === 1 ? "" : "s"})`)}`
118
118
  );
119
119
  } else {
120
120
  const parts = [];
@@ -123,7 +123,7 @@ Validating: ${pc.bold(filename)}
123
123
  parts.push(`${totalWarnings} warning${totalWarnings === 1 ? "" : "s"}`);
124
124
  }
125
125
  lines.push(
126
- ` ${pc.red(pc.bold(`\u2717 ${parts.join(", ")}`))} \u2014 invoice non-compliant`
126
+ ` ${pc.red(pc.bold("\u2717 Pre-flight checks found errors"))} ${pc.dim(`(${parts.join(", ")})`)}`
127
127
  );
128
128
  }
129
129
  lines.push("");
@@ -1987,12 +1987,12 @@ function validateInvoice(input) {
1987
1987
  function violation(ruleId, severity, message, field) {
1988
1988
  return { ruleId, severity, message, field };
1989
1989
  }
1990
- var _knownUnitCodes;
1991
- function getKnownUnitCodes() {
1992
- if (!_knownUnitCodes) {
1993
- _knownUnitCodes = new Set(getAllUnits().map((u) => u.code));
1990
+ var _sdkUnitCodes;
1991
+ function getSdkUnitCodes() {
1992
+ if (!_sdkUnitCodes) {
1993
+ _sdkUnitCodes = new Set(getAllUnits().map((u) => u.code));
1994
1994
  }
1995
- return _knownUnitCodes;
1995
+ return _sdkUnitCodes;
1996
1996
  }
1997
1997
  var VALID_VAT_CATEGORIES = /* @__PURE__ */ new Set(["S", "Z", "E", "AE", "K", "G", "O", "L", "M", "B"]);
1998
1998
  var SENDABLE_VAT_CATEGORIES = ["S", "Z", "E", "AE", "K", "G", "O"];
@@ -2012,18 +2012,18 @@ var br02 = (input) => {
2012
2012
  }
2013
2013
  return [];
2014
2014
  };
2015
- var br03 = (input) => {
2015
+ var issueDateDefaulted = (input) => {
2016
2016
  if (!input.date) {
2017
2017
  return [
2018
- violation("BR-03", "warning", "Invoice issue date is not set. The SDK will default to today's date.", "date")
2018
+ violation("GETPEPPR-ISSUE-DATE-DEFAULTED", "warning", "Invoice issue date is not set. The SDK will default to today's date.", "date")
2019
2019
  ];
2020
2020
  }
2021
2021
  return [];
2022
2022
  };
2023
- var br06 = (input) => {
2023
+ var sellerVatRecommendation = (input) => {
2024
2024
  if (input.from && !input.from.vatNumber) {
2025
2025
  return [
2026
- violation("BR-06", "warning", "Seller party has no VAT number. The gateway will use the account's VAT registration.", "from.vatNumber")
2026
+ violation("GETPEPPR-FROM-VAT-RECOMMENDED", "warning", "Seller party has no VAT number. The gateway will use the account's VAT registration.", "from.vatNumber")
2027
2027
  ];
2028
2028
  }
2029
2029
  return [];
@@ -2034,29 +2034,29 @@ var br07 = (input) => {
2034
2034
  }
2035
2035
  return [];
2036
2036
  };
2037
- var br08 = (input) => {
2037
+ var br16 = (input) => {
2038
2038
  if (!input.lines || input.lines.length === 0) {
2039
- return [violation("BR-08", "error", "Invoice must have at least one line item.", "lines")];
2039
+ return [violation("BR-16", "error", "Invoice must have at least one line item.", "lines")];
2040
2040
  }
2041
2041
  return [];
2042
2042
  };
2043
- var br09 = (input) => {
2043
+ var paymentTimingRecommendation = (input) => {
2044
2044
  if (!input.dueDate && !input.paymentTerms) {
2045
2045
  return [
2046
- violation("BR-09", "warning", "Neither due date nor payment terms specified. At least one is recommended.", "dueDate")
2046
+ violation("GETPEPPR-PAYMENT-TIMING-RECOMMENDED", "warning", "Neither due date nor payment terms specified. At least one is recommended.", "dueDate")
2047
2047
  ];
2048
2048
  }
2049
2049
  return [];
2050
2050
  };
2051
- var br10 = (input) => {
2051
+ var buyerOrOrderReferenceRecommendation = (input) => {
2052
2052
  if (!input.buyerReference && !input.orderReference) {
2053
2053
  return [
2054
- violation("BR-10", "warning", "Neither buyerReference nor orderReference specified. Peppol BIS 3.0 requires at least one.", "buyerReference")
2054
+ violation("GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED", "warning", "Neither buyerReference nor orderReference specified. Peppol BIS 3.0 requires at least one.", "buyerReference")
2055
2055
  ];
2056
2056
  }
2057
2057
  return [];
2058
2058
  };
2059
- var brCo10 = (input) => {
2059
+ var lineNetSanity = (input) => {
2060
2060
  const violations = [];
2061
2061
  if (!input.lines)
2062
2062
  return violations;
@@ -2066,12 +2066,12 @@ var brCo10 = (input) => {
2066
2066
  if (!Number.isFinite(net)) {
2067
2067
  const baseQty = line.baseQuantity ?? 1;
2068
2068
  const detail = baseQty === 0 ? "baseQuantity is 0, causing division by zero." : "Computed line amount is not a finite number.";
2069
- violations.push(violation("BR-CO-10", "error", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`));
2069
+ violations.push(violation("GETPEPPR-LINE-NET-SANITY", "error", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`));
2070
2070
  }
2071
2071
  }
2072
2072
  return violations;
2073
2073
  };
2074
- var brCo13 = (input) => {
2074
+ var computedVatSanity = (input) => {
2075
2075
  if (!input.lines || input.lines.length === 0)
2076
2076
  return [];
2077
2077
  let totalVat = 0;
@@ -2090,17 +2090,17 @@ var brCo13 = (input) => {
2090
2090
  }
2091
2091
  if (!Number.isFinite(totalVat)) {
2092
2092
  return [
2093
- violation("BR-CO-13", "error", "Computed total VAT amount is not a finite number. Check line amounts and VAT rates.")
2093
+ violation("GETPEPPR-COMPUTED-VAT-SANITY", "error", "Computed total VAT amount is not a finite number. Check line amounts and VAT rates.")
2094
2094
  ];
2095
2095
  }
2096
2096
  if (totalVat < -0.01) {
2097
2097
  return [
2098
- violation("BR-CO-13", "warning", `Computed total VAT is negative (${totalVat.toFixed(2)}). This is unusual for an invoice.`)
2098
+ violation("GETPEPPR-COMPUTED-VAT-SANITY", "warning", `Computed total VAT is negative (${totalVat.toFixed(2)}). This is unusual for an invoice.`)
2099
2099
  ];
2100
2100
  }
2101
2101
  return [];
2102
2102
  };
2103
- var brCo15 = (input) => {
2103
+ var taxInclusiveSanity = (input) => {
2104
2104
  if (!input.lines || input.lines.length === 0)
2105
2105
  return [];
2106
2106
  let lineTotal = 0;
@@ -2123,17 +2123,17 @@ var brCo15 = (input) => {
2123
2123
  const taxInclusive = lineTotal + vatTotal;
2124
2124
  if (!Number.isFinite(taxInclusive)) {
2125
2125
  return [
2126
- violation("BR-CO-15", "error", "Computed tax-inclusive amount is not a finite number.")
2126
+ violation("GETPEPPR-TAX-INCLUSIVE-SANITY", "error", "Computed tax-inclusive amount is not a finite number.")
2127
2127
  ];
2128
2128
  }
2129
2129
  if (taxInclusive < -0.01) {
2130
2130
  return [
2131
- violation("BR-CO-15", "warning", `Computed tax-inclusive amount is negative (${taxInclusive.toFixed(2)}). Consider using a credit note instead.`)
2131
+ violation("GETPEPPR-TAX-INCLUSIVE-SANITY", "warning", `Computed tax-inclusive amount is negative (${taxInclusive.toFixed(2)}). Consider using a credit note instead.`)
2132
2132
  ];
2133
2133
  }
2134
2134
  return [];
2135
2135
  };
2136
- var brCo16 = (input) => {
2136
+ var payableSanity = (input) => {
2137
2137
  if (!input.lines || input.lines.length === 0)
2138
2138
  return [];
2139
2139
  let lineTotal = 0;
@@ -2159,12 +2159,12 @@ var brCo16 = (input) => {
2159
2159
  const payable = taxInclusive - prepaid + rounding;
2160
2160
  if (!Number.isFinite(payable)) {
2161
2161
  return [
2162
- violation("BR-CO-16", "error", "Computed payable amount is not a finite number.")
2162
+ violation("GETPEPPR-PAYABLE-SANITY", "error", "Computed payable amount is not a finite number.")
2163
2163
  ];
2164
2164
  }
2165
2165
  if (payable < -0.01) {
2166
2166
  return [
2167
- violation("BR-CO-16", "warning", `Computed payable amount is negative (${payable.toFixed(2)}). Prepaid amount (${prepaid}) exceeds the invoice total.`)
2167
+ violation("GETPEPPR-PAYABLE-SANITY", "warning", `Computed payable amount is negative (${payable.toFixed(2)}). Check invoice totals, prepaid amount (${prepaid}), and rounding amount (${rounding}).`)
2168
2168
  ];
2169
2169
  }
2170
2170
  return [];
@@ -2372,10 +2372,10 @@ function validateUblBuilderVat(input) {
2372
2372
  ...UBL_BUILDER_VAT_RULES.flatMap((rule) => rule(input))
2373
2373
  ];
2374
2374
  }
2375
- var peppolR004 = (input) => {
2375
+ var buyerPeppolIdRequired = (input) => {
2376
2376
  if (!input.to?.peppolId) {
2377
2377
  return [
2378
- violation("PEPPOL-EN16931-R004", "error", "Buyer electronic address (peppolId) is required for Peppol delivery.", "to.peppolId")
2378
+ violation("GETPEPPR-BUYER-PEPPOL-ID-REQUIRED", "error", "Buyer electronic address (peppolId) is required for Peppol delivery.", "to.peppolId")
2379
2379
  ];
2380
2380
  }
2381
2381
  return [];
@@ -2400,17 +2400,17 @@ var vatCategoryCodes = (input) => {
2400
2400
  (input.charges ?? []).forEach((c, i) => check(c.vatCategory, `charges[${i}].vatCategory`, `Charge ${i}`));
2401
2401
  return violations;
2402
2402
  };
2403
- var peppolR080 = (input) => {
2403
+ var unitCodeRecognised = (input) => {
2404
2404
  const violations = [];
2405
2405
  if (!input.lines)
2406
2406
  return violations;
2407
- const knownCodes = getKnownUnitCodes();
2407
+ const knownCodes = getSdkUnitCodes();
2408
2408
  for (let i = 0; i < input.lines.length; i++) {
2409
2409
  const line = input.lines[i];
2410
2410
  if (line.unit) {
2411
2411
  const resolved = resolveUnit(line.unit);
2412
2412
  if (!knownCodes.has(resolved)) {
2413
- violations.push(violation("PEPPOL-EN16931-R080", "warning", `Line ${i}: unit "${line.unit}" (resolved: "${resolved}") is not a known UN/ECE Rec20 code. Common codes: EA, HUR, DAY, KGM.`, `lines[${i}].unit`));
2413
+ violations.push(violation("GETPEPPR-UNIT-CODE-RECOGNISED", "warning", `Line ${i}: unit "${line.unit}" (resolved: "${resolved}") is not in the SDK's common unit list. It may still be a valid UN/ECE Rec20/21 code; network validation decides. Common codes: EA, HUR, DAY, KGM.`, `lines[${i}].unit`));
2414
2414
  }
2415
2415
  }
2416
2416
  }
@@ -2419,17 +2419,17 @@ var peppolR080 = (input) => {
2419
2419
  var ALL_RULES = [
2420
2420
  // Required fields (BR)
2421
2421
  br02,
2422
- br03,
2423
- br06,
2422
+ issueDateDefaulted,
2423
+ sellerVatRecommendation,
2424
2424
  br07,
2425
- br08,
2426
- br09,
2427
- br10,
2425
+ br16,
2426
+ paymentTimingRecommendation,
2427
+ buyerOrOrderReferenceRecommendation,
2428
2428
  // Calculations (BR-CO)
2429
- brCo10,
2430
- brCo13,
2431
- brCo15,
2432
- brCo16,
2429
+ lineNetSanity,
2430
+ computedVatSanity,
2431
+ taxInclusiveSanity,
2432
+ payableSanity,
2433
2433
  // Tax categories (one family per category)
2434
2434
  brS05,
2435
2435
  brZ05,
@@ -2444,9 +2444,9 @@ var ALL_RULES = [
2444
2444
  brO10,
2445
2445
  brIc10,
2446
2446
  // Peppol-specific
2447
- peppolR004,
2447
+ buyerPeppolIdRequired,
2448
2448
  vatCategoryCodes,
2449
- peppolR080
2449
+ unitCodeRecognised
2450
2450
  ];
2451
2451
  function validateSchematron(input) {
2452
2452
  const errors = [];
@@ -2470,17 +2470,17 @@ function validateSchematron(input) {
2470
2470
  }
2471
2471
  var SDK_SCHEMATRON_RULE_IDS = [
2472
2472
  "BR-02",
2473
- "BR-03",
2474
- "BR-06",
2473
+ "GETPEPPR-ISSUE-DATE-DEFAULTED",
2474
+ "GETPEPPR-FROM-VAT-RECOMMENDED",
2475
2475
  "BR-07",
2476
- "BR-08",
2477
- "BR-09",
2478
- "BR-10",
2476
+ "BR-16",
2477
+ "GETPEPPR-PAYMENT-TIMING-RECOMMENDED",
2478
+ "GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED",
2479
2479
  "BR-CL-17",
2480
- "BR-CO-10",
2481
- "BR-CO-13",
2482
- "BR-CO-15",
2483
- "BR-CO-16",
2480
+ "GETPEPPR-LINE-NET-SANITY",
2481
+ "GETPEPPR-COMPUTED-VAT-SANITY",
2482
+ "GETPEPPR-TAX-INCLUSIVE-SANITY",
2483
+ "GETPEPPR-PAYABLE-SANITY",
2484
2484
  "BR-S-05",
2485
2485
  "BR-Z-05",
2486
2486
  "BR-E-05",
@@ -2504,8 +2504,8 @@ var SDK_SCHEMATRON_RULE_IDS = [
2504
2504
  "BR-G-10",
2505
2505
  "BR-O-10",
2506
2506
  "BR-IC-10",
2507
- "PEPPOL-EN16931-R004",
2508
- "PEPPOL-EN16931-R080"
2507
+ "GETPEPPR-BUYER-PEPPOL-ID-REQUIRED",
2508
+ "GETPEPPR-UNIT-CODE-RECOGNISED"
2509
2509
  ];
2510
2510
 
2511
2511
  // ../sdk/dist/core/status-precedence.js
@@ -2533,7 +2533,7 @@ function statusFamily(status) {
2533
2533
  var TERMINAL_FAILURE_STATUSES = STATUS_PRECEDENCE.filter((e) => e.family === "terminal-failure").map((e) => e.status);
2534
2534
 
2535
2535
  // ../sdk/dist/version.js
2536
- var SDK_VERSION = "5.1.0";
2536
+ var SDK_VERSION = "5.2.0";
2537
2537
 
2538
2538
  // ../sdk/dist/core/api-result.js
2539
2539
  var API_RESULT_HEADER_NAMES = {
@@ -4158,7 +4158,8 @@ ${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (
4158
4158
  /**
4159
4159
  * Validate an invoice server-side using the getpeppr gateway's offline SDK-backed checks.
4160
4160
  * The gateway runs SDK validation, verifies UBL XML generation, and evaluates offline
4161
- * Peppol business rules without sending the invoice to Storecove.
4161
+ * pre-flight checks without sending the invoice to Storecove. This is not a Peppol
4162
+ * conformance verdict.
4162
4163
  *
4163
4164
  * @example
4164
4165
  * ```ts