@subly_fi/pay 0.5.0 → 0.6.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.
package/README.md CHANGED
@@ -19,10 +19,14 @@ Ships one `pay` dispatcher bin with subcommands, all runnable with `npx` (no clo
19
19
  threshold, deposits, and (when the mandate opts in) withdrawals return an
20
20
  `approveUrl` to paste into chat; retry with the `approvalId` once the
21
21
  human approved.
22
- - `pay fetch <url>` — one-shot: pay for a URL, print the receipt (used by the
23
- OpenClaw skill)
24
- - `pay deposit <amountRawUsdc>` / `pay withdraw <amountRawUsdc>` — vault
25
- deposit / withdraw
22
+ - `pay fetch <url> [maxAmountRawUsdc] [apr_<approvalId>]` — one-shot: pay for
23
+ a URL, print the receipt (used by the OpenClaw skill); retry with the
24
+ `apr_...` id after an `approval_required` refusal
25
+ - `pay deposit <amountRawUsdc> [apr_...]` / `pay withdraw <amountRawUsdc>
26
+ [apr_...]` — vault deposit / withdraw with the same owner-approval flow
27
+ - `pay setup-link [--initial-deposit <raw>] [--approval-threshold <raw>] ...`
28
+ / `pay setup-status <sessionId>` — owner onboarding for CLI/skill harnesses
29
+ (same flow as the MCP setup tools)
26
30
 
27
31
  ## Wallet
28
32
 
package/dist/cli.js CHANGED
@@ -9,14 +9,16 @@ const TARGETS = {
9
9
  mcp: "mcp-server.js",
10
10
  fetch: "pay.js",
11
11
  deposit: "deposit.js",
12
- withdraw: "withdraw.js"
12
+ withdraw: "withdraw.js",
13
+ "setup-link": "setup-link.js",
14
+ "setup-status": "setup-status.js"
13
15
  };
14
16
 
15
17
  const [sub, ...rest] = process.argv.slice(2);
16
18
  const target = sub === undefined ? undefined : TARGETS[sub];
17
19
  if (target === undefined) {
18
20
  console.error(
19
- "usage: subly <mcp|fetch <url>|deposit <amountRawUsdc>|withdraw <amountRawUsdc>>"
21
+ "usage: subly <mcp|fetch <url>|deposit <amountRawUsdc>|withdraw <amountRawUsdc>|setup-link|setup-status <sessionId>>"
20
22
  );
21
23
  process.exit(1);
22
24
  }
package/dist/deposit.js CHANGED
@@ -1115,26 +1115,26 @@ var VaultFlowClient = class {
1115
1115
  * up and used automatically before surfacing deposit_approval_required.
1116
1116
  */
1117
1117
  async deposit(input) {
1118
- let approvalId = input.approvalId;
1118
+ let approvalId2 = input.approvalId;
1119
1119
  let prepared;
1120
1120
  try {
1121
1121
  prepared = await this.postJson("prepare", "/v1/deposits/prepare", {
1122
1122
  wallet: this.signer.walletAddress,
1123
1123
  amountRawUsdc: input.amountRawUsdc.toString(),
1124
- ...approvalId === void 0 ? {} : { approvalId }
1124
+ ...approvalId2 === void 0 ? {} : { approvalId: approvalId2 }
1125
1125
  });
1126
1126
  } catch (error) {
1127
- if (!(error instanceof VaultFlowClientError) || error.code !== "deposit_approval_required" || approvalId !== void 0) {
1127
+ if (!(error instanceof VaultFlowClientError) || error.code !== "deposit_approval_required" || approvalId2 !== void 0) {
1128
1128
  throw error;
1129
1129
  }
1130
- approvalId = await this.findApprovedDepositApproval(input.amountRawUsdc);
1131
- if (approvalId === void 0) {
1130
+ approvalId2 = await this.findApprovedDepositApproval(input.amountRawUsdc);
1131
+ if (approvalId2 === void 0) {
1132
1132
  throw error;
1133
1133
  }
1134
1134
  prepared = await this.postJson("prepare", "/v1/deposits/prepare", {
1135
1135
  wallet: this.signer.walletAddress,
1136
1136
  amountRawUsdc: input.amountRawUsdc.toString(),
1137
- approvalId
1137
+ approvalId: approvalId2
1138
1138
  });
1139
1139
  }
1140
1140
  const signed = await this.signer.signDeposit({
@@ -1480,9 +1480,13 @@ var relayerBaseUrl = process.env.SUBLY_RELAYER_URL ?? process.env.SUBLY_FACILITA
1480
1480
  var amountRawUsdc = process.argv[2];
1481
1481
  if (amountRawUsdc === void 0 || !/^[1-9]\d*$/.test(amountRawUsdc)) {
1482
1482
  fail(
1483
- "Usage: npm run demo:deposit -- <amountRawUsdc> (positive integer, e.g. 60000000 = 60 USDC)"
1483
+ "Usage: pay deposit <amountRawUsdc> [apr_<approvalId>] (positive integer, e.g. 60000000 = 60 USDC)"
1484
1484
  );
1485
1485
  }
1486
+ var approvalId = process.argv[3];
1487
+ if (approvalId !== void 0 && !/^apr_[0-9a-f]+$/i.test(approvalId)) {
1488
+ fail(`unrecognized argument: ${approvalId} (expected apr_<approvalId>)`);
1489
+ }
1486
1490
  var keyPairSigner = await loadKeyPairSigner({
1487
1491
  base58Secret: process.env.SUBLY_DEMO_AGENT_KEYPAIR,
1488
1492
  jsonFilePath: process.env.SUBLY_DEMO_AGENT_KEYPAIR_PATH,
@@ -1508,9 +1512,46 @@ console.log(
1508
1512
  );
1509
1513
  var submitted;
1510
1514
  try {
1511
- submitted = await vaultFlows.deposit({ amountRawUsdc: BigInt(amountRawUsdc) });
1515
+ submitted = await vaultFlows.deposit({
1516
+ amountRawUsdc: BigInt(amountRawUsdc),
1517
+ ...approvalId === void 0 ? {} : { approvalId }
1518
+ });
1512
1519
  } catch (error) {
1513
1520
  if (error instanceof VaultFlowClientError) {
1521
+ if (error.code === "deposit_approval_required") {
1522
+ const details = error.errorDetails ?? {};
1523
+ process.stdout.write(
1524
+ `${JSON.stringify(
1525
+ {
1526
+ ok: false,
1527
+ approvalRequired: true,
1528
+ approvalId: details.approvalId ?? null,
1529
+ approveUrl: details.approveUrl ?? null,
1530
+ expiresAtMs: details.expiresAtMs ?? null,
1531
+ message: `This deposit needs the owner's approval. Paste approveUrl to the user; once they approve (Face ID / wallet sign), retry: pay deposit ${amountRawUsdc} ${details.approvalId ?? "<approvalId>"}`
1532
+ },
1533
+ null,
1534
+ 2
1535
+ )}
1536
+ `
1537
+ );
1538
+ process.exit(1);
1539
+ }
1540
+ if (error.code === "mandate_required_for_deposit") {
1541
+ process.stdout.write(
1542
+ `${JSON.stringify(
1543
+ {
1544
+ ok: false,
1545
+ setupRequired: true,
1546
+ message: `Deposits require a registered owner. Create a setup link (pay setup-link --initial-deposit ${amountRawUsdc}), paste the setupUrl to the user, wait for their Face ID, then deposit again \u2014 the first deposit is pre-approved.`
1547
+ },
1548
+ null,
1549
+ 2
1550
+ )}
1551
+ `
1552
+ );
1553
+ process.exit(1);
1554
+ }
1514
1555
  fail(`[deposit] ${error.step} failed: ${error.message}`);
1515
1556
  }
1516
1557
  throw error;
package/dist/pay.js CHANGED
@@ -1120,26 +1120,26 @@ var VaultFlowClient = class {
1120
1120
  * up and used automatically before surfacing deposit_approval_required.
1121
1121
  */
1122
1122
  async deposit(input) {
1123
- let approvalId = input.approvalId;
1123
+ let approvalId2 = input.approvalId;
1124
1124
  let prepared;
1125
1125
  try {
1126
1126
  prepared = await this.postJson("prepare", "/v1/deposits/prepare", {
1127
1127
  wallet: this.signer.walletAddress,
1128
1128
  amountRawUsdc: input.amountRawUsdc.toString(),
1129
- ...approvalId === void 0 ? {} : { approvalId }
1129
+ ...approvalId2 === void 0 ? {} : { approvalId: approvalId2 }
1130
1130
  });
1131
1131
  } catch (error) {
1132
- if (!(error instanceof VaultFlowClientError) || error.code !== "deposit_approval_required" || approvalId !== void 0) {
1132
+ if (!(error instanceof VaultFlowClientError) || error.code !== "deposit_approval_required" || approvalId2 !== void 0) {
1133
1133
  throw error;
1134
1134
  }
1135
- approvalId = await this.findApprovedDepositApproval(input.amountRawUsdc);
1136
- if (approvalId === void 0) {
1135
+ approvalId2 = await this.findApprovedDepositApproval(input.amountRawUsdc);
1136
+ if (approvalId2 === void 0) {
1137
1137
  throw error;
1138
1138
  }
1139
1139
  prepared = await this.postJson("prepare", "/v1/deposits/prepare", {
1140
1140
  wallet: this.signer.walletAddress,
1141
1141
  amountRawUsdc: input.amountRawUsdc.toString(),
1142
- approvalId
1142
+ approvalId: approvalId2
1143
1143
  });
1144
1144
  }
1145
1145
  const signed = await this.signer.signDeposit({
@@ -2251,9 +2251,20 @@ function fail(message) {
2251
2251
  }
2252
2252
  var url = process.argv[2];
2253
2253
  if (url === void 0 || !/^https?:\/\//.test(url)) {
2254
- fail("Usage: pay fetch <url> [maxAmountRawUsdc]");
2254
+ fail("Usage: pay fetch <url> [maxAmountRawUsdc] [apr_<approvalId>]");
2255
+ }
2256
+ var maxAmountArg;
2257
+ var approvalId;
2258
+ for (const arg of process.argv.slice(3)) {
2259
+ if (/^apr_[0-9a-f]+$/i.test(arg)) {
2260
+ approvalId = arg;
2261
+ } else if (/^\d+$/.test(arg)) {
2262
+ maxAmountArg = arg;
2263
+ } else {
2264
+ fail(`unrecognized argument: ${arg}
2265
+ Usage: pay fetch <url> [maxAmountRawUsdc] [apr_<approvalId>]`);
2266
+ }
2255
2267
  }
2256
- var maxAmountArg = process.argv[3];
2257
2268
  var relayerBaseUrl = process.env.SUBLY_RELAYER_URL ?? process.env.SUBLY_FACILITATOR_URL ?? "https://api.demo.sublyfi.com";
2258
2269
  var rpcUrl = process.env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com";
2259
2270
  var defaultMaxAmountRawUsdc = process.env.SUBLY_MCP_MAX_AMOUNT_RAW_USDC === void 0 ? 10000n : BigInt(process.env.SUBLY_MCP_MAX_AMOUNT_RAW_USDC);
@@ -2294,6 +2305,7 @@ try {
2294
2305
  ...method === void 0 ? {} : { method },
2295
2306
  ...body === void 0 ? {} : { body, headers: { "content-type": "application/json" } },
2296
2307
  ...maxAmountArg === void 0 ? {} : { maxAmountRawUsdc: BigInt(maxAmountArg) },
2308
+ ...approvalId === void 0 ? {} : { approvalId },
2297
2309
  ...process.env.SUBLY_PAY_FORCE_NEW_PAYMENT === "1" ? { forceNewPayment: true } : {}
2298
2310
  });
2299
2311
  process.stdout.write(`${JSON.stringify(result, null, 2)}
@@ -2305,7 +2317,12 @@ try {
2305
2317
  if (error instanceof StandardX402PayError) {
2306
2318
  process.stdout.write(
2307
2319
  `${JSON.stringify(
2308
- { paid: false, reason: error.reason, message: error.message },
2320
+ {
2321
+ paid: false,
2322
+ reason: error.reason,
2323
+ message: error.message,
2324
+ detail: error.detail ?? null
2325
+ },
2309
2326
  null,
2310
2327
  2
2311
2328
  )}