@@ -63,12 +63,25 @@ export interface WeeklyLimitError {
6363 resetsAt : Date
6464}
6565
66- export type BlockGrantResult = BlockGrant | WeeklyLimitError
66+ export interface BlockExhaustedError {
67+ error : 'block_exhausted'
68+ blockUsed : number
69+ blockLimit : number
70+ resetsAt : Date
71+ }
72+
73+ export type BlockGrantResult = BlockGrant | WeeklyLimitError | BlockExhaustedError
6774
6875export function isWeeklyLimitError (
6976 result : BlockGrantResult ,
7077) : result is WeeklyLimitError {
71- return 'error' in result
78+ return 'error' in result && result . error === 'weekly_limit_reached'
79+ }
80+
81+ export function isBlockExhaustedError (
82+ result : BlockGrantResult ,
83+ ) : result is BlockExhaustedError {
84+ return 'error' in result && result . error === 'block_exhausted'
7285}
7386
7487export interface RateLimitStatus {
@@ -251,7 +264,7 @@ export async function ensureActiveBlockGrantCallback(params: {
251264 const { conn, userId, subscription, logger, now = new Date ( ) } = params
252265 const subscriptionId = subscription . stripe_subscription_id
253266
254- // 1. Check for an existing active block grant
267+ // 1. Check for an existing non-expired block grant (regardless of balance)
255268 const existingGrants = await conn
256269 . select ( )
257270 . from ( schema . creditLedger )
@@ -260,20 +273,31 @@ export async function ensureActiveBlockGrantCallback(params: {
260273 eq ( schema . creditLedger . user_id , userId ) ,
261274 eq ( schema . creditLedger . type , 'subscription' ) ,
262275 gt ( schema . creditLedger . expires_at , now ) ,
263- gt ( schema . creditLedger . balance , 0 ) ,
264276 ) ,
265277 )
266278 . orderBy ( desc ( schema . creditLedger . expires_at ) )
267279 . limit ( 1 )
268280
269281 if ( existingGrants . length > 0 ) {
270282 const g = existingGrants [ 0 ]
283+
284+ // Block exists with credits remaining - return it
285+ if ( g . balance > 0 ) {
286+ return {
287+ grantId : g . operation_id ,
288+ credits : g . balance ,
289+ expiresAt : g . expires_at ! ,
290+ isNew : false ,
291+ } satisfies BlockGrant
292+ }
293+
294+ // Block exists but is exhausted - don't create a new one until it expires
271295 return {
272- grantId : g . operation_id ,
273- credits : g . balance ,
274- expiresAt : g . expires_at ! ,
275- isNew : false ,
276- } satisfies BlockGrant
296+ error : 'block_exhausted' ,
297+ blockUsed : g . principal ,
298+ blockLimit : g . principal ,
299+ resetsAt : g . expires_at ! ,
300+ } satisfies BlockExhaustedError
277301 }
278302
279303 // 2. Resolve limits
0 commit comments