@getpeppr/cli 0.4.3 → 0.4.4

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/README.md CHANGED
@@ -17,7 +17,7 @@ getpeppr --help
17
17
 
18
18
  ### `getpeppr init` — Scaffold an invoice
19
19
 
20
- Generate a starter JSON file with all required fields pre-filled:
20
+ Generate a starter JSON file suitable for local validation and UBL conversion:
21
21
 
22
22
  ```bash
23
23
  getpeppr init # creates invoice.json
@@ -26,7 +26,7 @@ getpeppr init --credit-note # credit note template
26
26
  getpeppr init --force # overwrite existing file
27
27
  ```
28
28
 
29
- The generated template includes a Belgian seller, a German buyer, and two invoice lines — ready to edit and validate.
29
+ The generated template includes a Belgian seller, a German buyer, and two invoice lines — ready to edit, validate, and convert locally.
30
30
 
31
31
  ### `getpeppr validate` — Validate an invoice
32
32
 
@@ -82,7 +82,7 @@ Look up any participant registered on the Peppol network:
82
82
 
83
83
  ```bash
84
84
  # Direct lookup by Peppol ID
85
- getpeppr lookup 0208:BE0685660237
85
+ getpeppr lookup 0208:0685660237
86
86
 
87
87
  # Search by company name
88
88
  getpeppr lookup --name "Dupont"
@@ -91,7 +91,7 @@ getpeppr lookup --name "Dupont"
91
91
  getpeppr lookup --name "GmbH" --country DE
92
92
 
93
93
  # JSON output
94
- getpeppr lookup 0208:BE0685660237 --json
94
+ getpeppr lookup 0208:0685660237 --json
95
95
  ```
96
96
 
97
97
  | Flag | Description |
@@ -131,7 +131,7 @@ Send an invoice through the getpeppr API to the Peppol network. Targets sandbox
131
131
  getpeppr send invoice.json
132
132
 
133
133
  # Quick test — synthesize an invoice from flags (no file needed)
134
- getpeppr send --to 0208:BE0314595348 --amount 100 --desc "Test invoice"
134
+ getpeppr send --to 9925:BE0314595348 --amount 100 --desc "Test invoice"
135
135
 
136
136
  # Watch delivery status until terminal (60s timeout)
137
137
  getpeppr send invoice.json --watch
@@ -157,6 +157,8 @@ getpeppr send invoice.json --prod
157
157
  | `--json` | Machine-readable JSON output |
158
158
  | `--quiet` | Exit code only, no output |
159
159
 
160
+ When sending through the API, getpeppr determines the seller from the API key. A `from` party can still be present for local validation and UBL conversion, but the gateway ignores it for delivery.
161
+
160
162
  ### `getpeppr logout` — Remove stored credentials
161
163
 
162
164
  ```bash
@@ -198,7 +200,7 @@ Scaffolding (`init`), validation, and conversion run fully offline — no API ke
198
200
 
199
201
  ## Invoice format
200
202
 
201
- The input file must be a JSON object matching the getpeppr `InvoiceInput` type:
203
+ The input file must be a JSON object matching the getpeppr `InvoiceInput` type. `number`, `to`, and `lines` are required for API sends. The `from` party is included in the scaffold because offline validation and UBL conversion need seller metadata; API sends use the legal entity linked to your key.
202
204
 
203
205
  ```json
