| | import { logger } from '@librechat/data-schemas'; |
| | import type { NextFunction, Request as ServerRequest, Response as ServerResponse } from 'express'; |
| | import type { IBalance, IUser, BalanceConfig, ObjectId, AppConfig } from '@librechat/data-schemas'; |
| | import type { Model } from 'mongoose'; |
| | import type { BalanceUpdateFields } from '~/types'; |
| | import { getBalanceConfig } from '~/app/config'; |
| |
|
| | export interface BalanceMiddlewareOptions { |
| | getAppConfig: (options?: { role?: string; refresh?: boolean }) => Promise<AppConfig>; |
| | Balance: Model<IBalance>; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | function buildUpdateFields( |
| | config: BalanceConfig, |
| | userRecord: IBalance | null, |
| | userId: string, |
| | ): BalanceUpdateFields { |
| | const updateFields: BalanceUpdateFields = {}; |
| |
|
| | |
| | if (!userRecord) { |
| | updateFields.user = userId; |
| | updateFields.tokenCredits = config.startBalance; |
| | } |
| |
|
| | if (userRecord?.tokenCredits == null && config.startBalance != null) { |
| | updateFields.tokenCredits = config.startBalance; |
| | } |
| |
|
| | const isAutoRefillConfigValid = |
| | config.autoRefillEnabled && |
| | config.refillIntervalValue != null && |
| | config.refillIntervalUnit != null && |
| | config.refillAmount != null; |
| |
|
| | if (!isAutoRefillConfigValid) { |
| | return updateFields; |
| | } |
| |
|
| | if (userRecord?.autoRefillEnabled !== config.autoRefillEnabled) { |
| | updateFields.autoRefillEnabled = config.autoRefillEnabled; |
| | } |
| |
|
| | if (userRecord?.refillIntervalValue !== config.refillIntervalValue) { |
| | updateFields.refillIntervalValue = config.refillIntervalValue; |
| | } |
| |
|
| | if (userRecord?.refillIntervalUnit !== config.refillIntervalUnit) { |
| | updateFields.refillIntervalUnit = config.refillIntervalUnit; |
| | } |
| |
|
| | if (userRecord?.refillAmount !== config.refillAmount) { |
| | updateFields.refillAmount = config.refillAmount; |
| | } |
| |
|
| | |
| | if (config.autoRefillEnabled && !userRecord?.lastRefill) { |
| | updateFields.lastRefill = new Date(); |
| | } |
| |
|
| | return updateFields; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export function createSetBalanceConfig({ |
| | getAppConfig, |
| | Balance, |
| | }: BalanceMiddlewareOptions): ( |
| | req: ServerRequest, |
| | res: ServerResponse, |
| | next: NextFunction, |
| | ) => Promise<void> { |
| | return async (req: ServerRequest, res: ServerResponse, next: NextFunction): Promise<void> => { |
| | try { |
| | const user = req.user as IUser & { _id: string | ObjectId }; |
| | const appConfig = await getAppConfig({ role: user?.role }); |
| | const balanceConfig = getBalanceConfig(appConfig); |
| | if (!balanceConfig?.enabled) { |
| | return next(); |
| | } |
| | if (balanceConfig.startBalance == null) { |
| | return next(); |
| | } |
| |
|
| | if (!user || !user._id) { |
| | return next(); |
| | } |
| | const userId = typeof user._id === 'string' ? user._id : user._id.toString(); |
| | const userBalanceRecord = await Balance.findOne({ user: userId }).lean(); |
| | const updateFields = buildUpdateFields(balanceConfig, userBalanceRecord, userId); |
| |
|
| | if (Object.keys(updateFields).length === 0) { |
| | return next(); |
| | } |
| |
|
| | await Balance.findOneAndUpdate( |
| | { user: userId }, |
| | { $set: updateFields }, |
| | { upsert: true, new: true }, |
| | ); |
| |
|
| | next(); |
| | } catch (error) { |
| | logger.error('Error setting user balance:', error); |
| | next(error); |
| | } |
| | }; |
| | } |
| |
|