diff --git a/apps/api/src/routes/setup.ts b/apps/api/src/routes/setup.ts index 63bc98d..13795e5 100644 --- a/apps/api/src/routes/setup.ts +++ b/apps/api/src/routes/setup.ts @@ -255,11 +255,14 @@ setupRouter.post('/credential', zValidator('json', credentialSchema, noEchoHook) let localUser: typeof users.$inferSelect | undefined; try { localUser = await db.transaction(async (tx) => { - // Serialise: at most one unclaimed admin row may exist (WR-02) - const [{ count }] = await tx.execute<{ count: number }>( + // Serialise: at most one unclaimed admin row may exist (WR-02). + // Cast through unknown — Drizzle mysql2 execute() returns [rows, fields] for SELECTs; + // the generic type parameter on execute() is not sufficient to type the result correctly. + const countRows = (await tx.execute( sql`SELECT COUNT(*) AS count FROM users WHERE claimed = false FOR UPDATE`, - ); - if (Number(count) > 0) { + )) as unknown as [{ count: string | number }[], unknown]; + const unclaimedCount = Number(countRows[0][0]?.count ?? 0); + if (unclaimedCount > 0) { throw Object.assign(new Error('An unclaimed user already exists'), { code: 'DUPLICATE_UNCLAIMED' }); }