@@ -18,7 +18,6 @@ import type {
1818 SentryProject ,
1919} from "../../types/index.js" ;
2020
21- import { getAllOrgRegions } from "../db/regions.js" ;
2221import { type AuthGuardSuccess , withAuthGuard } from "../errors.js" ;
2322import { logger } from "../logger.js" ;
2423import { getApiBaseUrl } from "../sentry-client.js" ;
@@ -179,62 +178,35 @@ export async function findProjectsBySlug(
179178) : Promise < ProjectSearchResult > {
180179 const isNumericId = isAllDigits ( projectSlug ) ;
181180
182- /** Search for the project in a list of org slugs (parallel getProject per org). */
183- const searchOrgs = ( orgSlugs : string [ ] ) =>
184- Promise . all (
185- orgSlugs . map ( ( orgSlug ) =>
186- withAuthGuard ( async ( ) => {
187- const project = await getProject ( orgSlug , projectSlug ) ;
188- // The API accepts project_id_or_slug, so a numeric input could
189- // resolve by ID instead of slug. When the input is all digits,
190- // accept the match (the user passed a numeric project ID).
191- // For non-numeric inputs, verify the slug actually matches to
192- // avoid false positives from coincidental ID collisions.
193- // Note: Sentry enforces that project slugs must start with a letter,
194- // so an all-digits input can only ever be a numeric ID, never a slug.
195- if ( ! isNumericId && project . slug !== projectSlug ) {
196- return null ;
197- }
198- return { ...project , orgSlug } ;
199- } )
200- )
201- ) ;
202-
203- const extractProjects = (
204- results : Awaited < ReturnType < typeof searchOrgs > >
205- ) : ProjectWithOrg [ ] =>
206- results
207- . filter ( ( r ) : r is AuthGuardSuccess < ProjectWithOrg | null > => r . ok )
208- . map ( ( r ) => r . value )
209- . filter ( ( v ) : v is ProjectWithOrg => v !== null ) ;
210-
211- // Fast path: use cached org slugs to skip the expensive listOrganizations()
212- // round-trip (getUserRegions + listOrganizationsInRegion).
213- // The cache is expected to be complete: callers reach this function via the
214- // project-search format (e.g. "buybridge-5BS") whose short suffix only comes
215- // from `sentry issue list` output — which already called listOrganizations()
216- // and populated org_regions with all accessible orgs.
217- const cachedOrgRegions = await getAllOrgRegions ( ) ;
218- const cachedSlugs = [ ...cachedOrgRegions . keys ( ) ] ;
219- if ( cachedSlugs . length > 0 ) {
220- const cachedResults = await searchOrgs ( cachedSlugs ) ;
221- const cachedProjects = extractProjects ( cachedResults ) ;
222- if ( cachedProjects . length > 0 ) {
223- return { projects : cachedProjects , orgs : [ ] } ;
224- }
225- // Fall through: project might be in a new org not yet cached
226- }
227-
228- // Full listing: fetch all orgs from API, then skip already-searched cached orgs
181+ // listOrganizations() returns from cache when populated, avoiding
182+ // the expensive getUserRegions() + listOrganizationsInRegion() fan-out.
229183 const orgs = await listOrganizations ( ) ;
230- const cachedSet = new Set ( cachedSlugs ) ;
231- const newOrgSlugs = orgs
232- . filter ( ( o ) => ! cachedSet . has ( o . slug ) )
233- . map ( ( o ) => o . slug ) ;
234- const searchResults = await searchOrgs ( newOrgSlugs ) ;
184+
185+ // Direct lookup in parallel — one API call per org instead of paginating all projects
186+ const searchResults = await Promise . all (
187+ orgs . map ( ( org ) =>
188+ withAuthGuard ( async ( ) => {
189+ const project = await getProject ( org . slug , projectSlug ) ;
190+ // The API accepts project_id_or_slug, so a numeric input could
191+ // resolve by ID instead of slug. When the input is all digits,
192+ // accept the match (the user passed a numeric project ID).
193+ // For non-numeric inputs, verify the slug actually matches to
194+ // avoid false positives from coincidental ID collisions.
195+ // Note: Sentry enforces that project slugs must start with a letter,
196+ // so an all-digits input can only ever be a numeric ID, never a slug.
197+ if ( ! isNumericId && project . slug !== projectSlug ) {
198+ return null ;
199+ }
200+ return { ...project , orgSlug : org . slug } ;
201+ } )
202+ )
203+ ) ;
235204
236205 return {
237- projects : extractProjects ( searchResults ) ,
206+ projects : searchResults
207+ . filter ( ( r ) : r is AuthGuardSuccess < ProjectWithOrg | null > => r . ok )
208+ . map ( ( r ) => r . value )
209+ . filter ( ( v ) : v is ProjectWithOrg => v !== null ) ,
238210 orgs,
239211 } ;
240212}
0 commit comments