@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,5 +1,5 @@
1
1
  /**
2
- * withdraw 命令:将 session key 中的资金转回主钱包(USDT + BNB
2
+ * wallet-withdraw: move the session key's funds (USDT + BNB) back to the main wallet.
3
3
  */
4
4
  import { createPublicClient, createWalletClient, http, parseUnits, formatUnits, encodeFunctionData } from "viem";
5
5
  import { privateKeyToAccount } from "viem/accounts";
@@ -54,7 +54,7 @@ export async function withdraw(opts) {
54
54
 
55
55
  const isWithdrawAll = !opts.amount;
56
56
 
57
- // 无任何资金
57
+ // No funds at all
58
58
  if (balance.usdtRaw === 0n && balance.bnbRaw === 0n) {
59
59
  emitErr("wallet-withdraw", "NO_FUNDS", { message: "No funds to withdraw.", appId });
60
60
  return;
@@ -63,9 +63,9 @@ export async function withdraw(opts) {
63
63
  let usdtTxHash = null;
64
64
  let bnbTxHash = null;
65
65
 
66
- // 1. 赎回 USDT(有 USDT 才执行)
66
+ // 1. Reclaim USDT (only when USDT balance > 0)
67
67
  if (balance.usdtRaw > 0n) {
68
- // USDT 转账需要 BNB gas
68
+ // USDT transfer needs BNB for gas
69
69
  if (balance.bnbRaw === 0n) {
70
70
  emitErr("wallet-withdraw", "INSUFFICIENT_BNB", {
71
71
  message: "No BNB for gas. Withdraw is a normal on-chain transfer and requires BNB to pay gas.",
@@ -119,7 +119,7 @@ export async function withdraw(opts) {
119
119
  }
120
120
  }
121
121
 
122
- // 2. 赎回剩余 BNB(仅赎回全部时)
122
+ // 2. Reclaim remaining BNB (only when withdrawing everything)
123
123
  if (isWithdrawAll) {
124
124
  const freshBalance = balance.usdtRaw > 0n
125
125
  ? await getBalanceByAddress(sessionAddress)
@@ -128,7 +128,7 @@ export async function withdraw(opts) {
128
128
  if (freshBalance.bnbRaw > 0n) {
129
129
  try {
130
130
  const gasPrice = await publicClient.getGasPrice();
131
- // 预留 20% buffer 应对 gas price 波动
131
+ // Reserve a 20% buffer to absorb gas-price fluctuations
132
132
  const gasCost = BNB_TRANSFER_GAS * (gasPrice * 120n / 100n);
133
133
  const sendable = freshBalance.bnbRaw - gasCost;
134
134
 
@@ -159,7 +159,7 @@ export async function withdraw(opts) {
159
159
  }
160
160
  }
161
161
 
162
- // 查询最终余额
162
+ // Final balance lookup
163
163
  let finalBalance;
164
164
  try {
165
165
  finalBalance = await getBalanceByAddress(sessionAddress);
package/src/config.mjs CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
- * 配置管理:~/.aigateway/config.json
3
- * 优先级:CLI 参数 > 环境变量 > config.json
2
+ * Config management: ~/.aigateway/config.json
3
+ * Resolution priority: CLI args > env vars > config.json
4
4
  *
5
- * AEON AI Gateway 统一使用同一个 x402 服务端(ai-api.aeon.xyz),
6
- * 不同能力(虚拟卡 / Skill Boss 调用)走不同的路径前缀。
5
+ * AEON AI Gateway uses a single x402 service (ai-api.aeon.xyz);
6
+ * different capabilities (virtual card / Skill Boss calls) share the host
7
+ * but use distinct path prefixes.
7
8
  */
8
9
  import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "fs";
9
10
  import { join } from "path";
@@ -31,7 +32,7 @@ export function saveConfig(config) {
31
32
  }
32
33
 
33
34
  /**
34
- * 解析配置值,优先级:cliValue > envKey > config[configKey]
35
+ * Resolve a value with priority: cliValue > envKey > config[configKey]
35
36
  */
36
37
  export function resolve(cliValue, envKey, configKey) {
37
38
  if (cliValue) return cliValue;
@@ -1,16 +1,16 @@
1
1
  /**
2
- * 错误码常量表 —— CLI 与文档的单一事实源
2
+ * Error-code registry — single source of truth shared by the CLI and the docs.
3
3
  *
4
- * 退出码语义:
5
- * 0 成功
6
- * 1 用户错误(参数、余额、配置、用户拒绝)
7
- * 2 超时(轮询、WalletConnect、签名、链上)
8
- * 3 服务端 / 网络
9
- * 4 内部错误
4
+ * Exit-code semantics:
5
+ * 0 success
6
+ * 1 user error (bad argument, insufficient balance, configuration, user reject)
7
+ * 2 timeout (polling, WalletConnect, signature, on-chain wait)
8
+ * 3 service / network
9
+ * 4 internal error
10
10
  */
11
11
 
12
12
  export const ERROR_CODES = {
13
- // ===== 用户错误(exit 1)=====
13
+ // ===== User error (exit 1) =====
14
14
  WALLET_NOT_CONFIGURED: { exit: 1, message: "Wallet not configured. Run: aigateway wallet-init" },
15
15
  SERVICE_URL_MISSING: { exit: 1, message: "Service URL not configured." },
16
16
  AMOUNT_INVALID: { exit: 1, message: "Invalid amount." },
@@ -25,13 +25,13 @@ export const ERROR_CODES = {
25
25
  TOPUP_AMOUNT_TOO_SMALL: { exit: 1, message: "Top-up amount is below the minimum." },
26
26
  PAYMENT_REJECTED: { exit: 1, message: "Payment approval was rejected. Please try again if you'd like to proceed." },
27
27
 
28
- // ===== 超时(exit 2)=====
28
+ // ===== Timeout (exit 2) =====
29
29
  PAYMENT_TIMEOUT: { exit: 2, message: "Payment approval timed out. Please try again." },
30
30
  WC_SESSION_EXPIRED: { exit: 2, message: "WalletConnect session expired." },
31
31
  POLL_TIMEOUT: { exit: 2, message: "Polling timed out. Card may still be provisioning." },
32
32
  TX_TIMEOUT: { exit: 2, message: "On-chain transaction timed out." },
33
33
 
34
- // ===== 服务/网络(exit 3)=====
34
+ // ===== Service / network (exit 3) =====
35
35
  SERVICE_UNAVAILABLE: { exit: 3, message: "Service unavailable or network error." },
36
36
  PAYMENT_FETCH_FAILED: { exit: 3, message: "Failed to fetch payment requirements." },
37
37
  BALANCE_CHECK_FAILED: { exit: 3, message: "Failed to check balance." },
@@ -44,7 +44,7 @@ export const ERROR_CODES = {
44
44
  IMAGE_DOWNLOAD_FAILED: { exit: 3, message: "Image download failed." },
45
45
  FUNDING_FAILED: { exit: 3, message: "Funding flow failed." },
46
46
 
47
- // ===== 内部(exit 4)=====
47
+ // ===== Internal (exit 4) =====
48
48
  INTERNAL_ERROR: { exit: 4, message: "Internal error." },
49
49
  WALLET_ERROR: { exit: 1, message: "Wallet operation failed." },
50
50
  };
package/src/output.mjs CHANGED
@@ -1,12 +1,13 @@
1
1
  /**
2
- * 统一输出封装:envelope JSON + 分级日志
2
+ * Unified output envelope: JSON on stdout + tiered stderr logs.
3
3
  *
4
- * stdout: 一行最终 JSONmachine-readable
5
- * - 成功:{ ok: true, command, version, data }
6
- * - 失败:{ ok: false, command, version, error: { code, message, ...context } }
7
- * stderr: 进度日志(human-readable,agent 可忽略)
4
+ * stdout: a single line of final JSON (machine-readable)
5
+ * - success: { ok: true, command, version, data }
6
+ * - failure: { ok: false, command, version, error: { code, message, ...context } }
7
+ * stderr: progress logs (human-readable; agents can ignore them)
8
8
  *
9
- * --legacy-output 模式:保留旧裸字段格式,便于已按旧 JSON 解析的脚本/agent 平滑过渡。
9
+ * --legacy-output mode: emit the pre-envelope shape so scripts / agents that
10
+ * already parse the old JSON can migrate gradually.
10
11
  */
11
12
 
12
13
  import { readFileSync } from "fs";
@@ -30,10 +31,11 @@ export function isLegacyMode() { return LEGACY_MODE; }
30
31
  export function isVerboseMode() { return VERBOSE_MODE; }
31
32
 
32
33
  /**
33
- * 输出成功结果。调用方应在调用后让函数自然返回(不要再 process.exit)。
34
- * @param {string} command - 命令名,如 "create-card" / "wallet-init"
35
- * @param {object} data - envelope 模式下放在 data 字段
36
- * @param {object} [legacyShape] - legacy 模式下直接输出的旧格式对象;省略则使用 data 本身
34
+ * Emit a success result. Callers should let the function return naturally
35
+ * (do not call process.exit afterwards).
36
+ * @param {string} command - command name, e.g. "create-card" / "wallet-init"
37
+ * @param {object} data - placed under envelope.data
38
+ * @param {object} [legacyShape] - the legacy-mode payload; if omitted, `data` is used
37
39
  */
38
40
  export function emitOk(command, data, legacyShape) {
39
41
  if (LEGACY_MODE) {
@@ -44,10 +46,11 @@ export function emitOk(command, data, legacyShape) {
44
46
  }
45
47
 
46
48
  /**
47
- * 输出错误并退出(按错误码对应的 exit 码)。
49
+ * Emit an error and exit with the corresponding exit code.
48
50
  * @param {string} command
49
- * @param {string} code - ERROR_CODES 键名
50
- * @param {object} [details] - 额外字段。message 字段会覆盖默认 message;legacy 字段在 legacy 模式下完全替代输出
51
+ * @param {string} code - key of ERROR_CODES
52
+ * @param {object} [details] - extra fields. `message` overrides the default message;
53
+ * `legacy` fully replaces the output in legacy mode.
51
54
  */
52
55
  export function emitErr(command, code, details = {}) {
53
56
  const info = ERROR_CODES[code] || ERROR_CODES.INTERNAL_ERROR;
@@ -69,17 +72,17 @@ export function emitErr(command, code, details = {}) {
69
72
  process.exit(exit);
70
73
  }
71
74
 
72
- /** 进度日志(quiet 模式压制) */
75
+ /** Progress log (suppressed in quiet mode) */
73
76
  export function logInfo(msg) {
74
77
  if (!QUIET_MODE) console.error(msg);
75
78
  }
76
79
 
77
- /** 详细日志(仅 verbose 模式下输出) */
80
+ /** Verbose log (only emitted in verbose mode) */
78
81
  export function logVerbose(msg) {
79
82
  if (VERBOSE_MODE && !QUIET_MODE) console.error(msg);
80
83
  }
81
84
 
82
- /** 错误日志(quiet 模式下也会输出) */
85
+ /** Error log (still emitted in quiet mode) */
83
86
  export function logError(msg) {
84
87
  console.error(msg);
85
88
  }
package/src/sanitize.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  /**
2
- * 卡片输出脱敏:隐藏敏感卡片信息(完整卡号→末4位、移除CVV、移除有效期)
3
- * CLI 输出 JSON Agent 解析,Agent 按产品模板展示给用户
2
+ * Card output sanitisation: redact sensitive card data (truncate the full PAN to its last 4 digits, drop CVV, drop expiry).
3
+ * The CLI emits JSON for an agent to parse; the agent then renders the product-specific template to the user.
4
4
  */
5
5
 
6
- // 需要替换为末4位的字段
6
+ // Fields whose value should be replaced with the last-4 representation
7
7
  const CARD_NUMBER_KEYS = new Set([
8
8
  "cardnumber", "cardno",
9
9
  ]);
10
10
 
11
- // 需要完全移除的字段
11
+ // Fields that must be removed entirely
12
12
  const REMOVE_KEYS = new Set([
13
13
  "cvv", "cvv2", "cvc", "cvc2", "securitycode",
14
14
  "expiry", "expirydate", "expiredate", "cardexpiry",
@@ -16,10 +16,10 @@ const REMOVE_KEYS = new Set([
16
16
  ]);
17
17
 
18
18
  /**
19
- * 递归脱敏对象:
20
- * - cardNumber/cardNo → 只保留末4位("•••• 3398"
21
- * - cvv/securityCode → 移除
22
- * - expiry/expireDate → 移除
19
+ * Recursively sanitise an object:
20
+ * - cardNumber / cardNo → keep only the last four digits ("•••• 3398")
21
+ * - cvv / securityCode → drop
22
+ * - expiry / expireDate → drop
23
23
  */
24
24
  export function sanitizeOutput(obj) {
25
25
  if (obj === null || obj === undefined) return obj;
@@ -30,15 +30,15 @@ export function sanitizeOutput(obj) {
30
30
  for (const [key, value] of Object.entries(obj)) {
31
31
  const normalized = key.toLowerCase().replace(/[-_]/g, "");
32
32
 
33
- // 移除 CVV、有效期等敏感字段
33
+ // Drop sensitive fields (CVV, expiry, etc.)
34
34
  if (REMOVE_KEYS.has(normalized)) continue;
35
35
 
36
- // 卡号只保留末4
36
+ // Card number: only keep the last 4 digits
37
37
  if (CARD_NUMBER_KEYS.has(normalized)) {
38
38
  if (typeof value === "string" && value.length >= 4) {
39
39
  result[key] = "•••• " + value.slice(-4);
40
40
  }
41
- // value null 时不输出此字段
41
+ // when value is null, do not emit this field
42
42
  continue;
43
43
  }
44
44
 
@@ -1,11 +1,11 @@
1
1
  /**
2
- * 自动版本检查 + 静默后台升级
2
+ * Auto version check + silent background upgrade.
3
3
  *
4
- * 策略:
5
- * 1. 同步快速检查(npm view)— 发现新版本时输出提示
6
- * 2. spawn 后台子进程执行 npm install -g 升级
7
- * 3. 升级后执行 postinstall.mjsskills CLI 安装到所有工具)
8
- * 不阻塞主进程
4
+ * Strategy:
5
+ * 1. Synchronously poll the npm registry (`npm view`) — print a notice when a newer version is found.
6
+ * 2. Spawn a detached background process to run `npm install -g`.
7
+ * 3. After install, run postinstall.mjs (which re-installs the skill into every detected tool via the skills CLI).
8
+ * Does not block the main process.
9
9
  */
10
10
 
11
11
  import { execFileSync, spawn } from "node:child_process";
@@ -13,11 +13,11 @@ import { execFileSync, spawn } from "node:child_process";
13
13
  const PKG_NAME = "@aeon-ai-pay/aigateway";
14
14
 
15
15
  /**
16
- * 启动时调用:同步检查版本 + 后台升级
16
+ * Called at CLI startup: synchronous version probe + detached upgrade.
17
17
  * @param {string} currentVersion
18
18
  */
19
19
  export function checkForUpdates(currentVersion) {
20
- // 同步快速检查最新版本(超时短,不阻塞太久)
20
+ // Synchronous fast probe (short timeout so it does not block too long)
21
21
  let latest;
22
22
  try {
23
23
  latest = execFileSync("npm", ["view", PKG_NAME, "version"], {
@@ -25,15 +25,15 @@ export function checkForUpdates(currentVersion) {
25
25
  stdio: ["ignore", "pipe", "ignore"],
26
26
  }).toString().trim();
27
27
  } catch {
28
- return; // 网络不可用,静默跳过
28
+ return; // network unavailable — silently skip
29
29
  }
30
30
 
31
31
  if (!latest || latest === currentVersion) return;
32
32
 
33
- // 有新版本:输出提示
33
+ // A newer version exists — print a notice
34
34
  console.error(`[update] ${PKG_NAME} ${currentVersion} → ${latest}, upgrading in background...`);
35
35
 
36
- // 后台执行升级(结果写入日志文件)
36
+ // Run the upgrade in a detached child, writing the result to a log file
37
37
  const script = `
38
38
  const { execFileSync } = require("child_process");
39
39
  const { join } = require("path");