@itpay/cli 0.1.8 → 0.1.9

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/bin/itp +81 -3
  2. package/package.json +1 -1
package/bin/itp CHANGED
@@ -3422,6 +3422,15 @@ async function renderHumanAction(action, flags = {}) {
3422
3422
  return { rendered: false, mode: "json-local-qr", outputs: [localPath] };
3423
3423
  }
3424
3424
  }
3425
+ if (!qrImageURL && shouldGenerateLocalQRFromActionURL(action, mode, flags)) {
3426
+ const localPath = await prepareLocalQRFromActionURL(action, flags, mode !== "file" && !flags.qr_file && !process.env.ITP_QR_FILE);
3427
+ if (localPath) {
3428
+ attachAgentLocalQR(action, localPath);
3429
+ annotateHumanActionPresentation(action, "");
3430
+ persistHumanAction(action, flags);
3431
+ return { rendered: false, mode: "json-local-url-qr", outputs: [localPath] };
3432
+ }
3433
+ }
3425
3434
  return { rendered: false, mode: flags.json ? "json" : mode };
3426
3435
  }
3427
3436
  const host = String(process.env.ITP_HOST || flags.host || "").toLowerCase();
@@ -3435,9 +3444,18 @@ async function renderHumanAction(action, flags = {}) {
3435
3444
  persistHumanAction(action, flags);
3436
3445
  return { rendered: false, mode: localPath ? "agent-local-image-qr" : "agent-image-qr", host, outputs: [localPath || "preferred_qr_url"] };
3437
3446
  }
3438
- process.stderr.write(`No QR image available. Open payment URL: ${action.url}\n`);
3447
+ if (shouldGenerateLocalQRFromActionURL(action, mode, flags)) {
3448
+ const localPath = await prepareLocalQRFromActionURL(action, flags, true);
3449
+ if (localPath) {
3450
+ attachAgentLocalQR(action, localPath);
3451
+ annotateHumanActionPresentation(action, "");
3452
+ persistHumanAction(action, flags);
3453
+ return { rendered: false, mode: "agent-local-url-qr", host, outputs: [localPath] };
3454
+ }
3455
+ }
3456
+ process.stderr.write(`No QR image available. Open action URL: ${action.url}\n`);
3439
3457
  persistHumanAction(action, flags);
3440
- return { rendered: false, mode: "agent-url-fallback", host, outputs: ["payment_url"] };
3458
+ return { rendered: false, mode: "agent-url-fallback", host, outputs: ["action_url"] };
3441
3459
  }
3442
3460
 
3443
3461
  const renderResult = { rendered: false, mode, outputs: [] };
@@ -3461,7 +3479,19 @@ async function renderHumanAction(action, flags = {}) {
3461
3479
  renderResult.outputs.push(file);
3462
3480
  if (mode === "file") return renderResult;
3463
3481
  } else {
3464
- process.stderr.write(`No QR image available. Open payment URL: ${action.url}\n`);
3482
+ const localPath = shouldGenerateLocalQRFromActionURL(action, mode, flags)
3483
+ ? await prepareLocalQRFromActionURL(action, flags, false)
3484
+ : "";
3485
+ if (localPath) {
3486
+ attachAgentLocalQR(action, localPath);
3487
+ annotateHumanActionPresentation(action, "");
3488
+ process.stderr.write(`Alipay action QR image: ${localPath}\n`);
3489
+ renderResult.rendered = true;
3490
+ renderResult.outputs.push(localPath);
3491
+ if (mode === "file") return renderResult;
3492
+ } else {
3493
+ process.stderr.write(`No QR image available. Open action URL: ${action.url}\n`);
3494
+ }
3465
3495
  }
3466
3496
  }
3467
3497
 
@@ -3535,6 +3565,12 @@ function shouldPrepareLocalQRForJSON(mode, flags = {}, action = {}) {
3535
3565
  return false;
3536
3566
  }
3537
3567
 
3568
+ function shouldGenerateLocalQRFromActionURL(action = {}, mode = "", flags = {}) {
3569
+ if (!action?.url) return false;
3570
+ if (action.kind === "auth_qr") return true;
3571
+ return mode === "file" || Boolean(flags.qr_file || process.env.ITP_QR_FILE);
3572
+ }
3573
+
3538
3574
  async function prepareLocalQRFile(action, qrImageURL, flags = {}, optional = false) {
3539
3575
  if (!qrImageURL) return "";
3540
3576
  const file = flags.qr_file || process.env.ITP_QR_FILE || defaultQRFilePath(action, qrImageURL);
@@ -3550,11 +3586,37 @@ async function prepareLocalQRFile(action, qrImageURL, flags = {}, optional = fal
3550
3586
  return file;
3551
3587
  }
3552
3588
 
3589
+ async function prepareLocalQRFromActionURL(action, flags = {}, optional = false) {
3590
+ if (!action?.url) return "";
3591
+ const file = flags.qr_file || process.env.ITP_QR_FILE || defaultGeneratedQRFilePath(action);
3592
+ try {
3593
+ fs.mkdirSync(path.dirname(file), { recursive: true });
3594
+ await QRCode.toFile(file, action.url, {
3595
+ type: "png",
3596
+ errorCorrectionLevel: "M",
3597
+ margin: 2,
3598
+ width: 512
3599
+ });
3600
+ } catch (error) {
3601
+ if (!optional) throw error;
3602
+ action.local_qr_error = safeErrorMessage(error);
3603
+ return "";
3604
+ }
3605
+ action.local_qr_path = file;
3606
+ action.local_qr_mime = "image/png";
3607
+ return file;
3608
+ }
3609
+
3553
3610
  function defaultQRFilePath(action, qrImageURL) {
3554
3611
  const id = sanitizeFilename(action?.payment_intent_id || action?.id || "qr");
3555
3612
  return path.join(os.tmpdir(), `itp-${id}.${qrFileExtension(qrImageURL, action)}`);
3556
3613
  }
3557
3614
 
3615
+ function defaultGeneratedQRFilePath(action) {
3616
+ const id = sanitizeFilename(action?.payment_intent_id || action?.id || "qr");
3617
+ return path.join(os.tmpdir(), `itp-${id}.png`);
3618
+ }
3619
+
3558
3620
  function qrFileExtension(qrImageURL, action = {}) {
3559
3621
  const mime = qrMimeType(qrImageURL, action);
3560
3622
  if (mime === "image/png") return "png";
@@ -3620,6 +3682,22 @@ function attachAgentQRImage(action, qrImageURL, localPath = "") {
3620
3682
  return action;
3621
3683
  }
3622
3684
 
3685
+ function attachAgentLocalQR(action, localPath = "") {
3686
+ if (!action || !localPath) return action;
3687
+ if (!Array.isArray(action.display)) {
3688
+ action.display = [];
3689
+ }
3690
+ if (!action.display.some((item) => item?.type === "image" && item?.local_path === localPath)) {
3691
+ action.display.push({
3692
+ type: "image",
3693
+ format: "png",
3694
+ local_path: localPath,
3695
+ instructions: "Render this local QR image for the human to scan. It encodes the ItPay human action URL, not a provider raw QR payload."
3696
+ });
3697
+ }
3698
+ return action;
3699
+ }
3700
+
3623
3701
  async function downloadQRImage(qrImageURL, file, flags = {}) {
3624
3702
  const controller = new AbortController();
3625
3703
  const timer = setTimeout(() => controller.abort(), apiTimeoutMs(flags));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itpay/cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "ItPay CLI, buyer skill, and agent-readable docs for agent-native commerce.",
5
5
  "type": "module",
6
6
  "bin": {