The executor agents wrote sync SQLite-style calls (.get(), .all(), .run()) instead of the async Postgres pattern established in Phase 14. Fixed: - auth.service.ts: use await + destructuring for all DB operations - auth routes: await listApiKeys - All auth test files: async createTestDb(), await service calls Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
import { randomBytes } from "node:crypto";
|
|
import { eq } from "drizzle-orm";
|
|
import { db as prodDb } from "../../db/index.ts";
|
|
import { apiKeys } from "../../db/schema.ts";
|
|
|
|
type Db = typeof prodDb;
|
|
|
|
// ── API Key Management ───────────────────────────────────────────────
|
|
|
|
export async function createApiKey(db: Db = prodDb, name: string) {
|
|
const rawKey = randomBytes(32).toString("hex");
|
|
const keyHash = await Bun.password.hash(rawKey);
|
|
const keyPrefix = rawKey.slice(0, 8);
|
|
|
|
const [record] = await db
|
|
.insert(apiKeys)
|
|
.values({ name, keyHash, keyPrefix })
|
|
.returning();
|
|
|
|
return { ...record, rawKey };
|
|
}
|
|
|
|
export async function verifyApiKey(
|
|
db: Db = prodDb,
|
|
rawKey: string,
|
|
): Promise<boolean> {
|
|
const prefix = rawKey.slice(0, 8);
|
|
const candidates = await db
|
|
.select()
|
|
.from(apiKeys)
|
|
.where(eq(apiKeys.keyPrefix, prefix));
|
|
|
|
for (const candidate of candidates) {
|
|
const valid = await Bun.password.verify(rawKey, candidate.keyHash);
|
|
if (valid) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export async function listApiKeys(db: Db = prodDb) {
|
|
return db
|
|
.select({
|
|
id: apiKeys.id,
|
|
name: apiKeys.name,
|
|
keyPrefix: apiKeys.keyPrefix,
|
|
createdAt: apiKeys.createdAt,
|
|
})
|
|
.from(apiKeys);
|
|
}
|
|
|
|
export async function deleteApiKey(db: Db = prodDb, id: number) {
|
|
await db.delete(apiKeys).where(eq(apiKeys.id, id));
|
|
}
|