@@ -187,41 +187,6 @@ async function attemptRefreshWithActivityCheck(
187187 }
188188}
189189
190- function buildOrgProjectsMapFromUser (
191- user : Record < string , unknown > ,
192- ) : Record < string , OrgProjects > {
193- const org = user ?. organization as
194- | {
195- id ?: string ;
196- name ?: string ;
197- teams ?: { id : number | string ; name ?: string } [ ] ;
198- }
199- | undefined ;
200-
201- if ( ! org ?. id ) return { } ;
202-
203- const orgId = String ( org . id ) ;
204- const teams = Array . isArray ( org . teams ) ? org . teams : [ ] ;
205-
206- return {
207- [ orgId ] : {
208- orgName : org . name ?? "Unknown Organization" ,
209- projects : teams
210- . filter (
211- ( t ) : t is { id : number | string ; name ?: string } =>
212- t != null &&
213- typeof t === "object" &&
214- ( typeof t . id === "number" || typeof t . id === "string" ) ,
215- )
216- . map ( ( t ) => ( {
217- id : Number ( t . id ) ,
218- name : t . name ?? `Project ${ t . id } ` ,
219- } ) )
220- . filter ( ( t ) => ! Number . isNaN ( t . id ) ) ,
221- } ,
222- } ;
223- }
224-
225190async function buildOrgProjectsMap (
226191 user : Record < string , unknown > ,
227192 client : PostHogAPIClient ,
@@ -231,35 +196,88 @@ async function buildOrgProjectsMap(
231196 name ?: string ;
232197 } [ ] ;
233198
234- const entries = await Promise . all (
235- orgs . map ( async ( org ) => {
236- const projects = await client . listOrgProjects ( org . id ) . catch ( ( err ) => {
237- log . warn ( "Failed to fetch projects for org" , { orgId : org . id , err } ) ;
238- return null ;
239- } ) ;
240- return { orgId : org . id , orgName : org . name , projects } ;
241- } ) ,
242- ) ;
199+ const map : Record < string , OrgProjects > = { } ;
200+ for ( const org of orgs ) {
201+ map [ org . id ] = {
202+ orgName : org . name ?? "Unknown Organization" ,
203+ projects : [ ] ,
204+ } ;
205+ }
206+
207+ // Try the first org to check if org-level endpoints are accessible.
208+ // If not (e.g. project-scoped token), skip the rest and fall back to
209+ // the project-scoped endpoint.
210+ if ( orgs . length > 0 ) {
211+ try {
212+ map [ orgs [ 0 ] . id ] . projects = await client . listOrgProjects ( orgs [ 0 ] . id ) ;
213+
214+ // First org worked, fetch the rest in parallel
215+ if ( orgs . length > 1 ) {
216+ const rest = await Promise . all (
217+ orgs . slice ( 1 ) . map ( async ( org ) => {
218+ const projects = await client
219+ . listOrgProjects ( org . id )
220+ . catch ( ( err ) => {
221+ log . warn ( "Failed to fetch projects for org" , {
222+ orgId : org . id ,
223+ err,
224+ } ) ;
225+ return [ ] ;
226+ } ) ;
227+ return [ org . id , projects ] as const ;
228+ } ) ,
229+ ) ;
230+ for ( const [ orgId , projects ] of rest ) {
231+ map [ orgId ] . projects = projects ;
232+ }
233+ }
234+
235+ return map ;
236+ } catch ( err ) {
237+ log . warn (
238+ "Org-level project listing unavailable, falling back to project endpoint" ,
239+ { err } ,
240+ ) ;
241+ }
242+ }
243+
244+ // Fallback: switch into each org and read team from /me.
245+ // Both switchOrganization and getCurrentUser are user-level endpoints
246+ // that work regardless of token scoping.
247+ const currentOrgId = ( user ?. organization as { id ?: string } | undefined ) ?. id ;
248+
249+ for ( const org of orgs ) {
250+ try {
251+ let orgUser : Record < string , unknown > ;
252+ if ( org . id === currentOrgId ) {
253+ orgUser = user ;
254+ } else {
255+ await client . switchOrganization ( org . id ) ;
256+ orgUser = await client . getCurrentUser ( ) ;
257+ }
243258
244- const allFailed =
245- entries . length > 0 && entries . every ( ( e ) => e . projects === null ) ;
259+ const team = orgUser ?. team as { id ?: number ; name ?: string } | undefined ;
260+ if ( team ?. id && map [ org . id ] ) {
261+ map [ org . id ] . projects = [
262+ { id : team . id , name : team . name ?? `Project ${ team . id } ` } ,
263+ ] ;
264+ }
265+ } catch ( err ) {
266+ log . warn ( "Failed to fetch project via org switch" , {
267+ orgId : org . id ,
268+ err,
269+ } ) ;
270+ }
271+ }
246272
247- if ( allFailed ) {
248- log . warn (
249- "All org project calls failed, falling back to user organization teams" ,
250- ) ;
251- return buildOrgProjectsMapFromUser ( user ) ;
273+ // Switch back to the original org
274+ if ( currentOrgId && orgs . length > 1 ) {
275+ await client . switchOrganization ( currentOrgId ) . catch ( ( err ) => {
276+ log . warn ( "Failed to switch back to original org" , { err } ) ;
277+ } ) ;
252278 }
253279
254- return Object . fromEntries (
255- entries . map ( ( e ) => [
256- e . orgId ,
257- {
258- orgName : e . orgName ?? "Unknown Organization" ,
259- projects : e . projects ?? [ ] ,
260- } ,
261- ] ) ,
262- ) ;
280+ return map ;
263281}
264282
265283export const useAuthStore = create < AuthState > ( ) (
0 commit comments