x402-safe-fetch 0.5.0 → 0.7.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 +22 -5
- package/index.d.ts +12 -2
- package/index.js +69 -14
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A free endpoint is answered as is. For a paid one (HTTP 402), your agent first p
|
|
|
10
10
|
| `caution` | `onCaution`: `"stop"` (default, throws), `"pay"`, or your own function (e.g. ask the user) |
|
|
11
11
|
| `no_go` | Throws `SafePayError`; the endpoint is not paid |
|
|
12
12
|
|
|
13
|
-
The preflight reads the endpoint's 402 challenge and checks, among others, the price against your budget and against what the service advertises, whether the option is payable on your network (USDC, a valid payout address, a Solana payout account that exists), HTTPS, and whether the endpoint is listed in the CDP Bazaar. A verdict is reused
|
|
13
|
+
The preflight reads the endpoint's 402 challenge and checks, among others, the price against your budget and against what the service advertises, whether the option is payable on your network (USDC, a valid payout address, a Solana payout account that exists, an Algorand payout opted in to USDC), whether the payout address is on the OFAC SDN sanctions list (then `no_go`: never paid), HTTPS, and whether the endpoint is listed in the CDP Bazaar. A verdict is reused while the endpoint's 402 offers the same thing (up to an hour); a changed price, payout address, token or network is checked again right away. Hosts you already trust skip it.
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
@@ -45,17 +45,34 @@ try {
|
|
|
45
45
|
|
|
46
46
|
Solana works the same way: `network: "solana"` and register an `ExactSvmScheme` from `@x402/svm/exact/client` with a `@solana/kit` signer.
|
|
47
47
|
|
|
48
|
+
Algorand and the XRP Ledger work the same way, and only their dollar stablecoin is ever paid. On Algorand that is USDC (ASA 31566704), never ALGO or another ASA. On the XRP Ledger it is RLUSD from Ripple's issuer, never XRP or a look-alike token. RLUSD prices are decimal dollars, so the budget is checked in dollars. The Doctor preflight is paid on the same network.
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { toClientAvmSigner } from "@x402/avm";
|
|
52
|
+
import { ExactAvmScheme } from "@x402/avm/exact/client";
|
|
53
|
+
|
|
54
|
+
const safeFetch = createSafeFetch({
|
|
55
|
+
network: "algorand", // your account must be opted in to USDC
|
|
56
|
+
register: (client) => client.register("algorand:*", new ExactAvmScheme(toClientAvmSigner(process.env.AVM_PRIVATE_KEY))),
|
|
57
|
+
});
|
|
58
|
+
// XRP Ledger: network: "xrpl" and an ExactXrplScheme from @x402/xrpl/exact/client
|
|
59
|
+
// (createXrplWalletSigner(Wallet.fromSeed(process.env.XRPL_SEED))); needs an RLUSD trust line.
|
|
60
|
+
// Stellar: network: "stellar" and an ExactStellarScheme from @x402/stellar/exact/client
|
|
61
|
+
// (createEd25519Signer(process.env.STELLAR_SECRET, "stellar:pubnet")); needs a USDC trustline.
|
|
62
|
+
// Only Circle's USDC contract is paid, never XLM; the facilitator pays the network fee.
|
|
63
|
+
```
|
|
64
|
+
|
|
48
65
|
## Options
|
|
49
66
|
|
|
50
67
|
| Option | Default | |
|
|
51
68
|
|---|---|---|
|
|
52
69
|
| `register` | required | `(client) => client.register(network, scheme)`: your payment schemes; your keys stay in your code |
|
|
53
|
-
| `network` | `"base"` | `"base"`, `"solana"` or a CAIP-2 id; the preflight checks the option on this network |
|
|
70
|
+
| `network` | `"base"` | `"base"`, `"solana"`, `"algorand"` (USDC), `"xrpl"` (RLUSD), their `-testnet` forms, or a CAIP-2 id; the preflight checks the option on this network |
|
|
54
71
|
| `maxUsd` | `0.05` | Budget per endpoint call; the payment is capped at it and the preflight says `no_go` above it |
|
|
55
72
|
| `onCaution` | `"stop"` | `"stop"`, `"pay"` or `async (preflight) => boolean` |
|
|
56
73
|
| `trusted` | `[]` | Hosts paid without a preflight |
|
|
57
74
|
| `onPreflight` | | `(preflight, { url, method, cached }) => void`, e.g. for logging |
|
|
58
|
-
| `cacheMs` |
|
|
75
|
+
| `cacheMs` | 1 hour | How long a verdict is reused per method and URL while the 402 offers the same thing (at most 10 minutes when the offer can't be read); any change in price, payout address, token or network means a new preflight |
|
|
59
76
|
| `verifyReceipts` | `"require"` | Check Doctor's signed receipt on every preflight; `"off"` skips it |
|
|
60
77
|
| `doctorSigners` | Doctor's published signer | Accepted signer addresses (for a self-hosted Doctor) |
|
|
61
78
|
| `diagnoseOnFailure` | `false` | When a payment still fails, buy a $0.01 Doctor diagnosis of why (see below) |
|
|
@@ -111,8 +128,8 @@ x402 Doctor signs every paid preflight (EIP-191 over canonical JSON, with the re
|
|
|
111
128
|
|
|
112
129
|
## Costs and limits
|
|
113
130
|
|
|
114
|
-
- $0.001 per preflight (once per endpoint per
|
|
115
|
-
- With `diagnoseOnFailure`: $0.01 per diagnosis, only when a payment fails (once per endpoint per
|
|
131
|
+
- $0.001 per preflight (once per endpoint per hour while its offer stays the same, again at once when it changes), plus the endpoint's own price.
|
|
132
|
+
- With `diagnoseOnFailure`: $0.01 per diagnosis, only when a payment fails (once per endpoint per `cacheMs`).
|
|
116
133
|
- Bodies must be strings, Buffers or `URLSearchParams`: the request is sent once unpaid (to see the 402) and once paid.
|
|
117
134
|
- If Doctor is unreachable, nothing is paid (`SafePayError` with code `preflight_failed`).
|
|
118
135
|
- The preflight checks whether a payment can succeed and is sensible; it does not guarantee what the service delivers after payment.
|
package/index.d.ts
CHANGED
|
@@ -6,6 +6,16 @@ export declare const DIAGNOSE_CAP: string;
|
|
|
6
6
|
export declare const VERSION: string;
|
|
7
7
|
export declare const BASE: "eip155:8453";
|
|
8
8
|
export declare const SOLANA: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
9
|
+
export declare const ALGORAND: "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=";
|
|
10
|
+
export declare const ALGORAND_TESTNET: "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=";
|
|
11
|
+
export declare const XRPL: "xrpl:0";
|
|
12
|
+
export declare const XRPL_TESTNET: "xrpl:1";
|
|
13
|
+
export declare const STELLAR: "stellar:pubnet";
|
|
14
|
+
export declare const STELLAR_TESTNET: "stellar:testnet";
|
|
15
|
+
/** The option paid on `network`: on Algorand only USDC, on Stellar only Circle's USDC contract within maxUsd, on the XRP Ledger only RLUSD from Ripple's issuer within maxUsd (in dollars); null when there is none. */
|
|
16
|
+
/** What a 402 offers (per x402 option: scheme, network, asset, amount, payTo) as a stable string; null without a readable x402 challenge. Consumes the body. */
|
|
17
|
+
export declare function offerFingerprint(res: Response): Promise<string | null>;
|
|
18
|
+
export declare function payableOption<A extends { network: string; asset?: unknown; amount?: unknown; extra?: Record<string, unknown> }>(accepts: A[], network: string, maxUsd: number | string): A | null;
|
|
9
19
|
|
|
10
20
|
/** The x402 Doctor preflight: see https://x402-doctor.fizzl.eu/openapi.json */
|
|
11
21
|
export interface Preflight {
|
|
@@ -34,7 +44,7 @@ export declare class SafePayError extends Error {
|
|
|
34
44
|
export interface SafeFetchOptions {
|
|
35
45
|
/** Registers your payment schemes, e.g. (c) => c.register("eip155:8453", new ExactEvmScheme(account)). */
|
|
36
46
|
register: (client: x402Client) => unknown;
|
|
37
|
-
/** The network you pay on: "base", "solana" or a CAIP-2 id. Default Base. */
|
|
47
|
+
/** The network you pay on: "base", "solana", "algorand" (USDC), "xrpl" (RLUSD), "stellar" (USDC), their "-testnet" forms, or a CAIP-2 id. Default Base. */
|
|
38
48
|
network?: string;
|
|
39
49
|
/** Budget per endpoint call in USD. Default 0.05. */
|
|
40
50
|
maxUsd?: number | string;
|
|
@@ -43,7 +53,7 @@ export interface SafeFetchOptions {
|
|
|
43
53
|
/** Hosts you already trust: paid without a preflight. */
|
|
44
54
|
trusted?: string[];
|
|
45
55
|
onPreflight?: (preflight: Preflight, info: { url: string; method: string; cached: boolean }) => void;
|
|
46
|
-
/** How long a verdict is reused, in ms. Default 10 minutes. */
|
|
56
|
+
/** How long a verdict is reused while the endpoint's 402 offers the same thing, in ms. Default 1 hour; a changed price, payout address, token or network is checked again at once; at most 10 minutes when the offer can't be read. */
|
|
47
57
|
cacheMs?: number;
|
|
48
58
|
doctorUrl?: string;
|
|
49
59
|
/** Check Doctor's signed receipt on every preflight (signer, and bound to this request). Default "require". */
|
package/index.js
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
// caution → onCaution: "stop" (default, throws), "pay", or your own async
|
|
9
9
|
// function that decides (e.g. ask the user)
|
|
10
10
|
// go → pays the endpoint, never more than maxUsd
|
|
11
|
-
// Trusted hosts skip the preflight
|
|
11
|
+
// Trusted hosts skip the preflight. A verdict is reused while the endpoint's 402 offers the same thing
|
|
12
|
+
// (up to an hour); a changed price, payout address, token or network is checked again at once.
|
|
12
13
|
// With diagnoseOnFailure, a payment that still fails (the endpoint answers 402
|
|
13
14
|
// again, or paying throws) gets a $0.01 Doctor diagnosis that says why and how
|
|
14
15
|
// to fix it: onDiagnosis(report), diagnosisOf(response) or error.diagnosis.
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
//
|
|
23
24
|
// Payments use @x402/fetch with the schemes you register (your keys stay in
|
|
24
25
|
// your code): register: (client) => client.register("eip155:8453", new ExactEvmScheme(account))
|
|
26
|
+
// On Algorand (USDC), the XRP Ledger (RLUSD) and Stellar (USDC) only the dollar stablecoin is paid.
|
|
25
27
|
|
|
26
28
|
import { wrapFetchWithPayment, x402Client, decodePaymentResponseHeader } from "@x402/fetch";
|
|
27
29
|
import { verifyReceipt, DOCTOR_SIGNERS, AUTHORITY } from "./receipt.js";
|
|
@@ -31,12 +33,62 @@ export { verifyReceipt, recoverSigner, canonicalJson, inputHash, certMessage, DO
|
|
|
31
33
|
export const DOCTOR_URL = "https://x402-doctor.fizzl.eu";
|
|
32
34
|
export const PREFLIGHT_CAP = "$0.002"; // the preflight costs $0.001; never more than twice that
|
|
33
35
|
export const DIAGNOSE_CAP = "$0.02"; // the diagnosis costs $0.01; never more than twice that
|
|
34
|
-
export const VERSION = "0.
|
|
36
|
+
export const VERSION = "0.7.0";
|
|
35
37
|
// Doctor sees which calls come from this package (in its usage counts), nothing more.
|
|
36
38
|
const DOCTOR_HEADERS = { accept: "application/json", "user-agent": `x402-safe-fetch/${VERSION}` };
|
|
37
39
|
export const BASE = "eip155:8453";
|
|
38
40
|
export const SOLANA = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
39
|
-
const
|
|
41
|
+
export const ALGORAND = "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=";
|
|
42
|
+
export const ALGORAND_TESTNET = "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=";
|
|
43
|
+
export const XRPL = "xrpl:0";
|
|
44
|
+
export const XRPL_TESTNET = "xrpl:1";
|
|
45
|
+
export const STELLAR = "stellar:pubnet";
|
|
46
|
+
export const STELLAR_TESTNET = "stellar:testnet";
|
|
47
|
+
const NETWORK_ALIASES = { base: BASE, solana: SOLANA, algorand: ALGORAND, "algorand-testnet": ALGORAND_TESTNET, xrpl: XRPL, "xrpl-testnet": XRPL_TESTNET, stellar: STELLAR, "stellar-testnet": STELLAR_TESTNET };
|
|
48
|
+
|
|
49
|
+
// On Algorand and the XRP Ledger only the dollar stablecoin is paid: USDC (an ASA) on Algorand, RLUSD from
|
|
50
|
+
// Ripple's issuer on the XRP Ledger. Never ALGO, XRP or another token, so the dollar budget always holds.
|
|
51
|
+
const ALGORAND_USDC = { [ALGORAND]: "31566704", [ALGORAND_TESTNET]: "10458941" };
|
|
52
|
+
const RLUSD_HEX = "524C555344000000000000000000000000000000";
|
|
53
|
+
const RLUSD_ISSUER = { [XRPL]: "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De", [XRPL_TESTNET]: "rQhWct2fv4Vc4KRjRgMrxa8xPN9Zx9iLKV" };
|
|
54
|
+
// On Stellar only Circle's USDC token contract (7 decimals), never XLM or another token named USDC.
|
|
55
|
+
const STELLAR_USDC = { [STELLAR]: "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75", [STELLAR_TESTNET]: "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" };
|
|
56
|
+
|
|
57
|
+
// The option to pay on `network`, or null. RLUSD prices are decimal dollars ("0.001", and "2" is two dollars),
|
|
58
|
+
// which x402's spend controls would read as base units, so the budget is checked here in dollars.
|
|
59
|
+
// What a 402 offers, as a stable string: per x402 option its scheme, network, asset, amount and payout address
|
|
60
|
+
// (not extra: invoices and nonces change per request). null when there is no x402 challenge to read (e.g. an
|
|
61
|
+
// MPP-only 402). Reads and consumes the response body.
|
|
62
|
+
export async function offerFingerprint(res) {
|
|
63
|
+
let challenge = null;
|
|
64
|
+
const header = res?.headers?.get?.("payment-required");
|
|
65
|
+
if (header) {
|
|
66
|
+
try { challenge = JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(header), (c) => c.charCodeAt(0)))); } catch { /* not base64 JSON */ }
|
|
67
|
+
try { await res.body?.cancel(); } catch { /* already consumed */ }
|
|
68
|
+
} else {
|
|
69
|
+
try { challenge = JSON.parse(await res.text()); } catch { /* not JSON */ }
|
|
70
|
+
}
|
|
71
|
+
if (!Array.isArray(challenge?.accepts)) return null;
|
|
72
|
+
const parts = challenge.accepts.map((a) => JSON.stringify([a?.scheme ?? null, a?.network ?? null, String(a?.asset ?? ""), String(a?.amount ?? a?.maxAmountRequired ?? ""), String(a?.payTo ?? "")]));
|
|
73
|
+
return JSON.stringify(parts.sort());
|
|
74
|
+
}
|
|
75
|
+
// Without an offer to compare (no readable x402 challenge), a verdict is reused for at most 10 minutes.
|
|
76
|
+
const UNREAD_OFFER_MS = 10 * 60 * 1000;
|
|
77
|
+
|
|
78
|
+
export function payableOption(accepts, network, maxUsd) {
|
|
79
|
+
const cap = Number(String(maxUsd).replace(/^\$/, ""));
|
|
80
|
+
const on = (accepts ?? []).filter((a) => a?.network === network);
|
|
81
|
+
if (ALGORAND_USDC[network]) return on.find((a) => String(a.asset) === ALGORAND_USDC[network]) ?? null;
|
|
82
|
+
// x402's spend controls cap Stellar USDC too; the budget is checked here as well, in dollars.
|
|
83
|
+
if (STELLAR_USDC[network]) {
|
|
84
|
+
return on.find((a) => a.asset === STELLAR_USDC[network] && /^\d+$/.test(String(a.amount)) && Number(a.amount) > 0 && Number(a.amount) / 1e7 <= cap) ?? null;
|
|
85
|
+
}
|
|
86
|
+
if (RLUSD_ISSUER[network]) {
|
|
87
|
+
return on.find((a) => String(a.asset ?? "").toUpperCase() === RLUSD_HEX && a.extra?.issuer === RLUSD_ISSUER[network]
|
|
88
|
+
&& /^\d+(\.\d+)?$/.test(String(a.amount)) && Number(a.amount) > 0 && Number(a.amount) <= cap) ?? null;
|
|
89
|
+
}
|
|
90
|
+
return on[0] ?? null;
|
|
91
|
+
}
|
|
40
92
|
|
|
41
93
|
export class SafePayError extends Error {
|
|
42
94
|
/** code: "no_go" | "caution" | "preflight_failed" | "bad_receipt" | "no_option" */
|
|
@@ -107,12 +159,12 @@ function requestOf(input, init) {
|
|
|
107
159
|
/**
|
|
108
160
|
* @param {object} options
|
|
109
161
|
* @param {(client: x402Client) => unknown} options.register registers your payment schemes on a client
|
|
110
|
-
* @param {string} [options.network] the network you pay on: "base", "solana" or a CAIP-2 id (default Base)
|
|
162
|
+
* @param {string} [options.network] the network you pay on: "base", "solana", "algorand", "xrpl", "stellar" or a CAIP-2 id (default Base)
|
|
111
163
|
* @param {number|string} [options.maxUsd] budget per endpoint call (default 0.05)
|
|
112
164
|
* @param {"stop"|"pay"|((preflight: object) => boolean|Promise<boolean>)} [options.onCaution]
|
|
113
165
|
* @param {string[]} [options.trusted] hosts you already trust: paid without a preflight
|
|
114
166
|
* @param {(preflight: object, info: {url: string, method: string, cached: boolean}) => void} [options.onPreflight]
|
|
115
|
-
* @param {number} [options.cacheMs] how long a verdict is reused (default 10 minutes)
|
|
167
|
+
* @param {number} [options.cacheMs] how long a verdict is reused while the 402 offers the same thing (default 1 hour; at most 10 minutes when the offer can't be read)
|
|
116
168
|
* @param {string} [options.doctorUrl]
|
|
117
169
|
* @param {"require"|"off"} [options.verifyReceipts] check Doctor's signature on every preflight (default "require")
|
|
118
170
|
* @param {string[]} [options.doctorSigners] accepted Doctor signer addresses (default: the published signer)
|
|
@@ -131,7 +183,7 @@ export function createSafeFetch({
|
|
|
131
183
|
onCaution = "stop",
|
|
132
184
|
trusted = [],
|
|
133
185
|
onPreflight,
|
|
134
|
-
cacheMs =
|
|
186
|
+
cacheMs = 60 * 60 * 1000,
|
|
135
187
|
doctorUrl = DOCTOR_URL,
|
|
136
188
|
verifyReceipts = "require",
|
|
137
189
|
doctorSigners = DOCTOR_SIGNERS,
|
|
@@ -156,8 +208,8 @@ export function createSafeFetch({
|
|
|
156
208
|
|
|
157
209
|
const makePayingFetch = createPayingFetch ?? ((cap) => {
|
|
158
210
|
const client = new x402Client((_version, accepts) => {
|
|
159
|
-
const pick = accepts
|
|
160
|
-
if (!pick) throw new SafePayError(`no payment option on ${payNetwork}`, { code: "no_option" });
|
|
211
|
+
const pick = payableOption(accepts, payNetwork, cap);
|
|
212
|
+
if (!pick) throw new SafePayError(`no payment option on ${payNetwork}${ALGORAND_USDC[payNetwork] ? " in USDC" : STELLAR_USDC[payNetwork] ? ` in USDC within ${cap}` : RLUSD_ISSUER[payNetwork] ? ` in RLUSD within ${cap}` : ""}`, { code: "no_option" });
|
|
161
213
|
return pick;
|
|
162
214
|
}).setSpendControls({ maxAmountPerPayment: cap });
|
|
163
215
|
register(client);
|
|
@@ -171,10 +223,11 @@ export function createSafeFetch({
|
|
|
171
223
|
const payEndpoint = (...args) => (endpointFetch ??= makePayingFetch(budget))(...args);
|
|
172
224
|
|
|
173
225
|
const verdicts = new Map();
|
|
174
|
-
async function preflightFor(url, method) {
|
|
226
|
+
async function preflightFor(url, method, offer) {
|
|
175
227
|
const key = `${method} ${url}`;
|
|
176
228
|
const hit = verdicts.get(key);
|
|
177
|
-
|
|
229
|
+
const ttl = offer === null ? Math.min(cacheMs, UNREAD_OFFER_MS) : cacheMs;
|
|
230
|
+
if (hit && hit.offer === offer && hit.at + ttl > now()) return { preflight: hit.preflight, cached: true };
|
|
178
231
|
const pfUrl = preflightUrl(url, { method, maxUsd: budget, network: payNetwork, doctorUrl });
|
|
179
232
|
const res = await payPreflight(pfUrl, { headers: DOCTOR_HEADERS });
|
|
180
233
|
const preflight = await res.json().catch(() => null);
|
|
@@ -187,7 +240,7 @@ export function createSafeFetch({
|
|
|
187
240
|
const check = verifyReceipt(preflight, { signers: doctorSigners, route: "GET /api/v1/preflight", input, authority, service: "x402-doctor" });
|
|
188
241
|
if (!check.valid) throw new SafePayError(`preflight not trusted (${check.reason}); the endpoint was not paid`, { code: "bad_receipt", preflight, url });
|
|
189
242
|
}
|
|
190
|
-
verdicts.set(key, { preflight,
|
|
243
|
+
verdicts.set(key, { preflight, offer, at: now() });
|
|
191
244
|
if (verdicts.size > 1000) verdicts.delete(verdicts.keys().next().value);
|
|
192
245
|
return { preflight, cached: false };
|
|
193
246
|
}
|
|
@@ -265,11 +318,13 @@ export function createSafeFetch({
|
|
|
265
318
|
const { url, method } = requestOf(input, init);
|
|
266
319
|
const probe = await baseFetch(url, init);
|
|
267
320
|
if (probe.status !== 402) return probe;
|
|
268
|
-
try { await probe.body?.cancel(); } catch { /* already consumed */ }
|
|
269
321
|
|
|
270
|
-
if (trustedHosts.has(hostOf(url)))
|
|
322
|
+
if (trustedHosts.has(hostOf(url))) {
|
|
323
|
+
try { await probe.body?.cancel(); } catch { /* already consumed */ }
|
|
324
|
+
return payAndCheck(url, init, method);
|
|
325
|
+
}
|
|
271
326
|
|
|
272
|
-
const { preflight, cached } = await preflightFor(url, method);
|
|
327
|
+
const { preflight, cached } = await preflightFor(url, method, await offerFingerprint(probe));
|
|
273
328
|
const payAfterPreflight = async () => {
|
|
274
329
|
const res = await payAndCheck(url, init, method);
|
|
275
330
|
reportOutcome(url, method, preflight, res);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x402-safe-fetch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A fetch for AI agents that checks an unknown x402 endpoint ($0.001 x402 Doctor preflight) before paying it, and never pays above your budget.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -28,8 +28,12 @@
|
|
|
28
28
|
"@x402/fetch": "^2.27.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
+
"@algorandfoundation/algokit-utils": "^10.0.0-alpha.46",
|
|
32
|
+
"@x402/avm": "^2.28.0",
|
|
31
33
|
"@x402/evm": "^2.27.0",
|
|
32
34
|
"@x402/fetch": "^2.27.0",
|
|
35
|
+
"@x402/stellar": "^2.28.0",
|
|
36
|
+
"@x402/xrpl": "^2.28.0",
|
|
33
37
|
"viem": "^2.56.9"
|
|
34
38
|
},
|
|
35
39
|
"keywords": [
|
|
@@ -41,7 +45,11 @@
|
|
|
41
45
|
"usdc",
|
|
42
46
|
"base",
|
|
43
47
|
"solana",
|
|
44
|
-
"
|
|
48
|
+
"algorand",
|
|
49
|
+
"xrpl",
|
|
50
|
+
"rlusd",
|
|
51
|
+
"signed-receipts",
|
|
52
|
+
"stellar"
|
|
45
53
|
],
|
|
46
54
|
"repository": {
|
|
47
55
|
"type": "git",
|