yeetful 0.1.0 → 0.2.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/CHANGELOG.md +17 -0
- package/README.md +49 -11
- package/dist/agent.cjs +258 -0
- package/dist/agent.cjs.map +1 -0
- package/dist/agent.d.cts +97 -0
- package/dist/agent.d.ts +97 -0
- package/dist/agent.js +255 -0
- package/dist/agent.js.map +1 -0
- package/dist/index.cjs +112 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +111 -1
- package/dist/index.js.map +1 -1
- package/package.json +13 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
- **New: `yeetful/agent` — the agent expense account.** `yeetful({ wallet, grant })`
|
|
6
|
+
returns a grant-aware paid `fetch` that enforces an allowlist + per-call/per-day/
|
|
7
|
+
lifetime USD caps + expiry **before** signing any x402 payment, pays via the
|
|
8
|
+
existing client, and emits a `Receipt` per call. Throws a typed `GrantError`
|
|
9
|
+
(`NOT_ALLOWED` / `OVER_PER_CALL` / `BUDGET_EXCEEDED` / `EXPIRED` / `REVOKED`) and
|
|
10
|
+
exposes `spentTodayUsd()` / `remainingTodayUsd()` / `spentTotalUsd()`.
|
|
11
|
+
- Repositioned the package around spend-controlled x402 for AI agents; the
|
|
12
|
+
existing `client` / `server` / `next` / `express` entries are unchanged.
|
|
13
|
+
|
|
14
|
+
## 0.1.0
|
|
15
|
+
|
|
16
|
+
- Initial release: drop-in x402 client + server (`gate`/`withPayment`/
|
|
17
|
+
`paymentRequired`) + facilitator helpers.
|
package/README.md
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
# yeetful
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Spend-controlled [x402](https://www.x402.org) for AI agents.** Give an agent an *expense account* — an allowlist of endpoints plus per-call / per-day budgets — and let it pay any x402 service with no API keys. Enforcement is local and instant; every call emits a receipt. Built for [Yeetful](https://yeetful.com), MIT-licensed, works anywhere TypeScript does.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install yeetful viem
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
// Server — gate a route for 1¢ USDC
|
|
11
|
-
import { withPayment } from 'yeetful/next'
|
|
9
|
+
## Agent expense account
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
{ price: '0.01', recipient: '0xYourAddress', network: 'base' },
|
|
15
|
-
async () => Response.json({ secret: 'gm' })
|
|
16
|
-
)
|
|
17
|
-
```
|
|
11
|
+
Wrap your agent's calls in one grant-aware `pay()`. It refuses anything off the allowlist or over budget **before** signing a payment — your guardrail against runaway loops, bugs, and prompt-injected tool calls.
|
|
18
12
|
|
|
19
13
|
```ts
|
|
20
|
-
|
|
21
|
-
import { createPaymentClient } from 'yeetful/client'
|
|
14
|
+
import { yeetful, GrantError } from 'yeetful/agent'
|
|
22
15
|
import { createWalletClient, http } from 'viem'
|
|
23
16
|
import { base } from 'viem/chains'
|
|
24
17
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
@@ -29,6 +22,51 @@ const wallet = createWalletClient({
|
|
|
29
22
|
transport: http(),
|
|
30
23
|
})
|
|
31
24
|
|
|
25
|
+
const pay = yeetful({
|
|
26
|
+
wallet,
|
|
27
|
+
grant: {
|
|
28
|
+
allow: ['tripadvisor.x402.paysponge.com', 'anthropic.yeetful.com'],
|
|
29
|
+
perCallUsd: 0.05,
|
|
30
|
+
perDayUsd: 2,
|
|
31
|
+
expiresAt: '2026-12-31',
|
|
32
|
+
},
|
|
33
|
+
onReceipt: (r) => console.log(r.host, `$${r.amountUsd}`, r.txHash ?? r.note),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const res = await pay('https://tripadvisor.x402.paysponge.com/api/v1/location/search?searchQuery=tokyo')
|
|
38
|
+
console.log(await res.json())
|
|
39
|
+
console.log(`spent today: $${pay.spentTodayUsd()} / left: $${pay.remainingTodayUsd()}`)
|
|
40
|
+
} catch (e) {
|
|
41
|
+
// GrantError.code: NOT_ALLOWED | OVER_PER_CALL | BUDGET_EXCEEDED | EXPIRED | REVOKED
|
|
42
|
+
if (e instanceof GrantError) console.error(`blocked: ${e.code}`)
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
One grant authorizes **many** endpoints (the allowlist). Use `onReceipt` to stream the audit trail to your dashboard or the Yeetful control plane.
|
|
47
|
+
|
|
48
|
+
> **Local vs. hard enforcement.** This SDK enforces the grant in-process — ideal for governing *your own* agents (runaway loops, bugs, injected tool calls). For adversarial guarantees, back the grant with an on-chain Coinbase **Spend Permission** so the wallet contract caps spend regardless of the SDK.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Low-level x402 primitives
|
|
53
|
+
|
|
54
|
+
The agent wrapper is built on a full x402 toolkit you can use directly:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// Server — gate a route for 1¢ USDC
|
|
58
|
+
import { withPayment } from 'yeetful/next'
|
|
59
|
+
|
|
60
|
+
export const GET = withPayment(
|
|
61
|
+
{ price: '0.01', recipient: '0xYourAddress', network: 'base' },
|
|
62
|
+
async () => Response.json({ secret: 'gm' })
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// Client — auto-pay when a server returns 402 (no grant enforcement)
|
|
68
|
+
import { createPaymentClient } from 'yeetful/client'
|
|
69
|
+
|
|
32
70
|
const pay = createPaymentClient({ wallet })
|
|
33
71
|
const res = await pay('https://api.example.com/premium')
|
|
34
72
|
console.log(await res.json()) // → { secret: 'gm' }
|
package/dist/agent.cjs
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/utils.ts
|
|
4
|
+
var utf8Encoder = new TextEncoder();
|
|
5
|
+
var utf8Decoder = new TextDecoder();
|
|
6
|
+
function encodePayment(value) {
|
|
7
|
+
const bytes = utf8Encoder.encode(JSON.stringify(value));
|
|
8
|
+
if (typeof Buffer !== "undefined") {
|
|
9
|
+
return Buffer.from(bytes).toString("base64");
|
|
10
|
+
}
|
|
11
|
+
let binary = "";
|
|
12
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
13
|
+
return btoa(binary);
|
|
14
|
+
}
|
|
15
|
+
function decodePayment(b64) {
|
|
16
|
+
let bytes;
|
|
17
|
+
if (typeof Buffer !== "undefined") {
|
|
18
|
+
bytes = new Uint8Array(Buffer.from(b64, "base64"));
|
|
19
|
+
} else {
|
|
20
|
+
const binary = atob(b64);
|
|
21
|
+
bytes = new Uint8Array(binary.length);
|
|
22
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
23
|
+
}
|
|
24
|
+
return JSON.parse(utf8Decoder.decode(bytes));
|
|
25
|
+
}
|
|
26
|
+
function randomNonce() {
|
|
27
|
+
const bytes = new Uint8Array(32);
|
|
28
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
29
|
+
return "0x" + Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/client.ts
|
|
33
|
+
function createPaymentClient(options) {
|
|
34
|
+
const baseFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
35
|
+
return async function payFetch(input, init = {}) {
|
|
36
|
+
const first = await baseFetch(input, init);
|
|
37
|
+
if (first.status !== 402) return first;
|
|
38
|
+
const requirements = await parsePaymentRequired(first);
|
|
39
|
+
const requirement = selectRequirement(requirements.accepts, options);
|
|
40
|
+
if (!requirement) {
|
|
41
|
+
throw new PaymentError("No acceptable payment requirement matched client constraints", requirements);
|
|
42
|
+
}
|
|
43
|
+
if (options.onPaymentRequired) {
|
|
44
|
+
const approved = await options.onPaymentRequired(requirement);
|
|
45
|
+
if (!approved) throw new PaymentError("Payment rejected by user", requirements);
|
|
46
|
+
}
|
|
47
|
+
const payment = await signPayment(options.wallet, requirement);
|
|
48
|
+
const headers = new Headers(init.headers);
|
|
49
|
+
headers.set("X-PAYMENT", encodePayment(payment));
|
|
50
|
+
return baseFetch(input, { ...init, headers });
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
var PaymentError = class extends Error {
|
|
54
|
+
requirements;
|
|
55
|
+
constructor(message, requirements) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "PaymentError";
|
|
58
|
+
this.requirements = requirements;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
async function parsePaymentRequired(res) {
|
|
62
|
+
try {
|
|
63
|
+
return await res.clone().json();
|
|
64
|
+
} catch {
|
|
65
|
+
throw new PaymentError("402 response did not contain a valid x402 discovery body");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function selectRequirement(accepts, opts) {
|
|
69
|
+
const filtered = accepts.filter((a) => a.scheme === "exact").filter((a) => !opts.allowedNetworks || opts.allowedNetworks.includes(a.network)).filter((a) => !opts.maxAmountAtomic || BigInt(a.maxAmountRequired) <= opts.maxAmountAtomic);
|
|
70
|
+
return filtered.sort(
|
|
71
|
+
(a, b) => BigInt(a.maxAmountRequired) < BigInt(b.maxAmountRequired) ? -1 : 1
|
|
72
|
+
)[0];
|
|
73
|
+
}
|
|
74
|
+
async function signPayment(wallet, requirement) {
|
|
75
|
+
const account = wallet.account;
|
|
76
|
+
if (!account) throw new PaymentError("Wallet has no account attached");
|
|
77
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
78
|
+
const validAfter = BigInt(now - 60);
|
|
79
|
+
const validBefore = BigInt(now + (requirement.maxTimeoutSeconds ?? 600));
|
|
80
|
+
const nonce = randomNonce();
|
|
81
|
+
const tokenName = requirement.extra?.name ?? "USD Coin";
|
|
82
|
+
const tokenVersion = requirement.extra?.version ?? "2";
|
|
83
|
+
const signature = await wallet.signTypedData({
|
|
84
|
+
account,
|
|
85
|
+
domain: {
|
|
86
|
+
name: tokenName,
|
|
87
|
+
version: tokenVersion,
|
|
88
|
+
chainId: chainIdForNetwork(requirement.network),
|
|
89
|
+
verifyingContract: requirement.asset
|
|
90
|
+
},
|
|
91
|
+
types: {
|
|
92
|
+
TransferWithAuthorization: [
|
|
93
|
+
{ name: "from", type: "address" },
|
|
94
|
+
{ name: "to", type: "address" },
|
|
95
|
+
{ name: "value", type: "uint256" },
|
|
96
|
+
{ name: "validAfter", type: "uint256" },
|
|
97
|
+
{ name: "validBefore", type: "uint256" },
|
|
98
|
+
{ name: "nonce", type: "bytes32" }
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
primaryType: "TransferWithAuthorization",
|
|
102
|
+
message: {
|
|
103
|
+
from: account.address,
|
|
104
|
+
to: requirement.payTo,
|
|
105
|
+
value: BigInt(requirement.maxAmountRequired),
|
|
106
|
+
validAfter,
|
|
107
|
+
validBefore,
|
|
108
|
+
nonce
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
x402Version: 1,
|
|
113
|
+
scheme: "exact",
|
|
114
|
+
network: requirement.network,
|
|
115
|
+
payload: {
|
|
116
|
+
signature,
|
|
117
|
+
authorization: {
|
|
118
|
+
from: account.address,
|
|
119
|
+
to: requirement.payTo,
|
|
120
|
+
value: requirement.maxAmountRequired,
|
|
121
|
+
validAfter: validAfter.toString(),
|
|
122
|
+
validBefore: validBefore.toString(),
|
|
123
|
+
nonce
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function chainIdForNetwork(network) {
|
|
129
|
+
switch (network) {
|
|
130
|
+
case "base":
|
|
131
|
+
return 8453;
|
|
132
|
+
case "base-sepolia":
|
|
133
|
+
return 84532;
|
|
134
|
+
case "ethereum":
|
|
135
|
+
return 1;
|
|
136
|
+
case "optimism":
|
|
137
|
+
return 10;
|
|
138
|
+
case "arbitrum":
|
|
139
|
+
return 42161;
|
|
140
|
+
case "polygon":
|
|
141
|
+
return 137;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/agent.ts
|
|
146
|
+
var GrantError = class extends Error {
|
|
147
|
+
constructor(code, message) {
|
|
148
|
+
super(message);
|
|
149
|
+
this.code = code;
|
|
150
|
+
this.name = "GrantError";
|
|
151
|
+
}
|
|
152
|
+
code;
|
|
153
|
+
};
|
|
154
|
+
function expiryMs(expiresAt) {
|
|
155
|
+
if (expiresAt == null) return Infinity;
|
|
156
|
+
if (expiresAt instanceof Date) return expiresAt.getTime();
|
|
157
|
+
if (typeof expiresAt === "number") return expiresAt;
|
|
158
|
+
const t = new Date(expiresAt).getTime();
|
|
159
|
+
return Number.isNaN(t) ? Infinity : t;
|
|
160
|
+
}
|
|
161
|
+
function utcDayIndex(ms) {
|
|
162
|
+
return Math.floor(ms / 864e5);
|
|
163
|
+
}
|
|
164
|
+
function hostOf(input) {
|
|
165
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
166
|
+
try {
|
|
167
|
+
return new URL(url).host.toLowerCase();
|
|
168
|
+
} catch {
|
|
169
|
+
return "";
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function txHashOf(res) {
|
|
173
|
+
const header = res.headers.get("x-payment-response");
|
|
174
|
+
if (!header) return void 0;
|
|
175
|
+
try {
|
|
176
|
+
return decodePayment(header).transaction;
|
|
177
|
+
} catch {
|
|
178
|
+
return void 0;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function yeetful(options) {
|
|
182
|
+
const { wallet, grant, onReceipt, onEvent } = options;
|
|
183
|
+
const log = onEvent ?? (() => {
|
|
184
|
+
});
|
|
185
|
+
let spentToday = 0;
|
|
186
|
+
let spentTotal = 0;
|
|
187
|
+
let dayIndex = utcDayIndex(Date.now());
|
|
188
|
+
const emit = (r) => {
|
|
189
|
+
void Promise.resolve(onReceipt?.(r)).catch(() => {
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
const deny = (host, code, msg) => {
|
|
193
|
+
emit({ host, amountUsd: 0, ok: false, note: code, ts: Date.now() });
|
|
194
|
+
log(`\u2717 ${host} \u2014 ${code}: ${msg}`);
|
|
195
|
+
throw new GrantError(code, msg);
|
|
196
|
+
};
|
|
197
|
+
const pay = async function pay2(input, init = {}) {
|
|
198
|
+
const today = utcDayIndex(Date.now());
|
|
199
|
+
if (today !== dayIndex) {
|
|
200
|
+
dayIndex = today;
|
|
201
|
+
spentToday = 0;
|
|
202
|
+
}
|
|
203
|
+
const host = hostOf(input);
|
|
204
|
+
if ((grant.status ?? "active") === "revoked") deny(host, "REVOKED", "grant is revoked");
|
|
205
|
+
if (Date.now() > expiryMs(grant.expiresAt)) deny(host, "EXPIRED", "grant has expired");
|
|
206
|
+
if (!grant.allow.map((h) => h.toLowerCase()).includes(host)) {
|
|
207
|
+
deny(host, "NOT_ALLOWED", `${host} is not in this grant's allowlist`);
|
|
208
|
+
}
|
|
209
|
+
let pricedUsd = 0;
|
|
210
|
+
const client = createPaymentClient({
|
|
211
|
+
wallet,
|
|
212
|
+
fetch: options.fetch,
|
|
213
|
+
allowedNetworks: options.allowedNetworks,
|
|
214
|
+
// Per-call enforcement lives in the hook (not maxAmountAtomic) so an
|
|
215
|
+
// over-cap call surfaces a clean GrantError instead of a filtered no-match.
|
|
216
|
+
onPaymentRequired: (req) => {
|
|
217
|
+
const price = Number(req.maxAmountRequired) / 1e6;
|
|
218
|
+
if (price > grant.perCallUsd) {
|
|
219
|
+
deny(host, "OVER_PER_CALL", `$${price.toFixed(4)} exceeds per-call cap $${grant.perCallUsd}`);
|
|
220
|
+
}
|
|
221
|
+
if (spentToday + price > grant.perDayUsd) {
|
|
222
|
+
deny(host, "BUDGET_EXCEEDED", `$${(spentToday + price).toFixed(2)} exceeds today's cap $${grant.perDayUsd}`);
|
|
223
|
+
}
|
|
224
|
+
if (grant.totalUsd != null && spentTotal + price > grant.totalUsd) {
|
|
225
|
+
deny(host, "BUDGET_EXCEEDED", `$${(spentTotal + price).toFixed(2)} exceeds lifetime cap $${grant.totalUsd}`);
|
|
226
|
+
}
|
|
227
|
+
pricedUsd = price;
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
let res;
|
|
232
|
+
try {
|
|
233
|
+
res = await client(input, init);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
if (err instanceof GrantError) throw err;
|
|
236
|
+
const note = err instanceof PaymentError ? "payment-failed" : "error";
|
|
237
|
+
emit({ host, amountUsd: 0, ok: false, note, ts: Date.now() });
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
240
|
+
if (pricedUsd > 0) {
|
|
241
|
+
spentToday += pricedUsd;
|
|
242
|
+
spentTotal += pricedUsd;
|
|
243
|
+
}
|
|
244
|
+
const txHash = txHashOf(res);
|
|
245
|
+
emit({ host, amountUsd: pricedUsd, ok: true, txHash, note: "settled", ts: Date.now() });
|
|
246
|
+
log(`\u2713 ${host} \u2014 $${pricedUsd.toFixed(4)} \xB7 today $${spentToday.toFixed(2)}/$${grant.perDayUsd}`);
|
|
247
|
+
return res;
|
|
248
|
+
};
|
|
249
|
+
pay.spentTodayUsd = () => spentToday;
|
|
250
|
+
pay.remainingTodayUsd = () => Math.max(0, grant.perDayUsd - spentToday);
|
|
251
|
+
pay.spentTotalUsd = () => spentTotal;
|
|
252
|
+
return pay;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
exports.GrantError = GrantError;
|
|
256
|
+
exports.yeetful = yeetful;
|
|
257
|
+
//# sourceMappingURL=agent.cjs.map
|
|
258
|
+
//# sourceMappingURL=agent.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/client.ts","../src/agent.ts"],"names":["pay"],"mappings":"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","file":"agent.cjs","sourcesContent":["import type { X402Network } from './types.js'\n\nconst USDC_BY_NETWORK: Record<X402Network, `0x${string}`> = {\n base: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'base-sepolia': '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n ethereum: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n optimism: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n arbitrum: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n polygon: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n}\n\nexport const USDC_DECIMALS = 6\n\n/** Returns the canonical USDC contract address for a supported network. */\nexport function usdcAddress(network: X402Network): `0x${string}` {\n return USDC_BY_NETWORK[network]\n}\n\n/**\n * Convert a human-friendly USD amount (e.g. \"0.01\") into atomic USDC units.\n * Fixed-point to avoid float drift — safer than Number math for payments.\n */\nexport function usdToAtomic(amount: string | number, decimals = USDC_DECIMALS): string {\n const str = typeof amount === 'number' ? amount.toString() : amount\n if (!/^\\d+(\\.\\d+)?$/.test(str)) {\n throw new Error(`Invalid amount: ${str}`)\n }\n const [whole, frac = ''] = str.split('.')\n const padded = frac.slice(0, decimals).padEnd(decimals, '0')\n return (BigInt(whole ?? '0') * 10n ** BigInt(decimals) + BigInt(padded || '0')).toString()\n}\n\nconst utf8Encoder = new TextEncoder()\nconst utf8Decoder = new TextDecoder()\n\n/** Base64 encode a JSON value — works in Node 18+ and browsers. */\nexport function encodePayment(value: unknown): string {\n const bytes = utf8Encoder.encode(JSON.stringify(value))\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64')\n }\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary)\n}\n\n/** Base64 decode a payment header value back into JSON. */\nexport function decodePayment<T = unknown>(b64: string): T {\n let bytes: Uint8Array\n if (typeof Buffer !== 'undefined') {\n bytes = new Uint8Array(Buffer.from(b64, 'base64'))\n } else {\n const binary = atob(b64)\n bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n }\n return JSON.parse(utf8Decoder.decode(bytes)) as T\n}\n\n/** Generate a random 32-byte nonce as a 0x-prefixed hex string. */\nexport function randomNonce(): `0x${string}` {\n const bytes = new Uint8Array(32)\n globalThis.crypto.getRandomValues(bytes)\n return ('0x' + Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`\n}\n","import type { Address, Hex, WalletClient } from 'viem'\nimport type {\n PaymentPayload,\n PaymentRequiredResponse,\n PaymentRequirement,\n X402Network,\n} from './types.js'\nimport { encodePayment, randomNonce } from './utils.js'\n\nexport interface ClientOptions {\n /** A viem WalletClient able to sign EIP-712 typed data. */\n wallet: WalletClient\n /** Underlying fetch to wrap (defaults to global fetch). */\n fetch?: typeof fetch\n /**\n * Hook called before signing. Return `false` to reject the payment.\n * Useful for showing a confirmation UI to the user.\n */\n onPaymentRequired?: (requirement: PaymentRequirement) => boolean | Promise<boolean>\n /** Only allow payments up to this atomic-units cap. Safety belt. */\n maxAmountAtomic?: bigint\n /** Restrict to specific networks (defaults to all). */\n allowedNetworks?: X402Network[]\n}\n\n/**\n * Create a fetch wrapper that transparently handles x402 payments.\n *\n * On a 402 response, it picks the cheapest acceptable requirement,\n * signs an EIP-3009 authorization with the provided wallet, and retries\n * the request with an `X-PAYMENT` header.\n *\n * @example\n * ```ts\n * const pay = createPaymentClient({ wallet })\n * const res = await pay('https://api.example.com/premium')\n * ```\n */\nexport function createPaymentClient(options: ClientOptions) {\n const baseFetch = options.fetch ?? globalThis.fetch.bind(globalThis)\n\n return async function payFetch(\n input: string | URL | Request,\n init: RequestInit = {},\n ): Promise<Response> {\n const first = await baseFetch(input, init)\n if (first.status !== 402) return first\n\n const requirements = await parsePaymentRequired(first)\n const requirement = selectRequirement(requirements.accepts, options)\n if (!requirement) {\n throw new PaymentError('No acceptable payment requirement matched client constraints', requirements)\n }\n\n if (options.onPaymentRequired) {\n const approved = await options.onPaymentRequired(requirement)\n if (!approved) throw new PaymentError('Payment rejected by user', requirements)\n }\n\n const payment = await signPayment(options.wallet, requirement)\n const headers = new Headers(init.headers)\n headers.set('X-PAYMENT', encodePayment(payment))\n\n return baseFetch(input, { ...init, headers })\n }\n}\n\nexport class PaymentError extends Error {\n readonly requirements?: PaymentRequiredResponse\n constructor(message: string, requirements?: PaymentRequiredResponse) {\n super(message)\n this.name = 'PaymentError'\n this.requirements = requirements\n }\n}\n\nasync function parsePaymentRequired(res: Response): Promise<PaymentRequiredResponse> {\n try {\n return (await res.clone().json()) as PaymentRequiredResponse\n } catch {\n throw new PaymentError('402 response did not contain a valid x402 discovery body')\n }\n}\n\nfunction selectRequirement(\n accepts: PaymentRequirement[],\n opts: ClientOptions,\n): PaymentRequirement | undefined {\n const filtered = accepts\n .filter((a) => a.scheme === 'exact')\n .filter((a) => !opts.allowedNetworks || opts.allowedNetworks.includes(a.network))\n .filter((a) => !opts.maxAmountAtomic || BigInt(a.maxAmountRequired) <= opts.maxAmountAtomic)\n\n return filtered.sort((a, b) =>\n BigInt(a.maxAmountRequired) < BigInt(b.maxAmountRequired) ? -1 : 1,\n )[0]\n}\n\n/** Sign an EIP-3009 `TransferWithAuthorization` for the given requirement. */\nexport async function signPayment(\n wallet: WalletClient,\n requirement: PaymentRequirement,\n): Promise<PaymentPayload> {\n const account = wallet.account\n if (!account) throw new PaymentError('Wallet has no account attached')\n\n const now = Math.floor(Date.now() / 1000)\n const validAfter = BigInt(now - 60)\n const validBefore = BigInt(now + (requirement.maxTimeoutSeconds ?? 600))\n const nonce = randomNonce()\n\n const tokenName =\n (requirement.extra?.name as string | undefined) ?? 'USD Coin'\n const tokenVersion =\n (requirement.extra?.version as string | undefined) ?? '2'\n\n const signature = (await wallet.signTypedData({\n account,\n domain: {\n name: tokenName,\n version: tokenVersion,\n chainId: chainIdForNetwork(requirement.network),\n verifyingContract: requirement.asset,\n },\n types: {\n TransferWithAuthorization: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'validAfter', type: 'uint256' },\n { name: 'validBefore', type: 'uint256' },\n { name: 'nonce', type: 'bytes32' },\n ],\n },\n primaryType: 'TransferWithAuthorization',\n message: {\n from: account.address as Address,\n to: requirement.payTo,\n value: BigInt(requirement.maxAmountRequired),\n validAfter,\n validBefore,\n nonce,\n },\n })) as Hex\n\n return {\n x402Version: 1,\n scheme: 'exact',\n network: requirement.network,\n payload: {\n signature,\n authorization: {\n from: account.address as Address,\n to: requirement.payTo,\n value: requirement.maxAmountRequired,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n }\n}\n\nfunction chainIdForNetwork(network: X402Network): number {\n switch (network) {\n case 'base':\n return 8453\n case 'base-sepolia':\n return 84532\n case 'ethereum':\n return 1\n case 'optimism':\n return 10\n case 'arbitrum':\n return 42161\n case 'polygon':\n return 137\n }\n}\n","/**\n * yeetful/agent — the \"agent expense account.\"\n *\n * Wrap your agent's HTTP calls in a single grant-aware `pay()`. Before any x402\n * payment is signed it enforces a spend grant — an allowlist of hosts plus\n * per-call / per-day / lifetime USD caps and an expiry — then pays via the\n * standard x402 client and emits a receipt for every call.\n *\n * One grant authorizes MANY endpoints (the allowlist). It's a guardrail for\n * your own agents (runaway loops, bugs, prompt-injected tool calls) and the\n * receipt feed behind budgets + audit. Enforcement here is local + instant;\n * for hard, adversarial guarantees back the grant with an on-chain Spend\n * Permission (the wallet contract caps spend regardless of this SDK).\n *\n * @example\n * ```ts\n * import { yeetful } from 'yeetful/agent'\n *\n * const pay = yeetful({\n * wallet, // viem WalletClient\n * grant: {\n * allow: ['tripadvisor.x402.paysponge.com', 'anthropic.yeetful.com'],\n * perCallUsd: 0.05,\n * perDayUsd: 2,\n * expiresAt: '2026-12-31',\n * },\n * onReceipt: (r) => console.log(r.host, r.amountUsd, r.txHash),\n * })\n *\n * const res = await pay('https://tripadvisor.x402.paysponge.com/api/v1/location/search?searchQuery=tokyo')\n * // throws GrantError on NOT_ALLOWED / OVER_PER_CALL / BUDGET_EXCEEDED / EXPIRED\n * ```\n */\n\nimport type { WalletClient } from 'viem'\nimport { createPaymentClient, PaymentError } from './client.js'\nimport { decodePayment } from './utils.js'\nimport type { PaymentRequirement, SettleResult, X402Network } from './types.js'\n\nexport type GrantViolation =\n | 'EXPIRED'\n | 'REVOKED'\n | 'NOT_ALLOWED'\n | 'OVER_PER_CALL'\n | 'BUDGET_EXCEEDED'\n\nexport class GrantError extends Error {\n constructor(\n public code: GrantViolation,\n message: string,\n ) {\n super(message)\n this.name = 'GrantError'\n }\n}\n\n/** A scoped spend authorization (mirrors the hosted SpendGrant). */\nexport interface GrantPolicy {\n /** Optional id of the hosted grant this mirrors. */\n id?: string\n /** Exact hostnames this grant may pay (e.g. \"tripadvisor.x402.paysponge.com\"). */\n allow: string[]\n perCallUsd: number\n perDayUsd: number\n /** Optional lifetime cap across the life of this client instance. */\n totalUsd?: number | null\n /** Unix ms, ISO string, or Date. Omit for no expiry. */\n expiresAt?: number | string | Date\n /** 'active' | 'revoked'. Defaults to active. */\n status?: string\n}\n\n/** A single authorization decision — the audit trail + x402 receipt. */\nexport interface Receipt {\n host: string\n amountUsd: number\n ok: boolean\n txHash?: string\n /** \"settled\" on success, or the GrantViolation code on a denial. */\n note: string\n ts: number\n}\n\nexport interface AgentOptions {\n /** viem WalletClient that signs the EIP-3009 payment. */\n wallet: WalletClient\n /** The spend grant to enforce. */\n grant: GrantPolicy\n /** Underlying fetch (defaults to global fetch). */\n fetch?: typeof fetch\n /** Restrict payments to specific networks (defaults to all). */\n allowedNetworks?: X402Network[]\n /** Called after every decision — wire this to your ledger / dashboard. */\n onReceipt?: (receipt: Receipt) => void | Promise<void>\n /** Human-readable progress logging. */\n onEvent?: (message: string) => void\n}\n\nexport interface PayFn {\n (input: string | URL | Request, init?: RequestInit): Promise<Response>\n /** USD spent under this grant since UTC midnight (this client instance). */\n spentTodayUsd(): number\n /** USD remaining in today's budget. */\n remainingTodayUsd(): number\n /** USD spent over the life of this client instance. */\n spentTotalUsd(): number\n}\n\nfunction expiryMs(expiresAt: GrantPolicy['expiresAt']): number {\n if (expiresAt == null) return Infinity\n if (expiresAt instanceof Date) return expiresAt.getTime()\n if (typeof expiresAt === 'number') return expiresAt\n const t = new Date(expiresAt).getTime()\n return Number.isNaN(t) ? Infinity : t\n}\n\nfunction utcDayIndex(ms: number): number {\n return Math.floor(ms / 86_400_000)\n}\n\nfunction hostOf(input: string | URL | Request): string {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url\n try {\n return new URL(url).host.toLowerCase()\n } catch {\n return ''\n }\n}\n\n/** Pull the settlement tx hash from the X-PAYMENT-RESPONSE header, if present. */\nfunction txHashOf(res: Response): string | undefined {\n const header = res.headers.get('x-payment-response')\n if (!header) return undefined\n try {\n return decodePayment<SettleResult>(header).transaction\n } catch {\n return undefined\n }\n}\n\n/**\n * Create a grant-aware paid `fetch`. Enforces the grant locally before signing\n * any x402 payment, pays with the wallet, and emits a receipt per call.\n */\nexport function yeetful(options: AgentOptions): PayFn {\n const { wallet, grant, onReceipt, onEvent } = options\n const log = onEvent ?? (() => {})\n\n let spentToday = 0\n let spentTotal = 0\n let dayIndex = utcDayIndex(Date.now())\n\n const emit = (r: Receipt) => {\n void Promise.resolve(onReceipt?.(r)).catch(() => {})\n }\n const deny = (host: string, code: GrantViolation, msg: string): never => {\n emit({ host, amountUsd: 0, ok: false, note: code, ts: Date.now() })\n log(`✗ ${host} — ${code}: ${msg}`)\n throw new GrantError(code, msg)\n }\n\n const pay = async function pay(\n input: string | URL | Request,\n init: RequestInit = {},\n ): Promise<Response> {\n // Roll the daily budget at UTC midnight.\n const today = utcDayIndex(Date.now())\n if (today !== dayIndex) {\n dayIndex = today\n spentToday = 0\n }\n\n const host = hostOf(input)\n\n // ── Pre-flight policy (no network): status → expiry → allowlist ─────────\n if ((grant.status ?? 'active') === 'revoked') deny(host, 'REVOKED', 'grant is revoked')\n if (Date.now() > expiryMs(grant.expiresAt)) deny(host, 'EXPIRED', 'grant has expired')\n if (!grant.allow.map((h) => h.toLowerCase()).includes(host)) {\n deny(host, 'NOT_ALLOWED', `${host} is not in this grant's allowlist`)\n }\n\n // Price is only known from the 402 challenge — check caps in the hook,\n // which runs after the challenge is parsed and before the payment is signed.\n let pricedUsd = 0\n const client = createPaymentClient({\n wallet,\n fetch: options.fetch,\n allowedNetworks: options.allowedNetworks,\n // Per-call enforcement lives in the hook (not maxAmountAtomic) so an\n // over-cap call surfaces a clean GrantError instead of a filtered no-match.\n onPaymentRequired: (req: PaymentRequirement) => {\n const price = Number(req.maxAmountRequired) / 1e6\n if (price > grant.perCallUsd) {\n deny(host, 'OVER_PER_CALL', `$${price.toFixed(4)} exceeds per-call cap $${grant.perCallUsd}`)\n }\n if (spentToday + price > grant.perDayUsd) {\n deny(host, 'BUDGET_EXCEEDED', `$${(spentToday + price).toFixed(2)} exceeds today's cap $${grant.perDayUsd}`)\n }\n if (grant.totalUsd != null && spentTotal + price > grant.totalUsd) {\n deny(host, 'BUDGET_EXCEEDED', `$${(spentTotal + price).toFixed(2)} exceeds lifetime cap $${grant.totalUsd}`)\n }\n pricedUsd = price\n return true\n },\n })\n\n let res: Response\n try {\n res = await client(input, init)\n } catch (err) {\n if (err instanceof GrantError) throw err // already denied + receipted\n // A rejection from the underlying client (e.g. no acceptable requirement).\n const note = err instanceof PaymentError ? 'payment-failed' : 'error'\n emit({ host, amountUsd: 0, ok: false, note, ts: Date.now() })\n throw err\n }\n\n // Settled (or a free, non-402 call where pricedUsd stayed 0).\n if (pricedUsd > 0) {\n spentToday += pricedUsd\n spentTotal += pricedUsd\n }\n const txHash = txHashOf(res)\n emit({ host, amountUsd: pricedUsd, ok: true, txHash, note: 'settled', ts: Date.now() })\n log(`✓ ${host} — $${pricedUsd.toFixed(4)} · today $${spentToday.toFixed(2)}/$${grant.perDayUsd}`)\n return res\n } as PayFn\n\n pay.spentTodayUsd = () => spentToday\n pay.remainingTodayUsd = () => Math.max(0, grant.perDayUsd - spentToday)\n pay.spentTotalUsd = () => spentTotal\n return pay\n}\n"]}
|
package/dist/agent.d.cts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { WalletClient } from 'viem';
|
|
2
|
+
import { X as X402Network } from './types-DzGpKiV3.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* yeetful/agent — the "agent expense account."
|
|
6
|
+
*
|
|
7
|
+
* Wrap your agent's HTTP calls in a single grant-aware `pay()`. Before any x402
|
|
8
|
+
* payment is signed it enforces a spend grant — an allowlist of hosts plus
|
|
9
|
+
* per-call / per-day / lifetime USD caps and an expiry — then pays via the
|
|
10
|
+
* standard x402 client and emits a receipt for every call.
|
|
11
|
+
*
|
|
12
|
+
* One grant authorizes MANY endpoints (the allowlist). It's a guardrail for
|
|
13
|
+
* your own agents (runaway loops, bugs, prompt-injected tool calls) and the
|
|
14
|
+
* receipt feed behind budgets + audit. Enforcement here is local + instant;
|
|
15
|
+
* for hard, adversarial guarantees back the grant with an on-chain Spend
|
|
16
|
+
* Permission (the wallet contract caps spend regardless of this SDK).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { yeetful } from 'yeetful/agent'
|
|
21
|
+
*
|
|
22
|
+
* const pay = yeetful({
|
|
23
|
+
* wallet, // viem WalletClient
|
|
24
|
+
* grant: {
|
|
25
|
+
* allow: ['tripadvisor.x402.paysponge.com', 'anthropic.yeetful.com'],
|
|
26
|
+
* perCallUsd: 0.05,
|
|
27
|
+
* perDayUsd: 2,
|
|
28
|
+
* expiresAt: '2026-12-31',
|
|
29
|
+
* },
|
|
30
|
+
* onReceipt: (r) => console.log(r.host, r.amountUsd, r.txHash),
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* const res = await pay('https://tripadvisor.x402.paysponge.com/api/v1/location/search?searchQuery=tokyo')
|
|
34
|
+
* // throws GrantError on NOT_ALLOWED / OVER_PER_CALL / BUDGET_EXCEEDED / EXPIRED
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
type GrantViolation = 'EXPIRED' | 'REVOKED' | 'NOT_ALLOWED' | 'OVER_PER_CALL' | 'BUDGET_EXCEEDED';
|
|
39
|
+
declare class GrantError extends Error {
|
|
40
|
+
code: GrantViolation;
|
|
41
|
+
constructor(code: GrantViolation, message: string);
|
|
42
|
+
}
|
|
43
|
+
/** A scoped spend authorization (mirrors the hosted SpendGrant). */
|
|
44
|
+
interface GrantPolicy {
|
|
45
|
+
/** Optional id of the hosted grant this mirrors. */
|
|
46
|
+
id?: string;
|
|
47
|
+
/** Exact hostnames this grant may pay (e.g. "tripadvisor.x402.paysponge.com"). */
|
|
48
|
+
allow: string[];
|
|
49
|
+
perCallUsd: number;
|
|
50
|
+
perDayUsd: number;
|
|
51
|
+
/** Optional lifetime cap across the life of this client instance. */
|
|
52
|
+
totalUsd?: number | null;
|
|
53
|
+
/** Unix ms, ISO string, or Date. Omit for no expiry. */
|
|
54
|
+
expiresAt?: number | string | Date;
|
|
55
|
+
/** 'active' | 'revoked'. Defaults to active. */
|
|
56
|
+
status?: string;
|
|
57
|
+
}
|
|
58
|
+
/** A single authorization decision — the audit trail + x402 receipt. */
|
|
59
|
+
interface Receipt {
|
|
60
|
+
host: string;
|
|
61
|
+
amountUsd: number;
|
|
62
|
+
ok: boolean;
|
|
63
|
+
txHash?: string;
|
|
64
|
+
/** "settled" on success, or the GrantViolation code on a denial. */
|
|
65
|
+
note: string;
|
|
66
|
+
ts: number;
|
|
67
|
+
}
|
|
68
|
+
interface AgentOptions {
|
|
69
|
+
/** viem WalletClient that signs the EIP-3009 payment. */
|
|
70
|
+
wallet: WalletClient;
|
|
71
|
+
/** The spend grant to enforce. */
|
|
72
|
+
grant: GrantPolicy;
|
|
73
|
+
/** Underlying fetch (defaults to global fetch). */
|
|
74
|
+
fetch?: typeof fetch;
|
|
75
|
+
/** Restrict payments to specific networks (defaults to all). */
|
|
76
|
+
allowedNetworks?: X402Network[];
|
|
77
|
+
/** Called after every decision — wire this to your ledger / dashboard. */
|
|
78
|
+
onReceipt?: (receipt: Receipt) => void | Promise<void>;
|
|
79
|
+
/** Human-readable progress logging. */
|
|
80
|
+
onEvent?: (message: string) => void;
|
|
81
|
+
}
|
|
82
|
+
interface PayFn {
|
|
83
|
+
(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
84
|
+
/** USD spent under this grant since UTC midnight (this client instance). */
|
|
85
|
+
spentTodayUsd(): number;
|
|
86
|
+
/** USD remaining in today's budget. */
|
|
87
|
+
remainingTodayUsd(): number;
|
|
88
|
+
/** USD spent over the life of this client instance. */
|
|
89
|
+
spentTotalUsd(): number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a grant-aware paid `fetch`. Enforces the grant locally before signing
|
|
93
|
+
* any x402 payment, pays with the wallet, and emits a receipt per call.
|
|
94
|
+
*/
|
|
95
|
+
declare function yeetful(options: AgentOptions): PayFn;
|
|
96
|
+
|
|
97
|
+
export { type AgentOptions, GrantError, type GrantPolicy, type GrantViolation, type PayFn, type Receipt, yeetful };
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { WalletClient } from 'viem';
|
|
2
|
+
import { X as X402Network } from './types-DzGpKiV3.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* yeetful/agent — the "agent expense account."
|
|
6
|
+
*
|
|
7
|
+
* Wrap your agent's HTTP calls in a single grant-aware `pay()`. Before any x402
|
|
8
|
+
* payment is signed it enforces a spend grant — an allowlist of hosts plus
|
|
9
|
+
* per-call / per-day / lifetime USD caps and an expiry — then pays via the
|
|
10
|
+
* standard x402 client and emits a receipt for every call.
|
|
11
|
+
*
|
|
12
|
+
* One grant authorizes MANY endpoints (the allowlist). It's a guardrail for
|
|
13
|
+
* your own agents (runaway loops, bugs, prompt-injected tool calls) and the
|
|
14
|
+
* receipt feed behind budgets + audit. Enforcement here is local + instant;
|
|
15
|
+
* for hard, adversarial guarantees back the grant with an on-chain Spend
|
|
16
|
+
* Permission (the wallet contract caps spend regardless of this SDK).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { yeetful } from 'yeetful/agent'
|
|
21
|
+
*
|
|
22
|
+
* const pay = yeetful({
|
|
23
|
+
* wallet, // viem WalletClient
|
|
24
|
+
* grant: {
|
|
25
|
+
* allow: ['tripadvisor.x402.paysponge.com', 'anthropic.yeetful.com'],
|
|
26
|
+
* perCallUsd: 0.05,
|
|
27
|
+
* perDayUsd: 2,
|
|
28
|
+
* expiresAt: '2026-12-31',
|
|
29
|
+
* },
|
|
30
|
+
* onReceipt: (r) => console.log(r.host, r.amountUsd, r.txHash),
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* const res = await pay('https://tripadvisor.x402.paysponge.com/api/v1/location/search?searchQuery=tokyo')
|
|
34
|
+
* // throws GrantError on NOT_ALLOWED / OVER_PER_CALL / BUDGET_EXCEEDED / EXPIRED
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
type GrantViolation = 'EXPIRED' | 'REVOKED' | 'NOT_ALLOWED' | 'OVER_PER_CALL' | 'BUDGET_EXCEEDED';
|
|
39
|
+
declare class GrantError extends Error {
|
|
40
|
+
code: GrantViolation;
|
|
41
|
+
constructor(code: GrantViolation, message: string);
|
|
42
|
+
}
|
|
43
|
+
/** A scoped spend authorization (mirrors the hosted SpendGrant). */
|
|
44
|
+
interface GrantPolicy {
|
|
45
|
+
/** Optional id of the hosted grant this mirrors. */
|
|
46
|
+
id?: string;
|
|
47
|
+
/** Exact hostnames this grant may pay (e.g. "tripadvisor.x402.paysponge.com"). */
|
|
48
|
+
allow: string[];
|
|
49
|
+
perCallUsd: number;
|
|
50
|
+
perDayUsd: number;
|
|
51
|
+
/** Optional lifetime cap across the life of this client instance. */
|
|
52
|
+
totalUsd?: number | null;
|
|
53
|
+
/** Unix ms, ISO string, or Date. Omit for no expiry. */
|
|
54
|
+
expiresAt?: number | string | Date;
|
|
55
|
+
/** 'active' | 'revoked'. Defaults to active. */
|
|
56
|
+
status?: string;
|
|
57
|
+
}
|
|
58
|
+
/** A single authorization decision — the audit trail + x402 receipt. */
|
|
59
|
+
interface Receipt {
|
|
60
|
+
host: string;
|
|
61
|
+
amountUsd: number;
|
|
62
|
+
ok: boolean;
|
|
63
|
+
txHash?: string;
|
|
64
|
+
/** "settled" on success, or the GrantViolation code on a denial. */
|
|
65
|
+
note: string;
|
|
66
|
+
ts: number;
|
|
67
|
+
}
|
|
68
|
+
interface AgentOptions {
|
|
69
|
+
/** viem WalletClient that signs the EIP-3009 payment. */
|
|
70
|
+
wallet: WalletClient;
|
|
71
|
+
/** The spend grant to enforce. */
|
|
72
|
+
grant: GrantPolicy;
|
|
73
|
+
/** Underlying fetch (defaults to global fetch). */
|
|
74
|
+
fetch?: typeof fetch;
|
|
75
|
+
/** Restrict payments to specific networks (defaults to all). */
|
|
76
|
+
allowedNetworks?: X402Network[];
|
|
77
|
+
/** Called after every decision — wire this to your ledger / dashboard. */
|
|
78
|
+
onReceipt?: (receipt: Receipt) => void | Promise<void>;
|
|
79
|
+
/** Human-readable progress logging. */
|
|
80
|
+
onEvent?: (message: string) => void;
|
|
81
|
+
}
|
|
82
|
+
interface PayFn {
|
|
83
|
+
(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
84
|
+
/** USD spent under this grant since UTC midnight (this client instance). */
|
|
85
|
+
spentTodayUsd(): number;
|
|
86
|
+
/** USD remaining in today's budget. */
|
|
87
|
+
remainingTodayUsd(): number;
|
|
88
|
+
/** USD spent over the life of this client instance. */
|
|
89
|
+
spentTotalUsd(): number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a grant-aware paid `fetch`. Enforces the grant locally before signing
|
|
93
|
+
* any x402 payment, pays with the wallet, and emits a receipt per call.
|
|
94
|
+
*/
|
|
95
|
+
declare function yeetful(options: AgentOptions): PayFn;
|
|
96
|
+
|
|
97
|
+
export { type AgentOptions, GrantError, type GrantPolicy, type GrantViolation, type PayFn, type Receipt, yeetful };
|