UNPKG

@payai/x402

Version:

PayAI-distributed wrapper for @x402/core v2

1 lines 17.5 kB
{"version":3,"sources":["../../../src/client/x402Client.ts"],"sourcesContent":["import { x402Version } from \"..\";\nimport { SchemeNetworkClient } from \"../types/mechanisms\";\nimport { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport { Network, PaymentRequired } from \"../types\";\nimport { findByNetworkAndScheme, findSchemesByNetwork } from \"../utils\";\n\n/**\n * Client Hook Context Interfaces\n */\n\nexport interface PaymentCreationContext {\n paymentRequired: PaymentRequired;\n selectedRequirements: PaymentRequirements;\n}\n\nexport interface PaymentCreatedContext extends PaymentCreationContext {\n paymentPayload: PaymentPayload;\n}\n\nexport interface PaymentCreationFailureContext extends PaymentCreationContext {\n error: Error;\n}\n\n/**\n * Client Hook Type Definitions\n */\n\nexport type BeforePaymentCreationHook = (\n context: PaymentCreationContext,\n) => Promise<void | { abort: true; reason: string }>;\n\nexport type AfterPaymentCreationHook = (context: PaymentCreatedContext) => Promise<void>;\n\nexport type OnPaymentCreationFailureHook = (\n context: PaymentCreationFailureContext,\n) => Promise<void | { recovered: true; payload: PaymentPayload }>;\n\nexport type SelectPaymentRequirements = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements;\n\n/**\n * A policy function that filters or transforms payment requirements.\n * Policies are applied in order before the selector chooses the final option.\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - Array of payment requirements to filter/transform\n * @returns Filtered array of payment requirements\n */\nexport type PaymentPolicy = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements[];\n\n\n/**\n * Configuration for registering a payment scheme with a specific network\n */\nexport interface SchemeRegistration {\n /**\n * The network identifier (e.g., 'eip155:8453', 'solana:mainnet')\n */\n network: Network;\n\n /**\n * The scheme client implementation for this network\n */\n client: SchemeNetworkClient;\n\n /**\n * The x402 protocol version to use for this scheme\n *\n * @default 2\n */\n x402Version?: number;\n}\n\n/**\n * Configuration options for the fetch wrapper\n */\nexport interface x402ClientConfig {\n /**\n * Array of scheme registrations defining which payment methods are supported\n */\n schemes: SchemeRegistration[];\n\n /**\n * Policies to apply to the client\n */\n policies?: PaymentPolicy[];\n\n /**\n * Custom payment requirements selector function\n * If not provided, uses the default selector (first available option)\n */\n paymentRequirementsSelector?: SelectPaymentRequirements;\n}\n\n/**\n * Core client for managing x402 payment schemes and creating payment payloads.\n *\n * Handles registration of payment schemes, policy-based filtering of payment requirements,\n * and creation of payment payloads based on server requirements.\n */\nexport class x402Client {\n private readonly paymentRequirementsSelector: SelectPaymentRequirements;\n private readonly registeredClientSchemes: Map<number, Map<string, Map<string, SchemeNetworkClient>>> = new Map();\n private readonly policies: PaymentPolicy[] = [];\n\n private beforePaymentCreationHooks: BeforePaymentCreationHook[] = [];\n private afterPaymentCreationHooks: AfterPaymentCreationHook[] = [];\n private onPaymentCreationFailureHooks: OnPaymentCreationFailureHook[] = [];\n\n /**\n * Creates a new x402Client instance.\n *\n * @param paymentRequirementsSelector - Function to select payment requirements from available options\n */\n constructor(paymentRequirementsSelector?: SelectPaymentRequirements) {\n this.paymentRequirementsSelector = paymentRequirementsSelector || ((x402Version, accepts) => accepts[0]);\n }\n\n /**\n * Creates a new x402Client instance from a configuration object.\n *\n * @param config - The client configuration including schemes, policies, and payment requirements selector\n * @returns A configured x402Client instance\n */\n static fromConfig(config: x402ClientConfig): x402Client {\n const client = new x402Client(config.paymentRequirementsSelector);\n config.schemes.forEach(scheme => {\n if (scheme.x402Version === 1) {\n client.registerV1(scheme.network, scheme.client);\n } else {\n client.register(scheme.network, scheme.client);\n }\n });\n config.policies?.forEach(policy => {\n client.registerPolicy(policy);\n });\n return client;\n }\n\n /**\n * Registers a scheme client for the current x402 version.\n *\n * @param network - The network to register the client for\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n register(network: Network, client: SchemeNetworkClient): x402Client {\n return this._registerScheme(x402Version, network, client);\n }\n\n /**\n * Registers a scheme client for x402 version 1.\n *\n * @param network - The v1 network identifier (e.g., 'base-sepolia', 'solana-devnet')\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n registerV1(network: string, client: SchemeNetworkClient): x402Client {\n return this._registerScheme(1, network as Network, client);\n }\n\n /**\n * Registers a policy to filter or transform payment requirements.\n *\n * Policies are applied in order after filtering by registered schemes\n * and before the selector chooses the final payment requirement.\n *\n * @param policy - Function to filter/transform payment requirements\n * @returns The x402Client instance for chaining\n *\n * @example\n * ```typescript\n * // Prefer cheaper options\n * client.registerPolicy((version, reqs) =>\n * reqs.filter(r => BigInt(r.value) < BigInt('1000000'))\n * );\n *\n * // Prefer specific networks\n * client.registerPolicy((version, reqs) =>\n * reqs.filter(r => r.network.startsWith('eip155:'))\n * );\n * ```\n */\n registerPolicy(policy: PaymentPolicy): x402Client {\n this.policies.push(policy);\n return this;\n }\n\n /**\n * Register a hook to execute before payment payload creation.\n * Can abort creation by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onBeforePaymentCreation(hook: BeforePaymentCreationHook): x402Client {\n this.beforePaymentCreationHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment payload creation.\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onAfterPaymentCreation(hook: AfterPaymentCreationHook): x402Client {\n this.afterPaymentCreationHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment payload creation fails.\n * Can recover from failure by returning { recovered: true, payload: PaymentPayload }\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onPaymentCreationFailure(hook: OnPaymentCreationFailureHook): x402Client {\n this.onPaymentCreationFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Creates a payment payload based on a PaymentRequired response.\n *\n * Automatically extracts x402Version, resource, and extensions from the PaymentRequired\n * response and constructs a complete PaymentPayload with the accepted requirements.\n *\n * @param paymentRequired - The PaymentRequired response from the server\n * @returns Promise resolving to the complete payment payload\n */\n async createPaymentPayload(\n paymentRequired: PaymentRequired,\n ): Promise<PaymentPayload> {\n const clientSchemesByNetwork = this.registeredClientSchemes.get(paymentRequired.x402Version);\n if (!clientSchemesByNetwork) {\n throw new Error(`No client registered for x402 version: ${paymentRequired.x402Version}`);\n }\n\n const requirements = this.selectPaymentRequirements(paymentRequired.x402Version, paymentRequired.accepts);\n\n const context: PaymentCreationContext = {\n paymentRequired,\n selectedRequirements: requirements,\n };\n\n // Execute beforePaymentCreation hooks\n for (const hook of this.beforePaymentCreationHooks) {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n throw new Error(`Payment creation aborted: ${result.reason}`);\n }\n }\n\n try {\n const schemeNetworkClient = findByNetworkAndScheme(clientSchemesByNetwork, requirements.scheme, requirements.network);\n if (!schemeNetworkClient) {\n throw new Error(`No client registered for scheme: ${requirements.scheme} and network: ${requirements.network}`);\n }\n\n const partialPayload = await schemeNetworkClient.createPaymentPayload(paymentRequired.x402Version, requirements);\n\n let paymentPayload: PaymentPayload;\n if (partialPayload.x402Version == 1) {\n paymentPayload = partialPayload as PaymentPayload;\n } else {\n paymentPayload = {\n ...partialPayload,\n extensions: paymentRequired.extensions,\n resource: paymentRequired.resource,\n accepted: requirements,\n };\n }\n\n // Execute afterPaymentCreation hooks\n const createdContext: PaymentCreatedContext = {\n ...context,\n paymentPayload,\n };\n\n for (const hook of this.afterPaymentCreationHooks) {\n await hook(createdContext);\n }\n\n return paymentPayload;\n } catch (error) {\n const failureContext: PaymentCreationFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onPaymentCreationFailure hooks\n for (const hook of this.onPaymentCreationFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.payload;\n }\n }\n\n throw error;\n }\n }\n\n\n\n /**\n * Selects appropriate payment requirements based on registered clients and policies.\n *\n * Selection process:\n * 1. Filter by registered schemes (network + scheme support)\n * 2. Apply all registered policies in order\n * 3. Use selector to choose final requirement\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - Array of available payment requirements\n * @returns The selected payment requirements\n */\n private selectPaymentRequirements(x402Version: number, paymentRequirements: PaymentRequirements[]): PaymentRequirements {\n const clientSchemesByNetwork = this.registeredClientSchemes.get(x402Version);\n if (!clientSchemesByNetwork) {\n throw new Error(`No client registered for x402 version: ${x402Version}`);\n }\n\n // Step 1: Filter by registered schemes\n const supportedPaymentRequirements = paymentRequirements.filter(requirement => {\n let clientSchemes = findSchemesByNetwork(clientSchemesByNetwork, requirement.network);\n if (!clientSchemes) {\n return false;\n }\n\n return clientSchemes.has(requirement.scheme);\n })\n\n if (supportedPaymentRequirements.length === 0) {\n throw new Error(`No network/scheme registered for x402 version: ${x402Version} which comply with the payment requirements. ${JSON.stringify({\n x402Version,\n paymentRequirements,\n x402Versions: Array.from(this.registeredClientSchemes.keys()),\n networks: Array.from(clientSchemesByNetwork.keys()),\n schemes: Array.from(clientSchemesByNetwork.values()).map(schemes => Array.from(schemes.keys())).flat(),\n })}`);\n }\n\n // Step 2: Apply all policies in order\n let filteredRequirements = supportedPaymentRequirements;\n for (const policy of this.policies) {\n filteredRequirements = policy(x402Version, filteredRequirements);\n\n if (filteredRequirements.length === 0) {\n throw new Error(`All payment requirements were filtered out by policies for x402 version: ${x402Version}`);\n }\n }\n\n // Step 3: Use selector to choose final requirement\n return this.paymentRequirementsSelector(x402Version, filteredRequirements);\n }\n\n /**\n * Internal method to register a scheme client.\n *\n * @param x402Version - The x402 protocol version\n * @param network - The network to register the client for\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n private _registerScheme(x402Version: number, network: Network, client: SchemeNetworkClient): x402Client {\n if (!this.registeredClientSchemes.has(x402Version)) {\n this.registeredClientSchemes.set(x402Version, new Map());\n }\n const clientSchemesByNetwork = this.registeredClientSchemes.get(x402Version)!;\n if (!clientSchemesByNetwork.has(network)) {\n clientSchemesByNetwork.set(network, new Map());\n }\n\n const clientByScheme = clientSchemesByNetwork.get(network)!;\n if (!clientByScheme.has(client.scheme)) {\n clientByScheme.set(client.scheme, client);\n }\n\n return this;\n }\n}\n"],"mappings":"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","names":["x402Version"]}