@@ -301,57 +301,85 @@ export async function findEnvironmentByApiKeyWithResolution(
301301 return resolveEnvironmentByApiKey ( apiKey , branchName , tx , additionalApiKeyLookupEnabled ) ;
302302}
303303
304- export type AdditionalApiKeyRateLimitScope = {
304+ export type PrivateApiKeyRateLimitScope = {
305305 environmentId : string ;
306- // Organization rate limiter override (bucket size), if configured.
307306 apiRateLimiterConfig : unknown ;
308307} ;
309308
310- /**
311- * Resolve ONLY the environment id (and its organization's rate limiter config)
312- * for an additional API key, for RATE-LIMIT BUCKETING.
313- *
314- * Deliberately scope-agnostic: unlike `findEnvironmentByApiKey`, a
315- * scope-restricted additional key still resolves here, so every additional key
316- * for an environment shares that environment's rate limit bucket. This is NOT
317- * an authentication or authorization decision and must never be used as one —
318- * request auth still goes through the RBAC bearer controller, which enforces
319- * scopes. Revoked and expired keys are excluded so they cannot keep a bucket
320- * warm.
321- */
322- export async function resolveAdditionalApiKeyRateLimitScope (
309+ export async function resolvePrivateApiKeyRateLimitScope (
323310 apiKey : string ,
324311 tx : PrismaClientOrTransaction = $replica
325- ) : Promise < AdditionalApiKeyRateLimitScope | null > {
326- if ( ! isAdditionalApiKey ( apiKey ) ) {
327- return null ;
328- }
329-
312+ ) : Promise < PrivateApiKeyRateLimitScope | null > {
330313 const now = new Date ( ) ;
331314
332- const match = await tx . apiKey . findFirst ( {
333- where : {
334- keyHash : hashApiKey ( apiKey ) ,
335- revokedAt : null ,
336- OR : [ { expiresAt : null } , { expiresAt : { gt : now } } ] ,
315+ if ( isAdditionalApiKey ( apiKey ) ) {
316+ const match = await tx . apiKey . findFirst ( {
317+ where : {
318+ keyHash : hashApiKey ( apiKey ) ,
319+ revokedAt : null ,
320+ OR : [ { expiresAt : null } , { expiresAt : { gt : now } } ] ,
321+ } ,
322+ select : {
323+ runtimeEnvironment : {
324+ select : {
325+ id : true ,
326+ organization : { select : { apiRateLimiterConfig : true } } ,
327+ } ,
328+ } ,
329+ } ,
330+ } ) ;
331+
332+ if ( ! match ?. runtimeEnvironment ) {
333+ return null ;
334+ }
335+
336+ return {
337+ environmentId : match . runtimeEnvironment . id ,
338+ apiRateLimiterConfig : match . runtimeEnvironment . organization . apiRateLimiterConfig ,
339+ } ;
340+ }
341+
342+ const environment = await tx . runtimeEnvironment . findFirst ( {
343+ where : { apiKey } ,
344+ select : {
345+ id : true ,
346+ project : { select : { deletedAt : true } } ,
347+ organization : { select : { apiRateLimiterConfig : true } } ,
337348 } ,
349+ } ) ;
350+
351+ if ( environment ) {
352+ if ( environment . project . deletedAt ) {
353+ return null ;
354+ }
355+
356+ return {
357+ environmentId : environment . id ,
358+ apiRateLimiterConfig : environment . organization . apiRateLimiterConfig ,
359+ } ;
360+ }
361+
362+ const revokedApiKey = await tx . revokedApiKey . findFirst ( {
363+ where : { apiKey, expiresAt : { gt : now } } ,
338364 select : {
339365 runtimeEnvironment : {
340366 select : {
341367 id : true ,
368+ project : { select : { deletedAt : true } } ,
342369 organization : { select : { apiRateLimiterConfig : true } } ,
343370 } ,
344371 } ,
345372 } ,
346373 } ) ;
347374
348- if ( ! match ?. runtimeEnvironment ) {
375+ const revokedEnvironment = revokedApiKey ?. runtimeEnvironment ;
376+ if ( ! revokedEnvironment || revokedEnvironment . project . deletedAt ) {
349377 return null ;
350378 }
351379
352380 return {
353- environmentId : match . runtimeEnvironment . id ,
354- apiRateLimiterConfig : match . runtimeEnvironment . organization . apiRateLimiterConfig ,
381+ environmentId : revokedEnvironment . id ,
382+ apiRateLimiterConfig : revokedEnvironment . organization . apiRateLimiterConfig ,
355383 } ;
356384}
357385
0 commit comments