1- import { getUserTier , getModelByModelId } from './database' ;
1+ import { getUserTier , getModelByModelId , type UserTier } from './database' ;
22import redis from './redis' ;
33
44const MAX_TOKENS = parseInt ( process . env . RATE_LIMIT_ANONYMOUS_TOKENS || '25000' ) ;
@@ -23,18 +23,18 @@ export interface RateLimit {
2323export function formatTimeUntilReset ( resetTime : Date ) : string {
2424 const now = new Date ( ) ;
2525 const diff = resetTime . getTime ( ) - now . getTime ( ) ;
26-
26+
2727 if ( diff <= 0 ) {
2828 return 'now' ;
2929 }
30-
30+
3131 const hours = Math . floor ( diff / ( 1000 * 60 * 60 ) ) ;
3232 const minutes = Math . floor ( ( diff % ( 1000 * 60 * 60 ) ) / ( 1000 * 60 ) ) ;
33-
33+
3434 if ( hours > 0 ) {
3535 return `${ hours } h ${ minutes } m` ;
3636 }
37-
37+
3838 return `${ minutes } m` ;
3939}
4040
@@ -44,6 +44,39 @@ export interface RateLimitConfig {
4444 keyPrefix ?: string ;
4545}
4646
47+ // Cache for permissionless tier - initialized on first use
48+ let permissionlessTierCache : UserTier | null = null ;
49+ let permissionlessTierCachePromise : Promise < UserTier | null > | null = null ;
50+
51+ /**
52+ * Get cached permissionless tier from database
53+ */
54+ async function getPermissionlessTier ( ) : Promise < UserTier | null > {
55+ if ( permissionlessTierCache ) {
56+ return permissionlessTierCache ;
57+ }
58+
59+ // If already fetching, return the existing promise
60+ if ( permissionlessTierCachePromise ) {
61+ return permissionlessTierCachePromise ;
62+ }
63+
64+ // Start fetching and cache the promise
65+ permissionlessTierCachePromise = getUserTier ( null )
66+ . then ( tier => {
67+ permissionlessTierCache = tier ;
68+ permissionlessTierCachePromise = null ;
69+ return tier ;
70+ } )
71+ . catch ( error => {
72+ console . error ( 'Failed to cache permissionless tier:' , error ) ;
73+ permissionlessTierCachePromise = null ;
74+ return null ;
75+ } ) ;
76+
77+ return permissionlessTierCachePromise ;
78+ }
79+
4780export const DEFAULT_ANONYMOUS_LIMIT : RateLimitConfig = {
4881 maxTokens : MAX_TOKENS ,
4982 windowMs : 4 * 60 * 60 * 1000 , // 4 hours
@@ -72,22 +105,50 @@ export function getRateLimitConfig(isAuthenticated: boolean): RateLimitConfig {
72105 */
73106export async function getRateLimitConfigForUser ( userId : string | null ) : Promise < RateLimitConfig > {
74107 if ( ! userId ) {
108+ // Use cached permissionless tier from database
109+ const permissionlessTier = await getPermissionlessTier ( ) ;
110+ if ( permissionlessTier ) {
111+ return {
112+ maxTokens : permissionlessTier . token_limit ,
113+ windowMs : permissionlessTier . rate_limit_window_ms ,
114+ keyPrefix : 'token_limit:anonymous:' ,
115+ } ;
116+ }
117+ // Fallback to env var if database fetch fails
75118 return DEFAULT_ANONYMOUS_LIMIT ;
76119 }
77-
120+
78121 try {
79122 const userTier = await getUserTier ( userId ) ;
80123 if ( ! userTier ) {
124+ // User has no tier, use permissionless tier
125+ const permissionlessTier = await getPermissionlessTier ( ) ;
126+ if ( permissionlessTier ) {
127+ return {
128+ maxTokens : permissionlessTier . token_limit ,
129+ windowMs : permissionlessTier . rate_limit_window_ms ,
130+ keyPrefix : 'token_limit:user:' ,
131+ } ;
132+ }
81133 return DEFAULT_ANONYMOUS_LIMIT ;
82134 }
83-
135+
84136 return {
85137 maxTokens : userTier . token_limit ,
86138 windowMs : userTier . rate_limit_window_ms ,
87139 keyPrefix : 'token_limit:user:' ,
88140 } ;
89141 } catch ( error ) {
90142 console . error ( 'Error fetching user tier for rate limiting:' , error ) ;
143+ // Try to use cached permissionless tier as fallback
144+ const permissionlessTier = await getPermissionlessTier ( ) ;
145+ if ( permissionlessTier ) {
146+ return {
147+ maxTokens : permissionlessTier . token_limit ,
148+ windowMs : permissionlessTier . rate_limit_window_ms ,
149+ keyPrefix : 'token_limit:user:' ,
150+ } ;
151+ }
91152 return DEFAULT_ANONYMOUS_LIMIT ;
92153 }
93154}
0 commit comments