feat(14-04): convert auth, OAuth, settings routes and auth middleware to async/await

- Add await before all service calls in auth, OAuth routes
- Convert settings.ts direct DB calls: remove .get()/.run(), use await + destructuring
- Auth middleware: await getUserCount, getSession, refreshSession
- Fix formatting in threads.ts for biome compliance
- All files pass lint
This commit is contained in:
2026-04-04 12:43:29 +02:00
parent 5edcc660e4
commit 22aaed76f2
5 changed files with 45 additions and 45 deletions

View File

@@ -11,7 +11,7 @@ export async function requireAuth(c: Context, next: Next) {
const db = c.get("db"); const db = c.get("db");
// Check if any users exist at all // Check if any users exist at all
if (getUserCount(db) === 0) { if ((await getUserCount(db)) === 0) {
return c.json({ error: "setup_required" }, 403); return c.json({ error: "setup_required" }, 403);
} }
@@ -26,10 +26,10 @@ export async function requireAuth(c: Context, next: Next) {
// Check session cookie // Check session cookie
const sessionId = getCookie(c, "gearbox_session"); const sessionId = getCookie(c, "gearbox_session");
if (sessionId) { if (sessionId) {
const session = getSession(db, sessionId); const session = await getSession(db, sessionId);
if (session) { if (session) {
// Refresh session expiry on use // Refresh session expiry on use
refreshSession(db, sessionId); await refreshSession(db, sessionId);
return next(); return next();
} }
} }

View File

@@ -43,12 +43,12 @@ const app = new Hono<Env>();
// ── Public routes ─────────────────────────────────────────────────── // ── Public routes ───────────────────────────────────────────────────
app.get("/me", (c) => { app.get("/me", async (c) => {
const db = c.get("db"); const db = c.get("db");
const sessionId = getCookie(c, COOKIE_NAME); const sessionId = getCookie(c, COOKIE_NAME);
if (sessionId) { if (sessionId) {
const session = getSession(db, sessionId); const session = await getSession(db, sessionId);
if (session) { if (session) {
return c.json({ return c.json({
user: { id: session.userId }, user: { id: session.userId },
@@ -57,20 +57,20 @@ app.get("/me", (c) => {
} }
} }
const setupRequired = getUserCount(db) === 0; const setupRequired = (await getUserCount(db)) === 0;
return c.json({ user: null, setupRequired }); return c.json({ user: null, setupRequired });
}); });
app.post("/setup", rateLimit, zValidator("json", setupSchema), async (c) => { app.post("/setup", rateLimit, zValidator("json", setupSchema), async (c) => {
const db = c.get("db"); const db = c.get("db");
if (getUserCount(db) > 0) { if ((await getUserCount(db)) > 0) {
return c.json({ error: "Setup already completed" }, 403); return c.json({ error: "Setup already completed" }, 403);
} }
const { username, password } = c.req.valid("json"); const { username, password } = c.req.valid("json");
const user = await createUser(db, username, password); const user = await createUser(db, username, password);
const session = createSession(db, user.id); const session = await createSession(db, user.id);
setCookie(c, COOKIE_NAME, session.id, { setCookie(c, COOKIE_NAME, session.id, {
httpOnly: true, httpOnly: true,
@@ -91,7 +91,7 @@ app.post("/login", rateLimit, zValidator("json", loginSchema), async (c) => {
return c.json({ error: "Invalid credentials" }, 401); return c.json({ error: "Invalid credentials" }, 401);
} }
const session = createSession(db, user.id); const session = await createSession(db, user.id);
setCookie(c, COOKIE_NAME, session.id, { setCookie(c, COOKIE_NAME, session.id, {
httpOnly: true, httpOnly: true,
@@ -103,12 +103,12 @@ app.post("/login", rateLimit, zValidator("json", loginSchema), async (c) => {
return c.json({ username: user.username }); return c.json({ username: user.username });
}); });
app.post("/logout", (c) => { app.post("/logout", async (c) => {
const db = c.get("db"); const db = c.get("db");
const sessionId = getCookie(c, COOKIE_NAME); const sessionId = getCookie(c, COOKIE_NAME);
if (sessionId) { if (sessionId) {
deleteSession(db, sessionId); await deleteSession(db, sessionId);
} }
deleteCookie(c, COOKIE_NAME, { path: "/" }); deleteCookie(c, COOKIE_NAME, { path: "/" });
@@ -127,17 +127,16 @@ app.put(
if (!sessionId) { if (!sessionId) {
return c.json({ error: "Session required for password change" }, 401); return c.json({ error: "Session required for password change" }, 401);
} }
const session = getSession(db, sessionId); const session = await getSession(db, sessionId);
if (!session) { if (!session) {
return c.json({ error: "Session required for password change" }, 401); return c.json({ error: "Session required for password change" }, 401);
} }
const userRecord = db const [userRecord] = await db
.select() .select()
.from(users) .from(users)
.where(eq(users.id, session.userId)) .where(eq(users.id, session.userId));
.get();
if (!userRecord) { if (!userRecord) {
return c.json({ error: "User not found" }, 404); return c.json({ error: "User not found" }, 404);
@@ -159,9 +158,9 @@ app.put(
}, },
); );
app.get("/keys", requireAuth, (c) => { app.get("/keys", requireAuth, async (c) => {
const db = c.get("db"); const db = c.get("db");
const keys = listApiKeys(db); const keys = await listApiKeys(db);
return c.json(keys); return c.json(keys);
}); });
@@ -186,11 +185,11 @@ app.post(
}, },
); );
app.delete("/keys/:id", requireAuth, (c) => { app.delete("/keys/:id", requireAuth, async (c) => {
const db = c.get("db"); const db = c.get("db");
const id = parseId(c.req.param("id")); const id = parseId(c.req.param("id"));
if (!id) return c.json({ error: "Invalid key ID" }, 400); if (!id) return c.json({ error: "Invalid key ID" }, 400);
deleteApiKey(db, id); await deleteApiKey(db, id);
return c.json({ ok: true }); return c.json({ ok: true });
}); });

View File

@@ -129,7 +129,7 @@ oauthRoutes.post("/register", async (c) => {
} }
const clientName = body.client_name || "Unknown Client"; const clientName = body.client_name || "Unknown Client";
const { clientId } = registerClient(db, clientName, body.redirect_uris); const { clientId } = await registerClient(db, clientName, body.redirect_uris);
return c.json( return c.json(
{ {
@@ -159,7 +159,7 @@ oauthRoutes.get("/authorize", async (c) => {
return c.json({ error: "Missing required parameters" }, 400); return c.json({ error: "Missing required parameters" }, 400);
} }
const client = getClient(db, clientId); const client = await getClient(db, clientId);
if (!client) { if (!client) {
return c.json({ error: "Unknown client_id" }, 400); return c.json({ error: "Unknown client_id" }, 400);
} }
@@ -196,7 +196,7 @@ oauthRoutes.post("/authorize", async (c) => {
const user = await verifyPassword(db, username, password); const user = await verifyPassword(db, username, password);
if (!user) { if (!user) {
const client = getClient(db, clientId); const client = await getClient(db, clientId);
return c.html( return c.html(
renderLoginForm({ renderLoginForm({
clientName: client?.clientName ?? "Unknown", clientName: client?.clientName ?? "Unknown",
@@ -210,7 +210,7 @@ oauthRoutes.post("/authorize", async (c) => {
); );
} }
const { code } = createAuthorizationCode( const { code } = await createAuthorizationCode(
db, db,
clientId, clientId,
codeChallenge, codeChallenge,
@@ -233,7 +233,7 @@ oauthRoutes.post("/token", async (c) => {
const grantType = body.grant_type as string; const grantType = body.grant_type as string;
// Opportunistic cleanup // Opportunistic cleanup
cleanExpiredOAuthData(db); await cleanExpiredOAuthData(db);
if (grantType === "authorization_code") { if (grantType === "authorization_code") {
const code = body.code as string; const code = body.code as string;

View File

@@ -6,14 +6,13 @@ type Env = { Variables: { db?: any } };
const app = new Hono<Env>(); const app = new Hono<Env>();
app.get("/:key", (c) => { app.get("/:key", async (c) => {
const database = c.get("db"); const database = c.get("db");
const key = c.req.param("key"); const key = c.req.param("key");
const row = database const [row] = await database
.select() .select()
.from(settings) .from(settings)
.where(eq(settings.key, key)) .where(eq(settings.key, key));
.get();
if (!row) return c.json({ error: "Setting not found" }, 404); if (!row) return c.json({ error: "Setting not found" }, 404);
return c.json(row); return c.json(row);
}); });
@@ -27,17 +26,15 @@ app.put("/:key", async (c) => {
return c.json({ error: "value is required" }, 400); return c.json({ error: "value is required" }, 400);
} }
database await database
.insert(settings) .insert(settings)
.values({ key, value: body.value }) .values({ key, value: body.value })
.onConflictDoUpdate({ target: settings.key, set: { value: body.value } }) .onConflictDoUpdate({ target: settings.key, set: { value: body.value } });
.run();
const row = database const [row] = await database
.select() .select()
.from(settings) .from(settings)
.where(eq(settings.key, key)) .where(eq(settings.key, key));
.get();
return c.json(row); return c.json(row);
}); });

View File

@@ -84,19 +84,23 @@ app.delete("/:id", async (c) => {
// Candidate CRUD (nested under thread) // Candidate CRUD (nested under thread)
app.post("/:id/candidates", zValidator("json", createCandidateSchema), async (c) => { app.post(
const db = c.get("db"); "/:id/candidates",
const threadId = parseId(c.req.param("id")); zValidator("json", createCandidateSchema),
if (!threadId) return c.json({ error: "Invalid thread ID" }, 400); async (c) => {
const db = c.get("db");
const threadId = parseId(c.req.param("id"));
if (!threadId) return c.json({ error: "Invalid thread ID" }, 400);
// Verify thread exists // Verify thread exists
const thread = await getThreadWithCandidates(db, threadId); const thread = await getThreadWithCandidates(db, threadId);
if (!thread) return c.json({ error: "Thread not found" }, 404); if (!thread) return c.json({ error: "Thread not found" }, 404);
const data = c.req.valid("json"); const data = c.req.valid("json");
const candidate = await createCandidate(db, threadId, data); const candidate = await createCandidate(db, threadId, data);
return c.json(candidate, 201); return c.json(candidate, 201);
}); },
);
app.put( app.put(
"/:threadId/candidates/:candidateId", "/:threadId/candidates/:candidateId",