// Fake x402 discovery indexes + candidate endpoints for tests (no network).
import { CDP_URL, PAYAI_URL } from '../src/engine.js';
const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const SOL_USDC = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
const iso = (dAgo) => new Date(Date.now() - dAgo * 86400_000).toISOString();
const item = (resource, { price = 10000, net = 'eip155:8453', asset = BASE_USDC, desc = '', tags = [], svc, calls = 0, payers = 0, last = 1, method = 'GET', version = 2 } = {}) => ({
resource, description: desc, tags, serviceName: svc, x402Version: version, type: 'http',
accepts: [{ scheme: 'exact', network: net, asset, amount: String(price), payTo: '0x' + '11'.repeat(20) }],
extensions: { bazaar: { info: { input: { type: 'http', method } } } },
quality: { l30DaysTotalCalls: calls, l30DaysUniquePayers: payers, lastCalledAt: last === null ? undefined : iso(last) },
});
export const CDP_ITEMS = [
item('https://search.example.com/v1/search', { desc: 'Neural web search: ranked results with title, URL and snippet', tags: ['search', 'web'], svc: 'SearchCo', calls: 5000, payers: 120, price: 10000 }),
item('https://cheapsearch.example.com/search', { desc: 'Web search API, JSON results', tags: ['search'], svc: 'CheapSearch', calls: 300, payers: 9, price: 2000 }),
item('https://deadsearch.example.com/search', { desc: 'Web search for agents', tags: ['search'], svc: 'DeadSearch', calls: 900, payers: 30, price: 5000 }),
item('https://solsafe.example.com/v1/check', { desc: 'Solana token safety: mint authority, freeze authority, holders, liquidity', tags: ['solana', 'token', 'safety'], svc: 'SolSafe', calls: 800, payers: 40, price: 10000, net: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', asset: SOL_USDC }),
item('https://rug.example.com/api/:mint/rug', { desc: 'Solana token rug check', tags: ['solana', 'rug'], svc: 'RugCo', calls: 100, payers: 5, price: 5000 }),
item('https://pdf.example.com/extract', { desc: 'PDF to text extraction', tags: ['pdf'], svc: 'PdfCo', calls: 50, payers: 2, price: 20000, method: 'POST' }),
item('https://testnet.example.com/search', { desc: 'Web search testnet', tags: ['search'], net: 'eip155:84532', asset: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', calls: 10, payers: 1 }),
item('https://toolpick.agentgate.workers.dev/v1/lite', { desc: 'Find paid x402 web search APIs', tags: ['search', 'x402'], svc: 'ToolPick by AgentGate', calls: 1, payers: 1, price: 3000 }),
];
export const PAYAI_ITEMS = [
{ resource: 'https://search.example.com/v1/search', accepts: [{ network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', asset: SOL_USDC, amount: '10000' }], description: 'dup' },
{ resource: 'https://newsearch.example.com/q', accepts: [{ network: 'base', asset: BASE_USDC, maxAmountRequired: '1000' }], description: 'New web search endpoint', x402Version: 1 },
];
const page = (items, url) => { const u = new URL(url); const off = Number(u.searchParams.get('offset') || 0); const lim = Number(u.searchParams.get('limit') || 1000); return { items: items.slice(off, off + lim), pagination: { limit: lim, offset: off, total: items.length } }; };
const b64 = (o) => Buffer.from(JSON.stringify(o)).toString('base64');
/** opts: { cdpDown, payaiDown, cdpItems, payaiItems, live: { [url]: 'live'|'down'|'200'|'price' } } */
export function mockNet({ cdpDown = false, payaiDown = false, cdpItems = CDP_ITEMS, payaiItems = PAYAI_ITEMS, live = {} } = {}) {
const calls = [];
const fetchImpl = async (input, init = {}) => {
const url = String(input?.url || input); calls.push(url);
if (url.startsWith(CDP_URL)) return cdpDown ? new Response('down', { status: 503 }) : Response.json(page(cdpItems, url));
if (url.startsWith(PAYAI_URL)) return payaiDown ? new Response('down', { status: 503 }) : Response.json(page(payaiItems, url));
const mode = live[url] ?? (url.includes('deadsearch') ? 'down' : 'live');
if (mode === 'down') throw new Error('connect ECONNREFUSED');
if (mode === 'hang') return new Promise(() => {});
if (mode === '200') return Response.json({ ok: true });
const it = cdpItems.find((x) => x.resource === url);
const accepts = (it?.accepts || [{ scheme: 'exact', network: 'eip155:8453', asset: BASE_USDC, amount: '1000' }]).map((a) => ({ ...a, amount: mode === 'price' ? String(Number(a.amount) * 2) : a.amount }));
return new Response(JSON.stringify({ x402Version: 1, accepts: accepts.map((a) => ({ ...a, maxAmountRequired: a.amount, network: 'base' })) }), { status: 402, headers: { 'content-type': 'application/json', 'payment-required': b64({ x402Version: 2, accepts }) } });
};
return { calls, fetchImpl };
}
agentgate-source: code mirror on Cloudflare Pages. All repos