@dexterai/x402 2.1.0 → 3.0.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.
@@ -656,21 +656,51 @@ var EvmAdapter = class {
656
656
  });
657
657
  const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
658
658
  const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
659
+ let approvalExtension;
659
660
  if (currentAllowance < BigInt(amount)) {
660
- if (!wallet.sendTransaction) {
661
+ const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
662
+ if (wallet.signTransaction) {
663
+ this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
664
+ const chainId2 = this.getChainId(accept.network);
665
+ const gasPrice = await this.readGasPrice(url);
666
+ const nonce2 = await this.readNonce(url, wallet.address);
667
+ const signedTx = await wallet.signTransaction({
668
+ to: asset,
669
+ data: approveData,
670
+ chainId: chainId2,
671
+ gas: 50000n,
672
+ // standard ERC-20 approve
673
+ gasPrice,
674
+ nonce: nonce2
675
+ });
676
+ approvalExtension = {
677
+ erc20ApprovalGasSponsoring: {
678
+ info: {
679
+ from: wallet.address,
680
+ asset,
681
+ spender: PERMIT2_ADDRESS,
682
+ amount: MAX_UINT256.toString(),
683
+ signedTransaction: signedTx,
684
+ version: "1"
685
+ }
686
+ }
687
+ };
688
+ this.log("Permit2 approval signed for facilitator relay");
689
+ } else if (wallet.sendTransaction) {
690
+ this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
691
+ const approveTxHash = await wallet.sendTransaction({
692
+ to: asset,
693
+ data: approveData,
694
+ value: 0n
695
+ });
696
+ this.log(`Permit2 approval tx sent: ${approveTxHash}`);
697
+ await this.waitForReceipt(url, approveTxHash);
698
+ this.log("Permit2 approval confirmed");
699
+ } else {
661
700
  throw new Error(
662
- "Permit2 payments require a wallet that supports sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
701
+ "Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
663
702
  );
664
703
  }
665
- this.log(`Approving Permit2 for ${asset} (current allowance: ${currentAllowance})`);
666
- const approveTxHash = await wallet.sendTransaction({
667
- to: asset,
668
- data: this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256),
669
- value: 0n
670
- });
671
- this.log(`Permit2 approval tx sent: ${approveTxHash}`);
672
- await this.waitForReceipt(url, approveTxHash);
673
- this.log("Permit2 approval confirmed");
674
704
  } else {
675
705
  this.log("Sufficient Permit2 allowance, skipping approval");
676
706
  }
@@ -725,7 +755,8 @@ var EvmAdapter = class {
725
755
  };
726
756
  return {
727
757
  serialized: JSON.stringify(payload),
728
- signature
758
+ signature,
759
+ extensions: approvalExtension
729
760
  };
730
761
  }
