From 3f8b3e8aee3ebfa8ff2d44a60ce1efdb97203dce Mon Sep 17 00:00:00 2001 From: "Rudy B." Date: Sat, 25 Apr 2026 17:57:45 +0200 Subject: [PATCH] fix(2FA): cast transaction return to match return type --- src/lib/two-factor/rate-limit.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/lib/two-factor/rate-limit.ts b/src/lib/two-factor/rate-limit.ts index ad2ad3b4c..46afc0aae 100644 --- a/src/lib/two-factor/rate-limit.ts +++ b/src/lib/two-factor/rate-limit.ts @@ -16,12 +16,17 @@ export async function checkRateLimit( return { allowed: true }; } -export async function recordFailedAttempt(userId: string) { +export async function recordFailedAttempt(userId: string): Promise<{ lockedUntil?: Date }> { let retries = 0; while (retries < MAX_RETRIES) { try { - return await prisma.transaction( - async (tx: Prisma.TransactionClient) => { + /* + prisma.transaction accepts `any` to support both batch and callback forms, + so TypeScript resolves to the batch overload and infers `any[]`. Cast is safe: + the callback form always returns the callback's return type. + */ + return await (prisma.transaction( + async (tx: Prisma.TransactionClient): Promise<{ lockedUntil?: Date }> => { const record = await tx.twoFactorRateLimit.upsert({ where: { userId }, update: { attempts: { increment: 1 } }, @@ -35,7 +40,7 @@ export async function recordFailedAttempt(userId: string) { return {}; }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable }, - ); + ) as Promise<{ lockedUntil?: Date }>); } catch (err: any) { if (err.code === 'P2034') { retries++;