import initSqlJs, { Database as SqlJsDatabase } from 'sql.js'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import bcrypt from 'bcryptjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const dbPath = path.join(__dirname, '..', 'data.db'); let db: SqlJsDatabase; export async function initDb(): Promise { const SQL = await initSqlJs(); if (fs.existsSync(dbPath)) { const buffer = fs.readFileSync(dbPath); db = new SQL.Database(buffer); } else { db = new SQL.Database(); } db.run('PRAGMA foreign_keys = ON'); db.run(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, points INTEGER DEFAULT 0, is_admin INTEGER DEFAULT 0, created_at TEXT DEFAULT (datetime('now')) ) `); // Add is_admin column if missing (existing DB migration) try { db.run('ALTER TABLE users ADD COLUMN is_admin INTEGER DEFAULT 0'); } catch {} // Auto-create admin if not exists const admin = queryOne('SELECT id FROM users WHERE username = ?', ['admin']); if (!admin) { const hash = bcrypt.hashSync('admin123', 10); execute('INSERT INTO users (username, password_hash, is_admin) VALUES (?, ?, 1)', ['admin', hash]); console.log('Admin user created: admin / admin123'); } db.run(` CREATE TABLE IF NOT EXISTS cats ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id), image_url TEXT NOT NULL, caption TEXT DEFAULT '', created_at TEXT DEFAULT (datetime('now')) ) `); db.run(` CREATE TABLE IF NOT EXISTS likes ( id INTEGER PRIMARY KEY AUTOINCREMENT, cat_id INTEGER NOT NULL REFERENCES cats(id), user_id INTEGER NOT NULL REFERENCES users(id), UNIQUE(cat_id, user_id) ) `); db.run(` CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, cat_id INTEGER NOT NULL REFERENCES cats(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id), text TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ) `); saveDb(); return db; } export function saveDb(): void { const data = db.export(); const buffer = Buffer.from(data); fs.writeFileSync(dbPath, buffer); } export function getDb(): SqlJsDatabase { return db; } export function queryOne(sql: string, params: any[] = []): any { const stmt = db.prepare(sql); stmt.bind(params); const result = stmt.step() ? stmt.getAsObject() : null; stmt.free(); return result; } export function queryAll(sql: string, params: any[] = []): any[] { const stmt = db.prepare(sql); stmt.bind(params); const results: any[] = []; while (stmt.step()) { results.push(stmt.getAsObject()); } stmt.free(); return results; } export function execute(sql: string, params: any[] = []): { changes: number; lastInsertRowid: number } { const stmt = db.prepare(sql); stmt.bind(params); stmt.step(); const lastId = db.exec('SELECT last_insert_rowid() AS id')[0]?.values[0][0] || 0; const changes = db.getRowsModified(); stmt.free(); saveDb(); return { changes, lastInsertRowid: Number(lastId) }; }