import type { SQLOutputValue } from "node:sqlite"; import { isRole, type PublicUser, type Role, type SelfUser, } from "../../shared/user.ts"; /** A user as stored: what they see of themselves, plus the password hash. */ export interface User extends SelfUser { passwordHash: string; } export function toPublicUser( { passwordHash: _, email: _email, ...user }: User, ): PublicUser { return user; } export function toSelfUser({ passwordHash: _, ...user }: User): SelfUser { return user; } export interface UserRow { id: string; username: string; password_hash: string; role: Role; created_at: string; updated_at: string | null; avatar_mime: string | null; description: string | null; invited_by: string | null; // Present only when joined: LEFT JOIN users i ON i.id = u.invited_by invited_by_username: string | null; email: string; [key: string]: SQLOutputValue; // Index signature } export function isUserRow(obj: unknown): obj is UserRow { return !!obj && typeof obj === "object" && "id" in obj && typeof obj.id === "string" && "username" in obj && typeof obj.username === "string" && "password_hash" in obj && typeof obj.password_hash === "string" && "role" in obj && isRole(obj.role) && "created_at" in obj && typeof obj.created_at === "string" && "updated_at" in obj && (typeof obj.updated_at === "string" || obj.updated_at === null) && "avatar_mime" in obj && (typeof obj.avatar_mime === "string" || obj.avatar_mime === null) && "description" in obj && (typeof obj.description === "string" || obj.description === null) && "invited_by" in obj && (typeof obj.invited_by === "string" || obj.invited_by === null) && "email" in obj && typeof obj.email === "string"; } export function userRowToApi(row: UserRow): User { return { id: row.id, username: row.username, passwordHash: row.password_hash, role: row.role, createdAt: new Date(row.created_at), updatedAt: row.updated_at ? new Date(row.updated_at) : undefined, avatarMime: row.avatar_mime ?? undefined, description: row.description ?? undefined, invitedByUsername: typeof row.invited_by_username === "string" ? row.invited_by_username : undefined, email: row.email, }; } export function userApiToRow(user: User): UserRow { return { id: user.id, username: user.username, password_hash: user.passwordHash, role: user.role, created_at: user.createdAt.toISOString(), updated_at: user.updatedAt?.toISOString() ?? null, avatar_mime: user.avatarMime ?? null, description: user.description ?? null, invited_by: null, invited_by_username: null, email: user.email, }; }