UNPKG

@thorium-dev-group/x402-mcp-extension

Version:
195 lines 9.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PaymentOrchestrator = void 0; const schemas_1 = require("../../../shared/schemas"); const PaymentError_1 = require("../../../shared/errors/PaymentError"); const error_codes_1 = require("../../../shared/error-codes"); class PaymentOrchestrator { options; logger; constructor(options) { this.options = options; this.logger = options.loggerFactory.createLogger(PaymentOrchestrator.name); } async validatePayment(handlerName, paymentRequirements, extra) { this.logger.info('Validating payment for handler', { operation: 'payment_validation_start', handlerName: handlerName, amount: paymentRequirements.maxAmountRequired }); try { const paymentResponse = await this.sendPaymentRequiredRequest(paymentRequirements, extra); this.logger.info('Payment required request sent', { operation: 'payment_required_request_sent', handlerName: handlerName, paymentResponse: paymentResponse }); await this.validatePaymentProof(paymentResponse, paymentRequirements, extra); this.logger.info('Payment validation successful', { operation: 'payment_validation_success', handlerName: handlerName }); } catch (error) { this.logger.error('Payment validation failed', { operation: 'payment_validation_failed', handlerName: handlerName, error: error instanceof Error ? error.message : String(error) }); if (error instanceof PaymentError_1.PaymentError) { throw error; } else { throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_INVALID, `Payment validation failed: ${error instanceof Error ? error.message : String(error)}`); } } } async settlePayment(extra) { this.logger.info('Settling payment', { operation: 'payment_settlement_start' }); try { const paymentProof = extra.paymentProof; const paymentRequirements = extra.paymentRequirements; if (!paymentProof || !paymentRequirements) { throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_INVALID, 'Payment proof or requirements not found in context'); } const paymentResult = await this.executePayment(paymentProof, paymentRequirements); if (!paymentResult.success) { throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_EXECUTION_FAILED, `Payment settlement failed: ${paymentResult.errorReason}`); } await extra.sendNotification({ jsonrpc: '2.0', method: schemas_1.PaymentResultNotificationSchema.shape.method.value, params: { success: true, transaction: paymentResult.transaction, network: paymentResult.network, requestId: extra.requestId, payer: paymentResult.payer, }, }); this.logger.info('Payment settled successfully', { operation: 'payment_settlement_success', transaction: paymentResult.transaction }); } catch (error) { this.logger.error('Payment settlement failed', { operation: 'payment_settlement_failed', error: error instanceof Error ? error.message : String(error) }); await extra.sendNotification({ jsonrpc: '2.0', method: schemas_1.PaymentResultNotificationSchema.shape.method.value, params: { success: false, errorReason: error instanceof Error ? error.message : String(error), network: this.options.network, requestId: extra.requestId, }, }); if (error instanceof PaymentError_1.PaymentError) { throw error; } else { throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_EXECUTION_FAILED, `Payment settlement failed: ${error instanceof Error ? error.message : String(error)}`); } } } async sendPaymentRequiredRequest(paymentRequirements, extra) { const requestId = extra.requestId; const paymentRequest = { jsonrpc: '2.0', id: requestId, method: 'x402/payment_required', params: { scheme: paymentRequirements.scheme, network: paymentRequirements.network, maxAmountRequired: paymentRequirements.maxAmountRequired, resource: paymentRequirements.resource, description: paymentRequirements.description, mimeType: paymentRequirements.mimeType, payTo: paymentRequirements.payTo, maxTimeoutSeconds: paymentRequirements.maxTimeoutSeconds, asset: paymentRequirements.asset, outputSchema: paymentRequirements.outputSchema, extra: paymentRequirements.extra, x402Version: 1, requestId: requestId, }, }; try { const response = await extra.sendRequest(paymentRequest, schemas_1.PaymentRequiredResponseSchema); return response; } catch (error) { this.logger.error('Failed to send payment request', { operation: 'send_payment_required_request', error: error }); if (this.isMethodNotFoundError(error)) { throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_REQUIRED, `Payment required: ${paymentRequirements.description || 'Payment is required for this operation'}`, { amount: paymentRequirements.maxAmountRequired, asset: paymentRequirements.asset, paymentAddress: this.options.payTo, network: this.options.network, }); } throw new PaymentError_1.PaymentError(error.code ? error.code : error_codes_1.ERROR_CODES.PAYMENT_INVALID, 'Failed to send payment request', error); } } isMethodNotFoundError(error) { return error?.code === -32601 || error?.message?.includes('Method not found') || error?.message?.includes('method not found'); } async validatePaymentProof(response, paymentRequirements, extra) { const payment = response.result.payment; if (!payment || !payment.payload?.signature) { this.logger.error('Invalid payment proof: missing signature', { operation: 'validate_payment_proof', payment: payment }); throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_INVALID, 'Invalid payment proof: missing signature'); } if (payment.x402Version !== 1) { this.logger.error('Invalid x402 version', { operation: 'validate_payment_proof', payment: payment }); throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.INVALID_REQUEST, 'Invalid x402 version'); } if (payment.scheme !== 'exact') { this.logger.error('Invalid payment scheme', { operation: 'validate_payment_proof', payment: payment }); throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_INVALID, 'Invalid payment scheme'); } if (payment.network !== paymentRequirements.network) { this.logger.error('Invalid payment proof: network mismatch', { operation: 'validate_payment_proof', payment: payment }); throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_INVALID, 'Invalid payment proof: network mismatch'); } const res = await this.options.facilitator.validatePayment(payment, paymentRequirements); if (!res.isValid) { this.logger.error('Payment proof validation failed', { operation: 'validate_payment_proof', payment: payment, failReason: res.invalidReason }); throw new PaymentError_1.PaymentError(error_codes_1.ERROR_CODES.PAYMENT_INVALID, res.invalidReason || 'Payment proof validation failed'); } extra.paymentProof = payment; extra.paymentRequirements = paymentRequirements; return payment; } async executePayment(paymentProof, paymentRequirements) { return await this.options.facilitator.executePayment(paymentProof, paymentRequirements); } } exports.PaymentOrchestrator = PaymentOrchestrator; //# sourceMappingURL=PaymentOrchestrator.js.map