@@ -46,12 +46,18 @@ const TEMPLATE_BUILD_TIMEOUT_MS =
4646interface ListBuildsPaginationOptions {
4747 limit ?: number
4848 cursor ?: string
49+ direction ?: 'forward' | 'backward'
50+ }
51+
52+ interface PaginationCursor {
53+ timestamp : string
54+ direction : 'forward' | 'backward'
4955}
5056
5157interface ListBuildsPaginatedResult < T > {
5258 data : T [ ]
53- nextCursor : string | null
54- previousCursor : string | null
59+ nextCursor : PaginationCursor | null
60+ previousCursor : PaginationCursor | null
5561 hasMore : boolean
5662}
5763
@@ -111,7 +117,12 @@ export async function listBuilds(
111117 const isBuildUUID = isUUID ( buildIdOrTemplate )
112118
113119 if ( ! resolvedEnvId && ! isBuildUUID ) {
114- return { data : [ ] , nextCursor : null , previousCursor : null , hasMore : false }
120+ return {
121+ data : [ ] ,
122+ nextCursor : null ,
123+ previousCursor : null ,
124+ hasMore : false ,
125+ }
115126 }
116127
117128 if ( resolvedEnvId && isBuildUUID ) {
@@ -123,8 +134,14 @@ export async function listBuilds(
123134 }
124135 }
125136
137+ const isBackward = options . direction === 'backward'
138+
126139 if ( options . cursor ) {
127- query = query . lt ( 'created_at' , options . cursor )
140+ if ( isBackward ) {
141+ query = query . gt ( 'created_at' , options . cursor )
142+ } else {
143+ query = query . lt ( 'created_at' , options . cursor )
144+ }
128145 }
129146
130147 const { data : rawBuilds , error } = await query
@@ -134,17 +151,35 @@ export async function listBuilds(
134151 }
135152
136153 if ( ! rawBuilds || rawBuilds . length === 0 ) {
137- return { data : [ ] , nextCursor : null , previousCursor : null , hasMore : false }
154+ return {
155+ data : [ ] ,
156+ nextCursor : null ,
157+ previousCursor : null ,
158+ hasMore : false ,
159+ }
138160 }
139161
140- const builds = rawBuilds . map ( mapDatabaseBuildToListedBuildDTO )
162+ // for backward queries, we need to reverse to maintain chronological order (newest first)
163+ const orderedBuilds = isBackward ? [ ...rawBuilds ] . reverse ( ) : rawBuilds
164+
165+ const builds = orderedBuilds . map ( mapDatabaseBuildToListedBuildDTO )
141166 const hasMore = builds . length > limit
142167 const data = hasMore ? builds . slice ( 0 , limit ) : builds
143- const firstRawBuild = rawBuilds [ 0 ]
144- const lastRawBuild = rawBuilds [ data . length - 1 ]
145- const nextCursor = hasMore && lastRawBuild ? lastRawBuild . created_at : null
146- const previousCursor =
147- options . cursor && firstRawBuild ? firstRawBuild . created_at : null
168+ const firstRawBuild = orderedBuilds [ 0 ]
169+ const lastRawBuild = orderedBuilds [ data . length - 1 ]
170+
171+ // nextCursor: for fetching older builds (forward direction)
172+ const nextCursor : PaginationCursor | null =
173+ hasMore && lastRawBuild
174+ ? { timestamp : lastRawBuild . created_at , direction : 'forward' }
175+ : null
176+
177+ // previousCursor: for fetching newer builds (backward direction)
178+ // only available when we've navigated away from the first page
179+ const previousCursor : PaginationCursor | null =
180+ options . cursor && firstRawBuild
181+ ? { timestamp : firstRawBuild . created_at , direction : 'backward' }
182+ : null
148183
149184 return {
150185 data,
0 commit comments