feat: wrap multi-step DB writes in transactions (#118)

- saveSourceConfig: upsert + credential update run atomically
- updateSourceConfig: SELECT FOR UPDATE prevents lost updates
- Widen Database type to accept transaction handles

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2026-04-12 15:46:30 +01:00
committed by GitHub
parent e54c5d5462
commit 62c8dfe0b1
5 changed files with 78 additions and 33 deletions

View File

@@ -26,6 +26,18 @@ export function sources(db: Database, userId: string) {
return rows[0]
},
/** Like find(), but acquires a row lock to prevent concurrent modifications. Must be called inside a transaction. */
async findForUpdate(sourceId: string) {
const rows = await db
.select()
.from(userSources)
.where(and(eq(userSources.userId, userId), eq(userSources.sourceId, sourceId)))
.limit(1)
.for("update")
return rows[0]
},
/** Enables a source for the user. Throws if the source row doesn't exist. */
async enableSource(sourceId: string) {
const rows = await db