Add transactions to auth procedures and extract DB models

- Wrap multiple DB operations in transactions for atomicity:
  - login-if-completed: device upsert + session + login_request deletion
  - forgot-password: delete old tokens + insert new token
  - signup: session + email_verification creation

- Extract reusable DB model operations to packages/db/src/models/:
  - sessions.ts: insertSession()
  - user-devices.ts: upsertUserDevice(), isDeviceTrusted()

- Update session.ts to use new model functions from @reviq/db
- Fix type narrowing in admin.test.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
igm
2026-01-12 15:52:05 +08:00
parent 5a2e0297e5
commit b085a315be
9 changed files with 241 additions and 124 deletions

View File

@@ -89,36 +89,39 @@ export const loginIfRequestIsCompleted =
const geo = getGeoInfo(context.reqHeaders, context.clientIP);
const userAgent = getUserAgent(context.reqHeaders);
// Upsert user device
const deviceId = await upsertUserDevice(
context.db,
userId,
deviceFingerprint,
geo,
userAgent,
);
// Create session in transaction (atomic: device upsert + session + login_request delete)
const { session, deviceTrusted } = await context.db
.transaction()
.execute(async (trx) => {
// Upsert user device
const deviceId = await upsertUserDevice(
trx,
userId,
deviceFingerprint,
geo,
userAgent,
);
// Check if device is already trusted
const deviceTrusted = await isDeviceTrusted(
context.db,
userId,
deviceFingerprint,
);
// Check if device is already trusted
const trusted = await isDeviceTrusted(trx, userId, deviceFingerprint);
// Create session with trusted mode = true (email-confirmed login)
const session = await createSession(context.db, {
userId,
deviceId,
trustedMode: true,
geo,
userAgent,
});
// Create session with trusted mode = true (email-confirmed login)
const newSession = await createSession(trx, {
userId,
deviceId,
trustedMode: true,
geo,
userAgent,
});
// Delete the login request (it's been consumed)
await context.db
.deleteFrom("login_requests")
.where("id", "=", loginRequest.id)
.execute();
// Delete the login request (it's been consumed)
await trx
.deleteFrom("login_requests")
.where("id", "=", loginRequest.id)
.execute();
return { session: newSession, deviceTrusted: trusted };
});
// Set session cookie
setCookie(