@@ -83,35 +83,61 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
8383 return NextResponse . json ( { error : cloudIdValidation . error } , { status : 400 } )
8484 }
8585
86- const url = `https://api.atlassian.com/ex/confluence/${ cloudIdValidation . sanitized } /wiki/api/v2/spaces?limit=250`
87-
88- const response = await fetch ( url , {
89- method : 'GET' ,
90- headers : {
91- Accept : 'application/json' ,
92- Authorization : `Bearer ${ accessToken } ` ,
93- } ,
94- } )
86+ const baseUrl = `https://api.atlassian.com/ex/confluence/${ cloudIdValidation . sanitized } /wiki/api/v2/spaces`
87+ const PAGE_LIMIT = 250
88+ const MAX_PAGES = 20
89+ const spaces : { id : string ; name : string ; key : string } [ ] = [ ]
90+ let cursor : string | undefined
91+ let pageCount = 0
92+
93+ while ( pageCount < MAX_PAGES ) {
94+ const params = new URLSearchParams ( { limit : String ( PAGE_LIMIT ) } )
95+ if ( cursor ) params . set ( 'cursor' , cursor )
96+ const url = `${ baseUrl } ?${ params . toString ( ) } `
9597
96- if ( ! response . ok ) {
97- const errorText = await response . text ( )
98- logger . error ( 'Confluence API error response:' , {
99- status : response . status ,
100- statusText : response . statusText ,
101- error : errorText ,
98+ const response = await fetch ( url , {
99+ method : 'GET' ,
100+ headers : {
101+ Accept : 'application/json' ,
102+ Authorization : `Bearer ${ accessToken } ` ,
103+ } ,
102104 } )
103- return NextResponse . json (
104- { error : parseAtlassianErrorMessage ( response . status , response . statusText , errorText ) } ,
105- { status : response . status }
106- )
105+
106+ if ( ! response . ok ) {
107+ const errorText = await response . text ( )
108+ logger . error ( 'Confluence API error response:' , {
109+ status : response . status ,
110+ statusText : response . statusText ,
111+ error : errorText ,
112+ } )
113+ return NextResponse . json (
114+ { error : parseAtlassianErrorMessage ( response . status , response . statusText , errorText ) } ,
115+ { status : response . status }
116+ )
117+ }
118+
119+ const data = await response . json ( )
120+ for ( const space of data . results || [ ] ) {
121+ spaces . push ( { id : space . id , name : space . name , key : space . key } )
122+ }
123+
124+ const nextLink = data . _links ?. next as string | undefined
125+ if ( ! nextLink ) break
126+ try {
127+ cursor = new URL ( nextLink , 'https://placeholder' ) . searchParams . get ( 'cursor' ) || undefined
128+ } catch {
129+ cursor = undefined
130+ }
131+ if ( ! cursor ) break
132+ pageCount += 1
107133 }
108134
109- const data = await response . json ( )
110- const spaces = ( data . results || [ ] ) . map ( ( space : { id : string ; name : string ; key : string } ) => ( {
111- id : space . id ,
112- name : space . name ,
113- key : space . key ,
114- } ) )
135+ if ( pageCount >= MAX_PAGES ) {
136+ logger . warn ( 'Confluence space listing hit pagination cap' , {
137+ cap : MAX_PAGES * PAGE_LIMIT ,
138+ returned : spaces . length ,
139+ } )
140+ }
115141
116142 return NextResponse . json ( { spaces } )
117143 } catch ( error ) {
0 commit comments