agent402-client 0.6.10 → 0.6.11

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 (3) hide show
  1. package/README.md +26 -0
  2. package/index.js +28 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -69,6 +69,15 @@ const a = new Agent402({ fetch: payFetch });
69
69
  const article = await a.call("extract", { url: "https://example.com/article" });
70
70
  ```
71
71
 
72
+ ## Retries never double-charge
73
+
74
+ Every paid call the SDK makes carries an `Idempotency-Key`, so a retry of a
75
+ call whose response was lost replays the original result instead of paying
76
+ again. If your x402 client attaches the standard `payment-identifier`
77
+ extension to its payloads instead, Agent402 honours that id the same way (an
78
+ exact retry with the same credential replays; a fresh authorization with the
79
+ same id is a new payment).
80
+
72
81
  ## Workflows (skill packs)
73
82
 
74
83
  For jobs that no single tool covers — e.g. "audit a domain", "build a stock
@@ -179,6 +188,23 @@ Short names map to CAIP-2 (`base`, `solana`, `polygon`, `arbitrum`,
179
188
  without a package update. If the preference matches none of a seller's
180
189
  payment options it throws **before** any payment is signed.
181
190
 
191
+
192
+ ## Only pay who you meant to (`withPayeeAllowlist`)
193
+
194
+ The buyer-side mirror of a spend control: bound WHO gets paid, not just how
195
+ much. Wrap your x402 client before `wrapFetchWithPayment` and any 402 whose
196
+ `accepts` would send funds to an address outside the list is refused before a
197
+ signature exists (a routed or redirected seller can never collect).
198
+
199
+ ```js
200
+ import { withPayeeAllowlist } from "agent402-client";
201
+ withPayeeAllowlist(client, ["0xYourSellerPayTo", "0xAnother"]); // 0x addresses compare case-insensitively
202
+ const payFetch = wrapFetchWithPayment(fetch, client);
203
+ ```
204
+
205
+ Pairs with `maxPerCallUsd` / `dailyLimitUsd` (how much) and
206
+ `withNetworkPreference` (which chain).
207
+
182
208
  ## Legal
183
209
 
184
210
  Use of the hosted instance at agent402.tools is subject to its [Terms of Service](https://agent402.tools/terms) (acceptable-use policy included) and [Privacy Policy](https://agent402.tools/privacy). This package is MIT-licensed; the hosted server is AGPL-3.0. Both are provided as-is without warranty, and self-hosted deployments are their operator's responsibility.
package/index.js CHANGED
@@ -402,4 +402,32 @@ export function withNetworkPreference(client, networks) {
402
402
  return client;
403
403
  }
404
404
 
405
+ /**
406
+ * Payee allowlist: refuse to pay ANY 402 whose accepts would send funds to an
407
+ * address outside `payees` - the buyer-side mirror of a spend control (CDP's
408
+ * CdpX402Client bounds amounts and networks; this bounds WHO gets paid). Same
409
+ * wrapping style as withNetworkPreference: the payment-aware fetch sees a
410
+ * filtered `accepts`, so a quote that names an unknown payTo is never paid -
411
+ * it throws before any signature exists. Addresses compare case-insensitively
412
+ * for 0x (EVM) and exactly otherwise (base58/Stellar are case-sensitive).
413
+ * Works on any x402Client (createPaymentPayload) - register it before
414
+ * wrapFetchWithPayment.
415
+ */
416
+ export function withPayeeAllowlist(client, payees) {
417
+ const norm = (a) => (typeof a === "string" && /^0x[0-9a-fA-F]{40}$/.test(a) ? a.toLowerCase() : String(a || "").trim());
418
+ const allowed = new Set((payees || []).map(norm).filter(Boolean));
419
+ if (!allowed.size) throw new Error("withPayeeAllowlist: at least one payee address is required");
420
+ const orig = client.createPaymentPayload.bind(client);
421
+ client.createPaymentPayload = (paymentRequired) => {
422
+ const list = Array.isArray(paymentRequired?.accepts) ? paymentRequired.accepts : [];
423
+ const picked = list.filter((a) => allowed.has(norm(a?.payTo)));
424
+ if (!picked.length) {
425
+ const offered = [...new Set(list.map((a) => a?.payTo).filter(Boolean))];
426
+ throw new Error(`payee allowlist refused this quote: the seller asks to be paid at [${offered.join(", ")}], none of which is allowlisted`);
427
+ }
428
+ return orig({ ...paymentRequired, accepts: picked });
429
+ };
430
+ return client;
431
+ }
432
+
405
433
  export default Agent402;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent402-client",
3
- "version": "0.6.10",
3
+ "version": "0.6.11",
4
4
  "description": "Agent402 buyer SDK: resolve a task to a tool across 500+ pay-per-call endpoints and call it with payment handled - free via proof-of-work, or over x402 or MPP (a stock mppx fetch works) with a wallet you keep; the buy side of Agentic Finance. Caching, idempotent retries (Idempotency-Key), non-custodial, zero dependencies.",
5
5
  "type": "module",
6
6
  "main": "index.js",