toll402-client 0.1.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 ADDED
@@ -0,0 +1,54 @@
1
+ # toll402-client
2
+
3
+ One-line access to [Toll402](https://toll402.dev): pay-per-call tools for AI agents over x402 (USDC on Base).
4
+ No API keys. Without a wallet you get the free trial (cheap tools, per-IP daily quota); with a wallet every call pays itself.
5
+
6
+ ```bash
7
+ npm i toll402-client
8
+ ```
9
+
10
+ ```ts
11
+ import { Toll402 } from "toll402-client";
12
+
13
+ const t = new Toll402({ walletKey: process.env.WALLET_KEY as `0x${string}` }); // omit walletKey → free trial
14
+
15
+ await t.read("https://example.com"); // page → clean Markdown ($0.002)
16
+ await t.do("convert 100 usd to mxn", { base: "USD", quote: "MXN", amount: 100 }); // router: best tool, runs it
17
+ await t.provenance("https://some-article"); // human or synthetic? evidence + score
18
+ await t.lookup("HTTP 402", { sources: ["wikipedia", "wikidata"] }); // trusted sources with citations
19
+ await t.business.search({ city: "Ciudad de México", category: "dentist", minLevel: "corroborated" });
20
+ await t.call("hn_top", { n: 5 }); // any catalog tool by name
21
+ await t.forge({ name: "reverse_text", description: "...", inputSchema: {...}, examples: [...] }); // new tool for everyone
22
+
23
+ t.lastPayment; // decoded settlement of the last paid call (tx hash on Base)
24
+ t.trialRemaining; // free-trial calls left today (no wallet)
25
+ ```
26
+
27
+ Errors throw `Toll402Error` with `status`, `code` (`payment_required`, `invalid_input`, `tool_failed`, …) and `price` when known.
28
+ You are charged only on 2xx.
29
+
30
+ ## LangChain
31
+
32
+ ```ts
33
+ import { toll402Tools } from "toll402-client/langchain";
34
+ const tools = await toll402Tools(t, { maxPriceUsd: 0.05 }); // DynamicStructuredTool[] from the live catalog
35
+ ```
36
+
37
+ ## Vercel AI SDK
38
+
39
+ ```ts
40
+ import { toll402AiTools } from "toll402-client/ai";
41
+ const tools = await toll402AiTools(t, { kinds: ["builtin", "forged"] });
42
+ await generateText({ model, tools, prompt: "Find verified dentists in Mexico City and summarize the top 3" });
43
+ ```
44
+
45
+ ## Options
46
+
47
+ | Option | Default | Notes |
48
+ |---|---|---|
49
+ | `walletKey` | — | 0x private key holding USDC on Base. Never hard-code it. |
50
+ | `baseUrl` | `https://toll402.dev` | Self-hosted gateway URL |
51
+ | `maxUsdPerCall` | `0.25` | Hard spend cap per payment |
52
+ | `network` | `eip155:8453` | CAIP-2 network to pay on |
53
+
54
+ Docs for machines: https://toll402.dev/llms.txt · Catalog: https://toll402.dev/v1/catalog · MIT.
package/dist/ai.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Vercel AI SDK adapter: every available Toll402 tool as an AI SDK `tool()`.
3
+ * import { toll402AiTools } from "toll402-client/ai";
4
+ * const tools = await toll402AiTools(new Toll402({ walletKey }));
5
+ * generateText({ model, tools, prompt })
6
+ */
7
+ import { type ToolSet } from "ai";
8
+ import type { Toll402, CatalogTool } from "./index.js";
9
+ export interface Toll402AiToolsOptions {
10
+ kinds?: ("builtin" | "forged" | "external")[];
11
+ maxPriceUsd?: number;
12
+ include?: (t: CatalogTool) => boolean;
13
+ }
14
+ export declare function toll402AiTools(client: Toll402, opts?: Toll402AiToolsOptions): Promise<ToolSet>;
package/dist/ai.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Vercel AI SDK adapter: every available Toll402 tool as an AI SDK `tool()`.
3
+ * import { toll402AiTools } from "toll402-client/ai";
4
+ * const tools = await toll402AiTools(new Toll402({ walletKey }));
5
+ * generateText({ model, tools, prompt })
6
+ */
7
+ import { tool, jsonSchema } from "ai";
8
+ export async function toll402AiTools(client, opts = {}) {
9
+ const cat = await client.catalog();
10
+ const kinds = new Set(opts.kinds ?? ["builtin", "forged", "external"]);
11
+ const out = {};
12
+ for (const t of cat.tools) {
13
+ if (!t.available || !kinds.has(t.kind))
14
+ continue;
15
+ if (opts.maxPriceUsd !== undefined && t.priceUsd > opts.maxPriceUsd)
16
+ continue;
17
+ if (opts.include && !opts.include(t))
18
+ continue;
19
+ const name = t.name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
20
+ out[name] = tool({
21
+ description: `${t.description} (Toll402 ${t.kind} tool, ${t.price} per call, paid automatically in USDC via x402)`,
22
+ parameters: jsonSchema(t.inputSchema),
23
+ execute: async (input) => client.call(t.path, input),
24
+ });
25
+ }
26
+ return out;
27
+ }
@@ -0,0 +1,265 @@
1
+ export interface Toll402Options {
2
+ /** 0x-prefixed private key of a wallet holding USDC on Base. Omit to use the free trial (cheap tools, per-IP quota). */
3
+ walletKey?: `0x${string}`;
4
+ /** Gateway URL. Default https://toll402.dev */
5
+ baseUrl?: string;
6
+ /** Hard cap per single payment in USD. Default 0.25 */
7
+ maxUsdPerCall?: number;
8
+ /** CAIP-2 network to pay on. Default "eip155:8453" (Base). Use "eip155:*" to accept any EVM network the server offers. */
9
+ network?: string;
10
+ /** Custom fetch (tests, polyfills). */
11
+ fetch?: typeof fetch;
12
+ }
13
+ export interface CatalogTool {
14
+ id: string;
15
+ kind: "builtin" | "forged" | "external";
16
+ name: string;
17
+ description: string;
18
+ tags: string[];
19
+ method: string;
20
+ path: string;
21
+ url: string;
22
+ price: string;
23
+ priceUsd: number;
24
+ available: boolean;
25
+ inputSchema: Record<string, unknown>;
26
+ example?: unknown;
27
+ outputExample?: unknown;
28
+ meta?: Record<string, unknown>;
29
+ }
30
+ export interface Catalog {
31
+ service: string;
32
+ version: string;
33
+ description: string;
34
+ baseUrl: string;
35
+ payment: Record<string, unknown>;
36
+ counts: {
37
+ builtin: number;
38
+ forged: number;
39
+ external: number;
40
+ };
41
+ freeTrial?: {
42
+ callsPerIpPerDay: number;
43
+ toolsPricedUpTo: string;
44
+ note: string;
45
+ } | null;
46
+ tools: CatalogTool[];
47
+ }
48
+ export interface PaymentInfo {
49
+ success: boolean;
50
+ transaction?: string;
51
+ network?: string;
52
+ payer?: string;
53
+ [k: string]: unknown;
54
+ }
55
+ export declare class Toll402Error extends Error {
56
+ status: number;
57
+ code: string;
58
+ price?: string | undefined;
59
+ details?: unknown | undefined;
60
+ constructor(message: string, status: number, code: string, price?: string | undefined, details?: unknown | undefined);
61
+ }
62
+ export interface ForgeSpec {
63
+ name: string;
64
+ description: string;
65
+ inputSchema: Record<string, unknown>;
66
+ outputSchema?: Record<string, unknown>;
67
+ examples: {
68
+ input: Record<string, unknown>;
69
+ expectedOutput?: unknown;
70
+ }[];
71
+ allowNetwork?: boolean;
72
+ priceUsd?: number;
73
+ tags?: string[];
74
+ creator?: string;
75
+ }
76
+ export declare class Toll402 {
77
+ readonly baseUrl: string;
78
+ readonly address?: string;
79
+ /** Decoded PAYMENT-RESPONSE of the last paid call (undefined for free/trial calls). */
80
+ lastPayment?: PaymentInfo;
81
+ /** Remaining free-trial calls reported by the server on the last call (undefined once you pay). */
82
+ trialRemaining?: number;
83
+ private readonly f;
84
+ private catalogCache?;
85
+ constructor(opts?: Toll402Options);
86
+ catalog(opts?: {
87
+ fresh?: boolean;
88
+ }): Promise<Catalog>;
89
+ /** Free: ranked tools for a plain-language need. */
90
+ find(need: string, opts?: {
91
+ limit?: number;
92
+ kinds?: ("builtin" | "forged" | "external")[];
93
+ }): Promise<{
94
+ matches: (CatalogTool & {
95
+ score: number;
96
+ })[];
97
+ forgeHint?: string;
98
+ }>;
99
+ /** Call any tool by catalog name ("read_url", "hn_top", …), id ("t/hn_top", "x/abc123") or path ("/v1/read"). Returns the tool's `result`. */
100
+ call<T = unknown>(tool: string, input?: Record<string, unknown>): Promise<T>;
101
+ /** One endpoint for everything: routes `need` to the best tool and runs it with `input`. */
102
+ do<T = unknown>(need: string, input: Record<string, unknown>, opts?: {
103
+ maxPriceUsd?: number;
104
+ tool?: string;
105
+ }): Promise<{
106
+ executed: boolean;
107
+ tool?: {
108
+ id: string;
109
+ name: string;
110
+ price: string;
111
+ };
112
+ result?: T;
113
+ reason?: string;
114
+ alternatives?: unknown[];
115
+ }>;
116
+ /** Create a new tool from a description + examples; published for every agent on success. */
117
+ forge(spec: ForgeSpec): Promise<{
118
+ published: boolean;
119
+ tool?: {
120
+ name: string;
121
+ url: string;
122
+ price: string;
123
+ };
124
+ attempts: number;
125
+ results: unknown[];
126
+ notes?: string;
127
+ }>;
128
+ read(url: string, opts?: {
129
+ format?: "markdown" | "text" | "both";
130
+ includeLinks?: boolean;
131
+ maxChars?: number;
132
+ }): Promise<{
133
+ url: string;
134
+ title: string | null;
135
+ markdown?: string;
136
+ text?: string;
137
+ wordCount: number;
138
+ links?: {
139
+ text: string;
140
+ href: string;
141
+ }[];
142
+ }>;
143
+ provenance(url: string, opts?: {
144
+ deep?: boolean;
145
+ }): Promise<{
146
+ humanOriginScore: number;
147
+ verdict: string;
148
+ confidence: number;
149
+ evidence: unknown[];
150
+ firstArchived: string | null;
151
+ }>;
152
+ lookup(query: string, opts?: {
153
+ language?: string;
154
+ sources?: string[];
155
+ maxPassages?: number;
156
+ synthesize?: boolean;
157
+ }): Promise<{
158
+ answer: {
159
+ text: string;
160
+ citations: number[];
161
+ confidence: number;
162
+ } | null;
163
+ passages: unknown[];
164
+ }>;
165
+ extract<T = unknown>(input: {
166
+ url?: string;
167
+ text?: string;
168
+ schema: Record<string, unknown>;
169
+ instructions?: string;
170
+ }): Promise<{
171
+ data: T;
172
+ source: string | null;
173
+ }>;
174
+ summarize(input: {
175
+ url?: string;
176
+ text?: string;
177
+ style?: "bullets" | "paragraph" | "tldr" | "detailed";
178
+ maxWords?: number;
179
+ language?: string;
180
+ focus?: string;
181
+ }): Promise<{
182
+ summary: string;
183
+ title: string | null;
184
+ }>;
185
+ judge(input: {
186
+ task: string;
187
+ candidate: string;
188
+ reference?: string;
189
+ criteria?: string[];
190
+ }): Promise<{
191
+ overall: number;
192
+ pass: boolean;
193
+ scores: unknown[];
194
+ issues: string[];
195
+ suggestions: string[];
196
+ }>;
197
+ verifyEmail(email: string): Promise<{
198
+ valid: boolean;
199
+ score: number;
200
+ disposable: boolean;
201
+ roleAccount: boolean;
202
+ }>;
203
+ fx(base: string, quote?: string, amount?: number): Promise<{
204
+ base: string;
205
+ quote?: string;
206
+ rate?: number;
207
+ converted?: number;
208
+ rates?: Record<string, number>;
209
+ date: string;
210
+ }>;
211
+ /** Verified business directory. */
212
+ readonly business: {
213
+ search: (q: {
214
+ query?: string;
215
+ category?: string;
216
+ city?: string;
217
+ cityKey?: string;
218
+ country?: string;
219
+ near?: {
220
+ lat: number;
221
+ lon: number;
222
+ radiusKm?: number;
223
+ };
224
+ minScore?: number;
225
+ minLevel?: string;
226
+ claimedOnly?: boolean;
227
+ includeEvidence?: boolean;
228
+ limit?: number;
229
+ offset?: number;
230
+ }) => Promise<{
231
+ total: number;
232
+ items: unknown[];
233
+ region?: unknown;
234
+ }>;
235
+ verify: (q: {
236
+ id?: string;
237
+ name?: string;
238
+ website?: string;
239
+ phone?: string;
240
+ address?: string;
241
+ city?: string;
242
+ country?: string;
243
+ }) => Promise<{
244
+ inDirectory: boolean;
245
+ matches: unknown[];
246
+ liveChecks: {
247
+ score: number;
248
+ level: string;
249
+ evidence: unknown[];
250
+ };
251
+ verdict: string;
252
+ }>;
253
+ details: (id: string, opts?: {
254
+ force?: boolean;
255
+ }) => Promise<{
256
+ business: unknown;
257
+ enrichment: unknown;
258
+ cached: boolean;
259
+ }>;
260
+ /** Free public profile. */
261
+ get: (id: string) => Promise<Record<string, unknown>>;
262
+ };
263
+ private resolvePath;
264
+ }
265
+ export default Toll402;
package/dist/index.js ADDED
@@ -0,0 +1,158 @@
1
+ /**
2
+ * toll402-client — one-line access to Toll402 (https://toll402.dev):
3
+ * pay-per-call tools for AI agents over x402 (USDC on Base).
4
+ *
5
+ * const t = new Toll402({ walletKey: process.env.WALLET_KEY }); // or no key → free trial
6
+ * await t.read("https://example.com");
7
+ * await t.do("convert 100 usd to mxn", { base: "USD", quote: "MXN", amount: 100 });
8
+ */
9
+ import { wrapFetchWithPaymentFromConfig, decodePaymentResponseHeader } from "@x402/fetch";
10
+ import { ExactEvmScheme } from "@x402/evm/exact/client";
11
+ import { privateKeyToAccount } from "viem/accounts";
12
+ export class Toll402Error extends Error {
13
+ status;
14
+ code;
15
+ price;
16
+ details;
17
+ constructor(message, status, code, price, details) {
18
+ super(message);
19
+ this.status = status;
20
+ this.code = code;
21
+ this.price = price;
22
+ this.details = details;
23
+ this.name = "Toll402Error";
24
+ }
25
+ }
26
+ export class Toll402 {
27
+ baseUrl;
28
+ address;
29
+ /** Decoded PAYMENT-RESPONSE of the last paid call (undefined for free/trial calls). */
30
+ lastPayment;
31
+ /** Remaining free-trial calls reported by the server on the last call (undefined once you pay). */
32
+ trialRemaining;
33
+ f;
34
+ catalogCache;
35
+ constructor(opts = {}) {
36
+ this.baseUrl = (opts.baseUrl ?? "https://toll402.dev").replace(/\/$/, "");
37
+ const base = opts.fetch ?? globalThis.fetch;
38
+ if (opts.walletKey) {
39
+ const account = privateKeyToAccount(opts.walletKey);
40
+ this.address = account.address;
41
+ this.f = wrapFetchWithPaymentFromConfig(base, {
42
+ schemes: [{ network: (opts.network ?? "eip155:8453"), client: new ExactEvmScheme(account) }],
43
+ spendControls: { maxAmountPerPayment: `$${opts.maxUsdPerCall ?? 0.25}` },
44
+ });
45
+ }
46
+ else {
47
+ this.f = base;
48
+ }
49
+ }
50
+ // ---- discovery (free) ------------------------------------------------------
51
+ async catalog(opts = {}) {
52
+ if (!opts.fresh && this.catalogCache && Date.now() - this.catalogCache.at < 5 * 60_000)
53
+ return this.catalogCache.data;
54
+ const r = await this.f(`${this.baseUrl}/v1/catalog`);
55
+ if (!r.ok)
56
+ throw new Toll402Error(`catalog: HTTP ${r.status}`, r.status, "catalog_unavailable");
57
+ const data = (await r.json());
58
+ this.catalogCache = { at: Date.now(), data };
59
+ return data;
60
+ }
61
+ /** Free: ranked tools for a plain-language need. */
62
+ async find(need, opts = {}) {
63
+ const r = await this.f(`${this.baseUrl}/v1/find`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ need, ...opts }) });
64
+ const j = (await r.json());
65
+ if (!r.ok)
66
+ throw new Toll402Error(`find: HTTP ${r.status}`, r.status, "find_failed", undefined, j);
67
+ return j;
68
+ }
69
+ // ---- calls (paid; free trial when no wallet) ----------------------------------
70
+ /** Call any tool by catalog name ("read_url", "hn_top", …), id ("t/hn_top", "x/abc123") or path ("/v1/read"). Returns the tool's `result`. */
71
+ async call(tool, input = {}) {
72
+ const path = await this.resolvePath(tool);
73
+ const r = await this.f(`${this.baseUrl}${path}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input) });
74
+ const trial = r.headers.get("x-toll402-trial-remaining");
75
+ this.trialRemaining = trial !== null ? Number(trial) : undefined;
76
+ const pr = r.headers.get("payment-response") ?? r.headers.get("x-payment-response");
77
+ if (pr) {
78
+ try {
79
+ this.lastPayment = decodePaymentResponseHeader(pr);
80
+ }
81
+ catch {
82
+ /* ignore undecodable header */
83
+ }
84
+ }
85
+ const text = await r.text();
86
+ let body = {};
87
+ try {
88
+ body = JSON.parse(text);
89
+ }
90
+ catch {
91
+ body = { raw: text };
92
+ }
93
+ if (r.status === 402) {
94
+ throw new Toll402Error(body.message ?? "Payment required: configure walletKey with USDC on Base (or your free-trial quota is exhausted)", 402, "payment_required", body.price, body);
95
+ }
96
+ if (!r.ok || body.ok === false) {
97
+ throw new Toll402Error(body.message ?? `HTTP ${r.status}`, r.status, body.error ?? "error", undefined, body);
98
+ }
99
+ return body.result;
100
+ }
101
+ /** One endpoint for everything: routes `need` to the best tool and runs it with `input`. */
102
+ async do(need, input, opts = {}) {
103
+ return this.call("/v1/do", { need, input, ...opts });
104
+ }
105
+ /** Create a new tool from a description + examples; published for every agent on success. */
106
+ forge(spec) {
107
+ return this.call("/v1/forge", spec);
108
+ }
109
+ read(url, opts = {}) {
110
+ return this.call("/v1/read", { url, ...opts });
111
+ }
112
+ provenance(url, opts = {}) {
113
+ return this.call("/v1/provenance", { url, ...opts });
114
+ }
115
+ lookup(query, opts = {}) {
116
+ return this.call("/v1/lookup", { query, ...opts });
117
+ }
118
+ extract(input) {
119
+ return this.call("/v1/extract", input);
120
+ }
121
+ summarize(input) {
122
+ return this.call("/v1/summarize", input);
123
+ }
124
+ judge(input) {
125
+ return this.call("/v1/judge", input);
126
+ }
127
+ verifyEmail(email) {
128
+ return this.call("/v1/email/verify", { email });
129
+ }
130
+ fx(base, quote, amount = 1) {
131
+ return this.call("/v1/fx", { base, quote, amount });
132
+ }
133
+ /** Verified business directory. */
134
+ business = {
135
+ search: (q) => this.call("/v1/biz/search", q),
136
+ verify: (q) => this.call("/v1/biz/verify", q),
137
+ details: (id, opts = {}) => this.call("/v1/biz/details", { id, ...opts }),
138
+ /** Free public profile. */
139
+ get: async (id) => {
140
+ const r = await this.f(`${this.baseUrl}/v1/biz/${encodeURIComponent(id)}`);
141
+ if (!r.ok)
142
+ throw new Toll402Error(`business ${id}: HTTP ${r.status}`, r.status, "not_found");
143
+ return r.json();
144
+ },
145
+ };
146
+ async resolvePath(tool) {
147
+ if (tool.startsWith("/"))
148
+ return tool;
149
+ if (tool.startsWith("t/") || tool.startsWith("x/"))
150
+ return `/v1/${tool}`;
151
+ const cat = await this.catalog();
152
+ const hit = cat.tools.find((t) => t.name === tool || t.id === tool);
153
+ if (!hit)
154
+ throw new Toll402Error(`Unknown tool "${tool}". Use find() to discover tools.`, 404, "unknown_tool");
155
+ return hit.path;
156
+ }
157
+ }
158
+ export default Toll402;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * LangChain adapter: every available Toll402 tool as a DynamicStructuredTool.
3
+ * import { toll402Tools } from "toll402-client/langchain";
4
+ * const tools = await toll402Tools(new Toll402({ walletKey }));
5
+ */
6
+ import { DynamicStructuredTool } from "@langchain/core/tools";
7
+ import { z } from "zod";
8
+ import type { Toll402, CatalogTool } from "./index.js";
9
+ /** Minimal JSON-Schema → zod conversion (objects with string/number/integer/boolean/array/object props, enums, optional). */
10
+ export declare function jsonSchemaToZod(schema: Record<string, unknown>): z.ZodTypeAny;
11
+ export interface Toll402ToolsOptions {
12
+ /** Only these kinds (default: builtin + forged; external excluded unless proxied/available). */
13
+ kinds?: ("builtin" | "forged" | "external")[];
14
+ /** Skip tools priced above this (USD). */
15
+ maxPriceUsd?: number;
16
+ /** Filter by name/id. */
17
+ include?: (t: CatalogTool) => boolean;
18
+ }
19
+ export declare function toll402Tools(client: Toll402, opts?: Toll402ToolsOptions): Promise<DynamicStructuredTool<z.ZodObject<z.ZodRawShape, z.UnknownKeysParam, z.ZodTypeAny, {
20
+ [x: string]: any;
21
+ }, {
22
+ [x: string]: any;
23
+ }>, Record<string, unknown>, {
24
+ [x: string]: any;
25
+ }, string>[]>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * LangChain adapter: every available Toll402 tool as a DynamicStructuredTool.
3
+ * import { toll402Tools } from "toll402-client/langchain";
4
+ * const tools = await toll402Tools(new Toll402({ walletKey }));
5
+ */
6
+ import { DynamicStructuredTool } from "@langchain/core/tools";
7
+ import { z } from "zod";
8
+ /** Minimal JSON-Schema → zod conversion (objects with string/number/integer/boolean/array/object props, enums, optional). */
9
+ export function jsonSchemaToZod(schema) {
10
+ const type = schema.type;
11
+ if (schema.enum && Array.isArray(schema.enum))
12
+ return z.enum(schema.enum.map(String));
13
+ switch (type) {
14
+ case "string":
15
+ return z.string();
16
+ case "number":
17
+ return z.number();
18
+ case "integer":
19
+ return z.number().int();
20
+ case "boolean":
21
+ return z.boolean();
22
+ case "array":
23
+ return z.array(schema.items ? jsonSchemaToZod(schema.items) : z.unknown());
24
+ case "object": {
25
+ const props = schema.properties ?? {};
26
+ const required = new Set(schema.required ?? []);
27
+ const shape = {};
28
+ for (const [k, v] of Object.entries(props)) {
29
+ let zz = jsonSchemaToZod(v);
30
+ if (typeof v.description === "string")
31
+ zz = zz.describe(v.description);
32
+ shape[k] = required.has(k) ? zz : zz.optional();
33
+ }
34
+ return Object.keys(shape).length ? z.object(shape).passthrough() : z.record(z.unknown());
35
+ }
36
+ default:
37
+ return z.unknown();
38
+ }
39
+ }
40
+ export async function toll402Tools(client, opts = {}) {
41
+ const cat = await client.catalog();
42
+ const kinds = new Set(opts.kinds ?? ["builtin", "forged", "external"]);
43
+ return cat.tools
44
+ .filter((t) => t.available && kinds.has(t.kind) && (opts.maxPriceUsd === undefined || t.priceUsd <= opts.maxPriceUsd) && (opts.include?.(t) ?? true))
45
+ .map((t) => new DynamicStructuredTool({
46
+ name: t.name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64),
47
+ description: `${t.description} (Toll402 ${t.kind} tool, ${t.price} per call, paid automatically in USDC via x402)`,
48
+ schema: jsonSchemaToZod(t.inputSchema),
49
+ func: async (input) => JSON.stringify(await client.call(t.path, input)),
50
+ }));
51
+ }
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "toll402-client",
3
+ "version": "0.1.0",
4
+ "description": "One-line client for Toll402 — pay-per-call tools for AI agents via x402 (USDC on Base). Free trial without a wallet; automatic payment with one.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "homepage": "https://toll402.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://gitlab.com/toll402/toll402",
11
+ "directory": "clients/js"
12
+ },
13
+ "keywords": [
14
+ "x402",
15
+ "ai-agents",
16
+ "tools",
17
+ "usdc",
18
+ "base",
19
+ "langchain",
20
+ "vercel-ai",
21
+ "mcp"
22
+ ],
23
+ "main": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js"
29
+ },
30
+ "./langchain": {
31
+ "types": "./dist/langchain.d.ts",
32
+ "import": "./dist/langchain.js"
33
+ },
34
+ "./ai": {
35
+ "types": "./dist/ai.d.ts",
36
+ "import": "./dist/ai.js"
37
+ }
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "README.md"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.json",
45
+ "typecheck": "tsc -p tsconfig.json --noEmit",
46
+ "smoke": "tsx src/__smoke__.ts"
47
+ },
48
+ "dependencies": {
49
+ "@x402/evm": "~2.25.0",
50
+ "@x402/fetch": "~2.25.0",
51
+ "viem": "^2.56.3"
52
+ },
53
+ "peerDependencies": {
54
+ "@langchain/core": ">=0.3.0",
55
+ "ai": ">=4.0.0",
56
+ "zod": ">=3.23.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "@langchain/core": {
60
+ "optional": true
61
+ },
62
+ "ai": {
63
+ "optional": true
64
+ },
65
+ "zod": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "devDependencies": {
70
+ "@langchain/core": "^0.3.0",
71
+ "@types/node": "^22",
72
+ "ai": "^4.0.0",
73
+ "tsx": "^4.23.13",
74
+ "typescript": "^5.7.0",
75
+ "zod": "^3.24.2"
76
+ },
77
+ "engines": {
78
+ "node": ">=20"
79
+ }
80
+ }