@aeon-ai-pay/aigateway 0.1.3 → 0.1.5

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * WalletConnect v2 封装模块
3
- * 用于通过 WalletConnect 协议连接用户钱包并发起交易
2
+ * WalletConnect v2 wrapper.
3
+ * Connects to the user's wallet over WalletConnect and submits transactions.
4
4
  */
5
5
  import { SignClient } from "@walletconnect/sign-client";
6
6
  import { encodeFunctionData, parseUnits } from "viem";
@@ -13,8 +13,9 @@ import { WC_CONNECT_TIMEOUT_MS, ERC20_TRANSFER_ABI, DEFAULT_WC_PROJECT_ID } from
13
13
  import { loadConfig, saveConfig } from "./config.mjs";
14
14
 
15
15
  /**
16
- * WalletConnect 流程抛出的错误,携带稳定 error code(PAYMENT_TIMEOUT / PAYMENT_REJECTED / WALLET_ERROR)。
17
- * Commands 层捕获后通过 emitErr 输出,无需关心底层细节。
16
+ * Error type thrown by the WalletConnect flow, carrying a stable error code
17
+ * (PAYMENT_TIMEOUT / PAYMENT_REJECTED / WALLET_ERROR). The Commands layer
18
+ * catches it and forwards it via emitErr; no caller needs to look at the underlying details.
18
19
  */
