@@ -88,6 +88,7 @@ export async function GET(request: NextRequest) {
8888 const apiKeyHeader = request . headers . get ( 'x-api-key' ) ;
8989 let merchantId : string | undefined ;
9090 let businessIds : string [ ] | undefined ;
91+ let scopedWalletAddresses : string [ ] = [ ] ;
9192
9293 if ( authHeader || apiKeyHeader ) {
9394 try {
@@ -115,31 +116,118 @@ export async function GET(request: NextRequest) {
115116
116117 if ( businesses && businesses . length > 0 ) {
117118 businessIds = businesses . map ( ( b : { id : string } ) => b . id ) ;
118- } else {
119- // Merchant has no businesses — return empty
120- return NextResponse . json ( { escrows : [ ] , total : 0 , limit : filters . limit , offset : filters . offset } ) ;
121119 }
120+
121+ // Also scope by wallets owned by this merchant (global + business wallets)
122+ const walletAddressSet = new Set < string > ( ) ;
123+
124+ const { data : merchantWallets } = await supabase
125+ . from ( 'merchant_wallets' )
126+ . select ( 'wallet_address' )
127+ . eq ( 'merchant_id' , merchantId )
128+ . eq ( 'is_active' , true ) ;
129+
130+ for ( const row of merchantWallets || [ ] ) {
131+ if ( row . wallet_address ) walletAddressSet . add ( row . wallet_address ) ;
132+ }
133+
134+ if ( businessIds && businessIds . length > 0 ) {
135+ const { data : businessWallets } = await supabase
136+ . from ( 'business_wallets' )
137+ . select ( 'wallet_address' )
138+ . in ( 'business_id' , businessIds )
139+ . eq ( 'is_active' , true ) ;
140+
141+ for ( const row of businessWallets || [ ] ) {
142+ if ( row . wallet_address ) walletAddressSet . add ( row . wallet_address ) ;
143+ }
144+ }
145+
146+ scopedWalletAddresses = Array . from ( walletAddressSet ) ;
122147 }
123148
124- // Must have at least one scoping filter (don't allow listing all escrows)
125- const hasFilter = filters . status || filters . depositor_address ||
126- filters . beneficiary_address || filters . business_id || businessIds ;
127- if ( ! hasFilter ) {
149+ // Must have a scoping filter (status alone must NOT allow listing all escrows)
150+ const hasScope = Boolean (
151+ filters . depositor_address ||
152+ filters . beneficiary_address ||
153+ filters . business_id ||
154+ ( businessIds && businessIds . length > 0 ) ||
155+ ( scopedWalletAddresses && scopedWalletAddresses . length > 0 )
156+ ) ;
157+ if ( ! hasScope ) {
128158 return NextResponse . json (
129- { error : 'At least one filter required (status, depositor, beneficiary, or business_id )' } ,
159+ { error : 'A scoping filter is required (depositor, beneficiary, business_id, or authenticated account scope )' } ,
130160 { status : 400 }
131161 ) ;
132162 }
133163
134- const result = await listEscrows ( supabase , { ...filters , business_ids : businessIds } as any ) ;
164+ const offset = Number ( filters . offset || 0 ) ;
165+ const limit = Number ( filters . limit || 20 ) ;
135166
136- if ( ! result . success ) {
137- return NextResponse . json ( { error : result . error } , { status : 500 } ) ;
167+ // If the caller explicitly scopes by depositor/beneficiary/business_id, keep direct behavior.
168+ const hasExplicitPartyScope = Boolean ( filters . depositor_address || filters . beneficiary_address || filters . business_id ) ;
169+ if ( hasExplicitPartyScope ) {
170+ const result = await listEscrows ( supabase , { ...filters , business_ids : businessIds } as any ) ;
171+
172+ if ( ! result . success ) {
173+ return NextResponse . json ( { error : result . error } , { status : 500 } ) ;
174+ }
175+
176+ return NextResponse . json ( {
177+ escrows : result . escrows ,
178+ total : result . total ,
179+ limit : filters . limit ,
180+ offset : filters . offset ,
181+ } ) ;
182+ }
183+
184+ // Implicit authenticated account scope: union of business escrows + wallet-party escrows.
185+ const aggregate = new Map < string , any > ( ) ;
186+ const queries : Array < Promise < { success : boolean ; escrows ?: any [ ] ; total ?: number ; error ?: string } > > = [ ] ;
187+
188+ if ( businessIds && businessIds . length > 0 ) {
189+ queries . push ( listEscrows ( supabase , {
190+ ...filters ,
191+ business_ids : businessIds ,
192+ limit : 500 ,
193+ offset : 0 ,
194+ } as any ) ) ;
195+ }
196+
197+ if ( scopedWalletAddresses . length > 0 ) {
198+ queries . push ( listEscrows ( supabase , {
199+ ...filters ,
200+ depositor_addresses : scopedWalletAddresses ,
201+ limit : 500 ,
202+ offset : 0 ,
203+ } as any ) ) ;
204+ queries . push ( listEscrows ( supabase , {
205+ ...filters ,
206+ beneficiary_addresses : scopedWalletAddresses ,
207+ limit : 500 ,
208+ offset : 0 ,
209+ } as any ) ) ;
210+ }
211+
212+ const results = await Promise . all ( queries ) ;
213+ for ( const result of results ) {
214+ if ( ! result . success ) {
215+ return NextResponse . json ( { error : result . error } , { status : 500 } ) ;
216+ }
217+ for ( const escrow of result . escrows || [ ] ) {
218+ aggregate . set ( escrow . id , escrow ) ;
219+ }
138220 }
139221
222+ const mergedEscrows = Array . from ( aggregate . values ( ) ) . sort ( ( a , b ) =>
223+ new Date ( b . created_at ) . getTime ( ) - new Date ( a . created_at ) . getTime ( )
224+ ) ;
225+
226+ const pagedEscrows = mergedEscrows . slice ( offset , offset + limit ) ;
227+
140228 return NextResponse . json ( {
141- escrows : result . escrows ,
142- total : result . total ,
229+ escrows : pagedEscrows ,
230+ total : mergedEscrows . length ,
143231 limit : filters . limit ,
144232 offset : filters . offset ,
145233 } ) ;
0 commit comments