@@ -5,7 +5,7 @@ import { calculateRefundAmount } from 'utils';
55import { checkBalance } from 'services/BalanceCheckService' ;
66import { prisma } from 'server' ;
77import { makeProxyPassthroughRequest } from 'services/ProxyPassthroughService' ;
8- import logger from 'logger' ;
8+ import logger , { logMetric } from 'logger' ;
99import { ProviderType } from 'providers/ProviderType' ;
1010import { settle } from 'handlers/settle' ;
1111import { finalize } from 'handlers/finalize' ;
@@ -24,55 +24,91 @@ export async function handleX402Request({
2424 if ( isPassthroughProxyRoute ) {
2525 return await makeProxyPassthroughRequest ( req , res , provider , headers ) ;
2626 }
27- const settleResult = await settle ( req , res , headers , maxCost ) ;
28- if ( ! settleResult ) {
29- return ;
30- }
3127
32- const { payload , paymentAmountDecimal } = settleResult ;
28+ const settlePromise = settle ( req , res , headers , maxCost ) ;
3329
34- try {
35- const transactionResult = await modelRequestService . executeModelRequest (
36- req ,
37- res ,
38- headers ,
39- provider ,
40- isStream
41- ) ;
42- const transaction = transactionResult . transaction ;
43- if ( provider . getType ( ) === ProviderType . OPENAI_VIDEOS ) {
44- await prisma . videoGenerationX402 . create ( {
45- data : {
46- videoId : transaction . metadata . providerId ,
47- wallet : payload . authorization . from ,
48- cost : transaction . rawTransactionCost ,
49- expiresAt : new Date ( Date . now ( ) + 1000 * 60 * 60 * 1 ) ,
50- } ,
51- } ) ;
52- }
30+ const modelResultPromise = modelRequestService
31+ . executeModelRequest ( req , res , headers , provider , isStream )
32+ . then ( ( data ) => ( { success : true as const , data } ) )
33+ . catch ( ( error ) => ( { success : false as const , error : error as Error } ) ) ;
34+
35+ const [ settleResult , modelResult ] = await Promise . all ( [
36+ settlePromise ,
37+ modelResultPromise ,
38+ ] ) ;
39+
40+ // Case 1: Settle failed and model failed
41+ if ( ! settleResult && ! modelResult . success ) {
42+ return ;
43+ }
5344
45+ // Case 2: Settle failed but model succeeded
46+ if ( ! settleResult && modelResult . success ) {
47+ const { data } = modelResult ;
48+ logger . error ( 'Settle failed but model request succeeded' , {
49+ provider : provider . getType ( ) ,
50+ url : req . url ,
51+ metadata : data . transaction . metadata ,
52+ } ) ;
53+ logMetric ( 'x402_request_settle_failed_model_request_succeeded' , 1 , {
54+ provider : provider . getType ( ) ,
55+ url : req . url ,
56+ } ) ;
5457 modelRequestService . handleResolveResponse (
5558 res ,
5659 isStream ,
57- transactionResult . data
60+ data
5861 ) ;
62+ return ;
63+ }
5964
60- logger . info (
61- `Creating X402 transaction for app. Metadata: ${ JSON . stringify ( transaction . metadata ) } `
62- ) ;
63- const transactionCosts =
64- await x402AuthenticationService . createX402Transaction ( transaction ) ;
65-
66- await finalize (
67- paymentAmountDecimal ,
68- transactionCosts . rawTransactionCost ,
69- transactionCosts . totalAppProfit ,
70- transactionCosts . echoProfit ,
71- payload
72- ) ;
73- } catch ( error ) {
65+ // At this point, settleResult is guaranteed to exist
66+ if ( ! settleResult ) {
67+ return ;
68+ }
69+
70+ const { payload, paymentAmountDecimal } = settleResult ;
71+
72+ // Case 3: Settle succeeded but model failed
73+ if ( ! modelResult . success ) {
7474 await refund ( paymentAmountDecimal , payload ) ;
75+ return ;
7576 }
77+
78+ // Case 4: Both settle and model succeeded
79+ const transactionResult = modelResult . data ;
80+ const transaction = transactionResult . transaction ;
81+
82+ if ( provider . getType ( ) === ProviderType . OPENAI_VIDEOS ) {
83+ await prisma . videoGenerationX402 . create ( {
84+ data : {
85+ videoId : transaction . metadata . providerId ,
86+ wallet : payload . authorization . from ,
87+ cost : transaction . rawTransactionCost ,
88+ expiresAt : new Date ( Date . now ( ) + 1000 * 60 * 60 * 1 ) ,
89+ } ,
90+ } ) ;
91+ }
92+
93+ modelRequestService . handleResolveResponse (
94+ res ,
95+ isStream ,
96+ transactionResult . data
97+ ) ;
98+
99+ logger . info (
100+ `Creating X402 transaction for app. Metadata: ${ JSON . stringify ( transaction . metadata ) } `
101+ ) ;
102+ const transactionCosts =
103+ await x402AuthenticationService . createX402Transaction ( transaction ) ;
104+
105+ await finalize (
106+ paymentAmountDecimal ,
107+ transactionCosts . rawTransactionCost ,
108+ transactionCosts . totalAppProfit ,
109+ transactionCosts . echoProfit ,
110+ payload
111+ ) ;
76112}
77113
78114export async function handleApiKeyRequest ( {
0 commit comments