import { SQL } from "bun" const db = new SQL({ adapter: "sqlite", filename: "./leo-typing.db", create: true, strict: true, }) export async function initDb() { await db` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, created_at TEXT DEFAULT (datetime('now')) ) ` await db` CREATE TABLE IF NOT EXISTS credentials ( id TEXT PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), public_key TEXT NOT NULL, counter INTEGER NOT NULL DEFAULT 0, transports TEXT, created_at TEXT DEFAULT (datetime('now')) ) ` await db` CREATE TABLE IF NOT EXISTS sessions ( token TEXT PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), expires_at TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ) ` } // ---- User queries ---- export async function createUser(username: string): Promise<{ id: number; username: string }> { const [user] = await db` INSERT INTO users (username) VALUES (${username}) RETURNING id, username ` return user as { id: number; username: string } } export async function getUserByUsername(username: string) { const [user] = await db`SELECT id, username FROM users WHERE username = ${username}` return user as { id: number; username: string } | undefined } export async function getUserById(id: number) { const [user] = await db`SELECT id, username FROM users WHERE id = ${id}` return user as { id: number; username: string } | undefined } // ---- Credential queries ---- export async function storeCredential( credentialId: string, userId: number, publicKey: string, counter: number, transports?: string[], ) { await db` INSERT INTO credentials (id, user_id, public_key, counter, transports) VALUES (${credentialId}, ${userId}, ${publicKey}, ${counter}, ${transports ? JSON.stringify(transports) : null}) ` } export async function getCredentialById(credentialId: string) { const [cred] = await db`SELECT * FROM credentials WHERE id = ${credentialId}` return cred as { id: string user_id: number public_key: string counter: number transports: string | null } | undefined } export async function getCredentialsByUserId(userId: number) { const creds = await db`SELECT * FROM credentials WHERE user_id = ${userId}` return creds as Array<{ id: string user_id: number public_key: string counter: number transports: string | null }> } export async function updateCredentialCounter(credentialId: string, counter: number) { await db`UPDATE credentials SET counter = ${counter} WHERE id = ${credentialId}` } // ---- Session queries ---- export async function createSession(userId: number): Promise { const token = crypto.randomUUID() const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() await db` INSERT INTO sessions (token, user_id, expires_at) VALUES (${token}, ${userId}, ${expires}) ` return token } export async function getSession(token: string) { const [session] = await db` SELECT s.token, s.user_id, s.expires_at, u.username FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.token = ${token} AND s.expires_at > datetime('now') ` return session as { token: string; user_id: number; username: string; expires_at: string } | undefined } export async function deleteSession(token: string) { await db`DELETE FROM sessions WHERE token = ${token}` }