@nehorai/credits-drizzle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/repository/index.ts","../../src/schema/index.ts"],"sourcesContent":["import { and, count, desc, eq, gte, lte, lt, sql } from 'drizzle-orm'\nimport type {\n AIProviderType,\n CreateJournalEntryInput,\n CreateReservationInput,\n CreateTransactionInput,\n CreateUsageLogInput,\n CreditBalanceUpdate,\n CreditOperationType,\n ICreditRepository,\n JournalEntryQuery,\n JournalReferenceType,\n MonthlyResetResult,\n PortableJournalEntry,\n PortableReservation,\n PortableTransaction,\n PortableUsageLog,\n PortableUserCredits,\n ReservationStatus,\n SubscriptionExpiryResult,\n SubscriptionTier,\n TierUpdateInput,\n UsageLogQuery,\n} from '@nehorai/credits'\nimport {\n getConfigMonthlyLimit,\n getConfigTierConfig,\n} from '@nehorai/credits'\nimport { getNextMonthlyReset } from '@nehorai/credits'\nimport {\n creditBalances,\n creditJournalEntries,\n creditPluginTransactions,\n creditReservations,\n creditUsageLogs,\n type CreditBalanceRow,\n type CreditJournalEntryRow,\n type CreditPluginTransactionRow,\n type CreditReservationRow,\n type CreditUsageLogRow,\n} from '../schema/index.js'\n\nexport interface DrizzleLikeDB {\n select: (...args: any[]) => any\n insert: (...args: any[]) => any\n update: (...args: any[]) => any\n transaction?: <T>(callback: (tx: DrizzleLikeDB) => Promise<T>) => Promise<T>\n}\n\nfunction numberValue(value: unknown): number {\n if (value === null || value === undefined) return 0\n if (typeof value === 'number') return value\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n}\n\nfunction dateValue(value: Date | string | null | undefined): Date | null {\n if (!value) return null\n return value instanceof Date ? value : new Date(value)\n}\n\nfunction iso(value: Date | string | null | undefined): string {\n if (!value) return new Date().toISOString()\n return value instanceof Date ? value.toISOString() : new Date(value).toISOString()\n}\n\nfunction toUserCredits(row: CreditBalanceRow): PortableUserCredits {\n return {\n userId: row.userId,\n balance: numberValue(row.balance),\n bonusCredits: numberValue(row.bonusCredits),\n reserved: numberValue(row.reserved),\n tier: row.tier as SubscriptionTier,\n monthlyLimit: numberValue(row.monthlyLimit),\n monthlyUsed: numberValue(row.monthlyUsed),\n monthlyResetAt: iso(row.monthlyResetAt),\n subscriptionExpiresAt: row.subscriptionExpiresAt ? iso(row.subscriptionExpiresAt) : null,\n createdAt: iso(row.createdAt),\n updatedAt: iso(row.updatedAt),\n }\n}\n\nfunction toReservation(row: CreditReservationRow): PortableReservation {\n return {\n id: row.id,\n userId: row.userId,\n amount: numberValue(row.amount),\n operationType: row.operationType as CreditOperationType,\n status: row.status as ReservationStatus,\n createdAt: iso(row.createdAt),\n expiresAt: iso(row.expiresAt),\n completedAt: row.completedAt ? iso(row.completedAt) : undefined,\n }\n}\n\nfunction toTransaction(row: CreditPluginTransactionRow): PortableTransaction {\n return {\n id: row.id,\n userId: row.userId,\n type: row.type as PortableTransaction['type'],\n amount: numberValue(row.amount),\n description: row.description,\n paymentRef: row.paymentRef ?? undefined,\n previousBalance: numberValue(row.previousBalance),\n newBalance: numberValue(row.newBalance),\n createdAt: iso(row.createdAt),\n }\n}\n\nfunction toUsageLog(row: CreditUsageLogRow): PortableUsageLog {\n return {\n id: row.id,\n userId: row.userId,\n operationType: row.operationType as CreditOperationType,\n provider: row.provider as AIProviderType,\n creditsUsed: numberValue(row.creditsUsed),\n success: row.success,\n errorMessage: row.errorMessage ?? undefined,\n resourceId: row.resourceId ?? undefined,\n resourceType: row.resourceType ?? undefined,\n requestId: row.requestId ?? undefined,\n metadata: row.metadata ?? undefined,\n createdAt: iso(row.createdAt),\n }\n}\n\nfunction toJournalEntry(row: CreditJournalEntryRow): PortableJournalEntry {\n return {\n id: row.id,\n userId: row.userId,\n entryType: row.entryType as 'debit' | 'credit',\n amount: numberValue(row.amount),\n balanceAfter: numberValue(row.balanceAfter),\n source: row.source as PortableJournalEntry['source'],\n referenceId: row.referenceId,\n referenceType: row.referenceType as JournalReferenceType,\n description: row.description,\n metadata: row.metadata ?? undefined,\n createdAt: iso(row.createdAt),\n }\n}\n\nexport class DrizzleCreditRepository implements ICreditRepository {\n constructor(private readonly db: DrizzleLikeDB) {}\n\n private async withTx<T>(callback: (tx: DrizzleLikeDB) => Promise<T>): Promise<T> {\n if (this.db.transaction) {\n return this.db.transaction(callback)\n }\n return callback(this.db)\n }\n\n private async ensureUserCredits(\n db: DrizzleLikeDB,\n userId: string,\n tier: SubscriptionTier = 'free'\n ): Promise<PortableUserCredits> {\n const existing = await db.select().from(creditBalances).where(eq(creditBalances.userId, userId)).limit(1)\n if (existing[0]) return toUserCredits(existing[0])\n\n const monthlyLimit = getConfigMonthlyLimit(tier)\n const initialBalance = Number.isFinite(monthlyLimit) ? monthlyLimit : 0\n const inserted = await db\n .insert(creditBalances)\n .values({\n userId,\n tier,\n balance: String(initialBalance),\n monthlyLimit: String(initialBalance),\n monthlyResetAt: getNextMonthlyReset(),\n })\n .onConflictDoNothing()\n .returning()\n\n if (inserted[0]) return toUserCredits(inserted[0])\n\n const afterConflict = await db.select().from(creditBalances).where(eq(creditBalances.userId, userId)).limit(1)\n if (!afterConflict[0]) {\n throw new Error(`Failed to initialize credits for user ${userId}`)\n }\n return toUserCredits(afterConflict[0])\n }\n\n async getUserCredits(userId: string): Promise<PortableUserCredits | null> {\n const rows = await this.db.select().from(creditBalances).where(eq(creditBalances.userId, userId)).limit(1)\n return rows[0] ? toUserCredits(rows[0]) : null\n }\n\n async initializeUserCredits(\n userId: string,\n tier: SubscriptionTier,\n initialBalance: number\n ): Promise<PortableUserCredits> {\n const monthlyLimit = getConfigMonthlyLimit(tier)\n const rows = await this.db\n .insert(creditBalances)\n .values({\n userId,\n tier,\n balance: String(initialBalance),\n monthlyLimit: String(Number.isFinite(monthlyLimit) ? monthlyLimit : 0),\n monthlyResetAt: getNextMonthlyReset(),\n })\n .onConflictDoUpdate({\n target: creditBalances.userId,\n set: { updatedAt: new Date() },\n })\n .returning()\n\n return toUserCredits(rows[0])\n }\n\n async updateUserCredits(userId: string, updates: CreditBalanceUpdate): Promise<void> {\n const set: Record<string, unknown> = { updatedAt: new Date() }\n if (updates.balance !== undefined) set.balance = String(updates.balance)\n if (updates.bonusCredits !== undefined) set.bonusCredits = String(updates.bonusCredits)\n if (updates.reserved !== undefined) set.reserved = String(updates.reserved)\n if (updates.tier !== undefined) set.tier = updates.tier\n if (updates.monthlyLimit !== undefined) set.monthlyLimit = String(updates.monthlyLimit)\n if (updates.monthlyUsed !== undefined) set.monthlyUsed = String(updates.monthlyUsed)\n if (updates.monthlyResetAt !== undefined) set.monthlyResetAt = dateValue(updates.monthlyResetAt)\n if (updates.subscriptionExpiresAt !== undefined) set.subscriptionExpiresAt = dateValue(updates.subscriptionExpiresAt)\n\n await this.db\n .update(creditBalances)\n .set({\n ...set,\n balance:\n updates.balanceIncrement !== undefined\n ? sql`${creditBalances.balance} + ${updates.balanceIncrement}`\n : set.balance,\n bonusCredits:\n updates.bonusCreditsIncrement !== undefined\n ? sql`${creditBalances.bonusCredits} + ${updates.bonusCreditsIncrement}`\n : set.bonusCredits,\n reserved:\n updates.reservedIncrement !== undefined\n ? sql`${creditBalances.reserved} + ${updates.reservedIncrement}`\n : set.reserved,\n monthlyUsed:\n updates.monthlyUsedIncrement !== undefined\n ? sql`${creditBalances.monthlyUsed} + ${updates.monthlyUsedIncrement}`\n : set.monthlyUsed,\n } as any)\n .where(eq(creditBalances.userId, userId))\n }\n\n async updateUserTier(userId: string, input: TierUpdateInput): Promise<void> {\n await this.db\n .update(creditBalances)\n .set({\n tier: input.tier,\n monthlyLimit: String(input.monthlyLimit),\n balance: input.balance !== undefined ? String(input.balance) : undefined,\n monthlyUsed: input.monthlyUsed !== undefined ? String(input.monthlyUsed) : undefined,\n subscriptionExpiresAt:\n input.subscriptionExpiresAt !== undefined ? dateValue(input.subscriptionExpiresAt) : undefined,\n updatedAt: new Date(),\n } as any)\n .where(eq(creditBalances.userId, userId))\n }\n\n async createReservation(input: CreateReservationInput): Promise<PortableReservation> {\n const rows = await this.db\n .insert(creditReservations)\n .values({\n userId: input.userId,\n amount: String(input.amount),\n operationType: input.operationType,\n expiresAt: input.expiresAt,\n })\n .returning()\n return toReservation(rows[0])\n }\n\n async getReservation(userId: string, reservationId: string): Promise<PortableReservation | null> {\n const rows = await this.db\n .select()\n .from(creditReservations)\n .where(and(eq(creditReservations.userId, userId), eq(creditReservations.id, reservationId)))\n .limit(1)\n return rows[0] ? toReservation(rows[0]) : null\n }\n\n async updateReservationStatus(\n userId: string,\n reservationId: string,\n status: ReservationStatus,\n completedAt?: Date\n ): Promise<void> {\n await this.db\n .update(creditReservations)\n .set({ status, completedAt: completedAt ?? new Date() })\n .where(and(eq(creditReservations.userId, userId), eq(creditReservations.id, reservationId)))\n }\n\n async reserveCreditsAtomic(\n userId: string,\n amount: number,\n operationType: CreditOperationType,\n expiresAt: Date\n ): Promise<PortableReservation> {\n return this.withTx(async (tx) => {\n await this.ensureUserCredits(tx, userId)\n const updated = await tx\n .update(creditBalances)\n .set({\n reserved: sql`${creditBalances.reserved} + ${amount}`,\n updatedAt: new Date(),\n })\n .where(\n and(\n eq(creditBalances.userId, userId),\n sql`${creditBalances.balance} + ${creditBalances.bonusCredits} - ${creditBalances.reserved} >= ${amount}`\n )\n )\n .returning()\n\n if (!updated[0]) {\n throw new Error(`Insufficient credits for user ${userId}`)\n }\n\n const reservation = await tx\n .insert(creditReservations)\n .values({\n userId,\n amount: String(amount),\n operationType,\n expiresAt,\n })\n .returning()\n return toReservation(reservation[0])\n })\n }\n\n async commitReservationAtomic(userId: string, reservationId: string): Promise<void> {\n await this.withTx(async (tx) => {\n const reservationRows = await tx\n .select()\n .from(creditReservations)\n .where(and(eq(creditReservations.userId, userId), eq(creditReservations.id, reservationId)))\n .limit(1)\n const reservation = reservationRows[0]\n if (!reservation) throw new Error(`Reservation ${reservationId} not found`)\n if (reservation.status === 'committed') return\n if (reservation.status !== 'reserved') {\n throw new Error(`Cannot commit reservation in ${reservation.status} state`)\n }\n\n const creditRows = await tx.select().from(creditBalances).where(eq(creditBalances.userId, userId)).limit(1)\n const credits = creditRows[0]\n if (!credits) throw new Error(`User credits not found for user ${userId}`)\n\n const amount = numberValue(reservation.amount)\n const balance = numberValue(credits.balance)\n const bonusCredits = numberValue(credits.bonusCredits)\n if (balance + bonusCredits < amount) {\n throw new Error(`Insufficient credits to commit reservation ${reservationId}`)\n }\n\n const balanceDeduction = Math.min(balance, amount)\n const bonusDeduction = amount - balanceDeduction\n const previousTotal = balance + bonusCredits\n const newTotal = previousTotal - amount\n\n await tx\n .update(creditBalances)\n .set({\n balance: String(balance - balanceDeduction),\n bonusCredits: String(bonusCredits - bonusDeduction),\n reserved: sql`greatest(${creditBalances.reserved} - ${amount}, 0)`,\n monthlyUsed: sql`${creditBalances.monthlyUsed} + ${amount}`,\n updatedAt: new Date(),\n })\n .where(eq(creditBalances.userId, userId))\n\n await tx\n .update(creditReservations)\n .set({ status: 'committed', completedAt: new Date() })\n .where(and(eq(creditReservations.userId, userId), eq(creditReservations.id, reservationId)))\n\n await tx.insert(creditJournalEntries).values({\n userId,\n entryType: 'debit',\n amount: String(amount),\n balanceAfter: String(newTotal),\n source: 'operation_commit',\n referenceId: reservationId,\n referenceType: 'reservation',\n description: `Committed ${amount} credits`,\n })\n })\n }\n\n async releaseReservationAtomic(userId: string, reservationId: string): Promise<void> {\n await this.withTx(async (tx) => {\n const reservationRows = await tx\n .select()\n .from(creditReservations)\n .where(and(eq(creditReservations.userId, userId), eq(creditReservations.id, reservationId)))\n .limit(1)\n const reservation = reservationRows[0]\n if (!reservation) throw new Error(`Reservation ${reservationId} not found`)\n if (reservation.status !== 'reserved') return\n\n const amount = numberValue(reservation.amount)\n await tx\n .update(creditBalances)\n .set({\n reserved: sql`greatest(${creditBalances.reserved} - ${amount}, 0)`,\n updatedAt: new Date(),\n })\n .where(eq(creditBalances.userId, userId))\n await tx\n .update(creditReservations)\n .set({ status: 'released', completedAt: new Date() })\n .where(and(eq(creditReservations.userId, userId), eq(creditReservations.id, reservationId)))\n })\n }\n\n async addCreditsAtomic(\n userId: string,\n amount: number,\n description: string,\n paymentRef?: string\n ): Promise<void> {\n await this.withTx(async (tx) => {\n if (paymentRef) {\n const existing = await tx\n .select()\n .from(creditPluginTransactions)\n .where(eq(creditPluginTransactions.paymentRef, paymentRef))\n .limit(1)\n if (existing[0]) return\n }\n\n const credits = await this.ensureUserCredits(tx, userId)\n const previousBalance = credits.balance + credits.bonusCredits\n const newBalance = previousBalance + amount\n\n await tx\n .update(creditBalances)\n .set({\n bonusCredits: sql`${creditBalances.bonusCredits} + ${amount}`,\n updatedAt: new Date(),\n })\n .where(eq(creditBalances.userId, userId))\n\n const inserted = await tx\n .insert(creditPluginTransactions)\n .values({\n userId,\n type: 'purchase',\n amount: String(amount),\n description,\n paymentRef,\n previousBalance: String(previousBalance),\n newBalance: String(newBalance),\n })\n .returning()\n\n await tx.insert(creditJournalEntries).values({\n userId,\n entryType: 'credit',\n amount: String(amount),\n balanceAfter: String(newBalance),\n source: 'purchase',\n referenceId: inserted[0]?.id ?? paymentRef ?? 'unknown',\n referenceType: 'transaction',\n description,\n metadata: paymentRef ? { paymentRef } : undefined,\n })\n })\n }\n\n async deductCreditsAtomic(userId: string, amount: number): Promise<{ previousBalance: number; newBalance: number }> {\n return this.withTx(async (tx) => {\n const creditRows = await tx.select().from(creditBalances).where(eq(creditBalances.userId, userId)).limit(1)\n const credits = creditRows[0]\n if (!credits) throw new Error(`User credits not found for user ${userId}`)\n\n const balance = numberValue(credits.balance)\n const bonusCredits = numberValue(credits.bonusCredits)\n const reserved = numberValue(credits.reserved)\n const available = balance + bonusCredits - reserved\n if (available < amount) {\n throw new Error(`Insufficient credits. Available: ${available}, requested: ${amount}`)\n }\n\n const balanceDeduction = Math.min(balance, amount)\n const bonusDeduction = amount - balanceDeduction\n const previousBalance = balance + bonusCredits\n const newBalance = previousBalance - amount\n\n await tx\n .update(creditBalances)\n .set({\n balance: String(balance - balanceDeduction),\n bonusCredits: String(bonusCredits - bonusDeduction),\n updatedAt: new Date(),\n })\n .where(eq(creditBalances.userId, userId))\n\n return { previousBalance, newBalance }\n })\n }\n\n async createTransaction(input: CreateTransactionInput): Promise<PortableTransaction> {\n const rows = await this.db\n .insert(creditPluginTransactions)\n .values({\n userId: input.userId,\n type: input.type,\n amount: String(input.amount),\n description: input.description,\n paymentRef: input.paymentRef,\n previousBalance: String(input.previousBalance),\n newBalance: String(input.newBalance),\n })\n .returning()\n return toTransaction(rows[0])\n }\n\n async getTransactions(userId: string, limit = 50, offset = 0): Promise<PortableTransaction[]> {\n const rows = await this.db\n .select()\n .from(creditPluginTransactions)\n .where(eq(creditPluginTransactions.userId, userId))\n .orderBy(desc(creditPluginTransactions.createdAt))\n .limit(limit)\n .offset(offset)\n return rows.map(toTransaction)\n }\n\n async logUsage(input: CreateUsageLogInput): Promise<PortableUsageLog> {\n const rows = await this.db\n .insert(creditUsageLogs)\n .values({\n userId: input.userId,\n operationType: input.operationType,\n provider: input.provider,\n creditsUsed: String(input.creditsUsed),\n success: input.success,\n errorMessage: input.errorMessage,\n resourceId: input.resourceId,\n resourceType: input.resourceType,\n requestId: input.requestId,\n metadata: input.metadata,\n })\n .returning()\n return toUsageLog(rows[0])\n }\n\n async getUsageLogs(query: UsageLogQuery): Promise<PortableUsageLog[]> {\n const filters = this.usageFilters(query)\n const rows = await this.db\n .select()\n .from(creditUsageLogs)\n .where(filters.length ? and(...filters) : undefined)\n .orderBy(desc(creditUsageLogs.createdAt))\n .limit(query.limit ?? 50)\n .offset(query.offset ?? 0)\n return rows.map(toUsageLog)\n }\n\n async getUsageLogsCount(query: Omit<UsageLogQuery, 'limit' | 'offset'>): Promise<number> {\n const filters = this.usageFilters(query)\n const rows = await this.db\n .select({ value: count() })\n .from(creditUsageLogs)\n .where(filters.length ? and(...filters) : undefined)\n return Number(rows[0]?.value ?? 0)\n }\n\n async findAndExpireReservations(batchSize = 100, maxIterations = 100): Promise<{\n expiredCount: number\n creditsReleased: number\n errors: string[]\n }> {\n const errors: string[] = []\n let expiredCount = 0\n let creditsReleased = 0\n\n for (let i = 0; i < maxIterations; i += 1) {\n const rows = await this.db\n .select()\n .from(creditReservations)\n .where(and(eq(creditReservations.status, 'reserved'), lt(creditReservations.expiresAt, new Date())))\n .limit(batchSize)\n if (rows.length === 0) break\n\n for (const row of rows) {\n try {\n await this.releaseReservationAtomic(row.userId, row.id)\n await this.db\n .update(creditReservations)\n .set({ status: 'expired', completedAt: new Date() })\n .where(eq(creditReservations.id, row.id))\n expiredCount += 1\n creditsReleased += numberValue(row.amount)\n } catch (error) {\n errors.push(`Failed to expire reservation ${row.id}: ${String(error)}`)\n }\n }\n }\n\n return { expiredCount, creditsReleased, errors }\n }\n\n async atomicMonthlyReset(\n userId: string,\n tier: SubscriptionTier,\n expectedResetAt: Date | string\n ): Promise<MonthlyResetResult> {\n const newBalance = getConfigMonthlyLimit(tier)\n const nextReset = getNextMonthlyReset()\n const expected = dateValue(expectedResetAt)\n const rows = await this.db\n .update(creditBalances)\n .set({\n balance: Number.isFinite(newBalance) ? String(newBalance) : sql`${creditBalances.balance}`,\n monthlyUsed: '0',\n monthlyResetAt: nextReset,\n updatedAt: new Date(),\n } as any)\n .where(and(eq(creditBalances.userId, userId), eq(creditBalances.monthlyResetAt, expected as Date)))\n .returning()\n\n if (rows[0]) return { wasReset: true, credits: toUserCredits(rows[0]) }\n const current = await this.getUserCredits(userId)\n if (!current) throw new Error(`User ${userId} not found`)\n return { wasReset: false, credits: current }\n }\n\n async checkAndHandleSubscriptionExpiry(userId: string, gracePeriodDays = 3): Promise<SubscriptionExpiryResult> {\n const credits = await this.getUserCredits(userId)\n if (!credits) throw new Error(`User ${userId} not found`)\n\n const tierConfig = getConfigTierConfig(credits.tier) as { isFree?: boolean }\n if ((tierConfig.isFree ?? credits.tier === 'free') || !credits.subscriptionExpiresAt) {\n return { wasDowngraded: false, inGracePeriod: false, graceDaysRemaining: 0, credits }\n }\n\n const expiresAt = new Date(credits.subscriptionExpiresAt)\n const daysSinceExpiry = (Date.now() - expiresAt.getTime()) / (1000 * 60 * 60 * 24)\n if (daysSinceExpiry <= 0) {\n return { wasDowngraded: false, inGracePeriod: false, graceDaysRemaining: 0, credits }\n }\n if (daysSinceExpiry <= gracePeriodDays) {\n return {\n wasDowngraded: false,\n inGracePeriod: true,\n graceDaysRemaining: Math.ceil(gracePeriodDays - daysSinceExpiry),\n credits,\n }\n }\n\n const defaultTier = 'free' as SubscriptionTier\n const defaultTierConfig = getConfigTierConfig(defaultTier)\n await this.updateUserTier(userId, {\n tier: defaultTier,\n monthlyLimit: defaultTierConfig.monthlyCredits,\n balance: Math.min(credits.balance, defaultTierConfig.monthlyCredits),\n subscriptionExpiresAt: null,\n })\n const updatedCredits = (await this.getUserCredits(userId)) ?? credits\n return { wasDowngraded: true, inGracePeriod: false, graceDaysRemaining: 0, credits: updatedCredits }\n }\n\n async createJournalEntry(input: CreateJournalEntryInput): Promise<PortableJournalEntry> {\n const rows = await this.db\n .insert(creditJournalEntries)\n .values({\n userId: input.userId,\n entryType: input.entryType,\n amount: String(input.amount),\n balanceAfter: String(input.balanceAfter),\n source: input.source,\n referenceId: input.referenceId,\n referenceType: input.referenceType,\n description: input.description,\n metadata: input.metadata,\n })\n .returning()\n return toJournalEntry(rows[0])\n }\n\n async getJournalEntries(query: JournalEntryQuery): Promise<PortableJournalEntry[]> {\n const filters = this.journalFilters(query)\n const rows = await this.db\n .select()\n .from(creditJournalEntries)\n .where(filters.length ? and(...filters) : undefined)\n .orderBy(desc(creditJournalEntries.createdAt))\n .limit(query.limit ?? 50)\n .offset(query.offset ?? 0)\n return rows.map(toJournalEntry)\n }\n\n async getJournalEntriesCount(query: Omit<JournalEntryQuery, 'limit' | 'offset'>): Promise<number> {\n const filters = this.journalFilters(query)\n const rows = await this.db\n .select({ value: count() })\n .from(creditJournalEntries)\n .where(filters.length ? and(...filters) : undefined)\n return Number(rows[0]?.value ?? 0)\n }\n\n private usageFilters(query: Omit<UsageLogQuery, 'limit' | 'offset'>): any[] {\n const filters: any[] = []\n if (query.userId) filters.push(eq(creditUsageLogs.userId, query.userId))\n if (query.operationType) filters.push(eq(creditUsageLogs.operationType, query.operationType))\n if (query.success !== undefined) filters.push(eq(creditUsageLogs.success, query.success))\n if (query.startDate) filters.push(gte(creditUsageLogs.createdAt, query.startDate))\n if (query.endDate) filters.push(lte(creditUsageLogs.createdAt, query.endDate))\n return filters\n }\n\n private journalFilters(query: Omit<JournalEntryQuery, 'limit' | 'offset'>): any[] {\n const filters: any[] = [eq(creditJournalEntries.userId, query.userId)]\n if (query.source) filters.push(eq(creditJournalEntries.source, query.source))\n if (query.referenceType) filters.push(eq(creditJournalEntries.referenceType, query.referenceType))\n if (query.startDate) filters.push(gte(creditJournalEntries.createdAt, query.startDate))\n if (query.endDate) filters.push(lte(creditJournalEntries.createdAt, query.endDate))\n return filters\n }\n}\n\nexport function createDrizzleCreditRepository(db: DrizzleLikeDB): DrizzleCreditRepository {\n return new DrizzleCreditRepository(db)\n}\n","import { sql } from 'drizzle-orm'\nimport {\n boolean,\n index,\n integer,\n jsonb,\n numeric,\n pgTable,\n text,\n timestamp,\n uniqueIndex,\n uuid,\n} from 'drizzle-orm/pg-core'\n\nexport const creditBalances = pgTable('credit_balances', {\n userId: uuid('user_id').primaryKey(),\n balance: numeric('balance', { precision: 12, scale: 2 }).notNull().default('0'),\n bonusCredits: numeric('bonus_credits', { precision: 12, scale: 2 }).notNull().default('0'),\n reserved: numeric('reserved', { precision: 12, scale: 2 }).notNull().default('0'),\n tier: text('tier').notNull().default('free'),\n monthlyLimit: numeric('monthly_limit', { precision: 12, scale: 2 }).notNull().default('0'),\n monthlyUsed: numeric('monthly_used', { precision: 12, scale: 2 }).notNull().default('0'),\n monthlyResetAt: timestamp('monthly_reset_at', { withTimezone: true }).notNull(),\n subscriptionExpiresAt: timestamp('subscription_expires_at', { withTimezone: true }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n})\n\nexport const creditReservations = pgTable(\n 'credit_reservations',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),\n operationType: text('operation_type').notNull(),\n status: text('status').notNull().default('reserved'),\n expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),\n completedAt: timestamp('completed_at', { withTimezone: true }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userIdx: index('credit_reservations_user_idx').on(table.userId),\n statusExpiresIdx: index('credit_reservations_status_expires_idx').on(table.status, table.expiresAt),\n })\n)\n\nexport const creditPluginTransactions = pgTable(\n 'credit_plugin_transactions',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n type: text('type').notNull(),\n amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),\n description: text('description').notNull(),\n paymentRef: text('payment_ref'),\n previousBalance: numeric('previous_balance', { precision: 12, scale: 2 }).notNull(),\n newBalance: numeric('new_balance', { precision: 12, scale: 2 }).notNull(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userCreatedIdx: index('credit_plugin_transactions_user_created_idx').on(table.userId, table.createdAt),\n paymentRefUnique: uniqueIndex('credit_plugin_transactions_payment_ref_unique')\n .on(table.paymentRef)\n .where(sql`${table.paymentRef} is not null`),\n })\n)\n\nexport const creditUsageLogs = pgTable(\n 'credit_usage_logs',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n operationType: text('operation_type').notNull(),\n provider: text('provider').notNull(),\n creditsUsed: numeric('credits_used', { precision: 12, scale: 2 }).notNull(),\n success: boolean('success').notNull(),\n errorMessage: text('error_message'),\n resourceId: text('resource_id'),\n resourceType: text('resource_type'),\n requestId: text('request_id'),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userCreatedIdx: index('credit_usage_logs_user_created_idx').on(table.userId, table.createdAt),\n operationIdx: index('credit_usage_logs_operation_idx').on(table.operationType),\n successIdx: index('credit_usage_logs_success_idx').on(table.success),\n })\n)\n\nexport const creditJournalEntries = pgTable(\n 'credit_journal_entries',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n entryType: text('entry_type').notNull(),\n amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),\n balanceAfter: numeric('balance_after', { precision: 12, scale: 2 }).notNull(),\n source: text('source').notNull(),\n referenceId: text('reference_id').notNull(),\n referenceType: text('reference_type').notNull(),\n description: text('description').notNull(),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userCreatedIdx: index('credit_journal_entries_user_created_idx').on(table.userId, table.createdAt),\n sourceIdx: index('credit_journal_entries_source_idx').on(table.source),\n referenceIdx: index('credit_journal_entries_reference_idx').on(table.referenceId, table.referenceType),\n })\n)\n\nexport type CreditBalanceRow = typeof creditBalances.$inferSelect\nexport type CreditReservationRow = typeof creditReservations.$inferSelect\nexport type CreditPluginTransactionRow = typeof creditPluginTransactions.$inferSelect\nexport type CreditUsageLogRow = typeof creditUsageLogs.$inferSelect\nexport type CreditJournalEntryRow = typeof creditJournalEntries.$inferSelect\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,sBAAwD;AAwBxD,qBAGO;AACP,IAAAC,kBAAoC;;;AC5BpC,yBAAoB;AACpB,qBAWO;AAEA,IAAM,qBAAiB,wBAAQ,mBAAmB;AAAA,EACvD,YAAQ,qBAAK,SAAS,EAAE,WAAW;AAAA,EACnC,aAAS,wBAAQ,WAAW,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG;AAAA,EAC9E,kBAAc,wBAAQ,iBAAiB,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG;AAAA,EACzF,cAAU,wBAAQ,YAAY,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG;AAAA,EAChF,UAAM,qBAAK,MAAM,EAAE,QAAQ,EAAE,QAAQ,MAAM;AAAA,EAC3C,kBAAc,wBAAQ,iBAAiB,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG;AAAA,EACzF,iBAAa,wBAAQ,gBAAgB,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG;AAAA,EACvF,oBAAgB,0BAAU,oBAAoB,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ;AAAA,EAC9E,2BAAuB,0BAAU,2BAA2B,EAAE,cAAc,KAAK,CAAC;AAAA,EAClF,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAChF,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAClF,CAAC;AAEM,IAAM,yBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,IACE,QAAI,qBAAK,IAAI,EAAE,WAAW,EAAE,cAAc;AAAA,IAC1C,YAAQ,qBAAK,SAAS,EAAE,QAAQ;AAAA,IAChC,YAAQ,wBAAQ,UAAU,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IAC/D,mBAAe,qBAAK,gBAAgB,EAAE,QAAQ;AAAA,IAC9C,YAAQ,qBAAK,QAAQ,EAAE,QAAQ,EAAE,QAAQ,UAAU;AAAA,IACnD,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ;AAAA,IACnE,iBAAa,0BAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;AAAA,IAC7D,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAClF;AAAA,EACA,CAAC,WAAW;AAAA,IACV,aAAS,sBAAM,8BAA8B,EAAE,GAAG,MAAM,MAAM;AAAA,IAC9D,sBAAkB,sBAAM,wCAAwC,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,EACpG;AACF;AAEO,IAAM,+BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,IACE,QAAI,qBAAK,IAAI,EAAE,WAAW,EAAE,cAAc;AAAA,IAC1C,YAAQ,qBAAK,SAAS,EAAE,QAAQ;AAAA,IAChC,UAAM,qBAAK,MAAM,EAAE,QAAQ;AAAA,IAC3B,YAAQ,wBAAQ,UAAU,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IAC/D,iBAAa,qBAAK,aAAa,EAAE,QAAQ;AAAA,IACzC,gBAAY,qBAAK,aAAa;AAAA,IAC9B,qBAAiB,wBAAQ,oBAAoB,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IAClF,gBAAY,wBAAQ,eAAe,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IACxE,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAClF;AAAA,EACA,CAAC,WAAW;AAAA,IACV,oBAAgB,sBAAM,6CAA6C,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,IACrG,sBAAkB,4BAAY,+CAA+C,EAC1E,GAAG,MAAM,UAAU,EACnB,MAAM,yBAAM,MAAM,UAAU,cAAc;AAAA,EAC/C;AACF;AAEO,IAAM,sBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,IACE,QAAI,qBAAK,IAAI,EAAE,WAAW,EAAE,cAAc;AAAA,IAC1C,YAAQ,qBAAK,SAAS,EAAE,QAAQ;AAAA,IAChC,mBAAe,qBAAK,gBAAgB,EAAE,QAAQ;AAAA,IAC9C,cAAU,qBAAK,UAAU,EAAE,QAAQ;AAAA,IACnC,iBAAa,wBAAQ,gBAAgB,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IAC1E,aAAS,wBAAQ,SAAS,EAAE,QAAQ;AAAA,IACpC,kBAAc,qBAAK,eAAe;AAAA,IAClC,gBAAY,qBAAK,aAAa;AAAA,IAC9B,kBAAc,qBAAK,eAAe;AAAA,IAClC,eAAW,qBAAK,YAAY;AAAA,IAC5B,cAAU,sBAAM,UAAU,EAAE,MAA+B;AAAA,IAC3D,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAClF;AAAA,EACA,CAAC,WAAW;AAAA,IACV,oBAAgB,sBAAM,oCAAoC,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,IAC5F,kBAAc,sBAAM,iCAAiC,EAAE,GAAG,MAAM,aAAa;AAAA,IAC7E,gBAAY,sBAAM,+BAA+B,EAAE,GAAG,MAAM,OAAO;AAAA,EACrE;AACF;AAEO,IAAM,2BAAuB;AAAA,EAClC;AAAA,EACA;AAAA,IACE,QAAI,qBAAK,IAAI,EAAE,WAAW,EAAE,cAAc;AAAA,IAC1C,YAAQ,qBAAK,SAAS,EAAE,QAAQ;AAAA,IAChC,eAAW,qBAAK,YAAY,EAAE,QAAQ;AAAA,IACtC,YAAQ,wBAAQ,UAAU,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IAC/D,kBAAc,wBAAQ,iBAAiB,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ;AAAA,IAC5E,YAAQ,qBAAK,QAAQ,EAAE,QAAQ;AAAA,IAC/B,iBAAa,qBAAK,cAAc,EAAE,QAAQ;AAAA,IAC1C,mBAAe,qBAAK,gBAAgB,EAAE,QAAQ;AAAA,IAC9C,iBAAa,qBAAK,aAAa,EAAE,QAAQ;AAAA,IACzC,cAAU,sBAAM,UAAU,EAAE,MAA+B;AAAA,IAC3D,eAAW,0BAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAClF;AAAA,EACA,CAAC,WAAW;AAAA,IACV,oBAAgB,sBAAM,yCAAyC,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,IACjG,eAAW,sBAAM,mCAAmC,EAAE,GAAG,MAAM,MAAM;AAAA,IACrE,kBAAc,sBAAM,sCAAsC,EAAE,GAAG,MAAM,aAAa,MAAM,aAAa;AAAA,EACvG;AACF;;;AD7DA,SAAS,YAAY,OAAwB;AAC3C,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,SAAS,OAAO,KAAK;AAC3B,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAEA,SAAS,UAAU,OAAsD;AACvE,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,iBAAiB,OAAO,QAAQ,IAAI,KAAK,KAAK;AACvD;AAEA,SAAS,IAAI,OAAiD;AAC5D,MAAI,CAAC,MAAO,SAAO,oBAAI,KAAK,GAAE,YAAY;AAC1C,SAAO,iBAAiB,OAAO,MAAM,YAAY,IAAI,IAAI,KAAK,KAAK,EAAE,YAAY;AACnF;AAEA,SAAS,cAAc,KAA4C;AACjE,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ,SAAS,YAAY,IAAI,OAAO;AAAA,IAChC,cAAc,YAAY,IAAI,YAAY;AAAA,IAC1C,UAAU,YAAY,IAAI,QAAQ;AAAA,IAClC,MAAM,IAAI;AAAA,IACV,cAAc,YAAY,IAAI,YAAY;AAAA,IAC1C,aAAa,YAAY,IAAI,WAAW;AAAA,IACxC,gBAAgB,IAAI,IAAI,cAAc;AAAA,IACtC,uBAAuB,IAAI,wBAAwB,IAAI,IAAI,qBAAqB,IAAI;AAAA,IACpF,WAAW,IAAI,IAAI,SAAS;AAAA,IAC5B,WAAW,IAAI,IAAI,SAAS;AAAA,EAC9B;AACF;AAEA,SAAS,cAAc,KAAgD;AACrE,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,QAAQ,YAAY,IAAI,MAAM;AAAA,IAC9B,eAAe,IAAI;AAAA,IACnB,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI,IAAI,SAAS;AAAA,IAC5B,WAAW,IAAI,IAAI,SAAS;AAAA,IAC5B,aAAa,IAAI,cAAc,IAAI,IAAI,WAAW,IAAI;AAAA,EACxD;AACF;AAEA,SAAS,cAAc,KAAsD;AAC3E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,QAAQ,YAAY,IAAI,MAAM;AAAA,IAC9B,aAAa,IAAI;AAAA,IACjB,YAAY,IAAI,cAAc;AAAA,IAC9B,iBAAiB,YAAY,IAAI,eAAe;AAAA,IAChD,YAAY,YAAY,IAAI,UAAU;AAAA,IACtC,WAAW,IAAI,IAAI,SAAS;AAAA,EAC9B;AACF;AAEA,SAAS,WAAW,KAA0C;AAC5D,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,eAAe,IAAI;AAAA,IACnB,UAAU,IAAI;AAAA,IACd,aAAa,YAAY,IAAI,WAAW;AAAA,IACxC,SAAS,IAAI;AAAA,IACb,cAAc,IAAI,gBAAgB;AAAA,IAClC,YAAY,IAAI,cAAc;AAAA,IAC9B,cAAc,IAAI,gBAAgB;AAAA,IAClC,WAAW,IAAI,aAAa;AAAA,IAC5B,UAAU,IAAI,YAAY;AAAA,IAC1B,WAAW,IAAI,IAAI,SAAS;AAAA,EAC9B;AACF;AAEA,SAAS,eAAe,KAAkD;AACxE,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,QAAQ,YAAY,IAAI,MAAM;AAAA,IAC9B,cAAc,YAAY,IAAI,YAAY;AAAA,IAC1C,QAAQ,IAAI;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,eAAe,IAAI;AAAA,IACnB,aAAa,IAAI;AAAA,IACjB,UAAU,IAAI,YAAY;AAAA,IAC1B,WAAW,IAAI,IAAI,SAAS;AAAA,EAC9B;AACF;AAEO,IAAM,0BAAN,MAA2D;AAAA,EAChE,YAA6B,IAAmB;AAAnB;AAAA,EAAoB;AAAA,EAEjD,MAAc,OAAU,UAAyD;AAC/E,QAAI,KAAK,GAAG,aAAa;AACvB,aAAO,KAAK,GAAG,YAAY,QAAQ;AAAA,IACrC;AACA,WAAO,SAAS,KAAK,EAAE;AAAA,EACzB;AAAA,EAEA,MAAc,kBACZ,IACA,QACA,OAAyB,QACK;AAC9B,UAAM,WAAW,MAAM,GAAG,OAAO,EAAE,KAAK,cAAc,EAAE,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC;AACxG,QAAI,SAAS,CAAC,EAAG,QAAO,cAAc,SAAS,CAAC,CAAC;AAEjD,UAAM,mBAAe,sCAAsB,IAAI;AAC/C,UAAM,iBAAiB,OAAO,SAAS,YAAY,IAAI,eAAe;AACtE,UAAM,WAAW,MAAM,GACpB,OAAO,cAAc,EACrB,OAAO;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,OAAO,cAAc;AAAA,MAC9B,cAAc,OAAO,cAAc;AAAA,MACnC,oBAAgB,qCAAoB;AAAA,IACtC,CAAC,EACA,oBAAoB,EACpB,UAAU;AAEb,QAAI,SAAS,CAAC,EAAG,QAAO,cAAc,SAAS,CAAC,CAAC;AAEjD,UAAM,gBAAgB,MAAM,GAAG,OAAO,EAAE,KAAK,cAAc,EAAE,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC;AAC7G,QAAI,CAAC,cAAc,CAAC,GAAG;AACrB,YAAM,IAAI,MAAM,yCAAyC,MAAM,EAAE;AAAA,IACnE;AACA,WAAO,cAAc,cAAc,CAAC,CAAC;AAAA,EACvC;AAAA,EAEA,MAAM,eAAe,QAAqD;AACxE,UAAM,OAAO,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,cAAc,EAAE,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC;AACzG,WAAO,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,CAAC,IAAI;AAAA,EAC5C;AAAA,EAEA,MAAM,sBACJ,QACA,MACA,gBAC8B;AAC9B,UAAM,mBAAe,sCAAsB,IAAI;AAC/C,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,cAAc,EACrB,OAAO;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,OAAO,cAAc;AAAA,MAC9B,cAAc,OAAO,OAAO,SAAS,YAAY,IAAI,eAAe,CAAC;AAAA,MACrE,oBAAgB,qCAAoB;AAAA,IACtC,CAAC,EACA,mBAAmB;AAAA,MAClB,QAAQ,eAAe;AAAA,MACvB,KAAK,EAAE,WAAW,oBAAI,KAAK,EAAE;AAAA,IAC/B,CAAC,EACA,UAAU;AAEb,WAAO,cAAc,KAAK,CAAC,CAAC;AAAA,EAC9B;AAAA,EAEA,MAAM,kBAAkB,QAAgB,SAA6C;AACnF,UAAM,MAA+B,EAAE,WAAW,oBAAI,KAAK,EAAE;AAC7D,QAAI,QAAQ,YAAY,OAAW,KAAI,UAAU,OAAO,QAAQ,OAAO;AACvE,QAAI,QAAQ,iBAAiB,OAAW,KAAI,eAAe,OAAO,QAAQ,YAAY;AACtF,QAAI,QAAQ,aAAa,OAAW,KAAI,WAAW,OAAO,QAAQ,QAAQ;AAC1E,QAAI,QAAQ,SAAS,OAAW,KAAI,OAAO,QAAQ;AACnD,QAAI,QAAQ,iBAAiB,OAAW,KAAI,eAAe,OAAO,QAAQ,YAAY;AACtF,QAAI,QAAQ,gBAAgB,OAAW,KAAI,cAAc,OAAO,QAAQ,WAAW;AACnF,QAAI,QAAQ,mBAAmB,OAAW,KAAI,iBAAiB,UAAU,QAAQ,cAAc;AAC/F,QAAI,QAAQ,0BAA0B,OAAW,KAAI,wBAAwB,UAAU,QAAQ,qBAAqB;AAEpH,UAAM,KAAK,GACR,OAAO,cAAc,EACrB,IAAI;AAAA,MACH,GAAG;AAAA,MACH,SACE,QAAQ,qBAAqB,SACzB,0BAAM,eAAe,OAAO,MAAM,QAAQ,gBAAgB,KAC1D,IAAI;AAAA,MACV,cACE,QAAQ,0BAA0B,SAC9B,0BAAM,eAAe,YAAY,MAAM,QAAQ,qBAAqB,KACpE,IAAI;AAAA,MACV,UACE,QAAQ,sBAAsB,SAC1B,0BAAM,eAAe,QAAQ,MAAM,QAAQ,iBAAiB,KAC5D,IAAI;AAAA,MACV,aACE,QAAQ,yBAAyB,SAC7B,0BAAM,eAAe,WAAW,MAAM,QAAQ,oBAAoB,KAClE,IAAI;AAAA,IACZ,CAAQ,EACP,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAM,eAAe,QAAgB,OAAuC;AAC1E,UAAM,KAAK,GACR,OAAO,cAAc,EACrB,IAAI;AAAA,MACH,MAAM,MAAM;AAAA,MACZ,cAAc,OAAO,MAAM,YAAY;AAAA,MACvC,SAAS,MAAM,YAAY,SAAY,OAAO,MAAM,OAAO,IAAI;AAAA,MAC/D,aAAa,MAAM,gBAAgB,SAAY,OAAO,MAAM,WAAW,IAAI;AAAA,MAC3E,uBACE,MAAM,0BAA0B,SAAY,UAAU,MAAM,qBAAqB,IAAI;AAAA,MACvF,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAQ,EACP,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAM,kBAAkB,OAA6D;AACnF,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,kBAAkB,EACzB,OAAO;AAAA,MACN,QAAQ,MAAM;AAAA,MACd,QAAQ,OAAO,MAAM,MAAM;AAAA,MAC3B,eAAe,MAAM;AAAA,MACrB,WAAW,MAAM;AAAA,IACnB,CAAC,EACA,UAAU;AACb,WAAO,cAAc,KAAK,CAAC,CAAC;AAAA,EAC9B;AAAA,EAEA,MAAM,eAAe,QAAgB,eAA4D;AAC/F,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EACP,KAAK,kBAAkB,EACvB,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,MAAM,OAAG,wBAAG,mBAAmB,IAAI,aAAa,CAAC,CAAC,EAC1F,MAAM,CAAC;AACV,WAAO,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,CAAC,IAAI;AAAA,EAC5C;AAAA,EAEA,MAAM,wBACJ,QACA,eACA,QACA,aACe;AACf,UAAM,KAAK,GACR,OAAO,kBAAkB,EACzB,IAAI,EAAE,QAAQ,aAAa,eAAe,oBAAI,KAAK,EAAE,CAAC,EACtD,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,MAAM,OAAG,wBAAG,mBAAmB,IAAI,aAAa,CAAC,CAAC;AAAA,EAC/F;AAAA,EAEA,MAAM,qBACJ,QACA,QACA,eACA,WAC8B;AAC9B,WAAO,KAAK,OAAO,OAAO,OAAO;AAC/B,YAAM,KAAK,kBAAkB,IAAI,MAAM;AACvC,YAAM,UAAU,MAAM,GACnB,OAAO,cAAc,EACrB,IAAI;AAAA,QACH,UAAU,0BAAM,eAAe,QAAQ,MAAM,MAAM;AAAA,QACnD,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EACA;AAAA,YACC;AAAA,cACE,wBAAG,eAAe,QAAQ,MAAM;AAAA,UAChC,0BAAM,eAAe,OAAO,MAAM,eAAe,YAAY,MAAM,eAAe,QAAQ,OAAO,MAAM;AAAA,QACzG;AAAA,MACF,EACC,UAAU;AAEb,UAAI,CAAC,QAAQ,CAAC,GAAG;AACf,cAAM,IAAI,MAAM,iCAAiC,MAAM,EAAE;AAAA,MAC3D;AAEA,YAAM,cAAc,MAAM,GACvB,OAAO,kBAAkB,EACzB,OAAO;AAAA,QACN;AAAA,QACA,QAAQ,OAAO,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,MACF,CAAC,EACA,UAAU;AACb,aAAO,cAAc,YAAY,CAAC,CAAC;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,wBAAwB,QAAgB,eAAsC;AAClF,UAAM,KAAK,OAAO,OAAO,OAAO;AAC9B,YAAM,kBAAkB,MAAM,GAC3B,OAAO,EACP,KAAK,kBAAkB,EACvB,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,MAAM,OAAG,wBAAG,mBAAmB,IAAI,aAAa,CAAC,CAAC,EAC1F,MAAM,CAAC;AACV,YAAM,cAAc,gBAAgB,CAAC;AACrC,UAAI,CAAC,YAAa,OAAM,IAAI,MAAM,eAAe,aAAa,YAAY;AAC1E,UAAI,YAAY,WAAW,YAAa;AACxC,UAAI,YAAY,WAAW,YAAY;AACrC,cAAM,IAAI,MAAM,gCAAgC,YAAY,MAAM,QAAQ;AAAA,MAC5E;AAEA,YAAM,aAAa,MAAM,GAAG,OAAO,EAAE,KAAK,cAAc,EAAE,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC;AAC1G,YAAM,UAAU,WAAW,CAAC;AAC5B,UAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mCAAmC,MAAM,EAAE;AAEzE,YAAM,SAAS,YAAY,YAAY,MAAM;AAC7C,YAAM,UAAU,YAAY,QAAQ,OAAO;AAC3C,YAAM,eAAe,YAAY,QAAQ,YAAY;AACrD,UAAI,UAAU,eAAe,QAAQ;AACnC,cAAM,IAAI,MAAM,8CAA8C,aAAa,EAAE;AAAA,MAC/E;AAEA,YAAM,mBAAmB,KAAK,IAAI,SAAS,MAAM;AACjD,YAAM,iBAAiB,SAAS;AAChC,YAAM,gBAAgB,UAAU;AAChC,YAAM,WAAW,gBAAgB;AAEjC,YAAM,GACH,OAAO,cAAc,EACrB,IAAI;AAAA,QACH,SAAS,OAAO,UAAU,gBAAgB;AAAA,QAC1C,cAAc,OAAO,eAAe,cAAc;AAAA,QAClD,UAAU,mCAAe,eAAe,QAAQ,MAAM,MAAM;AAAA,QAC5D,aAAa,0BAAM,eAAe,WAAW,MAAM,MAAM;AAAA,QACzD,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EACA,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC;AAE1C,YAAM,GACH,OAAO,kBAAkB,EACzB,IAAI,EAAE,QAAQ,aAAa,aAAa,oBAAI,KAAK,EAAE,CAAC,EACpD,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,MAAM,OAAG,wBAAG,mBAAmB,IAAI,aAAa,CAAC,CAAC;AAE7F,YAAM,GAAG,OAAO,oBAAoB,EAAE,OAAO;AAAA,QAC3C;AAAA,QACA,WAAW;AAAA,QACX,QAAQ,OAAO,MAAM;AAAA,QACrB,cAAc,OAAO,QAAQ;AAAA,QAC7B,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,eAAe;AAAA,QACf,aAAa,aAAa,MAAM;AAAA,MAClC,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,yBAAyB,QAAgB,eAAsC;AACnF,UAAM,KAAK,OAAO,OAAO,OAAO;AAC9B,YAAM,kBAAkB,MAAM,GAC3B,OAAO,EACP,KAAK,kBAAkB,EACvB,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,MAAM,OAAG,wBAAG,mBAAmB,IAAI,aAAa,CAAC,CAAC,EAC1F,MAAM,CAAC;AACV,YAAM,cAAc,gBAAgB,CAAC;AACrC,UAAI,CAAC,YAAa,OAAM,IAAI,MAAM,eAAe,aAAa,YAAY;AAC1E,UAAI,YAAY,WAAW,WAAY;AAEvC,YAAM,SAAS,YAAY,YAAY,MAAM;AAC7C,YAAM,GACH,OAAO,cAAc,EACrB,IAAI;AAAA,QACH,UAAU,mCAAe,eAAe,QAAQ,MAAM,MAAM;AAAA,QAC5D,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EACA,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC;AAC1C,YAAM,GACH,OAAO,kBAAkB,EACzB,IAAI,EAAE,QAAQ,YAAY,aAAa,oBAAI,KAAK,EAAE,CAAC,EACnD,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,MAAM,OAAG,wBAAG,mBAAmB,IAAI,aAAa,CAAC,CAAC;AAAA,IAC/F,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBACJ,QACA,QACA,aACA,YACe;AACf,UAAM,KAAK,OAAO,OAAO,OAAO;AAC9B,UAAI,YAAY;AACd,cAAM,WAAW,MAAM,GACpB,OAAO,EACP,KAAK,wBAAwB,EAC7B,UAAM,wBAAG,yBAAyB,YAAY,UAAU,CAAC,EACzD,MAAM,CAAC;AACV,YAAI,SAAS,CAAC,EAAG;AAAA,MACnB;AAEA,YAAM,UAAU,MAAM,KAAK,kBAAkB,IAAI,MAAM;AACvD,YAAM,kBAAkB,QAAQ,UAAU,QAAQ;AAClD,YAAM,aAAa,kBAAkB;AAErC,YAAM,GACH,OAAO,cAAc,EACrB,IAAI;AAAA,QACH,cAAc,0BAAM,eAAe,YAAY,MAAM,MAAM;AAAA,QAC3D,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EACA,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC;AAE1C,YAAM,WAAW,MAAM,GACpB,OAAO,wBAAwB,EAC/B,OAAO;AAAA,QACN;AAAA,QACA,MAAM;AAAA,QACN,QAAQ,OAAO,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,QACA,iBAAiB,OAAO,eAAe;AAAA,QACvC,YAAY,OAAO,UAAU;AAAA,MAC/B,CAAC,EACA,UAAU;AAEb,YAAM,GAAG,OAAO,oBAAoB,EAAE,OAAO;AAAA,QAC3C;AAAA,QACA,WAAW;AAAA,QACX,QAAQ,OAAO,MAAM;AAAA,QACrB,cAAc,OAAO,UAAU;AAAA,QAC/B,QAAQ;AAAA,QACR,aAAa,SAAS,CAAC,GAAG,MAAM,cAAc;AAAA,QAC9C,eAAe;AAAA,QACf;AAAA,QACA,UAAU,aAAa,EAAE,WAAW,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,oBAAoB,QAAgB,QAA0E;AAClH,WAAO,KAAK,OAAO,OAAO,OAAO;AAC/B,YAAM,aAAa,MAAM,GAAG,OAAO,EAAE,KAAK,cAAc,EAAE,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC;AAC1G,YAAM,UAAU,WAAW,CAAC;AAC5B,UAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mCAAmC,MAAM,EAAE;AAEzE,YAAM,UAAU,YAAY,QAAQ,OAAO;AAC3C,YAAM,eAAe,YAAY,QAAQ,YAAY;AACrD,YAAM,WAAW,YAAY,QAAQ,QAAQ;AAC7C,YAAM,YAAY,UAAU,eAAe;AAC3C,UAAI,YAAY,QAAQ;AACtB,cAAM,IAAI,MAAM,oCAAoC,SAAS,gBAAgB,MAAM,EAAE;AAAA,MACvF;AAEA,YAAM,mBAAmB,KAAK,IAAI,SAAS,MAAM;AACjD,YAAM,iBAAiB,SAAS;AAChC,YAAM,kBAAkB,UAAU;AAClC,YAAM,aAAa,kBAAkB;AAErC,YAAM,GACH,OAAO,cAAc,EACrB,IAAI;AAAA,QACH,SAAS,OAAO,UAAU,gBAAgB;AAAA,QAC1C,cAAc,OAAO,eAAe,cAAc;AAAA,QAClD,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EACA,UAAM,wBAAG,eAAe,QAAQ,MAAM,CAAC;AAE1C,aAAO,EAAE,iBAAiB,WAAW;AAAA,IACvC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,kBAAkB,OAA6D;AACnF,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,wBAAwB,EAC/B,OAAO;AAAA,MACN,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,QAAQ,OAAO,MAAM,MAAM;AAAA,MAC3B,aAAa,MAAM;AAAA,MACnB,YAAY,MAAM;AAAA,MAClB,iBAAiB,OAAO,MAAM,eAAe;AAAA,MAC7C,YAAY,OAAO,MAAM,UAAU;AAAA,IACrC,CAAC,EACA,UAAU;AACb,WAAO,cAAc,KAAK,CAAC,CAAC;AAAA,EAC9B;AAAA,EAEA,MAAM,gBAAgB,QAAgB,QAAQ,IAAI,SAAS,GAAmC;AAC5F,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EACP,KAAK,wBAAwB,EAC7B,UAAM,wBAAG,yBAAyB,QAAQ,MAAM,CAAC,EACjD,YAAQ,0BAAK,yBAAyB,SAAS,CAAC,EAChD,MAAM,KAAK,EACX,OAAO,MAAM;AAChB,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B;AAAA,EAEA,MAAM,SAAS,OAAuD;AACpE,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,eAAe,EACtB,OAAO;AAAA,MACN,QAAQ,MAAM;AAAA,MACd,eAAe,MAAM;AAAA,MACrB,UAAU,MAAM;AAAA,MAChB,aAAa,OAAO,MAAM,WAAW;AAAA,MACrC,SAAS,MAAM;AAAA,MACf,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,cAAc,MAAM;AAAA,MACpB,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM;AAAA,IAClB,CAAC,EACA,UAAU;AACb,WAAO,WAAW,KAAK,CAAC,CAAC;AAAA,EAC3B;AAAA,EAEA,MAAM,aAAa,OAAmD;AACpE,UAAM,UAAU,KAAK,aAAa,KAAK;AACvC,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM,QAAQ,aAAS,yBAAI,GAAG,OAAO,IAAI,MAAS,EAClD,YAAQ,0BAAK,gBAAgB,SAAS,CAAC,EACvC,MAAM,MAAM,SAAS,EAAE,EACvB,OAAO,MAAM,UAAU,CAAC;AAC3B,WAAO,KAAK,IAAI,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAM,kBAAkB,OAAiE;AACvF,UAAM,UAAU,KAAK,aAAa,KAAK;AACvC,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EAAE,WAAO,2BAAM,EAAE,CAAC,EACzB,KAAK,eAAe,EACpB,MAAM,QAAQ,aAAS,yBAAI,GAAG,OAAO,IAAI,MAAS;AACrD,WAAO,OAAO,KAAK,CAAC,GAAG,SAAS,CAAC;AAAA,EACnC;AAAA,EAEA,MAAM,0BAA0B,YAAY,KAAK,gBAAgB,KAI9D;AACD,UAAM,SAAmB,CAAC;AAC1B,QAAI,eAAe;AACnB,QAAI,kBAAkB;AAEtB,aAAS,IAAI,GAAG,IAAI,eAAe,KAAK,GAAG;AACzC,YAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EACP,KAAK,kBAAkB,EACvB,UAAM,6BAAI,wBAAG,mBAAmB,QAAQ,UAAU,OAAG,wBAAG,mBAAmB,WAAW,oBAAI,KAAK,CAAC,CAAC,CAAC,EAClG,MAAM,SAAS;AAClB,UAAI,KAAK,WAAW,EAAG;AAEvB,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,KAAK,yBAAyB,IAAI,QAAQ,IAAI,EAAE;AACtD,gBAAM,KAAK,GACR,OAAO,kBAAkB,EACzB,IAAI,EAAE,QAAQ,WAAW,aAAa,oBAAI,KAAK,EAAE,CAAC,EAClD,UAAM,wBAAG,mBAAmB,IAAI,IAAI,EAAE,CAAC;AAC1C,0BAAgB;AAChB,6BAAmB,YAAY,IAAI,MAAM;AAAA,QAC3C,SAAS,OAAO;AACd,iBAAO,KAAK,gCAAgC,IAAI,EAAE,KAAK,OAAO,KAAK,CAAC,EAAE;AAAA,QACxE;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,cAAc,iBAAiB,OAAO;AAAA,EACjD;AAAA,EAEA,MAAM,mBACJ,QACA,MACA,iBAC6B;AAC7B,UAAM,iBAAa,sCAAsB,IAAI;AAC7C,UAAM,gBAAY,qCAAoB;AACtC,UAAM,WAAW,UAAU,eAAe;AAC1C,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,cAAc,EACrB,IAAI;AAAA,MACH,SAAS,OAAO,SAAS,UAAU,IAAI,OAAO,UAAU,IAAI,0BAAM,eAAe,OAAO;AAAA,MACxF,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAQ,EACP,UAAM,6BAAI,wBAAG,eAAe,QAAQ,MAAM,OAAG,wBAAG,eAAe,gBAAgB,QAAgB,CAAC,CAAC,EACjG,UAAU;AAEb,QAAI,KAAK,CAAC,EAAG,QAAO,EAAE,UAAU,MAAM,SAAS,cAAc,KAAK,CAAC,CAAC,EAAE;AACtE,UAAM,UAAU,MAAM,KAAK,eAAe,MAAM;AAChD,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,QAAQ,MAAM,YAAY;AACxD,WAAO,EAAE,UAAU,OAAO,SAAS,QAAQ;AAAA,EAC7C;AAAA,EAEA,MAAM,iCAAiC,QAAgB,kBAAkB,GAAsC;AAC7G,UAAM,UAAU,MAAM,KAAK,eAAe,MAAM;AAChD,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,QAAQ,MAAM,YAAY;AAExD,UAAM,iBAAa,oCAAoB,QAAQ,IAAI;AACnD,SAAK,WAAW,UAAU,QAAQ,SAAS,WAAW,CAAC,QAAQ,uBAAuB;AACpF,aAAO,EAAE,eAAe,OAAO,eAAe,OAAO,oBAAoB,GAAG,QAAQ;AAAA,IACtF;AAEA,UAAM,YAAY,IAAI,KAAK,QAAQ,qBAAqB;AACxD,UAAM,mBAAmB,KAAK,IAAI,IAAI,UAAU,QAAQ,MAAM,MAAO,KAAK,KAAK;AAC/E,QAAI,mBAAmB,GAAG;AACxB,aAAO,EAAE,eAAe,OAAO,eAAe,OAAO,oBAAoB,GAAG,QAAQ;AAAA,IACtF;AACA,QAAI,mBAAmB,iBAAiB;AACtC,aAAO;AAAA,QACL,eAAe;AAAA,QACf,eAAe;AAAA,QACf,oBAAoB,KAAK,KAAK,kBAAkB,eAAe;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAEA,UAAM,cAAc;AACpB,UAAM,wBAAoB,oCAAoB,WAAW;AACzD,UAAM,KAAK,eAAe,QAAQ;AAAA,MAChC,MAAM;AAAA,MACN,cAAc,kBAAkB;AAAA,MAChC,SAAS,KAAK,IAAI,QAAQ,SAAS,kBAAkB,cAAc;AAAA,MACnE,uBAAuB;AAAA,IACzB,CAAC;AACD,UAAM,iBAAkB,MAAM,KAAK,eAAe,MAAM,KAAM;AAC9D,WAAO,EAAE,eAAe,MAAM,eAAe,OAAO,oBAAoB,GAAG,SAAS,eAAe;AAAA,EACrG;AAAA,EAEA,MAAM,mBAAmB,OAA+D;AACtF,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,oBAAoB,EAC3B,OAAO;AAAA,MACN,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,QAAQ,OAAO,MAAM,MAAM;AAAA,MAC3B,cAAc,OAAO,MAAM,YAAY;AAAA,MACvC,QAAQ,MAAM;AAAA,MACd,aAAa,MAAM;AAAA,MACnB,eAAe,MAAM;AAAA,MACrB,aAAa,MAAM;AAAA,MACnB,UAAU,MAAM;AAAA,IAClB,CAAC,EACA,UAAU;AACb,WAAO,eAAe,KAAK,CAAC,CAAC;AAAA,EAC/B;AAAA,EAEA,MAAM,kBAAkB,OAA2D;AACjF,UAAM,UAAU,KAAK,eAAe,KAAK;AACzC,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EACP,KAAK,oBAAoB,EACzB,MAAM,QAAQ,aAAS,yBAAI,GAAG,OAAO,IAAI,MAAS,EAClD,YAAQ,0BAAK,qBAAqB,SAAS,CAAC,EAC5C,MAAM,MAAM,SAAS,EAAE,EACvB,OAAO,MAAM,UAAU,CAAC;AAC3B,WAAO,KAAK,IAAI,cAAc;AAAA,EAChC;AAAA,EAEA,MAAM,uBAAuB,OAAqE;AAChG,UAAM,UAAU,KAAK,eAAe,KAAK;AACzC,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,EAAE,WAAO,2BAAM,EAAE,CAAC,EACzB,KAAK,oBAAoB,EACzB,MAAM,QAAQ,aAAS,yBAAI,GAAG,OAAO,IAAI,MAAS;AACrD,WAAO,OAAO,KAAK,CAAC,GAAG,SAAS,CAAC;AAAA,EACnC;AAAA,EAEQ,aAAa,OAAuD;AAC1E,UAAM,UAAiB,CAAC;AACxB,QAAI,MAAM,OAAQ,SAAQ,SAAK,wBAAG,gBAAgB,QAAQ,MAAM,MAAM,CAAC;AACvE,QAAI,MAAM,cAAe,SAAQ,SAAK,wBAAG,gBAAgB,eAAe,MAAM,aAAa,CAAC;AAC5F,QAAI,MAAM,YAAY,OAAW,SAAQ,SAAK,wBAAG,gBAAgB,SAAS,MAAM,OAAO,CAAC;AACxF,QAAI,MAAM,UAAW,SAAQ,SAAK,yBAAI,gBAAgB,WAAW,MAAM,SAAS,CAAC;AACjF,QAAI,MAAM,QAAS,SAAQ,SAAK,yBAAI,gBAAgB,WAAW,MAAM,OAAO,CAAC;AAC7E,WAAO;AAAA,EACT;AAAA,EAEQ,eAAe,OAA2D;AAChF,UAAM,UAAiB,KAAC,wBAAG,qBAAqB,QAAQ,MAAM,MAAM,CAAC;AACrE,QAAI,MAAM,OAAQ,SAAQ,SAAK,wBAAG,qBAAqB,QAAQ,MAAM,MAAM,CAAC;AAC5E,QAAI,MAAM,cAAe,SAAQ,SAAK,wBAAG,qBAAqB,eAAe,MAAM,aAAa,CAAC;AACjG,QAAI,MAAM,UAAW,SAAQ,SAAK,yBAAI,qBAAqB,WAAW,MAAM,SAAS,CAAC;AACtF,QAAI,MAAM,QAAS,SAAQ,SAAK,yBAAI,qBAAqB,WAAW,MAAM,OAAO,CAAC;AAClF,WAAO;AAAA,EACT;AACF;AAEO,SAAS,8BAA8B,IAA4C;AACxF,SAAO,IAAI,wBAAwB,EAAE;AACvC;","names":["import_drizzle_orm","import_credits"]}
@@ -0,0 +1,49 @@
1
+ import { ICreditRepository, PortableUserCredits, SubscriptionTier, CreditBalanceUpdate, TierUpdateInput, CreateReservationInput, PortableReservation, ReservationStatus, CreditOperationType, CreateTransactionInput, PortableTransaction, CreateUsageLogInput, PortableUsageLog, UsageLogQuery, MonthlyResetResult, SubscriptionExpiryResult, CreateJournalEntryInput, PortableJournalEntry, JournalEntryQuery } from '@nehorai/credits';
2
+
3
+ interface DrizzleLikeDB {
4
+ select: (...args: any[]) => any;
5
+ insert: (...args: any[]) => any;
6
+ update: (...args: any[]) => any;
7
+ transaction?: <T>(callback: (tx: DrizzleLikeDB) => Promise<T>) => Promise<T>;
8
+ }
9
+ declare class DrizzleCreditRepository implements ICreditRepository {
10
+ private readonly db;
11
+ constructor(db: DrizzleLikeDB);
12
+ private withTx;
13
+ private ensureUserCredits;
14
+ getUserCredits(userId: string): Promise<PortableUserCredits | null>;
15
+ initializeUserCredits(userId: string, tier: SubscriptionTier, initialBalance: number): Promise<PortableUserCredits>;
16
+ updateUserCredits(userId: string, updates: CreditBalanceUpdate): Promise<void>;
17
+ updateUserTier(userId: string, input: TierUpdateInput): Promise<void>;
18
+ createReservation(input: CreateReservationInput): Promise<PortableReservation>;
19
+ getReservation(userId: string, reservationId: string): Promise<PortableReservation | null>;
20
+ updateReservationStatus(userId: string, reservationId: string, status: ReservationStatus, completedAt?: Date): Promise<void>;
21
+ reserveCreditsAtomic(userId: string, amount: number, operationType: CreditOperationType, expiresAt: Date): Promise<PortableReservation>;
22
+ commitReservationAtomic(userId: string, reservationId: string): Promise<void>;
23
+ releaseReservationAtomic(userId: string, reservationId: string): Promise<void>;
24
+ addCreditsAtomic(userId: string, amount: number, description: string, paymentRef?: string): Promise<void>;
25
+ deductCreditsAtomic(userId: string, amount: number): Promise<{
26
+ previousBalance: number;
27
+ newBalance: number;
28
+ }>;
29
+ createTransaction(input: CreateTransactionInput): Promise<PortableTransaction>;
30
+ getTransactions(userId: string, limit?: number, offset?: number): Promise<PortableTransaction[]>;
31
+ logUsage(input: CreateUsageLogInput): Promise<PortableUsageLog>;
32
+ getUsageLogs(query: UsageLogQuery): Promise<PortableUsageLog[]>;
33
+ getUsageLogsCount(query: Omit<UsageLogQuery, 'limit' | 'offset'>): Promise<number>;
34
+ findAndExpireReservations(batchSize?: number, maxIterations?: number): Promise<{
35
+ expiredCount: number;
36
+ creditsReleased: number;
37
+ errors: string[];
38
+ }>;
39
+ atomicMonthlyReset(userId: string, tier: SubscriptionTier, expectedResetAt: Date | string): Promise<MonthlyResetResult>;
40
+ checkAndHandleSubscriptionExpiry(userId: string, gracePeriodDays?: number): Promise<SubscriptionExpiryResult>;
41
+ createJournalEntry(input: CreateJournalEntryInput): Promise<PortableJournalEntry>;
42
+ getJournalEntries(query: JournalEntryQuery): Promise<PortableJournalEntry[]>;
43
+ getJournalEntriesCount(query: Omit<JournalEntryQuery, 'limit' | 'offset'>): Promise<number>;
44
+ private usageFilters;
45
+ private journalFilters;
46
+ }
47
+ declare function createDrizzleCreditRepository(db: DrizzleLikeDB): DrizzleCreditRepository;
48
+
49
+ export { DrizzleCreditRepository, type DrizzleLikeDB, createDrizzleCreditRepository };
@@ -0,0 +1,49 @@
1
+ import { ICreditRepository, PortableUserCredits, SubscriptionTier, CreditBalanceUpdate, TierUpdateInput, CreateReservationInput, PortableReservation, ReservationStatus, CreditOperationType, CreateTransactionInput, PortableTransaction, CreateUsageLogInput, PortableUsageLog, UsageLogQuery, MonthlyResetResult, SubscriptionExpiryResult, CreateJournalEntryInput, PortableJournalEntry, JournalEntryQuery } from '@nehorai/credits';
2
+
3
+ interface DrizzleLikeDB {
4
+ select: (...args: any[]) => any;
5
+ insert: (...args: any[]) => any;
6
+ update: (...args: any[]) => any;
7
+ transaction?: <T>(callback: (tx: DrizzleLikeDB) => Promise<T>) => Promise<T>;
8
+ }
9
+ declare class DrizzleCreditRepository implements ICreditRepository {
10
+ private readonly db;
11
+ constructor(db: DrizzleLikeDB);
12
+ private withTx;
13
+ private ensureUserCredits;
14
+ getUserCredits(userId: string): Promise<PortableUserCredits | null>;
15
+ initializeUserCredits(userId: string, tier: SubscriptionTier, initialBalance: number): Promise<PortableUserCredits>;
16
+ updateUserCredits(userId: string, updates: CreditBalanceUpdate): Promise<void>;
17
+ updateUserTier(userId: string, input: TierUpdateInput): Promise<void>;
18
+ createReservation(input: CreateReservationInput): Promise<PortableReservation>;
19
+ getReservation(userId: string, reservationId: string): Promise<PortableReservation | null>;
20
+ updateReservationStatus(userId: string, reservationId: string, status: ReservationStatus, completedAt?: Date): Promise<void>;
21
+ reserveCreditsAtomic(userId: string, amount: number, operationType: CreditOperationType, expiresAt: Date): Promise<PortableReservation>;
22
+ commitReservationAtomic(userId: string, reservationId: string): Promise<void>;
23
+ releaseReservationAtomic(userId: string, reservationId: string): Promise<void>;
24
+ addCreditsAtomic(userId: string, amount: number, description: string, paymentRef?: string): Promise<void>;
25
+ deductCreditsAtomic(userId: string, amount: number): Promise<{
26
+ previousBalance: number;
27
+ newBalance: number;
28
+ }>;
29
+ createTransaction(input: CreateTransactionInput): Promise<PortableTransaction>;
30
+ getTransactions(userId: string, limit?: number, offset?: number): Promise<PortableTransaction[]>;
31
+ logUsage(input: CreateUsageLogInput): Promise<PortableUsageLog>;
32
+ getUsageLogs(query: UsageLogQuery): Promise<PortableUsageLog[]>;
33
+ getUsageLogsCount(query: Omit<UsageLogQuery, 'limit' | 'offset'>): Promise<number>;
34
+ findAndExpireReservations(batchSize?: number, maxIterations?: number): Promise<{
35
+ expiredCount: number;
36
+ creditsReleased: number;
37
+ errors: string[];
38
+ }>;
39
+ atomicMonthlyReset(userId: string, tier: SubscriptionTier, expectedResetAt: Date | string): Promise<MonthlyResetResult>;
40
+ checkAndHandleSubscriptionExpiry(userId: string, gracePeriodDays?: number): Promise<SubscriptionExpiryResult>;
41
+ createJournalEntry(input: CreateJournalEntryInput): Promise<PortableJournalEntry>;
42
+ getJournalEntries(query: JournalEntryQuery): Promise<PortableJournalEntry[]>;
43
+ getJournalEntriesCount(query: Omit<JournalEntryQuery, 'limit' | 'offset'>): Promise<number>;
44
+ private usageFilters;
45
+ private journalFilters;
46
+ }
47
+ declare function createDrizzleCreditRepository(db: DrizzleLikeDB): DrizzleCreditRepository;
48
+
49
+ export { DrizzleCreditRepository, type DrizzleLikeDB, createDrizzleCreditRepository };
@@ -0,0 +1,10 @@
1
+ import {
2
+ DrizzleCreditRepository,
3
+ createDrizzleCreditRepository
4
+ } from "../chunk-ZIOAIRV6.js";
5
+ import "../chunk-7R6F67RH.js";
6
+ export {
7
+ DrizzleCreditRepository,
8
+ createDrizzleCreditRepository
9
+ };
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/schema/index.ts
21
+ var schema_exports = {};
22
+ __export(schema_exports, {
23
+ creditBalances: () => creditBalances,
24
+ creditJournalEntries: () => creditJournalEntries,
25
+ creditPluginTransactions: () => creditPluginTransactions,
26
+ creditReservations: () => creditReservations,
27
+ creditUsageLogs: () => creditUsageLogs
28
+ });
29
+ module.exports = __toCommonJS(schema_exports);
30
+ var import_drizzle_orm = require("drizzle-orm");
31
+ var import_pg_core = require("drizzle-orm/pg-core");
32
+ var creditBalances = (0, import_pg_core.pgTable)("credit_balances", {
33
+ userId: (0, import_pg_core.uuid)("user_id").primaryKey(),
34
+ balance: (0, import_pg_core.numeric)("balance", { precision: 12, scale: 2 }).notNull().default("0"),
35
+ bonusCredits: (0, import_pg_core.numeric)("bonus_credits", { precision: 12, scale: 2 }).notNull().default("0"),
36
+ reserved: (0, import_pg_core.numeric)("reserved", { precision: 12, scale: 2 }).notNull().default("0"),
37
+ tier: (0, import_pg_core.text)("tier").notNull().default("free"),
38
+ monthlyLimit: (0, import_pg_core.numeric)("monthly_limit", { precision: 12, scale: 2 }).notNull().default("0"),
39
+ monthlyUsed: (0, import_pg_core.numeric)("monthly_used", { precision: 12, scale: 2 }).notNull().default("0"),
40
+ monthlyResetAt: (0, import_pg_core.timestamp)("monthly_reset_at", { withTimezone: true }).notNull(),
41
+ subscriptionExpiresAt: (0, import_pg_core.timestamp)("subscription_expires_at", { withTimezone: true }),
42
+ createdAt: (0, import_pg_core.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow(),
43
+ updatedAt: (0, import_pg_core.timestamp)("updated_at", { withTimezone: true }).notNull().defaultNow()
44
+ });
45
+ var creditReservations = (0, import_pg_core.pgTable)(
46
+ "credit_reservations",
47
+ {
48
+ id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
49
+ userId: (0, import_pg_core.uuid)("user_id").notNull(),
50
+ amount: (0, import_pg_core.numeric)("amount", { precision: 12, scale: 2 }).notNull(),
51
+ operationType: (0, import_pg_core.text)("operation_type").notNull(),
52
+ status: (0, import_pg_core.text)("status").notNull().default("reserved"),
53
+ expiresAt: (0, import_pg_core.timestamp)("expires_at", { withTimezone: true }).notNull(),
54
+ completedAt: (0, import_pg_core.timestamp)("completed_at", { withTimezone: true }),
55
+ createdAt: (0, import_pg_core.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow()
56
+ },
57
+ (table) => ({
58
+ userIdx: (0, import_pg_core.index)("credit_reservations_user_idx").on(table.userId),
59
+ statusExpiresIdx: (0, import_pg_core.index)("credit_reservations_status_expires_idx").on(table.status, table.expiresAt)
60
+ })
61
+ );
62
+ var creditPluginTransactions = (0, import_pg_core.pgTable)(
63
+ "credit_plugin_transactions",
64
+ {
65
+ id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
66
+ userId: (0, import_pg_core.uuid)("user_id").notNull(),
67
+ type: (0, import_pg_core.text)("type").notNull(),
68
+ amount: (0, import_pg_core.numeric)("amount", { precision: 12, scale: 2 }).notNull(),
69
+ description: (0, import_pg_core.text)("description").notNull(),
70
+ paymentRef: (0, import_pg_core.text)("payment_ref"),
71
+ previousBalance: (0, import_pg_core.numeric)("previous_balance", { precision: 12, scale: 2 }).notNull(),
72
+ newBalance: (0, import_pg_core.numeric)("new_balance", { precision: 12, scale: 2 }).notNull(),
73
+ createdAt: (0, import_pg_core.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow()
74
+ },
75
+ (table) => ({
76
+ userCreatedIdx: (0, import_pg_core.index)("credit_plugin_transactions_user_created_idx").on(table.userId, table.createdAt),
77
+ paymentRefUnique: (0, import_pg_core.uniqueIndex)("credit_plugin_transactions_payment_ref_unique").on(table.paymentRef).where(import_drizzle_orm.sql`${table.paymentRef} is not null`)
78
+ })
79
+ );
80
+ var creditUsageLogs = (0, import_pg_core.pgTable)(
81
+ "credit_usage_logs",
82
+ {
83
+ id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
84
+ userId: (0, import_pg_core.uuid)("user_id").notNull(),
85
+ operationType: (0, import_pg_core.text)("operation_type").notNull(),
86
+ provider: (0, import_pg_core.text)("provider").notNull(),
87
+ creditsUsed: (0, import_pg_core.numeric)("credits_used", { precision: 12, scale: 2 }).notNull(),
88
+ success: (0, import_pg_core.boolean)("success").notNull(),
89
+ errorMessage: (0, import_pg_core.text)("error_message"),
90
+ resourceId: (0, import_pg_core.text)("resource_id"),
91
+ resourceType: (0, import_pg_core.text)("resource_type"),
92
+ requestId: (0, import_pg_core.text)("request_id"),
93
+ metadata: (0, import_pg_core.jsonb)("metadata").$type(),
94
+ createdAt: (0, import_pg_core.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow()
95
+ },
96
+ (table) => ({
97
+ userCreatedIdx: (0, import_pg_core.index)("credit_usage_logs_user_created_idx").on(table.userId, table.createdAt),
98
+ operationIdx: (0, import_pg_core.index)("credit_usage_logs_operation_idx").on(table.operationType),
99
+ successIdx: (0, import_pg_core.index)("credit_usage_logs_success_idx").on(table.success)
100
+ })
101
+ );
102
+ var creditJournalEntries = (0, import_pg_core.pgTable)(
103
+ "credit_journal_entries",
104
+ {
105
+ id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
106
+ userId: (0, import_pg_core.uuid)("user_id").notNull(),
107
+ entryType: (0, import_pg_core.text)("entry_type").notNull(),
108
+ amount: (0, import_pg_core.numeric)("amount", { precision: 12, scale: 2 }).notNull(),
109
+ balanceAfter: (0, import_pg_core.numeric)("balance_after", { precision: 12, scale: 2 }).notNull(),
110
+ source: (0, import_pg_core.text)("source").notNull(),
111
+ referenceId: (0, import_pg_core.text)("reference_id").notNull(),
112
+ referenceType: (0, import_pg_core.text)("reference_type").notNull(),
113
+ description: (0, import_pg_core.text)("description").notNull(),
114
+ metadata: (0, import_pg_core.jsonb)("metadata").$type(),
115
+ createdAt: (0, import_pg_core.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow()
116
+ },
117
+ (table) => ({
118
+ userCreatedIdx: (0, import_pg_core.index)("credit_journal_entries_user_created_idx").on(table.userId, table.createdAt),
119
+ sourceIdx: (0, import_pg_core.index)("credit_journal_entries_source_idx").on(table.source),
120
+ referenceIdx: (0, import_pg_core.index)("credit_journal_entries_reference_idx").on(table.referenceId, table.referenceType)
121
+ })
122
+ );
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ creditBalances,
126
+ creditJournalEntries,
127
+ creditPluginTransactions,
128
+ creditReservations,
129
+ creditUsageLogs
130
+ });
131
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/schema/index.ts"],"sourcesContent":["import { sql } from 'drizzle-orm'\nimport {\n boolean,\n index,\n integer,\n jsonb,\n numeric,\n pgTable,\n text,\n timestamp,\n uniqueIndex,\n uuid,\n} from 'drizzle-orm/pg-core'\n\nexport const creditBalances = pgTable('credit_balances', {\n userId: uuid('user_id').primaryKey(),\n balance: numeric('balance', { precision: 12, scale: 2 }).notNull().default('0'),\n bonusCredits: numeric('bonus_credits', { precision: 12, scale: 2 }).notNull().default('0'),\n reserved: numeric('reserved', { precision: 12, scale: 2 }).notNull().default('0'),\n tier: text('tier').notNull().default('free'),\n monthlyLimit: numeric('monthly_limit', { precision: 12, scale: 2 }).notNull().default('0'),\n monthlyUsed: numeric('monthly_used', { precision: 12, scale: 2 }).notNull().default('0'),\n monthlyResetAt: timestamp('monthly_reset_at', { withTimezone: true }).notNull(),\n subscriptionExpiresAt: timestamp('subscription_expires_at', { withTimezone: true }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n})\n\nexport const creditReservations = pgTable(\n 'credit_reservations',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),\n operationType: text('operation_type').notNull(),\n status: text('status').notNull().default('reserved'),\n expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),\n completedAt: timestamp('completed_at', { withTimezone: true }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userIdx: index('credit_reservations_user_idx').on(table.userId),\n statusExpiresIdx: index('credit_reservations_status_expires_idx').on(table.status, table.expiresAt),\n })\n)\n\nexport const creditPluginTransactions = pgTable(\n 'credit_plugin_transactions',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n type: text('type').notNull(),\n amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),\n description: text('description').notNull(),\n paymentRef: text('payment_ref'),\n previousBalance: numeric('previous_balance', { precision: 12, scale: 2 }).notNull(),\n newBalance: numeric('new_balance', { precision: 12, scale: 2 }).notNull(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userCreatedIdx: index('credit_plugin_transactions_user_created_idx').on(table.userId, table.createdAt),\n paymentRefUnique: uniqueIndex('credit_plugin_transactions_payment_ref_unique')\n .on(table.paymentRef)\n .where(sql`${table.paymentRef} is not null`),\n })\n)\n\nexport const creditUsageLogs = pgTable(\n 'credit_usage_logs',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n operationType: text('operation_type').notNull(),\n provider: text('provider').notNull(),\n creditsUsed: numeric('credits_used', { precision: 12, scale: 2 }).notNull(),\n success: boolean('success').notNull(),\n errorMessage: text('error_message'),\n resourceId: text('resource_id'),\n resourceType: text('resource_type'),\n requestId: text('request_id'),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userCreatedIdx: index('credit_usage_logs_user_created_idx').on(table.userId, table.createdAt),\n operationIdx: index('credit_usage_logs_operation_idx').on(table.operationType),\n successIdx: index('credit_usage_logs_success_idx').on(table.success),\n })\n)\n\nexport const creditJournalEntries = pgTable(\n 'credit_journal_entries',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n entryType: text('entry_type').notNull(),\n amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),\n balanceAfter: numeric('balance_after', { precision: 12, scale: 2 }).notNull(),\n source: text('source').notNull(),\n referenceId: text('reference_id').notNull(),\n referenceType: text('reference_type').notNull(),\n description: text('description').notNull(),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n userCreatedIdx: index('credit_journal_entries_user_created_idx').on(table.userId, table.createdAt),\n sourceIdx: index('credit_journal_entries_source_idx').on(table.source),\n referenceIdx: index('credit_journal_entries_reference_idx').on(table.referenceId, table.referenceType),\n })\n)\n\nexport type CreditBalanceRow = typeof creditBalances.$inferSelect\nexport type CreditReservationRow = typeof creditReservations.$inferSelect\nexport type CreditPluginTransactionRow = typeof creditPluginTransactions.$inferSelect\nexport type CreditUsageLogRow = typeof creditUsageLogs.$inferSelect\nexport type CreditJournalEntryRow = typeof creditJournalEntries.$inferSelect\n"],"mappings":"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","names":[]}