@vonpay/checkout-cli 0.20.0 → 0.21.0

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.
Files changed (2) hide show
  1. package/dist/index.js +77 -17
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1358,7 +1358,7 @@ function parseMetadata(pairs) {
1358
1358
  return out;
1359
1359
  }
1360
1360
  var METADATA_FILTER_KEY = /^[A-Za-z0-9_.:-]{1,64}$/;
1361
- var METADATA_FILTER_VALUE_MAX = 500;
1361
+ var METADATA_FILTER_VALUE_MAX = 128;
1362
1362
  function assertMetadataFilterKey(key, flag) {
1363
1363
  if (!METADATA_FILTER_KEY.test(key)) {
1364
1364
  throw new Error(
@@ -1378,6 +1378,41 @@ function parseMetadataFilter(raw, flag) {
1378
1378
  return { [key]: value };
1379
1379
  }
1380
1380
 
1381
+ // src/utils/processor-detail.ts
1382
+ import { SAFE_CODE_PATTERN, SAFE_CONNECTION_ID_PATTERN, safeValueOrWithheld } from "@vonpay/checkout-node";
1383
+ var INCLUDE_PROCESSOR_DETAIL_HELP = "With --json: also print the card processor's own answer (untrusted text), every try with its connection name, the connection's name, and the card's first six digits";
1384
+ var PROCESSOR_DETAIL_KEYS = ["processorResponse", "attempts", "attemptsStatus"];
1385
+ function cardForDisplay(card) {
1386
+ if (card === null || typeof card !== "object" || Array.isArray(card)) return card;
1387
+ const c = card;
1388
+ return { brand: c.brand ?? null, last4: c.last4 ?? null };
1389
+ }
1390
+ function attemptSummary(a) {
1391
+ return {
1392
+ connectionId: safeValueOrWithheld(a.processorConnection?.id, SAFE_CONNECTION_ID_PATTERN),
1393
+ result: safeValueOrWithheld(a.result, SAFE_CODE_PATTERN),
1394
+ declineCode: safeValueOrWithheld(a.declineCode, SAFE_CODE_PATTERN),
1395
+ outcome: safeValueOrWithheld(a.outcome, SAFE_CODE_PATTERN)
1396
+ };
1397
+ }
1398
+ function attemptsStatusForDisplay(value) {
1399
+ return safeValueOrWithheld(value, SAFE_CODE_PATTERN);
1400
+ }
1401
+ function connectionForDisplay(connection) {
1402
+ if (connection === null || typeof connection !== "object" || Array.isArray(connection)) return connection;
1403
+ return { id: connection.id ?? null };
1404
+ }
1405
+ function withoutProcessorDetail(obj, includeProcessorDetail) {
1406
+ const src = obj;
1407
+ if (includeProcessorDetail) return src;
1408
+ const out = { ...src };
1409
+ for (const k of PROCESSOR_DETAIL_KEYS) delete out[k];
1410
+ if ("card" in out) out.card = cardForDisplay(out.card);
1411
+ if ("processorConnection" in out) out.processorConnection = connectionForDisplay(out.processorConnection);
1412
+ return out;
1413
+ }
1414
+ var PROCESSOR_DETAIL_NEEDS_JSON = "--include-processor-detail is used with --json.";
1415
+
1381
1416
  // src/commands/payment-reports.ts
1382
1417
  import chalk8 from "chalk";
1383
1418
  import { formatMinorUnits as formatMinorUnits2 } from "@vonpay/checkout-node";
@@ -1430,12 +1465,24 @@ var PAYMENT_LIST_JSON_FIELDS = [
1430
1465
  "declineCode",
1431
1466
  "action",
1432
1467
  "ruleCode",
1433
- "networkAdvice"
1468
+ "networkAdvice",
1469
+ // Each try as the safe summary only (connection id, result, decline code, outcome), and
1470
+ // whether that list is the full record. --include-processor-detail prints the whole tries.
1471
+ "attempts",
1472
+ "attemptsStatus"
1434
1473
  ];
1435
- function listItemJson(pi, includeMetadata) {
1436
- if (includeMetadata) return pi;
1474
+ function listItemJson(pi, includeMetadata, includeProcessorDetail) {
1437
1475
  const src = pi;
1438
- return Object.fromEntries(PAYMENT_LIST_JSON_FIELDS.filter((k) => src[k] !== void 0).map((k) => [k, src[k]]));
1476
+ const out = includeMetadata ? { ...src } : Object.fromEntries(PAYMENT_LIST_JSON_FIELDS.filter((k) => src[k] !== void 0).map((k) => [k, src[k]]));
1477
+ if (includeProcessorDetail) {
1478
+ if (src.processorResponse !== void 0) out.processorResponse = src.processorResponse;
1479
+ return out;
1480
+ }
1481
+ const safe = withoutProcessorDetail(out, false);
1482
+ if (src.attemptsStatus !== void 0) safe.attemptsStatus = attemptsStatusForDisplay(src.attemptsStatus);
1483
+ if (pi.attempts === null) safe.attempts = null;
1484
+ else if (Array.isArray(pi.attempts)) safe.attempts = pi.attempts.map(attemptSummary);
1485
+ return safe;
1439
1486
  }
1440
1487
  var ALL_DEFAULT_MAX_ITEMS = 1e4;
1441
1488
  function stoppedAtDefaultCap() {
@@ -1450,6 +1497,7 @@ function buildListParams(opts) {
1450
1497
  if (opts.startingAfter !== void 0) params.startingAfter = opts.startingAfter;
1451
1498
  if (opts.maxItems !== void 0 && !opts.all) throw new Error("--max-items is used with --all.");
1452
1499
  if (opts.includeMetadata && !opts.json) throw new Error("--include-metadata is used with --json.");
1500
+ if (opts.includeProcessorDetail && !opts.json) throw new Error(PROCESSOR_DETAIL_NEEDS_JSON);
1453
1501
  const maxItems = opts.maxItems !== void 0 ? positiveWholeNumber(opts.maxItems, "--max-items") : opts.all ? ALL_DEFAULT_MAX_ITEMS : void 0;
1454
1502
  return { params, ...maxItems !== void 0 ? { maxItems } : {} };
1455
1503
  }
@@ -1514,7 +1562,7 @@ var FILTER_HELP = {
1514
1562
  createdLt: "End of the window, exclusive (default: now). At most 31 days after the start (7 with summary --group-by hour)",
1515
1563
  outcome: "Only these outcomes, comma-separated (e.g. bank_declined,refused_before_bank)",
1516
1564
  store: "Only payments for this connected store hostname (e.g. shop.example.com)",
1517
- metadata: "Only payments with this metadata tag, key=value (ONE tag; key 1-64 of letters, digits, _ . : -; value 1-500 characters)",
1565
+ metadata: "Only payments with this metadata tag, key=value (ONE tag; key 1-64 of letters, digits, _ . : -; value 1-128 characters)",
1518
1566
  cardBrand: "Only these card brands, comma-separated (visa, mastercard, amex, discover, unionpay, jcb, diners, unknown)",
1519
1567
  currency: "Only payments in this currency (e.g. USD)",
1520
1568
  initiator: "merchant (merchant-initiated charges on a saved card) or customer",
@@ -1541,7 +1589,7 @@ function addPaymentReportCommands(intents) {
1541
1589
  ).option("--max-items <n>", `With --all: stop after this many payments (default ${ALL_DEFAULT_MAX_ITEMS})`).option(
1542
1590
  "--json",
1543
1591
  "Output JSON: each payment's status, outcome, amount, card, store and decline fields \u2014 not your metadata (with --all: one JSON array)"
1544
- ).option("--include-metadata", "With --json: print every field of each payment, your metadata included").action(async (opts) => {
1592
+ ).option("--include-metadata", "With --json: print every field of each payment, your metadata included (not the processor detail: see --include-processor-detail)").option("--include-processor-detail", INCLUDE_PROCESSOR_DETAIL_HELP).action(async (opts) => {
1545
1593
  let built;
1546
1594
  try {
1547
1595
  built = buildListParams(opts);
@@ -1558,7 +1606,7 @@ function addPaymentReportCommands(intents) {
1558
1606
  });
1559
1607
  if (opts.json) {
1560
1608
  const items = [];
1561
- for await (const pi of pager) items.push(listItemJson(pi, opts.includeMetadata));
1609
+ for await (const pi of pager) items.push(listItemJson(pi, opts.includeMetadata, opts.includeProcessorDetail));
1562
1610
  spinner.stop();
1563
1611
  console.log(jsonOutput(items));
1564
1612
  if (opts.maxItems === void 0 && items.length >= ALL_DEFAULT_MAX_ITEMS) console.error(stoppedAtDefaultCap());
@@ -1579,7 +1627,12 @@ function addPaymentReportCommands(intents) {
1579
1627
  const page = await client.paymentIntents.list(built.params);
1580
1628
  spinner.stop();
1581
1629
  if (opts.json) {
1582
- console.log(jsonOutput({ ...page, data: page.data.map((pi) => listItemJson(pi, opts.includeMetadata)) }));
1630
+ console.log(
1631
+ jsonOutput({
1632
+ ...page,
1633
+ data: page.data.map((pi) => listItemJson(pi, opts.includeMetadata, opts.includeProcessorDetail))
1634
+ })
1635
+ );
1583
1636
  return;
1584
1637
  }
1585
1638
  for (const line of paymentListLines(page)) console.log(line);
@@ -1620,6 +1673,9 @@ function addPaymentReportCommands(intents) {
1620
1673
  }
1621
1674
 
1622
1675
  // src/commands/payment-intents.ts
1676
+ function refuseProcessorDetailWithoutJson(opts) {
1677
+ if (opts.includeProcessorDetail && !opts.json) exitWithCliError(PROCESSOR_DETAIL_NEEDS_JSON, chalk9.red(PROCESSOR_DETAIL_NEEDS_JSON));
1678
+ }
1623
1679
  var MIT_INITIATORS = ["merchant", "customer"];
1624
1680
  var MIT_REASONS = [
1625
1681
  "recurring",
@@ -1755,7 +1811,8 @@ function paymentIntentsCommand() {
1755
1811
  ).option("--buyer-email <email>", "Buyer email for this charge").option(
1756
1812
  "--idempotency-key <key>",
1757
1813
  "Idempotency key for this charge. Reuse the SAME key to retry the same charge safely. REQUIRED on a live key; on a sandbox key generated (and printed) when omitted"
1758
- ).addOption(retiredConfirmLiveOption()).option("--json", "Output raw JSON").action(async (raw) => {
1814
+ ).addOption(retiredConfirmLiveOption()).option("--json", "Output raw JSON").option("--include-processor-detail", INCLUDE_PROCESSOR_DETAIL_HELP).action(async (raw) => {
1815
+ refuseProcessorDetailWithoutJson(raw);
1759
1816
  const apiKey = requireApiKey();
1760
1817
  const opts = { ...raw, amount: minorUnitsOrExit(raw.amount, "--amount") };
1761
1818
  const captureMethod = opts.captureMethod?.toLowerCase();
@@ -1797,7 +1854,7 @@ function paymentIntentsCommand() {
1797
1854
  });
1798
1855
  spinner.stop();
1799
1856
  if (opts.json) {
1800
- console.log(jsonOutput(intent));
1857
+ console.log(jsonOutput(withoutProcessorDetail(intent, opts.includeProcessorDetail)));
1801
1858
  } else {
1802
1859
  console.log(chalk9.green("\u2713 Payment intent created"));
1803
1860
  printPaymentIntent(intent);
@@ -1809,14 +1866,15 @@ function paymentIntentsCommand() {
1809
1866
  });
1810
1867
  intents.command("get").description(
1811
1868
  "Read a payment intent back \u2014 the way to check a payment whose outcome was unclear before doing anything else"
1812
- ).argument("<id>", "Payment intent ID (vpi_*)").option("--json", "Output raw JSON").action(async (id, opts) => {
1869
+ ).argument("<id>", "Payment intent ID (vpi_*)").option("--json", "Output raw JSON").option("--include-processor-detail", INCLUDE_PROCESSOR_DETAIL_HELP).action(async (id, opts) => {
1870
+ refuseProcessorDetailWithoutJson(opts);
1813
1871
  const client = makeCheckoutClient();
1814
1872
  const spinner = startSpinner("Fetching payment intent...");
1815
1873
  try {
1816
1874
  const intent = await client.paymentIntents.retrieve(id);
1817
1875
  spinner.stop();
1818
1876
  if (opts.json) {
1819
- console.log(jsonOutput(intent));
1877
+ console.log(jsonOutput(withoutProcessorDetail(intent, opts.includeProcessorDetail)));
1820
1878
  } else {
1821
1879
  printPaymentIntent(intent);
1822
1880
  }
@@ -1831,8 +1889,9 @@ function paymentIntentsCommand() {
1831
1889
  ).option(
1832
1890
  "--idempotency-key <key>",
1833
1891
  "Idempotency key. Reuse the SAME key to retry safely. REQUIRED on a live key; on a sandbox key generated (and printed) when omitted"
1834
- ).addOption(retiredConfirmLiveOption()).option("--json", "Output raw JSON").action(
1892
+ ).addOption(retiredConfirmLiveOption()).option("--json", "Output raw JSON").option("--include-processor-detail", INCLUDE_PROCESSOR_DETAIL_HELP).action(
1835
1893
  async (id, opts) => {
1894
+ refuseProcessorDetailWithoutJson(opts);
1836
1895
  const apiKey = requireApiKey();
1837
1896
  const amountToCapture = optionalMinorUnitsOrExit(
1838
1897
  opts.amountToCapture,
@@ -1866,7 +1925,7 @@ function paymentIntentsCommand() {
1866
1925
  );
1867
1926
  spinner.stop();
1868
1927
  if (opts.json) {
1869
- console.log(jsonOutput(intent));
1928
+ console.log(jsonOutput(withoutProcessorDetail(intent, opts.includeProcessorDetail)));
1870
1929
  } else {
1871
1930
  const captureLabel = amountToCapture !== void 0 ? ` (partial: ${formatMinorUnits3(amountToCapture, intent.currency)})` : "";
1872
1931
  console.log(chalk9.green(`\u2713 Payment intent captured${captureLabel}`));
@@ -1881,8 +1940,9 @@ function paymentIntentsCommand() {
1881
1940
  intents.command("void").description("Void an authorized (uncaptured) payment intent").argument("<id>", "Payment intent ID (vpi_*)").option(
1882
1941
  "--idempotency-key <key>",
1883
1942
  "Idempotency key. Reuse the SAME key to retry safely. REQUIRED on a live key; on a sandbox key generated (and printed) when omitted"
1884
- ).addOption(retiredConfirmLiveOption()).option("--json", "Output raw JSON").action(
1943
+ ).addOption(retiredConfirmLiveOption()).option("--json", "Output raw JSON").option("--include-processor-detail", INCLUDE_PROCESSOR_DETAIL_HELP).action(
1885
1944
  async (id, opts) => {
1945
+ refuseProcessorDetailWithoutJson(opts);
1886
1946
  const apiKey = requireApiKey();
1887
1947
  refuseUnsafeLiveDestination(apiKey);
1888
1948
  const idempotencyKey = idempotencyKeyFor(opts.idempotencyKey, "void", apiKey);
@@ -1905,7 +1965,7 @@ function paymentIntentsCommand() {
1905
1965
  const intent = await client.paymentIntents.void(id, { idempotencyKey });
1906
1966
  spinner.stop();
1907
1967
  if (opts.json) {
1908
- console.log(jsonOutput(intent));
1968
+ console.log(jsonOutput(withoutProcessorDetail(intent, opts.includeProcessorDetail)));
1909
1969
  } else {
1910
1970
  console.log(chalk9.green("\u2713 Payment intent voided"));
1911
1971
  printPaymentIntent(intent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonpay/checkout-cli",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "Von Payments CLI — developer tools for checkout integration",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,7 +20,7 @@
20
20
  "node": ">=20"
21
21
  },
22
22
  "dependencies": {
23
- "@vonpay/checkout-node": "^4.8.0",
23
+ "@vonpay/checkout-node": "^4.9.0",
24
24
  "commander": "^13.0.0",
25
25
  "chalk": "^5.4.0",
26
26
  "ora": "^8.2.0"