MCPcopy Index your code
hub / github.com/CodebuffAI/codebuff / consumeFromOrderedGrants

Function consumeFromOrderedGrants

packages/billing/src/balance-calculator.ts:213–289  ·  view source on GitHub ↗
(
  params: {
    userId: string
    creditsToConsume: number
    grants: (typeof schema.creditLedger.$inferSelect)[]
    logger: Logger
  } & ParamsExcluding<
    typeof updateGrantBalance,
    'grant' | 'consumed' | 'newBalance'
  >,
)

Source from the content-addressed store, hash-verified

211 * new credits are added. This function only deepens debt on overflow.
212 */
213export async function consumeFromOrderedGrants(
214 params: {
215 userId: string
216 creditsToConsume: number
217 grants: (typeof schema.creditLedger.$inferSelect)[]
218 logger: Logger
219 } & ParamsExcluding<
220 typeof updateGrantBalance,
221 'grant' | 'consumed' | 'newBalance'
222 >,
223): Promise<CreditConsumptionResult> {
224 const { userId, creditsToConsume, grants, logger } = params
225
226 let remainingToConsume = creditsToConsume
227 let consumed = 0
228 let fromPurchased = 0
229
230 // Consume from positive balances in priority order.
231 // NOTE: debt grants (balance < 0) are skipped. Consumption never repays
232 // debt; that only happens via grant-credits.ts when new credits arrive.
233 for (const grant of grants) {
234 if (remainingToConsume <= 0) break
235 if (grant.balance <= 0) continue
236
237 const consumeFromThisGrant = Math.min(remainingToConsume, grant.balance)
238 const newBalance = grant.balance - consumeFromThisGrant
239 remainingToConsume -= consumeFromThisGrant
240 consumed += consumeFromThisGrant
241
242 // Track consumption from purchased credits
243 if (grant.type === 'purchase') {
244 fromPurchased += consumeFromThisGrant
245 }
246
247 await updateGrantBalance({
248 ...params,
249 grant,
250 consumed: consumeFromThisGrant,
251 newBalance,
252 })
253
254 // Mutate in-memory balance so the overflow check below sees
255 // post-consumption state (not the stale original value).
256 grant.balance = newBalance
257 }
258
259 // If we still have remaining to consume, create or extend debt on the
260 // last grant. After the loop above all positive-balance grants are drained.
261 // The "last grant" (lowest consumption priority, typically a subscription
262 // grant that renews monthly) absorbs the overflow as debt.
263 if (remainingToConsume > 0 && grants.length > 0) {
264 const lastGrant = grants[grants.length - 1]
265 const newBalance = lastGrant.balance - remainingToConsume
266
267 await updateGrantBalance({
268 ...params,
269 grant: lastGrant,
270 consumed: remainingToConsume,

Callers 3

consumeCreditsFunction · 0.70

Calls 1

updateGrantBalanceFunction · 0.70

Tested by

no test coverage detected