@dexterai/x402 1.0.3 → 1.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 +185 -160
- package/dist/client/index.cjs +7 -1
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.js +7 -1
- package/dist/client/index.js.map +1 -1
- package/dist/react/index.cjs +7 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +7 -1
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +88 -2
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +105 -1
- package/dist/server/index.d.ts +105 -1
- package/dist/server/index.js +85 -1
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types.ts","../../src/utils.ts","../../src/server/facilitator-client.ts","../../src/server/x402-server.ts"],"sourcesContent":["/**\n * x402 v2 SDK — Shared Types\n *\n * Chain-agnostic types for x402 v2 payments.\n * Works with Solana, Base, and any future x402-compatible networks.\n */\n\n// ============================================================================\n// Network Constants\n// ============================================================================\n\n/** CAIP-2 network identifier for Solana mainnet */\nexport const SOLANA_MAINNET_NETWORK = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/** CAIP-2 network identifier for Base mainnet */\nexport const BASE_MAINNET_NETWORK = 'eip155:8453';\n\n/** Alias for Solana mainnet */\nexport const SOLANA_MAINNET = SOLANA_MAINNET_NETWORK;\n\n/** Alias for Base mainnet */\nexport const BASE_MAINNET = BASE_MAINNET_NETWORK;\n\n// ============================================================================\n// Asset Constants\n// ============================================================================\n\n/** USDC mint on Solana mainnet */\nexport const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';\n\n/** USDC address on Base mainnet */\nexport const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';\n\n// ============================================================================\n// Facilitator Constants\n// ============================================================================\n\n/** Dexter's public x402 v2 facilitator URL */\nexport const DEXTER_FACILITATOR_URL = 'https://x402.dexter.cash';\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\n/**\n * Asset configuration for payments\n */\nexport interface AssetConfig {\n /** Token address (mint on Solana, contract on EVM) */\n address: string;\n /** Token decimals */\n decimals: number;\n /** Optional: Human-readable symbol */\n symbol?: string;\n}\n\n/**\n * Resource info included in payment requirements\n */\nexport interface ResourceInfo {\n /** Resource URL */\n url: string;\n /** Human-readable description */\n description?: string;\n /** MIME type of the resource */\n mimeType?: string;\n}\n\n/**\n * Extra fields in payment requirements\n * Chain-specific fields may vary\n */\nexport interface AcceptsExtra {\n /** Facilitator address that pays tx fees (required) */\n feePayer: string;\n /** Token decimals (required) */\n decimals: number;\n /** EIP-712: Token name (EVM only) */\n name?: string;\n /** EIP-712: Token version (EVM only) */\n version?: string;\n /** Additional chain-specific fields */\n [key: string]: unknown;\n}\n\n/**\n * A single payment option in the accepts array\n */\nexport interface PaymentAccept {\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier */\n network: string;\n /** Payment amount in atomic units (as string to avoid precision loss) */\n amount: string;\n /** Token address */\n asset: string;\n /** Seller's address to receive payment */\n payTo: string;\n /** Maximum seconds until payment expires */\n maxTimeoutSeconds: number;\n /** Chain-specific extra data */\n extra: AcceptsExtra;\n}\n\n/**\n * Full PaymentRequired structure (sent in PAYMENT-REQUIRED header)\n */\nexport interface PaymentRequired {\n /** x402 version (always 2) */\n x402Version: 2;\n /** Resource being accessed */\n resource: ResourceInfo;\n /** Available payment options */\n accepts: PaymentAccept[];\n /** Optional error message */\n error?: string;\n}\n\n/**\n * PaymentSignature structure (sent in PAYMENT-SIGNATURE header)\n */\nexport interface PaymentSignature {\n /** x402 version (always 2) */\n x402Version: 2;\n /** Resource being accessed */\n resource: ResourceInfo;\n /** The payment option that was accepted */\n accepted: PaymentAccept;\n /** The signed payment */\n payload: {\n /** Signed transaction (base64 for Solana, JSON for EVM) */\n transaction: string;\n };\n}\n\n// ============================================================================\n// Facilitator Response Types\n// ============================================================================\n\n/**\n * Response from /verify endpoint\n */\nexport interface VerifyResponse {\n /** Whether the payment is valid */\n isValid: boolean;\n /** Reason for invalidity (if invalid) */\n invalidReason?: string;\n /** Payer address */\n payer?: string;\n}\n\n/**\n * Response from /settle endpoint\n */\nexport interface SettleResponse {\n /** Whether settlement succeeded */\n success: boolean;\n /** Transaction signature/hash */\n transaction?: string;\n /** Network the payment was made on */\n network: string;\n /** Error reason (if failed) */\n errorReason?: string;\n /** Error code (if failed) */\n errorCode?: string;\n /** Payer address */\n payer?: string;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * SDK error codes\n */\nexport type X402ErrorCode =\n // Client errors\n | 'missing_payment_required_header'\n | 'invalid_payment_required'\n | 'unsupported_network'\n | 'no_matching_payment_option'\n | 'no_solana_accept' // Legacy, kept for compatibility\n | 'missing_fee_payer'\n | 'missing_decimals'\n | 'amount_exceeds_max'\n | 'insufficient_balance'\n | 'wallet_missing_sign_transaction'\n | 'wallet_not_connected'\n | 'transaction_build_failed'\n | 'payment_rejected'\n // Server errors\n | 'invalid_payment_signature'\n | 'facilitator_verify_failed'\n | 'facilitator_settle_failed'\n | 'facilitator_request_failed'\n | 'no_matching_requirement';\n\n/**\n * Custom error class for x402 operations\n */\nexport class X402Error extends Error {\n /** Error code for programmatic handling */\n code: X402ErrorCode;\n /** Additional error details */\n details?: unknown;\n\n constructor(code: X402ErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'X402Error';\n this.code = code;\n this.details = details;\n // Maintain proper prototype chain\n Object.setPrototypeOf(this, X402Error.prototype);\n }\n}\n","/**\n * Utility Functions\n *\n * Chain-agnostic helpers for x402 payments.\n */\n\nimport { SOLANA_MAINNET_NETWORK, BASE_MAINNET_NETWORK } from './types';\n\n// ============================================================================\n// Amount Conversion\n// ============================================================================\n\n/**\n * Convert human-readable amount to atomic units\n *\n * @param amount - Human-readable amount (e.g., 0.05 for $0.05)\n * @param decimals - Token decimals (e.g., 6 for USDC)\n * @returns Amount in atomic units as string\n *\n * @example\n * ```typescript\n * toAtomicUnits(0.05, 6) // '50000'\n * toAtomicUnits(1.50, 6) // '1500000'\n * ```\n */\nexport function toAtomicUnits(amount: number, decimals: number): string {\n const multiplier = Math.pow(10, decimals);\n return Math.floor(amount * multiplier).toString();\n}\n\n/**\n * Convert atomic units to human-readable amount\n *\n * @param atomicUnits - Amount in smallest units\n * @param decimals - Token decimals\n * @returns Human-readable amount\n *\n * @example\n * ```typescript\n * fromAtomicUnits('50000', 6) // 0.05\n * fromAtomicUnits(1500000n, 6) // 1.5\n * ```\n */\nexport function fromAtomicUnits(\n atomicUnits: string | bigint | number,\n decimals: number\n): number {\n const divisor = Math.pow(10, decimals);\n return Number(atomicUnits) / divisor;\n}\n\n// ============================================================================\n// Network Helpers\n// ============================================================================\n\n/**\n * Network type\n */\nexport type ChainFamily = 'solana' | 'evm' | 'unknown';\n\n/**\n * Get the chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier\n * @returns Chain family\n *\n * @example\n * ```typescript\n * getChainFamily('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') // 'solana'\n * getChainFamily('eip155:8453') // 'evm'\n * ```\n */\nexport function getChainFamily(network: string): ChainFamily {\n if (network.startsWith('solana:') || network === 'solana') {\n return 'solana';\n }\n if (network.startsWith('eip155:') || ['base', 'ethereum', 'arbitrum'].includes(network)) {\n return 'evm';\n }\n return 'unknown';\n}\n\n/**\n * Get default RPC URL for a network\n *\n * @param network - CAIP-2 network identifier\n * @returns Default RPC URL\n */\nexport function getDefaultRpcUrl(network: string): string {\n const family = getChainFamily(network);\n\n if (family === 'solana') {\n if (network.includes('devnet') || network === 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1') {\n return 'https://api.devnet.solana.com';\n }\n if (network.includes('testnet') || network === 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z') {\n return 'https://api.testnet.solana.com';\n }\n return 'https://api.mainnet-beta.solana.com';\n }\n\n if (family === 'evm') {\n // Extract chain ID from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainId = network.split(':')[1];\n switch (chainId) {\n case '8453': return 'https://mainnet.base.org';\n case '84532': return 'https://sepolia.base.org';\n case '1': return 'https://eth.llamarpc.com';\n case '42161': return 'https://arb1.arbitrum.io/rpc';\n default: return 'https://mainnet.base.org';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://mainnet.base.org';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://mainnet.base.org';\n }\n\n // Unknown - return a generic\n return 'https://api.mainnet-beta.solana.com';\n}\n\n/**\n * Get human-readable chain name\n *\n * @param network - CAIP-2 network identifier\n * @returns Human-readable name\n */\nexport function getChainName(network: string): string {\n const mapping: Record<string, string> = {\n [SOLANA_MAINNET_NETWORK]: 'Solana',\n 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': 'Solana Devnet',\n 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z': 'Solana Testnet',\n 'solana': 'Solana',\n [BASE_MAINNET_NETWORK]: 'Base',\n 'eip155:84532': 'Base Sepolia',\n 'eip155:1': 'Ethereum',\n 'eip155:42161': 'Arbitrum One',\n 'base': 'Base',\n 'ethereum': 'Ethereum',\n 'arbitrum': 'Arbitrum',\n };\n return mapping[network] || network;\n}\n\n// ============================================================================\n// Transaction URL Helpers\n// ============================================================================\n\n/**\n * Get explorer URL for a transaction\n *\n * @param txSignature - Transaction signature/hash\n * @param network - CAIP-2 network identifier\n * @returns Explorer URL\n */\nexport function getExplorerUrl(txSignature: string, network: string): string {\n const family = getChainFamily(network);\n\n if (family === 'solana') {\n const isDevnet = network.includes('devnet') || network === 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\n if (isDevnet) {\n return `https://solscan.io/tx/${txSignature}?cluster=devnet`;\n }\n // Prefer Orb Markets for mainnet\n return `https://www.orbmarkets.io/tx/${txSignature}`;\n }\n\n if (family === 'evm') {\n // Extract chain ID\n let chainId = '8453'; // Default to Base\n if (network.startsWith('eip155:')) {\n chainId = network.split(':')[1];\n } else if (network === 'ethereum') {\n chainId = '1';\n } else if (network === 'arbitrum') {\n chainId = '42161';\n }\n\n switch (chainId) {\n case '8453': return `https://basescan.org/tx/${txSignature}`;\n case '84532': return `https://sepolia.basescan.org/tx/${txSignature}`;\n case '1': return `https://etherscan.io/tx/${txSignature}`;\n case '42161': return `https://arbiscan.io/tx/${txSignature}`;\n default: return `https://basescan.org/tx/${txSignature}`;\n }\n }\n\n return `https://solscan.io/tx/${txSignature}`;\n}\n\n// ============================================================================\n// Encoding Helpers\n// ============================================================================\n\n/**\n * Encode an object as base64 JSON\n */\nexport function encodeBase64Json(obj: unknown): string {\n return btoa(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(atob(encoded)) as T;\n}\n","/**\n * Facilitator Client\n *\n * Communicates with the x402 facilitator for:\n * - /supported - Get supported payment schemes and fee payer addresses\n * - /verify - Verify a payment signature before processing\n * - /settle - Submit the payment for execution\n *\n * Works with any x402 v2 facilitator (Dexter or others).\n */\n\nimport type { PaymentAccept, PaymentSignature, VerifyResponse, SettleResponse } from '../types';\nimport { DEXTER_FACILITATOR_URL } from '../types';\nimport { decodeBase64Json } from '../utils';\n\n/**\n * Supported payment kind from facilitator /supported endpoint\n */\nexport interface SupportedKind {\n x402Version: number;\n scheme: string;\n network: string;\n extra?: {\n feePayer?: string;\n decimals?: number;\n name?: string;\n version?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Response from facilitator /supported endpoint\n */\nexport interface SupportedResponse {\n kinds: SupportedKind[];\n}\n\n/**\n * Client for communicating with an x402 v2 facilitator\n */\nexport class FacilitatorClient {\n private facilitatorUrl: string;\n private cachedSupported: SupportedResponse | null = null;\n private cacheTime: number = 0;\n private readonly CACHE_TTL_MS = 60_000; // 1 minute cache\n\n constructor(facilitatorUrl: string = DEXTER_FACILITATOR_URL) {\n this.facilitatorUrl = facilitatorUrl.replace(/\\/$/, ''); // Remove trailing slash\n }\n\n /**\n * Get supported payment kinds from the facilitator\n * Results are cached for 1 minute to reduce network calls\n */\n async getSupported(): Promise<SupportedResponse> {\n const now = Date.now();\n if (this.cachedSupported && now - this.cacheTime < this.CACHE_TTL_MS) {\n return this.cachedSupported;\n }\n\n const response = await fetch(`${this.facilitatorUrl}/supported`);\n if (!response.ok) {\n throw new Error(`Facilitator /supported returned ${response.status}`);\n }\n\n this.cachedSupported = (await response.json()) as SupportedResponse;\n this.cacheTime = now;\n return this.cachedSupported;\n }\n\n /**\n * Get the fee payer address for a specific network\n *\n * @param network - CAIP-2 network identifier\n * @returns Fee payer address\n */\n async getFeePayer(network: string): Promise<string> {\n const supported = await this.getSupported();\n\n // Find matching network support (exact match or v2)\n const kind = supported.kinds.find(\n (k) =>\n k.x402Version === 2 &&\n k.scheme === 'exact' &&\n k.network === network\n );\n\n if (!kind?.extra?.feePayer) {\n throw new Error(\n `Facilitator does not support network \"${network}\" with scheme \"exact\", or feePayer not provided`\n );\n }\n\n return kind.extra.feePayer;\n }\n\n /**\n * Get extra data for a network (feePayer, decimals, EIP-712 data, etc.)\n *\n * @param network - CAIP-2 network identifier\n * @returns Extra data from /supported\n */\n async getNetworkExtra(network: string): Promise<SupportedKind['extra']> {\n const supported = await this.getSupported();\n\n const kind = supported.kinds.find(\n (k) =>\n k.x402Version === 2 &&\n k.scheme === 'exact' &&\n k.network === network\n );\n\n return kind?.extra;\n }\n\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value\n * @param requirements - The payment requirements that were sent to the client\n * @returns Verification response\n */\n async verifyPayment(\n paymentSignatureHeader: string,\n requirements: PaymentAccept\n ): Promise<VerifyResponse> {\n try {\n const paymentPayload = decodeBase64Json<PaymentSignature>(paymentSignatureHeader);\n\n const verifyPayload = {\n paymentPayload,\n paymentRequirements: requirements,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(verifyPayload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Facilitator /verify returned ${response.status}:`, errorText);\n return {\n isValid: false,\n invalidReason: `facilitator_error_${response.status}`,\n };\n }\n\n return (await response.json()) as VerifyResponse;\n } catch (error) {\n console.error('Payment verification failed:', error);\n return {\n isValid: false,\n invalidReason: error instanceof Error ? error.message : 'unexpected_verify_error',\n };\n }\n }\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value\n * @param requirements - The payment requirements that were sent to the client\n * @returns Settlement response with transaction signature on success\n */\n async settlePayment(\n paymentSignatureHeader: string,\n requirements: PaymentAccept\n ): Promise<SettleResponse> {\n try {\n const paymentPayload = decodeBase64Json<PaymentSignature>(paymentSignatureHeader);\n\n const settlePayload = {\n paymentPayload,\n paymentRequirements: requirements,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/settle`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(settlePayload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Facilitator /settle returned ${response.status}:`, errorText);\n return {\n success: false,\n network: requirements.network,\n errorReason: `facilitator_error_${response.status}`,\n };\n }\n\n const result = (await response.json()) as SettleResponse;\n return {\n ...result,\n network: requirements.network,\n };\n } catch (error) {\n console.error('Payment settlement failed:', error);\n return {\n success: false,\n network: requirements.network,\n errorReason: error instanceof Error ? error.message : 'unexpected_settle_error',\n };\n }\n }\n}\n","/**\n * x402 v2 Server\n *\n * Server-side helpers for accepting x402 payments.\n * Chain-agnostic - works with Solana, Base, and any x402-compatible network.\n *\n * @example\n * ```typescript\n * import { createX402Server } from '@dexterai/x402/server';\n *\n * const server = createX402Server({\n * payTo: 'YourAddress...',\n * network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n * });\n *\n * // Handle 402 responses\n * if (!paymentSignature) {\n * const requirements = await server.buildRequirements({\n * amountAtomic: '50000',\n * resourceUrl: '/api/protected',\n * });\n * res.setHeader('PAYMENT-REQUIRED', server.encodeRequirements(requirements));\n * res.status(402).json({});\n * return;\n * }\n *\n * // Verify and settle\n * const verify = await server.verifyPayment(paymentSignature);\n * if (!verify.isValid) throw new Error(verify.invalidReason);\n *\n * const settle = await server.settlePayment(paymentSignature);\n * if (!settle.success) throw new Error(settle.errorReason);\n *\n * // Payment successful!\n * res.json({ transaction: settle.transaction });\n * ```\n */\n\nimport type {\n PaymentRequired,\n PaymentAccept,\n ResourceInfo,\n AcceptsExtra,\n VerifyResponse,\n SettleResponse,\n} from '../types';\nimport {\n SOLANA_MAINNET_NETWORK,\n USDC_MINT,\n DEXTER_FACILITATOR_URL,\n} from '../types';\nimport { FacilitatorClient, type SupportedKind } from './facilitator-client';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Asset configuration\n */\nexport interface AssetConfig {\n /** Token address (mint on Solana, contract on EVM) */\n address: string;\n /** Token decimals */\n decimals: number;\n}\n\n/**\n * Server configuration\n */\nexport interface X402ServerConfig {\n /** Address to receive payments */\n payTo: string;\n /** Facilitator URL (defaults to Dexter) */\n facilitatorUrl?: string;\n /** CAIP-2 network identifier */\n network?: string;\n /** Asset configuration (defaults to USDC) */\n asset?: AssetConfig;\n /** Default payment timeout in seconds */\n defaultTimeoutSeconds?: number;\n}\n\n/**\n * Options for building payment requirements\n */\nexport interface BuildRequirementsOptions {\n /** Amount in atomic units (e.g., '50000' for 0.05 USDC) */\n amountAtomic: string;\n /** Full URL of the resource */\n resourceUrl: string;\n /** Human-readable description */\n description?: string;\n /** MIME type of the response */\n mimeType?: string;\n /** Override timeout for this request */\n timeoutSeconds?: number;\n}\n\n/**\n * x402 Server interface\n */\nexport interface X402Server {\n /** Build payment requirements (fetches feePayer from facilitator) */\n buildRequirements(options: BuildRequirementsOptions): Promise<PaymentRequired>;\n\n /** Encode requirements for PAYMENT-REQUIRED header */\n encodeRequirements(requirements: PaymentRequired): string;\n\n /** Create complete 402 response object */\n create402Response(requirements: PaymentRequired): {\n status: 402;\n headers: { 'PAYMENT-REQUIRED': string };\n body: Record<string, unknown>;\n };\n\n /** Verify payment with facilitator */\n verifyPayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<VerifyResponse>;\n\n /** Settle payment via facilitator */\n settlePayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<SettleResponse>;\n\n /** Get PaymentAccept for verify/settle */\n getPaymentAccept(options: BuildRequirementsOptions): Promise<PaymentAccept>;\n\n /** Get network this server is configured for */\n readonly network: string;\n\n /** Get facilitator client for advanced usage */\n readonly facilitator: FacilitatorClient;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Create an x402 server for accepting payments\n */\nexport function createX402Server(config: X402ServerConfig): X402Server {\n const {\n payTo,\n facilitatorUrl = DEXTER_FACILITATOR_URL,\n network = SOLANA_MAINNET_NETWORK,\n asset = { address: USDC_MINT, decimals: 6 },\n defaultTimeoutSeconds = 60,\n } = config;\n\n const facilitator = new FacilitatorClient(facilitatorUrl);\n\n // Cache for network extra data\n let cachedExtra: SupportedKind['extra'] | null = null;\n\n /**\n * Get extra data from facilitator (cached)\n */\n async function getNetworkExtra(): Promise<AcceptsExtra> {\n if (!cachedExtra) {\n cachedExtra = await facilitator.getNetworkExtra(network);\n }\n\n if (!cachedExtra?.feePayer) {\n throw new Error(`Facilitator does not provide feePayer for network \"${network}\"`);\n }\n\n return {\n feePayer: cachedExtra.feePayer,\n decimals: cachedExtra.decimals ?? asset.decimals,\n // Include any additional EIP-712 data for EVM chains\n name: cachedExtra.name,\n version: cachedExtra.version,\n };\n }\n\n /**\n * Build a PaymentAccept structure\n */\n async function getPaymentAccept(options: BuildRequirementsOptions): Promise<PaymentAccept> {\n const {\n amountAtomic,\n timeoutSeconds = defaultTimeoutSeconds,\n } = options;\n\n const extra = await getNetworkExtra();\n\n return {\n scheme: 'exact',\n network,\n amount: amountAtomic,\n asset: asset.address,\n payTo,\n maxTimeoutSeconds: timeoutSeconds,\n extra,\n };\n }\n\n /**\n * Build payment requirements for a 402 response\n */\n async function buildRequirements(options: BuildRequirementsOptions): Promise<PaymentRequired> {\n const {\n resourceUrl,\n description,\n mimeType = 'application/json',\n } = options;\n\n const resource: ResourceInfo = {\n url: resourceUrl,\n description,\n mimeType,\n };\n\n const accept = await getPaymentAccept(options);\n\n return {\n x402Version: 2,\n resource,\n accepts: [accept],\n error: 'Payment required',\n };\n }\n\n /**\n * Encode requirements for PAYMENT-REQUIRED header\n */\n function encodeRequirements(requirements: PaymentRequired): string {\n return btoa(JSON.stringify(requirements));\n }\n\n /**\n * Create complete 402 response object\n */\n function create402Response(requirements: PaymentRequired) {\n return {\n status: 402 as const,\n headers: {\n 'PAYMENT-REQUIRED': encodeRequirements(requirements),\n },\n body: {},\n };\n }\n\n /**\n * Verify payment with facilitator\n */\n async function verifyPayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<VerifyResponse> {\n // If requirements not provided, build default\n const req = requirements || await getPaymentAccept({\n amountAtomic: '0',\n resourceUrl: '',\n });\n\n return facilitator.verifyPayment(paymentSignatureHeader, req);\n }\n\n /**\n * Settle payment via facilitator\n */\n async function settlePayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<SettleResponse> {\n const req = requirements || await getPaymentAccept({\n amountAtomic: '0',\n resourceUrl: '',\n });\n\n return facilitator.settlePayment(paymentSignatureHeader, req);\n }\n\n return {\n buildRequirements,\n encodeRequirements,\n create402Response,\n verifyPayment,\n settlePayment,\n getPaymentAccept,\n network,\n facilitator,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts","../../src/utils.ts","../../src/server/facilitator-client.ts","../../src/server/x402-server.ts","../../src/server/dynamic-pricing.ts"],"sourcesContent":["/**\n * x402 v2 SDK — Shared Types\n *\n * Chain-agnostic types for x402 v2 payments.\n * Works with Solana, Base, and any future x402-compatible networks.\n */\n\n// ============================================================================\n// Network Constants\n// ============================================================================\n\n/** CAIP-2 network identifier for Solana mainnet */\nexport const SOLANA_MAINNET_NETWORK = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/** CAIP-2 network identifier for Base mainnet */\nexport const BASE_MAINNET_NETWORK = 'eip155:8453';\n\n/** Alias for Solana mainnet */\nexport const SOLANA_MAINNET = SOLANA_MAINNET_NETWORK;\n\n/** Alias for Base mainnet */\nexport const BASE_MAINNET = BASE_MAINNET_NETWORK;\n\n// ============================================================================\n// Asset Constants\n// ============================================================================\n\n/** USDC mint on Solana mainnet */\nexport const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';\n\n/** USDC address on Base mainnet */\nexport const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';\n\n// ============================================================================\n// Facilitator Constants\n// ============================================================================\n\n/** Dexter's public x402 v2 facilitator URL */\nexport const DEXTER_FACILITATOR_URL = 'https://x402.dexter.cash';\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\n/**\n * Asset configuration for payments\n */\nexport interface AssetConfig {\n /** Token address (mint on Solana, contract on EVM) */\n address: string;\n /** Token decimals */\n decimals: number;\n /** Optional: Human-readable symbol */\n symbol?: string;\n}\n\n/**\n * Resource info included in payment requirements\n */\nexport interface ResourceInfo {\n /** Resource URL */\n url: string;\n /** Human-readable description */\n description?: string;\n /** MIME type of the resource */\n mimeType?: string;\n}\n\n/**\n * Extra fields in payment requirements\n * Chain-specific fields may vary\n */\nexport interface AcceptsExtra {\n /** Facilitator address that pays tx fees (required) */\n feePayer: string;\n /** Token decimals (required) */\n decimals: number;\n /** EIP-712: Token name (EVM only) */\n name?: string;\n /** EIP-712: Token version (EVM only) */\n version?: string;\n /** Additional chain-specific fields */\n [key: string]: unknown;\n}\n\n/**\n * A single payment option in the accepts array\n */\nexport interface PaymentAccept {\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier */\n network: string;\n /** Payment amount in atomic units (as string to avoid precision loss) */\n amount: string;\n /** Token address */\n asset: string;\n /** Seller's address to receive payment */\n payTo: string;\n /** Maximum seconds until payment expires */\n maxTimeoutSeconds: number;\n /** Chain-specific extra data */\n extra: AcceptsExtra;\n}\n\n/**\n * Full PaymentRequired structure (sent in PAYMENT-REQUIRED header)\n */\nexport interface PaymentRequired {\n /** x402 version (always 2) */\n x402Version: 2;\n /** Resource being accessed */\n resource: ResourceInfo;\n /** Available payment options */\n accepts: PaymentAccept[];\n /** Optional error message */\n error?: string;\n}\n\n/**\n * PaymentSignature structure (sent in PAYMENT-SIGNATURE header)\n */\nexport interface PaymentSignature {\n /** x402 version (always 2) */\n x402Version: 2;\n /** Resource being accessed */\n resource: ResourceInfo;\n /** The payment option that was accepted */\n accepted: PaymentAccept;\n /** The signed payment */\n payload: {\n /** Signed transaction (base64 for Solana, JSON for EVM) */\n transaction: string;\n };\n}\n\n// ============================================================================\n// Facilitator Response Types\n// ============================================================================\n\n/**\n * Response from /verify endpoint\n */\nexport interface VerifyResponse {\n /** Whether the payment is valid */\n isValid: boolean;\n /** Reason for invalidity (if invalid) */\n invalidReason?: string;\n /** Payer address */\n payer?: string;\n}\n\n/**\n * Response from /settle endpoint\n */\nexport interface SettleResponse {\n /** Whether settlement succeeded */\n success: boolean;\n /** Transaction signature/hash */\n transaction?: string;\n /** Network the payment was made on */\n network: string;\n /** Error reason (if failed) */\n errorReason?: string;\n /** Error code (if failed) */\n errorCode?: string;\n /** Payer address */\n payer?: string;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * SDK error codes\n */\nexport type X402ErrorCode =\n // Client errors\n | 'missing_payment_required_header'\n | 'invalid_payment_required'\n | 'unsupported_network'\n | 'no_matching_payment_option'\n | 'no_solana_accept' // Legacy, kept for compatibility\n | 'missing_fee_payer'\n | 'missing_decimals'\n | 'amount_exceeds_max'\n | 'insufficient_balance'\n | 'wallet_missing_sign_transaction'\n | 'wallet_not_connected'\n | 'transaction_build_failed'\n | 'payment_rejected'\n // Server errors\n | 'invalid_payment_signature'\n | 'facilitator_verify_failed'\n | 'facilitator_settle_failed'\n | 'facilitator_request_failed'\n | 'no_matching_requirement';\n\n/**\n * Custom error class for x402 operations\n */\nexport class X402Error extends Error {\n /** Error code for programmatic handling */\n code: X402ErrorCode;\n /** Additional error details */\n details?: unknown;\n\n constructor(code: X402ErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'X402Error';\n this.code = code;\n this.details = details;\n // Maintain proper prototype chain\n Object.setPrototypeOf(this, X402Error.prototype);\n }\n}\n","/**\n * Utility Functions\n *\n * Chain-agnostic helpers for x402 payments.\n */\n\nimport { SOLANA_MAINNET_NETWORK, BASE_MAINNET_NETWORK } from './types';\n\n// ============================================================================\n// Amount Conversion\n// ============================================================================\n\n/**\n * Convert human-readable amount to atomic units\n *\n * @param amount - Human-readable amount (e.g., 0.05 for $0.05)\n * @param decimals - Token decimals (e.g., 6 for USDC)\n * @returns Amount in atomic units as string\n *\n * @example\n * ```typescript\n * toAtomicUnits(0.05, 6) // '50000'\n * toAtomicUnits(1.50, 6) // '1500000'\n * ```\n */\nexport function toAtomicUnits(amount: number, decimals: number): string {\n const multiplier = Math.pow(10, decimals);\n return Math.floor(amount * multiplier).toString();\n}\n\n/**\n * Convert atomic units to human-readable amount\n *\n * @param atomicUnits - Amount in smallest units\n * @param decimals - Token decimals\n * @returns Human-readable amount\n *\n * @example\n * ```typescript\n * fromAtomicUnits('50000', 6) // 0.05\n * fromAtomicUnits(1500000n, 6) // 1.5\n * ```\n */\nexport function fromAtomicUnits(\n atomicUnits: string | bigint | number,\n decimals: number\n): number {\n const divisor = Math.pow(10, decimals);\n return Number(atomicUnits) / divisor;\n}\n\n// ============================================================================\n// Network Helpers\n// ============================================================================\n\n/**\n * Network type\n */\nexport type ChainFamily = 'solana' | 'evm' | 'unknown';\n\n/**\n * Get the chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier\n * @returns Chain family\n *\n * @example\n * ```typescript\n * getChainFamily('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') // 'solana'\n * getChainFamily('eip155:8453') // 'evm'\n * ```\n */\nexport function getChainFamily(network: string): ChainFamily {\n if (network.startsWith('solana:') || network === 'solana') {\n return 'solana';\n }\n if (network.startsWith('eip155:') || ['base', 'ethereum', 'arbitrum'].includes(network)) {\n return 'evm';\n }\n return 'unknown';\n}\n\n/**\n * Get default RPC URL for a network\n *\n * @param network - CAIP-2 network identifier\n * @returns Default RPC URL\n */\nexport function getDefaultRpcUrl(network: string): string {\n const family = getChainFamily(network);\n\n if (family === 'solana') {\n if (network.includes('devnet') || network === 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1') {\n return 'https://api.devnet.solana.com';\n }\n if (network.includes('testnet') || network === 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z') {\n return 'https://api.testnet.solana.com';\n }\n return 'https://api.mainnet-beta.solana.com';\n }\n\n if (family === 'evm') {\n // Extract chain ID from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainId = network.split(':')[1];\n switch (chainId) {\n case '8453': return 'https://mainnet.base.org';\n case '84532': return 'https://sepolia.base.org';\n case '1': return 'https://eth.llamarpc.com';\n case '42161': return 'https://arb1.arbitrum.io/rpc';\n default: return 'https://mainnet.base.org';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://mainnet.base.org';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://mainnet.base.org';\n }\n\n // Unknown - return a generic\n return 'https://api.mainnet-beta.solana.com';\n}\n\n/**\n * Get human-readable chain name\n *\n * @param network - CAIP-2 network identifier\n * @returns Human-readable name\n */\nexport function getChainName(network: string): string {\n const mapping: Record<string, string> = {\n [SOLANA_MAINNET_NETWORK]: 'Solana',\n 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': 'Solana Devnet',\n 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z': 'Solana Testnet',\n 'solana': 'Solana',\n [BASE_MAINNET_NETWORK]: 'Base',\n 'eip155:84532': 'Base Sepolia',\n 'eip155:1': 'Ethereum',\n 'eip155:42161': 'Arbitrum One',\n 'base': 'Base',\n 'ethereum': 'Ethereum',\n 'arbitrum': 'Arbitrum',\n };\n return mapping[network] || network;\n}\n\n// ============================================================================\n// Transaction URL Helpers\n// ============================================================================\n\n/**\n * Get explorer URL for a transaction\n *\n * @param txSignature - Transaction signature/hash\n * @param network - CAIP-2 network identifier\n * @returns Explorer URL\n */\nexport function getExplorerUrl(txSignature: string, network: string): string {\n const family = getChainFamily(network);\n\n if (family === 'solana') {\n const isDevnet = network.includes('devnet') || network === 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\n if (isDevnet) {\n return `https://solscan.io/tx/${txSignature}?cluster=devnet`;\n }\n // Prefer Orb Markets for mainnet\n return `https://www.orbmarkets.io/tx/${txSignature}`;\n }\n\n if (family === 'evm') {\n // Extract chain ID\n let chainId = '8453'; // Default to Base\n if (network.startsWith('eip155:')) {\n chainId = network.split(':')[1];\n } else if (network === 'ethereum') {\n chainId = '1';\n } else if (network === 'arbitrum') {\n chainId = '42161';\n }\n\n switch (chainId) {\n case '8453': return `https://basescan.org/tx/${txSignature}`;\n case '84532': return `https://sepolia.basescan.org/tx/${txSignature}`;\n case '1': return `https://etherscan.io/tx/${txSignature}`;\n case '42161': return `https://arbiscan.io/tx/${txSignature}`;\n default: return `https://basescan.org/tx/${txSignature}`;\n }\n }\n\n return `https://solscan.io/tx/${txSignature}`;\n}\n\n// ============================================================================\n// Encoding Helpers\n// ============================================================================\n\n/**\n * Encode an object as base64 JSON\n */\nexport function encodeBase64Json(obj: unknown): string {\n return btoa(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(atob(encoded)) as T;\n}\n","/**\n * Facilitator Client\n *\n * Communicates with the x402 facilitator for:\n * - /supported - Get supported payment schemes and fee payer addresses\n * - /verify - Verify a payment signature before processing\n * - /settle - Submit the payment for execution\n *\n * Works with any x402 v2 facilitator (Dexter or others).\n */\n\nimport type { PaymentAccept, PaymentSignature, VerifyResponse, SettleResponse } from '../types';\nimport { DEXTER_FACILITATOR_URL } from '../types';\nimport { decodeBase64Json } from '../utils';\n\n/**\n * Supported payment kind from facilitator /supported endpoint\n */\nexport interface SupportedKind {\n x402Version: number;\n scheme: string;\n network: string;\n extra?: {\n feePayer?: string;\n decimals?: number;\n name?: string;\n version?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Response from facilitator /supported endpoint\n */\nexport interface SupportedResponse {\n kinds: SupportedKind[];\n}\n\n/**\n * Client for communicating with an x402 v2 facilitator\n */\nexport class FacilitatorClient {\n private facilitatorUrl: string;\n private cachedSupported: SupportedResponse | null = null;\n private cacheTime: number = 0;\n private readonly CACHE_TTL_MS = 60_000; // 1 minute cache\n\n constructor(facilitatorUrl: string = DEXTER_FACILITATOR_URL) {\n this.facilitatorUrl = facilitatorUrl.replace(/\\/$/, ''); // Remove trailing slash\n }\n\n /**\n * Get supported payment kinds from the facilitator\n * Results are cached for 1 minute to reduce network calls\n */\n async getSupported(): Promise<SupportedResponse> {\n const now = Date.now();\n if (this.cachedSupported && now - this.cacheTime < this.CACHE_TTL_MS) {\n return this.cachedSupported;\n }\n\n const response = await fetch(`${this.facilitatorUrl}/supported`);\n if (!response.ok) {\n throw new Error(`Facilitator /supported returned ${response.status}`);\n }\n\n this.cachedSupported = (await response.json()) as SupportedResponse;\n this.cacheTime = now;\n return this.cachedSupported;\n }\n\n /**\n * Get the fee payer address for a specific network\n *\n * @param network - CAIP-2 network identifier\n * @returns Fee payer address\n */\n async getFeePayer(network: string): Promise<string> {\n const supported = await this.getSupported();\n\n // Find matching network support (exact match or v2)\n const kind = supported.kinds.find(\n (k) =>\n k.x402Version === 2 &&\n k.scheme === 'exact' &&\n k.network === network\n );\n\n if (!kind?.extra?.feePayer) {\n throw new Error(\n `Facilitator does not support network \"${network}\" with scheme \"exact\", or feePayer not provided`\n );\n }\n\n return kind.extra.feePayer;\n }\n\n /**\n * Get extra data for a network (feePayer, decimals, EIP-712 data, etc.)\n *\n * @param network - CAIP-2 network identifier\n * @returns Extra data from /supported\n */\n async getNetworkExtra(network: string): Promise<SupportedKind['extra']> {\n const supported = await this.getSupported();\n\n const kind = supported.kinds.find(\n (k) =>\n k.x402Version === 2 &&\n k.scheme === 'exact' &&\n k.network === network\n );\n\n return kind?.extra;\n }\n\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value\n * @param requirements - The payment requirements that were sent to the client\n * @returns Verification response\n */\n async verifyPayment(\n paymentSignatureHeader: string,\n requirements: PaymentAccept\n ): Promise<VerifyResponse> {\n try {\n const paymentPayload = decodeBase64Json<PaymentSignature>(paymentSignatureHeader);\n\n const verifyPayload = {\n paymentPayload,\n paymentRequirements: requirements,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(verifyPayload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Facilitator /verify returned ${response.status}:`, errorText);\n return {\n isValid: false,\n invalidReason: `facilitator_error_${response.status}`,\n };\n }\n\n return (await response.json()) as VerifyResponse;\n } catch (error) {\n console.error('Payment verification failed:', error);\n return {\n isValid: false,\n invalidReason: error instanceof Error ? error.message : 'unexpected_verify_error',\n };\n }\n }\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value\n * @param requirements - The payment requirements that were sent to the client\n * @returns Settlement response with transaction signature on success\n */\n async settlePayment(\n paymentSignatureHeader: string,\n requirements: PaymentAccept\n ): Promise<SettleResponse> {\n try {\n const paymentPayload = decodeBase64Json<PaymentSignature>(paymentSignatureHeader);\n\n const settlePayload = {\n paymentPayload,\n paymentRequirements: requirements,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/settle`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(settlePayload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Facilitator /settle returned ${response.status}:`, errorText);\n return {\n success: false,\n network: requirements.network,\n errorReason: `facilitator_error_${response.status}`,\n };\n }\n\n const result = (await response.json()) as SettleResponse;\n return {\n ...result,\n network: requirements.network,\n };\n } catch (error) {\n console.error('Payment settlement failed:', error);\n return {\n success: false,\n network: requirements.network,\n errorReason: error instanceof Error ? error.message : 'unexpected_settle_error',\n };\n }\n }\n}\n","/**\n * x402 v2 Server\n *\n * Server-side helpers for accepting x402 payments.\n * Chain-agnostic - works with Solana, Base, and any x402-compatible network.\n *\n * @example\n * ```typescript\n * import { createX402Server } from '@dexterai/x402/server';\n *\n * const server = createX402Server({\n * payTo: 'YourAddress...',\n * network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n * });\n *\n * // Handle 402 responses\n * if (!paymentSignature) {\n * const requirements = await server.buildRequirements({\n * amountAtomic: '50000',\n * resourceUrl: '/api/protected',\n * });\n * res.setHeader('PAYMENT-REQUIRED', server.encodeRequirements(requirements));\n * res.status(402).json({});\n * return;\n * }\n *\n * // Verify and settle\n * const verify = await server.verifyPayment(paymentSignature);\n * if (!verify.isValid) throw new Error(verify.invalidReason);\n *\n * const settle = await server.settlePayment(paymentSignature);\n * if (!settle.success) throw new Error(settle.errorReason);\n *\n * // Payment successful!\n * res.json({ transaction: settle.transaction });\n * ```\n */\n\nimport type {\n PaymentRequired,\n PaymentAccept,\n ResourceInfo,\n AcceptsExtra,\n VerifyResponse,\n SettleResponse,\n} from '../types';\nimport {\n SOLANA_MAINNET_NETWORK,\n USDC_MINT,\n DEXTER_FACILITATOR_URL,\n} from '../types';\nimport { FacilitatorClient, type SupportedKind } from './facilitator-client';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Asset configuration\n */\nexport interface AssetConfig {\n /** Token address (mint on Solana, contract on EVM) */\n address: string;\n /** Token decimals */\n decimals: number;\n}\n\n/**\n * Server configuration\n */\nexport interface X402ServerConfig {\n /** Address to receive payments */\n payTo: string;\n /** Facilitator URL (defaults to Dexter) */\n facilitatorUrl?: string;\n /** CAIP-2 network identifier */\n network?: string;\n /** Asset configuration (defaults to USDC) */\n asset?: AssetConfig;\n /** Default payment timeout in seconds */\n defaultTimeoutSeconds?: number;\n}\n\n/**\n * Options for building payment requirements\n */\nexport interface BuildRequirementsOptions {\n /** Amount in atomic units (e.g., '50000' for 0.05 USDC) */\n amountAtomic: string;\n /** Full URL of the resource */\n resourceUrl: string;\n /** Human-readable description */\n description?: string;\n /** MIME type of the response */\n mimeType?: string;\n /** Override timeout for this request */\n timeoutSeconds?: number;\n}\n\n/**\n * x402 Server interface\n */\nexport interface X402Server {\n /** Build payment requirements (fetches feePayer from facilitator) */\n buildRequirements(options: BuildRequirementsOptions): Promise<PaymentRequired>;\n\n /** Encode requirements for PAYMENT-REQUIRED header */\n encodeRequirements(requirements: PaymentRequired): string;\n\n /** Create complete 402 response object */\n create402Response(requirements: PaymentRequired): {\n status: 402;\n headers: { 'PAYMENT-REQUIRED': string };\n body: Record<string, unknown>;\n };\n\n /** Verify payment with facilitator */\n verifyPayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<VerifyResponse>;\n\n /** Settle payment via facilitator */\n settlePayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<SettleResponse>;\n\n /** Get PaymentAccept for verify/settle */\n getPaymentAccept(options: BuildRequirementsOptions): Promise<PaymentAccept>;\n\n /** Get network this server is configured for */\n readonly network: string;\n\n /** Get facilitator client for advanced usage */\n readonly facilitator: FacilitatorClient;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Create an x402 server for accepting payments\n */\nexport function createX402Server(config: X402ServerConfig): X402Server {\n const {\n payTo,\n facilitatorUrl = DEXTER_FACILITATOR_URL,\n network = SOLANA_MAINNET_NETWORK,\n asset = { address: USDC_MINT, decimals: 6 },\n defaultTimeoutSeconds = 60,\n } = config;\n\n const facilitator = new FacilitatorClient(facilitatorUrl);\n\n // Cache for network extra data\n let cachedExtra: SupportedKind['extra'] | null = null;\n\n /**\n * Get extra data from facilitator (cached)\n */\n async function getNetworkExtra(): Promise<AcceptsExtra> {\n if (!cachedExtra) {\n cachedExtra = await facilitator.getNetworkExtra(network);\n }\n\n if (!cachedExtra?.feePayer) {\n throw new Error(`Facilitator does not provide feePayer for network \"${network}\"`);\n }\n\n return {\n feePayer: cachedExtra.feePayer,\n decimals: cachedExtra.decimals ?? asset.decimals,\n // Include any additional EIP-712 data for EVM chains\n name: cachedExtra.name,\n version: cachedExtra.version,\n };\n }\n\n /**\n * Build a PaymentAccept structure\n */\n async function getPaymentAccept(options: BuildRequirementsOptions): Promise<PaymentAccept> {\n const {\n amountAtomic,\n timeoutSeconds = defaultTimeoutSeconds,\n } = options;\n\n const extra = await getNetworkExtra();\n\n return {\n scheme: 'exact',\n network,\n amount: amountAtomic,\n asset: asset.address,\n payTo,\n maxTimeoutSeconds: timeoutSeconds,\n extra,\n };\n }\n\n /**\n * Build payment requirements for a 402 response\n */\n async function buildRequirements(options: BuildRequirementsOptions): Promise<PaymentRequired> {\n const {\n resourceUrl,\n description,\n mimeType = 'application/json',\n } = options;\n\n const resource: ResourceInfo = {\n url: resourceUrl,\n description,\n mimeType,\n };\n\n const accept = await getPaymentAccept(options);\n\n return {\n x402Version: 2,\n resource,\n accepts: [accept],\n error: 'Payment required',\n };\n }\n\n /**\n * Encode requirements for PAYMENT-REQUIRED header\n */\n function encodeRequirements(requirements: PaymentRequired): string {\n return btoa(JSON.stringify(requirements));\n }\n\n /**\n * Create complete 402 response object\n */\n function create402Response(requirements: PaymentRequired) {\n return {\n status: 402 as const,\n headers: {\n 'PAYMENT-REQUIRED': encodeRequirements(requirements),\n },\n body: {},\n };\n }\n\n /**\n * Verify payment with facilitator\n */\n async function verifyPayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<VerifyResponse> {\n // If requirements not provided, build default\n const req = requirements || await getPaymentAccept({\n amountAtomic: '0',\n resourceUrl: '',\n });\n\n return facilitator.verifyPayment(paymentSignatureHeader, req);\n }\n\n /**\n * Settle payment via facilitator\n */\n async function settlePayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<SettleResponse> {\n const req = requirements || await getPaymentAccept({\n amountAtomic: '0',\n resourceUrl: '',\n });\n\n return facilitator.settlePayment(paymentSignatureHeader, req);\n }\n\n return {\n buildRequirements,\n encodeRequirements,\n create402Response,\n verifyPayment,\n settlePayment,\n getPaymentAccept,\n network,\n facilitator,\n };\n}\n","/**\n * Dynamic Pricing for x402\n *\n * Calculate prices based on input length (characters, tokens, etc.)\n * Perfect for LLM/AI endpoints where cost scales with input size.\n *\n * @example\n * ```typescript\n * import { createDynamicPricing } from '@dexterai/x402/server';\n *\n * const pricing = createDynamicPricing({\n * unitSize: 1000, // chars per billing unit\n * ratePerUnit: 0.01, // $0.01 per unit\n * minUsd: 0.01, // floor\n * maxUsd: 10.00, // ceiling (optional)\n * });\n *\n * // Calculate price from input\n * const quote = pricing.calculate(userPrompt);\n * // → { amountAtomic: '23000', usdAmount: 0.023, quoteHash: 'abc...', units: 2.3 }\n *\n * // Validate on retry (prevents prompt manipulation)\n * const isValid = pricing.validateQuote(userPrompt, req.headers['x-quote-hash']);\n * ```\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Configuration for dynamic pricing\n */\nexport interface DynamicPricingConfig {\n /**\n * Characters per billing unit.\n * Example: 1000 means every 1000 chars = 1 unit\n */\n unitSize: number;\n\n /**\n * USD per unit.\n * Example: 0.01 means $0.01 per unit\n */\n ratePerUnit: number;\n\n /**\n * Minimum USD amount (floor).\n * Recommended: 0.01 (practical minimum for settlement)\n * @default 0.01\n */\n minUsd?: number;\n\n /**\n * Maximum USD amount (ceiling).\n * Optional - prevents unexpectedly large bills.\n */\n maxUsd?: number;\n\n /**\n * Rounding mode for unit calculation.\n * - 'ceil': Always round up (fair to seller)\n * - 'floor': Always round down (fair to buyer)\n * - 'round': Standard rounding\n * @default 'ceil'\n */\n roundingMode?: 'ceil' | 'floor' | 'round';\n\n /**\n * Token decimals for atomic conversion.\n * @default 6 (USDC)\n */\n decimals?: number;\n}\n\n/**\n * Price quote returned by calculate()\n */\nexport interface PriceQuote {\n /** Amount in atomic units (for buildRequirements) */\n amountAtomic: string;\n\n /** Human-readable USD amount (for display) */\n usdAmount: number;\n\n /**\n * Quote hash for validation.\n * Includes input + config, so config changes invalidate quotes.\n * Client should send this back as X-Quote-Hash header.\n */\n quoteHash: string;\n\n /** Number of billing units */\n units: number;\n\n /** Input length in characters */\n inputLength: number;\n}\n\n/**\n * Dynamic pricing calculator\n */\nexport interface DynamicPricing {\n /** Calculate price from input */\n calculate(input: string): PriceQuote;\n\n /** Validate quote hash (returns true if valid) */\n validateQuote(input: string, quoteHash: string): boolean;\n\n /** Get pricing config (for display) */\n readonly config: Required<DynamicPricingConfig>;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Simple hash function (browser-compatible, no crypto needed)\n * Uses FNV-1a for speed and simplicity\n */\nfunction simpleHash(str: string): string {\n let hash = 2166136261; // FNV offset basis\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, 16777619); // FNV prime\n }\n // Convert to hex string\n return (hash >>> 0).toString(16).padStart(8, '0');\n}\n\n/**\n * Create a dynamic pricing calculator\n */\nexport function createDynamicPricing(config: DynamicPricingConfig): DynamicPricing {\n const fullConfig: Required<DynamicPricingConfig> = {\n unitSize: config.unitSize,\n ratePerUnit: config.ratePerUnit,\n minUsd: config.minUsd ?? 0.01,\n maxUsd: config.maxUsd ?? Infinity,\n roundingMode: config.roundingMode ?? 'ceil',\n decimals: config.decimals ?? 6,\n };\n\n const { unitSize, ratePerUnit, minUsd, maxUsd, roundingMode, decimals } = fullConfig;\n\n // Validate config\n if (unitSize <= 0) throw new Error('unitSize must be positive');\n if (ratePerUnit <= 0) throw new Error('ratePerUnit must be positive');\n if (minUsd < 0) throw new Error('minUsd cannot be negative');\n if (maxUsd < minUsd) throw new Error('maxUsd must be >= minUsd');\n\n /**\n * Build hash input string (input + config)\n * Config is included so pricing changes invalidate old quotes\n */\n function buildHashInput(input: string): string {\n const configStr = JSON.stringify({\n unitSize,\n ratePerUnit,\n minUsd,\n maxUsd: maxUsd === Infinity ? 'none' : maxUsd,\n roundingMode,\n });\n return `${input}|${configStr}`;\n }\n\n /**\n * Calculate price from input\n */\n function calculate(input: string): PriceQuote {\n const inputLength = input.length;\n\n // Calculate units based on rounding mode\n const rawUnits = inputLength / unitSize;\n let units: number;\n switch (roundingMode) {\n case 'ceil':\n units = Math.ceil(rawUnits);\n break;\n case 'floor':\n units = Math.floor(rawUnits);\n break;\n case 'round':\n units = Math.round(rawUnits);\n break;\n }\n\n // Ensure at least 1 unit if there's any input\n if (inputLength > 0 && units === 0) {\n units = 1;\n }\n\n // Calculate USD amount\n let usdAmount = units * ratePerUnit;\n\n // Apply min/max\n usdAmount = Math.max(minUsd, usdAmount);\n usdAmount = Math.min(maxUsd, usdAmount);\n\n // Convert to atomic units\n const multiplier = Math.pow(10, decimals);\n const amountAtomic = Math.floor(usdAmount * multiplier).toString();\n\n // Generate quote hash (includes config)\n const quoteHash = simpleHash(buildHashInput(input));\n\n return {\n amountAtomic,\n usdAmount,\n quoteHash,\n units,\n inputLength,\n };\n }\n\n /**\n * Validate quote hash\n * Returns true if the hash matches (input + config unchanged)\n */\n function validateQuote(input: string, quoteHash: string): boolean {\n if (!quoteHash) return false;\n const expectedHash = simpleHash(buildHashInput(input));\n return expectedHash === quoteHash;\n }\n\n return {\n calculate,\n validateQuote,\n config: fullConfig,\n };\n}\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\n/**\n * Format pricing for display\n * Example: \"from $0.01 per 1,000 chars\"\n */\nexport function formatPricing(config: DynamicPricingConfig): string {\n const rate = config.ratePerUnit.toFixed(2);\n const units = config.unitSize.toLocaleString();\n return `from $${rate} per ${units} chars`;\n}\n\n"],"mappings":"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","names":[]}
|