@@ -67,6 +67,7 @@ export const createStream = async (req: Request, res: Response) => {
6767 depositedAmount,
6868 withdrawnAmount : "0" ,
6969 startTime : parseInt ( startTime ) ,
70+ endTime : parseInt ( startTime ) + Number ( BigInt ( depositedAmount ) / BigInt ( ratePerSecond ) ) ,
7071 lastUpdateTime : parseInt ( startTime )
7172 }
7273 } ) ;
@@ -79,26 +80,95 @@ export const createStream = async (req: Request, res: Response) => {
7980} ;
8081
8182/**
82- * List streams by sender or recipient
83+ * List streams by sender, recipient, status, token with sorting and pagination
8384 */
8485export const listStreams = async ( req : Request , res : Response ) => {
8586 try {
86- const { sender, recipient } = req . query ;
87+ const {
88+ sender,
89+ recipient,
90+ status,
91+ token,
92+ sort = 'createdAt' ,
93+ order = 'desc' ,
94+ limit = '20' ,
95+ offset = '0'
96+ } = req . query ;
8797
8898 const where : any = { } ;
8999 if ( typeof sender === 'string' ) where . sender = sender ;
90100 if ( typeof recipient === 'string' ) where . recipient = recipient ;
101+ if ( typeof token === 'string' ) where . tokenAddress = token ;
91102
92- const streams = await prisma . stream . findMany ( {
93- where,
94- orderBy : { createdAt : 'desc' } ,
95- include : {
96- senderUser : true ,
97- recipientUser : true
103+ // Handle status filtering
104+ if ( typeof status === 'string' ) {
105+ const validStatuses = [ 'active' , 'cancelled' , 'completed' , 'paused' ] ;
106+ if ( ! validStatuses . includes ( status ) ) {
107+ return res . status ( 400 ) . json ( {
108+ error : 'Invalid status parameter' ,
109+ message : `status must be one of: ${ validStatuses . join ( ', ' ) } `
110+ } ) ;
98111 }
99- } ) ;
100112
101- return res . status ( 200 ) . json ( streams ) ;
113+ // Map status to database conditions
114+ switch ( status ) {
115+ case 'active' :
116+ where . isActive = true ;
117+ where . isPaused = false ;
118+ break ;
119+ case 'cancelled' :
120+ where . isActive = false ;
121+ where . events = { some : { eventType : 'CANCELLED' } } ;
122+ break ;
123+ case 'completed' :
124+ where . isActive = false ;
125+ where . events = { some : { eventType : 'COMPLETED' } } ;
126+ break ;
127+ case 'paused' :
128+ where . isPaused = true ;
129+ break ;
130+ }
131+ }
132+
133+ // Validate and parse pagination parameters
134+ const parsedLimit = Math . min (
135+ typeof limit === 'string' ? ( Number . parseInt ( limit , 10 ) || 20 ) : 20 ,
136+ 100
137+ ) ;
138+ const parsedOffset = typeof offset === 'string' ? ( Number . parseInt ( offset , 10 ) || 0 ) : 0 ;
139+
140+ // Validate sort field
141+ const validSortFields = [ 'createdAt' , 'startTime' , 'lastUpdateTime' , 'depositedAmount' , 'endTime' ] ;
142+ const sortField = validSortFields . includes ( typeof sort === 'string' ? sort : 'createdAt' )
143+ ? ( sort as 'createdAt' | 'startTime' | 'lastUpdateTime' | 'depositedAmount' | 'endTime' )
144+ : 'createdAt' ;
145+
146+ // Validate order
147+ const sortOrder = order === 'asc' ? 'asc' : 'desc' ;
148+
149+ const [ streams , total ] = await Promise . all ( [
150+ prisma . stream . findMany ( {
151+ where,
152+ orderBy : { [ sortField ] : sortOrder } ,
153+ take : parsedLimit ,
154+ skip : parsedOffset ,
155+ include : {
156+ senderUser : true ,
157+ recipientUser : true
158+ }
159+ } ) ,
160+ prisma . stream . count ( { where } )
161+ ] ) ;
162+
163+ const hasMore = parsedOffset + streams . length < total ;
164+
165+ return res . status ( 200 ) . json ( {
166+ data : streams ,
167+ total,
168+ hasMore,
169+ limit : parsedLimit ,
170+ offset : parsedOffset
171+ } ) ;
102172 } catch ( error ) {
103173 logger . error ( 'Error listing streams:' , error ) ;
104174 return res . status ( 500 ) . json ( { error : 'Internal server error' } ) ;
@@ -184,9 +254,9 @@ export const getStreamEvents = async (req: Request, res: Response) => {
184254
185255 const whereClause : any = { streamId : parsedStreamId } ;
186256 if ( eventType ) {
187- const validEventTypes = [ 'CREATED' , 'TOPPED_UP' , 'WITHDRAWN' , 'CANCELLED' , 'COMPLETED' , 'PAUSED' , 'RESUMED' ] ;
257+ const validEventTypes = [ 'CREATED' , 'TOPPED_UP' , 'WITHDRAWN' , 'CANCELLED' , 'COMPLETED' , 'PAUSED' , 'RESUMED' , 'FEE_COLLECTED' ] ;
188258 if ( ! validEventTypes . includes ( eventType ) ) {
189- return res . status ( 400 ) . json ( {
259+ return res . status ( 400 ) . json ( {
190260 error : 'Invalid eventType parameter' ,
191261 message : `eventType must be one of: ${ validEventTypes . join ( ', ' ) } `
192262 } ) ;
@@ -251,8 +321,12 @@ export const getStreamClaimableAmount = async (req: Request, res: Response) => {
251321 ratePerSecond : true ,
252322 depositedAmount : true ,
253323 withdrawnAmount : true ,
324+ startTime : true ,
254325 lastUpdateTime : true ,
255326 isActive : true ,
327+ isPaused : true ,
328+ pausedAt : true ,
329+ totalPausedDuration : true ,
256330 updatedAt : true ,
257331 } ,
258332 } ) ;
@@ -302,7 +376,7 @@ export const getStreamClaimableAmount = async (req: Request, res: Response) => {
302376 */
303377export const getUserStreamSummary = async ( req : Request , res : Response ) => {
304378 try {
305- const address = ( req . params . address ?? '' ) . trim ( ) ;
379+ const address = Array . isArray ( req . params . address ) ? req . params . address [ 0 ] : ( req . params . address ?? '' ) . trim ( ) ;
306380 if ( ! address ) {
307381 return res . status ( 400 ) . json ( { error : 'Address is required' } ) ;
308382 }
@@ -331,18 +405,22 @@ export const getUserStreamSummary = async (req: Request, res: Response) => {
331405 ratePerSecond : true ,
332406 depositedAmount : true ,
333407 withdrawnAmount : true ,
408+ startTime : true ,
334409 lastUpdateTime : true ,
335410 isActive : true ,
411+ isPaused : true ,
412+ pausedAt : true ,
413+ totalPausedDuration : true ,
336414 updatedAt : true ,
337415 } ,
338416 } ) ,
339417 ] ) ;
340418
341419 const totalStreamsCreated = outgoingStreams . length ;
342- const totalStreamedOut = sumStringI128 ( outgoingStreams . map ( ( stream ) => stream . withdrawnAmount ) ) ;
343- const totalStreamedIn = sumStringI128 ( incomingStreams . map ( ( stream ) => stream . withdrawnAmount ) ) ;
344- const activeOutgoingCount = outgoingStreams . filter ( ( stream ) => stream . isActive ) . length ;
345- const activeIncomingCount = incomingStreams . filter ( ( stream ) => stream . isActive ) . length ;
420+ const totalStreamedOut = sumStringI128 ( outgoingStreams . map ( ( stream : any ) => stream . withdrawnAmount ) ) ;
421+ const totalStreamedIn = sumStringI128 ( incomingStreams . map ( ( stream : any ) => stream . withdrawnAmount ) ) ;
422+ const activeOutgoingCount = outgoingStreams . filter ( ( stream : any ) => stream . isActive ) . length ;
423+ const activeIncomingCount = incomingStreams . filter ( ( stream : any ) => stream . isActive ) . length ;
346424
347425 const calculatedAt = Math . floor ( nowMs / 1000 ) ;
348426 let claimableTotal = 0n ;
0 commit comments