init
This commit is contained in:
102
server/src/db.ts
Normal file
102
server/src/db.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import initSqlJs, { Database, Statement } from 'sql.js';
|
||||
|
||||
// Simple SQLite via sql.js persisted to a single file
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const DB_FILE = path.join(DATA_DIR, 'metoyou.sqlite');
|
||||
|
||||
function ensureDataDir() {
|
||||
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
let SQL: any = null;
|
||||
let db: Database | null = null;
|
||||
|
||||
export async function initDB(): Promise<void> {
|
||||
if (db) return;
|
||||
SQL = await initSqlJs({ locateFile: (file: string) => require.resolve('sql.js/dist/sql-wasm.wasm') });
|
||||
ensureDataDir();
|
||||
|
||||
if (fs.existsSync(DB_FILE)) {
|
||||
const fileBuffer = fs.readFileSync(DB_FILE);
|
||||
db = new SQL.Database(new Uint8Array(fileBuffer));
|
||||
} else {
|
||||
db = new SQL.Database();
|
||||
}
|
||||
|
||||
// Initialize schema
|
||||
db.run(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
passwordHash TEXT NOT NULL,
|
||||
displayName TEXT NOT NULL,
|
||||
createdAt INTEGER NOT NULL
|
||||
);
|
||||
`);
|
||||
|
||||
persist();
|
||||
}
|
||||
|
||||
function persist(): void {
|
||||
if (!db) return;
|
||||
const data = db.export();
|
||||
const buffer = Buffer.from(data);
|
||||
fs.writeFileSync(DB_FILE, buffer);
|
||||
}
|
||||
|
||||
export interface AuthUser {
|
||||
id: string;
|
||||
username: string;
|
||||
passwordHash: string;
|
||||
displayName: string;
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
export async function getUserByUsername(username: string): Promise<AuthUser | null> {
|
||||
if (!db) await initDB();
|
||||
const stmt: Statement = db!.prepare('SELECT id, username, passwordHash, displayName, createdAt FROM users WHERE username = ? LIMIT 1');
|
||||
stmt.bind([username]);
|
||||
let row: AuthUser | null = null;
|
||||
if (stmt.step()) {
|
||||
const r = stmt.getAsObject() as any;
|
||||
row = {
|
||||
id: String(r.id),
|
||||
username: String(r.username),
|
||||
passwordHash: String(r.passwordHash),
|
||||
displayName: String(r.displayName),
|
||||
createdAt: Number(r.createdAt),
|
||||
};
|
||||
}
|
||||
stmt.free();
|
||||
return row;
|
||||
}
|
||||
|
||||
export async function getUserById(id: string): Promise<AuthUser | null> {
|
||||
if (!db) await initDB();
|
||||
const stmt: Statement = db!.prepare('SELECT id, username, passwordHash, displayName, createdAt FROM users WHERE id = ? LIMIT 1');
|
||||
stmt.bind([id]);
|
||||
let row: AuthUser | null = null;
|
||||
if (stmt.step()) {
|
||||
const r = stmt.getAsObject() as any;
|
||||
row = {
|
||||
id: String(r.id),
|
||||
username: String(r.username),
|
||||
passwordHash: String(r.passwordHash),
|
||||
displayName: String(r.displayName),
|
||||
createdAt: Number(r.createdAt),
|
||||
};
|
||||
}
|
||||
stmt.free();
|
||||
return row;
|
||||
}
|
||||
|
||||
export async function createUser(user: AuthUser): Promise<void> {
|
||||
if (!db) await initDB();
|
||||
const stmt = db!.prepare('INSERT INTO users (id, username, passwordHash, displayName, createdAt) VALUES (?, ?, ?, ?, ?)');
|
||||
stmt.bind([user.id, user.username, user.passwordHash, user.displayName, user.createdAt]);
|
||||
stmt.step();
|
||||
stmt.free();
|
||||
persist();
|
||||
}
|
||||
Reference in New Issue
Block a user