11import { db } from '@sim/db'
2- import { userStats , workflow } from '@sim/db/schema'
2+ import { workflow } from '@sim/db/schema'
33import { createLogger } from '@sim/logger'
44import { eq , sql } from 'drizzle-orm'
55import { type NextRequest , NextResponse } from 'next/server'
66import { getBYOKKey } from '@/lib/api-key/byok'
77import { getSession } from '@/lib/auth'
8- import { logModelUsage } from '@/lib/billing/core/usage-log'
8+ import { recordUsage } from '@/lib/billing/core/usage-log'
99import { checkAndBillOverageThreshold } from '@/lib/billing/threshold-billing'
1010import { env } from '@/lib/core/config/env'
1111import { getCostMultiplier , isBillingEnabled } from '@/lib/core/config/feature-flags'
@@ -134,23 +134,21 @@ async function updateUserStatsForWand(
134134 costToStore = modelCost * costMultiplier
135135 }
136136
137- await db
138- . update ( userStats )
139- . set ( {
140- totalTokensUsed : sql `total_tokens_used + ${ totalTokens } ` ,
141- totalCost : sql `total_cost + ${ costToStore } ` ,
142- currentPeriodCost : sql `current_period_cost + ${ costToStore } ` ,
143- lastActive : new Date ( ) ,
144- } )
145- . where ( eq ( userStats . userId , userId ) )
146-
147- await logModelUsage ( {
137+ // Atomic write: usage_log INSERT + userStats UPDATE in one transaction
138+ await recordUsage ( {
148139 userId,
149- source : 'wand' ,
150- model : modelName ,
151- inputTokens : promptTokens ,
152- outputTokens : completionTokens ,
153- cost : costToStore ,
140+ entries : [
141+ {
142+ category : 'model' ,
143+ source : 'wand' ,
144+ description : modelName ,
145+ cost : costToStore ,
146+ metadata : { inputTokens : promptTokens , outputTokens : completionTokens } ,
147+ } ,
148+ ] ,
149+ additionalStats : {
150+ totalTokensUsed : sql `total_tokens_used + ${ totalTokens } ` ,
151+ } ,
154152 } )
155153
156154 await checkAndBillOverageThreshold ( userId )
@@ -341,7 +339,7 @@ export async function POST(req: NextRequest) {
341339 let finalUsage : any = null
342340 let usageRecorded = false
343341
344- const recordUsage = async ( ) => {
342+ const flushUsage = async ( ) => {
345343 if ( usageRecorded || ! finalUsage ) {
346344 return
347345 }
@@ -360,7 +358,7 @@ export async function POST(req: NextRequest) {
360358
361359 if ( done ) {
362360 logger . info ( `[${ requestId } ] Stream completed. Total chunks: ${ chunkCount } ` )
363- await recordUsage ( )
361+ await flushUsage ( )
364362 controller . enqueue ( encoder . encode ( `data: ${ JSON . stringify ( { done : true } ) } \n\n` ) )
365363 controller . close ( )
366364 break
@@ -390,7 +388,7 @@ export async function POST(req: NextRequest) {
390388 if ( data === '[DONE]' ) {
391389 logger . info ( `[${ requestId } ] Received [DONE] signal` )
392390
393- await recordUsage ( )
391+ await flushUsage ( )
394392
395393 controller . enqueue (
396394 encoder . encode ( `data: ${ JSON . stringify ( { done : true } ) } \n\n` )
@@ -468,7 +466,7 @@ export async function POST(req: NextRequest) {
468466 } )
469467
470468 try {
471- await recordUsage ( )
469+ await flushUsage ( )
472470 } catch ( usageError ) {
473471 logger . warn ( `[${ requestId } ] Failed to record usage after stream error` , usageError )
474472 }
0 commit comments