204
206
  {
@@ -209,7 +211,7 @@ The input file must be a JSON object matching the getpeppr `InvoiceInput` type:
209
211
  "buyerReference": "PO-2026-042",
210
212
  "from": {
211
213
  "name": "Dupont & Fils SPRL",
212
- "peppolId": "0208:BE0123456789",
214
+ "peppolId": "0208:0123456789",
213
215
  "street": "Avenue Louise 54",
214
216
  "city": "Bruxelles",
215
217
  "postalCode": "1050",
package/dist/index.js CHANGED
@@ -884,7 +884,7 @@ function validateParty(party, path) {
884
884
  errors.push(error(`${path}.name`, "Business name is required", "BR-06"));
885
885
  }
886
886
  if (party.peppolId === void 0 || party.peppolId === null || party.peppolId === "") {
887
- errors.push(error(`${path}.peppolId`, "Peppol participant ID is required", void 0, 'Format: "scheme:id", e.g. "0208:BE0123456789" for Belgian companies'));
887
+ errors.push(error(`${path}.peppolId`, "Peppol participant ID is required", void 0, 'Format: "scheme:id", e.g. "0208:0123456789" for Belgian companies'));
888
888
  } else if (!assertString(party.peppolId, `${path}.peppolId`, errors)) {
889
889
  } else if (!party.peppolId.includes(":")) {
890
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)'));
@@ -986,7 +986,7 @@ function validateInvoice(input) {
986
986
  }
987
987
  const ppId = input.payeeParty.peppolId;
988
988
  if (ppId === void 0 || ppId === null || ppId === "") {
989
- errors.push(error("payeeParty.peppolId", "Payee party Peppol ID is required", void 0, 'Format: "scheme:id", e.g. "0208:BE0123456789"'));
989
+ errors.push(error("payeeParty.peppolId", "Payee party Peppol ID is required", void 0, 'Format: "scheme:id", e.g. "0208:0123456789"'));
990
990
  } else if (!assertString(ppId, "payeeParty.peppolId", errors)) {
991
991
  } else if (!ppId.includes(":")) {
992
992
  errors.push(error("payeeParty.peppolId", `Invalid Peppol ID format: "${ppId}"`, void 0, 'Must be "scheme:id" format'));
@@ -1059,7 +1059,7 @@ function validateInvoice(input) {
1059
1059
  }
1060
1060
 
1061
1061
  // ../sdk/dist/version.js
1062
- var SDK_VERSION = "1.5.0";
1062
+ var SDK_VERSION = "1.5.1";
1063
1063
 
1064
1064
  // ../sdk/dist/core/client.js
1065
1065
  function findHeaderCaseInsensitive(headers, name) {
@@ -1819,8 +1819,8 @@ ${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (
1819
1819
  * ```ts
1820
1820
  * const result = await peppol.invoices.send({
1821
1821
  * number: "INV-001",
1822
- * from: { name: "My Company", peppolId: "0208:BE0123456789", country: "BE" },
1823
- * to: { name: "Client Co", peppolId: "0208:BE9876543210", country: "BE" },
1822
+ * from: { name: "My Company", peppolId: "0208:0123456789", country: "BE" },
1823
+ * to: { name: "Client Co", peppolId: "0208:0987654321", country: "BE" },
1824
1824
  * lines: [
1825
1825
  * { description: "Consulting", quantity: 10, unitPrice: 150, vatRate: 21 }
1826
1826
  * ]
@@ -1882,7 +1882,7 @@ ${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (
1882
1882
  * ```ts
1883
1883
  * const result = await peppol.invoices.validateServer({
1884
1884
  * number: "INV-001",
1885
- * to: { name: "Acme", peppolId: "0208:BE0123456789", country: "BE" },
1885
+ * to: { name: "Acme", peppolId: "0208:0123456789", country: "BE" },
1886
1886
  * lines: [{ description: "Item", quantity: 1, unitPrice: 100, vatRate: 21 }]
1887
1887
  * });
1888
1888
  * console.log(result.valid, result.schematron.errors);
@@ -2079,14 +2079,14 @@ var DirectoryOperations = class {
2079
2079
  *
2080
2080
  * @example
2081
2081
  * ```ts
2082
- * const entry = await peppol.directory.lookup("0208:BE0123456789");
2082
+ * const entry = await peppol.directory.lookup("0208:0123456789");
2083
2083
  * console.log(entry.name, entry.capabilities);
2084
2084
  * ```
2085
2085
  */
2086
2086
  async lookup(peppolId) {
2087
2087
  const colonIndex = peppolId.indexOf(":");
2088
2088
  if (colonIndex === -1) {
2089
- throw new PeppolError('Invalid Peppol ID format. Expected "scheme:id" (e.g., "0208:BE0123456789")');
2089
+ throw new PeppolError('Invalid Peppol ID format. Expected "scheme:id" (e.g., "0208:0123456789")');
2090
2090
  }
2091
2091
  const scheme = peppolId.slice(0, colonIndex);
2092
2092
  const id = peppolId.slice(colonIndex + 1);
@@ -2208,7 +2208,7 @@ var ContactOperations = class {
2208
2208
  * ```ts
2209
2209
  * const contact = await peppol.contacts.create({
2210
2210
  * name: "Acme Corp",
2211
- * peppolId: "0208:BE0123456789",
2211
+ * peppolId: "0208:0123456789",
2212
2212
  * country: "BE",
2213
2213
  * isClient: true,
2214
2214
  * });
@@ -2789,7 +2789,7 @@ var INVOICE_TEMPLATE = {
2789
2789
  buyerReference: "PO-2026-042",
2790
2790
  from: {
2791
2791
  name: "Dupont & Fils SPRL",
2792
- peppolId: "0208:BE0123456789",
2792
+ peppolId: "0208:0123456789",
2793
2793
  street: "Avenue Louise 54",
2794
2794
  city: "Bruxelles",
2795
2795
  postalCode: "1050",
@@ -2831,7 +2831,7 @@ var CREDIT_NOTE_TEMPLATE = {
2831
2831
  invoiceReference: "INV-2026-001",
2832
2832
  from: {
2833
2833
  name: "Dupont & Fils SPRL",
2834
- peppolId: "0208:BE0123456789",
2834
+ peppolId: "0208:0123456789",
2835
2835
  street: "Avenue Louise 54",
2836
2836
  city: "Bruxelles",
2837
2837
  postalCode: "1050",
@@ -2995,7 +2995,7 @@ function parseMatch(raw) {
2995
2995
  };
2996
2996
  }
2997
2997
  async function lookupParticipant(scheme, id) {
2998
- const participantParam = `iso6523-actorid-upis::${scheme}:${id}`;
2998
+ const participantParam = `iso6523-actorid-upis::${scheme}:${normalizeParticipantIdentifier(scheme, id)}`;
2999
2999
  const url = `${BASE_URL}?participant=${encodeURIComponent(participantParam)}`;
3000
3000
  const response = await fetch(url, {
3001
3001
  signal: AbortSignal.timeout(15e3),
@@ -3013,6 +3013,12 @@ async function lookupParticipant(scheme, id) {
3013
3013
  }
3014
3014
  return parseMatch(data.matches[0]);
3015
3015
  }
3016
+ function normalizeParticipantIdentifier(scheme, id) {
3017
+ if (scheme === "0208") {
3018
+ return id.replace(/^BE(?=(?:0|1)\d{9}$)/i, "");
3019
+ }
3020
+ return id;
3021
+ }
3016
3022
  async function searchParticipants(opts) {
3017
3023
  const params = new URLSearchParams();
3018
3024
  if (opts.name) params.set("name", opts.name);
@@ -3141,7 +3147,7 @@ function validatePeppolId(raw) {
3141
3147
  if (colonIndex === -1) {
3142
3148
  return {
3143
3149
  ok: false,
3144
- error: `Invalid Peppol ID format: "${raw}". Expected format: scheme:id (e.g. 0208:BE0685660237)`
3150
+ error: `Invalid Peppol ID format: "${raw}". Expected format: scheme:id (e.g. 0208:0685660237)`
3145
3151
  };
3146
3152
  }
3147
3153
  const scheme = raw.slice(0, colonIndex);
@@ -3396,6 +3402,20 @@ startxref
3396
3402
  190
3397
3403
  %%EOF`;
3398
3404
  var MINIMAL_TEST_PDF_BASE64 = Buffer.from(MINIMAL_PDF).toString("base64");
3405
+ var SCHEME_COUNTRY_DEFAULTS = {
3406
+ "0009": "FR",
3407
+ "0204": "DE",
3408
+ "0208": "BE",
3409
+ "9925": "BE"
3410
+ };
3411
+ function deriveCountryFromPeppolId(peppolId) {
3412
+ const [scheme, identifier = ""] = peppolId.split(":");
3413
+ const alphaPrefix = identifier.slice(0, 2);
3414
+ if (/^[A-Za-z]{2}$/.test(alphaPrefix)) {
3415
+ return alphaPrefix.toUpperCase();
3416
+ }
3417
+ return SCHEME_COUNTRY_DEFAULTS[scheme] ?? "BE";
3418
+ }
3399
3419
  function buildDefaultSendPayload(overrides = {}) {
3400
3420
  const today = /* @__PURE__ */ new Date();
3401
3421
  const due = new Date(today.getTime() + 30 * 864e5);
@@ -3407,7 +3427,7 @@ function buildDefaultSendPayload(overrides = {}) {
3407
3427
  const description = overrides.description ?? "Test service from getpeppr";
3408
3428
  const randomSuffix = Math.floor(Math.random() * 65536).toString(16).toUpperCase().padStart(4, "0");
3409
3429
  const number = `TEST-${Date.now().toString(36).toUpperCase()}-${randomSuffix}`;
3410
- const country = peppolId.split(":")[1]?.slice(0, 2) ?? "BE";
3430
+ const country = overrides.country != null ? overrides.country.toUpperCase() : deriveCountryFromPeppolId(peppolId);
3411
3431
  const payload = {
3412
3432
  number,
3413
3433
  date: isoToday,
@@ -3459,7 +3479,7 @@ var MutexError = class extends Error {
3459
3479
  function hasOverrides(o) {
3460
3480
  if (!o) return false;
3461
3481
  return Boolean(
3462
- o.to != null && o.to !== "" || o.amount != null || o.currency || o.description || o.attachment === true
3482
+ o.to != null && o.to !== "" || o.country != null && o.country !== "" || o.amount != null || o.currency || o.description || o.attachment === true
3463
3483
  );
3464
3484
  }
3465
3485
  function buildPayload(opts) {
@@ -3567,7 +3587,7 @@ var API_BASE = "https://api.getpeppr.dev/v1";
3567
3587
  var LOCAL_BASE = "http://localhost:3001/api/v1";
3568
3588
  var DASHBOARD_BASE = "https://console.getpeppr.dev/invoices";
3569
3589
  function registerSendCommand(program2) {
3570
- program2.command("send").description("Send an invoice to the Peppol network via getpeppr API").argument("[file]", "optional path to invoice JSON (mutex with --to/--amount/...)").option("--prod", "target production (live keys + confirmation)").option("--local", "target localhost:3001 dev server").option("--key <key>", "override API key \u2014 for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.").option("--to <peppol-id>", "recipient peppol id (e.g., 0208:BE0314595348)").option("--amount <number>", "line amount in major currency units (decimal allowed)").option("--currency <iso>", "ISO 4217 currency (default EUR)").option("--desc <text>", "line description").option("--attachment", "attach the test PDF").option("--watch", "poll status until delivered (60s timeout)").option("-y, --yes", "skip --prod confirmation prompt").option("--no-validate", "skip pre-validation locally").option("--json", "output JSON").option("--quiet", "exit code only, no output").action(async (file, flags) => {
3590
+ program2.command("send").description("Send an invoice to the Peppol network via getpeppr API").argument("[file]", "optional path to invoice JSON (mutex with --to/--amount/...)").option("--prod", "target production (live keys + confirmation)").option("--local", "target localhost:3001 dev server").option("--key <key>", "override API key \u2014 for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.").option("--to <peppol-id>", "recipient peppol id (e.g., 9925:BE0314595348)").option("--country <iso>", "recipient ISO 3166-1 alpha-2 country override (e.g., BE)").option("--amount <number>", "line amount in major currency units (decimal allowed)").option("--currency <iso>", "ISO 4217 currency (default EUR)").option("--desc <text>", "line description").option("--attachment", "attach the test PDF").option("--watch", "poll status until delivered (60s timeout)").option("-y, --yes", "skip --prod confirmation prompt").option("--no-validate", "skip pre-validation locally").option("--json", "output JSON").option("--quiet", "exit code only, no output").action(async (file, flags) => {
3571
3591
  let auth;
3572
3592
  try {
3573
3593
  auth = resolveApiKey({
@@ -3584,6 +3604,7 @@ function registerSendCommand(program2) {
3584
3604
  }
3585
3605
  const overrides = {
3586
3606
  to: flags.to,
3607
+ country: flags.country,
3587
3608
  amount: flags.amount != null ? Number(flags.amount) : void 0,
3588
3609
  currency: flags.currency,
3589
3610
  description: flags.desc,