@@ -154,37 +154,43 @@ export async function listPrincipals(
154154export interface ListGrantsFilter {
155155 readonly principalId ?: string ;
156156 readonly resource ?: string ;
157- readonly action ?: string ;
158157}
159158
160- /** Lists grants in the run's tenant, passing the given filters through as
161- * the native `GET /grants` query params (`principalId`, `resource`,
162- * `action`). */
159+ /** Lists every grant in the run's tenant matching the given filters,
160+ * following the native `nextCursor` pages to the end — the mirror honors
161+ * the same `principalId`/`resource` query params as the native
162+ * `GET /grants`. */
163163export async function listGrants (
164164 config : AccessToolClientConfig ,
165165 filter ?: ListGrantsFilter ,
166166) : Promise < ListedGrant [ ] > {
167167 const fetchImpl = config . fetchImpl ?? ( ( ...args ) => fetch ( ...args ) ) ;
168- const params = new URLSearchParams ( ) ;
169- if ( filter ?. principalId !== undefined )
170- params . set ( "principalId" , filter . principalId ) ;
171- if ( filter ?. resource !== undefined ) params . set ( "resource" , filter . resource ) ;
172- if ( filter ?. action !== undefined ) params . set ( "action" , filter . action ) ;
173- const query = params . size === 0 ? "" : `?${ params . toString ( ) } ` ;
174- const response = await fetchImpl ( `${ config . hubAccessUrl } /grants${ query } ` , {
175- headers : { ...authHeaders ( config ) } ,
176- } ) ;
177- if ( ! response . ok ) {
178- await throwForStatus ( "Listing grants" , response ) ;
179- }
180- const body : unknown = await response . json ( ) ;
181- const parsed = ListedGrantsResponse ( body ) ;
182- if ( parsed instanceof type . errors ) {
183- throw new Error (
184- `List-grants response did not match the expected shape: ${ parsed . summary } ` ,
185- ) ;
186- }
187- return parsed . data ;
168+ const grants : ListedGrant [ ] = [ ] ;
169+ let cursor : string | null | undefined ;
170+ do {
171+ const params = new URLSearchParams ( ) ;
172+ if ( filter ?. principalId !== undefined )
173+ params . set ( "principalId" , filter . principalId ) ;
174+ if ( filter ?. resource !== undefined ) params . set ( "resource" , filter . resource ) ;
175+ if ( cursor !== undefined && cursor !== null ) params . set ( "cursor" , cursor ) ;
176+ const query = params . size === 0 ? "" : `?${ params . toString ( ) } ` ;
177+ const response = await fetchImpl ( `${ config . hubAccessUrl } /grants${ query } ` , {
178+ headers : { ...authHeaders ( config ) } ,
179+ } ) ;
180+ if ( ! response . ok ) {
181+ await throwForStatus ( "Listing grants" , response ) ;
182+ }
183+ const body : unknown = await response . json ( ) ;
184+ const parsed = ListedGrantsResponse ( body ) ;
185+ if ( parsed instanceof type . errors ) {
186+ throw new Error (
187+ `List-grants response did not match the expected shape: ${ parsed . summary } ` ,
188+ ) ;
189+ }
190+ grants . push ( ...parsed . data ) ;
191+ cursor = parsed . nextCursor ?? null ;
192+ } while ( cursor !== null ) ;
193+ return grants ;
188194}
189195
190196/** Grants access by posting one native single-action `POST /grants` body
0 commit comments