731
762
  /**
@@ -794,6 +825,43 @@ var EvmAdapter = class {
794
825
  }
795
826
  throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
796
827
  }
828
+ /**
829
+ * Read gas price via eth_gasPrice RPC call.
830
+ */
831
+ async readGasPrice(rpcUrl) {
832
+ try {
833
+ const response = await fetch(rpcUrl, {
834
+ method: "POST",
835
+ headers: { "Content-Type": "application/json" },
836
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
837
+ });
838
+ const result = await response.json();
839
+ return result.result ? BigInt(result.result) : 50000000n;
840
+ } catch {
841
+ return 50000000n;
842
+ }
843
+ }
844
+ /**
845
+ * Read transaction count (nonce) via eth_getTransactionCount RPC call.
846
+ */
847
+ async readNonce(rpcUrl, address) {
848
+ try {
849
+ const response = await fetch(rpcUrl, {
850
+ method: "POST",
851
+ headers: { "Content-Type": "application/json" },
852
+ body: JSON.stringify({
853
+ jsonrpc: "2.0",
854
+ id: 1,
855
+ method: "eth_getTransactionCount",
856
+ params: [address, "latest"]
857
+ })
858
+ });
859
+ const result = await response.json();
860
+ return result.result ? parseInt(result.result, 16) : 0;
861
+ } catch {
862
+ return 0;
863
+ }
864
+ }
797
865
  /**
798
866
  * Calculate how much to approve based on the facilitator's approval strategy.
799
867
  * Buffered approvals reduce the number of on-chain approval txs for micropayments.
@@ -1,5 +1,5 @@
1
- import { e as SolanaAdapter, f as EvmAdapter, C as ChainAdapter } from '../types-D1u7iu8n.cjs';
2
- export { q as ARBITRUM_ONE, s as AVALANCHE, A as AdapterConfig, B as BASE_MAINNET, p as BASE_SEPOLIA, l as BSC_MAINNET, o as BSC_STABLECOIN_ADDRESSES, n as BSC_USDC, m as BSC_USDT, d as BalanceInfo, v as ETHEREUM_MAINNET, E as EvmWallet, G as GenericWallet, O as OPTIMISM, P as PERMIT2_ADDRESS, r as POLYGON, t as SKALE_BASE, u as SKALE_BASE_SEPOLIA, h as SOLANA_DEVNET, b as SOLANA_MAINNET, j as SOLANA_TESTNET, g as SignedTransaction, S as SolanaWallet, U as USDC_ADDRESSES, W as WalletSet, X as X402_EXACT_PERMIT2_PROXY, a as createEvmAdapter, c as createSolanaAdapter, k as isEvmWallet, i as isSolanaWallet } from '../types-D1u7iu8n.cjs';
1
+ import { e as SolanaAdapter, f as EvmAdapter, C as ChainAdapter } from '../types-C_aQh02s.cjs';
2
+ export { q as ARBITRUM_ONE, s as AVALANCHE, A as AdapterConfig, B as BASE_MAINNET, p as BASE_SEPOLIA, l as BSC_MAINNET, o as BSC_STABLECOIN_ADDRESSES, n as BSC_USDC, m as BSC_USDT, d as BalanceInfo, v as ETHEREUM_MAINNET, E as EvmWallet, G as GenericWallet, O as OPTIMISM, P as PERMIT2_ADDRESS, r as POLYGON, t as SKALE_BASE, u as SKALE_BASE_SEPOLIA, h as SOLANA_DEVNET, b as SOLANA_MAINNET, j as SOLANA_TESTNET, g as SignedTransaction, S as SolanaWallet, U as USDC_ADDRESSES, W as WalletSet, X as X402_EXACT_PERMIT2_PROXY, a as createEvmAdapter, c as createSolanaAdapter, k as isEvmWallet, i as isSolanaWallet } from '../types-C_aQh02s.cjs';
3
3
  import '../types-_iT11DL0.cjs';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { e as SolanaAdapter, f as EvmAdapter, C as ChainAdapter } from '../types-YQlJI5E3.js';
2
- export { q as ARBITRUM_ONE, s as AVALANCHE, A as AdapterConfig, B as BASE_MAINNET, p as BASE_SEPOLIA, l as BSC_MAINNET, o as BSC_STABLECOIN_ADDRESSES, n as BSC_USDC, m as BSC_USDT, d as BalanceInfo, v as ETHEREUM_MAINNET, E as EvmWallet, G as GenericWallet, O as OPTIMISM, P as PERMIT2_ADDRESS, r as POLYGON, t as SKALE_BASE, u as SKALE_BASE_SEPOLIA, h as SOLANA_DEVNET, b as SOLANA_MAINNET, j as SOLANA_TESTNET, g as SignedTransaction, S as SolanaWallet, U as USDC_ADDRESSES, W as WalletSet, X as X402_EXACT_PERMIT2_PROXY, a as createEvmAdapter, c as createSolanaAdapter, k as isEvmWallet, i as isSolanaWallet } from '../types-YQlJI5E3.js';
1
+ import { e as SolanaAdapter, f as EvmAdapter, C as ChainAdapter } from '../types-DBS0XOsH.js';
2
+ export { q as ARBITRUM_ONE, s as AVALANCHE, A as AdapterConfig, B as BASE_MAINNET, p as BASE_SEPOLIA, l as BSC_MAINNET, o as BSC_STABLECOIN_ADDRESSES, n as BSC_USDC, m as BSC_USDT, d as BalanceInfo, v as ETHEREUM_MAINNET, E as EvmWallet, G as GenericWallet, O as OPTIMISM, P as PERMIT2_ADDRESS, r as POLYGON, t as SKALE_BASE, u as SKALE_BASE_SEPOLIA, h as SOLANA_DEVNET, b as SOLANA_MAINNET, j as SOLANA_TESTNET, g as SignedTransaction, S as SolanaWallet, U as USDC_ADDRESSES, W as WalletSet, X as X402_EXACT_PERMIT2_PROXY, a as createEvmAdapter, c as createSolanaAdapter, k as isEvmWallet, i as isSolanaWallet } from '../types-DBS0XOsH.js';
3
3
  import '../types-_iT11DL0.js';
4
4
 
5
5
  /**
@@ -606,21 +606,51 @@ var EvmAdapter = class {
606
606
  });
607
607
  const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
608
608
  const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
609
+ let approvalExtension;
609
610
  if (currentAllowance < BigInt(amount)) {
610
- if (!wallet.sendTransaction) {
611
+ const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
612
+ if (wallet.signTransaction) {
613
+ this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
614
+ const chainId2 = this.getChainId(accept.network);
615
+ const gasPrice = await this.readGasPrice(url);
616
+ const nonce2 = await this.readNonce(url, wallet.address);
617
+ const signedTx = await wallet.signTransaction({
618
+ to: asset,
619
+ data: approveData,
620
+ chainId: chainId2,
621
+ gas: 50000n,
622
+ // standard ERC-20 approve
623
+ gasPrice,
624
+ nonce: nonce2
625
+ });
626
+ approvalExtension = {
627
+ erc20ApprovalGasSponsoring: {
628
+ info: {
629
+ from: wallet.address,
630
+ asset,
631
+ spender: PERMIT2_ADDRESS,
632
+ amount: MAX_UINT256.toString(),
633
+ signedTransaction: signedTx,
634
+ version: "1"
635
+ }
636
+ }
637
+ };
638
+ this.log("Permit2 approval signed for facilitator relay");
639
+ } else if (wallet.sendTransaction) {
640
+ this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
641
+ const approveTxHash = await wallet.sendTransaction({
642
+ to: asset,
643
+ data: approveData,
644
+ value: 0n
645
+ });
646
+ this.log(`Permit2 approval tx sent: ${approveTxHash}`);
647
+ await this.waitForReceipt(url, approveTxHash);
648
+ this.log("Permit2 approval confirmed");
649
+ } else {
611
650
  throw new Error(
612
- "Permit2 payments require a wallet that supports sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
651
+ "Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
613
652
  );
614
653
  }
615
- this.log(`Approving Permit2 for ${asset} (current allowance: ${currentAllowance})`);
616
- const approveTxHash = await wallet.sendTransaction({
617
- to: asset,
618
- data: this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256),
619
- value: 0n
620
- });
621
- this.log(`Permit2 approval tx sent: ${approveTxHash}`);
622
- await this.waitForReceipt(url, approveTxHash);
623
- this.log("Permit2 approval confirmed");
624
654
  } else {
625
655
  this.log("Sufficient Permit2 allowance, skipping approval");
626
656
  }
@@ -675,7 +705,8 @@ var EvmAdapter = class {
675
705
  };
676
706
  return {
677
707
  serialized: JSON.stringify(payload),
678
- signature
708
+ signature,
709
+ extensions: approvalExtension
679
710
  };
680
711
  }
681
712
  /**
@@ -744,6 +775,43 @@ var EvmAdapter = class {
744
775
  }
745
776
  throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
746
777
  }
778
+ /**
779
+ * Read gas price via eth_gasPrice RPC call.
780
+ */
781
+ async readGasPrice(rpcUrl) {
782
+ try {
783
+ const response = await fetch(rpcUrl, {
784
+ method: "POST",
785
+ headers: { "Content-Type": "application/json" },
786
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
787
+ });
788
+ const result = await response.json();
789
+ return result.result ? BigInt(result.result) : 50000000n;
790
+ } catch {
791
+ return 50000000n;
792
+ }
793
+ }
794
+ /**
795
+ * Read transaction count (nonce) via eth_getTransactionCount RPC call.
796
+ */
797
+ async readNonce(rpcUrl, address) {
798
+ try {
799
+ const response = await fetch(rpcUrl, {
800
+ method: "POST",
801
+ headers: { "Content-Type": "application/json" },
802
+ body: JSON.stringify({
803
+ jsonrpc: "2.0",
804
+ id: 1,
805
+ method: "eth_getTransactionCount",
806
+ params: [address, "latest"]
807
+ })
808
+ });
809
+ const result = await response.json();
810
+ return result.result ? parseInt(result.result, 16) : 0;
811
+ } catch {
812
+ return 0;
813
+ }
814
+ }
747
815
  /**
748
816
  * Calculate how much to approve based on the facilitator's approval strategy.
749
817
  * Buffered approvals reduce the number of on-chain approval txs for micropayments.
@@ -191,6 +191,7 @@ __export(client_exports, {
191
191
  SOLANA_MAINNET: () => SOLANA_MAINNET,
192
192
  USDC_MINT: () => USDC_MINT,
193
193
  X402Error: () => X402Error,
194
+ capabilitySearch: () => capabilitySearch,
194
195
  createBudgetAccount: () => createBudgetAccount,
195
196
  createEvmAdapter: () => createEvmAdapter,
196
197
  createEvmKeypairWallet: () => createEvmKeypairWallet,
@@ -203,7 +204,6 @@ __export(client_exports, {
203
204
  getSponsoredRecommendations: () => getSponsoredRecommendations,
204
205
  isEvmKeypairWallet: () => isEvmKeypairWallet,
205
206
  isKeypairWallet: () => isKeypairWallet,
206
- searchAPIs: () => searchAPIs,
207
207
  wrapFetch: () => wrapFetch
208
208
  });
209
209
  module.exports = __toCommonJS(client_exports);
@@ -820,21 +820,51 @@ var EvmAdapter = class {
820
820
  });
821
821
  const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
822
822
  const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
823
+ let approvalExtension;
823
824
  if (currentAllowance < BigInt(amount)) {
824
- if (!wallet.sendTransaction) {
825
+ const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
826
+ if (wallet.signTransaction) {
827
+ this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
828
+ const chainId2 = this.getChainId(accept.network);
829
+ const gasPrice = await this.readGasPrice(url);
830
+ const nonce2 = await this.readNonce(url, wallet.address);
831
+ const signedTx = await wallet.signTransaction({
832
+ to: asset,
833
+ data: approveData,
834
+ chainId: chainId2,
835
+ gas: 50000n,
836
+ // standard ERC-20 approve
837
+ gasPrice,
838
+ nonce: nonce2
839
+ });
840
+ approvalExtension = {
841
+ erc20ApprovalGasSponsoring: {
842
+ info: {
843
+ from: wallet.address,
844
+ asset,
845
+ spender: PERMIT2_ADDRESS,
846
+ amount: MAX_UINT256.toString(),
847
+ signedTransaction: signedTx,
848
+ version: "1"
849
+ }
850
+ }
851
+ };
852
+ this.log("Permit2 approval signed for facilitator relay");
853
+ } else if (wallet.sendTransaction) {
854
+ this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
855
+ const approveTxHash = await wallet.sendTransaction({
856
+ to: asset,
857
+ data: approveData,
858
+ value: 0n
859
+ });
860
+ this.log(`Permit2 approval tx sent: ${approveTxHash}`);
861
+ await this.waitForReceipt(url, approveTxHash);
862
+ this.log("Permit2 approval confirmed");
863
+ } else {
825
864
  throw new Error(
826
- "Permit2 payments require a wallet that supports sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
865
+ "Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
827
866
  );
828
867
  }
829
- this.log(`Approving Permit2 for ${asset} (current allowance: ${currentAllowance})`);
830
- const approveTxHash = await wallet.sendTransaction({
831
- to: asset,
832
- data: this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256),
833
- value: 0n
834
- });
835
- this.log(`Permit2 approval tx sent: ${approveTxHash}`);
836
- await this.waitForReceipt(url, approveTxHash);
837
- this.log("Permit2 approval confirmed");
838
868
  } else {
839
869
  this.log("Sufficient Permit2 allowance, skipping approval");
840
870
  }
@@ -889,7 +919,8 @@ var EvmAdapter = class {
889
919
  };
890
920
  return {
891
921
  serialized: JSON.stringify(payload),
892
- signature
922
+ signature,
923
+ extensions: approvalExtension
893
924
  };
894
925
  }
895
926
  /**
@@ -958,6 +989,43 @@ var EvmAdapter = class {
958
989
  }
959
990
  throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
960
991
  }
992
+ /**
993
+ * Read gas price via eth_gasPrice RPC call.
994
+ */
995
+ async readGasPrice(rpcUrl) {
996
+ try {
997
+ const response = await fetch(rpcUrl, {
998
+ method: "POST",
999
+ headers: { "Content-Type": "application/json" },
1000
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
1001
+ });
1002
+ const result = await response.json();
1003
+ return result.result ? BigInt(result.result) : 50000000n;
1004
+ } catch {
1005
+ return 50000000n;
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Read transaction count (nonce) via eth_getTransactionCount RPC call.
1010
+ */
1011
+ async readNonce(rpcUrl, address) {
1012
+ try {
1013
+ const response = await fetch(rpcUrl, {
1014
+ method: "POST",
1015
+ headers: { "Content-Type": "application/json" },
1016
+ body: JSON.stringify({
1017
+ jsonrpc: "2.0",
1018
+ id: 1,
1019
+ method: "eth_getTransactionCount",
1020
+ params: [address, "latest"]
1021
+ })
1022
+ });
1023
+ const result = await response.json();
1024
+ return result.result ? parseInt(result.result, 16) : 0;
1025
+ } catch {
1026
+ return 0;
1027
+ }
1028
+ }
961
1029
  /**
962
1030
  * Calculate how much to approve based on the facilitator's approval strategy.
963
1031
  * Buffered approvals reduce the number of on-chain approval txs for micropayments.
@@ -1219,6 +1287,9 @@ function createX402Client(config) {
1219
1287
  accepted: accept,
1220
1288
  payload
1221
1289
  };
1290
+ if (signedTx.extensions) {
1291
+ paymentSignature.extensions = signedTx.extensions;
1292
+ }
1222
1293
  const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
1223
1294
  const passResponse = await customFetch(passUrl, {
1224
1295
  ...init,
@@ -1397,6 +1468,9 @@ function createX402Client(config) {
1397
1468
  accepted: accept,
1398
1469
  payload
1399
1470
  };
1471
+ if (signedTx.extensions) {
1472
+ paymentSignature.extensions = signedTx.extensions;
1473
+ }
1400
1474
  const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
1401
1475
  log("Retrying request with payment...");
1402
1476
  const retryResponse = await fetchWithRetry(input, {
@@ -1525,7 +1599,16 @@ async function createEvmKeypairWallet(privateKey) {
1525
1599
  const account = privateKeyToAccount(normalizedKey);
1526
1600
  return {
1527
1601
  address: account.address,
1528
- signTypedData: (params) => account.signTypedData(params)
1602
+ signTypedData: (params) => account.signTypedData(params),
1603
+ signTransaction: (params) => account.signTransaction({
1604
+ to: params.to,
1605
+ data: params.data,
1606
+ chainId: params.chainId,
1607
+ gas: params.gas,
1608
+ gasPrice: params.gasPrice,
1609
+ nonce: params.nonce,
1610
+ type: "legacy"
1611
+ })
1529
1612
  };
1530
1613
  }
1531
1614
  function isEvmKeypairWallet(wallet) {
@@ -1592,55 +1675,84 @@ function wrapFetch(fetchImpl, options) {
1592
1675
  }
1593
1676
 
1594
1677
  // src/client/discovery.ts
1595
- var DEFAULT_MARKETPLACE = "https://x402.dexter.cash/api/facilitator/marketplace/resources";
1596
- async function searchAPIs(options = {}) {
1678
+ var DEFAULT_CAPABILITY_ENDPOINT = "https://x402.dexter.cash/api/x402gle/capability";
1679
+ function formatPriceLabel(priceUsdc) {
1680
+ if (priceUsdc == null) return "price on request";
1681
+ if (priceUsdc === 0) return "free";
1682
+ if (priceUsdc < 0.01) return `$${priceUsdc.toFixed(4)}`;
1683
+ return `$${priceUsdc.toFixed(2)}`;
1684
+ }
1685
+ function mapResult(r) {
1686
+ return {
1687
+ resourceId: r.resourceId,
1688
+ name: r.displayName ?? r.resourceUrl,
1689
+ url: r.resourceUrl,
1690
+ method: r.method || "GET",
1691
+ price: formatPriceLabel(r.pricing.usdc),
1692
+ priceUsdc: r.pricing.usdc,
1693
+ network: r.pricing.network,
1694
+ description: r.description ?? "",
1695
+ category: r.category ?? "uncategorized",
1696
+ qualityScore: r.verification.qualityScore,
1697
+ verified: r.verification.status === "pass",
1698
+ verificationStatus: r.verification.status,
1699
+ totalCalls: r.usage.totalSettlements,
1700
+ totalVolumeUsdc: r.usage.totalVolumeUsdc,
1701
+ iconUrl: r.icon,
1702
+ host: r.host,
1703
+ gamingFlags: r.gaming.flags,
1704
+ gamingSuspicious: r.gaming.suspicious,
1705
+ tier: r.tier,
1706
+ similarity: Math.round(r.similarity * 1e3) / 1e3,
1707
+ why: r.why,
1708
+ score: r.score
1709
+ };
1710
+ }
1711
+ async function capabilitySearch(options) {
1712
+ if (!options?.query || !options.query.trim()) {
1713
+ throw new Error("capabilitySearch: query is required");
1714
+ }
1597
1715
  const {
1598
1716
  query,
1599
- category,
1600
- network,
1601
- maxPrice,
1602
- verifiedOnly,
1603
- sort = "marketplace",
1604
1717
  limit = 20,
1605
- marketplaceUrl = DEFAULT_MARKETPLACE
1718
+ unverified,
1719
+ testnets,
1720
+ rerank,
1721
+ endpoint = DEFAULT_CAPABILITY_ENDPOINT
1606
1722
  } = options;
1607
1723
  const params = new URLSearchParams();
1608
- if (query) params.set("search", query);
1609
- if (category) params.set("category", category);
1610
- if (network) params.set("network", network);
1611
- if (maxPrice !== void 0) params.set("maxPrice", String(maxPrice));
1612
- if (verifiedOnly) params.set("verified", "true");
1613
- params.set("sort", sort);
1614
- params.set("order", "desc");
1615
- params.set("limit", String(Math.min(limit, 50)));
1616
- const url = `${marketplaceUrl}?${params.toString()}`;
1724
+ params.set("q", query);
1725
+ params.set("limit", String(Math.min(Math.max(limit, 1), 50)));
1726
+ if (unverified) params.set("unverified", "true");
1727
+ if (testnets) params.set("testnets", "true");
1728
+ if (rerank === false) params.set("rerank", "false");
1729
+ const url = `${endpoint}?${params.toString()}`;
1617
1730
  const response = await fetch(url, {
1618
- headers: { "Accept": "application/json" },
1619
- signal: AbortSignal.timeout(15e3)
1731
+ headers: { Accept: "application/json" },
1732
+ signal: AbortSignal.timeout(2e4)
1620
1733
  });
1621
1734
  if (!response.ok) {
1622
- throw new Error(`Marketplace search failed: ${response.status}`);
1735
+ const body = await response.text().catch(() => "");
1736
+ throw new Error(`Capability search failed: ${response.status} ${body.slice(0, 400)}`);
1623
1737
  }
1624
1738
  const data = await response.json();
1625
- if (!data.resources) return [];
1626
- return data.resources.map((r) => ({
1627
- name: r.displayName || r.resourceUrl,
1628
- url: r.resourceUrl,
1629
- method: r.method || "GET",
1630
- price: r.priceLabel || (r.priceUsdc ? `$${r.priceUsdc.toFixed(4)}` : "free"),
1631
- priceUsdc: r.priceUsdc ?? null,
1632
- network: r.priceNetwork ?? null,
1633
- description: r.description || "",
1634
- category: r.category || "uncategorized",
1635
- qualityScore: r.qualityScore ?? null,
1636
- verified: r.verificationStatus === "pass",
1637
- totalCalls: r.totalSettlements || 0,
1638
- totalVolume: r.totalVolumeUsdc ? `$${r.totalVolumeUsdc.toLocaleString("en-US", { minimumFractionDigits: 2 })}` : null,
1639
- seller: r.seller?.displayName ?? null,
1640
- sellerReputation: r.reputationScore ?? null,
1641
- authRequired: r.authRequired || false,
1642
- lastActive: r.lastSettlementAt ?? null
1643
- }));
1739
+ if (!data.ok) {
1740
+ throw new Error(
1741
+ `Capability search error${data.stage ? ` at stage ${data.stage}` : ""}: ${data.error ?? "unknown"}`
1742
+ );
1743
+ }
1744
+ return {
1745
+ query: data.query,
1746
+ strongResults: data.strongResults.map(mapResult),
1747
+ relatedResults: data.relatedResults.map(mapResult),
1748
+ strongCount: data.strongCount,
1749
+ relatedCount: data.relatedCount,
1750
+ topSimilarity: data.topSimilarity,
1751
+ noMatchReason: data.noMatchReason,
1752
+ rerank: data.rerank,
1753
+ intent: data.intent,
1754
+ durationMs: data.durationMs
1755
+ };
1644
1756
  }
1645
1757
 
1646
1758
  // src/client/budget-account.ts
@@ -1778,6 +1890,7 @@ async function fireImpressionBeacon(response) {
1778
1890
  SOLANA_MAINNET,
1779
1891
  USDC_MINT,
1780
1892
  X402Error,
1893
+ capabilitySearch,
1781
1894
  createBudgetAccount,
1782
1895
  createEvmAdapter,
1783
1896
  createEvmKeypairWallet,
@@ -1790,6 +1903,5 @@ async function fireImpressionBeacon(response) {
1790
1903
  getSponsoredRecommendations,
1791
1904
  isEvmKeypairWallet,
1792
1905
  isKeypairWallet,
1793
- searchAPIs,
1794
1906
  wrapFetch
1795
1907
  });