19
20
  export class WalletConnectError extends Error {
20
21
  constructor(code, message) {
@@ -24,7 +25,7 @@ export class WalletConnectError extends Error {
24
25
  }
25
26
  }
26
27
 
27
- // ============== 状态同步服务器(供浏览器页面轮询) ==============
28
+ // ============== Status server (polled by the browser-side QR page) ==============
28
29
 
29
30
  let _status = { state: "waiting_scan" };
30
31
  let _server = null;
@@ -65,14 +66,14 @@ export function stopStatusServer() {
65
66
 
66
67
  const BSC_CHAIN_ID = "eip155:56";
67
68
 
68
- // QR 页面倒计时(与 WalletConnect 连接超时一致)
69
+ // QR-page countdown (matches the WalletConnect connection timeout)
69
70
  const QR_EXPIRE_MS = 5 * 60 * 1000;
70
71
 
71
72
  /**
72
- * 生成 QR HTML 页面并在浏览器中打开(按 Figma Ai card v1.2 设计稿)
73
+ * Generate the QR-code HTML page and open it in a browser (follows the Figma "AI card v1.2" design).
73
74
  * @param {string} uri - WalletConnect URI
74
- * @param {number} statusPort - 状态服务端口
75
- * @param {string|null} amount - 用户需要支付的 USDT 数量(如 "0.66"
75
+ * @param {number} statusPort - port of the local status server
76
+ * @param {string|null} amount - USDT amount the user has to pay (e.g. "0.66")
76
77
  */
77
78
  function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB Chain(BEP20) only", gasAmount = null) {
78
79
  const html = `<!DOCTYPE html>
@@ -165,16 +166,16 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
165
166
  const EXPIRE_MS = ${QR_EXPIRE_MS};
166
167
  const startTime = Date.now();
167
168
 
168
- // 倒计时 SVG 图标(Figma 导出 1:63 clock 16x16)- 使用 currentColor 跟随 .timer 颜色
169
+ // Clock countdown icon (exported from Figma 1:63, 16x16) uses currentColor to track `.timer` color
169
170
  const CLOCK_SVG = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.667 8C14.667 11.68 11.68 14.667 8 14.667C4.32 14.667 1.334 11.68 1.334 8C1.334 4.32 4.32 1.333 8 1.333C11.68 1.333 14.667 4.32 14.667 8Z" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M10.476 10.12L8.409 8.887C8.049 8.674 7.756 8.16 7.756 7.74V5.007" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>';
170
- // 提示 info 图标(Figma 导出 1:43 Icon 20x20
171
+ // Info / hint icon (exported from Figma 1:43, 20x20)
171
172
  const INFO_SVG = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path opacity="0.2" d="M10 18.333C14.6 18.333 18.331 14.602 18.331 10C18.331 5.397 14.6 1.666 10 1.666C5.395 1.666 1.664 5.397 1.664 10C1.664 14.602 5.395 18.333 10 18.333Z" fill="#737A86"/><path d="M10 13.333V10" stroke="#737A86" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 6.666H10.008" stroke="#737A86" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
172
- // Loading 旋转图标(Figma 导出 1:50 loading-02 24x24
173
+ // Loading spinner icon (exported from Figma 1:50 loading-02, 24x24)
173
174
  const LOADING_SVG = '<svg class="loading-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path opacity=".7" d="M4.922 5l2.828 2.828" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".6" d="M6 12H2" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".5" d="M4.922 19.078l2.828-2.828" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".4" d="M12 18v4" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".3" d="M19.078 19.078L16.25 16.25" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".2" d="M22 12h-4" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".1" d="M19.078 5L16.25 7.828" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/><path opacity=".8" d="M12 2v4" stroke="#191B1F" stroke-width="2.5" stroke-linecap="round"/></svg>';
174
- // 成功勾选
175
+ // Success checkmark
175
176
  const CHECK_SVG = '<div class="check-icon"><svg viewBox="0 0 14 14" fill="none"><path d="M3 7l3 3 5-5" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>';
176
177
 
177
- // 超时插图 SVG(从 Figma 导出)
178
+ // "Expired" illustration SVG (exported from Figma)
178
179
  const EXPIRED_SVG = \`<svg width="144" height="129" viewBox="0 0 144 129" fill="none" xmlns="http://www.w3.org/2000/svg">
179
180
  <path opacity="0.1" d="M140.369 64.988C140.369 82.769 133.106 98.797 121.461 110.317C110.066 121.711 94.289 128.598 76.884 128.598C59.604 128.598 43.826 121.586 32.306 110.317C20.661 98.797 13.398 82.769 13.398 64.988C13.398 29.802 41.823 1.377 76.884 1.377C111.944 1.377 140.369 29.927 140.369 64.988Z" fill="#1A72F7"/>
180
181
  <path d="M134.859 23.291C137.695 23.291 139.993 20.992 139.993 18.157C139.993 15.321 137.695 13.023 134.859 13.023C132.024 13.023 129.725 15.321 129.725 18.157C129.725 20.992 132.024 23.291 134.859 23.291Z" fill="#E8F1FE"/>
@@ -194,7 +195,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
194
195
  <linearGradient id="pb2" x1="53.891" y1="104.557" x2="103.297" y2="105.207" gradientUnits="userSpaceOnUse"><stop stop-color="#DBDEE3" stop-opacity=".7"/><stop offset="1" stop-color="#DBDEE3"/></linearGradient>
195
196
  </defs></svg>\`;
196
197
 
197
- // 拒绝插图 SVG(基于超时插图,替换时钟为 X 标记,橙色改红色)
198
+ // "Rejected" illustration SVG (variant of the expired illustration: clock swapped for an X, orange swapped for red)
198
199
  const REJECTED_SVG = \`<svg width="144" height="129" viewBox="0 0 144 129" fill="none" xmlns="http://www.w3.org/2000/svg">
199
200
  <path opacity="0.1" d="M140.369 64.988C140.369 82.769 133.106 98.797 121.461 110.317C110.066 121.711 94.289 128.598 76.884 128.598C59.604 128.598 43.826 121.586 32.306 110.317C20.661 98.797 13.398 82.769 13.398 64.988C13.398 29.802 41.823 1.377 76.884 1.377C111.944 1.377 140.369 29.927 140.369 64.988Z" fill="#1A72F7"/>
200
201
  <path d="M134.859 23.291C137.695 23.291 139.993 20.992 139.993 18.157C139.993 15.321 137.695 13.023 134.859 13.023C132.024 13.023 129.725 15.321 129.725 18.157C129.725 20.992 132.024 23.291 134.859 23.291Z" fill="#E8F1FE"/>
@@ -223,7 +224,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
223
224
 
224
225
  function fmtAmount(v) {
225
226
  if (v == null || v === '') return '';
226
- // 完整显示原始金额(不做取整),去除末尾多余的 0,整数部分加千分位
227
+ // Render the full original amount (no rounding); trim trailing zeros and add thousands separators to the integer part
227
228
  const s = String(v);
228
229
  const neg = s.startsWith('-') ? '-' : '';
229
230
  const body = neg ? s.slice(1) : s;
@@ -233,7 +234,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
233
234
  return neg + intWithComma + (decPart ? '.' + decPart : '') + ' ' + TOKEN;
234
235
  }
235
236
 
236
- // ====== 页面渲染函数 ======
237
+ // ====== Page rendering helpers ======
237
238
 
238
239
  function renderQR(data) {
239
240
  const remaining = Math.max(0, EXPIRE_MS - (Date.now() - startTime));
@@ -250,22 +251,22 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
250
251
 
251
252
  const expireMin = Math.ceil(remaining / 60000);
252
253
 
253
- // QR wrap: 圆角矩形路径从12点(顶部中心)出发,顺时针绘制
254
- // canvas 200 + padding 12*2 = 224, 圆角 r=16, 描边偏移1px
254
+ // QR wrap: rounded-rectangle path starts at 12 o'clock (top center) and goes clockwise.
255
+ // canvas 200 + padding 12*2 = 224, corner radius r=16, stroke offset 1px
255
256
  const S = 224, R = 16, cx = S/2;
256
- // 从顶部中心开始,顺时针绘制一圈回到起点(开放路径,不用 Z 闭合,避免 dash 环绕)
257
+ // Start at top center, draw clockwise back to the start (open path, no Z avoids the dash wrapping around)
257
258
  const qrPath = 'M' + cx + ',1 H' + (S-1-R) + ' A' + R + ',' + R + ' 0 0 1 ' + (S-1) + ',' + (1+R) +
258
259
  ' V' + (S-1-R) + ' A' + R + ',' + R + ' 0 0 1 ' + (S-1-R) + ',' + (S-1) +
259
260
  ' H' + (1+R) + ' A' + R + ',' + R + ' 0 0 1 1,' + (S-1-R) +
260
261
  ' V' + (1+R) + ' A' + R + ',' + R + ' 0 0 1 ' + (1+R) + ',1 H' + cx;
261
- // pathLength=1000 统一长度,避免手算偏差
262
+ // Use pathLength=1000 so the dash math is exact (no hand-calculated drift)
262
263
  const PL = 1000;
263
264
  const progress = remaining / EXPIRE_MS;
264
265
  const dashOffset = -PL * (1 - progress);
265
266
 
266
- // USDT 图标 SVG(绿色圆形 Tether 标志)
267
+ // USDT icon SVG (green circle Tether glyph)
267
268
  const USDT_ICON = '<svg class="usdt-icon" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="9" cy="9" r="9" fill="#26A17B"/><path d="M10.1 9.6c-.06 0-.33.02-.73.02-.32 0-.58-.01-.67-.02-1.32-.06-2.3-.3-2.3-.58 0-.29.98-.52 2.3-.58v.93c.09.01.36.02.68.02.38 0 .66-.01.72-.02v-.93c1.31.06 2.29.3 2.29.58 0 .28-.98.52-2.29.58zm0-.87v-.83h2.05V6.5H5.88v1.4h2.05v.83c-1.48.07-2.6.38-2.6.75 0 .37 1.12.68 2.6.75v2.69h1.07v-2.69c1.48-.07 2.59-.38 2.59-.75 0-.37-1.11-.68-2.59-.75z" fill="#fff"/></svg>';
268
- // BNB 图标 SVG(黄色圆形 BNB 标志)
269
+ // BNB icon SVG (yellow circle BNB glyph)
269
270
  const BNB_ICON = '<svg class="usdt-icon" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="9" cy="9" r="9" fill="#F3BA2F"/><path d="M9 4.5L7.2 6.3l-1.8-1.8L9 1.2l3.6 3.3-1.8 1.8L9 4.5zm-4.5 4.5L2.7 7.2 4.5 5.4l1.8 1.8L4.5 9zm4.5 4.5l-1.8-1.8-1.8 1.8L9 16.8l3.6-3.3-1.8-1.8L9 13.5zm4.5-4.5l1.8 1.8-1.8 1.8-1.8-1.8 1.8-1.8zM10.8 9L9 7.2 7.2 9 9 10.8 10.8 9z" fill="#fff"/></svg>';
270
271
  const TOKEN_ICON = TOKEN === 'BNB' ? BNB_ICON : USDT_ICON;
271
272
 
@@ -307,7 +308,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
307
308
  '<div class="result-sub">' + (error || 'Something went wrong.') + '<br>Please try again.</div></div>';
308
309
  }
309
310
 
310
- // ====== 状态机 ======
311
+ // ====== State machine ======
311
312
 
312
313
  const FINAL = ['confirmed', 'rejected', 'failed', 'expired'];
313
314
  let lastState = null;
@@ -339,7 +340,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
339
340
  stopTimer();
340
341
  } else {
341
342
  body.innerHTML = renderQR(data);
342
- // 渲染 QR
343
+ // Render the QR code
343
344
  const qrEl = document.getElementById('qr');
344
345
  if (qrEl) {
345
346
  new QRious({ element: qrEl, value: URI, size: 200, backgroundAlpha: 1, background: '#ffffff', foreground: '#000000', level: 'M' });
@@ -361,13 +362,13 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
361
362
  closeTimer = setTimeout(tick, 1000);
362
363
  }
363
364
 
364
- // 初始渲染
365
+ // Initial render
365
366
  render(null);
366
367
 
367
- // 倒计时刷新(每秒更新 timer
368
+ // Countdown refresh (update timer every second)
368
369
  timerInterval = setInterval(() => {
369
370
  const remaining = EXPIRE_MS - (Date.now() - startTime);
370
- // 后端已进入活跃状态(已连接/签名中/交易已提交),不触发页面过期
371
+ // Backend has entered an active state (connected / signing / tx-submitted); do not expire the page
371
372
  const ACTIVE = ['connected', 'signing', 'tx_submitted'];
372
373
  if (remaining <= 0 && !FINAL.includes(lastState) && !ACTIVE.includes(lastState)) {
373
374
  lastState = 'expired';
@@ -375,7 +376,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
375
376
  maybeAutoClose('expired');
376
377
  return;
377
378
  }
378
- // 更新倒计时文字
379
+ // Update the countdown label
379
380
  const timerEl = document.querySelector('.timer');
380
381
  if (timerEl) {
381
382
  const expireMin = Math.ceil(Math.max(0, remaining) / 60000);
@@ -383,7 +384,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
383
384
  const hintSpan = document.querySelector('.hint-bar span');
384
385
  if (hintSpan) hintSpan.textContent = 'Expire in ' + expireMin + ' mins. This page will close automatically once the transfer is completed';
385
386
  }
386
- // 更新 QR 边框倒计时进度(负值12点顺时针消失)
387
+ // Update the QR-border progress (negative offset the dash recedes clockwise from 12 o'clock)
387
388
  const progressEl = document.getElementById('qr-progress');
388
389
  if (progressEl) {
389
390
  const PL = 1000;
@@ -392,7 +393,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
392
393
  }
393
394
  }, 1000);
394
395
 
395
- // 轮询后端状态
396
+ // Poll backend status
396
397
  async function poll() {
397
398
  if (stopped) return;
398
399
  try {
@@ -426,7 +427,7 @@ function openQRInBrowser(uri, statusPort, amount, token = "USDT", network = "BNB
426
427
  }
427
428
 
428
429
  /**
429
- * 初始化 WalletConnect SignClient
430
+ * Initialise the WalletConnect SignClient
430
431
  * @param {string} projectId - WalletConnect Cloud project ID
431
432
  */
432
433
  export async function initSignClient(projectId) {
@@ -446,8 +447,9 @@ export async function initSignClient(projectId) {
446
447
  ),
447
448
  ]);
448
449
 
449
- // WalletConnect relay 偶发 null WebSocket 帧,导致 isJsonRpcPayload('id' in null) 崩溃
450
- // connection 层过滤掉 null payload,避免错误传播到 provider / request 链路
450
+ // WalletConnect relay occasionally emits null WebSocket frames, which crashes
451
+ // isJsonRpcPayload('id' in null). Filter null payloads at the connection layer so
452
+ // the error never reaches the provider / request chain.
451
453
  try {
452
454
  const conn = client.core.relayer.provider.connection;
453
455
  const _origEmit = conn.emit.bind(conn);
@@ -460,7 +462,7 @@ export async function initSignClient(projectId) {
460
462
  };
461
463
  } catch {}
462
464
 
463
- // 清理残留 session + pairing(并行等待完成,确保 relay 状态干净后再建新连接)
465
+ // Tear down stale sessions + pairings (await in parallel to ensure the relay is clean before reconnecting)
464
466
  try {
465
467
  const sessions = client.session.getAll();
466
468
  if (sessions.length > 0) {
@@ -486,10 +488,10 @@ export async function initSignClient(projectId) {
486
488
  }
487
489
 
488
490
  /**
489
- * 连接钱包:展示 QR 码,等待用户扫码授权
491
+ * Connect to a wallet: render the QR code and wait for the user to approve via scan.
490
492
  * @param {SignClient} signClient
491
493
  * @param {number} statusPort
492
- * @param {string|null} amount - 需要展示的 USDT 金额(如 "0.66"
494
+ * @param {string|null} amount - USDT amount to display (e.g. "0.66")
493
495
  * @returns {{ session: object, peerAddress: string }}
494
496
  */
495
497
  export async function connectWallet(signClient, statusPort, amount = null, token = "USDT", gasAmount = null) {
@@ -503,7 +505,7 @@ export async function connectWallet(signClient, statusPort, amount = null, token
503
505
  },
504
506
  });
505
507
 
506
- // 生成 QR 码页面(含状态轮询)并在浏览器中打开
508
+ // Generate the QR-code page (with status polling) and open it in the browser
507
509
  openQRInBrowser(uri, statusPort, amount, token, "BNB Chain(BEP20) only", gasAmount);
508
510
  console.error("QR code opened in browser. Scan it with your wallet app.");
509
511
  console.error("Waiting for wallet approval...");
@@ -528,11 +530,11 @@ export async function connectWallet(signClient, statusPort, amount = null, token
528
530
  }
529
531
 
530
532
  /**
531
- * 请求 ERC-20 代币转账
533
+ * Request an ERC-20 token transfer
532
534
  * @param {SignClient} signClient
533
535
  * @param {object} session - WalletConnect session
534
536
  * @param {{ from: string, to: string, token: string, amount: string, decimals?: number }} params
535
- * @returns {string} 交易 hash
537
+ * @returns {string} transaction hash
536
538
  */
537
539
  export async function requestERC20Transfer(signClient, session, { from, to, token, amount, decimals = 18 }) {
538
540
  const value = parseUnits(amount, decimals);
@@ -554,7 +556,7 @@ export async function requestERC20Transfer(signClient, session, { from, to, toke
554
556
  from,
555
557
  to: token,
556
558
  data,
557
- gas: "0xFDE8", // 65000 — ERC20 transfer 合约调用
559
+ gas: "0xFDE8", // 65000 — ERC20.transfer contract call
558
560
  },
559
561
  ],
560
562
  },
@@ -568,11 +570,11 @@ export async function requestERC20Transfer(signClient, session, { from, to, toke
568
570
  }
569
571
 
570
572
  /**
571
- * 请求原生 BNB 转账
573
+ * Request a native BNB transfer
572
574
  * @param {SignClient} signClient
573
575
  * @param {object} session
574
- * @param {{ from: string, to: string, value: string }} params - value BNB 数量(如 "0.001"
575
- * @returns {string} 交易 hash
576
+ * @param {{ from: string, to: string, value: string }} params - `value` is the BNB amount (e.g. "0.001")
577
+ * @returns {string} transaction hash
576
578
  */
577
579
  export async function requestNativeTransfer(signClient, session, { from, to, value }) {
578
580
  const weiValue = "0x" + parseUnits(value, 18).toString(16);
@@ -589,7 +591,7 @@ export async function requestNativeTransfer(signClient, session, { from, to, val
589
591
  from,
590
592
  to,
591
593
  value: weiValue,
592
- gas: "0x5208", // 21000 — BNB 原生转账固定 gas
594
+ gas: "0x5208", // 21000 — fixed gas for a native BNB transfer
593
595
  },
594
596
  ],
595
597
  },
@@ -605,11 +607,11 @@ export async function requestNativeTransfer(signClient, session, { from, to, val
605
607
  const FINAL_LINGER_MS = 2000;
606
608
 
607
609
  /**
608
- * 通用钱包连接高阶函数:自动管理连接生命周期
609
- * - 启动状态服务器
610
- * - 扫码连接钱包
611
- * - 执行调用方的事务逻辑
612
- * - 无论成功失败,始终断开连接并清理
610
+ * Higher-order wallet-connect helper: manages the full connection lifecycle.
611
+ * - Starts the status server
612
+ * - Waits for the user to scan and connect their wallet
613
+ * - Runs the caller's transaction logic
614
+ * - Always disconnects and cleans up, whether the body succeeded or failed
613
615
  *
614
616
  * @param {{ amount?: string, projectId?: string }} opts
615
617
  * @param {(ctx: { signClient, session, peerAddress }) => Promise<void>} fn
@@ -629,7 +631,7 @@ export async function withWallet(opts, fn) {
629
631
 
630
632
  await fn({ signClient, session, peerAddress });
631
633
 
632
- // 成功:写回 mainWallet
634
+ // Success: persist mainWallet so subsequent withdraws can default to it
633
635
  const config = loadConfig();
634
636
  config.mainWallet = peerAddress;
635
637
  saveConfig(config);
@@ -652,11 +654,11 @@ export async function withWallet(opts, fn) {
652
654
  await new Promise((r) => setTimeout(r, FINAL_LINGER_MS));
653
655
  stopStatusServer();
654
656
  if (signClient) {
655
- // 断开当前 session
657
+ // Disconnect the current session
656
658
  if (session) {
657
659
  await disconnectSession(signClient, session);
658
660
  }
659
- // 断开所有 pairing,确保钱包端不残留连接
661
+ // Disconnect every pairing so the wallet side has no lingering connection
660
662
  try {
661
663
  const pairings = signClient.core.pairing.pairings.getAll({ active: true });
662
664
  await Promise.allSettled(
@@ -672,19 +674,19 @@ export async function withWallet(opts, fn) {
672
674
  }
673
675
 
674
676
  /**
675
- * 标准化钱包错误消息:将已知的中文/多语言错误映射为统一英文
677
+ * Normalise wallet error messages: map known Chinese / multilingual error strings to a unified English form.
676
678
  * @param {Error} error
677
- * @returns {Error} 同一个 error 对象,message 已替换
679
+ * @returns {Error} the same error object with its `message` rewritten
678
680
  */
679
681
  export function normalizeWalletError(error) {
680
682
  const msg = error?.message || "";
681
683
  const patterns = [
682
- // 拒绝类
683
- { test: /拒绝|用户取消|User rejected|User denied|declined/i, replacement: "rejected" },
684
- // 断开连接类
685
- { test: /断开.*连接|断开.*DApp|disconnect.*DApp|session.*expired|session.*disconnected/i, replacement: "rejected" },
686
- // 超时类
687
- { test: /超时|timed?\s*out|timeout/i, replacement: "timed out" },
684
+ // Rejection patterns (English error strings only — localised wallets fall through to WALLET_ERROR)
685
+ { test: /User rejected|User denied|declined/i, replacement: "rejected" },
686
+ // Disconnect patterns
687
+ { test: /disconnect.*DApp|session.*expired|session.*disconnected/i, replacement: "rejected" },
688
+ // Timeout patterns
689
+ { test: /timed?\s*out|timeout/i, replacement: "timed out" },
688
690
  ];
689
691
  for (const { test, replacement } of patterns) {
690
692
  if (test.test(msg)) {
@@ -696,7 +698,7 @@ export function normalizeWalletError(error) {
696
698
  }
697
699
 
698
700
  /**
699
- * 断开 WalletConnect 会话
701
+ * Disconnect a WalletConnect session.
700
702
  * @param {SignClient} signClient
701
703
  * @param {object} session
702
704
  */
@@ -707,6 +709,6 @@ export async function disconnectSession(signClient, session) {
707
709
  reason: { code: 6000, message: "Session complete" },
708
710
  });
709
711
  } catch {
710
- // 静默处理断开错误
712
+ // Silently ignore disconnect errors
711
713
  }
712
714
  }
package/src/x402.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * x402 协议客户端:初始化 EVM signer + x402Client
2
+ * x402 protocol client: initialise an EVM signer and an x402Client.
3
3
  */
4
4
  import { x402Client, wrapAxiosWithPayment, x402HTTPClient } from "@aeon-ai-pay/axios";
5
5
  import { registerExactEvmScheme } from "@aeon-ai-pay/evm/exact/client";
@@ -11,8 +11,8 @@ import { BSC_RPC_URL } from "./constants.mjs";
11
11
  import axios from "axios";
12
12
 
13
13
  /**
14
- * 创建已注册 EVM 签名的 x402 axios 客户端
15
- * @param {`0x${string}`} privateKey - EVM 私钥
14
+ * Build an x402 axios client with the EVM signer pre-registered.
15
+ * @param {`0x${string}`} privateKey - EVM private key
16
16
  * @returns {{ api: AxiosInstance, client: x402Client, address: string, getOrderNo: () => string|null }}
17
17
  */
18
18
  export function createX402Api(privateKey) {
@@ -39,8 +39,9 @@ export function createX402Api(privateKey) {
39
39
 
40
40
  const axiosInstance = axios.create();
41
41
 
42
- // wrapAxiosWithPayment 之前注册拦截器,
43
- // 402 响应体中捕获 orderNo(服务端在 firstRequest 返回)
42
+ // Register the interceptor *before* wrapAxiosWithPayment so it can
43
+ // capture orderNo from the 402 response body (the server returns it
44
+ // on the first request).
44
45
  let capturedOrderNo = null;
45
46
  axiosInstance.interceptors.response.use(
46
47
  (response) => response,
@@ -63,11 +64,13 @@ export function createX402Api(privateKey) {
63
64
  }
64
65
 
65
66
  /**
66
- * 第一次发起 x402 请求(不带签名),从 402 响应中提取实际付款要求。
67
- * 同时保留完整的 402 响应数据和原始请求配置,供后续手动签名使用。
68
- * 字段名与 x402 v2 PaymentRequirements 标准对齐:asset、payTo、amount。
67
+ * Send the first x402 request (unsigned) and extract the real payment requirements
68
+ * from the 402 response.
69
+ * Also keeps the raw 402 response and the original request config so the caller can
70
+ * sign manually later.
71
+ * Field names follow the x402 v2 PaymentRequirements standard: asset, payTo, amount.
69
72
  *
70
- * 兼容 GETcard 路径)和 POSTimage / Skill Boss 路径)。
73
+ * Supports both GET (card path) and POST (image / Skill Boss path).
71
74
  *
72
75
  * @param {string} url
73
76
  * @param {{ method?: "GET"|"POST", data?: any, headers?: object }} [options]
@@ -105,7 +108,7 @@ export async function fetchPaymentRequirements(url, options = {}) {
105
108
  }
106
109
 
107
110
  /**
108
- * 从响应头中解码 PAYMENT-RESPONSEx402 v2
111
+ * Decode the PAYMENT-RESPONSE response header (x402 v2).
109
112
  * @param {object} headers - axios response headers
110
113
  * @returns {object|null}
111
114
  */